/* * Parse one or more certificates and add them to the chain */ int x509_add_certs( x509_cert *chain, unsigned char *buf, int buflen ) { int ret, len; unsigned char *s1, *s2; unsigned char *p, *end; x509_cert *crt; crt = chain; while( crt->version != 0 ) crt = crt->next; /* * check if the certificate is encoded in base64 */ s1 = (unsigned char *) strstr( (char *) buf, "-----BEGIN CERTIFICATE-----" ); if( s1 != NULL ) { s2 = (unsigned char *) strstr( (char *) buf, "-----END CERTIFICATE-----" ); if( s2 == NULL || s2 <= s1 ) return( ERR_X509_CERT_INVALID_PEM ); s1 += 27; if( *s1 == '\r' ) s1++; if( *s1 == '\n' ) s1++; else return( 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 == ERR_BASE64_INVALID_CHARACTER ) return( 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( ERR_X509_CERT_INVALID_PEM | ret ); } /* * update the buffer size and offset */ s2 += 25; if( *s2 == '\r' ) s2++; if( *s2 == '\n' ) s2++; else return( 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; } 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_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT ); } if( len != (int) ( end - p ) ) { x509_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT | ERR_ASN1_LENGTH_MISMATCH ); } /* * TBSCertificate ::= SEQUENCE { */ crt->tbs.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_free_cert( crt ); return( ERR_X509_CERT_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( &p, end, &crt->sig_oid1 ) ) != 0 ) { x509_free_cert( crt ); return( ret ); } crt->version++; if( crt->version > 3 ) { x509_free_cert( crt ); return( ERR_X509_CERT_UNKNOWN_VERSION ); } if( crt->sig_oid1.len != 9 || memcmp( crt->sig_oid1.p, OID_PKCS1, 8 ) != 0 ) { x509_free_cert( crt ); return( ERR_X509_CERT_UNKNOWN_SIG_ALG ); } if( crt->sig_oid1.p[8] < 2 || crt->sig_oid1.p[8] > 5 ) { x509_free_cert( crt ); return( ERR_X509_CERT_UNKNOWN_SIG_ALG ); } /* * issuer Name */ crt->issuer_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT | ret ); } if( ( ret = x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) { x509_free_cert( 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_free_cert( crt ); return( ret ); } /* * subject Name */ crt->subject_raw.p = p; if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT | ret ); } if( ( ret = x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) { x509_free_cert( crt ); return( ret ); } crt->subject_raw.len = p - crt->subject_raw.p; /* * SubjectPublicKeyInfo ::= SEQUENCE * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING } */ if( ( ret = asn1_get_tag( &p, end, &len, ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 ) { x509_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT | ret ); } if( ( ret = x509_get_pubkey( &p, p + len, &crt->pk_oid, &crt->rsa.N, &crt->rsa.E ) ) != 0 ) { x509_free_cert( crt ); return( ret ); } if( ( ret = rsa_check_pubkey( &crt->rsa ) ) != 0 ) { x509_free_cert( crt ); return( ret ); } crt->rsa.len = ( mpi_size( &crt->rsa.N ) + 7 ) >> 3; /* * 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_free_cert( crt ); return( ret ); } } if( crt->version == 2 || crt->version == 3 ) { ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); if( ret != 0 ) { x509_free_cert( crt ); return( ret ); } } if( crt->version == 3 ) { ret = x509_get_ext( &p, end, &crt->v3_ext, &crt->ca_istrue, &crt->max_pathlen ); if( ret != 0 ) { x509_free_cert( crt ); return( ret ); } } if( p != end ) { x509_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT | ERR_ASN1_LENGTH_MISMATCH ); } end = crt->raw.p + crt->raw.len; /* * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING */ if( ( ret = x509_get_alg( &p, end, &crt->sig_oid2 ) ) != 0 ) { x509_free_cert( crt ); return( ret ); } if( memcmp( crt->sig_oid1.p, crt->sig_oid2.p, 9 ) != 0 ) { x509_free_cert( crt ); return( ERR_X509_CERT_SIG_MISMATCH ); } if( ( ret = x509_get_sig( &p, end, &crt->sig ) ) != 0 ) { x509_free_cert( crt ); return( ret ); } if( p != end ) { x509_free_cert( crt ); return( ERR_X509_CERT_INVALID_FORMAT | ERR_ASN1_LENGTH_MISMATCH ); } crt->next = (x509_cert *) malloc( sizeof( x509_cert ) ); if( crt->next == NULL ) { x509_free_cert( crt ); return( 1 ); } crt = crt->next; memset( crt, 0, sizeof( x509_cert ) ); if( buflen > 0 ) return( x509_add_certs( crt, buf, buflen ) ); return( 0 ); }
/** * 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 ); }