1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
Description: Fix CVE-2014-8155: missing date/time checks on CA certificates
Patch backported by Raphaƫl Hertzog.
Origin: backport, https://gitlab.com/gnutls/gnutls/commit/897cbce62c0263a498088ac3e465aa5f05f8719c
Last-Update: 2015-03-23
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -511,7 +511,11 @@ extern "C"
* periods of certificate chains. Don't set this unless you
* understand the security implications.
*/
- GNUTLS_VERIFY_DISABLE_TIME_CHECKS = 64
+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS = 64,
+
+ /* If set a signer in the trusted list is never checked for expiration
+ * or activation. */
+ GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS = 128,
} gnutls_certificate_verify_flags;
int gnutls_x509_crt_check_issuer (gnutls_x509_crt_t cert,
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -41,7 +41,7 @@
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);
@@ -259,17 +259,17 @@ find_issuer (gnutls_x509_crt_t cert,
* '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 = 0;
if (output)
@@ -296,6 +296,8 @@ _gnutls_verify_certificate2 (gnutls_x509
return 0;
}
+ if (_issuer != NULL) *_issuer = issuer;
+
issuer_version = gnutls_x509_crt_get_version (issuer);
if (issuer_version < 0)
{
@@ -398,6 +400,29 @@ gnutls_x509_crt_check_issuer (gnutls_x50
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.
*
@@ -416,6 +441,8 @@ _gnutls_x509_verify_certificate (const g
{
int i = 0, ret;
unsigned int status = 0, output;
+ time_t now = time (0);
+ gnutls_x509_crt_t issuer = NULL;
if (clist_size > 1)
{
@@ -451,6 +478,17 @@ _gnutls_x509_verify_certificate (const g
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;
}
@@ -466,7 +504,7 @@ _gnutls_x509_verify_certificate (const g
* 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
@@ -499,23 +537,27 @@ _gnutls_x509_verify_certificate (const g
*/
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;
}
}
@@ -536,7 +578,7 @@ _gnutls_x509_verify_certificate (const g
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;
@@ -999,7 +1041,7 @@ gnutls_x509_crt_verify (gnutls_x509_crt_
*/
ret =
_gnutls_verify_certificate2 (cert, CA_list, CA_list_length, flags,
- verify);
+ verify, NULL);
if (ret < 0)
{
gnutls_assert ();
|