Message ID | 20190629211254.26577-1-laszlo@ashin.hu |
---|---|
State | Changes Requested |
Headers | show |
Series | Add mbedtls as an alternative SSL implementation | expand |
Hi Laszlo, I wanted to test your implementation, I got no time to do it. Anyway, I do not see any issue for the current code - I tend to merge this and try to win some testers. By merging I have a couple of issues regarding "test": First, if more "test" will be introduced, I do not think it is a good idea to share it into src. Currently, there is just one example ./suricatta/test. I will propose to move all tests in a separate directory in the root directory of the project ( test/). Why do we need to put into repo "public.pem" ? Can we generate it during the test ? I will suggest you split the patch as: - [1] changes to SWUpdate ==> I will apply this - [2] test environment ==> maybe there are some mor ecomments. Thanks, Stefano On 29/06/19 23:12, 'Laszlo Ashin' via swupdate wrote: > This patch enables using mbedtls as an alternative implementation > as opposed to openssl. CMS signatures are not supported. > > Signed-off-by: Laszlo Ashin <laszlo@ashin.hu> > --- > .travis.yml | 5 +- > Kconfig | 48 +++++++--- > Makefile.deps | 4 + > Makefile.flags | 29 +----- > configs/mbedtls_defconfig | 18 ++++ > corelib/Makefile | 12 ++- > corelib/swupdate_decrypt.c | 2 +- > corelib/swupdate_decrypt_mbedtls.c | 100 +++++++++++++++++++++ > corelib/swupdate_rsa_verify_mbedtls.c | 103 +++++++++++++++++++++ > corelib/test/Makefile | 6 +- > corelib/test/data/public.pem | 9 ++ > corelib/test/data/test_file_to_sign | 1 + > corelib/test/test_crypt.c | 4 +- > corelib/test/test_hash.c | 124 ++++++++++++++++++++++++++ > corelib/test/test_verify.c | 108 ++++++++++++++++++++++ > corelib/verify_signature.c | 4 +- > corelib/verify_signature_mbedtls.c | 106 ++++++++++++++++++++++ > include/sslapi.h | 32 ++++++- > include/util.h | 1 + > mongoose/Config.in | 3 +- > suricatta/Config.in | 3 +- > 21 files changed, 668 insertions(+), 54 deletions(-) > create mode 100644 configs/mbedtls_defconfig > create mode 100644 corelib/swupdate_decrypt_mbedtls.c > create mode 100644 corelib/swupdate_rsa_verify_mbedtls.c > create mode 100644 corelib/test/data/public.pem > create mode 100644 corelib/test/data/test_file_to_sign > create mode 100644 corelib/test/test_hash.c > create mode 100644 corelib/test/test_verify.c > create mode 100644 corelib/verify_signature_mbedtls.c > > diff --git a/.travis.yml b/.travis.yml > index 5979153..3015f79 100644 > --- a/.travis.yml > +++ b/.travis.yml > @@ -28,6 +28,8 @@ before_install: > - sudo apt-get install -y graphviz > - sudo apt-get install -y autoconf-archive > - sudo apt-get install -y linux-headers-$(uname -r) > + - sudo apt-get install -y libmbedtls-dev > + - sudo apt-get install -y libcmocka-dev > > script: > - sudo ln -sf /usr/lib/x86_64-linux-gnu/pkgconfig/lua5.2.pc /usr/lib/x86_64-linux-gnu/pkgconfig/lua.pc > @@ -74,4 +76,5 @@ script: > - make > - sudo make install > - cd .. > - - for i in configs/*;do echo $i;make `basename $i` && make || exit 1;done > + - sudo ldconfig > + - for i in configs/*;do echo $i;make `basename $i` && make || exit 1;make corelib-tests || exit 1;done > diff --git a/Kconfig b/Kconfig > index b652d84..1449914 100644 > --- a/Kconfig > +++ b/Kconfig > @@ -69,6 +69,10 @@ config HAVE_LIBCRYPTO > bool > option env="HAVE_LIBCRYPTO" > > +config HAVE_MBEDTLS > + bool > + option env="HAVE_MBEDTLS" > + > config HAVE_JSON_C > bool > option env="HAVE_JSON_C" > @@ -313,6 +317,25 @@ endmenu > source bootloader/Config.in > > > +choice > + prompt "SSL implementation to use" > + default SSL_IMPL_OPENSSL > + help > + Select SSL implementation for hashing, verifying and decrypting images. > + > + config SSL_IMPL_NONE > + bool "None" > + > + config SSL_IMPL_OPENSSL > + bool "OpenSSL" > + depends on HAVE_LIBSSL > + > + config SSL_IMPL_MBEDTLS > + bool "mbedTLS" > + depends on HAVE_MBEDTLS > + > +endchoice > + > config DOWNLOAD > bool "Enable image downloading" > default n > @@ -329,8 +352,7 @@ config DOWNLOAD_SSL > bool "Enable SSL support for image downloading" > default n > depends on DOWNLOAD > - depends on HAVE_LIBSSL > - depends on HAVE_LIBCRYPTO > + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS > select CHANNEL_CURL_SSL > help > Enable SSL and checksum verification support in channels > @@ -344,26 +366,25 @@ config CHANNEL_CURL > config CHANNEL_CURL_SSL > bool > depends on CHANNEL_CURL > - depends on HAVE_LIBSSL > - depends on HAVE_LIBCRYPTO > + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS > select CURL_SSL > > config HASH_VERIFY > bool "Allow to add sha256 hash to each image" > - depends on HAVE_LIBSSL > + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS > help > Allow to add a sha256 hash to an artifact. > This is automatically set in case of Signed Image > > -comment "Hash verification needs libssl" > - depends on !HAVE_LIBSSL > +comment "Hash checking needs an SSL implementation" > + depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_MBEDTLS > > config SIGNED_IMAGES > bool "Enable verification of signed images" > - depends on HAVE_LIBSSL > + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS > select HASH_VERIFY > -comment "Image verification (signed images) needs libssl" > - depends on !HAVE_LIBSSL > +comment "Image signature verification needs an SSL implementation" > + depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_MBEDTLS > > choice > prompt "Signature verification algorithm" > @@ -378,6 +399,7 @@ choice > > config SIGALG_CMS > bool "Cryptographic Message Syntax (CMS)" > + depends on SSL_IMPL_OPENSSL > > endchoice > > @@ -396,9 +418,9 @@ endmenu > > config ENCRYPTED_IMAGES > bool "Images can be encrypted with a symmetric key" > - depends on HAVE_LIBSSL > -comment "Image encryption needs libssl" > - depends on !HAVE_LIBSSL > + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS > +comment "Image encryption needs an SSL implementation" > + depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_MBEDTLS > > source suricatta/Config.in > > diff --git a/Makefile.deps b/Makefile.deps > index df7379f..512d4b8 100644 > --- a/Makefile.deps > +++ b/Makefile.deps > @@ -54,6 +54,10 @@ ifeq ($(HAVE_LIBCRYPTO),) > export HAVE_LIBCRYPTO = y > endif > > +ifeq ($(HAVE_MBEDTLS),) > +export HAVE_MBEDTLS = y > +endif > + > ifeq ($(HAVE_JSON_C),) > export HAVE_JSON_C = y > endif > diff --git a/Makefile.flags b/Makefile.flags > index 663ce57..b880d32 100644 > --- a/Makefile.flags > +++ b/Makefile.flags > @@ -145,23 +145,12 @@ ifeq ($(CONFIG_JSON),y) > LDLIBS += json-c > endif > > -# signed images require openssl (digest) > -ifneq ($(CONFIG_HASH_VERIFY),) > +ifeq ($(CONFIG_SSL_IMPL_OPENSSL),y) > LDLIBS += crypto ssl > endif > > -# signed images require openssl (digest) > -ifneq ($(CONFIG_ENCRYPTED_IMAGES),) > -LDLIBS += crypto ssl > -endif > - > -# mongoose / webserver > -ifeq ($(CONFIG_WEBSERVER),y) > -ifeq ($(CONFIG_MONGOOSE),y) > -ifeq ($(CONFIG_MONGOOSESSL),y) > -LDLIBS += crypto ssl > -endif > -endif > +ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y) > +LDLIBS += mbedcrypto mbedtls > endif > > # MTD > @@ -197,20 +186,8 @@ ifeq ($(CONFIG_BOOTLOADER_EBG),y) > LDLIBS += ebgenv z > endif > > -# channel_curl > -ifneq ($(CONFIG_CHANNEL_CURL_SSL),) > -ifeq ($(strip $(findstring crypto,$(LDLIBS))),) > -LDLIBS += crypto ssl > -endif > -endif > - > # suricatta > ifneq ($(CONFIG_SURICATTA),) > -ifneq ($(CONFIG_SURICATTA_SSL),) > -ifeq ($(strip $(findstring crypto,$(LDLIBS))),) > -LDLIBS += crypto ssl > -endif > -endif > ifneq ($(CONFIG_SURICATTA_HAWKBIT),) > ifeq ($(strip $(findstring json-c,$(LDLIBS))),) > LDLIBS += json-c > diff --git a/configs/mbedtls_defconfig b/configs/mbedtls_defconfig > new file mode 100644 > index 0000000..c1f191a > --- /dev/null > +++ b/configs/mbedtls_defconfig > @@ -0,0 +1,18 @@ > +CONFIG_HW_COMPATIBILITY=y > +# CONFIG_MTD is not set > +CONFIG_LUAPKG="lua5.2" > +CONFIG_EXTRA_CFLAGS="-g" > +CONFIG_BOOTLOADER_NONE=y > +CONFIG_DOWNLOAD=y > +CONFIG_SSL_IMPL_MBEDTLS=y > +CONFIG_HASH_VERIFY=y > +CONFIG_SIGNED_IMAGES=y > +CONFIG_ENCRYPTED_IMAGES=y > +CONFIG_WEBSERVER=y > +CONFIG_LUAEXTERNAL=y > +CONFIG_RAW=y > +CONFIG_LUASCRIPTHANDLER=y > +CONFIG_SHELLSCRIPTHANDLER=y > +CONFIG_HANDLER_IN_LUA=y > +CONFIG_ARCHIVE=y > +CONFIG_REMOTE_HANDLER=y > diff --git a/corelib/Makefile b/corelib/Makefile > index d6edf65..7abea7f 100644 > --- a/corelib/Makefile > +++ b/corelib/Makefile > @@ -12,12 +12,18 @@ lib-y += installer.o \ > lib-$(CONFIG_DOWNLOAD) += downloader.o > lib-$(CONFIG_MTD) += mtd-interface.o > lib-$(CONFIG_LUA) += lua_interface.o lua_compat.o > +ifeq ($(CONFIG_SSL_IMPL_OPENSSL),y) > lib-$(CONFIG_HASH_VERIFY) += verify_signature.o > lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt.o > +lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify.o > +lib-$(CONFIG_SIGALG_CMS) += swupdate_cms_verify.o > +endif > +ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y) > +lib-$(CONFIG_HASH_VERIFY) += verify_signature_mbedtls.o > +lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_mbedtls.o > +lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify_mbedtls.o > +endif > lib-$(CONFIG_LIBCONFIG) += swupdate_settings.o \ > parsing_library_libconfig.o > lib-$(CONFIG_JSON) += parsing_library_libjson.o > lib-$(CONFIG_CHANNEL_CURL) += channel_curl.o > -lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify.o > -lib-$(CONFIG_SIGALG_CMS) += swupdate_cms_verify.o > - > diff --git a/corelib/swupdate_decrypt.c b/corelib/swupdate_decrypt.c > index e1043d8..f14ca9c 100644 > --- a/corelib/swupdate_decrypt.c > +++ b/corelib/swupdate_decrypt.c > @@ -67,7 +67,7 @@ struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char > } > > int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, > - int *outlen, unsigned char *cryptbuf, int inlen) > + int *outlen, const unsigned char *cryptbuf, int inlen) > { > if (EVP_DecryptUpdate(SSL_GET_CTXDEC(dgst), buf, outlen, cryptbuf, inlen) != 1) { > const char *reason = ERR_reason_error_string(ERR_peek_error()); > diff --git a/corelib/swupdate_decrypt_mbedtls.c b/corelib/swupdate_decrypt_mbedtls.c > new file mode 100644 > index 0000000..c970b9b > --- /dev/null > +++ b/corelib/swupdate_decrypt_mbedtls.c > @@ -0,0 +1,100 @@ > +#include <errno.h> > + > +#include "sslapi.h" > +#include "util.h" > + > +struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char *iv) > +{ > + struct swupdate_digest *dgst; > + const mbedtls_cipher_info_t *cipher_info; > + int error; > + > + if ((key == NULL) || (iv == NULL)) { > + ERROR("no key provided for decryption!"); > + return NULL; > + } > + > + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC); > + if (!cipher_info) { > + ERROR("mbedtls_cipher_info_from_type"); > + return NULL; > + } > + > + dgst = calloc(1, sizeof(*dgst)); > + if (!dgst) { > + return NULL; > + } > + > + mbedtls_cipher_init(&dgst->mbedtls_cipher_context); > + > + error = mbedtls_cipher_setup(&dgst->mbedtls_cipher_context, cipher_info); > + if (error) { > + ERROR("mbedtls_cipher_setup: %d", error); > + goto fail; > + } > + > + error = mbedtls_cipher_setkey(&dgst->mbedtls_cipher_context, key, 256, MBEDTLS_DECRYPT); > + if (error) { > + ERROR("mbedtls_cipher_setkey: %d", error); > + goto fail; > + } > + > + error = mbedtls_cipher_set_iv(&dgst->mbedtls_cipher_context, iv, 16); > + if (error) { > + ERROR("mbedtls_cipher_set_iv: %d", error); > + goto fail; > + } > + > + return dgst; > + > +fail: > + free(dgst); > + return NULL; > +} > + > +int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, > + int *outlen, const unsigned char *cryptbuf, int inlen) > +{ > + int error; > + size_t olen = *outlen; > + > + error = mbedtls_cipher_update(&dgst->mbedtls_cipher_context, cryptbuf, inlen, buf, &olen); > + if (error) { > + ERROR("mbedtls_cipher_update: %d", error); > + return -EFAULT; > + } > + *outlen = olen; > + > + return 0; > +} > + > +int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf, > + int *outlen) > +{ > + int error; > + size_t olen = *outlen; > + > + if (!dgst) { > + return -EINVAL; > + } > + > + error = mbedtls_cipher_finish(&dgst->mbedtls_cipher_context, buf, &olen); > + if (error) { > + ERROR("mbedtls_cipher_finish: %d", error); > + return -EFAULT; > + } > + *outlen = olen; > + > + return 0; > + > +} > + > +void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst) > +{ > + if (!dgst) { > + return; > + } > + > + mbedtls_cipher_free(&dgst->mbedtls_cipher_context); > + free(dgst); > +} > diff --git a/corelib/swupdate_rsa_verify_mbedtls.c b/corelib/swupdate_rsa_verify_mbedtls.c > new file mode 100644 > index 0000000..533020b > --- /dev/null > +++ b/corelib/swupdate_rsa_verify_mbedtls.c > @@ -0,0 +1,103 @@ > +/* > + * (C) Copyright 2019 > + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. > + * > + * SPDX-License-Identifier: GPL-2.0-or-later > + */ > + > +#include <assert.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <sys/stat.h> > +#include <sys/types.h> > +#include <unistd.h> > + > +#include "sslapi.h" > +#include "util.h" > + > +int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile) > +{ > + struct swupdate_digest *dgst; > + int error; > + > + dgst = calloc(1, sizeof(*dgst)); > + if (!dgst) { > + return -ENOMEM; > + } > + > + mbedtls_pk_init(&dgst->mbedtls_pk_context); > + > + error = mbedtls_pk_parse_public_keyfile(&dgst->mbedtls_pk_context, keyfile); > + if (error) { > + ERROR("mbedtls_pk_parse_public_keyfile: %d", error); > + goto fail; > + } > + > + sw->dgst = dgst; > + return 0; > + > +fail: > + free(dgst); > + return -EIO; > +} > + > +static int read_file_into_buffer(uint8_t *buffer, int size, const char *filename) > +{ > + int fd; > + ssize_t rd; > + int result = -1; > + > + fd = open(filename, O_RDONLY); > + if (fd == -1) { > + ERROR("Failed to open file \"%s\"", filename); > + return -errno; > + } > + > + rd = read(fd, buffer, size); > + if (rd != size) { > + ERROR("Failed to read %d bytes from file \"%s\"", size, filename); > + result = -EMSGSIZE; > + goto exit; > + } > + > + result = 0; > + > +exit: > + return result; > +} > + > +int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile, > + const char *file, const char *signer_name) > +{ > + int error; > + uint8_t hash_computed[32]; > + const mbedtls_md_info_t *md_info; > + uint8_t signature[256]; > + > + (void)signer_name; > + > + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); > + if (!md_info) { > + ERROR("mbedtls_md_info_from_type"); > + return -ENOENT; > + } > + > + assert(mbedtls_md_get_size(md_info) == sizeof(hash_computed)); > + > + error = mbedtls_md_file(md_info, file, hash_computed); > + if (error) { > + ERROR("mbedtls_md_file: %d", error); > + return error; > + } > + > + error = read_file_into_buffer(signature, sizeof(signature), sigfile); > + if (error) { > + return error; > + } > + > + return mbedtls_pk_verify( > + &dgst->mbedtls_pk_context, mbedtls_md_get_type(md_info), > + hash_computed, sizeof(hash_computed), > + signature, sizeof(signature) > + ); > +} > diff --git a/corelib/test/Makefile b/corelib/test/Makefile > index b071177..99f2138 100644 > --- a/corelib/test/Makefile > +++ b/corelib/test/Makefile > @@ -16,6 +16,10 @@ > ## Foundation, Inc. > > tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt > +tests-$(CONFIG_HASH_VERIFY) += test_hash > +ifeq ($(CONFIG_SIGALG_RAWRSA),y) > +tests-$(CONFIG_SIGNED_IMAGES) += test_verify > +endif > > ccflags-y += -I$(src)/../ > > @@ -57,7 +61,7 @@ tests: > @: > endif > > -$(obj)/%.lnk: $(objtree)/core/built-in.o > +$(obj)/%.lnk: $(obj)/%.o $(objtree)/core/built-in.o > $(Q)strip -N main -o $(objtree)/core/built-in.o.tmp $(objtree)/core/built-in.o > $(Q)$(call cmd,linktestexe) > > diff --git a/corelib/test/data/public.pem b/corelib/test/data/public.pem > new file mode 100644 > index 0000000..0b0ea12 > --- /dev/null > +++ b/corelib/test/data/public.pem > @@ -0,0 +1,9 @@ > +-----BEGIN PUBLIC KEY----- > +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApo5LaVd/dqPvTBbVIYtd > +pejuTjRQgoX4tnSNRCSuVu+GJghGlz3ihZVYsnPSbSzpxUJtyGnG3D6HFHDbWNY9 > +5CMjUpoV8kCbo1tlfGHlmMqHNCu280ZJ2NtL0I3oMaaEh30x1hn/93AQZfl2yHWm > +hYz1xTTiA1/Cw95G3VHrVGd7H8nG94F6aRGk7rFp5gthELjURI7dUQI7CvbAN76y > +/DMVGgLu1H81zCBK1r4x/mJKR8oH06eFtkMsCjmLAIVZ/Vz4CZiWHU9LC1qvC9V8 > +5bgJ5qOiW/sKKJlFJKLOCeYMJlJ58G7ywy1YNQ1NwzXgiplibsJb8O2nFPNG1tDP > +TwIDAQAB > +-----END PUBLIC KEY----- > diff --git a/corelib/test/data/test_file_to_sign b/corelib/test/data/test_file_to_sign > new file mode 100644 > index 0000000..8baef1b > --- /dev/null > +++ b/corelib/test/data/test_file_to_sign > @@ -0,0 +1 @@ > +abc > diff --git a/corelib/test/test_crypt.c b/corelib/test/test_crypt.c > index f3b39c6..2481d69 100644 > --- a/corelib/test/test_crypt.c > +++ b/corelib/test/test_crypt.c > @@ -51,7 +51,7 @@ static void do_crypt(struct cryptdata *crypt, unsigned char *CRYPTTEXT, unsigned > assert_true(ret >= 0); > assert_true(len == 0); > > - ret = swupdate_DECRYPT_final(dcrypt, crypt->crypttext, &len); > + ret = swupdate_DECRYPT_final(dcrypt, buffer, &len); > assert_true(ret == 0); > assert_true(len == (int)strlen((const char *)PLAINTEXT)); > assert_true(strncmp((const char *)buffer, (const char *)PLAINTEXT, len) == 0); > @@ -119,7 +119,7 @@ static void test_crypt_failure(void **state) > > unsigned char *buffer = calloc(1, strlen((const char *)CRYPTTEXT) + EVP_MAX_BLOCK_LENGTH); > int ret = swupdate_DECRYPT_update(dcrypt, buffer, &len, crypt.crypttext, strlen((const char *)CRYPTTEXT) / 2); > - ret = swupdate_DECRYPT_final(dcrypt, crypt.crypttext, &len); > + ret = swupdate_DECRYPT_final(dcrypt, buffer, &len); > assert_true(ret != 0); > free(buffer); > > diff --git a/corelib/test/test_hash.c b/corelib/test/test_hash.c > new file mode 100644 > index 0000000..06475fd > --- /dev/null > +++ b/corelib/test/test_hash.c > @@ -0,0 +1,124 @@ > +/* > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc. > + */ > + > +#include <stddef.h> > +#include <setjmp.h> > +#include <stdarg.h> > +#include <cmocka.h> > +#include <string.h> > + > +#include "sslapi.h" > +#include "util.h" > + > +struct testvector { > + const char *input; > + const char *sha1; > + const char *sha256; > +}; > + > +// https://www.di-mgt.com.au/sha_testvectors.html > +static const struct testvector testvectors[] = { > + { > + .input = "abc", > + .sha1 = "a9993e364706816aba3e25717850c26c9cd0d89d", > + .sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", > + }, > + { > + .input = "", > + .sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709", > + .sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", > + }, > + { > + .input = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", > + .sha1 = "84983e441c3bd26ebaae4aa1f95129e5e54670f1", > + .sha256 = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", > + }, > + { > + .input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", > + .sha1 = "a49b2446a02c645bf419f995b67091253a04a259", > + .sha256 = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", > + }, > +}; > + > +static void hex2bin(unsigned char *dest, const unsigned char *source) > +{ > + unsigned int val; > + for (unsigned int i = 0; i < strlen((const char *)source); i += 2) { > + val = from_ascii((const char *)&source[i], 2, LG_16); > + dest[i / 2] = val; > + } > +} > + > +static void do_concrete_hash(const char* algo, const char* input, const char* expected_hex) > +{ > + int error; > + uint8_t result[32] = {0}; > + unsigned len = 0; > + uint8_t expected_bin[32] = {0}; > + struct swupdate_digest *dgst; > + > + dgst = swupdate_HASH_init(algo); > + assert_non_null(dgst); > + error = swupdate_HASH_update(dgst, (uint8_t *)input, strlen(input)); > + assert_true(!error); > + > + error = swupdate_HASH_final(dgst, result, &len); > + assert_int_equal(error, 1); > + assert_int_equal(len, strlen(expected_hex) / 2); > + > + swupdate_HASH_cleanup(dgst); > + > + hex2bin(expected_bin, (uint8_t *)expected_hex); > + error = swupdate_HASH_compare(expected_bin, result); > + assert_true(!error); > +} > + > +static void do_hash(const struct testvector *vector) > +{ > + do_concrete_hash("sha1", vector->input, vector->sha1); > + do_concrete_hash("sha256", vector->input, vector->sha256); > +} > + > +static void test_hash_vectors(void **state) > +{ > + unsigned i; > + > + (void)state; > + > + for (i = 0; i < sizeof(testvectors) / sizeof(testvectors[0]); ++i) { > + do_hash(testvectors + i); > + } > +} > + > +static void test_hash_compare(void **state) > +{ > + (void)state; > + > + static const uint8_t a[32] = {0}; > + static const uint8_t b[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; > + > + assert_int_equal(swupdate_HASH_compare(a, a), 0); > + assert_int_equal(swupdate_HASH_compare(a, b), -1); > +} > + > +int main(void) > +{ > + static const struct CMUnitTest hash_tests[] = { > + cmocka_unit_test(test_hash_compare), > + cmocka_unit_test(test_hash_vectors), > + }; > + return cmocka_run_group_tests_name("hash", hash_tests, NULL, NULL); > +} > diff --git a/corelib/test/test_verify.c b/corelib/test/test_verify.c > new file mode 100644 > index 0000000..49a4933 > --- /dev/null > +++ b/corelib/test/test_verify.c > @@ -0,0 +1,108 @@ > +/* > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc. > + */ > + > +#include <errno.h> > +#include <fcntl.h> > +#include <setjmp.h> > +#include <stdarg.h> > +#include <stddef.h> > +#include <string.h> > +#include <sys/stat.h> > +#include <sys/types.h> > +#include <unistd.h> > + > +#include <cmocka.h> > + > +#include "sslapi.h" > +#include "util.h" > + > +#define DATADIR "corelib/test/data/" > +#define SIGNATURE_FILE DATADIR "test_file_to_sign.sig" > + > +static int put_file_contents(const char* filename, const uint8_t* buffer, > + size_t length) { > + ssize_t wr; > + const int fd = creat(filename, 0644); > + > + if (fd == -1) { > + fprintf(stderr, "%s: %s\n", filename, strerror(errno)); > + return -1; > + } > + > + wr = write(fd, buffer, length); > + if (wr != length) { > + fprintf(stderr, "Failed to write signature file\n"); > + return -2; > + } > + > + close(fd); > + return 0; > +} > + > +static void test_verify_pkcs15(void **state) > +{ > + static const uint8_t signature[] = { > + 0x51, 0x8c, 0x14, 0x98, 0xc0, 0x76, 0x75, 0xb2, 0x3f, 0xe9, 0x1f, 0x8c, > + 0x66, 0x7f, 0x42, 0xb0, 0x34, 0x88, 0x69, 0x01, 0xae, 0xc1, 0xf1, 0x07, > + 0x7c, 0xa0, 0xf5, 0x29, 0xe7, 0x25, 0xcd, 0xe5, 0x8e, 0x0e, 0x99, 0xf6, > + 0x1f, 0x19, 0x14, 0x2e, 0x21, 0xcb, 0xa9, 0x44, 0xc0, 0xbb, 0xef, 0x33, > + 0xd6, 0xa3, 0xbc, 0xcb, 0x33, 0x16, 0x88, 0xed, 0x7e, 0x1f, 0xd8, 0x94, > + 0xcf, 0x88, 0xf8, 0x55, 0x5d, 0xe7, 0x49, 0x03, 0x52, 0x47, 0x23, 0x71, > + 0x93, 0x13, 0x98, 0x1b, 0x73, 0xcf, 0xe3, 0x67, 0x39, 0x67, 0x9d, 0xae, > + 0xe1, 0x9c, 0x08, 0x79, 0x01, 0x5f, 0xd4, 0x2c, 0xcf, 0xfa, 0xe8, 0x89, > + 0x3b, 0x5c, 0xc9, 0x10, 0x07, 0x66, 0x52, 0xbd, 0x75, 0x84, 0x4b, 0x63, > + 0x8d, 0x19, 0x43, 0x4f, 0x04, 0xb7, 0x05, 0x23, 0xf3, 0x93, 0xb7, 0x2d, > + 0xd5, 0x60, 0x85, 0x96, 0xd5, 0x18, 0xfb, 0xcd, 0xd4, 0xd7, 0xe6, 0x6a, > + 0x3d, 0x3f, 0x1f, 0x61, 0x61, 0x4d, 0xc0, 0x97, 0x56, 0xc7, 0x16, 0x07, > + 0xc7, 0x24, 0xa2, 0x3b, 0xeb, 0x7c, 0x93, 0x64, 0x4e, 0xe5, 0x33, 0xff, > + 0x9a, 0x61, 0x7b, 0x1e, 0x0f, 0xe2, 0x0d, 0x7a, 0x12, 0x5c, 0xa0, 0x3e, > + 0x93, 0x27, 0x43, 0x9b, 0x5b, 0x70, 0x2f, 0x4a, 0xaf, 0xe8, 0xd7, 0x93, > + 0xef, 0x89, 0xd8, 0xfc, 0x5c, 0x35, 0xa3, 0x09, 0x3b, 0xc8, 0x8e, 0xb7, > + 0x30, 0x15, 0xe3, 0x4f, 0x38, 0x8d, 0x01, 0x52, 0x81, 0x02, 0x2c, 0xdd, > + 0xc2, 0xc4, 0x31, 0x66, 0xfb, 0x5a, 0x7a, 0x27, 0x1b, 0xc8, 0x77, 0x3a, > + 0x22, 0x9e, 0x95, 0xb2, 0x46, 0x2f, 0x88, 0x85, 0xd9, 0xe3, 0x88, 0x98, > + 0x63, 0xca, 0x97, 0x8a, 0x9e, 0x43, 0x80, 0xa4, 0x9d, 0x3e, 0x70, 0x2e, > + 0x60, 0xf2, 0xb3, 0x59, 0xb4, 0x1e, 0x6d, 0xf0, 0x41, 0x06, 0x4e, 0xc4, > + 0x77, 0x4f, 0x24, 0x50 > + }; > + > + int error; > + struct swupdate_cfg config; > + > + (void)state; > + > + config.dgst = NULL; > + error = swupdate_dgst_init(&config, DATADIR "public.pem"); > + assert_int_equal(error, 0); > + > + error = put_file_contents(SIGNATURE_FILE, signature, sizeof(signature)); > + assert_int_equal(error, 0); > + > + error = swupdate_verify_file(config.dgst, SIGNATURE_FILE, > + DATADIR "test_file_to_sign", NULL); > + assert_int_equal(error, 0); > + > + unlink(SIGNATURE_FILE); > +} > + > +int main(void) > +{ > + swupdate_crypto_init(); > + static const struct CMUnitTest verify_tests[] = { > + cmocka_unit_test(test_verify_pkcs15), > + }; > + return cmocka_run_group_tests_name("verify", verify_tests, NULL, NULL); > +} > diff --git a/corelib/verify_signature.c b/corelib/verify_signature.c > index 728246a..8de9de5 100644 > --- a/corelib/verify_signature.c > +++ b/corelib/verify_signature.c > @@ -63,7 +63,7 @@ struct swupdate_digest *swupdate_HASH_init(const char *SHAlength) > return dgst; > } > > -int swupdate_HASH_update(struct swupdate_digest *dgst, unsigned char *buf, > +int swupdate_HASH_update(struct swupdate_digest *dgst, const unsigned char *buf, > size_t len) > { > if (!dgst) > @@ -97,7 +97,7 @@ void swupdate_HASH_cleanup(struct swupdate_digest *dgst) > /* > * Just a wrap function to memcmp > */ > -int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2) > +int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2) > { > int i; > > diff --git a/corelib/verify_signature_mbedtls.c b/corelib/verify_signature_mbedtls.c > new file mode 100644 > index 0000000..0dd874d > --- /dev/null > +++ b/corelib/verify_signature_mbedtls.c > @@ -0,0 +1,106 @@ > +#include <ctype.h> > +#include <errno.h> > + > +#include "sslapi.h" > +#include "util.h" > + > +static char *algo_upper(const char *algo) > +{ > + static char result[16]; > + unsigned i; > + > + for (i = 0; algo[i] && (i < sizeof(result) - 1); ++i) { > + result[i] = toupper(algo[i]); > + } > + result[i] = '\0'; > + return result; > +} > + > +struct swupdate_digest *swupdate_HASH_init(const char *algo) > +{ > + struct swupdate_digest *dgst; > + int error; > + > + const mbedtls_md_info_t *info = mbedtls_md_info_from_string(algo_upper(algo)); > + if (!info) { > + ERROR("mbedtls_md_info_from_string(\"%s\")", algo); > + return NULL; > + } > + > + dgst = calloc(1, sizeof(*dgst)); > + if (!dgst) { > + return NULL; > + } > + > + mbedtls_md_init(&dgst->mbedtls_md_context); > + > + error = mbedtls_md_setup(&dgst->mbedtls_md_context, info, 0); > + if (error) { > + ERROR("mbedtls_md_setup: %d", error); > + goto fail; > + } > + > + error = mbedtls_md_starts(&dgst->mbedtls_md_context); > + if (error) { > + ERROR("mbedtls_md_starts: %d", error); > + goto fail; > + } > + > + return dgst; > + > +fail: > + free(dgst); > + return 0; > +} > + > +int swupdate_HASH_update(struct swupdate_digest *dgst, const unsigned char *buf, > + size_t len) > +{ > + if (!dgst) { > + return -EFAULT; > + } > + > + const int error = mbedtls_md_update(&dgst->mbedtls_md_context, buf, len); > + if (error) { > + ERROR("mbedtls_md_update: %d", error); > + return -EIO; > + } > + > + return 0; > +} > + > +int swupdate_HASH_final(struct swupdate_digest *dgst, unsigned char *md_value, > + unsigned int *md_len) > +{ > + if (!dgst) { > + return -EFAULT; > + } > + > + int error = mbedtls_md_finish(&dgst->mbedtls_md_context, md_value); > + if (error) { > + return -EINVAL; > + } > + if (md_len) { > + *md_len = mbedtls_md_get_size(dgst->mbedtls_md_context.md_info); > + } > + return 1; > + > +} > + > +void swupdate_HASH_cleanup(struct swupdate_digest *dgst) > +{ > + if (!dgst) { > + return; > + } > + > + mbedtls_md_free(&dgst->mbedtls_md_context); > + free(dgst); > +} > + > +/* > + * Just a wrap function to memcmp > + */ > +int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2) > +{ > + return memcmp(hash1, hash2, SHA256_HASH_LENGTH) ? -1 : 0; > +} > diff --git a/include/sslapi.h b/include/sslapi.h > index c66e005..1f1209b 100644 > --- a/include/sslapi.h > +++ b/include/sslapi.h > @@ -18,6 +18,7 @@ > */ > #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_ENCRYPTED_IMAGES) || \ > defined(CONFIG_SURICATTA_SSL) || defined(CONFIG_CHANNEL_CURL_SSL) > +#if defined(CONFIG_SSL_IMPL_OPENSSL) > #include <openssl/bio.h> > #include <openssl/objects.h> > #include <openssl/err.h> > @@ -95,22 +96,47 @@ static inline uint32_t SSL_X509_get_extended_key_usage(X509 *x) > #endif > } > > +#elif defined(CONFIG_SSL_IMPL_MBEDTLS) > +#include <mbedtls/md.h> > +#include <mbedtls/pk.h> > +#include <mbedtls/cipher.h> > + > +#define EVP_MAX_BLOCK_LENGTH (16) > +#define swupdate_crypto_init() > + > +struct swupdate_digest { > +#ifdef CONFIG_HASH_VERIFY > + mbedtls_md_context_t mbedtls_md_context; > +#endif /* CONFIG_HASH_VERIFY */ > +#ifdef CONFIG_SIGNED_IMAGES > + mbedtls_pk_context mbedtls_pk_context; > +#endif /* CONFIG_SIGNED_IMAGES */ > +#ifdef CONFIG_ENCRYPTED_IMAGES > + mbedtls_cipher_context_t mbedtls_cipher_context; > +#endif /* CONFIG_ENCRYPTED_IMAGES */ > +}; > + > +#else /* CONFIG_SSL_IMPL */ > +#error unknown SSL implementation > +#endif /* CONFIG_SSL_IMPL */ > #else > #define swupdate_crypto_init() > #define AES_BLOCK_SIZE 16 > #endif > > #if defined(CONFIG_HASH_VERIFY) > +struct swupdate_cfg; > + > int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile); > struct swupdate_digest *swupdate_HASH_init(const char *SHALength); > -int swupdate_HASH_update(struct swupdate_digest *dgst, unsigned char *buf, > +int swupdate_HASH_update(struct swupdate_digest *dgst, const unsigned char *buf, > size_t len); > int swupdate_HASH_final(struct swupdate_digest *dgst, unsigned char *md_value, > unsigned int *md_len); > void swupdate_HASH_cleanup(struct swupdate_digest *dgst); > int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile, > const char *file, const char *signer_name); > -int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2); > +int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2); > > > #else > @@ -126,7 +152,7 @@ int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2); > #ifdef CONFIG_ENCRYPTED_IMAGES > struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char *iv); > int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, > - int *outlen, unsigned char *cryptbuf, int inlen); > + int *outlen, const unsigned char *cryptbuf, int inlen); > int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf, > int *outlen); > void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst); > diff --git a/include/util.h b/include/util.h > index 4c261ed..99d183f 100644 > --- a/include/util.h > +++ b/include/util.h > @@ -10,6 +10,7 @@ > > #include <stdint.h> > #include <string.h> > +#include <stdio.h> > #if defined(__linux__) > #include <linux/types.h> > #endif > diff --git a/mongoose/Config.in b/mongoose/Config.in > index 29cac90..238b6de 100644 > --- a/mongoose/Config.in > +++ b/mongoose/Config.in > @@ -30,10 +30,11 @@ config MONGOOSESSL > depends on MONGOOSE > depends on HAVE_LIBSSL > depends on HAVE_LIBCRYPTO > + depends on SSL_IMPL_OPENSSL > help > It enables SSL support into mongoose > > comment "SSL support needs libcrypto, libssl" > - depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO > + depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO || !SSL_IMPL_OPENSSL > > endif > diff --git a/suricatta/Config.in b/suricatta/Config.in > index 20ac038..5db9081 100644 > --- a/suricatta/Config.in > +++ b/suricatta/Config.in > @@ -23,11 +23,12 @@ config SURICATTA_SSL > default n > depends on HAVE_LIBSSL > depends on HAVE_LIBCRYPTO > + depends on SSL_IMPL_OPENSSL > help > Enable SSL and checksum verification support in suricatta. > > comment "SSL support needs libcrypto, libssl" > - depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO > + depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO || !SSL_IMPL_OPENSSL > > choice > prompt "Update Status Storage" >
Stefano, On 2019-07-19 13:36, Stefano Babic wrote: > I wanted to test your implementation, I got no time to do it. Anyway, I > do not see any issue for the current code - I tend to merge this and > try > to win some testers. By merging I have a couple of issues regarding > "test": > > First, if more "test" will be introduced, I do not think it is a good > idea to share it into src. Currently, there is just one example > ./suricatta/test. I will propose to move all tests in a separate > directory in the root directory of the project ( test/). I just followed the pattern I observed under corelib/test but of course we can move all the tests to a common subdir, I agree it would make sense. > Why do we need to put into repo "public.pem" ? Can we generate it > during > the test ? Yes, we can. By doing so, we gain that the key generation process will be also documented. The flip side is this approach will need executing some commands other than the test executable but I agree it will worth to do it. > I will suggest you split the patch as: > > - [1] changes to SWUpdate ==> I will apply this > - [2] test environment ==> maybe there are some mor ecomments. OK, I will do the split and post a new version soon. Regards, Laszlo
Hi Laszlo, On 20/07/19 09:57, laszlo via swupdate wrote: > Stefano, > > On 2019-07-19 13:36, Stefano Babic wrote: >> I wanted to test your implementation, I got no time to do it. Anyway, I >> do not see any issue for the current code - I tend to merge this and try >> to win some testers. By merging I have a couple of issues regarding >> "test": >> >> First, if more "test" will be introduced, I do not think it is a good >> idea to share it into src. Currently, there is just one example >> ./suricatta/test. I will propose to move all tests in a separate >> directory in the root directory of the project ( test/). > > I just followed the pattern I observed under corelib/test Yes, you did right - but by reviewing your patches together with suricatta/test, I convinced myself that is not the best bay and does not scale well. > but of course we > can move all the tests to a common subdir, I agree it would make sense. Yes, I think it is better. > > >> Why do we need to put into repo "public.pem" ? Can we generate it during >> the test ? > > Yes, we can. By doing so, we gain that the key generation process will be > also documented. Right. > The flip side is this approach will need executing some > commands other than the test executable but I agree it will worth to do it. +1 > > >> I will suggest you split the patch as: >> >> - [1] changes to SWUpdate ==> I will apply this >> - [2] test environment ==> maybe there are some mor ecomments. > > OK, I will do the split and post a new version soon. > Thanks, Stefano
diff --git a/.travis.yml b/.travis.yml index 5979153..3015f79 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,8 @@ before_install: - sudo apt-get install -y graphviz - sudo apt-get install -y autoconf-archive - sudo apt-get install -y linux-headers-$(uname -r) + - sudo apt-get install -y libmbedtls-dev + - sudo apt-get install -y libcmocka-dev script: - sudo ln -sf /usr/lib/x86_64-linux-gnu/pkgconfig/lua5.2.pc /usr/lib/x86_64-linux-gnu/pkgconfig/lua.pc @@ -74,4 +76,5 @@ script: - make - sudo make install - cd .. - - for i in configs/*;do echo $i;make `basename $i` && make || exit 1;done + - sudo ldconfig + - for i in configs/*;do echo $i;make `basename $i` && make || exit 1;make corelib-tests || exit 1;done diff --git a/Kconfig b/Kconfig index b652d84..1449914 100644 --- a/Kconfig +++ b/Kconfig @@ -69,6 +69,10 @@ config HAVE_LIBCRYPTO bool option env="HAVE_LIBCRYPTO" +config HAVE_MBEDTLS + bool + option env="HAVE_MBEDTLS" + config HAVE_JSON_C bool option env="HAVE_JSON_C" @@ -313,6 +317,25 @@ endmenu source bootloader/Config.in +choice + prompt "SSL implementation to use" + default SSL_IMPL_OPENSSL + help + Select SSL implementation for hashing, verifying and decrypting images. + + config SSL_IMPL_NONE + bool "None" + + config SSL_IMPL_OPENSSL + bool "OpenSSL" + depends on HAVE_LIBSSL + + config SSL_IMPL_MBEDTLS + bool "mbedTLS" + depends on HAVE_MBEDTLS + +endchoice + config DOWNLOAD bool "Enable image downloading" default n @@ -329,8 +352,7 @@ config DOWNLOAD_SSL bool "Enable SSL support for image downloading" default n depends on DOWNLOAD - depends on HAVE_LIBSSL - depends on HAVE_LIBCRYPTO + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS select CHANNEL_CURL_SSL help Enable SSL and checksum verification support in channels @@ -344,26 +366,25 @@ config CHANNEL_CURL config CHANNEL_CURL_SSL bool depends on CHANNEL_CURL - depends on HAVE_LIBSSL - depends on HAVE_LIBCRYPTO + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS select CURL_SSL config HASH_VERIFY bool "Allow to add sha256 hash to each image" - depends on HAVE_LIBSSL + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS help Allow to add a sha256 hash to an artifact. This is automatically set in case of Signed Image -comment "Hash verification needs libssl" - depends on !HAVE_LIBSSL +comment "Hash checking needs an SSL implementation" + depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_MBEDTLS config SIGNED_IMAGES bool "Enable verification of signed images" - depends on HAVE_LIBSSL + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS select HASH_VERIFY -comment "Image verification (signed images) needs libssl" - depends on !HAVE_LIBSSL +comment "Image signature verification needs an SSL implementation" + depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_MBEDTLS choice prompt "Signature verification algorithm" @@ -378,6 +399,7 @@ choice config SIGALG_CMS bool "Cryptographic Message Syntax (CMS)" + depends on SSL_IMPL_OPENSSL endchoice @@ -396,9 +418,9 @@ endmenu config ENCRYPTED_IMAGES bool "Images can be encrypted with a symmetric key" - depends on HAVE_LIBSSL -comment "Image encryption needs libssl" - depends on !HAVE_LIBSSL + depends on SSL_IMPL_OPENSSL || SSL_IMPL_MBEDTLS +comment "Image encryption needs an SSL implementation" + depends on !SSL_IMPL_OPENSSL && !SSL_IMPL_MBEDTLS source suricatta/Config.in diff --git a/Makefile.deps b/Makefile.deps index df7379f..512d4b8 100644 --- a/Makefile.deps +++ b/Makefile.deps @@ -54,6 +54,10 @@ ifeq ($(HAVE_LIBCRYPTO),) export HAVE_LIBCRYPTO = y endif +ifeq ($(HAVE_MBEDTLS),) +export HAVE_MBEDTLS = y +endif + ifeq ($(HAVE_JSON_C),) export HAVE_JSON_C = y endif diff --git a/Makefile.flags b/Makefile.flags index 663ce57..b880d32 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -145,23 +145,12 @@ ifeq ($(CONFIG_JSON),y) LDLIBS += json-c endif -# signed images require openssl (digest) -ifneq ($(CONFIG_HASH_VERIFY),) +ifeq ($(CONFIG_SSL_IMPL_OPENSSL),y) LDLIBS += crypto ssl endif -# signed images require openssl (digest) -ifneq ($(CONFIG_ENCRYPTED_IMAGES),) -LDLIBS += crypto ssl -endif - -# mongoose / webserver -ifeq ($(CONFIG_WEBSERVER),y) -ifeq ($(CONFIG_MONGOOSE),y) -ifeq ($(CONFIG_MONGOOSESSL),y) -LDLIBS += crypto ssl -endif -endif +ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y) +LDLIBS += mbedcrypto mbedtls endif # MTD @@ -197,20 +186,8 @@ ifeq ($(CONFIG_BOOTLOADER_EBG),y) LDLIBS += ebgenv z endif -# channel_curl -ifneq ($(CONFIG_CHANNEL_CURL_SSL),) -ifeq ($(strip $(findstring crypto,$(LDLIBS))),) -LDLIBS += crypto ssl -endif -endif - # suricatta ifneq ($(CONFIG_SURICATTA),) -ifneq ($(CONFIG_SURICATTA_SSL),) -ifeq ($(strip $(findstring crypto,$(LDLIBS))),) -LDLIBS += crypto ssl -endif -endif ifneq ($(CONFIG_SURICATTA_HAWKBIT),) ifeq ($(strip $(findstring json-c,$(LDLIBS))),) LDLIBS += json-c diff --git a/configs/mbedtls_defconfig b/configs/mbedtls_defconfig new file mode 100644 index 0000000..c1f191a --- /dev/null +++ b/configs/mbedtls_defconfig @@ -0,0 +1,18 @@ +CONFIG_HW_COMPATIBILITY=y +# CONFIG_MTD is not set +CONFIG_LUAPKG="lua5.2" +CONFIG_EXTRA_CFLAGS="-g" +CONFIG_BOOTLOADER_NONE=y +CONFIG_DOWNLOAD=y +CONFIG_SSL_IMPL_MBEDTLS=y +CONFIG_HASH_VERIFY=y +CONFIG_SIGNED_IMAGES=y +CONFIG_ENCRYPTED_IMAGES=y +CONFIG_WEBSERVER=y +CONFIG_LUAEXTERNAL=y +CONFIG_RAW=y +CONFIG_LUASCRIPTHANDLER=y +CONFIG_SHELLSCRIPTHANDLER=y +CONFIG_HANDLER_IN_LUA=y +CONFIG_ARCHIVE=y +CONFIG_REMOTE_HANDLER=y diff --git a/corelib/Makefile b/corelib/Makefile index d6edf65..7abea7f 100644 --- a/corelib/Makefile +++ b/corelib/Makefile @@ -12,12 +12,18 @@ lib-y += installer.o \ lib-$(CONFIG_DOWNLOAD) += downloader.o lib-$(CONFIG_MTD) += mtd-interface.o lib-$(CONFIG_LUA) += lua_interface.o lua_compat.o +ifeq ($(CONFIG_SSL_IMPL_OPENSSL),y) lib-$(CONFIG_HASH_VERIFY) += verify_signature.o lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt.o +lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify.o +lib-$(CONFIG_SIGALG_CMS) += swupdate_cms_verify.o +endif +ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y) +lib-$(CONFIG_HASH_VERIFY) += verify_signature_mbedtls.o +lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_mbedtls.o +lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify_mbedtls.o +endif lib-$(CONFIG_LIBCONFIG) += swupdate_settings.o \ parsing_library_libconfig.o lib-$(CONFIG_JSON) += parsing_library_libjson.o lib-$(CONFIG_CHANNEL_CURL) += channel_curl.o -lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify.o -lib-$(CONFIG_SIGALG_CMS) += swupdate_cms_verify.o - diff --git a/corelib/swupdate_decrypt.c b/corelib/swupdate_decrypt.c index e1043d8..f14ca9c 100644 --- a/corelib/swupdate_decrypt.c +++ b/corelib/swupdate_decrypt.c @@ -67,7 +67,7 @@ struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char } int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, - int *outlen, unsigned char *cryptbuf, int inlen) + int *outlen, const unsigned char *cryptbuf, int inlen) { if (EVP_DecryptUpdate(SSL_GET_CTXDEC(dgst), buf, outlen, cryptbuf, inlen) != 1) { const char *reason = ERR_reason_error_string(ERR_peek_error()); diff --git a/corelib/swupdate_decrypt_mbedtls.c b/corelib/swupdate_decrypt_mbedtls.c new file mode 100644 index 0000000..c970b9b --- /dev/null +++ b/corelib/swupdate_decrypt_mbedtls.c @@ -0,0 +1,100 @@ +#include <errno.h> + +#include "sslapi.h" +#include "util.h" + +struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char *iv) +{ + struct swupdate_digest *dgst; + const mbedtls_cipher_info_t *cipher_info; + int error; + + if ((key == NULL) || (iv == NULL)) { + ERROR("no key provided for decryption!"); + return NULL; + } + + cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_256_CBC); + if (!cipher_info) { + ERROR("mbedtls_cipher_info_from_type"); + return NULL; + } + + dgst = calloc(1, sizeof(*dgst)); + if (!dgst) { + return NULL; + } + + mbedtls_cipher_init(&dgst->mbedtls_cipher_context); + + error = mbedtls_cipher_setup(&dgst->mbedtls_cipher_context, cipher_info); + if (error) { + ERROR("mbedtls_cipher_setup: %d", error); + goto fail; + } + + error = mbedtls_cipher_setkey(&dgst->mbedtls_cipher_context, key, 256, MBEDTLS_DECRYPT); + if (error) { + ERROR("mbedtls_cipher_setkey: %d", error); + goto fail; + } + + error = mbedtls_cipher_set_iv(&dgst->mbedtls_cipher_context, iv, 16); + if (error) { + ERROR("mbedtls_cipher_set_iv: %d", error); + goto fail; + } + + return dgst; + +fail: + free(dgst); + return NULL; +} + +int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, + int *outlen, const unsigned char *cryptbuf, int inlen) +{ + int error; + size_t olen = *outlen; + + error = mbedtls_cipher_update(&dgst->mbedtls_cipher_context, cryptbuf, inlen, buf, &olen); + if (error) { + ERROR("mbedtls_cipher_update: %d", error); + return -EFAULT; + } + *outlen = olen; + + return 0; +} + +int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf, + int *outlen) +{ + int error; + size_t olen = *outlen; + + if (!dgst) { + return -EINVAL; + } + + error = mbedtls_cipher_finish(&dgst->mbedtls_cipher_context, buf, &olen); + if (error) { + ERROR("mbedtls_cipher_finish: %d", error); + return -EFAULT; + } + *outlen = olen; + + return 0; + +} + +void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst) +{ + if (!dgst) { + return; + } + + mbedtls_cipher_free(&dgst->mbedtls_cipher_context); + free(dgst); +} diff --git a/corelib/swupdate_rsa_verify_mbedtls.c b/corelib/swupdate_rsa_verify_mbedtls.c new file mode 100644 index 0000000..533020b --- /dev/null +++ b/corelib/swupdate_rsa_verify_mbedtls.c @@ -0,0 +1,103 @@ +/* + * (C) Copyright 2019 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "sslapi.h" +#include "util.h" + +int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile) +{ + struct swupdate_digest *dgst; + int error; + + dgst = calloc(1, sizeof(*dgst)); + if (!dgst) { + return -ENOMEM; + } + + mbedtls_pk_init(&dgst->mbedtls_pk_context); + + error = mbedtls_pk_parse_public_keyfile(&dgst->mbedtls_pk_context, keyfile); + if (error) { + ERROR("mbedtls_pk_parse_public_keyfile: %d", error); + goto fail; + } + + sw->dgst = dgst; + return 0; + +fail: + free(dgst); + return -EIO; +} + +static int read_file_into_buffer(uint8_t *buffer, int size, const char *filename) +{ + int fd; + ssize_t rd; + int result = -1; + + fd = open(filename, O_RDONLY); + if (fd == -1) { + ERROR("Failed to open file \"%s\"", filename); + return -errno; + } + + rd = read(fd, buffer, size); + if (rd != size) { + ERROR("Failed to read %d bytes from file \"%s\"", size, filename); + result = -EMSGSIZE; + goto exit; + } + + result = 0; + +exit: + return result; +} + +int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile, + const char *file, const char *signer_name) +{ + int error; + uint8_t hash_computed[32]; + const mbedtls_md_info_t *md_info; + uint8_t signature[256]; + + (void)signer_name; + + md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256); + if (!md_info) { + ERROR("mbedtls_md_info_from_type"); + return -ENOENT; + } + + assert(mbedtls_md_get_size(md_info) == sizeof(hash_computed)); + + error = mbedtls_md_file(md_info, file, hash_computed); + if (error) { + ERROR("mbedtls_md_file: %d", error); + return error; + } + + error = read_file_into_buffer(signature, sizeof(signature), sigfile); + if (error) { + return error; + } + + return mbedtls_pk_verify( + &dgst->mbedtls_pk_context, mbedtls_md_get_type(md_info), + hash_computed, sizeof(hash_computed), + signature, sizeof(signature) + ); +} diff --git a/corelib/test/Makefile b/corelib/test/Makefile index b071177..99f2138 100644 --- a/corelib/test/Makefile +++ b/corelib/test/Makefile @@ -16,6 +16,10 @@ ## Foundation, Inc. tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt +tests-$(CONFIG_HASH_VERIFY) += test_hash +ifeq ($(CONFIG_SIGALG_RAWRSA),y) +tests-$(CONFIG_SIGNED_IMAGES) += test_verify +endif ccflags-y += -I$(src)/../ @@ -57,7 +61,7 @@ tests: @: endif -$(obj)/%.lnk: $(objtree)/core/built-in.o +$(obj)/%.lnk: $(obj)/%.o $(objtree)/core/built-in.o $(Q)strip -N main -o $(objtree)/core/built-in.o.tmp $(objtree)/core/built-in.o $(Q)$(call cmd,linktestexe) diff --git a/corelib/test/data/public.pem b/corelib/test/data/public.pem new file mode 100644 index 0000000..0b0ea12 --- /dev/null +++ b/corelib/test/data/public.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApo5LaVd/dqPvTBbVIYtd +pejuTjRQgoX4tnSNRCSuVu+GJghGlz3ihZVYsnPSbSzpxUJtyGnG3D6HFHDbWNY9 +5CMjUpoV8kCbo1tlfGHlmMqHNCu280ZJ2NtL0I3oMaaEh30x1hn/93AQZfl2yHWm +hYz1xTTiA1/Cw95G3VHrVGd7H8nG94F6aRGk7rFp5gthELjURI7dUQI7CvbAN76y +/DMVGgLu1H81zCBK1r4x/mJKR8oH06eFtkMsCjmLAIVZ/Vz4CZiWHU9LC1qvC9V8 +5bgJ5qOiW/sKKJlFJKLOCeYMJlJ58G7ywy1YNQ1NwzXgiplibsJb8O2nFPNG1tDP +TwIDAQAB +-----END PUBLIC KEY----- diff --git a/corelib/test/data/test_file_to_sign b/corelib/test/data/test_file_to_sign new file mode 100644 index 0000000..8baef1b --- /dev/null +++ b/corelib/test/data/test_file_to_sign @@ -0,0 +1 @@ +abc diff --git a/corelib/test/test_crypt.c b/corelib/test/test_crypt.c index f3b39c6..2481d69 100644 --- a/corelib/test/test_crypt.c +++ b/corelib/test/test_crypt.c @@ -51,7 +51,7 @@ static void do_crypt(struct cryptdata *crypt, unsigned char *CRYPTTEXT, unsigned assert_true(ret >= 0); assert_true(len == 0); - ret = swupdate_DECRYPT_final(dcrypt, crypt->crypttext, &len); + ret = swupdate_DECRYPT_final(dcrypt, buffer, &len); assert_true(ret == 0); assert_true(len == (int)strlen((const char *)PLAINTEXT)); assert_true(strncmp((const char *)buffer, (const char *)PLAINTEXT, len) == 0); @@ -119,7 +119,7 @@ static void test_crypt_failure(void **state) unsigned char *buffer = calloc(1, strlen((const char *)CRYPTTEXT) + EVP_MAX_BLOCK_LENGTH); int ret = swupdate_DECRYPT_update(dcrypt, buffer, &len, crypt.crypttext, strlen((const char *)CRYPTTEXT) / 2); - ret = swupdate_DECRYPT_final(dcrypt, crypt.crypttext, &len); + ret = swupdate_DECRYPT_final(dcrypt, buffer, &len); assert_true(ret != 0); free(buffer); diff --git a/corelib/test/test_hash.c b/corelib/test/test_hash.c new file mode 100644 index 0000000..06475fd --- /dev/null +++ b/corelib/test/test_hash.c @@ -0,0 +1,124 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <stddef.h> +#include <setjmp.h> +#include <stdarg.h> +#include <cmocka.h> +#include <string.h> + +#include "sslapi.h" +#include "util.h" + +struct testvector { + const char *input; + const char *sha1; + const char *sha256; +}; + +// https://www.di-mgt.com.au/sha_testvectors.html +static const struct testvector testvectors[] = { + { + .input = "abc", + .sha1 = "a9993e364706816aba3e25717850c26c9cd0d89d", + .sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + }, + { + .input = "", + .sha1 = "da39a3ee5e6b4b0d3255bfef95601890afd80709", + .sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + }, + { + .input = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + .sha1 = "84983e441c3bd26ebaae4aa1f95129e5e54670f1", + .sha256 = "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", + }, + { + .input = "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", + .sha1 = "a49b2446a02c645bf419f995b67091253a04a259", + .sha256 = "cf5b16a778af8380036ce59e7b0492370b249b11e8f07a51afac45037afee9d1", + }, +}; + +static void hex2bin(unsigned char *dest, const unsigned char *source) +{ + unsigned int val; + for (unsigned int i = 0; i < strlen((const char *)source); i += 2) { + val = from_ascii((const char *)&source[i], 2, LG_16); + dest[i / 2] = val; + } +} + +static void do_concrete_hash(const char* algo, const char* input, const char* expected_hex) +{ + int error; + uint8_t result[32] = {0}; + unsigned len = 0; + uint8_t expected_bin[32] = {0}; + struct swupdate_digest *dgst; + + dgst = swupdate_HASH_init(algo); + assert_non_null(dgst); + error = swupdate_HASH_update(dgst, (uint8_t *)input, strlen(input)); + assert_true(!error); + + error = swupdate_HASH_final(dgst, result, &len); + assert_int_equal(error, 1); + assert_int_equal(len, strlen(expected_hex) / 2); + + swupdate_HASH_cleanup(dgst); + + hex2bin(expected_bin, (uint8_t *)expected_hex); + error = swupdate_HASH_compare(expected_bin, result); + assert_true(!error); +} + +static void do_hash(const struct testvector *vector) +{ + do_concrete_hash("sha1", vector->input, vector->sha1); + do_concrete_hash("sha256", vector->input, vector->sha256); +} + +static void test_hash_vectors(void **state) +{ + unsigned i; + + (void)state; + + for (i = 0; i < sizeof(testvectors) / sizeof(testvectors[0]); ++i) { + do_hash(testvectors + i); + } +} + +static void test_hash_compare(void **state) +{ + (void)state; + + static const uint8_t a[32] = {0}; + static const uint8_t b[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; + + assert_int_equal(swupdate_HASH_compare(a, a), 0); + assert_int_equal(swupdate_HASH_compare(a, b), -1); +} + +int main(void) +{ + static const struct CMUnitTest hash_tests[] = { + cmocka_unit_test(test_hash_compare), + cmocka_unit_test(test_hash_vectors), + }; + return cmocka_run_group_tests_name("hash", hash_tests, NULL, NULL); +} diff --git a/corelib/test/test_verify.c b/corelib/test/test_verify.c new file mode 100644 index 0000000..49a4933 --- /dev/null +++ b/corelib/test/test_verify.c @@ -0,0 +1,108 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc. + */ + +#include <errno.h> +#include <fcntl.h> +#include <setjmp.h> +#include <stdarg.h> +#include <stddef.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <cmocka.h> + +#include "sslapi.h" +#include "util.h" + +#define DATADIR "corelib/test/data/" +#define SIGNATURE_FILE DATADIR "test_file_to_sign.sig" + +static int put_file_contents(const char* filename, const uint8_t* buffer, + size_t length) { + ssize_t wr; + const int fd = creat(filename, 0644); + + if (fd == -1) { + fprintf(stderr, "%s: %s\n", filename, strerror(errno)); + return -1; + } + + wr = write(fd, buffer, length); + if (wr != length) { + fprintf(stderr, "Failed to write signature file\n"); + return -2; + } + + close(fd); + return 0; +} + +static void test_verify_pkcs15(void **state) +{ + static const uint8_t signature[] = { + 0x51, 0x8c, 0x14, 0x98, 0xc0, 0x76, 0x75, 0xb2, 0x3f, 0xe9, 0x1f, 0x8c, + 0x66, 0x7f, 0x42, 0xb0, 0x34, 0x88, 0x69, 0x01, 0xae, 0xc1, 0xf1, 0x07, + 0x7c, 0xa0, 0xf5, 0x29, 0xe7, 0x25, 0xcd, 0xe5, 0x8e, 0x0e, 0x99, 0xf6, + 0x1f, 0x19, 0x14, 0x2e, 0x21, 0xcb, 0xa9, 0x44, 0xc0, 0xbb, 0xef, 0x33, + 0xd6, 0xa3, 0xbc, 0xcb, 0x33, 0x16, 0x88, 0xed, 0x7e, 0x1f, 0xd8, 0x94, + 0xcf, 0x88, 0xf8, 0x55, 0x5d, 0xe7, 0x49, 0x03, 0x52, 0x47, 0x23, 0x71, + 0x93, 0x13, 0x98, 0x1b, 0x73, 0xcf, 0xe3, 0x67, 0x39, 0x67, 0x9d, 0xae, + 0xe1, 0x9c, 0x08, 0x79, 0x01, 0x5f, 0xd4, 0x2c, 0xcf, 0xfa, 0xe8, 0x89, + 0x3b, 0x5c, 0xc9, 0x10, 0x07, 0x66, 0x52, 0xbd, 0x75, 0x84, 0x4b, 0x63, + 0x8d, 0x19, 0x43, 0x4f, 0x04, 0xb7, 0x05, 0x23, 0xf3, 0x93, 0xb7, 0x2d, + 0xd5, 0x60, 0x85, 0x96, 0xd5, 0x18, 0xfb, 0xcd, 0xd4, 0xd7, 0xe6, 0x6a, + 0x3d, 0x3f, 0x1f, 0x61, 0x61, 0x4d, 0xc0, 0x97, 0x56, 0xc7, 0x16, 0x07, + 0xc7, 0x24, 0xa2, 0x3b, 0xeb, 0x7c, 0x93, 0x64, 0x4e, 0xe5, 0x33, 0xff, + 0x9a, 0x61, 0x7b, 0x1e, 0x0f, 0xe2, 0x0d, 0x7a, 0x12, 0x5c, 0xa0, 0x3e, + 0x93, 0x27, 0x43, 0x9b, 0x5b, 0x70, 0x2f, 0x4a, 0xaf, 0xe8, 0xd7, 0x93, + 0xef, 0x89, 0xd8, 0xfc, 0x5c, 0x35, 0xa3, 0x09, 0x3b, 0xc8, 0x8e, 0xb7, + 0x30, 0x15, 0xe3, 0x4f, 0x38, 0x8d, 0x01, 0x52, 0x81, 0x02, 0x2c, 0xdd, + 0xc2, 0xc4, 0x31, 0x66, 0xfb, 0x5a, 0x7a, 0x27, 0x1b, 0xc8, 0x77, 0x3a, + 0x22, 0x9e, 0x95, 0xb2, 0x46, 0x2f, 0x88, 0x85, 0xd9, 0xe3, 0x88, 0x98, + 0x63, 0xca, 0x97, 0x8a, 0x9e, 0x43, 0x80, 0xa4, 0x9d, 0x3e, 0x70, 0x2e, + 0x60, 0xf2, 0xb3, 0x59, 0xb4, 0x1e, 0x6d, 0xf0, 0x41, 0x06, 0x4e, 0xc4, + 0x77, 0x4f, 0x24, 0x50 + }; + + int error; + struct swupdate_cfg config; + + (void)state; + + config.dgst = NULL; + error = swupdate_dgst_init(&config, DATADIR "public.pem"); + assert_int_equal(error, 0); + + error = put_file_contents(SIGNATURE_FILE, signature, sizeof(signature)); + assert_int_equal(error, 0); + + error = swupdate_verify_file(config.dgst, SIGNATURE_FILE, + DATADIR "test_file_to_sign", NULL); + assert_int_equal(error, 0); + + unlink(SIGNATURE_FILE); +} + +int main(void) +{ + swupdate_crypto_init(); + static const struct CMUnitTest verify_tests[] = { + cmocka_unit_test(test_verify_pkcs15), + }; + return cmocka_run_group_tests_name("verify", verify_tests, NULL, NULL); +} diff --git a/corelib/verify_signature.c b/corelib/verify_signature.c index 728246a..8de9de5 100644 --- a/corelib/verify_signature.c +++ b/corelib/verify_signature.c @@ -63,7 +63,7 @@ struct swupdate_digest *swupdate_HASH_init(const char *SHAlength) return dgst; } -int swupdate_HASH_update(struct swupdate_digest *dgst, unsigned char *buf, +int swupdate_HASH_update(struct swupdate_digest *dgst, const unsigned char *buf, size_t len) { if (!dgst) @@ -97,7 +97,7 @@ void swupdate_HASH_cleanup(struct swupdate_digest *dgst) /* * Just a wrap function to memcmp */ -int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2) +int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2) { int i; diff --git a/corelib/verify_signature_mbedtls.c b/corelib/verify_signature_mbedtls.c new file mode 100644 index 0000000..0dd874d --- /dev/null +++ b/corelib/verify_signature_mbedtls.c @@ -0,0 +1,106 @@ +#include <ctype.h> +#include <errno.h> + +#include "sslapi.h" +#include "util.h" + +static char *algo_upper(const char *algo) +{ + static char result[16]; + unsigned i; + + for (i = 0; algo[i] && (i < sizeof(result) - 1); ++i) { + result[i] = toupper(algo[i]); + } + result[i] = '\0'; + return result; +} + +struct swupdate_digest *swupdate_HASH_init(const char *algo) +{ + struct swupdate_digest *dgst; + int error; + + const mbedtls_md_info_t *info = mbedtls_md_info_from_string(algo_upper(algo)); + if (!info) { + ERROR("mbedtls_md_info_from_string(\"%s\")", algo); + return NULL; + } + + dgst = calloc(1, sizeof(*dgst)); + if (!dgst) { + return NULL; + } + + mbedtls_md_init(&dgst->mbedtls_md_context); + + error = mbedtls_md_setup(&dgst->mbedtls_md_context, info, 0); + if (error) { + ERROR("mbedtls_md_setup: %d", error); + goto fail; + } + + error = mbedtls_md_starts(&dgst->mbedtls_md_context); + if (error) { + ERROR("mbedtls_md_starts: %d", error); + goto fail; + } + + return dgst; + +fail: + free(dgst); + return 0; +} + +int swupdate_HASH_update(struct swupdate_digest *dgst, const unsigned char *buf, + size_t len) +{ + if (!dgst) { + return -EFAULT; + } + + const int error = mbedtls_md_update(&dgst->mbedtls_md_context, buf, len); + if (error) { + ERROR("mbedtls_md_update: %d", error); + return -EIO; + } + + return 0; +} + +int swupdate_HASH_final(struct swupdate_digest *dgst, unsigned char *md_value, + unsigned int *md_len) +{ + if (!dgst) { + return -EFAULT; + } + + int error = mbedtls_md_finish(&dgst->mbedtls_md_context, md_value); + if (error) { + return -EINVAL; + } + if (md_len) { + *md_len = mbedtls_md_get_size(dgst->mbedtls_md_context.md_info); + } + return 1; + +} + +void swupdate_HASH_cleanup(struct swupdate_digest *dgst) +{ + if (!dgst) { + return; + } + + mbedtls_md_free(&dgst->mbedtls_md_context); + free(dgst); +} + +/* + * Just a wrap function to memcmp + */ +int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2) +{ + return memcmp(hash1, hash2, SHA256_HASH_LENGTH) ? -1 : 0; +} diff --git a/include/sslapi.h b/include/sslapi.h index c66e005..1f1209b 100644 --- a/include/sslapi.h +++ b/include/sslapi.h @@ -18,6 +18,7 @@ */ #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_ENCRYPTED_IMAGES) || \ defined(CONFIG_SURICATTA_SSL) || defined(CONFIG_CHANNEL_CURL_SSL) +#if defined(CONFIG_SSL_IMPL_OPENSSL) #include <openssl/bio.h> #include <openssl/objects.h> #include <openssl/err.h> @@ -95,22 +96,47 @@ static inline uint32_t SSL_X509_get_extended_key_usage(X509 *x) #endif } +#elif defined(CONFIG_SSL_IMPL_MBEDTLS) +#include <mbedtls/md.h> +#include <mbedtls/pk.h> +#include <mbedtls/cipher.h> + +#define EVP_MAX_BLOCK_LENGTH (16) +#define swupdate_crypto_init() + +struct swupdate_digest { +#ifdef CONFIG_HASH_VERIFY + mbedtls_md_context_t mbedtls_md_context; +#endif /* CONFIG_HASH_VERIFY */ +#ifdef CONFIG_SIGNED_IMAGES + mbedtls_pk_context mbedtls_pk_context; +#endif /* CONFIG_SIGNED_IMAGES */ +#ifdef CONFIG_ENCRYPTED_IMAGES + mbedtls_cipher_context_t mbedtls_cipher_context; +#endif /* CONFIG_ENCRYPTED_IMAGES */ +}; + +#else /* CONFIG_SSL_IMPL */ +#error unknown SSL implementation +#endif /* CONFIG_SSL_IMPL */ #else #define swupdate_crypto_init() #define AES_BLOCK_SIZE 16 #endif #if defined(CONFIG_HASH_VERIFY) +struct swupdate_cfg; + int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile); struct swupdate_digest *swupdate_HASH_init(const char *SHALength); -int swupdate_HASH_update(struct swupdate_digest *dgst, unsigned char *buf, +int swupdate_HASH_update(struct swupdate_digest *dgst, const unsigned char *buf, size_t len); int swupdate_HASH_final(struct swupdate_digest *dgst, unsigned char *md_value, unsigned int *md_len); void swupdate_HASH_cleanup(struct swupdate_digest *dgst); int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile, const char *file, const char *signer_name); -int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2); +int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2); #else @@ -126,7 +152,7 @@ int swupdate_HASH_compare(unsigned char *hash1, unsigned char *hash2); #ifdef CONFIG_ENCRYPTED_IMAGES struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *key, unsigned char *iv); int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, - int *outlen, unsigned char *cryptbuf, int inlen); + int *outlen, const unsigned char *cryptbuf, int inlen); int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf, int *outlen); void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst); diff --git a/include/util.h b/include/util.h index 4c261ed..99d183f 100644 --- a/include/util.h +++ b/include/util.h @@ -10,6 +10,7 @@ #include <stdint.h> #include <string.h> +#include <stdio.h> #if defined(__linux__) #include <linux/types.h> #endif diff --git a/mongoose/Config.in b/mongoose/Config.in index 29cac90..238b6de 100644 --- a/mongoose/Config.in +++ b/mongoose/Config.in @@ -30,10 +30,11 @@ config MONGOOSESSL depends on MONGOOSE depends on HAVE_LIBSSL depends on HAVE_LIBCRYPTO + depends on SSL_IMPL_OPENSSL help It enables SSL support into mongoose comment "SSL support needs libcrypto, libssl" - depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO + depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO || !SSL_IMPL_OPENSSL endif diff --git a/suricatta/Config.in b/suricatta/Config.in index 20ac038..5db9081 100644 --- a/suricatta/Config.in +++ b/suricatta/Config.in @@ -23,11 +23,12 @@ config SURICATTA_SSL default n depends on HAVE_LIBSSL depends on HAVE_LIBCRYPTO + depends on SSL_IMPL_OPENSSL help Enable SSL and checksum verification support in suricatta. comment "SSL support needs libcrypto, libssl" - depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO + depends on !HAVE_LIBSSL || !HAVE_LIBCRYPTO || !SSL_IMPL_OPENSSL choice prompt "Update Status Storage"
This patch enables using mbedtls as an alternative implementation as opposed to openssl. CMS signatures are not supported. Signed-off-by: Laszlo Ashin <laszlo@ashin.hu> --- .travis.yml | 5 +- Kconfig | 48 +++++++--- Makefile.deps | 4 + Makefile.flags | 29 +----- configs/mbedtls_defconfig | 18 ++++ corelib/Makefile | 12 ++- corelib/swupdate_decrypt.c | 2 +- corelib/swupdate_decrypt_mbedtls.c | 100 +++++++++++++++++++++ corelib/swupdate_rsa_verify_mbedtls.c | 103 +++++++++++++++++++++ corelib/test/Makefile | 6 +- corelib/test/data/public.pem | 9 ++ corelib/test/data/test_file_to_sign | 1 + corelib/test/test_crypt.c | 4 +- corelib/test/test_hash.c | 124 ++++++++++++++++++++++++++ corelib/test/test_verify.c | 108 ++++++++++++++++++++++ corelib/verify_signature.c | 4 +- corelib/verify_signature_mbedtls.c | 106 ++++++++++++++++++++++ include/sslapi.h | 32 ++++++- include/util.h | 1 + mongoose/Config.in | 3 +- suricatta/Config.in | 3 +- 21 files changed, 668 insertions(+), 54 deletions(-) create mode 100644 configs/mbedtls_defconfig create mode 100644 corelib/swupdate_decrypt_mbedtls.c create mode 100644 corelib/swupdate_rsa_verify_mbedtls.c create mode 100644 corelib/test/data/public.pem create mode 100644 corelib/test/data/test_file_to_sign create mode 100644 corelib/test/test_hash.c create mode 100644 corelib/test/test_verify.c create mode 100644 corelib/verify_signature_mbedtls.c