Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PKCS#7: Improve and export the X.509 ASN.1 time object decoder

Make the X.509 ASN.1 time object decoder fill in a time64_t rather than a
struct tm to make comparison easier (unfortunately, this makes readable
display less easy) and export it so that it can be used by the PKCS#7 code
too.

Further, tighten up its parsing to reject invalid dates (eg. weird
characters, non-existent hour numbers) and unsupported dates (eg. timezones
other than 'Z' or dates earlier than 1970).

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: David Woodhouse <David.Woodhouse@intel.com>

+72 -31
+66 -21
crypto/asymmetric_keys/x509_cert_parser.c
··· 472 472 return 0; 473 473 } 474 474 475 - /* 476 - * Record a certificate time. 475 + /** 476 + * x509_decode_time - Decode an X.509 time ASN.1 object 477 + * @_t: The time to fill in 478 + * @hdrlen: The length of the object header 479 + * @tag: The object tag 480 + * @value: The object value 481 + * @vlen: The size of the object value 482 + * 483 + * Decode an ASN.1 universal time or generalised time field into a struct the 484 + * kernel can handle and check it for validity. The time is decoded thus: 485 + * 486 + * [RFC5280 §4.1.2.5] 487 + * CAs conforming to this profile MUST always encode certificate validity 488 + * dates through the year 2049 as UTCTime; certificate validity dates in 489 + * 2050 or later MUST be encoded as GeneralizedTime. Conforming 490 + * applications MUST be able to process validity dates that are encoded in 491 + * either UTCTime or GeneralizedTime. 477 492 */ 478 - static int x509_note_time(struct tm *tm, size_t hdrlen, 479 - unsigned char tag, 480 - const unsigned char *value, size_t vlen) 493 + int x509_decode_time(time64_t *_t, size_t hdrlen, 494 + unsigned char tag, 495 + const unsigned char *value, size_t vlen) 481 496 { 497 + static const unsigned char month_lengths[] = { 31, 29, 31, 30, 31, 30, 498 + 31, 31, 30, 31, 30, 31 }; 482 499 const unsigned char *p = value; 500 + unsigned year, mon, day, hour, min, sec, mon_len; 483 501 484 - #define dec2bin(X) ((X) - '0') 502 + #define dec2bin(X) ({ unsigned char x = (X) - '0'; if (x > 9) goto invalid_time; x; }) 485 503 #define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; }) 486 504 487 505 if (tag == ASN1_UNITIM) { 488 506 /* UTCTime: YYMMDDHHMMSSZ */ 489 507 if (vlen != 13) 490 508 goto unsupported_time; 491 - tm->tm_year = DD2bin(p); 492 - if (tm->tm_year >= 50) 493 - tm->tm_year += 1900; 509 + year = DD2bin(p); 510 + if (year >= 50) 511 + year += 1900; 494 512 else 495 - tm->tm_year += 2000; 513 + year += 2000; 496 514 } else if (tag == ASN1_GENTIM) { 497 515 /* GenTime: YYYYMMDDHHMMSSZ */ 498 516 if (vlen != 15) 499 517 goto unsupported_time; 500 - tm->tm_year = DD2bin(p) * 100 + DD2bin(p); 518 + year = DD2bin(p) * 100 + DD2bin(p); 519 + if (year >= 1950 && year <= 2049) 520 + goto invalid_time; 501 521 } else { 502 522 goto unsupported_time; 503 523 } 504 524 505 - tm->tm_year -= 1900; 506 - tm->tm_mon = DD2bin(p) - 1; 507 - tm->tm_mday = DD2bin(p); 508 - tm->tm_hour = DD2bin(p); 509 - tm->tm_min = DD2bin(p); 510 - tm->tm_sec = DD2bin(p); 525 + mon = DD2bin(p); 526 + day = DD2bin(p); 527 + hour = DD2bin(p); 528 + min = DD2bin(p); 529 + sec = DD2bin(p); 511 530 512 531 if (*p != 'Z') 513 532 goto unsupported_time; 514 533 534 + mon_len = month_lengths[mon]; 535 + if (mon == 2) { 536 + if (year % 4 == 0) { 537 + mon_len = 29; 538 + if (year % 100 == 0) { 539 + year /= 100; 540 + if (year % 4 != 0) 541 + mon_len = 28; 542 + } 543 + } 544 + } 545 + 546 + if (year < 1970 || 547 + mon < 1 || mon > 12 || 548 + day < 1 || day > mon_len || 549 + hour < 0 || hour > 23 || 550 + min < 0 || min > 59 || 551 + sec < 0 || sec > 59) 552 + goto invalid_time; 553 + 554 + *_t = mktime64(year, mon, day, hour, min, sec); 515 555 return 0; 516 556 517 557 unsupported_time: 518 - pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n", 519 - tag, (int)vlen, (int)vlen, value); 558 + pr_debug("Got unsupported time [tag %02x]: '%*phN'\n", 559 + tag, (int)vlen, value); 560 + return -EBADMSG; 561 + invalid_time: 562 + pr_debug("Got invalid time [tag %02x]: '%*phN'\n", 563 + tag, (int)vlen, value); 520 564 return -EBADMSG; 521 565 } 566 + EXPORT_SYMBOL_GPL(x509_decode_time); 522 567 523 568 int x509_note_not_before(void *context, size_t hdrlen, 524 569 unsigned char tag, 525 570 const void *value, size_t vlen) 526 571 { 527 572 struct x509_parse_context *ctx = context; 528 - return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); 573 + return x509_decode_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen); 529 574 } 530 575 531 576 int x509_note_not_after(void *context, size_t hdrlen, ··· 578 533 const void *value, size_t vlen) 579 534 { 580 535 struct x509_parse_context *ctx = context; 581 - return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); 536 + return x509_decode_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen); 582 537 } 583 538 584 539 /*
+5 -2
crypto/asymmetric_keys/x509_parser.h
··· 23 23 struct asymmetric_key_id *skid; /* Subject + subjectKeyId (optional) */ 24 24 struct asymmetric_key_id *akid_id; /* CA AuthKeyId matching ->id (optional) */ 25 25 struct asymmetric_key_id *akid_skid; /* CA AuthKeyId matching ->skid (optional) */ 26 - struct tm valid_from; 27 - struct tm valid_to; 26 + time64_t valid_from; 27 + time64_t valid_to; 28 28 const void *tbs; /* Signed data */ 29 29 unsigned tbs_size; /* Size of signed data */ 30 30 unsigned raw_sig_size; /* Size of sigature */ ··· 49 49 */ 50 50 extern void x509_free_certificate(struct x509_certificate *cert); 51 51 extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen); 52 + extern int x509_decode_time(time64_t *_t, size_t hdrlen, 53 + unsigned char tag, 54 + const unsigned char *value, size_t vlen); 52 55 53 56 /* 54 57 * x509_public_key.c
+1 -8
crypto/asymmetric_keys/x509_public_key.c
··· 302 302 } 303 303 304 304 pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]); 305 - pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n", 306 - cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1, 307 - cert->valid_from.tm_mday, cert->valid_from.tm_hour, 308 - cert->valid_from.tm_min, cert->valid_from.tm_sec); 309 - pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n", 310 - cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1, 311 - cert->valid_to.tm_mday, cert->valid_to.tm_hour, 312 - cert->valid_to.tm_min, cert->valid_to.tm_sec); 305 + pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); 313 306 pr_devel("Cert Signature: %s + %s\n", 314 307 pkey_algo_name[cert->sig.pkey_algo], 315 308 hash_algo_name[cert->sig.pkey_hash_algo]);