diff --git a/ChangeLog b/ChangeLog index 3b7c3abbe..7ab61d3ca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ mbed TLS ChangeLog (Sorted per branch, date) += mbed TLS 1.3.x + +Changes + * Add compile time option for relaxed X509 time verification to enable + accepting certificates with non-standard time format (that is without + seconds or with a time zone). Patch provided by OpenVPN. + = mbed TLS 1.3.17 branch 2016-06-28 Security diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 8fdf36e84..4e52790bb 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -1176,6 +1176,17 @@ */ //#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +/** + * \def POLARSSL_X509_ALLOW_RELAXED_DATE + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering ASN.1 UTCTime or ASN.1 GeneralizedTime without seconds or + * with a time zone. + * + * Uncomment to prevent an error. + */ +//#define POLARSSL_X509_ALLOW_RELAXED_DATE + /** * \def POLARSSL_X509_CHECK_KEY_USAGE * diff --git a/library/x509.c b/library/x509.c index ab105d8fa..0d54bebe6 100644 --- a/library/x509.c +++ b/library/x509.c @@ -489,6 +489,88 @@ static int x509_parse_int(unsigned char **p, unsigned n, int *res){ return 0; } +/* + * 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, unsigned int yearlen, x509_time *time ) +{ + int ret; + + /* + * minimum length is 10 or 12 depending on yearlen + */ + if ( len < yearlen + 8 ) + return POLARSSL_ERR_X509_INVALID_DATE; + len -= yearlen + 8; + + /* + * parse year, month, day, hour, minute + */ + CHECK( x509_parse_int( p, yearlen, &time->year ) ); + if ( 2 == yearlen ) + { + if ( time->year < 50 ) + time->year += 100; + + time->year += 1900; + } + + CHECK( x509_parse_int( p, 2, &time->mon ) ); + CHECK( x509_parse_int( p, 2, &time->day ) ); + CHECK( x509_parse_int( p, 2, &time->hour ) ); + CHECK( x509_parse_int( p, 2, &time->min ) ); + + /* + * parse seconds if present + */ + if ( len >= 2 && **p >= '0' && **p <= '9' ) + { + CHECK( x509_parse_int( p, 2, &time->sec ) ); + len -= 2; + } + else + { +#if defined(POLARSSL_X509_ALLOW_RELAXED_DATE) + /* + * if relaxed mode, allow seconds to be absent + */ + time->sec = 0; +#else + return POLARSSL_ERR_X509_INVALID_DATE; +#endif + } + + /* + * parse trailing 'Z' if present + */ + if ( 1 == len && 'Z' == **p ) + { + (*p)++; + return 0; + } +#if defined(POLARSSL_X509_ALLOW_RELAXED_DATE) + /* + * if relaxed mode, allow timezone to be present + */ + else if ( 5 == len && ( '+' == **p || '-' == **p ) ) + { + int tz; /* throwaway timezone */ + + (*p)++; + CHECK( x509_parse_int( p, 4, &tz ) ); + + return 0; + } +#endif + /* + * okay if no trailing 'Z' or timezone specified + */ + else if ( 0 == len ) + return 0; + else + return POLARSSL_ERR_X509_INVALID_DATE; +} + /* * Time ::= CHOICE { * utcTime UTCTime, @@ -515,20 +597,7 @@ int x509_get_time( unsigned char **p, const unsigned char *end, if( ret != 0 ) return( POLARSSL_ERR_X509_INVALID_DATE + ret ); - CHECK( x509_parse_int( p, 2, &time->year ) ); - CHECK( x509_parse_int( p, 2, &time->mon ) ); - CHECK( x509_parse_int( p, 2, &time->day ) ); - CHECK( x509_parse_int( p, 2, &time->hour ) ); - CHECK( x509_parse_int( p, 2, &time->min ) ); - if( len > 10 ) - CHECK( x509_parse_int( p, 2, &time->sec ) ); - if( len > 12 && *(*p)++ != 'Z' ) - return( POLARSSL_ERR_X509_INVALID_DATE ); - - time->year += 100 * ( time->year < 50 ); - time->year += 1900; - - return( 0 ); + return x509_parse_time( p, len, 2, time ); } else if( tag == ASN1_GENERALIZED_TIME ) { @@ -538,17 +607,7 @@ int x509_get_time( unsigned char **p, const unsigned char *end, if( ret != 0 ) return( POLARSSL_ERR_X509_INVALID_DATE + ret ); - CHECK( x509_parse_int( p, 4, &time->year ) ); - CHECK( x509_parse_int( p, 2, &time->mon ) ); - CHECK( x509_parse_int( p, 2, &time->day ) ); - CHECK( x509_parse_int( p, 2, &time->hour ) ); - CHECK( x509_parse_int( p, 2, &time->min ) ); - if( len > 12 ) - CHECK( x509_parse_int( p, 2, &time->sec ) ); - if( len > 14 && *(*p)++ != 'Z' ) - return( POLARSSL_ERR_X509_INVALID_DATE ); - - return( 0 ); + return x509_parse_time( p, len, 4, time ); } else return( POLARSSL_ERR_X509_INVALID_DATE +