/** * Parse and fill a single X.509 certificate in DER format. */ static int x509_crt_parse_der_core(ttls_x509_crt *crt, unsigned char *buf, size_t buflen) { int r; size_t len; unsigned char *p, *end, *crt_end; ttls_x509_buf sig_params1, sig_params2, sig_oid2; BUG_ON(!crt || !buf); memset(&sig_params1, 0, sizeof(ttls_x509_buf)); memset(&sig_params2, 0, sizeof(ttls_x509_buf)); memset(&sig_oid2, 0, sizeof(ttls_x509_buf)); p = (unsigned char*)buf; len = buflen; end = p + len; /* * Certificate ::= SEQUENCE { * tbsCertificate TBSCertificate, * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING * } */ r = ttls_asn1_get_tag(&p, end, &len, TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE); if (r) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT; } if (len > (size_t)(end - p)) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT + TTLS_ERR_ASN1_LENGTH_MISMATCH; } crt_end = p + len; /* * Create and populate a new buffer for the raw field. * Reuse the buffer, we're responsible to free the pages later. */ crt->raw.len = crt_end - buf; crt->raw.p = p = buf; /* Direct pointers to the new buffer. */ p += crt->raw.len - len; end = crt_end = p + len; /* TBSCertificate ::= SEQUENCE { */ crt->tbs.p = p; r = ttls_asn1_get_tag(&p, end, &len, TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE); if (r) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT + r; } end = p + len; crt->tbs.len = end - crt->tbs.p; /* * Version ::= INTEGER { v1(0), v2(1), v3(2) } * * CertificateSerialNumber ::= INTEGER * * signature AlgorithmIdentifier */ if ((r = x509_get_version( &p, end, &crt->version )) || (r = ttls_x509_get_serial(&p, end, &crt->serial)) || (r = ttls_x509_get_alg(&p, end, &crt->sig_oid, &sig_params1))) { ttls_x509_crt_free(crt); return r; } if (crt->version < 0 || crt->version > 2) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_UNKNOWN_VERSION; } crt->version++; r = ttls_x509_get_sig_alg(&crt->sig_oid, &sig_params1, &crt->sig_md, &crt->sig_pk, &crt->sig_opts); if (r) { ttls_x509_crt_free(crt); return r; } /* issuer Name */ crt->issuer_raw.p = p; r = ttls_asn1_get_tag(&p, end, &len, TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE); if (r) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT + r; } if ((r = ttls_x509_get_name(&p, p + len, &crt->issuer))) { ttls_x509_crt_free(crt); return r; } crt->issuer_raw.len = p - crt->issuer_raw.p; /* * Validity ::= SEQUENCE { * notBefore Time, * notAfter Time * } */ r = x509_get_dates(&p, end, &crt->valid_from, &crt->valid_to); if (r) { ttls_x509_crt_free(crt); return r; } /* subject Name */ crt->subject_raw.p = p; r = ttls_asn1_get_tag(&p, end, &len, TTLS_ASN1_CONSTRUCTED | TTLS_ASN1_SEQUENCE); if (r) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT + r; } if (len && (r = ttls_x509_get_name(&p, p + len, &crt->subject))) { ttls_x509_crt_free(crt); return r; } crt->subject_raw.len = p - crt->subject_raw.p; /* SubjectPublicKeyInfo */ if ((r = ttls_pk_parse_subpubkey(&p, end, &crt->pk))) { ttls_x509_crt_free(crt); return r; } /* * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version shall be v2 or v3 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version shall be v2 or v3 * extensions [3] EXPLICIT Extensions OPTIONAL * -- If present, version shall be v3 */ if (crt->version == 2 || crt->version == 3) { if ((r = x509_get_uid(&p, end, &crt->issuer_id, 1))) { ttls_x509_crt_free(crt); return r; } if ((r = x509_get_uid(&p, end, &crt->subject_id, 2))) { ttls_x509_crt_free(crt); return r; } } if (crt->version == 3) { if ((r = x509_get_crt_ext(&p, end, crt))) { ttls_x509_crt_free(crt); return r; } } if (p != end) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT + TTLS_ERR_ASN1_LENGTH_MISMATCH; } end = crt_end; /* * } * -- end of TBSCertificate * * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING */ if ((r = ttls_x509_get_alg(&p, end, &sig_oid2, &sig_params2))) { ttls_x509_crt_free(crt); return r; } if (crt->sig_oid.len != sig_oid2.len || memcmp(crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len) || sig_params1.len != sig_params2.len || (sig_params1.len && memcmp(sig_params1.p, sig_params2.p, sig_params1.len))) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_SIG_MISMATCH; } if ((r = ttls_x509_get_sig(&p, end, &crt->sig))) { ttls_x509_crt_free(crt); return r; } if (p != end) { ttls_x509_crt_free(crt); return TTLS_ERR_X509_INVALID_FORMAT + TTLS_ERR_ASN1_LENGTH_MISMATCH; } return 0; }
/* * Parse and fill a single X.509 certificate in DER format */ static int x509_crt_parse_der_core( x509_crt *crt, const unsigned char *buf, size_t buflen ) { int ret; size_t len; unsigned char *p, *end, *crt_end; /* * Check for valid input */ if( crt == NULL || buf == NULL ) return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); p = (unsigned char *) polarssl_malloc( len = buflen ); if( p == NULL ) return( POLARSSL_ERR_X509_MALLOC_FAILED ); memcpy( p, buf, buflen ); crt->raw.p = p; crt->raw.len = len; end = p + len; /* * Certificate ::= SEQUENCE { * tbsCertificate TBSCertificate, * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT ); } if( len > (size_t) ( end - p ) ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } crt_end = p + len; /* * TBSCertificate ::= SEQUENCE { */ crt->tbs.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } end = p + len; crt->tbs.len = end - crt->tbs.p; /* * Version ::= INTEGER { v1(0), v2(1), v3(2) } * * CertificateSerialNumber ::= INTEGER * * signature AlgorithmIdentifier */ if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || ( ret = x509_get_serial( &p, end, &crt->serial ) ) != 0 || ( ret = x509_get_alg_null( &p, end, &crt->sig_oid1 ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } crt->version++; if( crt->version > 3 ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_UNKNOWN_VERSION ); } if( ( ret = x509_get_sig_alg( &crt->sig_oid1, &crt->sig_md, &crt->sig_pk ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } /* * issuer Name */ crt->issuer_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } crt->issuer_raw.len = p - crt->issuer_raw.p; /* * Validity ::= SEQUENCE { * notBefore Time, * notAfter Time } * */ if( ( ret = x509_get_dates( &p, end, &crt->valid_from, &crt->valid_to ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } /* * subject Name */ crt->subject_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT + ret ); } if( len && ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } crt->subject_raw.len = p - crt->subject_raw.p; /* * SubjectPublicKeyInfo */ if( ( ret = pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } /* * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version shall be v2 or v3 * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, * -- If present, version shall be v2 or v3 * extensions [3] EXPLICIT Extensions OPTIONAL * -- If present, version shall be v3 */ if( crt->version == 2 || crt->version == 3 ) { ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); if( ret != 0 ) { x509_crt_free( crt ); return( ret ); } } if( crt->version == 2 || crt->version == 3 ) { ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); if( ret != 0 ) { x509_crt_free( crt ); return( ret ); } } #if !defined(POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3) if( crt->version == 3 ) { #endif ret = x509_get_crt_ext( &p, end, crt); if( ret != 0 ) { x509_crt_free( crt ); return( ret ); } #if !defined(POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3) } #endif if( p != end ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } end = crt_end; /* * } * -- end of TBSCertificate * * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING */ if( ( ret = x509_get_alg_null( &p, end, &crt->sig_oid2 ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } if( crt->sig_oid1.len != crt->sig_oid2.len || memcmp( crt->sig_oid1.p, crt->sig_oid2.p, crt->sig_oid1.len ) != 0 ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_SIG_MISMATCH ); } if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 ) { x509_crt_free( crt ); return( ret ); } if( p != end ) { x509_crt_free( crt ); return( POLARSSL_ERR_X509_INVALID_FORMAT + POLARSSL_ERR_ASN1_LENGTH_MISMATCH ); } return( 0 ); }