Validate ASN.1 times according to RFC 5280

Refuse to parse times that are invalid according to RFC 5280, with
a few exceptions for compatibility. This can affect test code that
relies on making and parsing certificates that contain invalid times.

Update-Note: Certificates containing invalid ASN.1 times will no longer parse.

Bug: 491, 427

Change-Id: I2a3fe3a4d359ac662340a225d05b360718eb8c29
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52665
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
chromium-5359
Bob Beck 3 years ago committed by Boringssl LUCI CQ
parent 1500ad0533
commit 652464ec78
  1. 122
      crypto/asn1/a_gentm.c
  2. 98
      crypto/asn1/a_utctm.c
  3. 29
      crypto/asn1/asn1_test.cc
  4. 9
      crypto/asn1/internal.h
  5. 25
      crypto/asn1/tasn_dec.c
  6. 126
      crypto/bytestring/bytestring_test.cc
  7. 165
      crypto/bytestring/cbs.c
  8. 20
      include/openssl/bytestring.h

@ -55,130 +55,26 @@
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <string.h>
#include <time.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "internal.h"
int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d)
{
static const int min[9] = { 0, 0, 1, 1, 0, 0, 0, 0, 0 };
static const int max[9] = { 99, 99, 12, 31, 23, 59, 59, 12, 59 };
char *a;
int n, i, l, o;
if (d->type != V_ASN1_GENERALIZEDTIME)
return (0);
l = d->length;
a = (char *)d->data;
o = 0;
/*
* GENERALIZEDTIME is similar to UTCTIME except the year is represented
* as YYYY. This stuff treats everything as a two digit field so make
* first two fields 00 to 99
*/
if (l < 13)
goto err;
for (i = 0; i < 7; i++) {
if ((i == 6) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
i++;
if (tm)
tm->tm_sec = 0;
break;
}
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = a[o] - '0';
if (++o > l)
goto err;
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = (n * 10) + a[o] - '0';
if (++o > l)
goto err;
if ((n < min[i]) || (n > max[i]))
goto err;
if (tm) {
switch (i) {
case 0:
tm->tm_year = n * 100 - 1900;
break;
case 1:
tm->tm_year += n;
break;
case 2:
tm->tm_mon = n - 1;
break;
case 3:
tm->tm_mday = n;
break;
case 4:
tm->tm_hour = n;
break;
case 5:
tm->tm_min = n;
break;
case 6:
tm->tm_sec = n;
break;
}
}
}
/*
* Optional fractional seconds: decimal point followed by one or more
* digits.
*/
if (a[o] == '.') {
if (++o > l)
goto err;
i = o;
while ((a[o] >= '0') && (a[o] <= '9') && (o <= l))
o++;
/* Must have at least one digit after decimal point */
if (i == o)
goto err;
}
if (a[o] == 'Z')
o++;
else if ((a[o] == '+') || (a[o] == '-')) {
int offsign = a[o] == '-' ? 1 : -1, offset = 0;
o++;
if (o + 4 > l)
goto err;
for (i = 7; i < 9; i++) {
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = a[o] - '0';
o++;
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = (n * 10) + a[o] - '0';
if ((n < min[i]) || (n > max[i]))
goto err;
if (tm) {
if (i == 7)
offset = n * 3600;
else if (i == 8)
offset += n * 60;
}
o++;
if (d->type != V_ASN1_GENERALIZEDTIME) {
return 0;
}
if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
CBS cbs;
CBS_init(&cbs, d->data, (size_t)d->length);
if (!CBS_parse_generalized_time(&cbs, tm, /*allow_timezone_offset=*/0)) {
return 0;
} else if (a[o]) {
/* Missing time zone information. */
goto err;
}
return (o == l);
err:
return (0);
return 1;
}
int ASN1_GENERALIZEDTIME_check(const ASN1_GENERALIZEDTIME *d)

@ -55,107 +55,27 @@
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <string.h>
#include <time.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "internal.h"
int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d)
{
static const int min[8] = { 0, 1, 1, 0, 0, 0, 0, 0 };
static const int max[8] = { 99, 12, 31, 23, 59, 59, 12, 59 };
char *a;
int n, i, l, o;
if (d->type != V_ASN1_UTCTIME)
return (0);
l = d->length;
a = (char *)d->data;
o = 0;
if (l < 11)
goto err;
for (i = 0; i < 6; i++) {
if ((i == 5) && ((a[o] == 'Z') || (a[o] == '+') || (a[o] == '-'))) {
i++;
if (tm)
tm->tm_sec = 0;
break;
}
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = a[o] - '0';
if (++o > l)
goto err;
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = (n * 10) + a[o] - '0';
if (++o > l)
goto err;
if ((n < min[i]) || (n > max[i]))
goto err;
if (tm) {
switch (i) {
case 0:
tm->tm_year = n < 50 ? n + 100 : n;
break;
case 1:
tm->tm_mon = n - 1;
break;
case 2:
tm->tm_mday = n;
break;
case 3:
tm->tm_hour = n;
break;
case 4:
tm->tm_min = n;
break;
case 5:
tm->tm_sec = n;
break;
}
}
}
if (a[o] == 'Z')
o++;
else if ((a[o] == '+') || (a[o] == '-')) {
int offsign = a[o] == '-' ? 1 : -1, offset = 0;
o++;
if (o + 4 > l)
goto err;
for (i = 6; i < 8; i++) {
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = a[o] - '0';
o++;
if ((a[o] < '0') || (a[o] > '9'))
goto err;
n = (n * 10) + a[o] - '0';
if ((n < min[i]) || (n > max[i]))
goto err;
if (tm) {
if (i == 6)
offset = n * 3600;
else if (i == 7)
offset += n * 60;
}
o++;
}
if (offset && !OPENSSL_gmtime_adj(tm, 0, offset * offsign))
if (d->type != V_ASN1_UTCTIME) {
return 0;
}
return o == l;
err:
CBS cbs;
CBS_init(&cbs, d->data, (size_t)d->length);
if (!CBS_parse_utc_time(&cbs, tm, /*allow_timezone_offset=*/1)) {
return 0;
}
return 1;
}
int ASN1_UTCTIME_check(const ASN1_UTCTIME *d)
{

@ -901,6 +901,31 @@ static std::string ASN1StringToStdString(const ASN1_STRING *str) {
ASN1_STRING_get0_data(str) + ASN1_STRING_length(str));
}
static bool ASN1Time_check_time_t(const ASN1_TIME *s, time_t t) {
struct tm stm, ttm;
int day, sec;
switch (ASN1_STRING_type(s)) {
case V_ASN1_GENERALIZEDTIME:
if (!asn1_generalizedtime_to_tm(&stm, s)) {
return false;
}
break;
case V_ASN1_UTCTIME:
if (!asn1_utctime_to_tm(&stm, s)) {
return false;
}
break;
default:
return 0;
}
if (!OPENSSL_gmtime(&t, &ttm) ||
!OPENSSL_gmtime_diff(&day, &sec, &ttm, &stm)) {
return false;
}
return day == 0 && sec ==0;
}
TEST(ASN1Test, SetTime) {
static const struct {
time_t time;
@ -911,6 +936,7 @@ TEST(ASN1Test, SetTime) {
{-631152000, "19500101000000Z", "500101000000Z"},
{0, "19700101000000Z", "700101000000Z"},
{981173106, "20010203040506Z", "010203040506Z"},
{951804000, "20000229060000Z", "000229060000Z"},
#if defined(OPENSSL_64_BIT)
// TODO(https://crbug.com/boringssl/416): These cases overflow 32-bit
// |time_t| and do not consistently work on 32-bit platforms. For now,
@ -939,6 +965,7 @@ TEST(ASN1Test, SetTime) {
ASSERT_TRUE(utc);
EXPECT_EQ(V_ASN1_UTCTIME, ASN1_STRING_type(utc.get()));
EXPECT_EQ(t.utc, ASN1StringToStdString(utc.get()));
EXPECT_TRUE(ASN1Time_check_time_t(utc.get(), t.time));
} else {
EXPECT_FALSE(utc);
}
@ -949,6 +976,7 @@ TEST(ASN1Test, SetTime) {
ASSERT_TRUE(generalized);
EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(generalized.get()));
EXPECT_EQ(t.generalized, ASN1StringToStdString(generalized.get()));
EXPECT_TRUE(ASN1Time_check_time_t(generalized.get(), t.time));
} else {
EXPECT_FALSE(generalized);
}
@ -963,6 +991,7 @@ TEST(ASN1Test, SetTime) {
EXPECT_EQ(V_ASN1_GENERALIZEDTIME, ASN1_STRING_type(choice.get()));
EXPECT_EQ(t.generalized, ASN1StringToStdString(choice.get()));
}
EXPECT_TRUE(ASN1Time_check_time_t(choice.get(), t.time));
} else {
EXPECT_FALSE(choice);
}

@ -72,7 +72,7 @@ extern "C" {
/* Wrapper functions for time functions. */
/* OPENSSL_gmtime wraps |gmtime_r|. See the manual page for that function. */
struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result);
OPENSSL_EXPORT struct tm *OPENSSL_gmtime(const time_t *time, struct tm *result);
/* OPENSSL_gmtime_adj updates |tm| by adding |offset_day| days and |offset_sec|
* seconds. */
@ -81,10 +81,10 @@ int OPENSSL_gmtime_adj(struct tm *tm, int offset_day, long offset_sec);
/* OPENSSL_gmtime_diff calculates the difference between |from| and |to| and
* outputs the difference as a number of days and seconds in |*out_days| and
* |*out_secs|. */
int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from,
OPENSSL_EXPORT int OPENSSL_gmtime_diff(int *out_days, int *out_secs,
const struct tm *from,
const struct tm *to);
/* Internal ASN1 structures and functions: not for application use */
/* These are used internally in the ASN1_OBJECT to keep track of
@ -216,6 +216,9 @@ typedef struct {
OPENSSL_EXPORT void asn1_get_string_table_for_testing(
const ASN1_STRING_TABLE **out_ptr, size_t *out_len);
OPENSSL_EXPORT int asn1_generalizedtime_to_tm(struct tm *tm,
const ASN1_GENERALIZEDTIME *d);
OPENSSL_EXPORT int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d);
#if defined(__cplusplus)
} /* extern C */

@ -55,14 +55,14 @@
* [including the GNU Public Licence.] */
#include <openssl/asn1.h>
#include <limits.h>
#include <string.h>
#include <openssl/asn1t.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <limits.h>
#include <string.h>
#include "../internal.h"
#include "internal.h"
@ -821,6 +821,23 @@ static int asn1_ex_c2i(ASN1_VALUE **pval, const unsigned char *cont, int len,
OPENSSL_PUT_ERROR(ASN1, ASN1_R_UNIVERSALSTRING_IS_WRONG_LENGTH);
goto err;
}
if (utype == V_ASN1_UTCTIME) {
CBS cbs;
CBS_init(&cbs, cont, (size_t)len);
if (!CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
goto err;
}
}
if (utype == V_ASN1_GENERALIZEDTIME) {
CBS cbs;
CBS_init(&cbs, cont, (size_t)len);
if (!CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0)) {
OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_TIME_FORMAT);
goto err;
}
}
/* All based on ASN1_STRING and handled the same */
if (!*pval) {
stmp = ASN1_STRING_type_new(utype);

@ -24,9 +24,9 @@
#include <openssl/crypto.h>
#include <openssl/span.h>
#include "internal.h"
#include "../internal.h"
#include "../test/test_util.h"
#include "internal.h"
TEST(CBSTest, Skip) {
@ -1493,3 +1493,127 @@ TEST(CBBTest, Unicode) {
EXPECT_EQ(4u, cbb_get_utf8_len(0x10000));
EXPECT_EQ(4u, cbb_get_utf8_len(0x10ffff));
}
TEST(CBSTest, BogusTime) {
static const struct {
const char *timestring;
} kBogusTimeTests[] = {
{""},
{"invalidtimesZ"},
{"Z"},
{"0000"},
{"9999Z"},
{"00000000000000000000000000000Z"},
{"19491231235959"},
{"500101000000.001Z"},
{"500101000000+6"},
{"-1970010100000Z"},
{"7a0101000000Z"},
{"20500101000000-6"},
{"20500101000000.001"},
{"20500229000000Z"},
{"220229000000Z"},
{"20500132000000Z"},
{"220132000000Z"},
{"20500332000000Z"},
{"220332000000Z"},
{"20500532000000Z"},
{"220532000000Z"},
{"20500732000000Z"},
{"220732000000Z"},
{"20500832000000Z"},
{"220832000000Z"},
{"20501032000000Z"},
{"221032000000Z"},
{"20501232000000Z"},
{"221232000000Z"},
{"20500431000000Z"},
{"220431000000Z"},
{"20500631000000Z"},
{"220631000000Z"},
{"20500931000000Z"},
{"220931000000Z"},
{"20501131000000Z"},
{"221131000000Z"},
{"20501100000000Z"},
{"221100000000Z"},
{"19500101000000+0600"},
};
for (const auto &t : kBogusTimeTests) {
SCOPED_TRACE(t.timestring);
CBS cbs;
CBS_init(&cbs, (const uint8_t *)t.timestring, strlen(t.timestring));
EXPECT_FALSE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0));
EXPECT_FALSE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1));
}
static const struct {
const char *timestring;
} kUTCTZTests[] = {
{"480711220333-0700"},
{"140704000000-0700"},
{"480222202332-0500"},
{"480726113216-0000"},
{"480726113216-2359"},
};
for (const auto &t : kUTCTZTests) {
SCOPED_TRACE(t.timestring);
CBS cbs;
CBS_init(&cbs, (const uint8_t *)t.timestring, strlen(t.timestring));
EXPECT_FALSE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0));
EXPECT_FALSE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/1));
EXPECT_TRUE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1));
EXPECT_FALSE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/0));
}
static const struct {
const char *timestring;
} kBogusUTCTZTests[] = {
{"480711220333-0160"},
{"140704000000-9999"},
{"480222202332-2400"},
};
for (const auto &t : kBogusUTCTZTests) {
SCOPED_TRACE(t.timestring);
CBS cbs;
CBS_init(&cbs, (const uint8_t *)t.timestring, strlen(t.timestring));
EXPECT_FALSE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0));
EXPECT_FALSE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1));
}
static const struct {
const char *timestring;
} kGenTZTests[] = {
{"20480711220333-0000"},
{"20140704000000-0100"},
{"20460311174630-0300"},
{"20140704000000-2359"},
};
for (const auto &t : kGenTZTests) {
SCOPED_TRACE(t.timestring);
CBS cbs;
CBS_init(&cbs, (const uint8_t *)t.timestring, strlen(t.timestring));
EXPECT_FALSE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0));
EXPECT_TRUE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/1));
EXPECT_FALSE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1));
EXPECT_FALSE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/0));
}
static const struct {
const char *timestring;
} kBogusGenTZTests[] = {
{"20480222202332-2400"},
{"20140704000000-9999"},
{"20480726113216-0160"},
};
for (const auto &t : kBogusGenTZTests) {
SCOPED_TRACE(t.timestring);
CBS cbs;
CBS_init(&cbs, (const uint8_t *)t.timestring, strlen(t.timestring));
EXPECT_FALSE(CBS_parse_generalized_time(&cbs, NULL,
/*allow_timezone_offset=*/0));
EXPECT_FALSE(CBS_parse_utc_time(&cbs, NULL, /*allow_timezone_offset=*/1));
}
}

@ -12,15 +12,18 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <openssl/mem.h>
#include <openssl/asn1.h>
#include <openssl/bytestring.h>
#include <openssl/mem.h>
#include <assert.h>
#include <ctype.h>
#include <inttypes.h>
#include <string.h>
#include "internal.h"
#include "../asn1/internal.h"
#include "../internal.h"
#include "internal.h"
void CBS_init(CBS *cbs, const uint8_t *data, size_t len) {
@ -720,3 +723,161 @@ err:
CBB_cleanup(&cbb);
return NULL;
}
static int cbs_get_two_digits(CBS *cbs, int *out) {
uint8_t first_digit, second_digit;
if (!CBS_get_u8(cbs, &first_digit)) {
return 0;
}
if (!isdigit(first_digit)) {
return 0;
}
if (!CBS_get_u8(cbs, &second_digit)) {
return 0;
}
if (!isdigit(second_digit)) {
return 0;
}
*out = (first_digit - '0') * 10 + (second_digit - '0');
return 1;
}
static int is_valid_day(int year, int month, int day) {
if (day < 1) {
return 0;
}
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
return day <= 31;
case 4:
case 6:
case 9:
case 11:
return day <= 30;
case 2:
if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) {
return day <= 29;
} else {
return day <= 28;
}
default:
return 0;
}
}
static int CBS_parse_rfc5280_time_internal(const CBS *cbs, int is_gentime,
int allow_timezone_offset,
struct tm *out_tm) {
int year, month, day, hour, min, sec, tmp;
CBS copy = *cbs;
uint8_t tz;
if (is_gentime) {
if (!cbs_get_two_digits(&copy, &tmp)) {
return 0;
}
year = tmp * 100;
if (!cbs_get_two_digits(&copy, &tmp)) {
return 0;
}
year += tmp;
} else {
year = 1900;
if (!cbs_get_two_digits(&copy, &tmp)) {
return 0;
}
year += tmp;
if (year < 1950) {
year += 100;
}
if (year >= 2050) {
return 0; // A Generalized time must be used.
}
}
if (!cbs_get_two_digits(&copy, &month) || month < 1 ||
month > 12 || // Reject invalid months.
!cbs_get_two_digits(&copy, &day) ||
!is_valid_day(year, month, day) || // Reject invalid days.
!cbs_get_two_digits(&copy, &hour) ||
hour > 23 || // Reject invalid hours.
!cbs_get_two_digits(&copy, &min) ||
min > 59 || // Reject invalid minutes.
!cbs_get_two_digits(&copy, &sec) || sec > 59 || !CBS_get_u8(&copy, &tz)) {
return 0;
}
int offset_sign = 0;
switch (tz) {
case 'Z':
break; // We correctly have 'Z' on the end as per spec.
case '+':
offset_sign = 1;
break; // Should not be allowed per RFC 5280.
case '-':
offset_sign = -1;
break; // Should not be allowed per RFC 5280.
default:
return 0; // Reject anything else after the time.
}
// If allow_timezone_offset is non-zero, allow for a four digit timezone
// offset to be specified even though this is not allowed by RFC 5280. We are
// permissive of this for UTCTimes due to the unfortunate existence of
// artisinally rolled long lived certificates that were baked into places that
// are now difficult to change. These certificates were generated with the
// 'openssl' command that permissively allowed the creation of certificates
// with notBefore and notAfter times specified as strings for direct
// certificate inclusion on the command line. For context see cl/237068815.
//
// TODO(bbe): This has been expunged from public web-pki as the ecosystem has
// managed to encourage CA compliance with standards. We should find a way to
// get rid of this or make it off by default.
int offset_seconds = 0;
if (offset_sign != 0) {
if (!allow_timezone_offset) {
return 0;
}
int offset_hours, offset_minutes;
if (!cbs_get_two_digits(&copy, &offset_hours) ||
offset_hours > 23 || // Reject invalid hours.
!cbs_get_two_digits(&copy, &offset_minutes) ||
offset_minutes > 59) { // Reject invalid minutes.
return 0;
}
offset_seconds = offset_sign * (offset_hours * 3600 + offset_minutes * 60);
}
if (CBS_len(&copy) != 0) {
return 0; // Reject invalid lengths.
}
if (out_tm != NULL) {
// Fill in the tm fields corresponding to what we validated.
out_tm->tm_year = year - 1900;
out_tm->tm_mon = month - 1;
out_tm->tm_mday = day;
out_tm->tm_hour = hour;
out_tm->tm_min = min;
out_tm->tm_sec = sec;
if (offset_seconds && !OPENSSL_gmtime_adj(out_tm, 0, offset_seconds)) {
return 0;
}
}
return 1;
}
int CBS_parse_generalized_time(const CBS *cbs, struct tm *out_tm,
int allow_timezone_offset) {
return CBS_parse_rfc5280_time_internal(cbs, 1, allow_timezone_offset, out_tm);
}
int CBS_parse_utc_time(const CBS *cbs, struct tm *out_tm,
int allow_timezone_offset) {
return CBS_parse_rfc5280_time_internal(cbs, 0, allow_timezone_offset, out_tm);
}

@ -18,6 +18,7 @@
#include <openssl/base.h>
#include <openssl/span.h>
#include <time.h>
#if defined(__cplusplus)
extern "C" {
@ -353,6 +354,25 @@ OPENSSL_EXPORT int CBS_is_unsigned_asn1_integer(const CBS *cbs);
OPENSSL_EXPORT char *CBS_asn1_oid_to_text(const CBS *cbs);
// CBS_parse_generalized_time returns one if |cbs| is a valid DER-encoded, ASN.1
// GeneralizedTime body within the limitations imposed by RFC 5280, or zero
// otherwise. If |allow_timezone_offset| is non-zero, four-digit timezone
// offsets, which would not be allowed by DER, are permitted. On success, if
// |out_tm| is non-NULL, |*out_tm| will be zeroed, and then set to the
// corresponding time in UTC. This function does not compute |out_tm->tm_wday|
// or |out_tm->tm_yday|.
OPENSSL_EXPORT int CBS_parse_generalized_time(const CBS *cbs, struct tm *out_tm,
int allow_timezeone_offset);
// CBS_parse_utc_time returns one if |cbs| is a valid DER-encoded, ASN.1
// UTCTime body within the limitations imposed by RFC 5280, or zero otherwise.
// If |allow_timezone_offset| is non-zero, four-digit timezone offsets, which
// would not be allowed by DER, are permitted. On success, if |out_tm| is
// non-NULL, |*out_tm| will be zeroed, and then set to the corresponding time
// in UTC. This function does not compute |out_tm->tm_wday| or |out_tm->tm_yday|.
OPENSSL_EXPORT int CBS_parse_utc_time(const CBS *cbs, struct tm *out_tm,
int allow_timezeone_offset);
// CRYPTO ByteBuilder.
//
// |CBB| objects allow one to build length-prefixed serialisations. A |CBB|

Loading…
Cancel
Save