diff --git a/.cirrus.yml b/.cirrus.yml index d4208ba..3b35df2 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -19,7 +19,7 @@ build_task: MBEDTLS_LIB: /usr/lib/x86_64-linux-gnu/libmbedcrypto.so install_script: - apt update - - apt install -y libgcc-6-dev build-essential pkg-config libcunit1-dev wget libsodium-dev libmbedtls-dev ca-certificates + - apt install -y libgcc-8-dev build-essential pkg-config libcunit1-dev wget libsodium-dev libmbedtls-dev ca-certificates - git clone https://github.com/intel/tinycbor/ ../tinycbor - bash -c "cd ../tinycbor && make -j" - git clone https://github.com/bergzand/nanocbor/ ../nanocbor @@ -69,6 +69,11 @@ build_task: - apt install -y unzip - wget https://www.dlbeer.co.nz/downloads/c25519-2017-10-05.zip -O ../c25519.zip - bash -c 'cd .. && unzip c25519.zip' + - name: tinydtls + env: + CRYPTO: tinydtls + crypto_script: + - git clone https://github.com/eclipse/tinydtls.git ../tinydtls -b develop test_script: - ls -al - pwd diff --git a/Makefile b/Makefile index 1e95084..879d2dd 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,9 @@ endif ifneq (,$(filter c25519,$(CRYPTO))) include $(MK_DIR)/c25519.mk endif +ifneq (,$(filter tinydtls,$(CRYPTO))) + include $(MK_DIR)/tinydtls.mk +endif CFLAGS += $(CFLAGS_CRYPTO) diff --git a/include/cose/crypto.h b/include/cose/crypto.h index 158d024..5878234 100644 --- a/include/cose/crypto.h +++ b/include/cose/crypto.h @@ -44,6 +44,9 @@ #if defined(CRYPTO_HACL) #include "cose/crypto/hacl.h" #endif +#if defined(CRYPTO_TINYDTLS) +#include "cose/crypto/tinydtls.h" +#endif #ifdef __cplusplus extern "C" { @@ -150,6 +153,9 @@ extern "C" { #define COSE_CRYPTO_AEAD_AES256GCM_NONCEBYTES COSE_CRYPTO_AEAD_AESGCM_NONCEBYTES #define COSE_CRYPTO_AEAD_AES256GCM_ABYTES COSE_CRYPTO_AEAD_AESGCM_ABYTES +#define COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES 16 +#define COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES 8 +#define COSE_CRYPTO_AEAD_AESCCM_16_64_128_NONCEBYTES 13 /** @} */ @@ -233,6 +239,26 @@ int cose_crypto_aead_decrypt_aesgcm(uint8_t *msg, const uint8_t *k, size_t keysize); +int cose_crypto_aead_encrypt_aesccm(uint8_t *c, + size_t *clen, + const uint8_t *msg, + size_t msglen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize); + +int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, + size_t *msglen, + const uint8_t *c, + size_t clen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize); + /** * Generate a symmetric key for AEAD operations */ diff --git a/include/cose/crypto/tinydtls.h b/include/cose/crypto/tinydtls.h new file mode 100644 index 0000000..92da23a --- /dev/null +++ b/include/cose/crypto/tinydtls.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 Freie Universitat Berlin + * Copyright (C) 2018 Inria + * Copyright (C) 2020 Christian Amsüss and Ericsson AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @defgroup cose_cryto_tinydtls Crypto glue layer, tinydtls definitions + * @ingroup cose_crypto + * + * Crypto function api for glueing tinydtls' AEAD functions. + * @{ + * + * @file + * @brief Crypto function api for glueing tinydtls. + * + * @author Christian Amsüss + */ + +#ifndef COSE_CRYPTO_TINYDTLS_H +#define COSE_CRYPTO_TINYDTLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name list of provided algorithms + * + * @{ + */ +#define HAVE_ALGO_AESCCM_16_64_128 /**< AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce */ +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif + +/** @} */ diff --git a/include/cose_defines.h b/include/cose_defines.h index 84ff534..f226cc4 100644 --- a/include/cose_defines.h +++ b/include/cose_defines.h @@ -160,6 +160,7 @@ typedef enum { COSE_ALGO_A128GCM = 1, /**< AES-GCM mode w/ 128-bit key, 128-bit tag */ COSE_ALGO_A192GCM = 2, /**< AES-GCM mode w/ 192-bit key, 128-bit tag */ COSE_ALGO_A256GCM = 3, /**< AES-GCM mode w/ 256-bit key, 128-bit tag */ + COSE_ALGO_AESCCM_16_64_128 = 10, /**< AES-CCM mode 128-bit key, 64-bit tag, 13-byte nonce */ COSE_ALGO_CHACHA20POLY1305 = 24, /**< IETF ChaCha20/Poly1305 w/ 256-bit key, 128-bit tag */ } cose_algo_t; diff --git a/makefiles/tinydtls.mk b/makefiles/tinydtls.mk new file mode 100644 index 0000000..8401ff9 --- /dev/null +++ b/makefiles/tinydtls.mk @@ -0,0 +1,14 @@ +TINYDTLS_DIR ?= ../tinydtls +TINYDTLS_CONFIGDIR ?= makefiles/tinydtls_config/ +CFLAGS += -DCRYPTO_TINYDTLS +CRYPTOSRC += $(SRC_DIR)/crypt/tinydtls.c +CFLAGS_CRYPTO += -I$(TINYDTLS_DIR) +CFLAGS_CRYPTO += -I$(TINYDTLS_CONFIGDIR) +CRYPTOOBJS += $(TINYDTLS_DIR)/crypto.o +CRYPTOOBJS += $(TINYDTLS_DIR)/aes/rijndael.o +CRYPTOOBJS += $(TINYDTLS_DIR)/aes/rijndael_wrap.o +CRYPTOOBJS += $(TINYDTLS_DIR)/hmac.o +CRYPTOOBJS += $(TINYDTLS_DIR)/ccm.o +CRYPTOOBJS += $(TINYDTLS_DIR)/sha2/sha2.o +CRYPTOOBJS += $(TINYDTLS_DIR)/netq.o +$(CRYPTOOBJS): CFLAGS += -Wno-gnu-zero-variadic-macro-arguments -Wno-unused-function diff --git a/makefiles/tinydtls_config/dtls_config.h b/makefiles/tinydtls_config/dtls_config.h new file mode 100644 index 0000000..d6e8e53 --- /dev/null +++ b/makefiles/tinydtls_config/dtls_config.h @@ -0,0 +1,10 @@ +/* Not that we'd need *that* code, but if neither ECC nro PSK is defined, + * there's empty unions and such (and newer verisons of the library complain + * more explicitly) */ +#define DTLS_PSK + +/* Similarly, without a SHA algorithm, there's unused variables and such */ +#define WITH_SHA256 + +/* Without, we get a #warning that is escalated to an #error by -Werror */ +#define HAVE_ASSERT_H diff --git a/src/cose_crypto.c b/src/cose_crypto.c index 5f67eb4..a6331f2 100644 --- a/src/cose_crypto.c +++ b/src/cose_crypto.c @@ -49,6 +49,10 @@ bool cose_crypto_is_aead(cose_algo_t algo) switch(algo) { case COSE_ALGO_CHACHA20POLY1305: return true; +#ifdef HAVE_ALGO_AESCCM_16_64_128 + case COSE_ALGO_AESCCM_16_64_128: + return true; +#endif default: return false; } @@ -82,6 +86,10 @@ int cose_crypto_aead_encrypt(uint8_t *c, /* NOLINT(readability-non-const-parame #ifdef HAVE_ALGO_AES128GCM case COSE_ALGO_A128GCM: return cose_crypto_aead_encrypt_aesgcm(c, clen, msg, msglen, aad, aadlen, npub, key, COSE_CRYPTO_AEAD_AES128GCM_KEYBYTES); +#endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 + case COSE_ALGO_AESCCM_16_64_128: + return cose_crypto_aead_encrypt_aesccm(c, clen, msg, msglen, aad, aadlen, npub, key, COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES); #endif default: (void)c; @@ -124,6 +132,10 @@ int cose_crypto_aead_decrypt(uint8_t *msg, /* NOLINT(readability-non-const-param #ifdef HAVE_ALGO_AES128GCM case COSE_ALGO_A128GCM: return cose_crypto_aead_decrypt_aesgcm(msg, msglen, c, clen, aad, aadlen, npub, k, COSE_CRYPTO_AEAD_AES128GCM_KEYBYTES); +#endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 + case COSE_ALGO_AESCCM_16_64_128: + return cose_crypto_aead_decrypt_aesccm(msg, msglen, c, clen, aad, aadlen, npub, k, COSE_CRYPTO_AEAD_AESCCM_16_64_128_KEYBYTES); #endif default: (void)c; @@ -169,6 +181,11 @@ int cose_crypto_sign(const cose_key_t *key, uint8_t *sign, size_t *signlen, uint break; #endif default: + (void)key; + (void)sign; + (void)signlen; + (void)msg; + (void)msglen; return COSE_ERR_NOTIMPLEMENTED; } return 0; @@ -192,6 +209,11 @@ int cose_crypto_verify(const cose_key_t *key, const uint8_t *sign, size_t signle break; #endif default: + (void)key; + (void)sign; + (void)signlen; + (void)msg; + (void)msglen; return COSE_ERR_NOTIMPLEMENTED; } return 0; diff --git a/src/crypt/tinydtls.c b/src/crypt/tinydtls.c new file mode 100644 index 0000000..2800d85 --- /dev/null +++ b/src/crypt/tinydtls.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2020 Christian Amsüss and Ericsson AB + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * Glue layer between libcose and tinydtls + */ + +#include "cose.h" +#include "cose/crypto.h" + +#include /* tinydtls', that is */ + +int cose_crypto_aead_encrypt_aesccm(uint8_t *c, + size_t *clen, + const uint8_t *msg, + size_t msglen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize) +{ + const dtls_ccm_params_t params = { npub, 8, 2 }; + int ret = dtls_encrypt_params(¶ms, msg, msglen, c, (uint8_t*)k, keysize, aad, aadlen); + if (ret >= 0 && (size_t)ret == msglen + COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { + *clen = ret; + return COSE_OK; + } else { + return COSE_ERR_CRYPTO; + } +} + +int cose_crypto_aead_decrypt_aesccm(uint8_t *msg, + size_t *msglen, + const uint8_t *c, + size_t clen, + const uint8_t *aad, + size_t aadlen, + const uint8_t *npub, + const uint8_t *k, + size_t keysize) +{ + const dtls_ccm_params_t params = { npub, 8, 2 }; + int ret = dtls_decrypt_params(¶ms, c, clen, msg, (uint8_t*)k, keysize, aad, aadlen); + if (ret >= 0 && (size_t)ret == clen - COSE_CRYPTO_AEAD_AESCCM_16_64_128_ABYTES) { + *msglen = ret; + return COSE_OK; + } else { + return COSE_ERR_CRYPTO; + } +} diff --git a/tests/crypto.c b/tests/crypto.c index 601f373..6d192c8 100644 --- a/tests/crypto.c +++ b/tests/crypto.c @@ -186,6 +186,75 @@ void test_crypto_aes256(void) } #endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 +/* Values from https://www.rfc-editor.org/rfc/rfc3610.html#section-8 */ +static const uint8_t aesccm1_key[16] = { + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, +}; + +static const uint8_t aesccm1_nonce[13] = { + 0x00, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, +}; + +static const uint8_t aesccm1_input[31] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e +}; + +static const uint8_t aesccm1_output[39] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x58, 0x8c, 0x97, 0x9a, + 0x61, 0xc6, 0x63, 0xd2, 0xf0, 0x66, 0xd0, 0xc2, 0xc0, 0xf9, 0x89, 0x80, + 0x6d, 0x5f, 0x6b, 0x61, 0xda, 0xc3, 0x84, 0x17, 0xe8, 0xd1, 0x2c, 0xfd, + 0xf9, 0x26, 0xe0, +}; + +/* The input and output packets in the RFC's test vectors are shown in + * concatenated form AAD || cleartext and AAD || ciphertext || tag, + * respectively; this plucks them apart. */ + +static const uint8_t *aesccm1_aad = &aesccm1_input[0]; +#define AESCCM1_AAD_LEN 8 + +static const uint8_t *aesccm1_plaintext = &aesccm1_input[AESCCM1_AAD_LEN]; +#define AESCCM1_PLAINTEXT_LEN (sizeof(aesccm1_input) - AESCCM1_AAD_LEN) + +static const uint8_t *aesccm1_ciphertext = &aesccm1_output[AESCCM1_AAD_LEN]; +#define AESCCM1_CIPHERTEXT_LEN (sizeof(aesccm1_output) - AESCCM1_AAD_LEN) + +void test_crypto_aesccm_vector(void) +{ + unsigned char ciphertext[AESCCM1_CIPHERTEXT_LEN]; + unsigned char plaintext[AESCCM1_PLAINTEXT_LEN]; + + size_t cipherlen = 0; + size_t msglen = 0; + /* Generate key */ + cose_crypto_aead_encrypt( + ciphertext, &cipherlen, + aesccm1_plaintext, AESCCM1_PLAINTEXT_LEN, + aesccm1_aad, AESCCM1_AAD_LEN, + NULL, aesccm1_nonce, + aesccm1_key, + COSE_ALGO_AESCCM_16_64_128 + ); + CU_ASSERT_EQUAL(AESCCM1_CIPHERTEXT_LEN, cipherlen); + CU_ASSERT_EQUAL(memcmp(ciphertext, aesccm1_ciphertext, AESCCM1_CIPHERTEXT_LEN), 0); + CU_ASSERT_EQUAL( + cose_crypto_aead_decrypt( + plaintext, &msglen, + ciphertext, cipherlen, + aesccm1_aad, AESCCM1_AAD_LEN, + aesccm1_nonce, + aesccm1_key, + COSE_ALGO_AESCCM_16_64_128 + ), + 0 ); + CU_ASSERT_EQUAL(msglen, AESCCM1_PLAINTEXT_LEN); + CU_ASSERT_EQUAL(memcmp(aesccm1_plaintext, plaintext, AESCCM1_PLAINTEXT_LEN), 0); +} +#endif + const test_t tests_crypto[] = { #ifdef HAVE_ALGO_EDDSA { @@ -220,6 +289,12 @@ const test_t tests_crypto[] = { .f = test_crypto_aes256, .n = "AEAD aes256gcm encrypt/decrypt", }, +#endif +#ifdef HAVE_ALGO_AESCCM_16_64_128 + { + .f = test_crypto_aesccm_vector, + .n = "AEAD Chacha20poly1305 encrypt/decrypt with IETF test vector", + }, #endif { .f = NULL, diff --git a/tests/sign.c b/tests/sign.c index 597d4d4..beece81 100644 --- a/tests/sign.c +++ b/tests/sign.c @@ -20,9 +20,6 @@ #include "CUnit/Basic.h" #include "CUnit/Automated.h" -static char kid[] = "koen@example.org"; -static char kid2[] = "koen@example.net"; - #ifdef HAVE_ALGO_EDDSA #define TEST_CRYPTO_SIGN_PUBLICKEYBYTES COSE_CRYPTO_SIGN_ED25519_PUBLICKEYBYTES #define TEST_CRYPTO_SIGN_SECRETKEYBYTES COSE_CRYPTO_SIGN_ED25519_SECRETKEYBYTES @@ -31,6 +28,11 @@ static char kid2[] = "koen@example.net"; #define TEST_CRYPTO_SIGN_SECRETKEYBYTES COSE_CRYPTO_SIGN_P521_SECRETKEYBYTES #endif +#if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) + +static char kid[] = "koen@example.org"; +static char kid2[] = "koen@example.net"; + static unsigned char pkx1[TEST_CRYPTO_SIGN_PUBLICKEYBYTES]; static unsigned char pky1[TEST_CRYPTO_SIGN_PUBLICKEYBYTES]; static unsigned char sk1[TEST_CRYPTO_SIGN_SECRETKEYBYTES]; @@ -486,8 +488,10 @@ void test_sign8(void) verification = cose_sign_verify(&verify, &vsignature, &key, ver_buf, sizeof(ver_buf)); CU_ASSERT_NOT_EQUAL(verification, COSE_OK); } +#endif const test_t tests_sign[] = { +#if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) { .f = test_sign1, .n = "Sign with 1 sig", @@ -520,6 +524,7 @@ const test_t tests_sign[] = { .f = test_sign8, .n = "Sign with aad test", }, +#endif { .f = NULL, .n = NULL, diff --git a/tests/suit.c b/tests/suit.c index c5da4cf..5f3e567 100644 --- a/tests/suit.c +++ b/tests/suit.c @@ -20,8 +20,6 @@ #include "CUnit/Basic.h" #include "CUnit/Automated.h" -static uint8_t buf[2048]; - #ifdef HAVE_ALGO_EDDSA static const unsigned char cose_suit[] = { 0xd8, 0x62, 0x84, 0x44, 0xa1, 0x03, 0x18, 0x2a, 0xa0, 0x58, 0xcd, 0x8a, @@ -115,9 +113,12 @@ static unsigned char pk_y[COSE_CRYPTO_SIGN_P521_PUBLICKEYBYTES] = { #define COSE_ALGO COSE_ALGO_ES256 #define COSE_CURVE COSE_EC_CURVE_P256 - #endif +#if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA) + +static uint8_t buf[2048]; + static const uint8_t keyid[] = "Something@somewhere"; static void print_bytestr(const uint8_t *bytes, size_t len) @@ -159,6 +160,7 @@ void test_suit1(void) CU_ASSERT(res); CU_ASSERT_EQUAL(memcmp(kid, keyid, sizeof(keyid) - 1), 0); } +#endif const test_t tests_suit[] = { #if defined(HAVE_ALGO_EDDSA) || defined(HAVE_ALGO_ECDSA)