|  | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     https://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <limits.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include <openssl/asn1.h> | 
|  | #include <openssl/asn1t.h> | 
|  | #include <openssl/bytestring.h> | 
|  | #include <openssl/evp.h> | 
|  | #include <openssl/mem.h> | 
|  | #include <openssl/obj.h> | 
|  | #include <openssl/pool.h> | 
|  | #include <openssl/x509.h> | 
|  |  | 
|  | #include "../asn1/internal.h" | 
|  | #include "../bytestring/internal.h" | 
|  | #include "../internal.h" | 
|  | #include "internal.h" | 
|  |  | 
|  | static CRYPTO_EX_DATA_CLASS g_ex_data_class = CRYPTO_EX_DATA_CLASS_INIT; | 
|  |  | 
|  | ASN1_SEQUENCE_enc(X509_CINF, enc, 0) = { | 
|  | ASN1_EXP_OPT(X509_CINF, version, ASN1_INTEGER, 0), | 
|  | ASN1_SIMPLE(X509_CINF, serialNumber, ASN1_INTEGER), | 
|  | ASN1_SIMPLE(X509_CINF, signature, X509_ALGOR), | 
|  | ASN1_SIMPLE(X509_CINF, issuer, X509_NAME), | 
|  | ASN1_SIMPLE(X509_CINF, validity, X509_VAL), | 
|  | ASN1_SIMPLE(X509_CINF, subject, X509_NAME), | 
|  | ASN1_SIMPLE(X509_CINF, key, X509_PUBKEY), | 
|  | ASN1_IMP_OPT(X509_CINF, issuerUID, ASN1_BIT_STRING, 1), | 
|  | ASN1_IMP_OPT(X509_CINF, subjectUID, ASN1_BIT_STRING, 2), | 
|  | ASN1_EXP_SEQUENCE_OF_OPT(X509_CINF, extensions, X509_EXTENSION, 3), | 
|  | } ASN1_SEQUENCE_END_enc(X509_CINF, X509_CINF) | 
|  |  | 
|  | IMPLEMENT_ASN1_FUNCTIONS(X509_CINF) | 
|  |  | 
|  | // x509_new_null returns a new |X509| object where the |cert_info|, |sig_alg|, | 
|  | // and |signature| fields are not yet filled in. | 
|  | static X509 *x509_new_null(void) { | 
|  | X509 *ret = reinterpret_cast<X509 *>(OPENSSL_zalloc(sizeof(X509))); | 
|  | if (ret == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | ret->references = 1; | 
|  | ret->ex_pathlen = -1; | 
|  | asn1_string_init(&ret->signature, V_ASN1_BIT_STRING); | 
|  | CRYPTO_new_ex_data(&ret->ex_data); | 
|  | CRYPTO_MUTEX_init(&ret->lock); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | X509 *X509_new(void) { | 
|  | X509 *ret = x509_new_null(); | 
|  | if (ret == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | ret->cert_info = X509_CINF_new(); | 
|  | ret->sig_alg = X509_ALGOR_new(); | 
|  | if (ret->cert_info == NULL || ret->sig_alg == NULL) { | 
|  | X509_free(ret); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | void X509_free(X509 *x509) { | 
|  | if (x509 == NULL || !CRYPTO_refcount_dec_and_test_zero(&x509->references)) { | 
|  | return; | 
|  | } | 
|  |  | 
|  | CRYPTO_free_ex_data(&g_ex_data_class, &x509->ex_data); | 
|  |  | 
|  | X509_CINF_free(x509->cert_info); | 
|  | X509_ALGOR_free(x509->sig_alg); | 
|  | asn1_string_cleanup(&x509->signature); | 
|  | ASN1_OCTET_STRING_free(x509->skid); | 
|  | AUTHORITY_KEYID_free(x509->akid); | 
|  | CRL_DIST_POINTS_free(x509->crldp); | 
|  | GENERAL_NAMES_free(x509->altname); | 
|  | NAME_CONSTRAINTS_free(x509->nc); | 
|  | X509_CERT_AUX_free(x509->aux); | 
|  | CRYPTO_MUTEX_cleanup(&x509->lock); | 
|  |  | 
|  | OPENSSL_free(x509); | 
|  | } | 
|  |  | 
|  | static X509 *x509_parse(CBS *cbs, CRYPTO_BUFFER *buf) { | 
|  | bssl::UniquePtr<X509> ret(x509_new_null()); | 
|  | if (ret == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | CBS cert, tbs, sigalg; | 
|  | if (!CBS_get_asn1(cbs, &cert, CBS_ASN1_SEQUENCE) || | 
|  | // Bound the length to comfortably fit in an int. Lengths in this | 
|  | // module often omit overflow checks. | 
|  | CBS_len(&cert) > INT_MAX / 2 || | 
|  | !CBS_get_asn1_element(&cert, &tbs, CBS_ASN1_SEQUENCE) || | 
|  | !CBS_get_asn1_element(&cert, &sigalg, CBS_ASN1_SEQUENCE) || | 
|  | // For just the signature field, we accept non-minimal BER lengths, though | 
|  | // not indefinite-length encoding. See b/18228011. | 
|  | // | 
|  | // TODO(crbug.com/boringssl/354): Switch the affected callers to convert | 
|  | // the certificate before parsing and then remove this workaround. | 
|  | !asn1_parse_bit_string_with_bad_length(&cert, &ret->signature) || | 
|  | CBS_len(&cert) != 0) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // TODO(crbug.com/boringssl/443): When the rest of the library is decoupled | 
|  | // from the tasn_*.c implementation, replace this with |CBS|-based | 
|  | // functions. | 
|  | const uint8_t *inp = CBS_data(&tbs); | 
|  | if (ASN1_item_ex_d2i((ASN1_VALUE **)&ret->cert_info, &inp, CBS_len(&tbs), | 
|  | ASN1_ITEM_rptr(X509_CINF), /*tag=*/-1, | 
|  | /*aclass=*/0, /*opt=*/0, buf) <= 0 || | 
|  | inp != CBS_data(&tbs) + CBS_len(&tbs)) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | inp = CBS_data(&sigalg); | 
|  | ret->sig_alg = d2i_X509_ALGOR(nullptr, &inp, CBS_len(&sigalg)); | 
|  | if (ret->sig_alg == nullptr || inp != CBS_data(&sigalg) + CBS_len(&sigalg)) { | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // The version must be one of v1(0), v2(1), or v3(2). | 
|  | long version = X509_VERSION_1; | 
|  | if (ret->cert_info->version != nullptr) { | 
|  | version = ASN1_INTEGER_get(ret->cert_info->version); | 
|  | // TODO(https://crbug.com/boringssl/364): |X509_VERSION_1| should | 
|  | // also be rejected here. This means an explicitly-encoded X.509v1 | 
|  | // version. v1 is DEFAULT, so DER requires it be omitted. | 
|  | if (version < X509_VERSION_1 || version > X509_VERSION_3) { | 
|  | OPENSSL_PUT_ERROR(X509, X509_R_INVALID_VERSION); | 
|  | return nullptr; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Per RFC 5280, section 4.1.2.8, these fields require v2 or v3. | 
|  | if (version == X509_VERSION_1 && (ret->cert_info->issuerUID != nullptr || | 
|  | ret->cert_info->subjectUID != nullptr)) { | 
|  | OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Per RFC 5280, section 4.1.2.9, extensions require v3. | 
|  | if (version != X509_VERSION_3 && ret->cert_info->extensions != nullptr) { | 
|  | OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | return ret.release(); | 
|  | } | 
|  |  | 
|  | X509 *d2i_X509(X509 **out, const uint8_t **inp, long len) { | 
|  | return bssl::D2IFromCBS(out, inp, len, | 
|  | [](CBS *cbs) { return x509_parse(cbs, nullptr); }); | 
|  | } | 
|  |  | 
|  | int i2d_X509(X509 *x509, uint8_t **outp) { | 
|  | if (x509 == NULL) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | return bssl::I2DFromCBB( | 
|  | /*initial_capacity=*/64, outp, [&](CBB *cbb) -> bool { | 
|  | CBB cert; | 
|  | if (!CBB_add_asn1(cbb, &cert, CBS_ASN1_SEQUENCE)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // TODO(crbug.com/boringssl/443): When the rest of the library is | 
|  | // decoupled from the tasn_*.c implementation, replace this with | 
|  | // |CBB|-based functions. | 
|  | uint8_t *out; | 
|  | int len = i2d_X509_CINF(x509->cert_info, NULL); | 
|  | if (len < 0 ||  // | 
|  | !CBB_add_space(&cert, &out, static_cast<size_t>(len)) || | 
|  | i2d_X509_CINF(x509->cert_info, &out) != len || | 
|  | !x509_marshal_algorithm(&cert, x509->sig_alg) || | 
|  | !asn1_marshal_bit_string(&cert, &x509->signature, /*tag=*/0) || | 
|  | !CBB_flush(cbb)) { | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | }); | 
|  | } | 
|  |  | 
|  | static int x509_new_cb(ASN1_VALUE **pval, const ASN1_ITEM *it) { | 
|  | *pval = (ASN1_VALUE *)X509_new(); | 
|  | return *pval != NULL; | 
|  | } | 
|  |  | 
|  | static void x509_free_cb(ASN1_VALUE **pval, const ASN1_ITEM *it) { | 
|  | X509_free((X509 *)*pval); | 
|  | *pval = NULL; | 
|  | } | 
|  |  | 
|  | static int x509_d2i_cb(ASN1_VALUE **pval, const unsigned char **in, long len, | 
|  | const ASN1_ITEM *it, int opt, ASN1_TLC *ctx) { | 
|  | if (len < 0) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | CBS cbs; | 
|  | CBS_init(&cbs, *in, len); | 
|  | if (opt && !CBS_peek_asn1_tag(&cbs, CBS_ASN1_SEQUENCE)) { | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | X509 *ret = x509_parse(&cbs, NULL); | 
|  | if (ret == NULL) { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | *in = CBS_data(&cbs); | 
|  | X509_free((X509 *)*pval); | 
|  | *pval = (ASN1_VALUE *)ret; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int x509_i2d_cb(ASN1_VALUE **pval, unsigned char **out, | 
|  | const ASN1_ITEM *it) { | 
|  | return i2d_X509((X509 *)*pval, out); | 
|  | } | 
|  |  | 
|  | static const ASN1_EXTERN_FUNCS x509_extern_funcs = { | 
|  | x509_new_cb, | 
|  | x509_free_cb, | 
|  | x509_d2i_cb, | 
|  | x509_i2d_cb, | 
|  | }; | 
|  |  | 
|  | IMPLEMENT_EXTERN_ASN1(X509, x509_extern_funcs) | 
|  |  | 
|  | X509 *X509_dup(X509 *x509) { | 
|  | uint8_t *der = NULL; | 
|  | int len = i2d_X509(x509, &der); | 
|  | if (len < 0) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | const uint8_t *inp = der; | 
|  | X509 *ret = d2i_X509(NULL, &inp, len); | 
|  | OPENSSL_free(der); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) { | 
|  | CBS cbs; | 
|  | CBS_init(&cbs, CRYPTO_BUFFER_data(buf), CRYPTO_BUFFER_len(buf)); | 
|  | X509 *ret = x509_parse(&cbs, buf); | 
|  | if (ret == NULL || CBS_len(&cbs) != 0) { | 
|  | X509_free(ret); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int X509_up_ref(X509 *x) { | 
|  | CRYPTO_refcount_inc(&x->references); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int X509_get_ex_new_index(long argl, void *argp, CRYPTO_EX_unused *unused, | 
|  | CRYPTO_EX_dup *dup_unused, | 
|  | CRYPTO_EX_free *free_func) { | 
|  | return CRYPTO_get_ex_new_index_ex(&g_ex_data_class, argl, argp, free_func); | 
|  | } | 
|  |  | 
|  | int X509_set_ex_data(X509 *r, int idx, void *arg) { | 
|  | return (CRYPTO_set_ex_data(&r->ex_data, idx, arg)); | 
|  | } | 
|  |  | 
|  | void *X509_get_ex_data(X509 *r, int idx) { | 
|  | return (CRYPTO_get_ex_data(&r->ex_data, idx)); | 
|  | } | 
|  |  | 
|  | // X509_AUX ASN1 routines. X509_AUX is the name given to a certificate with | 
|  | // extra info tagged on the end. Since these functions set how a certificate | 
|  | // is trusted they should only be used when the certificate comes from a | 
|  | // reliable source such as local storage. | 
|  |  | 
|  | X509 *d2i_X509_AUX(X509 **a, const unsigned char **pp, long length) { | 
|  | const unsigned char *q = *pp; | 
|  | X509 *ret; | 
|  | int freeret = 0; | 
|  |  | 
|  | if (!a || *a == NULL) { | 
|  | freeret = 1; | 
|  | } | 
|  | ret = d2i_X509(a, &q, length); | 
|  | // If certificate unreadable then forget it | 
|  | if (!ret) { | 
|  | return NULL; | 
|  | } | 
|  | // update length | 
|  | length -= q - *pp; | 
|  | // Parse auxiliary information if there is any. | 
|  | if (length > 0 && !d2i_X509_CERT_AUX(&ret->aux, &q, length)) { | 
|  | goto err; | 
|  | } | 
|  | *pp = q; | 
|  | return ret; | 
|  | err: | 
|  | if (freeret) { | 
|  | X509_free(ret); | 
|  | if (a) { | 
|  | *a = NULL; | 
|  | } | 
|  | } | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // Serialize trusted certificate to *pp or just return the required buffer | 
|  | // length if pp == NULL.  We ultimately want to avoid modifying *pp in the | 
|  | // error path, but that depends on similar hygiene in lower-level functions. | 
|  | // Here we avoid compounding the problem. | 
|  | static int i2d_x509_aux_internal(X509 *a, unsigned char **pp) { | 
|  | int length, tmplen; | 
|  | unsigned char *start = pp != NULL ? *pp : NULL; | 
|  |  | 
|  | assert(pp == NULL || *pp != NULL); | 
|  |  | 
|  | // This might perturb *pp on error, but fixing that belongs in i2d_X509() | 
|  | // not here.  It should be that if a == NULL length is zero, but we check | 
|  | // both just in case. | 
|  | length = i2d_X509(a, pp); | 
|  | if (length <= 0 || a == NULL) { | 
|  | return length; | 
|  | } | 
|  |  | 
|  | if (a->aux != NULL) { | 
|  | tmplen = i2d_X509_CERT_AUX(a->aux, pp); | 
|  | if (tmplen < 0) { | 
|  | if (start != NULL) { | 
|  | *pp = start; | 
|  | } | 
|  | return tmplen; | 
|  | } | 
|  | length += tmplen; | 
|  | } | 
|  |  | 
|  | return length; | 
|  | } | 
|  |  | 
|  | // Serialize trusted certificate to *pp, or just return the required buffer | 
|  | // length if pp == NULL. | 
|  | // | 
|  | // When pp is not NULL, but *pp == NULL, we allocate the buffer, but since | 
|  | // we're writing two ASN.1 objects back to back, we can't have i2d_X509() do | 
|  | // the allocation, nor can we allow i2d_X509_CERT_AUX() to increment the | 
|  | // allocated buffer. | 
|  | int i2d_X509_AUX(X509 *a, unsigned char **pp) { | 
|  | int length; | 
|  | unsigned char *tmp; | 
|  |  | 
|  | // Buffer provided by caller | 
|  | if (pp == NULL || *pp != NULL) { | 
|  | return i2d_x509_aux_internal(a, pp); | 
|  | } | 
|  |  | 
|  | // Obtain the combined length | 
|  | if ((length = i2d_x509_aux_internal(a, NULL)) <= 0) { | 
|  | return length; | 
|  | } | 
|  |  | 
|  | // Allocate requisite combined storage | 
|  | *pp = tmp = reinterpret_cast<uint8_t *>(OPENSSL_malloc(length)); | 
|  | if (tmp == NULL) { | 
|  | return -1;  // Push error onto error stack? | 
|  | } | 
|  |  | 
|  | // Encode, but keep *pp at the originally malloced pointer | 
|  | length = i2d_x509_aux_internal(a, &tmp); | 
|  | if (length <= 0) { | 
|  | OPENSSL_free(*pp); | 
|  | *pp = NULL; | 
|  | } | 
|  | return length; | 
|  | } | 
|  |  | 
|  | int i2d_re_X509_tbs(X509 *x509, unsigned char **outp) { | 
|  | asn1_encoding_clear(&x509->cert_info->enc); | 
|  | return i2d_X509_CINF(x509->cert_info, outp); | 
|  | } | 
|  |  | 
|  | int i2d_X509_tbs(X509 *x509, unsigned char **outp) { | 
|  | return i2d_X509_CINF(x509->cert_info, outp); | 
|  | } | 
|  |  | 
|  | int X509_set1_signature_algo(X509 *x509, const X509_ALGOR *algo) { | 
|  | return X509_ALGOR_copy(x509->sig_alg, algo) && | 
|  | X509_ALGOR_copy(x509->cert_info->signature, algo); | 
|  | } | 
|  |  | 
|  | int X509_set1_signature_value(X509 *x509, const uint8_t *sig, size_t sig_len) { | 
|  | if (!ASN1_STRING_set(&x509->signature, sig, sig_len)) { | 
|  | return 0; | 
|  | } | 
|  | x509->signature.flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); | 
|  | x509->signature.flags |= ASN1_STRING_FLAG_BITS_LEFT; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void X509_get0_signature(const ASN1_BIT_STRING **psig, const X509_ALGOR **palg, | 
|  | const X509 *x) { | 
|  | if (psig) { | 
|  | *psig = &x->signature; | 
|  | } | 
|  | if (palg) { | 
|  | *palg = x->sig_alg; | 
|  | } | 
|  | } | 
|  |  | 
|  | int X509_get_signature_nid(const X509 *x) { | 
|  | return OBJ_obj2nid(x->sig_alg->algorithm); | 
|  | } |