QUIC: Add ERR_raise() calls for EVP call failures

This improves tracking where the failure was triggered.

Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21700)
This commit is contained in:
Tomas Mraz 2023-08-09 16:28:41 +02:00
parent 68b9a32aa3
commit cb19528b93
7 changed files with 148 additions and 53 deletions

View File

@ -1428,6 +1428,7 @@ SSL_R_LENGTH_TOO_LONG:404:length too long
SSL_R_LENGTH_TOO_SHORT:160:length too short
SSL_R_LIBRARY_BUG:274:library bug
SSL_R_LIBRARY_HAS_NO_CIPHERS:161:library has no ciphers
SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED:395:maximum encrypted pkts reached
SSL_R_MISSING_DSA_SIGNING_CERT:165:missing dsa signing cert
SSL_R_MISSING_ECDSA_SIGNING_CERT:381:missing ecdsa signing cert
SSL_R_MISSING_FATAL:256:missing fatal

View File

@ -163,6 +163,7 @@
# define SSL_R_LENGTH_TOO_SHORT 160
# define SSL_R_LIBRARY_BUG 274
# define SSL_R_LIBRARY_HAS_NO_CIPHERS 161
# define SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED 395
# define SSL_R_MISSING_DSA_SIGNING_CERT 165
# define SSL_R_MISSING_ECDSA_SIGNING_CERT 381
# define SSL_R_MISSING_FATAL 256

View File

@ -114,18 +114,24 @@ static int el_setup_keyslot(OSSL_QRL_ENC_LEVEL_SET *els,
if (!ossl_assert(el != NULL
&& ossl_qrl_enc_level_set_has_keyslot(els, enc_level,
tgt_state, keyslot)))
tgt_state, keyslot))) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
cipher_name = ossl_qrl_get_suite_cipher_name(el->suite_id);
iv_len = ossl_qrl_get_suite_cipher_iv_len(el->suite_id);
key_len = ossl_qrl_get_suite_cipher_key_len(el->suite_id);
if (cipher_name == NULL)
if (cipher_name == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
if (secret_len != ossl_qrl_get_suite_secret_len(el->suite_id)
|| secret_len > EVP_MAX_KEY_LENGTH)
|| secret_len > EVP_MAX_KEY_LENGTH) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
assert(el->cctx[keyslot] == NULL);
@ -136,7 +142,7 @@ static int el_setup_keyslot(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_iv_label,
sizeof(quic_v1_iv_label),
NULL, 0,
el->iv[keyslot], iv_len, 0))
el->iv[keyslot], iv_len, 1))
goto err;
/* Derive "quic key" key. */
@ -146,23 +152,31 @@ static int el_setup_keyslot(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_key_label,
sizeof(quic_v1_key_label),
NULL, 0,
key, key_len, 0))
key, key_len, 1))
goto err;
/* Create and initialise cipher context. */
if ((cipher = EVP_CIPHER_fetch(el->libctx, cipher_name, el->propq)) == NULL)
if ((cipher = EVP_CIPHER_fetch(el->libctx, cipher_name, el->propq)) == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
if ((cctx = EVP_CIPHER_CTX_new()) == NULL)
if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
if (!ossl_assert(iv_len == (size_t)EVP_CIPHER_get_iv_length(cipher))
|| !ossl_assert(key_len == (size_t)EVP_CIPHER_get_key_length(cipher)))
|| !ossl_assert(key_len == (size_t)EVP_CIPHER_get_key_length(cipher))) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
goto err;
}
/* IV will be changed on RX/TX so we don't need to use a real value here. */
if (!EVP_CipherInit_ex(cctx, cipher, NULL, key, el->iv[keyslot], 0))
if (!EVP_CipherInit_ex(cctx, cipher, NULL, key, el->iv[keyslot], 0)) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
el->cctx[keyslot] = cctx;
@ -199,8 +213,10 @@ int ossl_qrl_enc_level_set_provide_secret(OSSL_QRL_ENC_LEVEL_SET *els,
if (el == NULL
|| md_name == NULL
|| init_key_phase_bit > 1 || is_tx < 0 || is_tx > 1
|| (init_key_phase_bit > 0 && enc_level != QUIC_ENC_LEVEL_1RTT))
|| (init_key_phase_bit > 0 && enc_level != QUIC_ENC_LEVEL_1RTT)) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (enc_level == QUIC_ENC_LEVEL_INITIAL
&& el->state == QRL_EL_STATE_PROV_NORMAL) {
@ -214,18 +230,24 @@ int ossl_qrl_enc_level_set_provide_secret(OSSL_QRL_ENC_LEVEL_SET *els,
el->state = QRL_EL_STATE_UNPROV;
}
if (el->state != QRL_EL_STATE_UNPROV)
if (el->state != QRL_EL_STATE_UNPROV) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
init_keyslot = is_tx ? 0 : init_key_phase_bit;
hpr_key_len = ossl_qrl_get_suite_hdr_prot_key_len(suite_id);
if (hpr_key_len == 0)
if (hpr_key_len == 0) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
if (md == NULL) {
md = EVP_MD_fetch(libctx, md_name, propq);
if (md == NULL)
if (md == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
own_md = 1;
}
@ -246,7 +268,7 @@ int ossl_qrl_enc_level_set_provide_secret(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_hp_label,
sizeof(quic_v1_hp_label),
NULL, 0,
hpr_key, hpr_key_len, 0))
hpr_key, hpr_key_len, 1))
goto err;
/* Setup KS0 (or KS1 if init_key_phase_bit), our initial keyslot. */
@ -264,7 +286,7 @@ int ossl_qrl_enc_level_set_provide_secret(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_ku_label,
sizeof(quic_v1_ku_label),
NULL, 0,
is_tx ? el->ku : ku_key, secret_len, 0))
is_tx ? el->ku : ku_key, secret_len, 1))
goto err;
if (!is_tx) {
@ -282,7 +304,7 @@ int ossl_qrl_enc_level_set_provide_secret(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_ku_label,
sizeof(quic_v1_ku_label),
NULL, 0,
el->ku, secret_len, 0))
el->ku, secret_len, 1))
goto err;
}
}
@ -327,11 +349,15 @@ int ossl_qrl_enc_level_set_key_update(OSSL_QRL_ENC_LEVEL_SET *els,
size_t secret_len;
unsigned char new_ku[EVP_MAX_KEY_LENGTH];
if (el == NULL || !ossl_assert(enc_level == QUIC_ENC_LEVEL_1RTT))
if (el == NULL || !ossl_assert(enc_level == QUIC_ENC_LEVEL_1RTT)) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (el->state != QRL_EL_STATE_PROV_NORMAL)
if (el->state != QRL_EL_STATE_PROV_NORMAL) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
if (!el->is_tx) {
/*
@ -354,7 +380,7 @@ int ossl_qrl_enc_level_set_key_update(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_ku_label,
sizeof(quic_v1_ku_label),
NULL, 0,
new_ku, secret_len, 0))
new_ku, secret_len, 1))
return 0;
el_teardown_keyslot(els, enc_level, 0);
@ -377,8 +403,10 @@ int ossl_qrl_enc_level_set_key_update_done(OSSL_QRL_ENC_LEVEL_SET *els,
{
OSSL_QRL_ENC_LEVEL *el = ossl_qrl_enc_level_set_get(els, enc_level, 0);
if (el == NULL || !ossl_assert(enc_level == QUIC_ENC_LEVEL_1RTT))
if (el == NULL || !ossl_assert(enc_level == QUIC_ENC_LEVEL_1RTT)) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
/* No new key yet, but erase key material to aid PFS. */
el_teardown_keyslot(els, enc_level, ~el->key_epoch & 1);
@ -397,15 +425,21 @@ int ossl_qrl_enc_level_set_key_cooldown_done(OSSL_QRL_ENC_LEVEL_SET *els,
size_t secret_len;
unsigned char new_ku[EVP_MAX_KEY_LENGTH];
if (el == NULL || !ossl_assert(enc_level == QUIC_ENC_LEVEL_1RTT))
if (el == NULL || !ossl_assert(enc_level == QUIC_ENC_LEVEL_1RTT)) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (el->state == QRL_EL_STATE_PROV_UPDATING
&& !ossl_qrl_enc_level_set_key_update_done(els, enc_level))
&& !ossl_qrl_enc_level_set_key_update_done(els, enc_level)) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
if (el->state != QRL_EL_STATE_PROV_COOLDOWN)
if (el->state != QRL_EL_STATE_PROV_COOLDOWN) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
secret_len = ossl_qrl_get_suite_secret_len(el->suite_id);
@ -420,7 +454,7 @@ int ossl_qrl_enc_level_set_key_cooldown_done(OSSL_QRL_ENC_LEVEL_SET *els,
quic_v1_ku_label,
sizeof(quic_v1_ku_label),
NULL, 0,
new_ku, secret_len, 0)) {
new_ku, secret_len, 1)) {
el_teardown_keyslot(els, enc_level, ~el->key_epoch & 1);
return 0;
}

View File

@ -480,15 +480,19 @@ static int qtx_encrypt_into_txe(OSSL_QTX *qtx, struct iovec_cur *cur, TXE *txe,
EVP_CIPHER_CTX *cctx = NULL;
/* We should not have been called if we do not have key material. */
if (!ossl_assert(el != NULL))
if (!ossl_assert(el != NULL)) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
/*
* Have we already encrypted the maximum number of packets using the current
* key?
*/
if (el->op_count >= ossl_qrl_get_suite_max_pkt(el->suite_id))
if (el->op_count >= ossl_qrl_get_suite_max_pkt(el->suite_id)) {
ERR_raise(ERR_LIB_SSL, SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED);
return 0;
}
/*
* TX key update is simpler than for RX; once we initiate a key update, we
@ -496,25 +500,33 @@ static int qtx_encrypt_into_txe(OSSL_QTX *qtx, struct iovec_cur *cur, TXE *txe,
* keys. Thus the EL always uses keyslot 0 for the TX side.
*/
cctx = el->cctx[0];
if (!ossl_assert(cctx != NULL))
if (!ossl_assert(cctx != NULL)) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
/* Construct nonce (nonce=IV ^ PN). */
nonce_len = EVP_CIPHER_CTX_get_iv_length(cctx);
if (!ossl_assert(nonce_len >= (int)sizeof(QUIC_PN)))
if (!ossl_assert(nonce_len >= (int)sizeof(QUIC_PN))) {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
memcpy(nonce, el->iv[0], (size_t)nonce_len);
for (i = 0; i < sizeof(QUIC_PN); ++i)
nonce[nonce_len - i - 1] ^= (unsigned char)(pn >> (i * 8));
/* type and key will already have been setup; feed the IV. */
if (EVP_CipherInit_ex(cctx, NULL, NULL, NULL, nonce, /*enc=*/1) != 1)
if (EVP_CipherInit_ex(cctx, NULL, NULL, NULL, nonce, /*enc=*/1) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
/* Feed AAD data. */
if (EVP_CipherUpdate(cctx, NULL, &l, hdr, hdr_len) != 1)
if (EVP_CipherUpdate(cctx, NULL, &l, hdr, hdr_len) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
/* Encrypt plaintext directly into TXE. */
for (;;) {
@ -526,20 +538,26 @@ static int qtx_encrypt_into_txe(OSSL_QTX *qtx, struct iovec_cur *cur, TXE *txe,
break;
if (EVP_CipherUpdate(cctx, txe_data(txe) + txe->data_len,
&l, src, src_len) != 1)
&l, src, src_len) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
assert(l > 0 && src_len == (size_t)l);
txe->data_len += src_len;
}
/* Finalise and get tag. */
if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1)
if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG,
el->tag_len, txe_data(txe) + txe->data_len) != 1)
el->tag_len, txe_data(txe) + txe->data_len) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
txe->data_len += el->tag_len;

View File

@ -117,7 +117,7 @@ int ossl_quic_provide_initial_secret(OSSL_LIB_CTX *libctx,
sizeof(quic_client_in_label),
NULL, 0,
client_initial_secret,
sizeof(client_initial_secret), 0))
sizeof(client_initial_secret), 1))
goto err;
/* Derive "server in" secret. */
@ -130,7 +130,7 @@ int ossl_quic_provide_initial_secret(OSSL_LIB_CTX *libctx,
sizeof(quic_server_in_label),
NULL, 0,
server_initial_secret,
sizeof(server_initial_secret), 0))
sizeof(server_initial_secret), 1))
goto err;
/* Setup RX EL. Initial encryption always uses AES-128-GCM. */

View File

@ -7,6 +7,7 @@
* https://www.openssl.org/source/license.html
*/
#include <openssl/err.h>
#include "internal/common.h"
#include "internal/quic_wire_pkt.h"
@ -30,21 +31,28 @@ int ossl_quic_hdr_protector_init(QUIC_HDR_PROTECTOR *hpr,
cipher_name = "ChaCha20";
break;
default:
ERR_raise(ERR_LIB_SSL, ERR_R_UNSUPPORTED);
return 0;
}
hpr->cipher_ctx = EVP_CIPHER_CTX_new();
if (hpr->cipher_ctx == NULL)
if (hpr->cipher_ctx == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
hpr->cipher = EVP_CIPHER_fetch(libctx, cipher_name, propq);
if (hpr->cipher == NULL
|| quic_hp_key_len != (size_t)EVP_CIPHER_get_key_length(hpr->cipher))
|| quic_hp_key_len != (size_t)EVP_CIPHER_get_key_length(hpr->cipher)) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
if (!EVP_CipherInit_ex(hpr->cipher_ctx, hpr->cipher, NULL,
quic_hp_key, NULL, 1))
quic_hp_key, NULL, 1)) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
hpr->libctx = libctx;
hpr->propq = propq;
@ -76,24 +84,33 @@ static int hdr_generate_mask(QUIC_HDR_PROTECTOR *hpr,
if (hpr->cipher_id == QUIC_HDR_PROT_CIPHER_AES_128
|| hpr->cipher_id == QUIC_HDR_PROT_CIPHER_AES_256) {
if (sample_len < 16)
if (sample_len < 16) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (!EVP_CipherInit_ex(hpr->cipher_ctx, NULL, NULL, NULL, NULL, 1)
|| !EVP_CipherUpdate(hpr->cipher_ctx, dst, &l, sample, 16))
|| !EVP_CipherUpdate(hpr->cipher_ctx, dst, &l, sample, 16)) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
for (i = 0; i < 5; ++i)
mask[i] = dst[i];
} else if (hpr->cipher_id == QUIC_HDR_PROT_CIPHER_CHACHA) {
if (sample_len < 16)
if (sample_len < 16) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
if (!EVP_CipherInit_ex(hpr->cipher_ctx, NULL, NULL, NULL, sample, 1)
|| !EVP_CipherUpdate(hpr->cipher_ctx, mask, &l,
zeroes, sizeof(zeroes)))
zeroes, sizeof(zeroes))) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
} else {
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
assert(0);
return 0;
}
@ -822,8 +839,10 @@ int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
|| hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN
|| hdr->data == NULL
|| client_initial_dcid == NULL || tag == NULL
|| client_initial_dcid->id_len > QUIC_MAX_CONN_ID_LEN)
|| client_initial_dcid->id_len > QUIC_MAX_CONN_ID_LEN) {
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
goto err;
}
/*
* Do not reserve packet body in WPACKET. Retry packet header
@ -834,54 +853,74 @@ int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
hdr2.len = 0;
/* Assemble retry psuedo-packet. */
if (!WPACKET_init_static_len(&wpkt, buf, sizeof(buf), 0))
if (!WPACKET_init_static_len(&wpkt, buf, sizeof(buf), 0)) {
ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
goto err;
}
wpkt_valid = 1;
/* Prepend original DCID to the packet. */
if (!WPACKET_put_bytes_u8(&wpkt, client_initial_dcid->id_len)
|| !WPACKET_memcpy(&wpkt, client_initial_dcid->id,
client_initial_dcid->id_len))
client_initial_dcid->id_len)) {
ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
goto err;
}
/* Encode main retry header. */
if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, hdr2.dst_conn_id.id_len,
&hdr2, NULL))
goto err;
if (!WPACKET_get_total_written(&wpkt, &hdr_enc_len))
if (!WPACKET_get_total_written(&wpkt, &hdr_enc_len)) {
ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);
return 0;
}
/* Create and initialise cipher context. */
/* TODO(QUIC FUTURE): Cipher fetch caching. */
if ((cipher = EVP_CIPHER_fetch(libctx, "AES-128-GCM", propq)) == NULL)
if ((cipher = EVP_CIPHER_fetch(libctx, "AES-128-GCM", propq)) == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
if ((cctx = EVP_CIPHER_CTX_new()) == NULL)
if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
if (!EVP_CipherInit_ex(cctx, cipher, NULL,
retry_integrity_key, retry_integrity_nonce, /*enc=*/1))
retry_integrity_key, retry_integrity_nonce, /*enc=*/1)) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
goto err;
}
/* Feed packet header as AAD data. */
if (EVP_CipherUpdate(cctx, NULL, &l, buf, hdr_enc_len) != 1)
if (EVP_CipherUpdate(cctx, NULL, &l, buf, hdr_enc_len) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
/* Feed packet body as AAD data. */
if (EVP_CipherUpdate(cctx, NULL, &l, hdr->data,
hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) != 1)
hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
/* Finalise and get tag. */
if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1)
if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG,
QUIC_RETRY_INTEGRITY_TAG_LEN,
tag) != 1)
tag) != 1) {
ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);
return 0;
}
ok = 1;
err:

View File

@ -244,6 +244,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_BUG), "library bug"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_HAS_NO_CIPHERS),
"library has no ciphers"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED),
"maximum encrypted pkts reached"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DSA_SIGNING_CERT),
"missing dsa signing cert"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDSA_SIGNING_CERT),