Add support for mbed TLS as crypto backend.
Contributed by Michael Balzer.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c19b45f..bea4878 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,10 +7,12 @@
PROJECT(libzip C)
-OPTION(ENABLE_GNUTLS "Enable use of GnuTLS" ON)
-OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
OPTION(ENABLE_COMMONCRYPTO "Enable use of CommonCrypto" ON)
+OPTION(ENABLE_GNUTLS "Enable use of GnuTLS" ON)
+OPTION(ENABLE_MBEDTLS "Enable use of mbed TLS" ON)
+OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
OPTION(ENABLE_WINDOWS_CRYPTO "Enable use of Windows cryptography libraries" ON)
+
OPTION(ENABLE_BZIP2 "Enable use of BZip2" ON)
OPTION(BUILD_TOOLS "Build tools in the src directory (zipcmp, zipmerge, ziptool)" ON)
@@ -38,6 +40,12 @@
ELSE()
SET(GNUTLS_FOUND FALSE)
ENDIF()
+IF(ENABLE_MBEDTLS)
+ FIND_PATH(MBEDTLS_INCLUDE_DIR mbedtls/aes.h)
+ FIND_LIBRARY(MBEDTLS_LIBRARIES NAMES mbedtls)
+ELSE()
+ SET(MBEDTLS_LIBRARIES FALSE)
+ENDIF()
IF(ENABLE_OPENSSL)
INCLUDE(FindOpenSSL)
ELSE()
@@ -223,10 +231,15 @@
SET (HAVE_OPENSSL 1)
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${OPENSSL_LIBRARIES})
+ELSEIF (MBEDTLS_LIBRARIES)
+ SET (HAVE_CRYPTO 1)
+ SET (HAVE_MBEDTLS 1)
+ INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
+ SET (OPTIONAL_LIBRARY ${OPTIONAL_LIBRARY} ${MBEDTLS_LIBRARIES})
ENDIF()
IF (NOT HAVE_CRYPTO)
- MESSAGE(WARNING "-- neither OpenSSL, GnuTLS, Common Crypto nor Windows Cryptography found; AES support disabled")
+ MESSAGE(WARNING "-- neither Common Crypto, GnuTLS, mbed TLS, OpenSSL, nor Windows Cryptography found; AES support disabled")
ENDIF()
IF(MSVC)
diff --git a/INSTALL.md b/INSTALL.md
index 053174c..eef900e 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -12,13 +12,14 @@
listed in order of preference:
- Apple's CommonCrypto (available on macOS and iOS)
-- Microsoft Windows Cryptography Framework
- [GnuTLS](https://www.gnutls.org/)
+- [mbed TLS](https://tls.mbed.org/)
- [OpenSSL](https://www.openssl.org/) >= 1.0.
+- Microsoft Windows Cryptography Framework
If you don't want a library even if it is installed, you can
pass `-DENABLE_<LIBRARY>=OFF` to cmake, where `<LIBRARY>` is one of
-`COMMONCRYPTO`, `OPENSSL`, or `GNUTLS`.
+`COMMONCRYPTO`, `GNUTLS`, `MBEDTLS`, or `OPENSSL`.
The basic usage is
```sh
diff --git a/NEWS.md b/NEWS.md
index fb93099..debe6e9 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,6 +1,7 @@
1.5.2 [201X-XX-XX]
==================
* Support systems with small stack size.
+* Support mbed TLS as crypto backend.
1.5.1 [2018-04-11]
==================
diff --git a/THANKS b/THANKS
index abdf46c..9db30fa 100644
--- a/THANKS
+++ b/THANKS
@@ -48,6 +48,7 @@
Martin Buchholz <martinrb@google.com>
Martin Herkt
Martin Szulecki <m.szulecki@libimobiledevice.org>
+Michael Balzer
Michael Beck <mm.beck@gmx.net>
MichaĆ Janiszewski
Michal Vyskocil <mvyskocil@suse.cz>
diff --git a/cmake-config.h.in b/cmake-config.h.in
index 2fa8e5b..bf8264c 100644
--- a/cmake-config.h.in
+++ b/cmake-config.h.in
@@ -29,9 +29,10 @@
#cmakedefine HAVE_GETPROGNAME
#cmakedefine HAVE_GNUTLS
#cmakedefine HAVE_LIBBZ2
+#cmakedefine HAVE_MBEDTLS
+#cmakedefine HAVE_MKSTEMP
#cmakedefine HAVE_OPEN
#cmakedefine HAVE_OPENSSL
-#cmakedefine HAVE_MKSTEMP
#cmakedefine HAVE_SETMODE
#cmakedefine HAVE_SNPRINTF
#cmakedefine HAVE_SSIZE_T_LIBZIP
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index ee27ee9..8be48a0 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -205,6 +205,9 @@
ELSEIF(HAVE_OPENSSL)
SET(LIBZIP_OPTIONAL_FILES ${LIBZIP_OPTIONAL_FILES} zip_crypto_openssl.c
)
+ELSEIF(HAVE_MBEDTLS)
+ SET(LIBZIP_OPTIONAL_FILES ${LIBZIP_OPTIONAL_FILES} zip_crypto_mbedtls.c
+)
ENDIF()
IF(HAVE_CRYPTO)
diff --git a/lib/zip_crypto.h b/lib/zip_crypto.h
index 89bd369..be8f918 100644
--- a/lib/zip_crypto.h
+++ b/lib/zip_crypto.h
@@ -45,6 +45,8 @@
#include "zip_crypto_gnutls.h"
#elif defined(HAVE_OPENSSL)
#include "zip_crypto_openssl.h"
+#elif defined(HAVE_MBEDTLS)
+#include "zip_crypto_mbedtls.h"
#else
#error "no crypto backend found"
#endif
diff --git a/lib/zip_crypto_mbedtls.c b/lib/zip_crypto_mbedtls.c
new file mode 100644
index 0000000..8e74fbc
--- /dev/null
+++ b/lib/zip_crypto_mbedtls.c
@@ -0,0 +1,160 @@
+/*
+ zip_crypto_mbedtls.c -- mbed TLS wrapper
+ Copyright (C) 2018 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+
+#include "zipint.h"
+#include "zip_crypto.h"
+
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/pkcs5.h>
+
+
+_zip_crypto_aes_t *
+_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error) {
+ _zip_crypto_aes_t *aes;
+
+ if ((aes = (_zip_crypto_aes_t *)malloc(sizeof(*aes))) == NULL) {
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
+ return NULL;
+ }
+
+ mbedtls_aes_init(aes);
+ mbedtls_aes_setkey_enc(aes, (const unsigned char *)key, (unsigned int)key_size);
+
+ return aes;
+}
+
+void
+_zip_crypto_aes_free(_zip_crypto_aes_t *aes) {
+ if (aes == NULL) {
+ return;
+ }
+
+ mbedtls_aes_free(aes);
+ free(aes);
+}
+
+
+_zip_crypto_hmac_t *
+_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error) {
+ _zip_crypto_hmac_t *hmac;
+
+ if (secret_length > INT_MAX) {
+ zip_error_set(error, ZIP_ER_INVAL, 0);
+ return NULL;
+ }
+
+ if ((hmac = (_zip_crypto_hmac_t *)malloc(sizeof(*hmac))) == NULL) {
+ zip_error_set(error, ZIP_ER_MEMORY, 0);
+ return NULL;
+ }
+
+ mbedtls_md_init(hmac);
+
+ if (mbedtls_md_setup(hmac, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 1) != 0) {
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
+ free(hmac);
+ return NULL;
+ }
+
+ if (mbedtls_md_hmac_starts(hmac, (const unsigned char *)secret, (size_t)secret_length) != 0) {
+ zip_error_set(error, ZIP_ER_INTERNAL, 0);
+ free(hmac);
+ return NULL;
+ }
+
+ return hmac;
+}
+
+
+void
+_zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac) {
+ if (hmac == NULL) {
+ return;
+ }
+
+ mbedtls_md_free(hmac);
+ free(hmac);
+}
+
+
+bool
+_zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length) {
+ mbedtls_md_context_t sha1_ctx;
+ bool ok = true;
+
+ mbedtls_md_init(&sha1_ctx);
+
+ if (mbedtls_md_setup(&sha1_ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA1), 1) != 0) {
+ ok = false;
+ }
+
+ if (ok && mbedtls_pkcs5_pbkdf2_hmac(&sha1_ctx, (const unsigned char *)key, (size_t)key_length, (const unsigned char *)salt, (size_t)salt_length, (unsigned int)iterations, (uint32_t)output_length, (unsigned char *)output) != 0) {
+ ok = false;
+ }
+
+ mbedtls_md_free(&sha1_ctx);
+ return ok;
+}
+
+
+typedef struct {
+ mbedtls_entropy_context entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+} zip_random_context_t;
+
+ZIP_EXTERN bool
+zip_random(zip_uint8_t *buffer, zip_uint16_t length) {
+ static zip_random_context_t *ctx = NULL;
+ const unsigned char *pers = "zip_crypto_mbedtls";
+
+ if (!ctx) {
+ ctx = (zip_random_context_t *)malloc(sizeof(zip_random_context_t));
+ if (!ctx) {
+ return false;
+ }
+ mbedtls_entropy_init(&ctx->entropy);
+ mbedtls_ctr_drbg_init(&ctx->ctr_drbg);
+ if (mbedtls_ctr_drbg_seed(&ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy, pers, strlen(pers)) != 0) {
+ mbedtls_ctr_drbg_free(&ctx->ctr_drbg);
+ mbedtls_entropy_free(&ctx->entropy);
+ free(ctx);
+ ctx = NULL;
+ return false;
+ }
+ }
+
+ return mbedtls_ctr_drbg_random(&ctx->ctr_drbg, (unsigned char *)buffer, (size_t)length) == 0;
+}
diff --git a/lib/zip_crypto_mbedtls.h b/lib/zip_crypto_mbedtls.h
new file mode 100644
index 0000000..af22d5b
--- /dev/null
+++ b/lib/zip_crypto_mbedtls.h
@@ -0,0 +1,54 @@
+/*
+ zip_crypto_mbedtls.h -- definitions for mbedtls wrapper
+ Copyright (C) 2018 Dieter Baron and Thomas Klausner
+
+ This file is part of libzip, a library to manipulate ZIP archives.
+ The authors can be contacted at <libzip@nih.at>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 3. The names of the authors may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
+ IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HAD_ZIP_CRYPTO_MBEDTLS_H
+#define HAD_ZIP_CRYPTO_MBEDTLS_H
+
+#include <mbedtls/aes.h>
+#include <mbedtls/md.h>
+
+#define _zip_crypto_aes_t mbedtls_aes_context
+#define _zip_crypto_hmac_t mbedtls_md_context_t
+
+_zip_crypto_aes_t *_zip_crypto_aes_new(const zip_uint8_t *key, zip_uint16_t key_size, zip_error_t *error);
+#define _zip_crypto_aes_encrypt_block(aes, in, out) (mbedtls_aes_crypt_ecb((aes), MBEDTLS_AES_ENCRYPT, (in), (out)) == 0)
+void _zip_crypto_aes_free(_zip_crypto_aes_t *aes);
+
+_zip_crypto_hmac_t *_zip_crypto_hmac_new(const zip_uint8_t *secret, zip_uint64_t secret_length, zip_error_t *error);
+#define _zip_crypto_hmac(hmac, data, length) (mbedtls_md_hmac_update((hmac), (data), (length)) == 0)
+#define _zip_crypto_hmac_output(hmac, data) (mbedtls_md_hmac_finish((hmac), (data)) == 0)
+void _zip_crypto_hmac_free(_zip_crypto_hmac_t *hmac);
+
+bool _zip_crypto_pbkdf2(const zip_uint8_t *key, zip_uint64_t key_length, const zip_uint8_t *salt, zip_uint16_t salt_length, int iterations, zip_uint8_t *output, zip_uint64_t output_length);
+
+#endif /* HAD_ZIP_CRYPTO_MBEDTLS_H */