- Added CRL revocation support to x509parse_verify()

- Fixed an off-by-one allocation in ssl_set_hostname()
 - Added CRL support to SSL/TLS code
This commit is contained in:
Paul Bakker 2009-05-03 10:18:48 +00:00
parent 7d06ad2b52
commit 40ea7de46d
9 changed files with 133 additions and 27 deletions

View file

@ -18,6 +18,10 @@ PolarSSL ChangeLog
systems (Found by Gernot). systems (Found by Gernot).
* Undefining POLARSSL_HAVE_ASM now also handles prevents asm in * Undefining POLARSSL_HAVE_ASM now also handles prevents asm in
padlock and timing code. padlock and timing code.
* Fixed an off-by-one buffer allocation in ssl_set_hostname().
* Added support for Certificate Revocation List (CRL parsing.
* Added support for CRL revocation to x509parse_verify() and
SSL/TLS code.
= Version 0.10.0 released on 2009-01-12 = Version 0.10.0 released on 2009-01-12
* Migrated XySSL to PolarSSL * Migrated XySSL to PolarSSL

View file

@ -235,6 +235,7 @@ struct _ssl_context
rsa_context *rsa_key; /*!< own RSA private key */ rsa_context *rsa_key; /*!< own RSA private key */
x509_cert *own_cert; /*!< own X.509 certificate */ x509_cert *own_cert; /*!< own X.509 certificate */
x509_cert *ca_chain; /*!< own trusted CA chain */ x509_cert *ca_chain; /*!< own trusted CA chain */
x509_crl *ca_crl; /*!< trusted CA CRLs */
x509_cert *peer_cert; /*!< peer X.509 cert chain */ x509_cert *peer_cert; /*!< peer X.509 cert chain */
char *peer_cn; /*!< expected peer CN */ char *peer_cn; /*!< expected peer CN */
@ -389,12 +390,13 @@ void ssl_set_ciphers( ssl_context *ssl, int *ciphers );
* *
* \param ssl SSL context * \param ssl SSL context
* \param ca_chain trusted CA chain * \param ca_chain trusted CA chain
* \param ca_crl trusted CA CRLs
* \param peer_cn expected peer CommonName (or NULL) * \param peer_cn expected peer CommonName (or NULL)
* *
* \note TODO: add two more parameters: depth and crl * \note TODO: add two more parameters: depth and crl
*/ */
void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,
char *peer_cn ); x509_crl *ca_crl, char *peer_cn );
/** /**
* \brief Set own certificate and private key * \brief Set own certificate and private key

View file

@ -60,6 +60,8 @@
#define BADCERT_REVOKED 2 #define BADCERT_REVOKED 2
#define BADCERT_CN_MISMATCH 4 #define BADCERT_CN_MISMATCH 4
#define BADCERT_NOT_TRUSTED 8 #define BADCERT_NOT_TRUSTED 8
#define BADCRL_NOT_TRUSTED 16
#define BADCRL_EXPIRED 32
/* /*
* DER constants * DER constants
@ -335,16 +337,17 @@ int x509parse_cert_info( char *buf, size_t size, char *prefix, x509_cert *crt );
int x509parse_crl_info( char *buf, size_t size, char *prefix, x509_crl *crl ); int x509parse_crl_info( char *buf, size_t size, char *prefix, x509_crl *crl );
/** /**
* \brief Return 0 if the certificate is still valid, * \brief Return 0 if the x509_time is still valid,
* or BADCERT_EXPIRED * or 1 otherwise.
*/ */
int x509parse_expired( x509_cert *crt ); int x509parse_time_expired( x509_time *time );
/** /**
* \brief Verify the certificate signature * \brief Verify the certificate signature
* *
* \param crt a certificate to be verified * \param crt a certificate to be verified
* \param trust_ca the trusted CA chain * \param trust_ca the trusted CA chain
* \param ca_crl the CRL chain for trusted CA's
* \param cn expected Common Name (can be set to * \param cn expected Common Name (can be set to
* NULL if the CN must not be verified) * NULL if the CN must not be verified)
* \param flags result of the verification * \param flags result of the verification
@ -361,6 +364,7 @@ int x509parse_expired( x509_cert *crt );
*/ */
int x509parse_verify( x509_cert *crt, int x509parse_verify( x509_cert *crt,
x509_cert *trust_ca, x509_cert *trust_ca,
x509_crl *ca_crl,
char *cn, int *flags ); char *cn, int *flags );
/** /**

View file

@ -1332,7 +1332,7 @@ int ssl_parse_certificate( ssl_context *ssl )
return( POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED ); return( POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED );
} }
ret = x509parse_verify( ssl->peer_cert, ssl->ca_chain, ret = x509parse_verify( ssl->peer_cert, ssl->ca_chain, ssl->ca_crl,
ssl->peer_cn, &ssl->verify_result ); ssl->peer_cn, &ssl->verify_result );
if( ret != 0 ) if( ret != 0 )
@ -1702,9 +1702,10 @@ void ssl_set_ciphers( ssl_context *ssl, int *ciphers )
} }
void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain, void ssl_set_ca_chain( ssl_context *ssl, x509_cert *ca_chain,
char *peer_cn ) x509_crl *ca_crl, char *peer_cn )
{ {
ssl->ca_chain = ca_chain; ssl->ca_chain = ca_chain;
ssl->ca_crl = ca_crl;
ssl->peer_cn = peer_cn; ssl->peer_cn = peer_cn;
} }
@ -1740,10 +1741,12 @@ int ssl_set_hostname( ssl_context *ssl, char *hostname )
return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); return( POLARSSL_ERR_SSL_BAD_INPUT_DATA );
ssl->hostname_len = strlen( hostname ); ssl->hostname_len = strlen( hostname );
ssl->hostname = (unsigned char *) malloc( ssl->hostname_len ); ssl->hostname = (unsigned char *) malloc( ssl->hostname_len + 1 );
memcpy( ssl->hostname, (unsigned char *) hostname, memcpy( ssl->hostname, (unsigned char *) hostname,
ssl->hostname_len ); ssl->hostname_len );
ssl->hostname[ssl->hostname_len] = '\0';
return( 0 ); return( 0 );
} }

View file

@ -2068,9 +2068,9 @@ int x509parse_crl_info( char *buf, size_t size, char *prefix, x509_crl *crl )
} }
/* /*
* Return 0 if the certificate is still valid, or BADCERT_EXPIRED * Return 0 if the x509_time is still valid, or 1 otherwise.
*/ */
int x509parse_expired( x509_cert *crt ) int x509parse_time_expired( x509_time *to )
{ {
struct tm *lt; struct tm *lt;
time_t tt; time_t tt;
@ -2078,17 +2078,38 @@ int x509parse_expired( x509_cert *crt )
tt = time( NULL ); tt = time( NULL );
lt = localtime( &tt ); lt = localtime( &tt );
if( lt->tm_year > crt->valid_to.year - 1900 ) if( lt->tm_year > to->year - 1900 )
return( BADCERT_EXPIRED ); return( 1 );
if( lt->tm_year == crt->valid_to.year - 1900 && if( lt->tm_year == to->year - 1900 &&
lt->tm_mon > crt->valid_to.mon - 1 ) lt->tm_mon > to->mon - 1 )
return( BADCERT_EXPIRED ); return( 1 );
if( lt->tm_year == crt->valid_to.year - 1900 && if( lt->tm_year == to->year - 1900 &&
lt->tm_mon == crt->valid_to.mon - 1 && lt->tm_mon == to->mon - 1 &&
lt->tm_mday > crt->valid_to.day ) lt->tm_mday > to->day )
return( BADCERT_EXPIRED ); return( 1 );
return( 0 );
}
/*
* Return 1 if the certificate is revoked, or 0 otherwise.
*/
int x509parse_revoked( x509_cert *crt, x509_crl *crl )
{
x509_crl_entry *cur = &crl->entry;
while( cur != NULL && cur->serial.len != 0 )
{
if( memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 )
{
if( x509parse_time_expired( &cur->revocation_date ) )
return( 1 );
}
cur = cur->next;
}
return( 0 ); return( 0 );
} }
@ -2125,6 +2146,7 @@ static void x509_hash( unsigned char *in, int len, int alg,
*/ */
int x509parse_verify( x509_cert *crt, int x509parse_verify( x509_cert *crt,
x509_cert *trust_ca, x509_cert *trust_ca,
x509_crl *ca_crl,
char *cn, int *flags ) char *cn, int *flags )
{ {
int cn_len; int cn_len;
@ -2134,7 +2156,10 @@ int x509parse_verify( x509_cert *crt,
x509_name *name; x509_name *name;
unsigned char hash[64]; unsigned char hash[64];
*flags = x509parse_expired( crt ); *flags = 0;
if( x509parse_time_expired( &crt->valid_to ) )
*flags = BADCERT_EXPIRED;
if( cn != NULL ) if( cn != NULL )
{ {
@ -2224,6 +2249,61 @@ int x509parse_verify( x509_cert *crt,
trust_ca = trust_ca->next; trust_ca = trust_ca->next;
} }
/*
* TODO: What happens if no CRL is present?
* Suggestion: Revocation state should be unknown if no CRL is present.
* For backwards compatibility this is not yet implemented.
*/
/*
* Check if the topmost certificate is revoked if the trusted CA is
* determined.
*/
while( trust_ca != NULL && ca_crl != NULL && ca_crl->version != 0 )
{
if( ca_crl->issuer_raw.len != trust_ca->subject_raw.len ||
memcmp( ca_crl->issuer_raw.p, trust_ca->subject_raw.p,
ca_crl->issuer_raw.len ) != 0 )
{
ca_crl = ca_crl->next;
continue;
}
/*
* Check if CRL is correctry signed by the trusted CA
*/
hash_id = ca_crl->sig_oid1.p[8];
x509_hash( ca_crl->tbs.p, ca_crl->tbs.len, hash_id, hash );
if( !rsa_pkcs1_verify( &trust_ca->rsa, RSA_PUBLIC, hash_id,
0, hash, ca_crl->sig.p ) == 0 )
{
/*
* CRL is not trusted
*/
*flags |= BADCRL_NOT_TRUSTED;
break;
}
/*
* Check for validity of CRL (Do not drop out)
*/
if( x509parse_time_expired( &ca_crl->next_update ) )
*flags |= BADCRL_EXPIRED;
/*
* Check if certificate is revoked
*/
if( x509parse_revoked(crt, ca_crl) )
{
*flags |= BADCERT_REVOKED;
break;
}
ca_crl = ca_crl->next;
}
if( *flags != 0 ) if( *flags != 0 )
return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED ); return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
@ -2406,7 +2486,7 @@ int x509_self_test( int verbose )
if( verbose != 0 ) if( verbose != 0 )
printf( "passed\n X.509 signature verify: "); printf( "passed\n X.509 signature verify: ");
ret = x509parse_verify( &clicert, &cacert, "Joe User", &i ); ret = x509parse_verify( &clicert, &cacert, NULL, "Joe User", &i );
if( ret != 0 ) if( ret != 0 )
{ {
if( verbose != 0 ) if( verbose != 0 )

View file

@ -158,7 +158,7 @@ int main( void )
ssl_set_ciphers( &ssl, ssl_default_ciphers ); ssl_set_ciphers( &ssl, ssl_default_ciphers );
ssl_set_session( &ssl, 1, 600, &ssn ); ssl_set_session( &ssl, 1, 600, &ssn );
ssl_set_ca_chain( &ssl, &cacert, SERVER_NAME ); ssl_set_ca_chain( &ssl, &cacert, NULL, SERVER_NAME );
ssl_set_own_cert( &ssl, &clicert, &rsa ); ssl_set_own_cert( &ssl, &clicert, &rsa );
ssl_set_hostname( &ssl, SERVER_NAME ); ssl_set_hostname( &ssl, SERVER_NAME );

View file

@ -286,7 +286,7 @@ accept:
memset( &ssn, 0, sizeof( ssl_session ) ); memset( &ssn, 0, sizeof( ssl_session ) );
ssl_set_ca_chain( &ssl, srvcert.next, NULL ); ssl_set_ca_chain( &ssl, srvcert.next, NULL, NULL );
ssl_set_own_cert( &ssl, &srvcert, &rsa ); ssl_set_own_cert( &ssl, &srvcert, &rsa );
ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G ); ssl_set_dh_param( &ssl, my_dhm_P, my_dhm_G );

View file

@ -32,12 +32,14 @@
#define snprintf _snprintf #define snprintf _snprintf
#endif #endif
#define MAX_CLIENT_CERTS 6 #define MAX_CLIENT_CERTS 8
char *client_certificates[MAX_CLIENT_CERTS] = char *client_certificates[MAX_CLIENT_CERTS] =
{ {
"client1.crt", "client1.crt",
"client2.crt", "client2.crt",
"server1.crt",
"server2.crt",
"cert_sha224.crt", "cert_sha224.crt",
"cert_sha256.crt", "cert_sha256.crt",
"cert_sha384.crt", "cert_sha384.crt",
@ -48,6 +50,8 @@ char *client_private_keys[MAX_CLIENT_CERTS] =
{ {
"client1.key", "client1.key",
"client2.key", "client2.key",
"server1.key",
"server2.key",
"cert_sha224.key", "cert_sha224.key",
"cert_sha256.key", "cert_sha256.key",
"cert_sha384.key", "cert_sha384.key",
@ -83,6 +87,9 @@ int main( void )
printf( " ok\n" ); printf( " ok\n" );
x509parse_cert_info( buf, 1024, "CRT: ", &cacert );
printf("%s\n", buf );
/* /*
* 1.2. Load the CRL * 1.2. Load the CRL
*/ */
@ -134,11 +141,17 @@ int main( void )
printf( " . Verify the client certificate with CA certificate..." ); printf( " . Verify the client certificate with CA certificate..." );
fflush( stdout ); fflush( stdout );
ret = x509parse_verify( &clicert, &cacert, NULL, &flags ); ret = x509parse_verify( &clicert, &cacert, &crl, NULL, &flags );
if( ret != 0 ) if( ret != 0 )
{ {
printf( " failed\n ! x509parse_verify returned %d\n\n", ret ); if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
goto exit; {
if( flags == BADCERT_REVOKED )
printf( " REVOKED " );
} else {
printf( " failed\n ! x509parse_verify returned %d\n\n", ret );
goto exit;
}
} }
printf( " ok\n" ); printf( " ok\n" );

View file

@ -225,7 +225,7 @@ static int ssl_test( struct options *opt )
ssl_set_endpoint( &ssl, SSL_IS_SERVER ); ssl_set_endpoint( &ssl, SSL_IS_SERVER );
ssl_set_dh_param( &ssl, dhm_P, dhm_G ); ssl_set_dh_param( &ssl, dhm_P, dhm_G );
ssl_set_ca_chain( &ssl, srvcert.next, NULL ); ssl_set_ca_chain( &ssl, srvcert.next, NULL, NULL );
ssl_set_own_cert( &ssl, &srvcert, &rsa ); ssl_set_own_cert( &ssl, &srvcert, &rsa );
} }