Use be_tls_* API for SSL information in sslinfo
authorMagnus Hagander <[email protected]>
Tue, 3 Nov 2020 08:47:36 +0000 (09:47 +0100)
committerMagnus Hagander <[email protected]>
Tue, 3 Nov 2020 08:47:36 +0000 (09:47 +0100)
sslinfo was passing the Port->ssl member directly to OpenSSL in order
to extract information regarding the connection. This breaks the API
provided by the backend TLS implementation, as well as duplicates code
for no benefit. Rewrite to make use of the backend API as much as
possible.

Author: Daniel Gustafsson <[email protected]>

contrib/sslinfo/sslinfo.c
doc/src/sgml/sslinfo.sgml

index 5ba3988e270405bcc6dd87a9f330546f79dbb0cb..30cae0bb985ee46ea79ce7c9e53aadd5c6e96aef 100644 (file)
@@ -22,7 +22,6 @@
 PG_MODULE_MAGIC;
 
 static Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName);
-static Datum X509_NAME_to_text(X509_NAME *name);
 static Datum ASN1_STRING_to_text(ASN1_STRING *str);
 
 /*
@@ -54,9 +53,16 @@ PG_FUNCTION_INFO_V1(ssl_version);
 Datum
 ssl_version(PG_FUNCTION_ARGS)
 {
-   if (MyProcPort->ssl == NULL)
+   const char *version;
+
+   if (!MyProcPort->ssl_in_use)
+       PG_RETURN_NULL();
+
+   version = be_tls_get_version(MyProcPort);
+   if (version == NULL)
        PG_RETURN_NULL();
-   PG_RETURN_TEXT_P(cstring_to_text(SSL_get_version(MyProcPort->ssl)));
+
+   PG_RETURN_TEXT_P(cstring_to_text(version));
 }
 
 
@@ -67,9 +73,16 @@ PG_FUNCTION_INFO_V1(ssl_cipher);
 Datum
 ssl_cipher(PG_FUNCTION_ARGS)
 {
-   if (MyProcPort->ssl == NULL)
+   const char *cipher;
+
+   if (!MyProcPort->ssl_in_use)
+       PG_RETURN_NULL();
+
+   cipher = be_tls_get_cipher(MyProcPort);
+   if (cipher == NULL)
        PG_RETURN_NULL();
-   PG_RETURN_TEXT_P(cstring_to_text(SSL_get_cipher(MyProcPort->ssl)));
+
+   PG_RETURN_TEXT_P(cstring_to_text(cipher));
 }
 
 
@@ -83,7 +96,7 @@ PG_FUNCTION_INFO_V1(ssl_client_cert_present);
 Datum
 ssl_client_cert_present(PG_FUNCTION_ARGS)
 {
-   PG_RETURN_BOOL(MyProcPort->peer != NULL);
+   PG_RETURN_BOOL(MyProcPort->peer_cert_valid);
 }
 
 
@@ -99,25 +112,21 @@ PG_FUNCTION_INFO_V1(ssl_client_serial);
 Datum
 ssl_client_serial(PG_FUNCTION_ARGS)
 {
+   char decimal[NAMEDATALEN];
    Datum       result;
-   Port       *port = MyProcPort;
-   X509       *peer = port->peer;
-   ASN1_INTEGER *serial = NULL;
-   BIGNUM     *b;
-   char       *decimal;
 
-   if (!peer)
+   if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+       PG_RETURN_NULL();
+
+   be_tls_get_peer_serial(MyProcPort, decimal, NAMEDATALEN);
+
+   if (!*decimal)
        PG_RETURN_NULL();
-   serial = X509_get_serialNumber(peer);
-   b = ASN1_INTEGER_to_BN(serial, NULL);
-   decimal = BN_bn2dec(b);
 
-   BN_free(b);
    result = DirectFunctionCall3(numeric_in,
                                 CStringGetDatum(decimal),
                                 ObjectIdGetDatum(0),
                                 Int32GetDatum(-1));
-   OPENSSL_free(decimal);
    return result;
 }
 
@@ -228,7 +237,7 @@ ssl_client_dn_field(PG_FUNCTION_ARGS)
    text       *fieldname = PG_GETARG_TEXT_PP(0);
    Datum       result;
 
-   if (!(MyProcPort->peer))
+   if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
        PG_RETURN_NULL();
 
    result = X509_NAME_field_to_text(X509_get_subject_name(MyProcPort->peer), fieldname);
@@ -275,76 +284,6 @@ ssl_issuer_field(PG_FUNCTION_ARGS)
 }
 
 
-/*
- * Equivalent of X509_NAME_oneline that respects encoding
- *
- * This function converts X509_NAME structure to the text variable
- * converting all textual data into current database encoding.
- *
- * Parameter: X509_NAME *name X509_NAME structure to be converted
- *
- * Returns: text datum which contains string representation of
- * X509_NAME
- */
-static Datum
-X509_NAME_to_text(X509_NAME *name)
-{
-   BIO        *membuf = BIO_new(BIO_s_mem());
-   int         i,
-               nid,
-               count = X509_NAME_entry_count(name);
-   X509_NAME_ENTRY *e;
-   ASN1_STRING *v;
-   const char *field_name;
-   size_t      size;
-   char        nullterm;
-   char       *sp;
-   char       *dp;
-   text       *result;
-
-   if (membuf == NULL)
-       ereport(ERROR,
-               (errcode(ERRCODE_OUT_OF_MEMORY),
-                errmsg("could not create OpenSSL BIO structure")));
-
-   (void) BIO_set_close(membuf, BIO_CLOSE);
-   for (i = 0; i < count; i++)
-   {
-       e = X509_NAME_get_entry(name, i);
-       nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
-       if (nid == NID_undef)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                    errmsg("could not get NID for ASN1_OBJECT object")));
-       v = X509_NAME_ENTRY_get_data(e);
-       field_name = OBJ_nid2sn(nid);
-       if (field_name == NULL)
-           field_name = OBJ_nid2ln(nid);
-       if (field_name == NULL)
-           ereport(ERROR,
-                   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                    errmsg("could not convert NID %d to an ASN1_OBJECT structure", nid)));
-       BIO_printf(membuf, "/%s=", field_name);
-       ASN1_STRING_print_ex(membuf, v,
-                            ((ASN1_STRFLGS_RFC2253 & ~ASN1_STRFLGS_ESC_MSB)
-                             | ASN1_STRFLGS_UTF8_CONVERT));
-   }
-
-   /* ensure null termination of the BIO's content */
-   nullterm = '\0';
-   BIO_write(membuf, &nullterm, 1);
-   size = BIO_get_mem_data(membuf, &sp);
-   dp = pg_any_to_server(sp, size - 1, PG_UTF8);
-   result = cstring_to_text(dp);
-   if (dp != sp)
-       pfree(dp);
-   if (BIO_free(membuf) != 1)
-       elog(ERROR, "could not free OpenSSL BIO structure");
-
-   PG_RETURN_TEXT_P(result);
-}
-
-
 /*
  * Returns current client certificate subject as one string
  *
@@ -358,9 +297,17 @@ PG_FUNCTION_INFO_V1(ssl_client_dn);
 Datum
 ssl_client_dn(PG_FUNCTION_ARGS)
 {
-   if (!(MyProcPort->peer))
+   char        subject[NAMEDATALEN];
+
+   if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
+       PG_RETURN_NULL();
+
+   be_tls_get_peer_subject_name(MyProcPort, subject, NAMEDATALEN);
+
+   if (!*subject)
        PG_RETURN_NULL();
-   return X509_NAME_to_text(X509_get_subject_name(MyProcPort->peer));
+
+   PG_RETURN_TEXT_P(cstring_to_text(subject));
 }
 
 
@@ -377,9 +324,17 @@ PG_FUNCTION_INFO_V1(ssl_issuer_dn);
 Datum
 ssl_issuer_dn(PG_FUNCTION_ARGS)
 {
-   if (!(MyProcPort->peer))
+   char        issuer[NAMEDATALEN];
+
+   if (!MyProcPort->ssl_in_use || !MyProcPort->peer_cert_valid)
        PG_RETURN_NULL();
-   return X509_NAME_to_text(X509_get_issuer_name(MyProcPort->peer));
+
+   be_tls_get_peer_issuer_name(MyProcPort, issuer, NAMEDATALEN);
+
+   if (!*issuer)
+       PG_RETURN_NULL();
+
+   PG_RETURN_TEXT_P(cstring_to_text(issuer));
 }
 
 
index e16f61b41d72c34d62971e00c3a8f2c29656f67c..3213c039ca67123dcc54cdfdaf49c0610ece2f0a 100644 (file)
@@ -53,8 +53,8 @@
     </term>
     <listitem>
     <para>
-     Returns the name of the protocol used for the SSL connection (e.g., TLSv1.0
-     TLSv1.1, or TLSv1.2).
+     Returns the name of the protocol used for the SSL connection (e.g., TLSv1.0,
+     TLSv1.1, TLSv1.2 or TLSv1.3).
     </para>
     </listitem>
    </varlistentry>