Skip to content

Commit

Permalink
update: disable non AEAD algorithms by default and introduce T_COSE_O…
Browse files Browse the repository at this point in the history
…PT_ENABLE_NON_AEAD to avoid unintentional use of them
  • Loading branch information
kentakayama committed Jul 28, 2024
1 parent 1eeef3b commit f271a5d
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 26 deletions.
13 changes: 13 additions & 0 deletions inc/t_cose/t_cose_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,19 @@ 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.
* By default, the error \ref T_COSE_ERR_UNSUPPORTED_ENCRYPTION_ALG
* is returned if non AEAD content encryption algorithms, such as
* AES-CTR and AES-CBC, are used.
* The sender and recipient can use them only with this option flag.
* The sender MUST use AES-CTR in conjunction with an authentication
* and integrity mechanism, such as a digital signature.
* The recipient MUST validate data authenticity and integrity.
*/
#define T_COSE_OPT_ENABLE_NON_AEAD 0x00002000


/**
* \brief Check whether an algorithm is supported.
Expand Down
10 changes: 10 additions & 0 deletions inc/t_cose/t_cose_encrypt_dec.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,16 @@ struct t_cose_encrypt_dec_ctx {
* explicitly set the CEK, but it rarely needed as the CEK is
* generated automatocally from the random number generator when
* it is not set.
*
* By default, the t_cose_encrypt_dec() decrypts COSE encrypted message
* only with AEAD content encryption algorithms, and returns
* \ref T_COSE_ERR_UNSUPPORTED_ENCRYPTION_ALG with non AEAD ones.
* If \c option_flags includes \ref T_COSE_OPT_ENABLE_NON_AEAD the function
* will also decrypt with non-AEAD ciphers.
* WARNING: Do not use this flag without considerations, because non-AEAD
* content encryption algorithms does NOT validate neither authentication
* nor integrity, it is library caller's responsibility to check them.
* See security considerations of RFC 9459.
*/
static void
t_cose_encrypt_dec_init(struct t_cose_encrypt_dec_ctx *context,
Expand Down
12 changes: 12 additions & 0 deletions inc/t_cose/t_cose_encrypt_enc.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,18 @@ struct t_cose_encrypt_enc {
* t_cose_recipient_enc being used. You can even have serveral with
* different algorithms (but there can only be one payload encryption
* algorithm).
*
* By default, the t_cose_encrypt_enc() encrypts a message
* only with AEAD content encryption algorithms, and returns
* \ref T_COSE_ERR_UNSUPPORTED_ENCRYPTION_ALG with non AEAD ones.
* If \c option_flags includes \ref T_COSE_OPT_ENABLE_NON_AEAD the function
* will also encrypt with non-AEAD ciphers.
* WARNING: Do not use this flag without considerations, because non-AEAD
* content encryption algorithms does NOT provide neither authentication
* nor integrity, it is library caller's responsibility to deliver the
* COSE message in conjunction with an authentication and integrity
* mechanism, such as a digital signature.
* See security considerations of RFC 9459.
*/
void
t_cose_encypt_enc_init(struct t_cose_encrypt_enc *context,
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_UNSUPPORTED_ENCRYPTION_ALG;
}
/* 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_UNSUPPORTED_ENCRYPTION_ALG;
}
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_UNSUPPORTED_ENCRYPTION_ALG && 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_UNSUPPORTED_ENCRYPTION_ALG && 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

0 comments on commit f271a5d

Please sign in to comment.