From 91bded414d09e84af1f1a3d17fee445ba27766b0 Mon Sep 17 00:00:00 2001 From: Bob Beck Date: Mon, 19 Oct 2015 16:32:38 +0000 Subject: Stop supporing "legcay" time formats that OpenSSL supports. Rewrite the utctime and gentime wrappers accordingly. Along with some other cleanup. this also removes the need for timegm. ok bcook@ sthen@ jsing@ --- lib/libcrypto/asn1/a_gentm.c | 153 -------------- lib/libcrypto/asn1/a_time.c | 117 +---------- lib/libcrypto/asn1/a_time_tm.c | 462 ++++++++++++++++++++++++++++------------- lib/libcrypto/asn1/a_utctm.c | 173 --------------- lib/libcrypto/asn1/asn1_locl.h | 6 +- lib/libcrypto/x509/x509_lcl.h | 1 + lib/libcrypto/x509/x509_vfy.c | 45 ++-- 7 files changed, 348 insertions(+), 609 deletions(-) delete mode 100644 lib/libcrypto/asn1/a_gentm.c delete mode 100644 lib/libcrypto/asn1/a_utctm.c (limited to 'lib') diff --git a/lib/libcrypto/asn1/a_gentm.c b/lib/libcrypto/asn1/a_gentm.c deleted file mode 100644 index 594eb630580..00000000000 --- a/lib/libcrypto/asn1/a_gentm.c +++ /dev/null @@ -1,153 +0,0 @@ -/* $OpenBSD: a_gentm.c,v 1.25 2015/10/02 15:04:45 beck Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -/* GENERALIZEDTIME implementation, written by Steve Henson. Based on UTCTIME */ - -#include -#include -#include - -#include -#include - -#include "o_time.h" -#include "asn1_locl.h" - -int -ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *d) -{ - if (d->type != V_ASN1_GENERALIZEDTIME) - return (0); - return (d->type == asn1_time_parse(d->data, d->length, NULL, d->type)); -} - -int -ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) -{ - ASN1_GENERALIZEDTIME t; - - t.type = V_ASN1_GENERALIZEDTIME; - t.length = strlen(str); - t.data = (unsigned char *)str; - if (ASN1_GENERALIZEDTIME_check(&t)) { - if (s != NULL) { - if (!ASN1_STRING_set((ASN1_STRING *)s, - (unsigned char *)str, t.length)) - return 0; - s->type = V_ASN1_GENERALIZEDTIME; - } - return (1); - } else - return (0); -} - -ASN1_GENERALIZEDTIME * -ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t) -{ - return ASN1_GENERALIZEDTIME_adj(s, t, 0, 0); -} - -static ASN1_GENERALIZEDTIME * -ASN1_GENERALIZEDTIME_adj_internal(ASN1_GENERALIZEDTIME *s, time_t t, - int offset_day, long offset_sec) -{ - char *p; - struct tm *tm; - struct tm data; - - tm = gmtime_r(&t, &data); - if (tm == NULL) - return (NULL); - - if (offset_day || offset_sec) { - if (!OPENSSL_gmtime_adj(tm, offset_day, offset_sec)) - return NULL; - } - - if ((p = gentime_string_from_tm(tm)) == NULL) { - ASN1err(ASN1_F_ASN1_GENERALIZEDTIME_ADJ, ERR_R_MALLOC_FAILURE); - return (NULL); - } - free(s->data); - s->data = p; - s->length = strlen(p); - - s->type = V_ASN1_GENERALIZEDTIME; - return (s); -} - -ASN1_GENERALIZEDTIME * -ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, - long offset_sec) -{ - ASN1_GENERALIZEDTIME *tmp = NULL, *ret; - - if (s == NULL) { - tmp = ASN1_GENERALIZEDTIME_new(); - if (tmp == NULL) - return NULL; - s = tmp; - } - - ret = ASN1_GENERALIZEDTIME_adj_internal(s, t, offset_day, offset_sec); - if (ret == NULL && tmp != NULL) - ASN1_GENERALIZEDTIME_free(tmp); - - return ret; - -} diff --git a/lib/libcrypto/asn1/a_time.c b/lib/libcrypto/asn1/a_time.c index a6c7c8e736a..7a3742fd70b 100644 --- a/lib/libcrypto/asn1/a_time.c +++ b/lib/libcrypto/asn1/a_time.c @@ -1,4 +1,4 @@ -/* $OpenBSD: a_time.c,v 1.26 2015/10/02 15:04:45 beck Exp $ */ +/* $OpenBSD: a_time.c,v 1.27 2015/10/19 16:32:37 beck Exp $ */ /* ==================================================================== * Copyright (c) 1999 The OpenSSL Project. All rights reserved. * @@ -105,118 +105,3 @@ ASN1_TIME_free(ASN1_TIME *a) { ASN1_item_free((ASN1_VALUE *)a, &ASN1_TIME_it); } - -ASN1_TIME * -ASN1_TIME_set(ASN1_TIME *s, time_t t) -{ - return ASN1_TIME_adj(s, t, 0, 0); -} - -ASN1_TIME * -ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec) -{ - struct tm *ts; - struct tm data; - - ts = gmtime_r(&t, &data); - if (ts == NULL) { - ASN1err(ASN1_F_ASN1_TIME_ADJ, ASN1_R_ERROR_GETTING_TIME); - return NULL; - } - if (offset_day || offset_sec) { - if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) - return NULL; - } - if ((ts->tm_year >= 50) && (ts->tm_year < 150)) - return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec); - return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, offset_sec); -} - -int -ASN1_TIME_check(ASN1_TIME *t) -{ - if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) - return 0; - return (t->type == asn1_time_parse(t->data, t->length, NULL, t->type)); -} - -/* Convert an ASN1_TIME structure to GeneralizedTime */ -static ASN1_GENERALIZEDTIME * -ASN1_TIME_to_generalizedtime_internal(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) -{ - ASN1_GENERALIZEDTIME *ret; - char *str; - int newlen; - int i; - - if (!ASN1_TIME_check(t)) - return NULL; - - ret = *out; - - /* If already GeneralizedTime just copy across */ - if (t->type == V_ASN1_GENERALIZEDTIME) { - if (!ASN1_STRING_set(ret, t->data, t->length)) - return NULL; - return ret; - } - - /* grow the string */ - if (!ASN1_STRING_set(ret, NULL, t->length + 2)) - return NULL; - /* ASN1_STRING_set() allocated 'len + 1' bytes. */ - newlen = t->length + 2 + 1; - str = (char *)ret->data; - /* XXX ASN1_TIME is not Y2050 compatible */ - i = snprintf(str, newlen, "%s%s", (t->data[0] >= '5') ? "19" : "20", - (char *) t->data); - if (i == -1 || i >= newlen) { - ASN1_GENERALIZEDTIME_free(ret); - *out = NULL; - return NULL; - } - return ret; -} - -ASN1_GENERALIZEDTIME * -ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) -{ - ASN1_GENERALIZEDTIME *tmp = NULL, *ret; - - if (!out || !*out) { - if (!(tmp = ASN1_GENERALIZEDTIME_new())) - return NULL; - if (out != NULL) - *out = tmp; - else - out = &tmp; - } - - ret = ASN1_TIME_to_generalizedtime_internal(t, out); - if (ret == NULL && tmp != NULL) - ASN1_GENERALIZEDTIME_free(tmp); - - return ret; -} - -int -ASN1_TIME_set_string(ASN1_TIME *s, const char *str) -{ - ASN1_TIME t; - - t.length = strlen(str); - t.data = (unsigned char *)str; - t.flags = 0; - - t.type = asn1_time_parse(t.data, t.length, NULL, V_ASN1_UTCTIME); - if (t.type == -1) - t.type = asn1_time_parse(t.data, t.length, NULL, - V_ASN1_GENERALIZEDTIME); - if (t.type == -1) - return 0; - - if (s && !ASN1_STRING_copy((ASN1_STRING *)s, (ASN1_STRING *)&t)) - return 0; - - return 1; -} diff --git a/lib/libcrypto/asn1/a_time_tm.c b/lib/libcrypto/asn1/a_time_tm.c index 53443fa965b..352b9159ee2 100644 --- a/lib/libcrypto/asn1/a_time_tm.c +++ b/lib/libcrypto/asn1/a_time_tm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: a_time_tm.c,v 1.5 2015/10/08 02:26:31 beck Exp $ */ +/* $OpenBSD: a_time_tm.c,v 1.6 2015/10/19 16:32:37 beck Exp $ */ /* * Copyright (c) 2015 Bob Beck * @@ -14,7 +14,6 @@ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - #include #include #include @@ -25,8 +24,41 @@ #include #include "o_time.h" -#include "asn1_locl.h" +#define RFC5280 0 +#define GENTIME_LENGTH 15 +#define UTCTIME_LENGTH 13 + +int +asn1_tm_cmp(struct tm *tm1, struct tm *tm2) { + if (tm1->tm_year < tm2->tm_year) + return (-1); + if (tm1->tm_year > tm2->tm_year) + return (1); + if (tm1->tm_mon < tm2->tm_mon) + return (-1); + if (tm1->tm_mon > tm2->tm_mon) + return (1); + if (tm1->tm_mday < tm2->tm_mday) + return (-1); + if (tm1->tm_mday > tm2->tm_mday) + return (1); + if (tm1->tm_hour < tm2->tm_hour) + return (-1); + if (tm1->tm_hour > tm2->tm_hour) + return (1); + if (tm1->tm_min < tm2->tm_min) + return (-1); + if (tm1->tm_min > tm2->tm_min) + return (1); + if (tm1->tm_sec < tm2->tm_sec) + return (-1); + if (tm1->tm_sec > tm2->tm_sec) + return (1); + return 0; +} + +/* Format a time as an RFC 5280 format Generalized time */ char * gentime_string_from_tm(struct tm *tm) { @@ -45,6 +77,7 @@ gentime_string_from_tm(struct tm *tm) return (ret); } +/* Format a time as an RFC 5280 format UTC time */ char * utctime_string_from_tm(struct tm *tm) { @@ -61,14 +94,32 @@ utctime_string_from_tm(struct tm *tm) return (ret); } +/* Format a time correctly for an X509 object as per RFC 5280 */ +char * +rfc5280_string_from_tm(struct tm *tm) +{ + char *ret = NULL; + int year; + + year = tm->tm_year + 1900; + if (year < 1950 || year > 9999) + return (NULL); + + if (year < 2050) + ret = utctime_string_from_tm(tm); + else + ret = gentime_string_from_tm(tm); + + return (ret); +} + /* - * Parse an ASN.1 time string. + * Parse an RFC 5280 format ASN.1 time string. * * mode must be: - * 0 if we expect to parse a time as specified in RFC 5280 from an - * X509 certificate. - * V_ASN1_UTCTIME if we wish to parse a legacy ASN1 UTC time. - * V_ASN1_GENERALIZEDTIME if we wish to parse a legacy ASN1 Generalized time. + * 0 if we expect to parse a time as specified in RFC 5280 from an X509 object. + * V_ASN1_UTCTIME if we wish to parse on RFC5280 format UTC time. + * V_ASN1_GENERALIZEDTIME if we wish to parse an RFC5280 format Generalized time. * * Returns: * -1 if the string was invalid. @@ -77,141 +128,54 @@ utctime_string_from_tm(struct tm *tm) * * Fills in *tm with the corresponding time if tm is non NULL. */ -#define RFC5280 0 #define ATOI2(ar) ((ar) += 2, ((ar)[-2] - '0') * 10 + ((ar)[-1] - '0')) int asn1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) { - char *p, *buf = NULL, *dot = NULL, *tz = NULL; - int i, offset = 0, noseconds = 0, type = 0, ret = -1; + int i, type = 0; struct tm ltm; struct tm *lt; - size_t tlen; - char tzc; + const char *p; if (bytes == NULL) - goto err; - - if (len > INT_MAX) - goto err; + return (-1); - /* Constrain the RFC5280 case within min/max valid lengths. */ - if (mode == RFC5280 && (len < 13 || len > 15)) - goto err; - - if ((buf = strndup(bytes, len)) == NULL) - goto err; + /* Constrain to valid lengths. */ + if (len != UTCTIME_LENGTH && len != GENTIME_LENGTH) + return (-1); lt = tm; if (lt == NULL) { - time_t t = time(NULL); - lt = gmtime_r(&t, <m); - if (lt == NULL) - goto err; + memset(<m, 0, sizeof(ltm)); + lt = <m; } - /* - * Find position of the optional fractional seconds, and the - * start of the timezone, while ensuring everything else is - * digits. - */ - for (i = 0; i < len; i++) { - char *t = buf + i; - if (isdigit((unsigned char)*t)) - continue; - if (*t == '.' && dot == NULL && tz == NULL) { - dot = t; - continue; - } - if ((*t == 'Z' || *t == '+' || *t == '-') && tz == NULL) { - tz = t; - continue; - } - goto err; - } - - /* - * Timezone is required. For the non-RFC case it may be - * either Z or +- HHMM, but for RFC5280 it may be only Z. - */ - if (tz == NULL) - goto err; - tzc = *tz; - *tz++ = '\0'; - if (tzc == 'Z') { - if (*tz != '\0') - goto err; - } else if (mode != RFC5280 && (tzc == '+' || tzc == '-') && - strlen(tz) == 4) { - int hours = ATOI2(tz); - int mins = ATOI2(tz); - - if (hours < 0 || hours > 12 || mins < 0 || mins > 59) - goto err; - offset = hours * 3600 + mins * 60; - if (tzc == '-') - offset = -offset; - } else - goto err; - - if (offset != 0) { - /* XXX - yuck - OPENSSL_gmtime_adj should go away */ - if (!OPENSSL_gmtime_adj(lt, 0, offset)) - goto err; - } + /* Timezone is required and must be GMT (Zulu). */ + if (bytes[len - 1] != 'Z') + return (-1); - /* - * We only allow fractional seconds to be present if we are in - * the non-RFC case of a Generalized time. RFC 5280 forbids - * fractional seconds. - */ - if (dot != NULL) { - if (mode != V_ASN1_GENERALIZEDTIME) - goto err; - *dot++ = '\0'; - if (!isdigit((unsigned char)*dot)) - goto err; + /* Make sure everything else is digits. */ + for (i = 0; i < len - 1; i++) { + if (isdigit((unsigned char)bytes[i])) + continue; + return (-1); } /* * Validate and convert the time */ - p = buf; - tlen = strlen(buf); - switch (tlen) { - case 14: + p = bytes; + switch (len) { + case GENTIME_LENGTH: + if (mode == V_ASN1_UTCTIME) + return (-1); lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */ - if (mode != RFC5280 && mode != V_ASN1_GENERALIZEDTIME) - goto err; type = V_ASN1_GENERALIZEDTIME; /* FALLTHROUGH */ - case 12: - if (type == 0 && mode == V_ASN1_GENERALIZEDTIME) { - /* - * In the non-RFC case of a Generalized time - * seconds may not have been provided. RFC - * 5280 mandates that seconds must be present. - */ - noseconds = 1; - lt->tm_year = (ATOI2(p) * 100) - 1900; /* cc */ - type = V_ASN1_GENERALIZEDTIME; - } - /* FALLTHROUGH */ - case 10: + case UTCTIME_LENGTH: if (type == 0) { - /* - * At this point we must have a UTC time. - * In the RFC 5280 case it must have the - * seconds present. In the non-RFC case - * may have no seconds. - */ if (mode == V_ASN1_GENERALIZEDTIME) - goto err; - if (tlen == 10) { - if (mode != V_ASN1_UTCTIME) - goto err; - noseconds = 1; - } + return (-1); type = V_ASN1_UTCTIME; } lt->tm_year += ATOI2(p); /* yy */ @@ -221,40 +185,258 @@ asn1_time_parse(const char *bytes, size_t len, struct tm *tm, int mode) } lt->tm_mon = ATOI2(p) - 1; /* mm */ if (lt->tm_mon < 0 || lt->tm_mon > 11) - goto err; + return (-1); lt->tm_mday = ATOI2(p); /* dd */ if (lt->tm_mday < 1 || lt->tm_mday > 31) - goto err; + return (-1); lt->tm_hour = ATOI2(p); /* HH */ if (lt->tm_hour < 0 || lt->tm_hour > 23) - goto err; + return (-1); lt->tm_min = ATOI2(p); /* MM */ - if (lt->tm_hour < 0 || lt->tm_min > 59) - goto err; - lt->tm_sec = 0; /* SS */ - if (noseconds) - break; - lt->tm_sec = ATOI2(p); + if (lt->tm_min < 0 || lt->tm_min > 59) + return (-1); + lt->tm_sec = ATOI2(p); /* SS */ /* Leap second 60 is not accepted. Reconsider later? */ - if (lt->tm_hour < 0 || lt->tm_sec > 59) - goto err; + if (lt->tm_sec < 0 || lt->tm_sec > 59) + return (-1); break; default: - goto err; + return (-1); + } + + return (type); +} + +/* + * ASN1_TIME generic functions. + */ + +static int +ASN1_TIME_set_string_internal(ASN1_TIME *s, const char *str, int mode) +{ + int type; + char *tmp; + + if ((type = asn1_time_parse(str, strlen(str), NULL, mode)) == -1) + return (0); + if (mode != 0 && mode != type) + return (0); + if ((tmp = strdup(str)) == NULL) + return (0); + free(s->data); + s->data = tmp; + s->length = strlen(tmp); + s->type = type; + return (1); +} + +static ASN1_TIME * +ASN1_TIME_adj_internal(ASN1_TIME *s, time_t t, int offset_day, long offset_sec, + int mode) +{ + int allocated = 0; + struct tm tm; + size_t len; + char * p; + + if (gmtime_r(&t, &tm) == NULL) + return (NULL); + + if (offset_day || offset_sec) { + if (!OPENSSL_gmtime_adj(&tm, offset_day, offset_sec)) + return (NULL); } - /* RFC 5280 section 4.1.2.5 */ - if (mode == RFC5280) { - if (lt->tm_year < 150 && type != V_ASN1_UTCTIME) - goto err; - if (lt->tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) - goto err; + switch (mode) { + case V_ASN1_UTCTIME: + p = utctime_string_from_tm(&tm); + break; + case V_ASN1_GENERALIZEDTIME: + p = gentime_string_from_tm(&tm); + break; + case RFC5280: + p = rfc5280_string_from_tm(&tm); + break; + default: + return (NULL); + } + if (p == NULL) { + ASN1err(ASN1_F_ASN1_GENERALIZEDTIME_ADJ, + ASN1_R_ILLEGAL_TIME_VALUE); + return (NULL); } - ret = type; + if (s == NULL) { + if ((s = ASN1_TIME_new()) == NULL) + return (NULL); + allocated = 1; + } -err: - free(buf); + len = strlen(p); + switch (len) { + case GENTIME_LENGTH: + s->type = V_ASN1_GENERALIZEDTIME; + break; + case UTCTIME_LENGTH: + s->type = V_ASN1_UTCTIME; + break; + default: + if (allocated) + ASN1_TIME_free(s); + free(p); + return (NULL); + } + free(s->data); + s->data = p; + s->length = len; + return (s); +} - return (ret); +ASN1_TIME * +ASN1_TIME_set(ASN1_TIME *s, time_t t) +{ + return (ASN1_TIME_adj(s, t, 0, 0)); } + +ASN1_TIME * +ASN1_TIME_adj(ASN1_TIME *s, time_t t, int offset_day, long offset_sec) +{ + return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, RFC5280)); +} + +int +ASN1_TIME_check(ASN1_TIME *t) +{ + if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) + return (0); + return (t->type == asn1_time_parse(t->data, t->length, NULL, t->type)); +} + +ASN1_GENERALIZEDTIME * +ASN1_TIME_to_generalizedtime(ASN1_TIME *t, ASN1_GENERALIZEDTIME **out) +{ + ASN1_GENERALIZEDTIME *tmp = NULL; + struct tm tm; + char *str; + + if (t->type != V_ASN1_GENERALIZEDTIME && t->type != V_ASN1_UTCTIME) + return (NULL); + + memset(&tm, 0, sizeof(tm)); + if (t->type != asn1_time_parse(t->data, t->length, &tm, t->type)) + return (NULL); + if ((str = gentime_string_from_tm(&tm)) == NULL) + return (NULL); + + if (out != NULL) + tmp = *out; + if (tmp == NULL && (tmp = ASN1_GENERALIZEDTIME_new()) == NULL) { + free(str); + return (NULL); + } + if (out != NULL) + *out = tmp; + + free(tmp->data); + tmp->data = str; + tmp->length = strlen(str); + return (tmp); +} + +int +ASN1_TIME_set_string(ASN1_TIME *s, const char *str) +{ + return (ASN1_TIME_set_string_internal(s, str, 0)); +} + +/* + * ASN1_UTCTIME wrappers + */ + +int +ASN1_UTCTIME_check(ASN1_UTCTIME *d) +{ + if (d->type != V_ASN1_UTCTIME) + return (0); + return (d->type == asn1_time_parse(d->data, d->length, NULL, d->type)); +} + +int +ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) +{ + if (s->type != V_ASN1_UTCTIME) + return (0); + return (ASN1_TIME_set_string_internal(s, str, V_ASN1_UTCTIME)); +} + +ASN1_UTCTIME * +ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) +{ + return (ASN1_UTCTIME_adj(s, t, 0, 0)); +} + +ASN1_UTCTIME * +ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec) +{ + return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, + V_ASN1_UTCTIME)); +} + +int +ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t2) +{ + struct tm tm1, tm2; + + /* + * This function has never handled failure conditions properly + * and should be deprecated. The OpenSSL version used to + * simply follow NULL pointers on failure. BoringSSL and + * OpenSSL now make it return -2 on failure. + * + * The danger is that users of this function will not + * differentiate the -2 failure case from t1 < t2. + */ + if (asn1_time_parse(s->data, s->length, &tm1, V_ASN1_UTCTIME) == -1) + return (-2); /* XXX */ + + if (gmtime_r(&t2, &tm2) == NULL) + return (-2); /* XXX */ + + return asn1_tm_cmp(&tm1, &tm2); +} + +/* + * ASN1_GENERALIZEDTIME wrappers + */ + +int +ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *d) +{ + if (d->type != V_ASN1_GENERALIZEDTIME) + return (0); + return (d->type == asn1_time_parse(d->data, d->length, NULL, d->type)); +} + +int +ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *s, const char *str) +{ + if (s->type != V_ASN1_GENERALIZEDTIME) + return (0); + return (ASN1_TIME_set_string_internal(s, str, V_ASN1_GENERALIZEDTIME)); +} + +ASN1_GENERALIZEDTIME * +ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *s, time_t t) +{ + return (ASN1_GENERALIZEDTIME_adj(s, t, 0, 0)); +} + +ASN1_GENERALIZEDTIME * +ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s, time_t t, int offset_day, + long offset_sec) +{ + return (ASN1_TIME_adj_internal(s, t, offset_day, offset_sec, + V_ASN1_GENERALIZEDTIME)); +} + + diff --git a/lib/libcrypto/asn1/a_utctm.c b/lib/libcrypto/asn1/a_utctm.c deleted file mode 100644 index 495c497bc8d..00000000000 --- a/lib/libcrypto/asn1/a_utctm.c +++ /dev/null @@ -1,173 +0,0 @@ -/* $OpenBSD: a_utctm.c,v 1.32 2015/10/08 02:42:58 beck Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include -#include -#include - -#include -#include - -#include "o_time.h" -#include "asn1_locl.h" - -int -ASN1_UTCTIME_check(ASN1_UTCTIME *d) -{ - if (d->type != V_ASN1_UTCTIME) - return (0); - return(d->type == asn1_time_parse(d->data, d->length, NULL, d->type)); -} - -int -ASN1_UTCTIME_set_string(ASN1_UTCTIME *s, const char *str) -{ - ASN1_UTCTIME t; - - t.type = V_ASN1_UTCTIME; - t.length = strlen(str); - t.data = (unsigned char *)str; - if (ASN1_UTCTIME_check(&t)) { - if (s != NULL) { - if (!ASN1_STRING_set((ASN1_STRING *)s, - (unsigned char *)str, t.length)) - return 0; - s->type = V_ASN1_UTCTIME; - } - return (1); - } else - return (0); -} - -ASN1_UTCTIME * -ASN1_UTCTIME_set(ASN1_UTCTIME *s, time_t t) -{ - return ASN1_UTCTIME_adj(s, t, 0, 0); -} - -static ASN1_UTCTIME * -ASN1_UTCTIME_adj_internal(ASN1_UTCTIME *s, time_t t, int offset_day, - long offset_sec) -{ - char *p; - struct tm *ts; - struct tm data; - - ts = gmtime_r(&t, &data); - if (ts == NULL) - return (NULL); - - if (offset_day || offset_sec) { - if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec)) - return NULL; - } - - if ((p = utctime_string_from_tm(ts)) == NULL) { - ASN1err(ASN1_F_ASN1_UTCTIME_ADJ, ERR_R_MALLOC_FAILURE); - return (NULL); - } - free(s->data); - s->data = p; - s->length = strlen(p); - - s->type = V_ASN1_UTCTIME; - return (s); -} - -ASN1_UTCTIME * -ASN1_UTCTIME_adj(ASN1_UTCTIME *s, time_t t, int offset_day, long offset_sec) -{ - ASN1_UTCTIME *tmp = NULL, *ret; - - if (s == NULL) { - tmp = ASN1_UTCTIME_new(); - if (tmp == NULL) - return NULL; - s = tmp; - } - - ret = ASN1_UTCTIME_adj_internal(s, t, offset_day, offset_sec); - if (ret == NULL && tmp != NULL) - ASN1_UTCTIME_free(tmp); - - return ret; -} - -int -ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *s, time_t t2) -{ - struct tm tm1; - time_t t1; - - /* - * This function has never handled failure conditions properly - * and should be deprecated. BoringSSL makes it return -2 on - * failures, the OpenSSL version follows NULL pointers instead. - */ - if (asn1_time_parse(s->data, s->length, &tm1, V_ASN1_UTCTIME) == -1) - return (-2); /* XXX */ - - if ((t1 = timegm(&tm1)) == -1) - return (-2); /* XXX */ - - if (t1 < t2) - return (-1); - if (t1 > t2) - return (1); - return (0); -} diff --git a/lib/libcrypto/asn1/asn1_locl.h b/lib/libcrypto/asn1/asn1_locl.h index d4994c7cee5..9b612c81832 100644 --- a/lib/libcrypto/asn1/asn1_locl.h +++ b/lib/libcrypto/asn1/asn1_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: asn1_locl.h,v 1.6 2015/10/02 15:04:45 beck Exp $ */ +/* $OpenBSD: asn1_locl.h,v 1.7 2015/10/19 16:32:37 beck Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2006. */ @@ -58,10 +58,6 @@ /* Internal ASN1 structures and functions: not for application use */ -char * gentime_string_from_tm(struct tm *tm); -char * utctime_string_from_tm(struct tm *tm); -int asn1_time_parse(const char *, size_t, struct tm *, int); - /* ASN1 print context structure */ struct asn1_pctx_st { diff --git a/lib/libcrypto/x509/x509_lcl.h b/lib/libcrypto/x509/x509_lcl.h index 0c1c130d5c8..9ffdd01e61c 100644 --- a/lib/libcrypto/x509/x509_lcl.h +++ b/lib/libcrypto/x509/x509_lcl.h @@ -58,3 +58,4 @@ int x509_check_cert_time(X509_STORE_CTX *ctx, X509 *x, int quiet); int asn1_time_parse(const char *, size_t, struct tm *, int); +int asn1_tm_cmp(struct tm *tm1, struct tm *tm2); diff --git a/lib/libcrypto/x509/x509_vfy.c b/lib/libcrypto/x509/x509_vfy.c index c48143f3517..159d60b0348 100644 --- a/lib/libcrypto/x509/x509_vfy.c +++ b/lib/libcrypto/x509/x509_vfy.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509_vfy.c,v 1.46 2015/10/02 15:04:45 beck Exp $ */ +/* $OpenBSD: x509_vfy.c,v 1.47 2015/10/19 16:32:37 beck Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1648,8 +1648,9 @@ int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) { time_t time1, time2; - struct tm tm1; + struct tm tm1, tm2; int ret = 0; + int type; if (cmp_time == NULL) time2 = time(NULL); @@ -1658,9 +1659,15 @@ X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) memset(&tm1, 0, sizeof(tm1)); - if (asn1_time_parse(ctm->data, ctm->length, &tm1, 0) == -1) + if ((type = asn1_time_parse(ctm->data, ctm->length, &tm1, 0)) == -1) goto out; /* invalid time */ + /* RFC 5280 section 4.1.2.5 */ + if (tm1.tm_year < 150 && type != V_ASN1_UTCTIME) + goto out; + if (tm1.tm_year >= 150 && type != V_ASN1_GENERALIZEDTIME) + goto out; + /* * Defensively fail if the time string is not representable as * a time_t. A time_t must be sane if you care about times after @@ -1669,10 +1676,12 @@ X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time) if ((time1 = timegm(&tm1)) == -1) goto out; - if (time1 <= time2) - ret = -1; - else - ret = 1; + if (gmtime_r(&time2, &tm2) == NULL) + goto out; + + ret = asn1_tm_cmp(&tm1, &tm2); + if (ret == 0) + ret = -1; /* 0 is used for error, so map same to less than */ out: return (ret); } @@ -1684,28 +1693,20 @@ X509_gmtime_adj(ASN1_TIME *s, long adj) } ASN1_TIME * -X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_tm) +X509_time_adj(ASN1_TIME *s, long offset_sec, time_t *in_time) { - return X509_time_adj_ex(s, 0, offset_sec, in_tm); + return X509_time_adj_ex(s, 0, offset_sec, in_time); } ASN1_TIME * -X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec, time_t *in_tm) +X509_time_adj_ex(ASN1_TIME *s, int offset_day, long offset_sec, time_t *in_time) { time_t t; - - if (in_tm) - t = *in_tm; + if (in_time == NULL) + t = time(NULL); else - time(&t); - - if (s && !(s->flags & ASN1_STRING_FLAG_MSTRING)) { - if (s->type == V_ASN1_UTCTIME) - return ASN1_UTCTIME_adj(s, t, offset_day, offset_sec); - if (s->type == V_ASN1_GENERALIZEDTIME) - return ASN1_GENERALIZEDTIME_adj(s, t, offset_day, - offset_sec); - } + t = *in_time; + return ASN1_TIME_adj(s, t, offset_day, offset_sec); } -- cgit v1.2.3