diff options
author | David Howells <dhowells@redhat.com> | 2012-10-02 09:36:16 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-10-10 05:36:37 -0400 |
commit | a5752d11b3853fcdb48b303573dd39b09d05e500 (patch) | |
tree | fdbf54986ce97f473661d62510a513bb4ba79aa9 | |
parent | d5b719365ec13ef825f2548ba54903b9d029238c (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.c | 25 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 4 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 42 |
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 | */ |
437 | static int x509_note_time(time_t *_time, size_t hdrlen, | 437 | static 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 | ||
477 | unsupported_time: | 476 | unsupported_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: | |||
106 | static int x509_key_preparse(struct key_preparsed_payload *prep) | 106 | static 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; |