summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/x509
diff options
context:
space:
mode:
authorbeck <>2015-10-02 15:04:45 +0000
committerbeck <>2015-10-02 15:04:45 +0000
commit61992d68f1934e7e4171e633f39fb76a4654b5a2 (patch)
tree8649498e5e9fdda4e44ebac5989504efbcc57b61 /src/lib/libcrypto/x509
parent5951a0298417b41fc2a1fb4ad8a057fb9530e872 (diff)
downloadopenbsd-61992d68f1934e7e4171e633f39fb76a4654b5a2.tar.gz
openbsd-61992d68f1934e7e4171e633f39fb76a4654b5a2.tar.bz2
openbsd-61992d68f1934e7e4171e633f39fb76a4654b5a2.zip
Flense the greasy black guts of unreadble string parsing code out of three areas
in asn1 and x509 code, all dealing with an ASN1_TIME. This brings the parsing together in one function that converts into a struct tm. While we are at it this also brings us into conformance with RFC 5280 for times allowed in an X509 cert, as OpenSSL is very liberal with what it allows. input and fixes from deraadt@ jsing@ guethther@ and others. ok krw@, guenther@, jsing@
Diffstat (limited to 'src/lib/libcrypto/x509')
-rw-r--r--src/lib/libcrypto/x509/x509_lcl.h1
-rw-r--r--src/lib/libcrypto/x509/x509_vfy.c128
2 files changed, 37 insertions, 92 deletions
diff --git a/src/lib/libcrypto/x509/x509_lcl.h b/src/lib/libcrypto/x509/x509_lcl.h
index b16df78ad7..0c1c130d5c 100644
--- a/src/lib/libcrypto/x509/x509_lcl.h
+++ b/src/lib/libcrypto/x509/x509_lcl.h
@@ -57,3 +57,4 @@
57 */ 57 */
58 58
59int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet); 59int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet);
60int asn1_time_parse(const char *, size_t, struct tm *, int);
diff --git a/src/lib/libcrypto/x509/x509_vfy.c b/src/lib/libcrypto/x509/x509_vfy.c
index 8d4d15668e..c48143f351 100644
--- a/src/lib/libcrypto/x509/x509_vfy.c
+++ b/src/lib/libcrypto/x509/x509_vfy.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_vfy.c,v 1.45 2015/09/14 16:13:39 jsing Exp $ */ 1/* $OpenBSD: x509_vfy.c,v 1.46 2015/10/02 15:04:45 beck Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -1631,106 +1631,50 @@ X509_cmp_current_time(const ASN1_TIME *ctm)
1631 return X509_cmp_time(ctm, NULL); 1631 return X509_cmp_time(ctm, NULL);
1632} 1632}
1633 1633
1634/*
1635 * Compare a possibly unvalidated ASN1_TIME string against a time_t
1636 * using RFC 5280 rules for the time string. If *cmp_time is NULL
1637 * the current system time is used.
1638 *
1639 * XXX NOTE that unlike what you expect a "cmp" function to do in C,
1640 * XXX this one is "special", and returns 0 for error.
1641 *
1642 * Returns:
1643 * -1 if the ASN1_time is earlier than OR the same as *cmp_time.
1644 * 1 if the ASN1_time is later than *cmp_time.
1645 * 0 on error.
1646 */
1634int 1647int
1635X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) 1648X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
1636{ 1649{
1637 char *str; 1650 time_t time1, time2;
1638 ASN1_TIME atm; 1651 struct tm tm1;
1639 long offset; 1652 int ret = 0;
1640 char buff1[24], buff2[24], *p;
1641 int i, j;
1642 1653
1643 p = buff1; 1654 if (cmp_time == NULL)
1644 i = ctm->length; 1655 time2 = time(NULL);
1645 str = (char *)ctm->data; 1656 else
1646 if (ctm->type == V_ASN1_UTCTIME) { 1657 time2 = *cmp_time;
1647 if ((i < 11) || (i > 17))
1648 return 0;
1649 memcpy(p, str, 10);
1650 p += 10;
1651 str += 10;
1652 i -= 10;
1653 } else {
1654 if (i < 13)
1655 return 0;
1656 memcpy(p, str, 12);
1657 p += 12;
1658 str += 12;
1659 i -= 12;
1660 }
1661 1658
1662 if (i < 1) 1659 memset(&tm1, 0, sizeof(tm1));
1663 return 0;
1664 if ((*str == 'Z') || (*str == '-') || (*str == '+')) {
1665 *(p++) = '0';
1666 *(p++) = '0';
1667 } else {
1668 if (i < 2)
1669 return 0;
1670 *(p++) = *(str++);
1671 *(p++) = *(str++);
1672 i -= 2;
1673 if (i < 1)
1674 return 0;
1675 /* Skip any fractional seconds... */
1676 if (*str == '.') {
1677 str++;
1678 i--;
1679 while (i > 1 && (*str >= '0') && (*str <= '9')) {
1680 str++;
1681 i--;
1682 }
1683 }
1684 }
1685 *(p++) = 'Z';
1686 *(p++) = '\0';
1687 1660
1688 if (i < 1) 1661 if (asn1_time_parse(ctm->data, ctm->length, &tm1, 0) == -1)
1689 return 0; 1662 goto out; /* invalid time */
1690 if (*str == 'Z') {
1691 if (i != 1)
1692 return 0;
1693 offset = 0;
1694 } else {
1695 if (i != 5)
1696 return 0;
1697 if ((*str != '+') && (*str != '-'))
1698 return 0;
1699 if (str[1] < '0' || str[1] > '9' ||
1700 str[2] < '0' || str[2] > '9' ||
1701 str[3] < '0' || str[3] > '9' ||
1702 str[4] < '0' || str[4] > '9')
1703 return 0;
1704 offset = ((str[1] - '0') * 10 + (str[2] - '0')) * 60;
1705 offset += (str[3] - '0') * 10 + (str[4] - '0');
1706 if (*str == '-')
1707 offset = -offset;
1708 }
1709 atm.type = ctm->type;
1710 atm.flags = 0;
1711 atm.length = sizeof(buff2);
1712 atm.data = (unsigned char *)buff2;
1713 1663
1714 if (X509_time_adj(&atm, offset * 60, cmp_time) == NULL) 1664 /*
1715 return 0; 1665 * Defensively fail if the time string is not representable as
1666 * a time_t. A time_t must be sane if you care about times after
1667 * Jan 19 2038.
1668 */
1669 if ((time1 = timegm(&tm1)) == -1)
1670 goto out;
1716 1671
1717 if (ctm->type == V_ASN1_UTCTIME) { 1672 if (time1 <= time2)
1718 i = (buff1[0] - '0') * 10 + (buff1[1] - '0'); 1673 ret = -1;
1719 if (i < 50)
1720 i += 100; /* cf. RFC 2459 */
1721 j = (buff2[0] - '0') * 10 + (buff2[1] - '0');
1722 if (j < 50)
1723 j += 100;
1724 if (i < j)
1725 return -1;
1726 if (i > j)
1727 return 1;
1728 }
1729 i = strcmp(buff1, buff2);
1730 if (i == 0) /* wait a second then return younger :-) */
1731 return -1;
1732 else 1674 else
1733 return i; 1675 ret = 1;
1676 out:
1677 return (ret);
1734} 1678}
1735 1679
1736ASN1_TIME * 1680ASN1_TIME *