Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce T_COSE_OPT_ENABLE_NON_AEAD #284

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions inc/t_cose/t_cose_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,10 @@ enum t_cose_err_t {
/** An initialization vector (IV) is empty, wrong type or such. */
T_COSE_ERR_BAD_IV = 92,

/** Disabled non AEAD content encryption algorithms are used.
* They are disabled by default for security reasons.
* See \ref T_COSE_OPT_ENABLE_NON_AEAD if you are sure to use them. */
T_COSE_ERR_NON_AEAD_DISABLED = 93,
};


Expand Down Expand Up @@ -791,6 +795,21 @@ enum t_cose_err_t {
*/
#define T_COSE_OPT_REQUIRE_KID 0x00001000

/**
* WARNING: DO NOT use this option flag without understanding the
* security consideration of RFC 9459 and AEAD to CBC Downgrade
* Attacks proposed in https://eprint.iacr.org/2024/1110.pdf .
* By default, non AEAD content encryption algorithms are disabled
* for security reasons, so that the encryption and decryption functions
* return error \ref T_COSE_ERR_NON_AEAD_DISABLED when they are used.
* They are enabled only this option flag is set on
* \ref t_cose_encrypt_enc_init and \ref t_cose_encrypt_dec_init .
*
* TODO: Warn COSE_Encrypt lacking authentication and integrity in one place,
* and refer it from here.
*/
#define T_COSE_OPT_ENABLE_NON_AEAD 0x00002000


/**
* \brief Check whether an algorithm is supported.
Expand Down
4 changes: 4 additions & 0 deletions src/t_cose_encrypt_dec.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ t_cose_encrypt_dec_detached(struct t_cose_encrypt_dec_ctx* me,
return T_COSE_ERR_NO_ALG_ID;
}
if(t_cose_alg_is_non_aead(ce_alg.cose_alg_id)) {
/* Make sure that the library caller (recipient) explicitly enables non AEAD ciphers*/
if(!(me->option_flags & T_COSE_OPT_ENABLE_NON_AEAD)) {
return T_COSE_ERR_NON_AEAD_DISABLED;
}
/* Make sure there are no protected headers for non-aead algorithms */
if(!t_cose_params_empty(protected_params)) {
return T_COSE_ERR_PROTECTED_NOT_ALLOWED;
Expand Down
8 changes: 8 additions & 0 deletions src/t_cose_encrypt_enc.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ t_cose_encrypt_enc_detached(struct t_cose_encrypt_enc *me,
/* ---- Algorithm ID, IV and parameter list ---- */
/* Determine algorithm parameters */
is_non_aead_cipher = t_cose_alg_is_non_aead(me->payload_cose_algorithm_id);
if(is_non_aead_cipher && !(me->option_flags & T_COSE_OPT_ENABLE_NON_AEAD)) {
/* The libraty caller (sender) MUST explicitly enable non AEAD
* content encryption algorithms with \c T_COSE_OPT_ENABLE_NON_AEAD
* awaring that the COSE message MUST be in conjunction with an
* authentication and integrity mechanism, such as a digital signature.
*/
return T_COSE_ERR_NON_AEAD_DISABLED;
}
if(is_non_aead_cipher && !q_useful_buf_c_is_null_or_empty(ext_sup_data)) {
/* Section 6 of RFC9459 says,
* COSE libraries that support either AES-CTR or AES-CBC and
Expand Down
148 changes: 122 additions & 26 deletions test/t_cose_encrypt_decrypt_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,11 @@ check_headers(const struct t_cose_parameter *headers, bool is_non_aead)
}


int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
int32_t encrypt0_enc_dec(int32_t cose_algorithm_id, bool enable_non_aead_encryption, bool enable_non_aead_decryption)
{
struct t_cose_encrypt_enc enc_context;
uint32_t option_flags;
bool is_non_aead = false;
enum t_cose_err_t t_cose_err;
int32_t return_value;
struct t_cose_key cek;
Expand All @@ -143,19 +145,22 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
struct t_cose_parameter p_storage_array[10];

switch(cose_algorithm_id) {
case T_COSE_ALGORITHM_A128GCM:
case T_COSE_ALGORITHM_A128CTR:
case T_COSE_ALGORITHM_A128CBC:
is_non_aead = true;
case T_COSE_ALGORITHM_A128GCM:
cek_bytes = Q_USEFUL_BUF_FROM_SZ_LITERAL("128-bit key xxxx");
break;
case T_COSE_ALGORITHM_A192GCM:
case T_COSE_ALGORITHM_A192CTR:
case T_COSE_ALGORITHM_A192CBC:
is_non_aead = true;
case T_COSE_ALGORITHM_A192GCM:
cek_bytes = Q_USEFUL_BUF_FROM_SZ_LITERAL("192-bit key xxxxyyyyyyyy");
break;
case T_COSE_ALGORITHM_A256GCM:
case T_COSE_ALGORITHM_A256CTR:
case T_COSE_ALGORITHM_A256CBC:
is_non_aead = true;
case T_COSE_ALGORITHM_A256GCM:
cek_bytes = Q_USEFUL_BUF_FROM_SZ_LITERAL("256-bit key xxxxyyyyyyyyzzzzzzzz");
break;
case T_COSE_ALGORITHM_AES128CCM_16_128:
Expand All @@ -176,8 +181,12 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
goto Done2;
}

option_flags = T_COSE_OPT_MESSAGE_TYPE_ENCRYPT0;
if(enable_non_aead_encryption) {
option_flags |= T_COSE_OPT_ENABLE_NON_AEAD;
}
t_cose_encrypt_enc_init(&enc_context,
T_COSE_OPT_MESSAGE_TYPE_ENCRYPT0,
option_flags,
cose_algorithm_id);


Expand Down Expand Up @@ -206,13 +215,21 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
cose_message_buf,
&encrypted_cose_message);

if(t_cose_err) {
if(t_cose_err == T_COSE_ERR_NON_AEAD_DISABLED && is_non_aead && !enable_non_aead_encryption) {
/* t_cose could prevent unintended use of non AEAD ciphers */
return_value = 0;
goto Done;
}
else if(t_cose_err) {
return_value = 2000 + (int32_t)t_cose_err;
goto Done;
}


t_cose_encrypt_dec_init(&dec_ctx, T_COSE_OPT_MESSAGE_TYPE_ENCRYPT0);
option_flags = T_COSE_OPT_MESSAGE_TYPE_ENCRYPT0;
if(enable_non_aead_decryption) {
option_flags |= T_COSE_OPT_ENABLE_NON_AEAD;
}
t_cose_encrypt_dec_init(&dec_ctx, option_flags);

t_cose_encrypt_dec_set_cek(&dec_ctx, cek);

Expand All @@ -236,7 +253,12 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
decrypted_payload_buf,
&decrypted_payload,
&decoded_parameters);
if(t_cose_err) {
if(t_cose_err == T_COSE_ERR_NON_AEAD_DISABLED && is_non_aead && !enable_non_aead_decryption) {
/* t_cose could prevent unintended use of non AEAD ciphers */
return_value = 0;
goto Done;
}
else if(t_cose_err) {
return_value = 3000 + (int32_t)t_cose_err;
goto Done;
}
Expand All @@ -254,7 +276,7 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)

/* ---- test detached ----- */
t_cose_encrypt_enc_init(&enc_context,
T_COSE_OPT_MESSAGE_TYPE_ENCRYPT0,
option_flags,
cose_algorithm_id);
t_cose_encrypt_set_cek(&enc_context, cek);
t_cose_err = t_cose_encrypt_enc_detached(&enc_context,
Expand All @@ -269,7 +291,7 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
goto Done;
}

t_cose_encrypt_dec_init(&dec_ctx, T_COSE_OPT_MESSAGE_TYPE_ENCRYPT0);
t_cose_encrypt_dec_init(&dec_ctx, option_flags);
t_cose_encrypt_dec_set_cek(&dec_ctx, cek);
t_cose_err = t_cose_encrypt_dec_detached(&dec_ctx,
encrypted_cose_message,
Expand Down Expand Up @@ -301,61 +323,131 @@ int32_t encrypt0_enc_dec(int32_t cose_algorithm_id)
int32_t base_encrypt_decrypt_test(void)
{
int32_t rv;
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128GCM);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128GCM, false, false);
if(rv) {
return 10000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192GCM);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192GCM, false, false);
if(rv) {
return 20000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256GCM);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256GCM, false, false);
if(rv) {
return 30000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CTR);
/* Enable non-AEAD ciphers on both Sender and Recipient side.
* Success on both side are expected.
*/
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CTR, true, true);
if(rv) {
return 40000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CTR);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CTR, true, true);
if(rv) {
return 50000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CTR);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CTR, true, true);
if(rv) {
return 60000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CBC);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CBC, true, true);
if(rv) {
return 70000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CBC);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CBC, true, true);
if(rv) {
return 80000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CBC);
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CBC, true, true);
if(rv) {
return 90000 + rv;
}

/* Disable non-AEAD ciphers on both Sender and Recipient side.
* Failure and early return on Sender side is expected.
*/
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CTR, false, false);
if(rv) {
return 100000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CTR, false, false);
if(rv) {
return 110000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CTR, false, false);
if(rv) {
return 120000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CBC, false, false);
if(rv) {
return 130000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CBC, false, false);
if(rv) {
return 140000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CBC, false, false);
if(rv) {
return 150000 + rv;
}

/* Disable non-AEAD ciphers on only Recipient side.
* Failure and early return on Recipient side is expected.
*/
rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CTR, true, false);
if(rv) {
return 160000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CTR, true, false);
if(rv) {
return 170000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CTR, true, false);
if(rv) {
return 180000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A128CBC, true, false);
if(rv) {
return 190000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A192CBC, true, false);
if(rv) {
return 200000 + rv;
}

rv = encrypt0_enc_dec(T_COSE_ALGORITHM_A256CBC, true, false);
if(rv) {
return 210000 + rv;
}

return 0;

}


#ifndef T_COSE_DISABLE_KEYWRAP

int32_t decrypt_key_wrap(struct q_useful_buf_c cose_encrypt_buffer)
int32_t decrypt_key_wrap(struct q_useful_buf_c cose_encrypt_buffer, bool enable_non_aead)
{
enum t_cose_err_t result;
uint32_t option_flags;
int32_t return_value = 0;
struct t_cose_recipient_dec_keywrap kw_unwrap_recipient;
struct t_cose_encrypt_dec_ctx decrypt_context;
Expand All @@ -374,7 +466,11 @@ int32_t decrypt_key_wrap(struct q_useful_buf_c cose_encrypt_buffer)
goto Done2;
}

t_cose_encrypt_dec_init(&decrypt_context, T_COSE_OPT_MESSAGE_TYPE_ENCRYPT);
option_flags = T_COSE_OPT_MESSAGE_TYPE_ENCRYPT;
if(enable_non_aead) {
option_flags |= T_COSE_OPT_ENABLE_NON_AEAD;
}
t_cose_encrypt_dec_init(&decrypt_context, option_flags);
t_cose_recipient_dec_keywrap_init(&kw_unwrap_recipient);
t_cose_recipient_dec_keywrap_set_kek(&kw_unwrap_recipient, kek, NULL_Q_USEFUL_BUF_C);
t_cose_encrypt_dec_add_recipient(&decrypt_context, (struct t_cose_recipient_dec *)&kw_unwrap_recipient);
Expand Down Expand Up @@ -415,11 +511,11 @@ int32_t decrypt_known_good_aeskw_non_aead_test(void)
return INT32_MIN; /* Means no testing was actually done */
}

return_value = decrypt_key_wrap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(cose_encrypt_a128ctr_a128kw));
return_value = decrypt_key_wrap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(cose_encrypt_a128ctr_a128kw), true);
if(return_value != 0) {
return return_value + 10000;
}
return_value = decrypt_key_wrap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(cose_encrypt_a128cbc_a128kw));
return_value = decrypt_key_wrap(UsefulBuf_FROM_BYTE_ARRAY_LITERAL(cose_encrypt_a128cbc_a128kw), true);
if(return_value != 0) {
return return_value + 20000;
}
Expand Down Expand Up @@ -475,7 +571,7 @@ esdh_enc_dec(int32_t curve, int32_t payload_cose_algorithm_id)
* body of the message.
*/
t_cose_encrypt_enc_init(&enc_ctx,
T_COSE_OPT_MESSAGE_TYPE_ENCRYPT,
T_COSE_OPT_MESSAGE_TYPE_ENCRYPT | T_COSE_OPT_ENABLE_NON_AEAD,
payload_cose_algorithm_id);

/* Create the recipient object telling it the algorithm and the public key
Expand Down Expand Up @@ -507,7 +603,7 @@ esdh_enc_dec(int32_t curve, int32_t payload_cose_algorithm_id)
}


t_cose_encrypt_dec_init(&dec_ctx, 0);
t_cose_encrypt_dec_init(&dec_ctx, T_COSE_OPT_ENABLE_NON_AEAD);

t_cose_recipient_dec_esdh_init(&dec_recipient);

Expand Down
Loading