From: Bastian Germann <
ba...@linutronix.de>
Add a PKCS#11 implementation for encrypted images. This replaces the
image decryption once activated. The interface stays the same but the key
is interpreted as PKCS#11 URI, which is first parsed via p11-kit. This
seems to be the most advanced parser implementation out there.
For the PKCS#11 abstraction, wolfSSL is used because it has first-class
support and AES is supported well, as opposed to OpenSSL that needs an
engine loaded at run time with the most prominent PKCS#11 engine not
supporting AES.
wolfSSL comes up with the concept of a crypto device that you register so
that the normal AES operations can be outsourced to them.
wolfSSL does not implement PKCS#7 padding in the AES operations, which is
needed because the encrypted images use it. Implement the unpadding in
swupdate_DECRYPT_final which operates on one block that is remembered from
the last AES decryption.
The decryption and PKCS#11 handling need context structs to live during
all decryption steps. Extend the existing decryption_key struct with them.
corelib/swupdate_decrypt_pkcs11.c | 183 ++++++++++++++++++++++++++++++
include/sslapi.h | 28 ++++-
2 files changed, 208 insertions(+), 3 deletions(-)
create mode 100644 corelib/swupdate_decrypt_pkcs11.c
diff --git a/corelib/swupdate_decrypt_pkcs11.c b/corelib/swupdate_decrypt_pkcs11.c
new file mode 100644
index 0000000..1ca0a93
--- /dev/null
+++ b/corelib/swupdate_decrypt_pkcs11.c
@@ -0,0 +1,183 @@
+/*
+ * (C) Copyright 2020, Linutronix GmbH
+ * Author: Bastian Germann
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "swupdate.h"
+#include "sslapi.h"
+#include "util.h"
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/logging.h>
+
+#ifdef DEBUG_WOLFSSL
+static void wolfssl_debug(int __attribute__ ((__unused__)) level, const char *const msg)
+{
+ DEBUG("%s", msg);
+}
+#endif
+
+struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *uri, unsigned char *iv)
+{
+ struct swupdate_digest *dgst;
+ const char *library;
+ const char *pin;
+ const char *msg;
+ CK_ATTRIBUTE_PTR key_id;
+ int slot_id;
+ int err = 0;
+ int dev_id = 1;
+
+ if ((uri == NULL) || (iv == NULL)) {
+ ERROR("PKCS#11 URI or AES IV missing for decryption!");
+ return NULL;
+ }
+
+ dgst = calloc(1, sizeof(*dgst));
+ if (!dgst) {
+ return NULL;
+ }
+
+ dgst->p11uri = p11_kit_uri_new();
+ err = p11_kit_uri_parse(uri, P11_KIT_URI_FOR_ANY, dgst->p11uri);
+ if (err) {
+ msg = p11_kit_uri_message(err);
+ ERROR("PKCS#11 URI: %s", msg);
+ return NULL;
+ }
+
+ slot_id = p11_kit_uri_get_slot_id(dgst->p11uri);
+ key_id = p11_kit_uri_get_attribute(dgst->p11uri, CKA_ID);
+ pin = p11_kit_uri_get_pin_value(dgst->p11uri);
+ library = p11_kit_uri_get_module_path(dgst->p11uri);
+ if (slot_id == -1 || key_id == NULL || pin == NULL || library == NULL) {
+ ERROR("PKCS#11 URI must contain slot-id, id, pin-value, and module-path.");
+ goto err_free;
+ }
+
+ // Set up a valid PKCS#7 block plus one state octet
+ for (int i = 0; i <= AES_BLK_SIZE; i++) {
+ dgst->last_decr[i] = AES_BLK_SIZE;
+ }
+
+#ifdef DEBUG_WOLFSSL
+ wolfSSL_SetLoggingCb(wolfssl_debug);
+ wolfSSL_Debugging_ON();
+#endif
+ wolfCrypt_Init();
+ err = wc_Pkcs11_Initialize(&dgst->pkdev, library, NULL);
+ if (err)
+ goto err_msg;
+
+ err = wc_Pkcs11Token_Init(&dgst->pktoken, &dgst->pkdev, slot_id,
+ "unspecified", pin, strlen(pin));
+ if (err)
+ goto err_msg;
+
+ err = wc_CryptoCb_RegisterDevice(dev_id, wc_Pkcs11_CryptoDevCb, &dgst->pktoken);
+ if (err)
+ goto err_msg;
+
+ err = wc_AesInit_Id(&dgst->ctxdec, key_id->pValue, key_id->ulValueLen, NULL, dev_id);
+ if (err)
+ goto err_msg;
+
+ err = wc_AesSetIV(&dgst->ctxdec, iv);
+ if (err)
+ goto err_msg;
+
+ INFO("PKCS#11 key set up successfully.");
+ return dgst;
+
+err_msg:
+ msg = wc_GetErrorString(err);
+ ERROR("PKCS#11 initialization failed: %s", msg);
+
+err_free:
+ if (&dgst->pktoken)
+ wc_Pkcs11Token_Final(&dgst->pktoken);
+ if (&dgst->pkdev)
+ wc_Pkcs11_Finalize(&dgst->pkdev);
+
+ p11_kit_uri_free(dgst->p11uri);
+ free(dgst);
+
+ return NULL;
+}
+
+int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf,
+ int *outlen, const unsigned char *cryptbuf, int inlen)
+{
+ unsigned char pad_buf[inlen];
+ const char *msg;
+ int err;
+ int one_off_sz = inlen - AES_BLK_SIZE;
+
+ if (inlen < AES_BLK_SIZE)
+ return -EFAULT;
+
+ err = wc_AesCbcDecrypt(&dgst->ctxdec, pad_buf, cryptbuf, inlen);
+ if (err) {
+ msg = wc_GetErrorString(err);
+ ERROR("PKCS#11 AES decryption failed: %s", msg);
+ return -EFAULT;
+ }
+
+ if (dgst->last_decr[AES_BLK_SIZE]) {
+ // This is for the first decryption operation
+ memcpy(buf, pad_buf, one_off_sz);
+ dgst->last_decr[AES_BLK_SIZE] = 0;
+ *outlen = one_off_sz;
+ } else {
+ memcpy(buf, dgst->last_decr, AES_BLK_SIZE);
+ memcpy(buf[AES_BLK_SIZE], pad_buf, one_off_sz);
+ *outlen = inlen;
+ }
+ // Remember the last decrypted block which might contain padding
+ memcpy(dgst->last_decr, &pad_buf[one_off_sz], AES_BLK_SIZE);
+
+ return 0;
+}
+
+// Gets rid of PKCS#7 padding
+int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf, int *outlen)
+{
+ unsigned char last_oct = dgst->last_decr[AES_BLK_SIZE - 1];
+ if (last_oct > AES_BLK_SIZE || last_oct == 0) {
+ ERROR("AES: Invalid PKCS#7 padding.");
+ return -EFAULT;
+ }
+
+ for (int i = 2; i <= last_oct; i++) {
+ if (dgst->last_decr[AES_BLK_SIZE - i] != last_oct) {
+ ERROR("AES: Invalid PKCS#7 padding.");
+ return -EFAULT;
+ }
+ }
+
+ *outlen = AES_BLK_SIZE - last_oct;
+ memcpy(buf, dgst->last_decr, *outlen);
+
+ return 0;
+}
+
+void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst)
+{
+ if (dgst) {
+ if (&dgst->pktoken)
+ wc_Pkcs11Token_Final(&dgst->pktoken);
+ if (&dgst->pkdev)
+ wc_Pkcs11_Finalize(&dgst->pkdev);
+ p11_kit_uri_free(dgst->p11uri);
+
+ free(dgst);
+ dgst = NULL;
+ }
+
+ wolfCrypt_Cleanup();
+}
diff --git a/include/sslapi.h b/include/sslapi.h
index 97e1f5c..5a3236a 100644
--- a/include/sslapi.h
+++ b/include/sslapi.h
@@ -18,6 +18,16 @@
*/
#if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_ENCRYPTED_IMAGES) || \
defined(CONFIG_CHANNEL_CURL_SSL)
+
+#ifdef CONFIG_PKCS11
+#include <wolfssl/options.h>
+#include <wolfssl/wolfcrypt/aes.h>
+#include <wolfssl/wolfcrypt/wc_pkcs11.h>
+// Exclude p11-kit's pkcs11.h to prevent conflicting with wolfssl's
+#define PKCS11_H 1
+#include <p11-kit/uri.h>
+#endif
+
#if defined(CONFIG_SSL_IMPL_OPENSSL) || defined(CONFIG_SSL_IMPL_WOLFSSL)
#include <openssl/bio.h>
#include <openssl/objects.h>
@@ -74,7 +84,13 @@ struct swupdate_digest {
EVP_PKEY_CTX *ckey; /* this is used for RSA key */
X509_STORE *certs; /* this is used if CMS is set */
EVP_MD_CTX *ctx;
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#ifdef CONFIG_PKCS11
+ unsigned char last_decr[AES_BLOCK_SIZE + 1];
+ P11KitUri *p11uri;
+ Aes ctxdec;
+ Pkcs11Dev pkdev;
+ Pkcs11Token pktoken;
+#elif OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
EVP_CIPHER_CTX ctxdec;
#else
EVP_CIPHER_CTX *ctxdec;
@@ -119,9 +135,15 @@ struct swupdate_digest {
#ifdef CONFIG_SIGNED_IMAGES
mbedtls_pk_context mbedtls_pk_context;
#endif /* CONFIG_SIGNED_IMAGES */
-#ifdef CONFIG_ENCRYPTED_IMAGES
+#ifdef CONFIG_PKCS11
+ unsigned char last_decr[AES_BLOCK_SIZE + 1];
+ P11KitUri *p11uri;
+ Aes ctxdec;
+ Pkcs11Dev pkdev;
+ Pkcs11Token pktoken;
+#elif defined(CONFIG_ENCRYPTED_IMAGES)
mbedtls_cipher_context_t mbedtls_cipher_context;
-#endif /* CONFIG_ENCRYPTED_IMAGES */
+#endif /* CONFIG_PKCS11 */
};
#else /* CONFIG_SSL_IMPL */
--
2.28.0