diff options
author | Paul Bakker <p.j.bakker@polarssl.org> | 2009-05-02 15:13:40 +0000 |
---|---|---|
committer | Paul Bakker <p.j.bakker@polarssl.org> | 2009-05-02 15:13:40 +0000 |
commit | d98030e7d6c91fadfd0055340cb8946d1ecd7adc (patch) | |
tree | 0afa849dac2573e8224286728a6807152c1ac864 | |
parent | 68041ec500b1fefa3481425d24f0d2befdeadb34 (diff) | |
download | mbedtls-d98030e7d6c91fadfd0055340cb8946d1ecd7adc.zip mbedtls-d98030e7d6c91fadfd0055340cb8946d1ecd7adc.tar.gz mbedtls-d98030e7d6c91fadfd0055340cb8946d1ecd7adc.tar.bz2 |
- Added prelimenary CRL parsing and info support
-rw-r--r-- | include/polarssl/x509.h | 80 | ||||
-rw-r--r-- | library/debug.c | 7 | ||||
-rw-r--r-- | library/x509parse.c | 896 | ||||
-rw-r--r-- | programs/ssl/ssl_client2.c | 3 | ||||
-rw-r--r-- | programs/test/ssl_cert_test.c | 196 |
5 files changed, 965 insertions, 217 deletions
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h index 7b76fb5..c0a50b7 100644 --- a/include/polarssl/x509.h +++ b/include/polarssl/x509.h @@ -169,6 +169,46 @@ typedef struct _x509_cert } x509_cert; +typedef struct _x509_crl_entry +{ + x509_buf raw; + + x509_buf serial; + + x509_time revocation_date; + + x509_buf entry_ext; + + struct _x509_crl_entry *next; +} +x509_crl_entry; + +typedef struct _x509_crl +{ + x509_buf raw; + x509_buf tbs; + + int version; + x509_buf sig_oid1; + + x509_buf issuer_raw; + + x509_name issuer; + + x509_time this_update; + x509_time next_update; + + x509_crl_entry entry; + + x509_buf crl_ext; + + x509_buf sig_oid2; + x509_buf sig; + + struct _x509_crl *next; +} +x509_crl; + /* * Structures for writing X.509 certificates */ @@ -228,6 +268,29 @@ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ); int x509parse_crtfile( x509_cert *chain, char *path ); /** + * \brief Parse one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_crl( x509_crl *chain, unsigned char *buf, int buflen ); + +/** + * \brief Load one or more CRLs and add them + * to the chained list + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from + * + * \return 0 if successful, or a specific X509 error code + */ +int x509parse_crlfile( x509_crl *chain, char *path ); + +/** * \brief Parse a private RSA key * * \param rsa RSA context to be initialized @@ -255,15 +318,21 @@ int x509parse_keyfile( rsa_context *rsa, char *path, char *password ); /** * \brief Store the certificate DN in printable form into buf; - * no more than (end - buf) characters will be written. + * no more than size characters will be written. */ -int x509parse_dn_gets( char *buf, char *end, x509_name *dn ); +int x509parse_dn_gets( char *buf, size_t size, x509_name *dn ); /** * \brief Returns an informational string about the * certificate. */ -char *x509parse_cert_info( char *prefix, x509_cert *crt ); +int x509parse_cert_info( char *buf, size_t size, char *prefix, x509_cert *crt ); + +/** + * \brief Returns an informational string about the + * CRL. + */ +int x509parse_crl_info( char *buf, size_t size, char *prefix, x509_crl *crl ); /** * \brief Return 0 if the certificate is still valid, @@ -300,6 +369,11 @@ int x509parse_verify( x509_cert *crt, void x509_free( x509_cert *crt ); /** + * \brief Unallocate all CRL data + */ +void x509_crl_free( x509_crl *crl ); + +/** * \brief Checkup routine * * \return 0 if successful, or 1 if the test failed diff --git a/library/debug.c b/library/debug.c index c5bfa0a..cd7664d 100644 --- a/library/debug.c +++ b/library/debug.c @@ -171,7 +171,7 @@ void debug_print_mpi( ssl_context *ssl, int level, void debug_print_crt( ssl_context *ssl, int level, char *file, int line, char *text, x509_cert *crt ) { - char str[1024], prefix[64], *p; + char str[1024], prefix[64]; int i = 0, maxlen = sizeof( prefix ) - 1; if( ssl->f_dbg == NULL || crt == NULL ) @@ -183,10 +183,11 @@ void debug_print_crt( ssl_context *ssl, int level, while( crt != NULL && crt->next != NULL ) { - p = x509parse_cert_info( prefix, crt ); + char buf[1024]; + x509parse_cert_info( buf, sizeof( buf ) - 1, prefix, crt ); snprintf( str, maxlen, "%s(%04d): %s #%d:\n%s", - file, line, text, ++i, p ); + file, line, text, ++i, buf ); str[maxlen] = '\0'; ssl->f_dbg( ssl->p_dbg, level, str ); diff --git a/library/x509parse.c b/library/x509parse.c index feb4d50..d6eafeb 100644 --- a/library/x509parse.c +++ b/library/x509parse.c @@ -351,31 +351,17 @@ static int x509_get_name( unsigned char **p, } /* - * Validity ::= SEQUENCE { - * notBefore Time, - * notAfter Time } - * * Time ::= CHOICE { * utcTime UTCTime, * generalTime GeneralizedTime } */ -static int x509_get_dates( unsigned char **p, - unsigned char *end, - x509_time *from, - x509_time *to ) +static int x509_get_UTCTime( unsigned char **p, + unsigned char *end, + x509_time *time ) { int ret, len; char date[64]; - if( ( ret = asn1_get_tag( p, end, &len, - ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE | ret ); - - end = *p + len; - - /* - * TODO: also handle GeneralizedTime - */ if( ( ret = asn1_get_tag( p, end, &len, ASN1_UTC_TIME ) ) != 0 ) return( POLARSSL_ERR_X509_CERT_INVALID_DATE | ret ); @@ -384,31 +370,45 @@ static int x509_get_dates( unsigned char **p, len : (int) sizeof( date ) - 1 ); if( sscanf( date, "%2d%2d%2d%2d%2d%2d", - &from->year, &from->mon, &from->day, - &from->hour, &from->min, &from->sec ) < 5 ) + &time->year, &time->mon, &time->day, + &time->hour, &time->min, &time->sec ) < 5 ) return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); - from->year += 100 * ( from->year < 90 ); - from->year += 1900; + time->year += 100 * ( time->year < 90 ); + time->year += 1900; *p += len; - if( ( ret = asn1_get_tag( p, end, &len, ASN1_UTC_TIME ) ) != 0 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE | ret ); + return( 0 ); +} - memset( date, 0, sizeof( date ) ); - memcpy( date, *p, ( len < (int) sizeof( date ) - 1 ) ? - len : (int) sizeof( date ) - 1 ); - if( sscanf( date, "%2d%2d%2d%2d%2d%2d", - &to->year, &to->mon, &to->day, - &to->hour, &to->min, &to->sec ) < 5 ) - return( POLARSSL_ERR_X509_CERT_INVALID_DATE ); +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ +static int x509_get_dates( unsigned char **p, + unsigned char *end, + x509_time *from, + x509_time *to ) +{ + int ret, len; - to->year += 100 * ( to->year < 90 ); - to->year += 1900; + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_DATE | ret ); - *p += len; + end = *p + len; + + /* + * TODO: also handle GeneralizedTime + */ + if( ( ret = x509_get_UTCTime( p, end, from ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_UTCTime( p, end, to ) ) != 0 ) + return( ret ); if( *p != end ) return( POLARSSL_ERR_X509_CERT_INVALID_DATE | @@ -529,32 +529,23 @@ static int x509_get_uid( unsigned char **p, } /* - * X.509 v3 extensions (only BasicConstraints are parsed) + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed! */ static int x509_get_ext( unsigned char **p, unsigned char *end, - x509_buf *ext, - int *ca_istrue, - int *max_pathlen ) + x509_buf *ext ) { int ret, len; - int is_critical = 1; - int is_cacert = 0; - unsigned char *end2; if( *p == end ) return( 0 ); ext->tag = **p; - + if( ( ret = asn1_get_tag( p, end, &ext->len, ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 3 ) ) != 0 ) - { - if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) - return( 0 ); - return( ret ); - } ext->p = *p; end = *p + ext->len; @@ -575,6 +566,64 @@ static int x509_get_ext( unsigned char **p, return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS | POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + return( 0 ); +} + +/* + * X.509 CRL v2 extensions (no extensions parsed yet.) + */ +static int x509_get_crl_ext( unsigned char **p, + unsigned char *end, + x509_buf *ext ) +{ + int ret, len; + + if( ( ret = x509_get_ext( p, end, ext ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + if( ( ret = asn1_get_tag( p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS | ret ); + + *p += len; + } + + if( *p != end ) + return( POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS | + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v3 extensions (only BasicConstraints are parsed) + */ +static int x509_get_crt_ext( unsigned char **p, + unsigned char *end, + x509_buf *ext, + int *ca_istrue, + int *max_pathlen ) +{ + int ret, len; + int is_critical = 1; + int is_cacert = 0; + unsigned char *end2; + + if( ( ret = x509_get_ext( p, end, ext ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + while( *p < end ) { if( ( ret = asn1_get_tag( p, end, &len, @@ -646,6 +695,65 @@ static int x509_get_ext( unsigned char **p, } /* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + unsigned char *end, + x509_crl_entry *entry ) +{ + int ret; + x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + entry->raw.tag = **p; + + if( ( ret = asn1_get_tag( p, end, &entry->raw.len, + ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + entry->raw.p = *p; + end = *p + entry->raw.len; + + while( *p < end ) + { + int len2; + + if( ( ret = asn1_get_tag( p, end, &len2, + ASN1_SEQUENCE | ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + if( ( ret = x509_get_serial( p, end, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_UTCTime( p, end, &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_ext( p, end, &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if ( *p < end ) { + cur_entry->next = malloc( sizeof( x509_crl_entry ) ); + cur_entry = cur_entry->next; + memset( cur_entry, 0, sizeof( x509_crl_entry ) ); + } + } + + return( 0 ); +} + +/* * Parse one or more certificates and add them to the chained list */ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ) @@ -673,14 +781,14 @@ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ) { crt->next = (x509_cert *) malloc( sizeof( x509_cert ) ); - if( crt->next == NULL ) - { + if( crt->next == NULL ) + { x509_free( crt ); - return( 1 ); - } + return( 1 ); + } - crt = crt->next; - memset( crt, 0, sizeof( x509_cert ) ); + crt = crt->next; + memset( crt, 0, sizeof( x509_cert ) ); } /* @@ -821,7 +929,7 @@ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ) if( crt->sig_oid1.p[8] < 2 || ( crt->sig_oid1.p[8] > 5 && crt->sig_oid1.p[8] < 11 ) || - crt->sig_oid1.p[8] > 14 ) + crt->sig_oid1.p[8] > 14 ) { x509_free( crt ); return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); @@ -937,7 +1045,7 @@ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ) if( crt->version == 3 ) { - ret = x509_get_ext( &p, end, &crt->v3_ext, + ret = x509_get_crt_ext( &p, end, &crt->v3_ext, &crt->ca_istrue, &crt->max_pathlen ); if( ret != 0 ) { @@ -988,14 +1096,14 @@ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ) { crt->next = (x509_cert *) malloc( sizeof( x509_cert ) ); - if( crt->next == NULL ) - { + if( crt->next == NULL ) + { x509_free( crt ); - return( 1 ); - } + return( 1 ); + } - crt = crt->next; - memset( crt, 0, sizeof( x509_cert ) ); + crt = crt->next; + memset( crt, 0, sizeof( x509_cert ) ); return( x509parse_crt( crt, buf, buflen ) ); } @@ -1004,34 +1112,338 @@ int x509parse_crt( x509_cert *chain, unsigned char *buf, int buflen ) } /* + * Parse one or more CRLs and add them to the chained list + */ +int x509parse_crl( x509_crl *chain, unsigned char *buf, int buflen ) +{ + int ret, len; + unsigned char *s1, *s2; + unsigned char *p, *end; + x509_crl *crl; + + crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( 1 ); + + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + /* + * Add new CRL on the end of the chain if needed. + */ + if ( crl->version != 0 && crl->next == NULL) + { + crl->next = (x509_crl *) malloc( sizeof( x509_crl ) ); + + if( crl->next == NULL ) + { + x509_crl_free( crl ); + return( 1 ); + } + + crl = crl->next; + memset( crl, 0, sizeof( x509_crl ) ); + } + + /* + * check if the CRL is encoded in base64 + */ + s1 = (unsigned char *) strstr( (char *) buf, + "-----BEGIN X509 CRL-----" ); + + if( s1 != NULL ) + { + s2 = (unsigned char *) strstr( (char *) buf, + "-----END X509 CRL-----" ); + + if( s2 == NULL || s2 <= s1 ) + return( POLARSSL_ERR_X509_CERT_INVALID_PEM ); + + s1 += 24; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( POLARSSL_ERR_X509_CERT_INVALID_PEM ); + + /* + * get the DER data length and decode the buffer + */ + len = 0; + ret = base64_decode( NULL, &len, s1, s2 - s1 ); + + if( ret == POLARSSL_ERR_BASE64_INVALID_CHARACTER ) + return( POLARSSL_ERR_X509_CERT_INVALID_PEM | ret ); + + if( ( p = (unsigned char *) malloc( len ) ) == NULL ) + return( 1 ); + + if( ( ret = base64_decode( p, &len, s1, s2 - s1 ) ) != 0 ) + { + free( p ); + return( POLARSSL_ERR_X509_CERT_INVALID_PEM | ret ); + } + + /* + * update the buffer size and offset + */ + s2 += 22; + if( *s2 == '\r' ) s2++; + if( *s2 == '\n' ) s2++; + else + { + free( p ); + return( POLARSSL_ERR_X509_CERT_INVALID_PEM ); + } + + buflen -= s2 - buf; + buf = s2; + } + else + { + /* + * nope, copy the raw DER data + */ + p = (unsigned char *) malloc( len = buflen ); + + if( p == NULL ) + return( 1 ); + + memcpy( p, buf, buflen ); + + buflen = 0; + } + + crl->raw.p = p; + crl->raw.len = len; + end = p + len; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT ); + } + + if( len != (int) ( end - p ) ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT | + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT | ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = x509_get_alg( &p, end, &crl->sig_oid1 ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + crl->version++; + + if( crl->version > 2 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION ); + } + + if( crl->sig_oid1.len != 9 || + memcmp( crl->sig_oid1.p, OID_PKCS1, 8 ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); + } + + if( crl->sig_oid1.p[8] < 2 || + ( crl->sig_oid1.p[8] > 5 && crl->sig_oid1.p[8] < 11 ) || + crl->sig_oid1.p[8] > 14 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = asn1_get_tag( &p, end, &len, + ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT | ret ); + } + + if( ( ret = x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = x509_get_UTCTime( &p, end, &crl->this_update ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = x509_get_UTCTime( &p, end, &crl->next_update ) ) != 0 ) + { + if ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) { + x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT | + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = x509_get_alg( &p, end, &crl->sig_oid2 ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_SIG_MISMATCH ); + } + + if( ( ret = x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + x509_crl_free( crl ); + return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT | + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( buflen > 0 ) + { + crl->next = (x509_crl *) malloc( sizeof( x509_crl ) ); + + if( crl->next == NULL ) + { + x509_crl_free( crl ); + return( 1 ); + } + + crl = crl->next; + memset( crl, 0, sizeof( x509_crl ) ); + + return( x509parse_crl( crl, buf, buflen ) ); + } + + return( 0 ); +} + +/* * Load all data from a file into a given buffer. */ int load_file( char *path, unsigned char **buf, size_t *n ) { - FILE *f; + FILE *f; - if( ( f = fopen( path, "rb" ) ) == NULL ) - return( 1 ); + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( 1 ); - fseek( f, 0, SEEK_END ); - *n = (size_t) ftell( f ); - fseek( f, 0, SEEK_SET ); + fseek( f, 0, SEEK_END ); + *n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); - if( ( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL ) - return( 1 ); + if( ( *buf = (unsigned char *) malloc( *n + 1 ) ) == NULL ) + return( 1 ); - if( fread( *buf, 1, *n, f ) != *n ) - { - fclose( f ); - free( *buf ); - return( 1 ); - } + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + free( *buf ); + return( 1 ); + } - fclose( f ); + fclose( f ); - (*buf)[*n] = '\0'; + (*buf)[*n] = '\0'; - return( 0 ); + return( 0 ); } /* @@ -1054,6 +1466,26 @@ int x509parse_crtfile( x509_cert *chain, char *path ) return( ret ); } +/* + * Load one or more CRLs and add them to the chained list + */ +int x509parse_crlfile( x509_crl *chain, char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if ( load_file( path, &buf, &n ) ) + return( 1 ); + + ret = x509parse_crl( chain, buf, (int) n ); + + memset( buf, 0, n + 1 ); + free( buf ); + + return( ret ); +} + #if defined(POLARSSL_DES_C) /* * Read a 16-byte hex string and convert it to binary @@ -1331,16 +1763,63 @@ int x509parse_keyfile( rsa_context *rsa, char *path, char *pwd ) } #if defined _MSC_VER && !defined snprintf -#define snprintf _snprintf +#include <stdarg.h> + +#if !defined vsnprintf +#define vsnprintf _vsnprintf +#endif // vsnprintf + +/* + * Windows _snprintf and _vsnprintf are not compatible to linux versions. + * Result value is not size of buffer needed, but -1 if no fit is possible. + * + * This fuction tries to 'fix' this by at least suggesting enlarging the + * size by 20. + */ +int compat_snprintf(char *str, size_t size, const char *format, ...) +{ + va_list ap; + int res = -1; + + va_start( ap, format ); + + res = vsnprintf( str, size, format, ap ); + + va_end( ap ); + + // No quick fix possible + if ( res < 0 ) + return( size + 20 ); + + return res; +} + +#define snprintf compat_snprintf #endif +#define POLARSSL_ERR_DEBUG_BUF_TOO_SMALL -2 + +#define SAFE_SNPRINTF() \ +{ \ + if( ret == -1 ) \ + return( -1 ); \ + \ + if ( ret > n ) { \ + p[n - 1] = '\0'; \ + return POLARSSL_ERR_DEBUG_BUF_TOO_SMALL;\ + } \ + \ + n -= ret; \ + p += ret; \ +} + /* * Store the name in printable form into buf; no more - * than (end - buf) characters will be written + * than size characters will be written */ -int x509parse_dn_gets( char *buf, char *end, x509_name *dn ) +int x509parse_dn_gets( char *buf, size_t size, x509_name *dn ) { - int i; + int i, ret, n; unsigned char c; x509_name *name; char s[128], *p; @@ -1349,55 +1828,63 @@ int x509parse_dn_gets( char *buf, char *end, x509_name *dn ) name = dn; p = buf; + n = size; while( name != NULL ) { - if( name != dn ) - p += snprintf( p, end - p, ", " ); + if( name != dn ) { + ret = snprintf( p, n, ", " ); + SAFE_SNPRINTF(); + } if( memcmp( name->oid.p, OID_X520, 2 ) == 0 ) { switch( name->oid.p[2] ) { case X520_COMMON_NAME: - p += snprintf( p, end - p, "CN=" ); break; + ret = snprintf( p, n, "CN=" ); break; case X520_COUNTRY: - p += snprintf( p, end - p, "C=" ); break; + ret = snprintf( p, n, "C=" ); break; case X520_LOCALITY: - p += snprintf( p, end - p, "L=" ); break; + ret = snprintf( p, n, "L=" ); break; case X520_STATE: - p += snprintf( p, end - p, "ST=" ); break; + ret = snprintf( p, n, "ST=" ); break; case X520_ORGANIZATION: - p += snprintf( p, end - p, "O=" ); break; + ret = snprintf( p, n, "O=" ); break; case X520_ORG_UNIT: - p += snprintf( p, end - p, "OU=" ); break; + ret = snprintf( p, n, "OU=" ); break; default: - p += snprintf( p, end - p, "0x%02X=", + ret = snprintf( p, n, "0x%02X=", name->oid.p[2] ); break; } + SAFE_SNPRINTF(); } else if( memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 ) { switch( name->oid.p[8] ) { case PKCS9_EMAIL: - p += snprintf( p, end - p, "emailAddress=" ); break; + ret = snprintf( p, n, "emailAddress=" ); break; default: - p += snprintf( p, end - p, "0x%02X=", + ret = snprintf( p, n, "0x%02X=", name->oid.p[8] ); break; } + SAFE_SNPRINTF(); } else - p += snprintf( p, end - p, "\?\?=" ); + { + ret = snprintf( p, n, "\?\?=" ); + SAFE_SNPRINTF(); + } for( i = 0; i < name->val.len; i++ ) { @@ -1410,75 +1897,174 @@ int x509parse_dn_gets( char *buf, char *end, x509_name *dn ) else s[i] = c; } s[i] = '\0'; - p += snprintf( p, end - p, "%s", s ); + ret = snprintf( p, n, "%s", s ); + SAFE_SNPRINTF(); name = name->next; } - return( p - buf ); + return( size - n ); } /* - * Return an informational string about the - * certificate, or NULL if memory allocation failed + * Return an informational string about the certificate. */ -char *x509parse_cert_info( char *prefix, x509_cert *crt ) +int x509parse_cert_info( char *buf, size_t size, char *prefix, x509_cert *crt ) { - int i, n; - char *p, *end; - static char buf[1024]; + int i, n, nr, ret; + char *p; p = buf; - end = buf + sizeof( buf ) - 1; + n = size; - p += snprintf( p, end - p, "%scert. version : %d\n", + ret = snprintf( p, n, "%scert. version : %d\n", prefix, crt->version ); - p += snprintf( p, end - p, "%sserial number : ", + SAFE_SNPRINTF(); + ret = snprintf( p, n, "%sserial number : ", prefix ); + SAFE_SNPRINTF(); - n = ( crt->serial.len <= 32 ) + nr = ( crt->serial.len <= 32 ) ? crt->serial.len : 32; - for( i = 0; i < n; i++ ) - p += snprintf( p, end - p, "%02X%s", - crt->serial.p[i], ( i < n - 1 ) ? ":" : "" ); + for( i = 0; i < nr; i++ ) + { + ret = snprintf( p, n, "%02X%s", + crt->serial.p[i], ( i < nr - 1 ) ? ":" : "" ); + SAFE_SNPRINTF(); + } - p += snprintf( p, end - p, "\n%sissuer name : ", prefix ); - p += x509parse_dn_gets( p, end, &crt->issuer ); + ret = snprintf( p, n, "\n%sissuer name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crt->issuer ); + SAFE_SNPRINTF(); - p += snprintf( p, end - p, "\n%ssubject name : ", prefix ); - p += x509parse_dn_gets( p, end, &crt->subject ); + ret = snprintf( p, n, "\n%ssubject name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crt->subject ); + SAFE_SNPRINTF(); - p += snprintf( p, end - p, "\n%sissued on : " \ + ret = snprintf( p, n, "\n%sissued on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, crt->valid_from.year, crt->valid_from.mon, crt->valid_from.day, crt->valid_from.hour, crt->valid_from.min, crt->valid_from.sec ); + SAFE_SNPRINTF(); - p += snprintf( p, end - p, "\n%sexpires on : " \ + ret = snprintf( p, n, "\n%sexpires on : " \ "%04d-%02d-%02d %02d:%02d:%02d", prefix, crt->valid_to.year, crt->valid_to.mon, crt->valid_to.day, crt->valid_to.hour, crt->valid_to.min, crt->valid_to.sec ); + SAFE_SNPRINTF(); - p += snprintf( p, end - p, "\n%ssigned using : RSA+", prefix ); + ret = snprintf( p, n, "\n%ssigned using : RSA+", prefix ); + SAFE_SNPRINTF(); switch( crt->sig_oid1.p[8] ) { - case SIG_RSA_MD2 : p += snprintf( p, end - p, "MD2" ); break; - case SIG_RSA_MD4 : p += snprintf( p, end - p, "MD4" ); break; - case SIG_RSA_MD5 : p += snprintf( p, end - p, "MD5" ); break; - case SIG_RSA_SHA1 : p += snprintf( p, end - p, "SHA1" ); break; - case SIG_RSA_SHA224 : p += snprintf( p, end - p, "SHA224" ); break; - case SIG_RSA_SHA256 : p += snprintf( p, end - p, "SHA256" ); break; - case SIG_RSA_SHA384 : p += snprintf( p, end - p, "SHA384" ); break; - case SIG_RSA_SHA512 : p += snprintf( p, end - p, "SHA512" ); break; - default: p += snprintf( p, end - p, "???" ); break; + case SIG_RSA_MD2 : ret = snprintf( p, n, "MD2" ); break; + case SIG_RSA_MD4 : ret = snprintf( p, n, "MD4" ); break; + case SIG_RSA_MD5 : ret = snprintf( p, n, "MD5" ); break; + case SIG_RSA_SHA1 : ret = snprintf( p, n, "SHA1" ); break; + case SIG_RSA_SHA224 : ret = snprintf( p, n, "SHA224" ); break; + case SIG_RSA_SHA256 : ret = snprintf( p, n, "SHA256" ); break; + case SIG_RSA_SHA384 : ret = snprintf( p, n, "SHA384" ); break; + case SIG_RSA_SHA512 : ret = snprintf( p, n, "SHA512" ); break; + default: ret = snprintf( p, n, "???" ); break; } + SAFE_SNPRINTF(); - p += snprintf( p, end - p, "\n%sRSA key size : %d bits\n", prefix, + ret = snprintf( p, n, "\n%sRSA key size : %d bits\n", prefix, crt->rsa.N.n * (int) sizeof( unsigned long ) * 8 ); + SAFE_SNPRINTF(); - return( buf ); + return( size - n ); +} + +/* + * Return an informational string about the CRL. + */ +int x509parse_crl_info( char *buf, size_t size, char *prefix, x509_crl *crl ) +{ + int i, n, nr, ret; + char *p; + x509_crl_entry *entry; + + p = buf; + n = size; + + ret = snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sissuer name : ", prefix ); + SAFE_SNPRINTF(); + ret = x509parse_dn_gets( p, n, &crl->issuer ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + SAFE_SNPRINTF(); + + ret = snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + SAFE_SNPRINTF(); + + entry = &crl->entry; + + ret = snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + SAFE_SNPRINTF(); + + while( entry != NULL ) + { + ret = snprintf( p, n, "\n%sserial number: ", + prefix ); + SAFE_SNPRINTF(); + + nr = ( entry->serial.len <= 32 ) + ? entry->serial.len : 32; + + for( i = 0; i < nr; i++ ) { + ret = snprintf( p, n, "%02X%s", + entry->serial.p[i], ( i < nr - 1 ) ? ":" : "" ); + SAFE_SNPRINTF(); + } + + ret = snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + SAFE_SNPRINTF(); + + entry = entry->next; + } + + ret = snprintf( p, n, "\n%ssigned using : RSA+", prefix ); + SAFE_SNPRINTF(); + + switch( crl->sig_oid1.p[8] ) + { + case SIG_RSA_MD2 : ret = snprintf( p, n, "MD2" ); break; + case SIG_RSA_MD4 : ret = snprintf( p, n, "MD4" ); break; + case SIG_RSA_MD5 : ret = snprintf( p, n, "MD5" ); break; + case SIG_RSA_SHA1 : ret = snprintf( p, n, "SHA1" ); break; + case SIG_RSA_SHA224 : ret = snprintf( p, n, "SHA224" ); break; + case SIG_RSA_SHA256 : ret = snprintf( p, n, "SHA256" ); break; + case SIG_RSA_SHA384 : ret = snprintf( p, n, "SHA384" ); break; + case SIG_RSA_SHA512 : ret = snprintf( p, n, "SHA512" ); break; + default: ret = snprintf( p, n, "???" ); break; + } + SAFE_SNPRINTF(); + + return( size - n ); } /* @@ -1702,6 +2288,64 @@ void x509_free( x509_cert *crt ) while( cert_cur != NULL ); } +/* + * Unallocate all CRL data + */ +void x509_crl_free( x509_crl *crl ) +{ + x509_crl *crl_cur = crl; + x509_crl *crl_prv; + x509_name *name_cur; + x509_name *name_prv; + x509_crl_entry *entry_cur; + x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { + name_cur = crl_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + memset( name_prv, 0, sizeof( x509_name ) ); + free( name_prv ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + memset( entry_prv, 0, sizeof( x509_crl_entry ) ); + free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + memset( crl_cur->raw.p, 0, crl_cur->raw.len ); + free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + memset( crl_prv, 0, sizeof( x509_crl ) ); + if( crl_prv != crl ) + free( crl_prv ); + } + while( crl_cur != NULL ); +} + #if defined(POLARSSL_SELF_TEST) #include "polarssl/certs.h" diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index b7a9728..66e0c69 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -208,7 +208,8 @@ int main( void ) printf( " ok\n" ); printf( " . Peer certificate information ...\n" ); - printf( x509parse_cert_info( " ", ssl.peer_cert ) ); + x509parse_cert_info( (char *) buf, sizeof( buf ) - 1, " ", ssl.peer_cert ); + printf( "%s\n", buf ); /* * 6. Write the GET request diff --git a/programs/test/ssl_cert_test.c b/programs/test/ssl_cert_test.c index 1be4341..a0c2e13 100644 --- a/programs/test/ssl_cert_test.c +++ b/programs/test/ssl_cert_test.c @@ -28,33 +28,41 @@ #include "polarssl/certs.h" #include "polarssl/x509.h" -#define MAX_CLIENT_CERTS 6 +#if defined _MSC_VER && !defined snprintf +#define snprintf _snprintf +#endif + +#define MAX_CLIENT_CERTS 6 char *client_certificates[MAX_CLIENT_CERTS] = { - "client1.crt", - "client2.crt", - "cert_sha224.crt", - "cert_sha256.crt", - "cert_sha384.crt", - "cert_sha512.crt" + "client1.crt", + "client2.crt", + "cert_sha224.crt", + "cert_sha256.crt", + "cert_sha384.crt", + "cert_sha512.crt" }; char *client_private_keys[MAX_CLIENT_CERTS] = { - "client1.key", - "client2.key", - "cert_sha224.key", - "cert_sha256.key", - "cert_sha384.key", - "cert_sha512.key" + "client1.key", + "client2.key", + "cert_sha224.key", + "cert_sha256.key", + "cert_sha384.key", + "cert_sha512.key" }; int main( void ) { int ret, i; - x509_cert cacert, clicert; - rsa_context rsa; + x509_cert cacert; + x509_crl crl; + char buf[10240]; + + memset( &cacert, 0, sizeof( x509_cert ) ); + memset( &crl, 0, sizeof( x509_crl ) ); /* * 1.1. Load the trusted CA @@ -62,8 +70,6 @@ int main( void ) printf( "\n . Loading the CA root certificate ..." ); fflush( stdout ); - memset( &cacert, 0, sizeof( x509_cert ) ); - /* * Alternatively, you may load the CA certificates from a .pem or * .crt file by calling x509parse_crtfile( &cacert, "myca.crt" ). @@ -77,97 +83,119 @@ int main( void ) printf( " ok\n" ); + /* + * 1.2. Load the CRL + */ + printf( " . Loading the CRL ..." ); + fflush( stdout ); + + ret = x509parse_crlfile( &crl, "ssl/test-ca/crl.pem" ); + if( ret != 0 ) + { + printf( " failed\n ! x509parse_crlfile returned %d\n\n", ret ); + goto exit; + } + + printf( " ok\n" ); + + x509parse_crl_info( buf, 1024, "CRL: ", &crl ); + printf("%s\n", buf ); + for( i = 0; i < MAX_CLIENT_CERTS; i++ ) { /* - * 1.2. Load own certificate + * 1.3. Load own certificate */ - char name[512]; - int flags; + char name[512]; + int flags; + x509_cert clicert; + rsa_context rsa; - snprintf(name, 512, "ssl/test-ca/%s", client_certificates[i]); + memset( &clicert, 0, sizeof( x509_cert ) ); + memset( &rsa, 0, sizeof( rsa_context ) ); - printf( " . Loading the client certificatei %s...", name ); - fflush( stdout ); + snprintf(name, 512, "ssl/test-ca/%s", client_certificates[i]); - memset( &clicert, 0, sizeof( x509_cert ) ); + printf( " . Loading the client certificate %s...", name ); + fflush( stdout ); ret = x509parse_crtfile( &clicert, name ); - if( ret != 0 ) - { - printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); - goto exit; - } + if( ret != 0 ) + { + printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); + goto exit; + } - printf( " ok\n" ); + printf( " ok\n" ); - /* - * 1.3. Verify certificate validity with CA certificate - */ - printf( " . Verify the client certificate with CA certificate..." ); - fflush( stdout ); + /* + * 1.4. Verify certificate validity with CA certificate + */ + printf( " . Verify the client certificate with CA certificate..." ); + fflush( stdout ); - ret = x509parse_verify( &clicert, &cacert, NULL, &flags ); - if( ret != 0 ) - { - printf( " failed\n ! x509parse_verify returned %d\n\n", ret ); - goto exit; - } + ret = x509parse_verify( &clicert, &cacert, NULL, &flags ); + if( ret != 0 ) + { + printf( " failed\n ! x509parse_verify returned %d\n\n", ret ); + goto exit; + } - printf( " ok\n" ); + printf( " ok\n" ); /* - * 1.4. Load own private key + * 1.5. Load own private key */ - snprintf(name, 512, "ssl/test-ca/%s", client_private_keys[i]); + snprintf(name, 512, "ssl/test-ca/%s", client_private_keys[i]); printf( " . Loading the client private key %s...", name ); fflush( stdout ); - memset( &rsa, 0, sizeof( rsa_context ) ); - - ret = x509parse_keyfile( &rsa, name, NULL ); - if( ret != 0 ) - { - printf( " failed\n ! x509parse_key returned %d\n\n", ret ); - goto exit; - } - - printf( " ok\n" ); - - /* - * 1.4. Verify certificate validity with private key - */ - printf( " . Verify the client certificate with private key..." ); - fflush( stdout ); - - ret = mpi_cmp_mpi(&rsa.N, &clicert.rsa.N); - if( ret != 0 ) - { - printf( " failed\n ! mpi_cmp_mpi for N returned %d\n\n", ret ); - goto exit; - } - - ret = mpi_cmp_mpi(&rsa.E, &clicert.rsa.E); - if( ret != 0 ) - { - printf( " failed\n ! mpi_cmp_mpi for E returned %d\n\n", ret ); - goto exit; - } - - ret = rsa_check_privkey( &rsa ); - if( ret != 0 ) - { - printf( " failed\n ! rsa_check_privkey returned %d\n\n", ret ); - goto exit; - } - - printf( " ok\n" ); + ret = x509parse_keyfile( &rsa, name, NULL ); + if( ret != 0 ) + { + printf( " failed\n ! x509parse_key returned %d\n\n", ret ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.5. Verify certificate validity with private key + */ + printf( " . Verify the client certificate with private key..." ); + fflush( stdout ); + + ret = mpi_cmp_mpi(&rsa.N, &clicert.rsa.N); + if( ret != 0 ) + { + printf( " failed\n ! mpi_cmp_mpi for N returned %d\n\n", ret ); + goto exit; + } + + ret = mpi_cmp_mpi(&rsa.E, &clicert.rsa.E); + if( ret != 0 ) + { + printf( " failed\n ! mpi_cmp_mpi for E returned %d\n\n", ret ); + goto exit; + } + + ret = rsa_check_privkey( &rsa ); + if( ret != 0 ) + { + printf( " failed\n ! rsa_check_privkey returned %d\n\n", ret ); + goto exit; + } + + printf( " ok\n" ); + + x509_free( &clicert ); + rsa_free( &rsa ); } exit: - x509_free( &clicert ); x509_free( &cacert ); + x509_crl_free( &crl ); #ifdef WIN32 printf( " + Press Enter to exit this program.\n" ); |