Merge pull request #6003 from gstrauss/x509_time
mbedtls_x509_time performance and reduce memory use
This commit is contained in:
commit
836aed7cf8
4 changed files with 147 additions and 162 deletions
3
ChangeLog.d/mbedtls_x509_time.txt
Normal file
3
ChangeLog.d/mbedtls_x509_time.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
Features
|
||||
* Improve mbedtls_x509_time performance and reduce memory use.
|
||||
* Reduce syscalls to time() during certificate verification.
|
|
@ -366,6 +366,31 @@ static inline mbedtls_x509_name *mbedtls_x509_dn_get_next(
|
|||
*/
|
||||
int mbedtls_x509_serial_gets(char *buf, size_t size, const mbedtls_x509_buf *serial);
|
||||
|
||||
/**
|
||||
* \brief Compare pair of mbedtls_x509_time.
|
||||
*
|
||||
* \param t1 mbedtls_x509_time to compare
|
||||
* \param t2 mbedtls_x509_time to compare
|
||||
*
|
||||
* \return < 0 if t1 is before t2
|
||||
* 0 if t1 equals t2
|
||||
* > 0 if t1 is after t2
|
||||
*/
|
||||
int mbedtls_x509_time_cmp(const mbedtls_x509_time *t1, const mbedtls_x509_time *t2);
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
/**
|
||||
* \brief Fill mbedtls_x509_time with provided mbedtls_time_t.
|
||||
*
|
||||
* \param tt mbedtls_time_t to convert
|
||||
* \param now mbedtls_x509_time to fill with converted mbedtls_time_t
|
||||
*
|
||||
* \return \c 0 on success
|
||||
* \return A non-zero return value on failure.
|
||||
*/
|
||||
int mbedtls_x509_time_gmtime(mbedtls_time_t tt, mbedtls_x509_time *now);
|
||||
#endif /* MBEDTLS_HAVE_TIME_DATE */
|
||||
|
||||
/**
|
||||
* \brief Check a given mbedtls_x509_time against the system time
|
||||
* and tell if it's in the past.
|
||||
|
|
236
library/x509.c
236
library/x509.c
|
@ -573,117 +573,82 @@ error:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int x509_parse_int(unsigned char **p, size_t n, int *res)
|
||||
static int x509_date_is_valid(const mbedtls_x509_time *t)
|
||||
{
|
||||
*res = 0;
|
||||
|
||||
for (; n > 0; --n) {
|
||||
if ((**p < '0') || (**p > '9')) {
|
||||
unsigned int month_days;
|
||||
unsigned int year;
|
||||
switch (t->mon) {
|
||||
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
|
||||
month_days = 31;
|
||||
break;
|
||||
case 4: case 6: case 9: case 11:
|
||||
month_days = 30;
|
||||
break;
|
||||
case 2:
|
||||
year = (unsigned int) t->year;
|
||||
month_days = ((year & 3) || (!(year % 100)
|
||||
&& (year % 400)))
|
||||
? 28 : 29;
|
||||
break;
|
||||
default:
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
}
|
||||
}
|
||||
|
||||
*res *= 10;
|
||||
*res += (*(*p)++ - '0');
|
||||
if ((unsigned int) (t->day - 1) >= month_days || /* (1 - days in month) */
|
||||
/* (unsigned int) (t->mon - 1) >= 12 || */ /* (1 - 12) checked above */
|
||||
(unsigned int) t->year > 9999 || /* (0 - 9999) */
|
||||
(unsigned int) t->hour > 23 || /* (0 - 23) */
|
||||
(unsigned int) t->min > 59 || /* (0 - 59) */
|
||||
(unsigned int) t->sec > 59) { /* (0 - 59) */
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x509_date_is_valid(const mbedtls_x509_time *t)
|
||||
static int x509_parse2_int(const unsigned char *p)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
int month_len;
|
||||
|
||||
CHECK_RANGE(0, 9999, t->year);
|
||||
CHECK_RANGE(0, 23, t->hour);
|
||||
CHECK_RANGE(0, 59, t->min);
|
||||
CHECK_RANGE(0, 59, t->sec);
|
||||
|
||||
switch (t->mon) {
|
||||
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
|
||||
month_len = 31;
|
||||
break;
|
||||
case 4: case 6: case 9: case 11:
|
||||
month_len = 30;
|
||||
break;
|
||||
case 2:
|
||||
if ((!(t->year % 4) && t->year % 100) ||
|
||||
!(t->year % 400)) {
|
||||
month_len = 29;
|
||||
} else {
|
||||
month_len = 28;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
CHECK_RANGE(1, month_len, t->day);
|
||||
|
||||
return 0;
|
||||
uint32_t d1 = p[0] - '0';
|
||||
uint32_t d2 = p[1] - '0';
|
||||
return (d1 < 10 && d2 < 10) ? (int) (d1 * 10 + d2) : -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4)
|
||||
* field.
|
||||
*/
|
||||
static int x509_parse_time(unsigned char **p, size_t len, size_t yearlen,
|
||||
mbedtls_x509_time *tm)
|
||||
static int x509_parse_time(const unsigned char *p, mbedtls_x509_time *tm,
|
||||
size_t yearlen)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
int x;
|
||||
|
||||
/*
|
||||
* Minimum length is 10 or 12 depending on yearlen
|
||||
* Parse year, month, day, hour, minute, second
|
||||
*/
|
||||
if (len < yearlen + 8) {
|
||||
tm->year = x509_parse2_int(p);
|
||||
if (tm->year < 0) {
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
}
|
||||
len -= yearlen + 8;
|
||||
|
||||
/*
|
||||
* Parse year, month, day, hour, minute
|
||||
*/
|
||||
CHECK(x509_parse_int(p, yearlen, &tm->year));
|
||||
if (2 == yearlen) {
|
||||
if (tm->year < 50) {
|
||||
tm->year += 100;
|
||||
if (4 == yearlen) {
|
||||
x = tm->year * 100;
|
||||
p += 2;
|
||||
tm->year = x509_parse2_int(p);
|
||||
if (tm->year < 0) {
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
}
|
||||
|
||||
tm->year += 1900;
|
||||
}
|
||||
|
||||
CHECK(x509_parse_int(p, 2, &tm->mon));
|
||||
CHECK(x509_parse_int(p, 2, &tm->day));
|
||||
CHECK(x509_parse_int(p, 2, &tm->hour));
|
||||
CHECK(x509_parse_int(p, 2, &tm->min));
|
||||
|
||||
/*
|
||||
* Parse seconds if present
|
||||
*/
|
||||
if (len >= 2) {
|
||||
CHECK(x509_parse_int(p, 2, &tm->sec));
|
||||
len -= 2;
|
||||
} else {
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
x = (tm->year < 50) ? 2000 : 1900;
|
||||
}
|
||||
tm->year += x;
|
||||
|
||||
/*
|
||||
* Parse trailing 'Z' if present
|
||||
*/
|
||||
if (1 == len && 'Z' == **p) {
|
||||
(*p)++;
|
||||
len--;
|
||||
}
|
||||
tm->mon = x509_parse2_int(p + 2);
|
||||
tm->day = x509_parse2_int(p + 4);
|
||||
tm->hour = x509_parse2_int(p + 6);
|
||||
tm->min = x509_parse2_int(p + 8);
|
||||
tm->sec = x509_parse2_int(p + 10);
|
||||
|
||||
/*
|
||||
* We should have parsed all characters at this point
|
||||
*/
|
||||
if (0 != len) {
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
}
|
||||
|
||||
CHECK(x509_date_is_valid(tm));
|
||||
|
||||
return 0;
|
||||
return x509_date_is_valid(tm);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -721,7 +686,14 @@ int mbedtls_x509_get_time(unsigned char **p, const unsigned char *end,
|
|||
return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_X509_INVALID_DATE, ret);
|
||||
}
|
||||
|
||||
return x509_parse_time(p, len, year_len, tm);
|
||||
/* len is 12 or 14 depending on year_len, plus optional trailing 'Z' */
|
||||
if (len != year_len + 10 &&
|
||||
!(len == year_len + 11 && (*p)[(len - 1)] == 'Z')) {
|
||||
return MBEDTLS_ERR_X509_INVALID_DATE;
|
||||
}
|
||||
|
||||
(*p) += len;
|
||||
return x509_parse_time(*p - len, tm, year_len);
|
||||
}
|
||||
|
||||
int mbedtls_x509_get_sig(unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig)
|
||||
|
@ -1002,81 +974,45 @@ int mbedtls_x509_key_size_helper(char *buf, size_t buf_size, const char *name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
/*
|
||||
* Set the time structure to the current time.
|
||||
* Return 0 on success, non-zero on failure.
|
||||
*/
|
||||
static int x509_get_current_time(mbedtls_x509_time *now)
|
||||
int mbedtls_x509_time_cmp(const mbedtls_x509_time *t1,
|
||||
const mbedtls_x509_time *t2)
|
||||
{
|
||||
struct tm *lt, tm_buf;
|
||||
mbedtls_time_t tt;
|
||||
int ret = 0;
|
||||
int x;
|
||||
|
||||
tt = mbedtls_time(NULL);
|
||||
lt = mbedtls_platform_gmtime_r(&tt, &tm_buf);
|
||||
|
||||
if (lt == NULL) {
|
||||
ret = -1;
|
||||
} else {
|
||||
now->year = lt->tm_year + 1900;
|
||||
now->mon = lt->tm_mon + 1;
|
||||
now->day = lt->tm_mday;
|
||||
now->hour = lt->tm_hour;
|
||||
now->min = lt->tm_min;
|
||||
now->sec = lt->tm_sec;
|
||||
x = (((t1->year << 9) | (t1->mon << 5) | (t1->day)) -
|
||||
((t2->year << 9) | (t2->mon << 5) | (t2->day)));
|
||||
if (x != 0) {
|
||||
return x;
|
||||
}
|
||||
|
||||
return ret;
|
||||
x = (((t1->hour << 12) | (t1->min << 6) | (t1->sec)) -
|
||||
((t2->hour << 12) | (t2->min << 6) | (t2->sec)));
|
||||
return x;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 if before <= after, 1 otherwise
|
||||
*/
|
||||
static int x509_check_time(const mbedtls_x509_time *before, const mbedtls_x509_time *after)
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
int mbedtls_x509_time_gmtime(mbedtls_time_t tt, mbedtls_x509_time *now)
|
||||
{
|
||||
if (before->year > after->year) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (before->year == after->year &&
|
||||
before->mon > after->mon) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (before->year == after->year &&
|
||||
before->mon == after->mon &&
|
||||
before->day > after->day) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (before->year == after->year &&
|
||||
before->mon == after->mon &&
|
||||
before->day == after->day &&
|
||||
before->hour > after->hour) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (before->year == after->year &&
|
||||
before->mon == after->mon &&
|
||||
before->day == after->day &&
|
||||
before->hour == after->hour &&
|
||||
before->min > after->min) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (before->year == after->year &&
|
||||
before->mon == after->mon &&
|
||||
before->day == after->day &&
|
||||
before->hour == after->hour &&
|
||||
before->min == after->min &&
|
||||
before->sec > after->sec) {
|
||||
return 1;
|
||||
struct tm tm;
|
||||
|
||||
if (mbedtls_platform_gmtime_r(&tt, &tm) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
now->year = tm.tm_year + 1900;
|
||||
now->mon = tm.tm_mon + 1;
|
||||
now->day = tm.tm_mday;
|
||||
now->hour = tm.tm_hour;
|
||||
now->min = tm.tm_min;
|
||||
now->sec = tm.tm_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int x509_get_current_time(mbedtls_x509_time *now)
|
||||
{
|
||||
return mbedtls_x509_time_gmtime(mbedtls_time(NULL), now);
|
||||
}
|
||||
|
||||
int mbedtls_x509_time_is_past(const mbedtls_x509_time *to)
|
||||
{
|
||||
mbedtls_x509_time now;
|
||||
|
@ -1085,7 +1021,7 @@ int mbedtls_x509_time_is_past(const mbedtls_x509_time *to)
|
|||
return 1;
|
||||
}
|
||||
|
||||
return x509_check_time(&now, to);
|
||||
return mbedtls_x509_time_cmp(to, &now) < 0;
|
||||
}
|
||||
|
||||
int mbedtls_x509_time_is_future(const mbedtls_x509_time *from)
|
||||
|
@ -1096,7 +1032,7 @@ int mbedtls_x509_time_is_future(const mbedtls_x509_time *from)
|
|||
return 1;
|
||||
}
|
||||
|
||||
return x509_check_time(from, &now);
|
||||
return mbedtls_x509_time_cmp(from, &now) > 0;
|
||||
}
|
||||
|
||||
#else /* MBEDTLS_HAVE_TIME_DATE */
|
||||
|
|
|
@ -2020,7 +2020,8 @@ int mbedtls_x509_crt_is_revoked(const mbedtls_x509_crt *crt, const mbedtls_x509_
|
|||
*/
|
||||
static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
|
||||
mbedtls_x509_crl *crl_list,
|
||||
const mbedtls_x509_crt_profile *profile)
|
||||
const mbedtls_x509_crt_profile *profile,
|
||||
const mbedtls_x509_time *now)
|
||||
{
|
||||
int flags = 0;
|
||||
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
|
||||
|
@ -2098,16 +2099,20 @@ static int x509_crt_verifycrl(mbedtls_x509_crt *crt, mbedtls_x509_crt *ca,
|
|||
break;
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
/*
|
||||
* Check for validity of CRL (Do not drop out)
|
||||
*/
|
||||
if (mbedtls_x509_time_is_past(&crl_list->next_update)) {
|
||||
if (mbedtls_x509_time_cmp(&crl_list->next_update, now) < 0) {
|
||||
flags |= MBEDTLS_X509_BADCRL_EXPIRED;
|
||||
}
|
||||
|
||||
if (mbedtls_x509_time_is_future(&crl_list->this_update)) {
|
||||
if (mbedtls_x509_time_cmp(&crl_list->this_update, now) > 0) {
|
||||
flags |= MBEDTLS_X509_BADCRL_FUTURE;
|
||||
}
|
||||
#else
|
||||
((void) now);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check if certificate is revoked
|
||||
|
@ -2265,7 +2270,8 @@ static int x509_crt_find_parent_in(
|
|||
int top,
|
||||
unsigned path_cnt,
|
||||
unsigned self_cnt,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx,
|
||||
const mbedtls_x509_time *now)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
mbedtls_x509_crt *parent, *fallback_parent;
|
||||
|
@ -2328,9 +2334,10 @@ check_signature:
|
|||
continue;
|
||||
}
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
/* optional time check */
|
||||
if (mbedtls_x509_time_is_past(&parent->valid_to) ||
|
||||
mbedtls_x509_time_is_future(&parent->valid_from)) {
|
||||
if (mbedtls_x509_time_cmp(&parent->valid_to, now) < 0 || /* past */
|
||||
mbedtls_x509_time_cmp(&parent->valid_from, now) > 0) { /* future */
|
||||
if (fallback_parent == NULL) {
|
||||
fallback_parent = parent;
|
||||
fallback_signature_is_good = signature_is_good;
|
||||
|
@ -2338,6 +2345,9 @@ check_signature:
|
|||
|
||||
continue;
|
||||
}
|
||||
#else
|
||||
((void) now);
|
||||
#endif
|
||||
|
||||
*r_parent = parent;
|
||||
*r_signature_is_good = signature_is_good;
|
||||
|
@ -2383,7 +2393,8 @@ static int x509_crt_find_parent(
|
|||
int *signature_is_good,
|
||||
unsigned path_cnt,
|
||||
unsigned self_cnt,
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx)
|
||||
mbedtls_x509_crt_restart_ctx *rs_ctx,
|
||||
const mbedtls_x509_time *now)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||
mbedtls_x509_crt *search_list;
|
||||
|
@ -2404,7 +2415,7 @@ static int x509_crt_find_parent(
|
|||
ret = x509_crt_find_parent_in(child, search_list,
|
||||
parent, signature_is_good,
|
||||
*parent_is_trusted,
|
||||
path_cnt, self_cnt, rs_ctx);
|
||||
path_cnt, self_cnt, rs_ctx, now);
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
|
||||
|
@ -2525,6 +2536,13 @@ static int x509_crt_verify_chain(
|
|||
int signature_is_good;
|
||||
unsigned self_cnt;
|
||||
mbedtls_x509_crt *cur_trust_ca = NULL;
|
||||
mbedtls_x509_time now;
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
if (mbedtls_x509_time_gmtime(mbedtls_time(NULL), &now) != 0) {
|
||||
return MBEDTLS_ERR_X509_FATAL_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
/* resume if we had an operation in progress */
|
||||
|
@ -2555,14 +2573,16 @@ static int x509_crt_verify_chain(
|
|||
ver_chain->len++;
|
||||
flags = &cur->flags;
|
||||
|
||||
#if defined(MBEDTLS_HAVE_TIME_DATE)
|
||||
/* Check time-validity (all certificates) */
|
||||
if (mbedtls_x509_time_is_past(&child->valid_to)) {
|
||||
if (mbedtls_x509_time_cmp(&child->valid_to, &now) < 0) {
|
||||
*flags |= MBEDTLS_X509_BADCERT_EXPIRED;
|
||||
}
|
||||
|
||||
if (mbedtls_x509_time_is_future(&child->valid_from)) {
|
||||
if (mbedtls_x509_time_cmp(&child->valid_from, &now) > 0) {
|
||||
*flags |= MBEDTLS_X509_BADCERT_FUTURE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Stop here for trusted roots (but not for trusted EE certs) */
|
||||
if (child_is_trusted) {
|
||||
|
@ -2613,7 +2633,8 @@ find_parent:
|
|||
/* Look for a parent in trusted CAs or up the chain */
|
||||
ret = x509_crt_find_parent(child, cur_trust_ca, &parent,
|
||||
&parent_is_trusted, &signature_is_good,
|
||||
ver_chain->len - 1, self_cnt, rs_ctx);
|
||||
ver_chain->len - 1, self_cnt, rs_ctx,
|
||||
&now);
|
||||
|
||||
#if defined(MBEDTLS_ECDSA_C) && defined(MBEDTLS_ECP_RESTARTABLE)
|
||||
if (rs_ctx != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
|
||||
|
@ -2662,7 +2683,7 @@ find_parent:
|
|||
|
||||
#if defined(MBEDTLS_X509_CRL_PARSE_C)
|
||||
/* Check trusted CA's CRL for the given crt */
|
||||
*flags |= x509_crt_verifycrl(child, parent, ca_crl, profile);
|
||||
*flags |= x509_crt_verifycrl(child, parent, ca_crl, profile, &now);
|
||||
#else
|
||||
(void) ca_crl;
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue