1818#include "libpq/libpq-be.h"
1919#include "miscadmin.h"
2020#include "utils/builtins.h"
21+ #include "utils/timestamp.h"
2122
2223/*
2324 * On Windows, <wincrypt.h> includes a #define for X509_NAME, which breaks our
@@ -34,6 +35,7 @@ PG_MODULE_MAGIC;
3435
3536static Datum X509_NAME_field_to_text (X509_NAME * name , text * fieldName );
3637static Datum ASN1_STRING_to_text (ASN1_STRING * str );
38+ static Datum ASN1_TIME_to_timestamp (ASN1_TIME * time );
3739
3840/*
3941 * Function context for data persisting over repeated calls.
@@ -225,6 +227,39 @@ X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
225227}
226228
227229
230+ /*
231+ * Converts OpenSSL ASN1_TIME structure into timestamp
232+ *
233+ * Parameter: time - OpenSSL ASN1_TIME structure.
234+ *
235+ * Returns Datum, which can be directly returned from a C language SQL
236+ * function.
237+ */
238+ static Datum
239+ ASN1_TIME_to_timestamp (ASN1_TIME * time )
240+ {
241+ struct tm tm_time ;
242+ struct pg_tm pgtm_time ;
243+ Timestamp ts ;
244+
245+ ASN1_TIME_to_tm (time , & tm_time );
246+
247+ pgtm_time .tm_sec = tm_time .tm_sec ;
248+ pgtm_time .tm_min = tm_time .tm_min ;
249+ pgtm_time .tm_hour = tm_time .tm_hour ;
250+ pgtm_time .tm_mday = tm_time .tm_mday ;
251+ pgtm_time .tm_mon = tm_time .tm_mon + 1 ;
252+ pgtm_time .tm_year = tm_time .tm_year + 1900 ;
253+
254+ if (tm2timestamp (& pgtm_time , 0 , NULL , & ts ))
255+ ereport (ERROR ,
256+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
257+ errmsg ("failed to convert tm to timestamp" )));
258+
259+ PG_RETURN_TIMESTAMP (ts );
260+ }
261+
262+
228263/*
229264 * Returns specified field of client certificate distinguished name
230265 *
@@ -482,3 +517,35 @@ ssl_extension_info(PG_FUNCTION_ARGS)
482517 /* All done */
483518 SRF_RETURN_DONE (funcctx );
484519}
520+
521+ /*
522+ * Returns current client certificate notBefore timestamp in
523+ * timestamp data type
524+ */
525+ PG_FUNCTION_INFO_V1 (ssl_client_get_notbefore );
526+ Datum
527+ ssl_client_get_notbefore (PG_FUNCTION_ARGS )
528+ {
529+ X509 * cert = MyProcPort -> peer ;
530+
531+ if (!MyProcPort -> ssl_in_use || !MyProcPort -> peer_cert_valid )
532+ PG_RETURN_NULL ();
533+
534+ return ASN1_TIME_to_timestamp (X509_get_notBefore (cert ));
535+ }
536+
537+ /*
538+ * Returns current client certificate notAfter timestamp in
539+ * timestamp data type
540+ */
541+ PG_FUNCTION_INFO_V1 (ssl_client_get_notafter );
542+ Datum
543+ ssl_client_get_notafter (PG_FUNCTION_ARGS )
544+ {
545+ X509 * cert = MyProcPort -> peer ;
546+
547+ if (!MyProcPort -> ssl_in_use || !MyProcPort -> peer_cert_valid )
548+ PG_RETURN_NULL ();
549+
550+ return ASN1_TIME_to_timestamp (X509_get_notAfter (cert ));
551+ }
0 commit comments