コード例 #1
0
ファイル: ssl_cert.c プロジェクト: ThomasWo/proto-quic
int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
  if (!ssl_has_certificate(ssl)) {
    return CBB_add_u24(cbb, 0);
  }

  CBB certs;
  if (!CBB_add_u24_length_prefixed(cbb, &certs)) {
    goto err;
  }

  STACK_OF(CRYPTO_BUFFER) *chain = ssl->cert->chain;
  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(chain); i++) {
    CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(chain, i);
    CBB child;
    if (!CBB_add_u24_length_prefixed(&certs, &child) ||
        !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
                       CRYPTO_BUFFER_len(buffer)) ||
        !CBB_flush(&certs)) {
      goto err;
    }
  }

  return CBB_flush(cbb);

err:
  OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
  return 0;
}
コード例 #2
0
ファイル: ssl_cert.c プロジェクト: ThomasWo/proto-quic
int ssl_add_client_CA_list(SSL *ssl, CBB *cbb) {
  CBB child, name_cbb;
  if (!CBB_add_u16_length_prefixed(cbb, &child)) {
    return 0;
  }

  STACK_OF(CRYPTO_BUFFER) *names = ssl->client_CA;
  if (names == NULL) {
    names = ssl->ctx->client_CA;
  }
  if (names == NULL) {
    return CBB_flush(cbb);
  }

  for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) {
    const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i);

    if (!CBB_add_u16_length_prefixed(&child, &name_cbb) ||
        !CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name),
                       CRYPTO_BUFFER_len(name))) {
      return 0;
    }
  }

  return CBB_flush(cbb);
}
コード例 #3
0
ファイル: ssl_cert.c プロジェクト: ThomasWo/proto-quic
int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey) {
  if (privkey == NULL) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
    return 0;
  }

  if (cert->chain == NULL ||
      sk_CRYPTO_BUFFER_value(cert->chain, 0) == NULL) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
    return 0;
  }

  CBS cert_cbs;
  CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(cert->chain, 0), &cert_cbs);
  EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs);
  if (!pubkey) {
    OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE);
    return 0;
  }

  const int ok = ssl_compare_public_and_private_key(pubkey, privkey);
  EVP_PKEY_free(pubkey);
  return ok;
}
コード例 #4
0
ファイル: ssl_cert.c プロジェクト: ThomasWo/proto-quic
int ssl_on_certificate_selected(SSL_HANDSHAKE *hs) {
  SSL *const ssl = hs->ssl;
  if (!ssl_has_certificate(ssl)) {
    /* Nothing to do. */
    return 1;
  }

  if (!ssl->ctx->x509_method->ssl_auto_chain_if_needed(ssl)) {
    return 0;
  }

  CBS leaf;
  CRYPTO_BUFFER_init_CBS(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0), &leaf);

  EVP_PKEY_free(hs->local_pubkey);
  hs->local_pubkey = ssl_cert_parse_pubkey(&leaf);
  return hs->local_pubkey != NULL;
}
コード例 #5
0
ファイル: ssl_rsa.c プロジェクト: baiwyc119/proto-quic
static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) {
  if (!is_key_type_supported(pkey->type)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
    return 0;
  }

  if (cert->chain != NULL &&
      sk_CRYPTO_BUFFER_value(cert->chain, 0) != NULL &&
      /* Sanity-check that the private key and the certificate match, unless
       * the key is opaque (in case of, say, a smartcard). */
      !EVP_PKEY_is_opaque(pkey) &&
      !ssl_cert_check_private_key(cert, pkey)) {
    return 0;
  }

  EVP_PKEY_free(cert->privatekey);
  EVP_PKEY_up_ref(pkey);
  cert->privatekey = pkey;

  return 1;
}
コード例 #6
0
ファイル: ssl_cert.c プロジェクト: ThomasWo/proto-quic
int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) {
  switch (check_leaf_cert_and_privkey(buffer, cert->privatekey)) {
    case leaf_cert_and_privkey_error:
      return 0;
    case leaf_cert_and_privkey_mismatch:
      /* don't fail for a cert/key mismatch, just free current private key
       * (when switching to a different cert & key, first this function should
       * be used, then |ssl_set_pkey|. */
      EVP_PKEY_free(cert->privatekey);
      cert->privatekey = NULL;
      break;
    case leaf_cert_and_privkey_ok:
      break;
  }

  cert->x509_method->cert_flush_cached_leaf(cert);

  if (cert->chain != NULL) {
    CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0));
    sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer);
    CRYPTO_BUFFER_up_ref(buffer);
    return 1;
  }

  cert->chain = sk_CRYPTO_BUFFER_new_null();
  if (cert->chain == NULL) {
    return 0;
  }

  if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
    sk_CRYPTO_BUFFER_free(cert->chain);
    cert->chain = NULL;
    return 0;
  }
  CRYPTO_BUFFER_up_ref(buffer);

  return 1;
}
コード例 #7
0
ファイル: ssl_cert.c プロジェクト: ThomasWo/proto-quic
int ssl_has_certificate(const SSL *ssl) {
  return ssl->cert->chain != NULL &&
         sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL &&
         ssl_has_private_key(ssl);
}
コード例 #8
0
ファイル: ssl_asn1.c プロジェクト: ThomasWo/proto-quic
static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
                                     size_t *out_len, int for_ticket) {
  CBB cbb, session, child, child2;

  if (in == NULL || in->cipher == NULL) {
    return 0;
  }

  CBB_zero(&cbb);
  if (!CBB_init(&cbb, 0) ||
      !CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) ||
      !CBB_add_asn1_uint64(&session, kVersion) ||
      !CBB_add_asn1_uint64(&session, in->ssl_version) ||
      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
      !CBB_add_u16(&child, (uint16_t)(in->cipher->id & 0xffff)) ||
      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
      /* The session ID is irrelevant for a session ticket. */
      !CBB_add_bytes(&child, in->session_id,
                     for_ticket ? 0 : in->session_id_length) ||
      !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) ||
      !CBB_add_bytes(&child, in->master_key, in->master_key_length) ||
      !CBB_add_asn1(&session, &child, kTimeTag) ||
      !CBB_add_asn1_uint64(&child, in->time) ||
      !CBB_add_asn1(&session, &child, kTimeoutTag) ||
      !CBB_add_asn1_uint64(&child, in->timeout)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  /* The peer certificate is only serialized if the SHA-256 isn't
   * serialized instead. */
  if (sk_CRYPTO_BUFFER_num(in->certs) > 0 && !in->peer_sha256_valid) {
    const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, 0);
    if (!CBB_add_asn1(&session, &child, kPeerTag) ||
        !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
                       CRYPTO_BUFFER_len(buffer))) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  /* Although it is OPTIONAL and usually empty, OpenSSL has
   * historically always encoded the sid_ctx. */
  if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) ||
      !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
      !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (in->verify_result != X509_V_OK) {
    if (!CBB_add_asn1(&session, &child, kVerifyResultTag) ||
        !CBB_add_asn1_uint64(&child, in->verify_result)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->tlsext_hostname) {
    if (!CBB_add_asn1(&session, &child, kHostNameTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname,
                       strlen(in->tlsext_hostname))) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->psk_identity) {
    if (!CBB_add_asn1(&session, &child, kPSKIdentityTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity,
                       strlen(in->psk_identity))) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->tlsext_tick_lifetime_hint > 0) {
    if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) ||
        !CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->tlsext_tick && !for_ticket) {
    if (!CBB_add_asn1(&session, &child, kTicketTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->peer_sha256_valid) {
    if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->original_handshake_hash_len > 0) {
    if (!CBB_add_asn1(&session, &child, kOriginalHandshakeHashTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, in->original_handshake_hash,
                       in->original_handshake_hash_len)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->tlsext_signed_cert_timestamp_list_length > 0) {
    if (!CBB_add_asn1(&session, &child, kSignedCertTimestampListTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list,
                       in->tlsext_signed_cert_timestamp_list_length)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->ocsp_response_length > 0) {
    if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->extended_master_secret) {
    if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
        !CBB_add_u8(&child2, 0xff)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->group_id > 0 &&
      (!CBB_add_asn1(&session, &child, kGroupIDTag) ||
       !CBB_add_asn1_uint64(&child, in->group_id))) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  /* The certificate chain is only serialized if the leaf's SHA-256 isn't
   * serialized instead. */
  if (in->certs != NULL &&
      !in->peer_sha256_valid &&
      sk_CRYPTO_BUFFER_num(in->certs) >= 2) {
    if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
    for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(in->certs); i++) {
      const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(in->certs, i);
      if (!CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer),
                         CRYPTO_BUFFER_len(buffer))) {
        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
        goto err;
      }
    }
  }

  if (in->ticket_age_add_valid) {
    if (!CBB_add_asn1(&session, &child, kTicketAgeAddTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_u32(&child2, in->ticket_age_add)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (!in->is_server) {
    if (!CBB_add_asn1(&session, &child, kIsServerTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
        !CBB_add_u8(&child2, 0x00)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (in->peer_signature_algorithm != 0 &&
      (!CBB_add_asn1(&session, &child, kPeerSignatureAlgorithmTag) ||
       !CBB_add_asn1_uint64(&child, in->peer_signature_algorithm))) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (in->ticket_max_early_data != 0 &&
      (!CBB_add_asn1(&session, &child, kTicketMaxEarlyDataTag) ||
       !CBB_add_asn1_uint64(&child, in->ticket_max_early_data))) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (in->timeout != in->auth_timeout &&
      (!CBB_add_asn1(&session, &child, kAuthTimeoutTag) ||
       !CBB_add_asn1_uint64(&child, in->auth_timeout))) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (in->early_alpn) {
    if (!CBB_add_asn1(&session, &child, kEarlyALPNTag) ||
        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
        !CBB_add_bytes(&child2, (const uint8_t *)in->early_alpn,
                       in->early_alpn_len)) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (!CBB_finish(&cbb, out_data, out_len)) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }
  return 1;

 err:
  CBB_cleanup(&cbb);
  return 0;
}
コード例 #9
0
ファイル: ssl_session.c プロジェクト: boringssl/boringssl
SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
  SSL_SESSION *new_session = ssl_session_new(session->x509_method);
  if (new_session == NULL) {
    goto err;
  }

  new_session->is_server = session->is_server;
  new_session->ssl_version = session->ssl_version;
  new_session->sid_ctx_length = session->sid_ctx_length;
  OPENSSL_memcpy(new_session->sid_ctx, session->sid_ctx, session->sid_ctx_length);

  /* Copy the key material. */
  new_session->master_key_length = session->master_key_length;
  OPENSSL_memcpy(new_session->master_key, session->master_key,
         session->master_key_length);
  new_session->cipher = session->cipher;

  /* Copy authentication state. */
  if (session->psk_identity != NULL) {
    new_session->psk_identity = BUF_strdup(session->psk_identity);
    if (new_session->psk_identity == NULL) {
      goto err;
    }
  }
  if (session->certs != NULL) {
    new_session->certs = sk_CRYPTO_BUFFER_new_null();
    if (new_session->certs == NULL) {
      goto err;
    }
    for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(session->certs); i++) {
      CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(session->certs, i);
      if (!sk_CRYPTO_BUFFER_push(new_session->certs, buffer)) {
        goto err;
      }
      CRYPTO_BUFFER_up_ref(buffer);
    }
  }

  if (!session->x509_method->session_dup(new_session, session)) {
    goto err;
  }

  new_session->verify_result = session->verify_result;

  new_session->ocsp_response_length = session->ocsp_response_length;
  if (session->ocsp_response != NULL) {
    new_session->ocsp_response = BUF_memdup(session->ocsp_response,
                                            session->ocsp_response_length);
    if (new_session->ocsp_response == NULL) {
      goto err;
    }
  }

  new_session->tlsext_signed_cert_timestamp_list_length =
      session->tlsext_signed_cert_timestamp_list_length;
  if (session->tlsext_signed_cert_timestamp_list != NULL) {
    new_session->tlsext_signed_cert_timestamp_list =
        BUF_memdup(session->tlsext_signed_cert_timestamp_list,
                   session->tlsext_signed_cert_timestamp_list_length);
    if (new_session->tlsext_signed_cert_timestamp_list == NULL) {
      goto err;
    }
  }

  OPENSSL_memcpy(new_session->peer_sha256, session->peer_sha256,
                 SHA256_DIGEST_LENGTH);
  new_session->peer_sha256_valid = session->peer_sha256_valid;

  if (session->tlsext_hostname != NULL) {
    new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
    if (new_session->tlsext_hostname == NULL) {
      goto err;
    }
  }

  new_session->peer_signature_algorithm = session->peer_signature_algorithm;

  new_session->timeout = session->timeout;
  new_session->auth_timeout = session->auth_timeout;
  new_session->time = session->time;

  /* Copy non-authentication connection properties. */
  if (dup_flags & SSL_SESSION_INCLUDE_NONAUTH) {
    new_session->session_id_length = session->session_id_length;
    OPENSSL_memcpy(new_session->session_id, session->session_id,
                   session->session_id_length);

    new_session->group_id = session->group_id;

    OPENSSL_memcpy(new_session->original_handshake_hash,
                   session->original_handshake_hash,
                   session->original_handshake_hash_len);
    new_session->original_handshake_hash_len =
        session->original_handshake_hash_len;
    new_session->tlsext_tick_lifetime_hint = session->tlsext_tick_lifetime_hint;
    new_session->ticket_age_add = session->ticket_age_add;
    new_session->ticket_max_early_data = session->ticket_max_early_data;
    new_session->extended_master_secret = session->extended_master_secret;

    if (session->early_alpn != NULL) {
      new_session->early_alpn =
          BUF_memdup(session->early_alpn, session->early_alpn_len);
      if (new_session->early_alpn == NULL) {
        goto err;
      }
    }
    new_session->early_alpn_len = session->early_alpn_len;
  }

  /* Copy the ticket. */
  if (dup_flags & SSL_SESSION_INCLUDE_TICKET) {
    if (session->tlsext_tick != NULL) {
      new_session->tlsext_tick =
          BUF_memdup(session->tlsext_tick, session->tlsext_ticklen);
      if (new_session->tlsext_tick == NULL) {
        goto err;
      }
    }
    new_session->tlsext_ticklen = session->tlsext_ticklen;
  }

  /* The new_session does not get a copy of the ex_data. */

  new_session->not_resumable = 1;
  return new_session;

err:
  SSL_SESSION_free(new_session);
  OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
  return 0;
}
コード例 #10
0
ファイル: ssl_rsa.c プロジェクト: baiwyc119/proto-quic
static int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) {
  CBS cert_cbs;
  CRYPTO_BUFFER_init_CBS(buffer, &cert_cbs);
  EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs);
  if (pubkey == NULL) {
    return 0;
  }

  if (!is_key_type_supported(pubkey->type)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
    EVP_PKEY_free(pubkey);
    return 0;
  }

  /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA
   * certificates, so sanity-check the key usage extension. */
  if (pubkey->type == EVP_PKEY_EC &&
      !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE);
    EVP_PKEY_free(pubkey);
    return 0;
  }

  if (cert->privatekey != NULL) {
    /* Sanity-check that the private key and the certificate match, unless the
     * key is opaque (in case of, say, a smartcard). */
    if (!EVP_PKEY_is_opaque(cert->privatekey) &&
        !ssl_compare_public_and_private_key(pubkey, cert->privatekey)) {
      /* don't fail for a cert/key mismatch, just free current private key
       * (when switching to a different cert & key, first this function should
       * be used, then ssl_set_pkey */
      EVP_PKEY_free(cert->privatekey);
      cert->privatekey = NULL;
      /* clear error queue */
      ERR_clear_error();
    }
  }

  EVP_PKEY_free(pubkey);

  ssl_cert_flush_cached_x509_leaf(cert);

  if (cert->chain != NULL) {
    CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0));
    sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer);
    CRYPTO_BUFFER_up_ref(buffer);
    return 1;
  }

  cert->chain = sk_CRYPTO_BUFFER_new_null();
  if (cert->chain == NULL) {
    return 0;
  }

  if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) {
    sk_CRYPTO_BUFFER_free(cert->chain);
    cert->chain = NULL;
    return 0;
  }
  CRYPTO_BUFFER_up_ref(buffer);

  return 1;
}