|  | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 
|  | * All rights reserved. | 
|  | * | 
|  | * This package is an SSL implementation written | 
|  | * by Eric Young (eay@cryptsoft.com). | 
|  | * The implementation was written so as to conform with Netscapes SSL. | 
|  | * | 
|  | * This library is free for commercial and non-commercial use as long as | 
|  | * the following conditions are aheared to.  The following conditions | 
|  | * apply to all code found in this distribution, be it the RC4, RSA, | 
|  | * lhash, DES, etc., code; not just the SSL code.  The SSL documentation | 
|  | * included with this distribution is covered by the same copyright terms | 
|  | * except that the holder is Tim Hudson (tjh@cryptsoft.com). | 
|  | * | 
|  | * Copyright remains Eric Young's, and as such any Copyright notices in | 
|  | * the code are not to be removed. | 
|  | * If this package is used in a product, Eric Young should be given attribution | 
|  | * as the author of the parts of the library used. | 
|  | * This can be in the form of a textual message at program startup or | 
|  | * in documentation (online or textual) provided with the package. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * 1. Redistributions of source code must retain the copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in the | 
|  | *    documentation and/or other materials provided with the distribution. | 
|  | * 3. All advertising materials mentioning features or use of this software | 
|  | *    must display the following acknowledgement: | 
|  | *    "This product includes cryptographic software written by | 
|  | *     Eric Young (eay@cryptsoft.com)" | 
|  | *    The word 'cryptographic' can be left out if the rouines from the library | 
|  | *    being used are not cryptographic related :-). | 
|  | * 4. If you include any Windows specific code (or a derivative thereof) from | 
|  | *    the apps directory (application code) you must include an acknowledgement: | 
|  | *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND | 
|  | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | 
|  | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
|  | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
|  | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
|  | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
|  | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | * SUCH DAMAGE. | 
|  | * | 
|  | * The licence and distribution terms for any publically available version or | 
|  | * derivative of this code cannot be changed.  i.e. this code cannot simply be | 
|  | * copied and put under another distribution licence | 
|  | * [including the GNU Public Licence.] */ | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <limits.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include <openssl/asn1t.h> | 
|  | #include <openssl/evp.h> | 
|  | #include <openssl/mem.h> | 
|  | #include <openssl/obj.h> | 
|  | #include <openssl/pool.h> | 
|  | #include <openssl/thread.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; | 
|  | 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(); | 
|  | ret->signature = ASN1_BIT_STRING_new(); | 
|  | if (ret->cert_info == NULL || ret->sig_alg == NULL || | 
|  | ret->signature == 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, &x509->ex_data); | 
|  |  | 
|  | X509_CINF_free(x509->cert_info); | 
|  | X509_ALGOR_free(x509->sig_alg); | 
|  | ASN1_BIT_STRING_free(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) { | 
|  | CBS cert, tbs, sigalg, sig; | 
|  | 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)) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | CBS_ASN1_TAG tag; | 
|  | size_t header_len; | 
|  | int indefinite; | 
|  | if (!CBS_get_any_ber_asn1_element(&cert, &sig, &tag, &header_len, | 
|  | /*out_ber_found=*/NULL, | 
|  | &indefinite) || | 
|  | tag != CBS_ASN1_BITSTRING || indefinite ||  // | 
|  | !CBS_skip(&sig, header_len) ||              // | 
|  | CBS_len(&cert) != 0) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_DECODE_ERROR); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | X509 *ret = x509_new_null(); | 
|  | if (ret == NULL) { | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | { | 
|  | // 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)) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | inp = CBS_data(&sigalg); | 
|  | ret->sig_alg = d2i_X509_ALGOR(NULL, &inp, CBS_len(&sigalg)); | 
|  | if (ret->sig_alg == NULL || inp != CBS_data(&sigalg) + CBS_len(&sigalg)) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | inp = CBS_data(&sig); | 
|  | ret->signature = c2i_ASN1_BIT_STRING(NULL, &inp, CBS_len(&sig)); | 
|  | if (ret->signature == NULL || inp != CBS_data(&sig) + CBS_len(&sig)) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | // The version must be one of v1(0), v2(1), or v3(2). | 
|  | long version = X509_VERSION_1; | 
|  | if (ret->cert_info->version != NULL) { | 
|  | 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); | 
|  | goto err; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Per RFC 5280, section 4.1.2.8, these fields require v2 or v3. | 
|  | if (version == X509_VERSION_1 && (ret->cert_info->issuerUID != NULL || | 
|  | ret->cert_info->subjectUID != NULL)) { | 
|  | OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | // Per RFC 5280, section 4.1.2.9, extensions require v3. | 
|  | if (version != X509_VERSION_3 && ret->cert_info->extensions != NULL) { | 
|  | OPENSSL_PUT_ERROR(X509, X509_R_INVALID_FIELD_FOR_VERSION); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | err: | 
|  | X509_free(ret); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | X509 *d2i_X509(X509 **out, const uint8_t **inp, long len) { | 
|  | X509 *ret = NULL; | 
|  | if (len < 0) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | CBS cbs; | 
|  | CBS_init(&cbs, *inp, (size_t)len); | 
|  | ret = x509_parse(&cbs, NULL); | 
|  | if (ret == NULL) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | *inp = CBS_data(&cbs); | 
|  |  | 
|  | err: | 
|  | if (out != NULL) { | 
|  | X509_free(*out); | 
|  | *out = ret; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | int i2d_X509(X509 *x509, uint8_t **outp) { | 
|  | if (x509 == NULL) { | 
|  | OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_VALUE); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | CBB cbb, cert; | 
|  | int len; | 
|  | if (!CBB_init(&cbb, 64) ||  // | 
|  | !CBB_add_asn1(&cbb, &cert, CBS_ASN1_SEQUENCE)) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | // TODO(crbug.com/boringssl/443): When the rest of the library is decoupled | 
|  | // from the tasn_*.c implementation, replace this with |CBS|-based functions. | 
|  | uint8_t *out; | 
|  | len = i2d_X509_CINF(x509->cert_info, NULL); | 
|  | if (len < 0 ||  // | 
|  | !CBB_add_space(&cert, &out, (size_t)len) || | 
|  | i2d_X509_CINF(x509->cert_info, &out) != len) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | len = i2d_X509_ALGOR(x509->sig_alg, NULL); | 
|  | if (len < 0 ||  // | 
|  | !CBB_add_space(&cert, &out, (size_t)len) || | 
|  | i2d_X509_ALGOR(x509->sig_alg, &out) != len) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | len = i2d_ASN1_BIT_STRING(x509->signature, NULL); | 
|  | if (len < 0 ||  // | 
|  | !CBB_add_space(&cert, &out, (size_t)len) || | 
|  | i2d_ASN1_BIT_STRING(x509->signature, &out) != len) { | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | return CBB_finish_i2d(&cbb, outp); | 
|  |  | 
|  | err: | 
|  | CBB_cleanup(&cbb); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | 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, V_ASN1_SEQUENCE, 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) { | 
|  | X509_ALGOR *copy1 = X509_ALGOR_dup(algo); | 
|  | X509_ALGOR *copy2 = X509_ALGOR_dup(algo); | 
|  | if (copy1 == NULL || copy2 == NULL) { | 
|  | X509_ALGOR_free(copy1); | 
|  | X509_ALGOR_free(copy2); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | X509_ALGOR_free(x509->sig_alg); | 
|  | x509->sig_alg = copy1; | 
|  | X509_ALGOR_free(x509->cert_info->signature); | 
|  | x509->cert_info->signature = copy2; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | 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); | 
|  | } |