]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Check the key usage bits during certificate verification.
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 2 Nov 2012 09:38:28 +0000 (10:38 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 2 Nov 2012 12:00:54 +0000 (13:00 +0100)
NEWS
lib/includes/gnutls/gnutls.h.in
lib/x509/verify.c
src/certtool.c
tests/suite/chain
tests/suite/x509paths/README

diff --git a/NEWS b/NEWS
index d18b7e89d214bd909e8372f29f277563a0efc0f0..72ea41a6f181bf19f9e3fa6f00c0ffc1aaabd6f4 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,10 @@ gnutls_certificate_verify_peers3().
 ** libgnutls: Added support for extension to establish keys
 for SRTP.
 
+** libgnutls: The X.509 verification functions check the key
+usage bits and output @GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
+if check fails.
+
 ** libgnutls: gnutls_x509_crl_verify() includes the time
 checks.
 
index 61421b635e4f54a72b3f2a3c9c8c2042e0ba629f..5cd3850e3826a2f5d58cc9cc6c6f4f4c55677e7d 100644 (file)
@@ -440,6 +440,8 @@ extern "C"
  * @GNUTLS_CERT_SIGNER_NOT_CA: The certificate's signer was not a CA. This
  *   may happen if this was a version 1 certificate, which is common with 
  *   some CAs, or a version 3 certificate without the basic constrains extension.
+ * @GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE: The certificate's signer constraints were
+ *   violated.
  * @GNUTLS_CERT_INSECURE_ALGORITHM:  The certificate was signed using an insecure
  *   algorithm such as MD2 or MD5. These algorithms have been broken and
  *   should not be trusted.
@@ -447,8 +449,8 @@ extern "C"
  * @GNUTLS_CERT_EXPIRED: The certificate has expired.
  * @GNUTLS_CERT_REVOCATION_DATA_TOO_OLD: The OCSP revocation data are too old.
  * @GNUTLS_CERT_REVOCATION_DATA_INVALID: The OCSP revocation data are invalid.
- * @GNUTLS_CERT_UNEXPECTED_OWNER: The owner is not the expected one.
  * @GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE: The revocation data have a future issue date.
+ * @GNUTLS_CERT_UNEXPECTED_OWNER: The owner is not the expected one.
  *
  * Enumeration of certificate status codes.  Note that the status
  * bits may have different meanings in OpenPGP keys and X.509
@@ -457,17 +459,18 @@ extern "C"
   typedef enum
   {
     GNUTLS_CERT_INVALID = 1<<1,
-    GNUTLS_CERT_REVOKED = 1<<6,
-    GNUTLS_CERT_SIGNER_NOT_FOUND = 1<<7,
-    GNUTLS_CERT_SIGNER_NOT_CA = 1<<8,
-    GNUTLS_CERT_INSECURE_ALGORITHM = 1<<9,
-    GNUTLS_CERT_NOT_ACTIVATED = 1<<10,
-    GNUTLS_CERT_EXPIRED = 1<<11,
-    GNUTLS_CERT_SIGNATURE_FAILURE = 1<<12,
-    GNUTLS_CERT_REVOCATION_DATA_TOO_OLD = 1<<13,
-    GNUTLS_CERT_REVOCATION_DATA_INVALID = 1<<14,
-    GNUTLS_CERT_UNEXPECTED_OWNER = 1<<15,
-    GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE = 1<<16,
+    GNUTLS_CERT_REVOKED = 1<<5,
+    GNUTLS_CERT_SIGNER_NOT_FOUND = 1<<6,
+    GNUTLS_CERT_SIGNER_NOT_CA = 1<<7,
+    GNUTLS_CERT_INSECURE_ALGORITHM = 1<<8,
+    GNUTLS_CERT_NOT_ACTIVATED = 1<<9,
+    GNUTLS_CERT_EXPIRED = 1<<10,
+    GNUTLS_CERT_SIGNATURE_FAILURE = 1<<11,
+    GNUTLS_CERT_REVOCATION_DATA_TOO_OLD = 1<<12,
+    GNUTLS_CERT_REVOCATION_DATA_INVALID = 1<<13,
+    GNUTLS_CERT_UNEXPECTED_OWNER = 1<<14,
+    GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE = 1<<15,
+    GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE = 1<<16,
   } gnutls_certificate_status_t;
 
 /**
index 6ff9258f219a348c88dff68bf2983357a1220768..0f3e625f2dae35066e1cce2f68a79048c7c31a94 100644 (file)
@@ -398,7 +398,7 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
   gnutls_datum_t cert_signature = { NULL, 0 };
   gnutls_x509_crt_t issuer = NULL;
   int issuer_version, result, hash_algo;
-  unsigned int out = 0;
+  unsigned int out = 0, usage;
 
   if (output)
     *output = 0;
@@ -451,6 +451,20 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
           result = 0;
           goto cleanup;
         }
+      
+      result = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
+      if (result >= 0)
+        {
+          if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN))
+            {
+              gnutls_assert();
+              out = GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID;
+              if (output)
+                *output |= out;
+              result = 0;
+              goto cleanup;
+            }
+        }
     }
 
   result =
@@ -978,6 +992,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
   gnutls_x509_crt_t issuer;
   int result, hash_algo;
   time_t now = gnutls_time(0);
+  unsigned int usage;
 
   if (output)
     *output = 0;
@@ -1012,6 +1027,18 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
             *output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
           return 0;
         }
+
+      result = gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
+      if (result >= 0)
+        {
+          if (!(usage & GNUTLS_KEY_CRL_SIGN))
+            {
+              gnutls_assert();
+              if (output)
+                *output |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE | GNUTLS_CERT_INVALID;
+              return 0;
+            }
+        }
     }
 
   result =
index 826e879f03935676510b2bb2c46f08206ca4ccb8..c9506a1318b713594c0df5cf10c01f79ae869186 100644 (file)
@@ -1982,7 +1982,7 @@ static int detailed_verification(gnutls_x509_crt_t cert,
   fprintf (outfile, "\tOutput: ");
   print_verification_res(outfile, verification_output);
 
-  fputs(".\n\n", outfile);
+  fputs("\n\n", outfile);
 
   return 0;
 }
@@ -2075,7 +2075,7 @@ _verify_x509_mem (const void *cert, int cert_size, const void* ca, int ca_size)
   fprintf (outfile, "Chain verification output: ");
   print_verification_res(outfile, output);
 
-  fprintf (outfile, ".\n\n");
+  fprintf (outfile, "\n\n");
 
   gnutls_free(x509_cert_list);
   gnutls_x509_trust_list_deinit(list, 1);
@@ -2098,13 +2098,13 @@ print_verification_res (FILE* outfile, unsigned int output)
     }
   else
     {
-      fprintf (outfile, "Verified");
+      fprintf (outfile, "Verified.");
     }
 
   ret = gnutls_certificate_verification_status_print( output, GNUTLS_CRT_X509, &pout, 0);
   if (ret < 0)
     {
-      fprintf(stderr, "error: %s\n", gnutls_strerror(ret);
+      fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
       exit(EXIT_FAILURE);
     }
 
@@ -2163,11 +2163,9 @@ verify_crl (common_info_st * cinfo)
   size_t size, dn_size;
   char dn[128];
   unsigned int output;
-  int comma = 0;
   int ret;
   gnutls_datum_t pem, pout;
   gnutls_x509_crl_t crl;
-  time_t now = time (0);
   gnutls_x509_crt_t issuer;
 
   issuer = load_ca_cert (cinfo);
@@ -2212,7 +2210,7 @@ verify_crl (common_info_st * cinfo)
   ret = gnutls_certificate_verification_status_print( output, GNUTLS_CRT_X509, &pout, 0);
   if (ret < 0)
     {
-      fprintf(stderr, "error: %s\n", gnutls_strerror(ret);
+      fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
       exit(EXIT_FAILURE);
     }
 
index effb686980b2d6b87a1fd0550a0dd6289e85392d..35bc541c9300c3947b9b033e95e39bd101601c10 100755 (executable)
@@ -24,7 +24,7 @@ CERTTOOL=../../../src/certtool
 
 SUCCESS=" 1 4 7 12 15 16 17 18 24 26 27 30 33 56 57 62 63 "
 FAILURE=" 2 3 5 6 8 9 10 11 13 14 19 20 21 22 23 25 28 29 31 32 54 55 58 59 60 61 "
-KNOWN_BUGS=" 15 16 17 18 19 28 29 31 32 54 55 58 59 60 61 "
+KNOWN_BUGS=" 15 16 17 18 19 31 32 54 55 58 59 60 61 "
 
 cd x509paths
 
@@ -49,14 +49,14 @@ while test -d X509tests/test$i; do
        if echo "$KNOWN_BUGS" | grep " $i " > /dev/null 2>&1; then
                echo "Chain $i verification was skipped due to known bug."
        elif echo "$SUCCESS" | grep " $i " > /dev/null 2>&1; then
-           if grep 'Chain verification output:' out | grep -v 'Chain verification output: Verified\.$' > /dev/null 2>&1; then
+           if grep 'Chain verification output:' out | grep -v 'Chain verification output: Verified\.' > /dev/null 2>&1; then
                echo "Chain $i verification failure UNEXPECTED."
                RET=1
            else
                echo "Chain $i verification success as expected."
            fi
        elif echo "$FAILURE" | grep " $i " >/dev/null 2>&1; then
-           if grep 'Chain verification output:' out | grep -v 'Chain verification output: Verified\.$' > /dev/null 2>&1; then
+           if grep 'Chain verification output:' out | grep -v 'Chain verification output: Verified\.' > /dev/null 2>&1; then
                echo "Chain $i verification failure as expected."
            else
                echo "Chain $i verification success UNEXPECTED. "
index 46450a09b8e5327cb9a43d12fed9f39dd5dbe260..0d5d892b14e85a91cfd4cb20fe361ed1b4fc5902 100644 (file)
@@ -20,12 +20,11 @@ Chain 19: This requires advanced verification that we don't support
 yet. It requires to check that this path contains no revocation data.
 We shouldn't make these tests.
 
-Chain 28-29: We fail to check keyCertSign (non-)critical key usage in
-intermediate certificates.  XXX
-
 Chain 31-32: The CRL is issued by a issuer without CRLSign
 (non-)critical keyCertSign.  We don't check the CRL, so this is not a
 real problem. This is easier to be supported now with the trust_list
-that can verify CRLs on addition.
+that can verify CRLs on addition. (there is an issue there since the
+CRLs that are being added are typically of an intermediate CA which
+is not in the trust list to verify them)
 
 Chain 54-55,58-61: We don't check path length constraints properly. XXX