]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Adds a new API gnutls_session_set_verify_output_function() that allows TLS applications
authorSahana Prasad <sahana@redhat.com>
Mon, 28 Sep 2020 08:21:40 +0000 (10:21 +0200)
committerSahana Prasad <sahana@redhat.com>
Tue, 10 Nov 2020 13:30:10 +0000 (14:30 +0100)
to have a way to pass the gnutls_verify_output_function() as a callback so that the full
path of the certificate chain to the trusted root can be avaiable as output.

Signed-off-by: Sahana Prasad <sahana@redhat.com>
NEWS
devel/libgnutls-latest-x86_64.abi
devel/symbols.last
doc/Makefile.am
doc/manpages/Makefile.am
lib/cert-cred.c
lib/cert-session.c
lib/gnutls_int.h
lib/includes/gnutls/x509.h
lib/libgnutls.map
tests/auto-verify.c

diff --git a/NEWS b/NEWS
index bc102b4eafabe8553b0ff5b637e6be75220bc412..c8fc9673103a798f6aa0b5a856f2536d59998f1f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,10 +10,15 @@ See the end for copying conditions.
 ** libgnutls: Added a new API that provides a callback function to
    retrieve missing certificates from incomplete certificate chains (#202).
 
+** libgnutls: Added a new API that provides a callback function to
+   output the complete path to the trusted root during certificate
+   chain verification (#1012)
+
 ** API and ABI modifications:
 gnutls_x509_trust_list_set_getissuer_function: Added
 gnutls_x509_trust_list_get_ptr: Added
 gnutls_x509_trust_list_set_ptr: Added
+gnutls_session_set_verify_output_function: Added
 
 * Version 3.6.14 (released 2020-06-03)
 
index f58dde4240502660de8dc35e43c51a70fefe13f8..9bf92f8bcd83bdc763cdb1b3cf47e0d884d3ad2d 100644 (file)
     <elf-symbol name='gnutls_session_set_verify_cert2' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='gnutls_session_set_verify_cert' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='gnutls_session_set_verify_function' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+    <elf-symbol name='gnutls_session_set_verify_output_function' version='GNUTLS_3_7_0' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='gnutls_session_supplemental_register' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='gnutls_session_ticket_enable_client' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
     <elf-symbol name='gnutls_session_ticket_enable_server' version='GNUTLS_3_4' is-default-version='yes' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
index c671c3dcda0beec640fb391b0ddfa0581ebb23e1..1f8fa4f50c433b576dd6f414457ff667c28da45e 100644 (file)
@@ -780,6 +780,7 @@ gnutls_session_set_ptr@GNUTLS_3_4
 gnutls_session_set_verify_cert2@GNUTLS_3_4
 gnutls_session_set_verify_cert@GNUTLS_3_4
 gnutls_session_set_verify_function@GNUTLS_3_4
+gnutls_session_set_verify_output_function@GNUTLS_3_7_0
 gnutls_session_supplemental_register@GNUTLS_3_4
 gnutls_session_ticket_enable_client@GNUTLS_3_4
 gnutls_session_ticket_enable_server@GNUTLS_3_4
index e1834016b12a6b6a9714ccb8697f9ef8990626f4..2e71f4a6192a5c7605f5878562bf47048b83d3d8 100644 (file)
@@ -1975,6 +1975,8 @@ FUNCS += functions/gnutls_session_set_verify_cert2
 FUNCS += functions/gnutls_session_set_verify_cert2.short
 FUNCS += functions/gnutls_session_set_verify_function
 FUNCS += functions/gnutls_session_set_verify_function.short
+FUNCS += functions/gnutls_session_set_verify_output_function
+FUNCS += functions/gnutls_session_set_verify_output_function.short
 FUNCS += functions/gnutls_session_supplemental_register
 FUNCS += functions/gnutls_session_supplemental_register.short
 FUNCS += functions/gnutls_session_ticket_enable_client
index c1043bca4a545081cc1a2def0f2068b81e8779bf..21621af9d73c81eb34c4ad98d5c94812055affa9 100644 (file)
@@ -789,6 +789,7 @@ APIMANS += gnutls_session_set_ptr.3
 APIMANS += gnutls_session_set_verify_cert.3
 APIMANS += gnutls_session_set_verify_cert2.3
 APIMANS += gnutls_session_set_verify_function.3
+APIMANS += gnutls_session_set_verify_output_function.3
 APIMANS += gnutls_session_supplemental_register.3
 APIMANS += gnutls_session_ticket_enable_client.3
 APIMANS += gnutls_session_ticket_enable_server.3
index 06a705433054fc070f3fb1d6ee91da5817eb3084..96f554408478b4f4b2b1696b1d96935c987ce3d0 100644 (file)
@@ -949,6 +949,38 @@ void *gnutls_x509_trust_list_get_ptr(gnutls_x509_trust_list_t tlist)
        return tlist->usr_ptr;
 }
 
+/**
+ * gnutls_session_set_verify_output_function:
+ * @session: is a #gnutls_x509_trust_list_t type.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called when the peer's certificate
+ * chain has to be verified and full path to the trusted root has to be
+ * printed.
+ *
+ * The callback's function prototype is defined in `x509.h':
+ * int (*callback)(
+ * gnutls_x509_crt_t cert,
+ * gnutls_x509_crt_t issuer,
+ * gnutls_x509_crl_t crl,
+ * unsigned int verification_output);
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * certificate verification procedure.
+ * To verify the certificate chain and print its path uptp the trusted root,
+ * functions such as gnutls_certificate_verify_peers(),
+ * gnutls_x509_trust_list_verify_crt(), and gnutls_x509_trust_list_verify_crt2()
+ * can be used. The callback is set in _gnutls_verify_crt_status() and
+ * _gnutls_pkcs11_verify_crt_status().
+ *
+ * Since: 3.7.0
+ **/
+void gnutls_session_set_verify_output_function(gnutls_session_t session,
+               gnutls_verify_output_function * func)
+{
+       session->internals.cert_output_callback = func;
+}
+
 #define TEST_TEXT "test text"
 /* returns error if the certificate has different algorithm than
  * the given key parameters.
index 86fa5868d0c0cd02fbb8f0546e40de04324c4bae..9b03600f3b3cdc526e33068ab09a9108e2de2981 100644 (file)
@@ -568,7 +568,7 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session,
                ret =
                        check_ocsp_response(session,
                                            peer_certificate_list[i],
-                                           cred->tlist, 
+                                           cred->tlist,
                                            verify_flags, cand_issuers,
                                            cand_issuers_size,
                                            &resp, &ocsp_status);
@@ -581,14 +581,25 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session,
 #endif
 
       skip_ocsp:
-       /* Verify certificate 
+       /* Verify certificate
         */
-       ret =
-           gnutls_x509_trust_list_verify_crt2(cred->tlist,
-                                              peer_certificate_list,
-                                              peer_certificate_list_size,
-                                              data, elements,
-                                              verify_flags, status, NULL);
+       if (session->internals.cert_output_callback != NULL) {
+               _gnutls_debug_log("Print full certificate path validation to trust root.\n");
+           ret =
+               gnutls_x509_trust_list_verify_crt2(cred->tlist,
+                                                  peer_certificate_list,
+                                                  peer_certificate_list_size,
+                                                  data, elements,
+                                                  verify_flags, status,
+                                                  session->internals.cert_output_callback);
+       } else {
+           ret =
+               gnutls_x509_trust_list_verify_crt2(cred->tlist,
+                                                  peer_certificate_list,
+                                                  peer_certificate_list_size,
+                                                  data, elements,
+                                                  verify_flags, status, NULL);
+       }
 
        if (ret < 0) {
                gnutls_assert();
index 31cec5c0cddbe2562d726368bebc5bba224f534c..4c82312e67ece1a5fc3992cae5b85ba3f17ba701 100644 (file)
@@ -1196,6 +1196,11 @@ typedef struct {
         */
        gnutls_certificate_request_t send_cert_req;
 
+       /* callback to print the full path of certificate
+        * validation to the trusted root.
+        */
+       gnutls_verify_output_function *cert_output_callback;
+
        size_t max_handshake_data_buffer_size;
 
        /* PUSH & PULL functions.
index c0c509dc11d63f7c7d77f400602fc63952023fcb..001aeb77db5f7280b19c71ad4270d0256defc401 100644 (file)
@@ -1622,15 +1622,19 @@ gnutls_x509_trust_list_iter_get_ca(gnutls_x509_trust_list_t list,
 
 void gnutls_x509_trust_list_iter_deinit(gnutls_x509_trust_list_iter_t iter);
 
-typedef int gnutls_verify_output_function(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,    /* The issuer if verification failed 
+typedef int gnutls_verify_output_function(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
+                                                                                                /* The issuer if verification failed
                                                                                                 * because of him. might be null.
                                                                                                 */
                                          gnutls_x509_crl_t crl,        /* The CRL that caused verification failure 
-                                                                        * if any. Might be null. 
+                                                                        * if any. Might be null.
                                                                         */
                                          unsigned int
                                          verification_output);
 
+void gnutls_session_set_verify_output_function(gnutls_session_t session,
+               gnutls_verify_output_function * func);
+
 int gnutls_x509_trust_list_verify_named_crt
     (gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert,
      const void *name, size_t name_size, unsigned int flags,
index 643d400a1f0452dede03e1e9ebc5d72fa35053e3..98b7319c4468015d73ff9c3c6510c9d653169a89 100644 (file)
@@ -1337,6 +1337,7 @@ GNUTLS_3_7_0
        gnutls_x509_trust_list_set_getissuer_function;
        gnutls_x509_trust_list_get_ptr;
        gnutls_x509_trust_list_set_ptr;
+       gnutls_session_set_verify_output_function;
  local:
        *;
 } GNUTLS_3_4;
index 34cae5ccd2d3c8bb22d08416949be0f436f80204..dd3b397c2eb7462944e07795b804909c4840baf6 100644 (file)
@@ -180,6 +180,144 @@ const gnutls_datum_t server_key = { server_key_pem,
        sizeof(server_key_pem)
 };
 
+static void print_verification_res(unsigned int output)
+{
+       gnutls_datum_t pout;
+       int ret;
+
+       if (output) {
+               success("Not verified.");
+       } else {
+               success("Verified.");
+       }
+
+       ret =
+           gnutls_certificate_verification_status_print(output,
+                                                        GNUTLS_CRT_X509,
+                                                        &pout, 0);
+       if (ret < 0) {
+               fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
+               exit(1);
+       }
+
+       success(" %s", pout.data);
+       gnutls_free(pout.data);
+}
+
+static const char *get_signature_algo(gnutls_x509_crt_t crt)
+{
+       int ret;
+       static char oid[128];
+
+       ret = gnutls_x509_crt_get_signature_algorithm(crt);
+       if (ret < 0 || ret == GNUTLS_SIGN_UNKNOWN) {
+               size_t oid_size = sizeof(oid);
+               ret = gnutls_x509_crt_get_signature_oid(crt, oid, &oid_size);
+               if (ret < 0)
+                       return NULL;
+               return oid;
+       }
+
+       return gnutls_sign_get_name(ret);
+}
+
+static int cert_out_callback(gnutls_x509_crt_t cert,
+                                gnutls_x509_crt_t issuer,
+                                gnutls_x509_crl_t crl,
+                                unsigned int verification_output)
+{
+       char tmp[255];
+       size_t tmp_size;
+       gnutls_datum_t name = {NULL,0}, issuer_name = {NULL,0};
+       gnutls_datum_t serial = {NULL,0};
+       int ret;
+
+       success("Printing full certificate path validation to trust root.\n");
+
+       ret =
+           gnutls_x509_crt_get_issuer_dn3(cert, &issuer_name, 0);
+       if (ret < 0) {
+               fprintf(stderr, "gnutls_x509_crt_get_issuer_dn: %s\n",
+                       gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_x509_crt_get_dn3(cert, &name, 0);
+       if (ret < 0) {
+               if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+                       name.data = 0;
+                       name.size = 0;
+               } else {
+                       fprintf(stderr, "gnutls_x509_crt_get_dn: %s\n",
+                               gnutls_strerror(ret));
+                       exit(1);
+               }
+       }
+
+       success("\tSubject: %s\n", name.data);
+       success("\tIssuer: %s\n", issuer_name.data);
+
+       if (issuer != NULL) {
+               gnutls_free(issuer_name.data);
+               ret =
+                   gnutls_x509_crt_get_dn3(issuer, &issuer_name, 0);
+               if (ret < 0) {
+                       fprintf(stderr,
+                               "gnutls_x509_crt_get_issuer_dn: %s\n",
+                               gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               success("\tChecked against: %s\n", issuer_name.data);
+       }
+
+       success("\tSignature algorithm: %s\n", get_signature_algo(cert));
+
+       if (crl != NULL) {
+               gnutls_datum_t data;
+               gnutls_free(issuer_name.data);
+
+               ret =
+                   gnutls_x509_crl_get_issuer_dn3(crl, &issuer_name, 0);
+               if (ret < 0) {
+                       fprintf(stderr,
+                               "gnutls_x509_crl_get_issuer_dn: %s\n",
+                               gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               tmp_size = sizeof(tmp);
+               ret =
+                   gnutls_x509_crl_get_number(crl, tmp, &tmp_size, NULL);
+               if (ret < 0) {
+                       serial.data = (void*)gnutls_strdup("unnumbered");
+               } else {
+                       data.data = (void *) tmp;
+                       data.size = tmp_size;
+
+                       ret = gnutls_hex_encode2(&data, &serial);
+                       if (ret < 0) {
+                               fprintf(stderr, "gnutls_hex_encode: %s\n",
+                                       gnutls_strerror(ret));
+                               exit(1);
+                       }
+               }
+               success("\tChecked against CRL[%s] of: %s\n",
+                       serial.data, issuer_name.data);
+       }
+
+       success("\tOutput: ");
+       print_verification_res(verification_output);
+
+       success("\n\n");
+
+       gnutls_free(serial.data);
+       gnutls_free(name.data);
+       gnutls_free(issuer_name.data);
+
+       return 0;
+}
+
 static
 void test_failure(const char *name, const char *prio)
 {
@@ -267,6 +405,7 @@ void test_failure(const char *name, const char *prio)
        if (ret < 0)
                exit(1);
 
+       gnutls_session_set_verify_output_function(client, cert_out_callback);
        assert(gnutls_priority_set_direct(client, prio, NULL) >= 0);
        gnutls_transport_set_push_function(client, client_push);
        gnutls_transport_set_pull_function(client, client_pull);