From fa33eacd1f259bb8a4a04aba5ba0f9b061e413af Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ga=C3=ABtan=20Harter?= <gaetan.harter@fu-berlin.de>
Date: Mon, 20 Nov 2017 14:32:33 +0100
Subject: [PATCH] crypto/ccm: fix _fits_in_nbytes function

Function is broken with num_bytes >= 4.

Could happen when storing input_len with len_encoding >= 4.
It can take values from 2 to 8, so make it work for cases it would overflow.
---
 sys/crypto/modes/ccm.c                        |  7 +++++--
 .../tests-crypto/tests-crypto-modes-ccm.c     | 20 +++++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/sys/crypto/modes/ccm.c b/sys/crypto/modes/ccm.c
index 0442e8abe1..0df28fa4bd 100644
--- a/sys/crypto/modes/ccm.c
+++ b/sys/crypto/modes/ccm.c
@@ -132,8 +132,11 @@ int ccm_compute_adata_mac(cipher_t* cipher, uint8_t* auth_data,
 /* Check if 'value' can be stored in 'num_bytes' */
 static inline int _fits_in_nbytes(size_t value, uint8_t num_bytes)
 {
-    uint32_t length_max = 1 << (8 * num_bytes);
-    return value < length_max;
+    /* Not allowed to shift more or equal than left operand width
+     * So we shift by maximum num bits of size_t -1 and compare to 1
+     */
+    unsigned shift = (8 * min(sizeof(size_t), num_bytes)) - 1;
+    return (value >> shift) <= 1;
 }
 
 
diff --git a/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c b/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c
index 81f1d7d654..1fe20e7972 100644
--- a/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c
+++ b/tests/unittests/tests-crypto/tests-crypto-modes-ccm.c
@@ -226,6 +226,26 @@ static void test_crypto_modes_ccm_check_len(void)
     TEST_ASSERT_EQUAL_INT(CCM_ERR_INVALID_LENGTH_ENCODING, ret);
     ret = _test_ccm_len(cipher_decrypt_ccm, 2, NULL, 1 << 16, 65535);
     TEST_ASSERT_EQUAL_INT(CCM_ERR_INVALID_LENGTH_ENCODING, ret);
+
+    /* Valid length that were wrongly checked */
+    /* Check should work with len_encoding >= 4, test with 8 */
+    uint8_t input[8];
+    ret = _test_ccm_len(cipher_encrypt_ccm, 8, input, 8, 0);
+    TEST_ASSERT_MESSAGE(ret > 0, "Encryption : failed with valid input_len");
+
+    /* einput is encrypted value for
+     * - 8 * 0 input
+     * - All 0 nonce and key
+     * - adata_len == 0
+     * - mac_len == 8 and len_encoding = 8
+     */
+    uint8_t einput[16] = {
+        0xa2, 0x46, 0x75, 0xfc, 0x5f, 0x1b, 0x01, 0x37,
+        0x8a, 0x85, 0xd7, 0xf8, 0x42, 0x82, 0x6a, 0x63,
+    };
+
+    ret = _test_ccm_len(cipher_decrypt_ccm, 8, einput, 16, 0);
+    TEST_ASSERT_MESSAGE(ret > 0, "Decryption : failed with valid input_len");
 }
 
 
-- 
GitLab