Add option for relaxed X509 time verification.

The certificates are not valid according to the RFC, but are in wide
distribution across the internet. Hence the request to add a
compile-time flag to accept these certificates if wanted by the
application.

If POLARSSL_RELAXED_X509_DATE is enabled it will allow dates without
seconds, and allow dates with timezones (but doesn't actually use
the timezone).

Patch provided by OpenVPN.
This commit is contained in:
Janos Follath 2016-09-19 09:35:18 +01:00
parent 2d01f2d4c5
commit 17da9dd829
3 changed files with 102 additions and 25 deletions

View file

@ -1,5 +1,12 @@
mbed TLS ChangeLog (Sorted per branch, date) 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 = mbed TLS 1.3.17 branch 2016-06-28
Security Security

View file

@ -1176,6 +1176,17 @@
*/ */
//#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION //#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 * \def POLARSSL_X509_CHECK_KEY_USAGE
* *

View file

@ -489,6 +489,88 @@ static int x509_parse_int(unsigned char **p, unsigned n, int *res){
return 0; 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 { * Time ::= CHOICE {
* utcTime UTCTime, * utcTime UTCTime,
@ -515,20 +597,7 @@ int x509_get_time( unsigned char **p, const unsigned char *end,
if( ret != 0 ) if( ret != 0 )
return( POLARSSL_ERR_X509_INVALID_DATE + ret ); return( POLARSSL_ERR_X509_INVALID_DATE + ret );
CHECK( x509_parse_int( p, 2, &time->year ) ); return x509_parse_time( p, len, 2, time );
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 );
} }
else if( tag == ASN1_GENERALIZED_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 ) if( ret != 0 )
return( POLARSSL_ERR_X509_INVALID_DATE + ret ); return( POLARSSL_ERR_X509_INVALID_DATE + ret );
CHECK( x509_parse_int( p, 4, &time->year ) ); return x509_parse_time( p, len, 4, time );
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 );
} }
else else
return( POLARSSL_ERR_X509_INVALID_DATE + return( POLARSSL_ERR_X509_INVALID_DATE +