aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2012-10-02 09:36:16 -0400
committerRusty Russell <rusty@rustcorp.com.au>2012-10-10 05:36:37 -0400
commita5752d11b3853fcdb48b303573dd39b09d05e500 (patch)
treefdbf54986ce97f473661d62510a513bb4ba79aa9
parentd5b719365ec13ef825f2548ba54903b9d029238c (diff)
MODSIGN: Fix 32-bit overflow in X.509 certificate validity date checking
The current choice of lifetime for the autogenerated X.509 of 100 years, putting the validTo date in 2112, causes problems on 32-bit systems where a 32-bit time_t wraps in 2106. 64-bit x86_64 systems seem to be unaffected. This can result in something like: Loading module verification certificates X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 has expired MODSIGN: Problem loading in-kernel X.509 certificate (-127) Or: X.509: Cert 6e03943da0f3b015ba6ed7f5e0cac4fe48680994 is not yet valid MODSIGN: Problem loading in-kernel X.509 certificate (-129) Instead of turning the dates into time_t values and comparing, turn the system clock and the ASN.1 dates into tm structs and compare those piecemeal instead. Reported-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: David Howells <dhowells@redhat.com> Acked-by: Josh Boyer <jwboyer@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--crypto/asymmetric_keys/x509_cert_parser.c25
-rw-r--r--crypto/asymmetric_keys/x509_parser.h4
-rw-r--r--crypto/asymmetric_keys/x509_public_key.c42
3 files changed, 51 insertions, 20 deletions
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 8fcac9493b7a..db07e8c9c883 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -434,11 +434,10 @@ int x509_process_extension(void *context, size_t hdrlen,
434/* 434/*
435 * Record a certificate time. 435 * Record a certificate time.
436 */ 436 */
437static int x509_note_time(time_t *_time, size_t hdrlen, 437static int x509_note_time(struct tm *tm, size_t hdrlen,
438 unsigned char tag, 438 unsigned char tag,
439 const unsigned char *value, size_t vlen) 439 const unsigned char *value, size_t vlen)
440{ 440{
441 unsigned YY, MM, DD, hh, mm, ss;
442 const unsigned char *p = value; 441 const unsigned char *p = value;
443 442
444#define dec2bin(X) ((X) - '0') 443#define dec2bin(X) ((X) - '0')
@@ -448,30 +447,30 @@ static int x509_note_time(time_t *_time, size_t hdrlen,
448 /* UTCTime: YYMMDDHHMMSSZ */ 447 /* UTCTime: YYMMDDHHMMSSZ */
449 if (vlen != 13) 448 if (vlen != 13)
450 goto unsupported_time; 449 goto unsupported_time;
451 YY = DD2bin(p); 450 tm->tm_year = DD2bin(p);
452 if (YY > 50) 451 if (tm->tm_year >= 50)
453 YY += 1900; 452 tm->tm_year += 1900;
454 else 453 else
455 YY += 2000; 454 tm->tm_year += 2000;
456 } else if (tag == ASN1_GENTIM) { 455 } else if (tag == ASN1_GENTIM) {
457 /* GenTime: YYYYMMDDHHMMSSZ */ 456 /* GenTime: YYYYMMDDHHMMSSZ */
458 if (vlen != 15) 457 if (vlen != 15)
459 goto unsupported_time; 458 goto unsupported_time;
460 YY = DD2bin(p) * 100 + DD2bin(p); 459 tm->tm_year = DD2bin(p) * 100 + DD2bin(p);
461 } else { 460 } else {
462 goto unsupported_time; 461 goto unsupported_time;
463 } 462 }
464 463
465 MM = DD2bin(p); 464 tm->tm_year -= 1900;
466 DD = DD2bin(p); 465 tm->tm_mon = DD2bin(p) - 1;
467 hh = DD2bin(p); 466 tm->tm_mday = DD2bin(p);
468 mm = DD2bin(p); 467 tm->tm_hour = DD2bin(p);
469 ss = DD2bin(p); 468 tm->tm_min = DD2bin(p);
469 tm->tm_sec = DD2bin(p);
470 470
471 if (*p != 'Z') 471 if (*p != 'Z')
472 goto unsupported_time; 472 goto unsupported_time;
473 473
474 *_time = mktime(YY, MM, DD, hh, mm, ss);
475 return 0; 474 return 0;
476 475
477unsupported_time: 476unsupported_time:
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 635053f7e962..f86dc5fcc4ad 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -18,8 +18,8 @@ struct x509_certificate {
18 char *subject; /* Name of certificate subject */ 18 char *subject; /* Name of certificate subject */
19 char *fingerprint; /* Key fingerprint as hex */ 19 char *fingerprint; /* Key fingerprint as hex */
20 char *authority; /* Authority key fingerprint as hex */ 20 char *authority; /* Authority key fingerprint as hex */
21 time_t valid_from; 21 struct tm valid_from;
22 time_t valid_to; 22 struct tm valid_to;
23 enum pkey_algo pkey_algo : 8; /* Public key algorithm */ 23 enum pkey_algo pkey_algo : 8; /* Public key algorithm */
24 enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */ 24 enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
25 enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */ 25 enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 716917ce0907..5ab736db94a9 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -106,7 +106,7 @@ error_no_sig:
106static int x509_key_preparse(struct key_preparsed_payload *prep) 106static int x509_key_preparse(struct key_preparsed_payload *prep)
107{ 107{
108 struct x509_certificate *cert; 108 struct x509_certificate *cert;
109 time_t now; 109 struct tm now;
110 size_t srlen, sulen; 110 size_t srlen, sulen;
111 char *desc = NULL; 111 char *desc = NULL;
112 int ret; 112 int ret;
@@ -118,7 +118,14 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
118 pr_devel("Cert Issuer: %s\n", cert->issuer); 118 pr_devel("Cert Issuer: %s\n", cert->issuer);
119 pr_devel("Cert Subject: %s\n", cert->subject); 119 pr_devel("Cert Subject: %s\n", cert->subject);
120 pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]); 120 pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
121 pr_devel("Cert Valid: %lu - %lu\n", cert->valid_from, cert->valid_to); 121 printk("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
122 cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
123 cert->valid_from.tm_mday, cert->valid_from.tm_hour,
124 cert->valid_from.tm_min, cert->valid_from.tm_sec);
125 printk("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
126 cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
127 cert->valid_to.tm_mday, cert->valid_to.tm_hour,
128 cert->valid_to.tm_min, cert->valid_to.tm_sec);
122 pr_devel("Cert Signature: %s + %s\n", 129 pr_devel("Cert Signature: %s + %s\n",
123 pkey_algo[cert->sig_pkey_algo], 130 pkey_algo[cert->sig_pkey_algo],
124 pkey_hash_algo[cert->sig_hash_algo]); 131 pkey_hash_algo[cert->sig_hash_algo]);
@@ -130,13 +137,38 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
130 goto error_free_cert; 137 goto error_free_cert;
131 } 138 }
132 139
133 now = CURRENT_TIME.tv_sec; 140 time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
134 if (now < cert->valid_from) { 141 printk("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
142 now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
143 now.tm_hour, now.tm_min, now.tm_sec);
144 if (now.tm_year < cert->valid_from.tm_year ||
145 (now.tm_year == cert->valid_from.tm_year &&
146 (now.tm_mon < cert->valid_from.tm_mon ||
147 (now.tm_mon == cert->valid_from.tm_mon &&
148 (now.tm_mday < cert->valid_from.tm_mday ||
149 (now.tm_mday == cert->valid_from.tm_mday &&
150 (now.tm_hour < cert->valid_from.tm_hour ||
151 (now.tm_hour == cert->valid_from.tm_hour &&
152 (now.tm_min < cert->valid_from.tm_min ||
153 (now.tm_min == cert->valid_from.tm_min &&
154 (now.tm_sec < cert->valid_from.tm_sec
155 ))))))))))) {
135 pr_warn("Cert %s is not yet valid\n", cert->fingerprint); 156 pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
136 ret = -EKEYREJECTED; 157 ret = -EKEYREJECTED;
137 goto error_free_cert; 158 goto error_free_cert;
138 } 159 }
139 if (now >= cert->valid_to) { 160 if (now.tm_year > cert->valid_to.tm_year ||
161 (now.tm_year == cert->valid_to.tm_year &&
162 (now.tm_mon > cert->valid_to.tm_mon ||
163 (now.tm_mon == cert->valid_to.tm_mon &&
164 (now.tm_mday > cert->valid_to.tm_mday ||
165 (now.tm_mday == cert->valid_to.tm_mday &&
166 (now.tm_hour > cert->valid_to.tm_hour ||
167 (now.tm_hour == cert->valid_to.tm_hour &&
168 (now.tm_min > cert->valid_to.tm_min ||
169 (now.tm_min == cert->valid_to.tm_min &&
170 (now.tm_sec > cert->valid_to.tm_sec
171 ))))))))))) {
140 pr_warn("Cert %s has expired\n", cert->fingerprint); 172 pr_warn("Cert %s has expired\n", cert->fingerprint);
141 ret = -EKEYEXPIRED; 173 ret = -EKEYEXPIRED;
142 goto error_free_cert; 174 goto error_free_cert;