enum ssl_private_key_result_t tls13_prepare_certificate_verify( SSL *ssl, int is_first_run) { enum ssl_private_key_result_t ret = ssl_private_key_failure; uint8_t *msg = NULL; size_t msg_len; CBB cbb, body; CBB_zero(&cbb); uint16_t signature_algorithm; if (!tls1_choose_signature_algorithm(ssl, &signature_algorithm)) { goto err; } if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE_VERIFY) || !CBB_add_u16(&body, signature_algorithm)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; } /* Sign the digest. */ CBB child; const size_t max_sig_len = ssl_private_key_max_signature_len(ssl); uint8_t *sig; size_t sig_len; if (!CBB_add_u16_length_prefixed(&body, &child) || !CBB_reserve(&child, &sig, max_sig_len)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } enum ssl_private_key_result_t sign_result; if (is_first_run) { if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len, ssl->server)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; } sign_result = ssl_private_key_sign(ssl, sig, &sig_len, max_sig_len, signature_algorithm, msg, msg_len); } else { sign_result = ssl_private_key_complete(ssl, sig, &sig_len, max_sig_len); } if (sign_result != ssl_private_key_success) { ret = sign_result; goto err; } if (!CBB_did_write(&child, sig_len) || !ssl->method->finish_message(ssl, &cbb)) { goto err; } ret = ssl_private_key_success; err: CBB_cleanup(&cbb); OPENSSL_free(msg); return ret; }
int ECDSA_sign_ex(int type, const uint8_t *digest, size_t digest_len, uint8_t *sig, unsigned int *sig_len, const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey) { int ret = 0; ECDSA_SIG *s = NULL; s = ECDSA_do_sign_ex(digest, digest_len, kinv, r, eckey); if (s == NULL) { *sig_len = 0; goto err; } CBB cbb; CBB_zero(&cbb); size_t len; if (!CBB_init_fixed(&cbb, sig, ECDSA_size(eckey)) || !ECDSA_SIG_marshal(&cbb, s) || !CBB_finish(&cbb, NULL, &len)) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); CBB_cleanup(&cbb); *sig_len = 0; goto err; } *sig_len = (unsigned)len; ret = 1; err: ECDSA_SIG_free(s); return ret; }
int ECDSA_SIG_to_bytes(uint8_t **out_bytes, size_t *out_len, const ECDSA_SIG *sig) { CBB cbb; CBB_zero(&cbb); if (!CBB_init(&cbb, 0) || !ECDSA_SIG_marshal(&cbb, sig) || !CBB_finish(&cbb, out_bytes, out_len)) { OPENSSL_PUT_ERROR(ECDSA, ECDSA_R_ENCODE_ERROR); CBB_cleanup(&cbb); return 0; } return 1; }
int RSA_private_key_to_bytes(uint8_t **out_bytes, size_t *out_len, const RSA *rsa) { CBB cbb; CBB_zero(&cbb); if (!CBB_init(&cbb, 0) || !RSA_marshal_private_key(&cbb, rsa) || !CBB_finish(&cbb, out_bytes, out_len)) { OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR); CBB_cleanup(&cbb); return 0; } return 1; }
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; }
static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) { /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the * client makes several connections before getting a renewal. */ static const int kNumTickets = 2; SSL *const ssl = hs->ssl; /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a * session ticket. */ if (!hs->accept_psk_mode) { hs->tls13_state = state_done; return ssl_hs_ok; } SSL_SESSION *session = ssl->s3->new_session; CBB cbb; CBB_zero(&cbb); for (int i = 0; i < kNumTickets; i++) { if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) { goto err; } CBB body, ticket, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) || !CBB_add_u32(&body, session->timeout) || !CBB_add_u32(&body, session->ticket_age_add) || !CBB_add_u16_length_prefixed(&body, &ticket) || !ssl_encrypt_ticket(ssl, &ticket, session) || !CBB_add_u16_length_prefixed(&body, &extensions)) { goto err; } if (ssl->ctx->enable_early_data) { session->ticket_max_early_data = kMaxEarlyDataAccepted; CBB early_data_info; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) || !CBB_add_u16_length_prefixed(&extensions, &early_data_info) || !CBB_add_u32(&early_data_info, session->ticket_max_early_data) || !CBB_flush(&extensions)) { goto err; } } /* Add a fake extension. See draft-davidben-tls-grease-01. */ if (!CBB_add_u16(&extensions, ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || !CBB_add_u16(&extensions, 0 /* empty */)) { goto err; } if (!ssl_add_message_cbb(ssl, &cbb)) { goto err; } } hs->session_tickets_sent++; hs->tls13_state = state_done; return ssl_hs_flush; err: CBB_cleanup(&cbb); return ssl_hs_error; }
static int add_new_session_tickets(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; /* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case * the client makes several connections before getting a renewal. */ static const int kNumTickets = 2; SSL_SESSION *session = hs->new_session; CBB cbb; CBB_zero(&cbb); /* Rebase the session timestamp so that it is measured from ticket * issuance. */ ssl_session_rebase_time(ssl, session); for (int i = 0; i < kNumTickets; i++) { if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) { goto err; } session->ticket_age_add_valid = 1; CBB body, ticket, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) || !CBB_add_u32(&body, session->timeout) || !CBB_add_u32(&body, session->ticket_age_add) || !CBB_add_u16_length_prefixed(&body, &ticket) || !ssl_encrypt_ticket(ssl, &ticket, session) || !CBB_add_u16_length_prefixed(&body, &extensions)) { goto err; } if (ssl->cert->enable_early_data) { session->ticket_max_early_data = kMaxEarlyDataAccepted; CBB early_data_info; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_ticket_early_data_info) || !CBB_add_u16_length_prefixed(&extensions, &early_data_info) || !CBB_add_u32(&early_data_info, session->ticket_max_early_data) || !CBB_flush(&extensions)) { goto err; } } /* Add a fake extension. See draft-davidben-tls-grease-01. */ if (!CBB_add_u16(&extensions, ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) || !CBB_add_u16(&extensions, 0 /* empty */)) { goto err; } if (!ssl_add_message_cbb(ssl, &cbb)) { goto err; } } return 1; err: CBB_cleanup(&cbb); return 0; }