Beispiel #1
0
void ssl_cert_free(CERT *c) {
  if (c == NULL) {
    return;
  }

  ssl_cert_clear_certs(c);
  c->x509_method->cert_free(c);
  OPENSSL_free(c->sigalgs);
  CRYPTO_BUFFER_free(c->signed_cert_timestamp_list);
  CRYPTO_BUFFER_free(c->ocsp_response);

  OPENSSL_free(c);
}
Beispiel #2
0
static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
                   void *exarg)
{
    X509 *ret = (X509 *)*pval;

    switch (operation) {

    case ASN1_OP_NEW_POST:
        ret->name = NULL;
        ret->ex_flags = 0;
        ret->ex_pathlen = -1;
        ret->skid = NULL;
        ret->akid = NULL;
        ret->aux = NULL;
        ret->crldp = NULL;
        ret->buf = NULL;
        CRYPTO_new_ex_data(&ret->ex_data);
        CRYPTO_MUTEX_init(&ret->lock);
        break;

    case ASN1_OP_D2I_PRE:
        CRYPTO_BUFFER_free(ret->buf);
        ret->buf = NULL;
        break;

    case ASN1_OP_D2I_POST:
        if (ret->name != NULL)
            OPENSSL_free(ret->name);
        ret->name = X509_NAME_oneline(ret->cert_info->subject, NULL, 0);
        break;

    case ASN1_OP_FREE_POST:
        CRYPTO_MUTEX_cleanup(&ret->lock);
        CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data);
        X509_CERT_AUX_free(ret->aux);
        ASN1_OCTET_STRING_free(ret->skid);
        AUTHORITY_KEYID_free(ret->akid);
        CRL_DIST_POINTS_free(ret->crldp);
        policy_cache_free(ret->policy_cache);
        GENERAL_NAMES_free(ret->altname);
        NAME_CONSTRAINTS_free(ret->nc);
        CRYPTO_BUFFER_free(ret->buf);
        OPENSSL_free(ret->name);
        break;

    }

    return 1;

}
Beispiel #3
0
int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) {
  CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL);
  if (buffer == NULL) {
    return 0;
  }

  const int ok = ssl_set_cert(ssl->cert, buffer);
  CRYPTO_BUFFER_free(buffer);
  return ok;
}
Beispiel #4
0
static int set_signed_cert_timestamp_list(CERT *cert, const uint8_t *list,
                                           size_t list_len) {
  CBS sct_list;
  CBS_init(&sct_list, list, list_len);
  if (!ssl_is_sct_list_valid(&sct_list)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST);
    return 0;
  }

  CRYPTO_BUFFER_free(cert->signed_cert_timestamp_list);
  cert->signed_cert_timestamp_list =
      CRYPTO_BUFFER_new(CBS_data(&sct_list), CBS_len(&sct_list), NULL);
  return cert->signed_cert_timestamp_list != NULL;
}
Beispiel #5
0
STACK_OF(CRYPTO_BUFFER) *
    ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) {
  CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool;

  STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
  if (ret == NULL) {
    *out_alert = SSL_AD_INTERNAL_ERROR;
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    return NULL;
  }

  CBS child;
  if (!CBS_get_u16_length_prefixed(cbs, &child)) {
    *out_alert = SSL_AD_DECODE_ERROR;
    OPENSSL_PUT_ERROR(SSL, SSL_R_LENGTH_MISMATCH);
    goto err;
  }

  while (CBS_len(&child) > 0) {
    CBS distinguished_name;
    if (!CBS_get_u16_length_prefixed(&child, &distinguished_name)) {
      *out_alert = SSL_AD_DECODE_ERROR;
      OPENSSL_PUT_ERROR(SSL, SSL_R_CA_DN_TOO_LONG);
      goto err;
    }

    CRYPTO_BUFFER *buffer =
        CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool);
    if (buffer == NULL ||
        !sk_CRYPTO_BUFFER_push(ret, buffer)) {
      CRYPTO_BUFFER_free(buffer);
      *out_alert = SSL_AD_INTERNAL_ERROR;
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  if (!ssl->ctx->x509_method->check_client_CA_list(ret)) {
    *out_alert = SSL_AD_INTERNAL_ERROR;
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    goto err;
  }

  return ret;

err:
  sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
  return NULL;
}
Beispiel #6
0
int SSL_use_certificate(SSL *ssl, X509 *x) {
  if (x == NULL) {
    OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER);
    return 0;
  }

  CRYPTO_BUFFER *buffer = x509_to_buffer(x);
  if (buffer == NULL) {
    return 0;
  }

  const int ok = ssl_set_cert(ssl->cert, buffer);
  CRYPTO_BUFFER_free(buffer);
  return ok;
}
Beispiel #7
0
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;
}
Beispiel #8
0
int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response,
                          size_t response_len) {
  CRYPTO_BUFFER_free(ssl->cert->ocsp_response);
  ssl->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL);
  return ssl->cert->ocsp_response != NULL;
}
Beispiel #9
0
int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response,
                              size_t response_len) {
  CRYPTO_BUFFER_free(ctx->cert->ocsp_response);
  ctx->cert->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL);
  return ctx->cert->ocsp_response != NULL;
}
Beispiel #10
0
STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert,
                                              EVP_PKEY **out_pubkey,
                                              uint8_t *out_leaf_sha256,
                                              CBS *cbs,
                                              CRYPTO_BUFFER_POOL *pool) {
  *out_pubkey = NULL;

  STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null();
  if (ret == NULL) {
    *out_alert = SSL_AD_INTERNAL_ERROR;
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    return NULL;
  }

  CBS certificate_list;
  if (!CBS_get_u24_length_prefixed(cbs, &certificate_list)) {
    *out_alert = SSL_AD_DECODE_ERROR;
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    goto err;
  }

  while (CBS_len(&certificate_list) > 0) {
    CBS certificate;
    if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
        CBS_len(&certificate) == 0) {
      *out_alert = SSL_AD_DECODE_ERROR;
      OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
      goto err;
    }

    if (sk_CRYPTO_BUFFER_num(ret) == 0) {
      *out_pubkey = ssl_cert_parse_pubkey(&certificate);
      if (*out_pubkey == NULL) {
        *out_alert = SSL_AD_DECODE_ERROR;
        goto err;
      }

      /* Retain the hash of the leaf certificate if requested. */
      if (out_leaf_sha256 != NULL) {
        SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
      }
    }

    CRYPTO_BUFFER *buf =
        CRYPTO_BUFFER_new_from_CBS(&certificate, pool);
    if (buf == NULL) {
      *out_alert = SSL_AD_DECODE_ERROR;
      goto err;
    }

    if (!sk_CRYPTO_BUFFER_push(ret, buf)) {
      *out_alert = SSL_AD_INTERNAL_ERROR;
      CRYPTO_BUFFER_free(buf);
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }
  }

  return ret;

err:
  EVP_PKEY_free(*out_pubkey);
  *out_pubkey = NULL;
  sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free);
  return NULL;
}
Beispiel #11
0
int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) {
  SSL *const ssl = hs->ssl;
  CBS cbs, context, certificate_list;
  CBS_init(&cbs, ssl->init_msg, ssl->init_num);
  if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
      CBS_len(&context) != 0) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    return 0;
  }

  const int retain_sha256 =
      ssl->server && ssl->retain_only_sha256_of_client_certs;
  int ret = 0;

  EVP_PKEY *pkey = NULL;
  STACK_OF(CRYPTO_BUFFER) *certs = sk_CRYPTO_BUFFER_new_null();
  if (certs == NULL) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
    OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
    goto err;
  }

  if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) {
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    goto err;
  }

  while (CBS_len(&certificate_list) > 0) {
    CBS certificate, extensions;
    if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
        !CBS_get_u16_length_prefixed(&certificate_list, &extensions) ||
        CBS_len(&certificate) == 0) {
      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
      OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
      goto err;
    }

    if (sk_CRYPTO_BUFFER_num(certs) == 0) {
      pkey = ssl_cert_parse_pubkey(&certificate);
      if (pkey == NULL) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
        OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
        goto err;
      }
      /* TLS 1.3 always uses certificate keys for signing thus the correct
       * keyUsage is enforced. */
      if (!ssl_cert_check_digital_signature_key_usage(&certificate)) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
        goto err;
      }

      if (retain_sha256) {
        /* Retain the hash of the leaf certificate if requested. */
        SHA256(CBS_data(&certificate), CBS_len(&certificate),
               ssl->s3->new_session->peer_sha256);
      }
    }

    CRYPTO_BUFFER *buf =
        CRYPTO_BUFFER_new_from_CBS(&certificate, ssl->ctx->pool);
    if (buf == NULL ||
        !sk_CRYPTO_BUFFER_push(certs, buf)) {
      CRYPTO_BUFFER_free(buf);
      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }

    /* Parse out the extensions. */
    int have_status_request = 0, have_sct = 0;
    CBS status_request, sct;
    const SSL_EXTENSION_TYPE ext_types[] = {
        {TLSEXT_TYPE_status_request, &have_status_request, &status_request},
        {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
    };

    uint8_t alert;
    if (!ssl_parse_extensions(&extensions, &alert, ext_types,
                              OPENSSL_ARRAY_SIZE(ext_types),
                              0 /* reject unknown */)) {
      ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
      goto err;
    }

    /* All Certificate extensions are parsed, but only the leaf extensions are
     * stored. */
    if (have_status_request) {
      if (ssl->server || !ssl->ocsp_stapling_enabled) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
        goto err;
      }

      uint8_t status_type;
      CBS ocsp_response;
      if (!CBS_get_u8(&status_request, &status_type) ||
          status_type != TLSEXT_STATUSTYPE_ocsp ||
          !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
          CBS_len(&ocsp_response) == 0 ||
          CBS_len(&status_request) != 0) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
        goto err;
      }

      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
          !CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
                    &ssl->s3->new_session->ocsp_response_length)) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
        goto err;
      }
    }

    if (have_sct) {
      if (ssl->server || !ssl->signed_cert_timestamps_enabled) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
        goto err;
      }

      if (!ssl_is_sct_list_valid(&sct)) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
        goto err;
      }

      if (sk_CRYPTO_BUFFER_num(certs) == 1 &&
          !CBS_stow(&sct,
                    &ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
                    &ssl->s3->new_session
                         ->tlsext_signed_cert_timestamp_list_length)) {
        ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
        goto err;
      }
    }
  }

  if (CBS_len(&cbs) != 0) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    goto err;
  }

  EVP_PKEY_free(hs->peer_pubkey);
  hs->peer_pubkey = pkey;
  pkey = NULL;

  sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free);
  ssl->s3->new_session->certs = certs;
  certs = NULL;

  if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
    ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
    goto err;
  }

  if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) {
    if (!allow_anonymous) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE);
      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_CERTIFICATE_REQUIRED);
      goto err;
    }

    /* OpenSSL returns X509_V_OK when no certificates are requested. This is
     * classed by them as a bug, but it's assumed by at least NGINX. */
    ssl->s3->new_session->verify_result = X509_V_OK;

    /* No certificate, so nothing more to do. */
    ret = 1;
    goto err;
  }

  ssl->s3->new_session->peer_sha256_valid = retain_sha256;

  if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
                             ssl->s3->new_session->x509_chain)) {
    goto err;
  }

  ret = 1;

err:
  sk_CRYPTO_BUFFER_pop_free(certs, CRYPTO_BUFFER_free);
  EVP_PKEY_free(pkey);
  return ret;
}
Beispiel #12
0
SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method,
                               CRYPTO_BUFFER_POOL *pool) {
  SSL_SESSION *ret = ssl_session_new(x509_method);
  if (ret == NULL) {
    goto err;
  }

  CBS session;
  uint64_t version, ssl_version;
  if (!CBS_get_asn1(cbs, &session, CBS_ASN1_SEQUENCE) ||
      !CBS_get_asn1_uint64(&session, &version) ||
      version != kVersion ||
      !CBS_get_asn1_uint64(&session, &ssl_version)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  ret->ssl_version = ssl_version;

  CBS cipher;
  uint16_t cipher_value;
  if (!CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) ||
      !CBS_get_u16(&cipher, &cipher_value) ||
      CBS_len(&cipher) != 0) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  ret->cipher = SSL_get_cipher_by_value(cipher_value);
  if (ret->cipher == NULL) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_CIPHER);
    goto err;
  }

  CBS session_id, master_key;
  if (!CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH ||
      !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) ||
      CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  OPENSSL_memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id));
  ret->session_id_length = CBS_len(&session_id);
  OPENSSL_memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
  ret->master_key_length = CBS_len(&master_key);

  CBS child;
  uint64_t timeout;
  if (!CBS_get_asn1(&session, &child, kTimeTag) ||
      !CBS_get_asn1_uint64(&child, &ret->time) ||
      !CBS_get_asn1(&session, &child, kTimeoutTag) ||
      !CBS_get_asn1_uint64(&child, &timeout) ||
      timeout > UINT32_MAX) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }

  ret->timeout = (uint32_t)timeout;

  CBS peer;
  int has_peer;
  if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) ||
      (has_peer && CBS_len(&peer) == 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  /* |peer| is processed with the certificate chain. */

  if (!SSL_SESSION_parse_bounded_octet_string(
          &session, ret->sid_ctx, &ret->sid_ctx_length, sizeof(ret->sid_ctx),
          kSessionIDContextTag) ||
      !SSL_SESSION_parse_long(&session, &ret->verify_result, kVerifyResultTag,
                              X509_V_OK) ||
      !SSL_SESSION_parse_string(&session, &ret->tlsext_hostname,
                                kHostNameTag) ||
      !SSL_SESSION_parse_string(&session, &ret->psk_identity,
                                kPSKIdentityTag) ||
      !SSL_SESSION_parse_u32(&session, &ret->tlsext_tick_lifetime_hint,
                             kTicketLifetimeHintTag, 0) ||
      !SSL_SESSION_parse_octet_string(&session, &ret->tlsext_tick,
                                      &ret->tlsext_ticklen, kTicketTag)) {
    goto err;
  }

  if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) {
    CBS peer_sha256;
    if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) ||
        !CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) ||
        CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) ||
        CBS_len(&child) != 0) {
      OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
      goto err;
    }
    OPENSSL_memcpy(ret->peer_sha256, CBS_data(&peer_sha256),
                   sizeof(ret->peer_sha256));
    ret->peer_sha256_valid = 1;
  } else {
    ret->peer_sha256_valid = 0;
  }

  if (!SSL_SESSION_parse_bounded_octet_string(
          &session, ret->original_handshake_hash,
          &ret->original_handshake_hash_len,
          sizeof(ret->original_handshake_hash), kOriginalHandshakeHashTag) ||
      !SSL_SESSION_parse_octet_string(
          &session, &ret->tlsext_signed_cert_timestamp_list,
          &ret->tlsext_signed_cert_timestamp_list_length,
          kSignedCertTimestampListTag) ||
      !SSL_SESSION_parse_octet_string(
          &session, &ret->ocsp_response, &ret->ocsp_response_length,
          kOCSPResponseTag)) {
    goto err;
  }

  int extended_master_secret;
  if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
                                  kExtendedMasterSecretTag,
                                  0 /* default to false */)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  ret->extended_master_secret = !!extended_master_secret;

  if (!SSL_SESSION_parse_u16(&session, &ret->group_id, kGroupIDTag, 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }

  CBS cert_chain;
  CBS_init(&cert_chain, NULL, 0);
  int has_cert_chain;
  if (!CBS_get_optional_asn1(&session, &cert_chain, &has_cert_chain,
                             kCertChainTag) ||
      (has_cert_chain && CBS_len(&cert_chain) == 0)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  if (has_cert_chain && !has_peer) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  if (has_peer || has_cert_chain) {
    ret->certs = sk_CRYPTO_BUFFER_new_null();
    if (ret->certs == NULL) {
      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
      goto err;
    }

    if (has_peer) {
      /* TODO(agl): this should use the |SSL_CTX|'s pool. */
      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, pool);
      if (buffer == NULL ||
          !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
        CRYPTO_BUFFER_free(buffer);
        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
        goto err;
      }
    }

    while (CBS_len(&cert_chain) > 0) {
      CBS cert;
      if (!CBS_get_any_asn1_element(&cert_chain, &cert, NULL, NULL) ||
          CBS_len(&cert) == 0) {
        OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
        goto err;
      }

      /* TODO(agl): this should use the |SSL_CTX|'s pool. */
      CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, pool);
      if (buffer == NULL ||
          !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) {
        CRYPTO_BUFFER_free(buffer);
        OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
        goto err;
      }
    }
  }

  if (!x509_method->session_cache_objects(ret)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }

  CBS age_add;
  int age_add_present;
  if (!CBS_get_optional_asn1_octet_string(&session, &age_add, &age_add_present,
                                          kTicketAgeAddTag) ||
      (age_add_present &&
       !CBS_get_u32(&age_add, &ret->ticket_age_add)) ||
      CBS_len(&age_add) != 0) {
    goto err;
  }
  ret->ticket_age_add_valid = age_add_present;

  int is_server;
  if (!CBS_get_optional_asn1_bool(&session, &is_server, kIsServerTag,
                                  1 /* default to true */)) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }
  /* TODO: in time we can include |is_server| for servers too, then we can
     enforce that client and server sessions are never mixed up. */

  ret->is_server = is_server;

  if (!SSL_SESSION_parse_u16(&session, &ret->peer_signature_algorithm,
                             kPeerSignatureAlgorithmTag, 0) ||
      !SSL_SESSION_parse_u32(&session, &ret->ticket_max_early_data,
                             kTicketMaxEarlyDataTag, 0) ||
      !SSL_SESSION_parse_u32(&session, &ret->auth_timeout, kAuthTimeoutTag,
                             ret->timeout) ||
      !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn,
                                      &ret->early_alpn_len, kEarlyALPNTag) ||
      CBS_len(&session) != 0) {
    OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
    goto err;
  }

  return ret;

err:
  SSL_SESSION_free(ret);
  return NULL;
}
Beispiel #13
0
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;
}