]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
ocsp: attempt harder to figure an OCSP staple issuer
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 2 Jun 2016 07:20:13 +0000 (09:20 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Thu, 2 Jun 2016 12:34:24 +0000 (14:34 +0200)
That is, check initially against the trust list set on the credentials,
and if verification is not possible attempt with all certificates in
the chain as possible issuers. The reason of this enhancement is the
few servers have an OCSP response signed not by their direct CA but
rather by one of the higher level CAs.

lib/x509.c

index e9b7555d3739445a4035b4fd8d867a663065ceaf..2efd76be05f709d5c840fc8311aedcb2f9c19768 100644 (file)
@@ -66,7 +66,8 @@
  */
 static int
 check_ocsp_response(gnutls_session_t session, gnutls_x509_crt_t cert,
-                   gnutls_x509_crt_t issuer,
+                   gnutls_x509_trust_list_t tl,
+                   gnutls_x509_crt_t *cand_issuers, unsigned cand_issuers_size,
                    gnutls_datum_t * data, unsigned int *ostatus)
 {
        gnutls_ocsp_resp_t resp;
@@ -102,7 +103,28 @@ check_ocsp_response(gnutls_session_t session, gnutls_x509_crt_t cert,
                goto cleanup;
        }
 
-       ret = gnutls_ocsp_resp_verify_direct(resp, issuer, &status, 0);
+       /* Attempt to verify against our trusted list */
+       ret = gnutls_ocsp_resp_verify(resp, tl, &status, 0);
+       if ((ret < 0 || status != 0) && cand_issuers_size > 0) {
+               /* Attempt to verify against the certificate list provided by the server */
+               ret = gnutls_ocsp_resp_verify_direct(resp, cand_issuers[0], &status, 0);
+               /* if verification fails attempt to find whether any of the other
+                * bundled CAs is an issuer of the OCSP response */
+               if ((ret < 0 || status != 0) && cand_issuers_size > 1) {
+                       int ret2;
+                       unsigned status2, i;
+
+                       for (i=1;i<cand_issuers_size;i++) {
+                               ret2 = gnutls_ocsp_resp_verify_direct(resp, cand_issuers[i], &status2, 0);
+                               if (ret2 >= 0 && status2 == 0) {
+                                       status = status2;
+                                       ret = ret2;
+                                       break;
+                               }
+                       }
+               }
+       }
+
        if (ret < 0) {
                ret = gnutls_assert_val(0);
                gnutls_assert();
@@ -248,10 +270,10 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session,
        gnutls_x509_crt_t *peer_certificate_list;
        gnutls_datum_t resp;
        int peer_certificate_list_size, i, x, ret;
-       gnutls_x509_crt_t issuer = NULL;
+       gnutls_x509_crt_t *cand_issuers = NULL;
+       unsigned cand_issuers_size = 0;
        unsigned int ocsp_status = 0;
        unsigned int verify_flags;
-       unsigned issuer_deinit = 0;
 
        /* No OCSP check so far */
        session->internals.ocsp_check_ok = 0;
@@ -330,23 +352,13 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session,
        }
 
        if (peer_certificate_list_size > 1) {
-               issuer = peer_certificate_list[1];
-       } else {
-               ret =
-                   gnutls_x509_trust_list_get_issuer(cred->tlist,
-                                                     peer_certificate_list
-                                                     [0], &issuer, GNUTLS_TL_GET_COPY);
-               if (ret < 0) {
-                       goto skip_ocsp;
-               }
-               issuer_deinit = 1;
+               cand_issuers = &peer_certificate_list[1];
+               cand_issuers_size = peer_certificate_list_size-1;
        }
 
        ret =
-           check_ocsp_response(session, peer_certificate_list[0], issuer,
-                               &resp, &ocsp_status);
-       if (issuer_deinit != 0)
-               gnutls_x509_crt_deinit(issuer);
+           check_ocsp_response(session, peer_certificate_list[0], cred->tlist, cand_issuers,
+                               cand_issuers_size, &resp, &ocsp_status);
 
        if (ret < 0) {
                CLEAR_CERTS;