CVE-2014-8155: DEPRECATED: Code (CWE-17)
value: GnuTLS before 2.9.10 does not verify the activation and expiration dates of CA certificates, which allows man-in-the-middle attackers to spoof servers via a certificate issued by a CA certificate that is (1) not yet valid or (2) no longer valid.
CWE description: This entry has been deprecated.  It was originally used for organizing the Development View (CWE-699) and some other views, but it introduced unnecessary complexity and depth to the resulting tree.
Published: 2015-08-14T18:59Z
Repository: https://gitlab.com/gnutls/gnutls
Language: Other
Files changed: NEWS, lib/includes/gnutls/x509.h, lib/x509/verify.c
Commit date: 2010-03-14 22:57:55 +0100
Commit message: Extended time verification to trusted certificate list as well. Introduced
the flag GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS that will prevent the
trusted certificate list verification.

Diff: diff --git a/NEWS b/NEWS
index b81277ae..c214963f 100644
--- a/NEWS
+++ b/NEWS
@@ -3,10 +3,13 @@ Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
               2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
 See the end for copying conditions.
 
 * Version 2.9.10 (unreleased)
 
+** libgnutls: Time verification extended to trusted certificate list,
+unless GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS flag is specified.
+
 ** libgnutls: Added Steve Dispensa's patch for safe renegotiation (RFC 5746)
 Solves the issue discussed in:
 <http://www.ietf.org/mail-archive/web/tls/current/msg03928.html> and
 <http://www.ietf.org/mail-archive/web/tls/current/msg03948.html>.
 Note that the TLS client implemented here will reject any connections
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 0645e9b1..6ea5f5d6 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -498,10 +498,12 @@ extern "C"
 /**
  * gnutls_certificate_verify_flags:
  * @GNUTLS_VERIFY_DISABLE_CA_SIGN: If set a signer does not have to be
  *   a certificate authority. This flag should normaly be disabled,
  *   unless you know what this means.
+ * @GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS: If set a signer in the trusted
+ *   list is never checked for expiration or activation.
  * @GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT: Allow only trusted CA
  *   certificates that have version 1.  This is safer than
  *   %GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT, and should be used
  *   instead. That way only signers in your trusted list will be
  *   allowed to have certificates of version 1.
@@ -529,11 +531,12 @@ extern "C"
       GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT = 2,
       GNUTLS_VERIFY_DO_NOT_ALLOW_SAME = 4,
       GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT = 8,
       GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2 = 16,
       GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5 = 32,
-      GNUTLS_VERIFY_DISABLE_TIME_CHECKS = 64
+      GNUTLS_VERIFY_DISABLE_TIME_CHECKS = 64,
+      GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS = 128,
     } gnutls_certificate_verify_flags;
 
   int gnutls_x509_crt_check_issuer (gnutls_x509_crt_t cert,
 				    gnutls_x509_crt_t issuer);
 
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index a464596a..5bb20bc9 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -40,11 +40,11 @@
 #include <common.h>
 
 static int _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
 					const gnutls_x509_crt_t * trusted_cas,
 					int tcas_size, unsigned int flags,
-					unsigned int *output);
+					unsigned int *output, gnutls_x509_crt_t* issuer);
 
 static int is_crl_issuer (gnutls_x509_crl_t crl,
 			  gnutls_x509_crt_t issuer_cert);
 
 static int _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
@@ -259,21 +259,21 @@ find_issuer (gnutls_x509_crt_t cert,
  * was successfuly verified.
  *
  * 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
  *
  * Output will hold some extra information about the verification
- * procedure.
+ * procedure. Issuer will hold the actual issuer from the trusted list.
  */
 static int
 _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
 			     const gnutls_x509_crt_t * trusted_cas,
 			     int tcas_size, unsigned int flags,
-			     unsigned int *output)
+			     unsigned int *output, gnutls_x509_crt_t *_issuer)
 {
   gnutls_datum_t cert_signed_data = { NULL, 0 };
   gnutls_datum_t cert_signature = { NULL, 0 };
-  gnutls_x509_crt_t issuer;
+  gnutls_x509_crt_t issuer = NULL;
   int ret, issuer_version, result;
 
   if (output)
     *output = 0;
 
@@ -296,10 +296,12 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
 	*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
       gnutls_assert ();
       return 0;
     }
 
+  if (_issuer != NULL) *_issuer = issuer;
+
   issuer_version = gnutls_x509_crt_get_version (issuer);
   if (issuer_version < 0)
     {
       gnutls_assert ();
       return issuer_version;
@@ -397,10 +399,33 @@ gnutls_x509_crt_check_issuer (gnutls_x509_crt_t cert,
 			      gnutls_x509_crt_t issuer)
 {
   return is_issuer (cert, issuer);
 }
 
+static unsigned int check_time(gnutls_x509_crt_t crt, time_t now)
+{
+int status = 0;
+time_t t;
+
+  t = gnutls_x509_crt_get_activation_time (crt);
+  if (t == (time_t) - 1 || now < t)
+    {
+      status |= GNUTLS_CERT_NOT_ACTIVATED;
+      status |= GNUTLS_CERT_INVALID;
+      return status;
+    }
+
+  t = gnutls_x509_crt_get_expiration_time (crt);
+  if (t == (time_t) - 1 || now > t)
+    {
+      status |= GNUTLS_CERT_EXPIRED;
+      status |= GNUTLS_CERT_INVALID;
+      return status;
+    }
+  
+  return 0;
+}
 
 /* Verify X.509 certificate chain.
  *
  * Note that the return value is an OR of GNUTLS_CERT_* elements.
  *
@@ -415,10 +440,12 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
 				 const gnutls_x509_crl_t * CRLs,
 				 int crls_size, unsigned int flags)
 {
   int i = 0, ret;
   unsigned int status = 0, output;
+  time_t now = time (0);
+  gnutls_x509_crt_t issuer = NULL;
 
   if (clist_size > 1)
     {
       /* Check if the last certificate in the path is self signed.
        * In that case ignore it (a certificate is trusted only if it
@@ -450,10 +477,21 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
 	  for (j = 0; j < tcas_size; j++)
 	    {
 	      if (check_if_same_cert (certificate_list[i],
 				      trusted_cas[j]) == 0)
 		{
+		  /* explicity time check for trusted CA that we remove from
+		   * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
+		   */
+		  if (!(flags&GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags&GNUTLS_VERIFY_DISABLE_TIME_CHECKS))
+		    {
+		      status |= check_time(trusted_cas[j], now);
+		      if (status != 0)
+		        {
+		          return status;
+                        }
+		    }
 		  clist_size = i;
 		  break;
 		}
 	    }
 	  /* clist_size may have been changed which gets out of loop */
@@ -470,11 +508,11 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
    *
    * If no CAs are present returns CERT_INVALID. Thus works
    * in self signed etc certificates.
    */
   ret = _gnutls_verify_certificate2 (certificate_list[clist_size - 1],
-				     trusted_cas, tcas_size, flags, &output);
+				     trusted_cas, tcas_size, flags, &output, &issuer);
   if (ret == 0)
     {
       /* if the last certificate in the certificate
        * list is invalid, then the certificate is not
        * trusted.
@@ -499,31 +537,36 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
 	  return status;
 	}
     }
 #endif
 
+
   /* Check activation/expiration times
    */
   if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS))
     {
-      time_t t, now = time (0);
+      /* check the time of the issuer first */
+      if (!(flags&GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS))
+        {
+          if (issuer == NULL)
+            {
+              gnutls_assert();
+              return GNUTLS_E_INTERNAL_ERROR;
+            }
+
+          status |= check_time(issuer, now);
+          if (status != 0)
+            {
+              return status;
+            }
+        }
 
       for (i = 0; i < clist_size; i++)
 	{
-	  t = gnutls_x509_crt_get_activation_time (certificate_list[i]);
-	  if (t == (time_t) - 1 || now < t)
-	    {
-	      status |= GNUTLS_CERT_NOT_ACTIVATED;
-	      status |= GNUTLS_CERT_INVALID;
-	      return status;
-	    }
-
-	  t = gnutls_x509_crt_get_expiration_time (certificate_list[i]);
-	  if (t == (time_t) - 1 || now > t)
+	  status |= check_time(certificate_list[i], now);
+	  if (status != 0)
 	    {
-	      status |= GNUTLS_CERT_EXPIRED;
-	      status |= GNUTLS_CERT_INVALID;
 	      return status;
 	    }
 	}
     }
 
@@ -540,11 +583,11 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
       if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT))
 	flags &= ~(GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
       if ((ret =
 	   _gnutls_verify_certificate2 (certificate_list[i - 1],
 					&certificate_list[i], 1, flags,
-					NULL)) == 0)
+					NULL, NULL)) == 0)
 	{
 	  status |= GNUTLS_CERT_INVALID;
 	  return status;
 	}
     }
@@ -1007,11 +1050,11 @@ gnutls_x509_crt_verify (gnutls_x509_crt_t cert,
   int ret;
   /* Verify certificate 
    */
   ret =
     _gnutls_verify_certificate2 (cert, CA_list, CA_list_length, flags,
-				 verify);
+				 verify, NULL);
   if (ret < 0)
     {
       gnutls_assert ();
       return ret;
     }

Vulnerable code:       GNUTLS_VERIFY_DISABLE_TIME_CHECKS = 64
					unsigned int *output);
 * procedure.
			     unsigned int *output)
  gnutls_x509_crt_t issuer;
				     trusted_cas, tcas_size, flags, &output);
      time_t t, now = time (0);
	  t = gnutls_x509_crt_get_activation_time (certificate_list[i]);
	  if (t == (time_t) - 1 || now < t)
	    {
	      status |= GNUTLS_CERT_NOT_ACTIVATED;
	      status |= GNUTLS_CERT_INVALID;
	      return status;
	    }

	  t = gnutls_x509_crt_get_expiration_time (certificate_list[i]);
	  if (t == (time_t) - 1 || now > t)
	      status |= GNUTLS_CERT_EXPIRED;
	      status |= GNUTLS_CERT_INVALID;
					NULL)) == 0)
				 verify);
Fixed code: ** libgnutls: Time verification extended to trusted certificate list,
unless GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS flag is specified.

 * @GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS: If set a signer in the trusted
 *   list is never checked for expiration or activation.
      GNUTLS_VERIFY_DISABLE_TIME_CHECKS = 64,
      GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS = 128,
					unsigned int *output, gnutls_x509_crt_t* issuer);
 * procedure. Issuer will hold the actual issuer from the trusted list.
			     unsigned int *output, gnutls_x509_crt_t *_issuer)
  gnutls_x509_crt_t issuer = NULL;
  if (_issuer != NULL) *_issuer = issuer;

static unsigned int check_time(gnutls_x509_crt_t crt, time_t now)
{
int status = 0;
time_t t;

  t = gnutls_x509_crt_get_activation_time (crt);
  if (t == (time_t) - 1 || now < t)
    {
      status |= GNUTLS_CERT_NOT_ACTIVATED;
      status |= GNUTLS_CERT_INVALID;
      return status;
    }

  t = gnutls_x509_crt_get_expiration_time (crt);
  if (t == (time_t) - 1 || now > t)
    {
      status |= GNUTLS_CERT_EXPIRED;
      status |= GNUTLS_CERT_INVALID;
      return status;
    }
  
  return 0;
}
  time_t now = time (0);
  gnutls_x509_crt_t issuer = NULL;
		  /* explicity time check for trusted CA that we remove from
		   * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
		   */
		  if (!(flags&GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags&GNUTLS_VERIFY_DISABLE_TIME_CHECKS))
		    {
		      status |= check_time(trusted_cas[j], now);
		      if (status != 0)
		        {
		          return status;
                        }
		    }
				     trusted_cas, tcas_size, flags, &output, &issuer);

      /* check the time of the issuer first */
      if (!(flags&GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS))
        {
          if (issuer == NULL)
            {
              gnutls_assert();
              return GNUTLS_E_INTERNAL_ERROR;
            }

          status |= check_time(issuer, now);
          if (status != 0)
            {
              return status;
            }
        }
	  status |= check_time(certificate_list[i], now);
	  if (status != 0)
					NULL, NULL)) == 0)
				 verify, NULL);