/* * Parse one CRLs in DER format and append it to the chained list */ int x509_crl_parse_der( x509_crl *chain, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; x509_buf sig_params1, sig_params2; x509_crl *crl = chain; /* * Check for valid input */ if( crl == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); memset( &sig_params1, 0, sizeof( x509_buf ) ); memset( &sig_params2, 0, sizeof( x509_buf ) ); /* * Add new CRL on the end of the chain if needed. */ while( crl->version != 0 && crl->next != NULL ) crl = crl->next; if( crl->version != 0 && crl->next == NULL ) { crl->next = polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } x509_crl_init( crl->next ); crl = crl->next; } /* * Copy raw DER-encoded CRL */ if( ( p = polarssl_malloc( buflen ) ) == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); memcpy( p, buf, buflen ); crl->raw.p = p; crl->raw.len = buflen; end = p + buflen; /* * 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_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_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_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_crl_get_version( &p, end, &crl->version ) ) != 0 || ( ret = x509_get_alg( &p, end, &crl->sig_oid1, &sig_params1 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } crl->version++; if( crl->version > 2 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_UNKNOWN_VERSION ); } if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &sig_params1, &crl->sig_md, &crl->sig_pk, &crl->sig_opts ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_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_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_time( &p, end, &crl->this_update ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) { if( ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) { 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_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, &sig_params2 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( crl->sig_oid1.len != crl->sig_oid2.len || memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 || sig_params1.len != sig_params2.len || ( sig_params1.len != 0 && memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_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_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } return( 0 ); }
/* * Parse one or more CRLs and add them to the chained list */ int x509_crl_parse( x509_crl *chain, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end; x509_crl *crl; #if defined(POLARSSL_PEM_PARSE_C) size_t use_len; pem_context pem; #endif crl = chain; /* * Check for valid input */ if( crl == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); 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 *) polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } crl = crl->next; x509_crl_init( crl ); } #if defined(POLARSSL_PEM_PARSE_C) pem_init( &pem ); ret = pem_read_buffer( &pem, "-----BEGIN X509 CRL-----", "-----END X509 CRL-----", buf, NULL, 0, &use_len ); if( ret == 0 ) { /* * Was PEM encoded */ buflen -= use_len; buf += use_len; /* * Steal PEM buffer */ p = pem.buf; pem.buf = NULL; len = pem.buflen; pem_free( &pem ); } else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) { pem_free( &pem ); return( ret ); } else #endif { /* * nope, copy the raw DER data */ p = (unsigned char *) polarssl_malloc( len = buflen ); if( p == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); 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_INVALID_FORMAT ); } if( len != (size_t) ( end - p ) ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_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_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_crl_get_version( &p, end, &crl->version ) ) != 0 || ( ret = x509_get_alg_null( &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_UNKNOWN_VERSION ); } if( ( ret = x509_get_sig_alg( &crl->sig_oid1, &crl->sig_md, &crl->sig_pk ) ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_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_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_time( &p, end, &crl->this_update ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( ( ret = x509_get_time( &p, end, &crl->next_update ) ) != 0 ) { if ( ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_UNEXPECTED_TAG ) && ret != ( POLARSSL_ERR_X509_INVALID_DATE + POLARSSL_ERR_ASN1_OUT_OF_DATA ) ) { 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_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } end = crl->raw.p + crl->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING */ if( ( ret = x509_get_alg_null( &p, end, &crl->sig_oid2 ) ) != 0 ) { x509_crl_free( crl ); return( ret ); } if( crl->sig_oid1.len != crl->sig_oid2.len || memcmp( crl->sig_oid1.p, crl->sig_oid2.p, crl->sig_oid1.len ) != 0 ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_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_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } if( buflen > 0 ) { crl->next = (x509_crl *) polarssl_malloc( sizeof( x509_crl ) ); if( crl->next == NULL ) { x509_crl_free( crl ); return( POLARSSL_ERR_X509_MALLOC_FAILED ); } crl = crl->next; x509_crl_init( crl ); return( x509_crl_parse( crl, buf, buflen ) ); } return( 0 ); }