From patchwork Thu Oct 17 21:08:06 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matej Zachar X-Patchwork-Id: 1998790 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=googlegroups.com header.i=@googlegroups.com header.a=rsa-sha256 header.s=20230601 header.b=Q7eSHZg3; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=EN6dY6fy; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2607:f8b0:4864:20::c38; helo=mail-oo1-xc38.google.com; envelope-from=swupdate+bncbdfl57px7ufbb3eky24amgqeto5tnoy@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-oo1-xc38.google.com (mail-oo1-xc38.google.com [IPv6:2607:f8b0:4864:20::c38]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4XV1bQ6z6qz1xw2 for ; Fri, 18 Oct 2024 08:45:21 +1100 (AEDT) Received: by mail-oo1-xc38.google.com with SMTP id 006d021491bc7-5e80448f56fsf987758eaf.1 for ; Thu, 17 Oct 2024 14:45:21 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1729201517; cv=pass; d=google.com; s=arc-20240605; b=VpYav5FQ7nAnJAGfSRoXd6KPWxPdGp95jo6uFsiIDp4RxgR8CHQDi8lzpNH4Bto5KR IdMEQj73QrplKhqPj1RYTJM2wnvBMzd7rx+2jORn9yDxYHY/MljkW+8eTZ6fsHwOUGLq ypO6Zwa/pNdNnczF+4pL2HA5SOv4Txk8jaBz7tTYABjMFBBCcs3DwSYVU/yc/uIpUhwz B7VEG72xradqNNzZr5VQ6Y3up5jFKQY+EMCAXNN1JJ6Y1L9C6rHE7S93oqsWLGdxvC37 EdOkYkFjhFdKos+wkAIjj6PQCLNHYdYiHZsbrSyTqKNJ25q6AkeXtFYw/INT6Kv4gjaQ AQiw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:to:subject:message-id:date:from :mime-version:sender:dkim-signature:dkim-signature; bh=IZvfCHlqpLWrzR1TElsf5yzDmFor0jh4gh9VyF8diIU=; fh=MYhqqzxsOyxusAKC+KAcEpysWwGVCj8EkMFou+rzdZk=; b=XypfvHXG817/Q+RBng0PCI70lBwRcGzZVy/44ozp1kabvMzNy1gyhPitW/2pQMkMef e8spZ5l0ZZrKXvffKQ7qSVMib8co4qVmJ3lQ5i8BqkzARL9KRp38u+csy/sh2u9Y9LpR lqy2UAixEI9MQAz6jttyn/8UN74/D7dSv0mpf670vGFJVMbKH648o9RAIjEmeIuGKPEN vHTunOpkR7mxj6TxR+FqTTZPj4I3wULvpZyMGQToFheQi166X1maCqgHpZUZN1P/unpC oMAHn/PLEp2Qib73N/Vyggj9q57+WzEzL0LGxLg79fK7K762T98+xAQw75uUWG08zw/w 2WiQ==; darn=patchwork.ozlabs.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=k6lWvkBg; spf=pass (google.com: domain of zachar.matej@gmail.com designates 2607:f8b0:4864:20::52c as permitted sender) smtp.mailfrom=zachar.matej@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1729201517; x=1729806317; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:to:subject:message-id:date:from:mime-version :sender:from:to:cc:subject:date:message-id:reply-to; bh=IZvfCHlqpLWrzR1TElsf5yzDmFor0jh4gh9VyF8diIU=; b=Q7eSHZg3OvNRqbn4QU43t+Tec0R3r8oojHstMfjOt2q7giMcYTDhqjd7o7EjiRcWty knWs6YgEw/gl7XDHtR+6xEy3XysMqaOnypuvGClGtQcO8faKpgivrDvDqv3Y6i7HoxCp P5MPQOpZI1vkZjoj5xsqacbFqlKFg9KeqJ5SWdfo7NicjqEMfTlcUzm/xg+5bgbzn6Xo r3k2fx/M9T78G71HPpv5XdMamX44/N42tD8l3qKwc/TN7vOGHCaMIwPSs4TRZJFoz/w2 PyIUYpnJQ8fNT3/ydWcjrWDorMaiLepzM8pkusaYClKEzZyHo+mvx9xqf6dHCnag/1L3 5y/g== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1729201517; x=1729806317; darn=patchwork.ozlabs.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:to:subject:message-id:date:from:mime-version:from :to:cc:subject:date:message-id:reply-to; bh=IZvfCHlqpLWrzR1TElsf5yzDmFor0jh4gh9VyF8diIU=; b=EN6dY6fyBG3rFTavGZeEKSNmq1B8WizevuveQFaOv8rvXbBDjJHREke8gMwZjR4B8q Datjnipv8Tp45EP/ntDU5PjkODLoTxehj8E4dOAdZ/txcfymcBUqkeORXZ0ZxuBfYhZ7 HpvfidBHCshtybbkIPJ5nzc7UwulWIG5yxU7oZc/GFX+diiEe7Z8GFDBmqTX9Y+EsBB1 3QyNLXk7Ca0b2HiJFdOBZN8gYd6oYqHfjEj286MxLjEgZFgg93iARm5kbElZshJZnf0d yAK5Cq3y2MObG2NPnYZVi6EwksolIfi02UDEBj5ZzunycPWC0r5BscInrNU1+CLkPyvB 2hgg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1729201517; x=1729806317; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:to:subject:message-id:date:from:mime-version :x-beenthere:x-gm-message-state:sender:from:to:cc:subject:date :message-id:reply-to; bh=IZvfCHlqpLWrzR1TElsf5yzDmFor0jh4gh9VyF8diIU=; b=B3duy/ZCvpQ/yT3fNP14OiVXVPUJrp6wpzhpZESJV0vBTPhLbbH0XLUptmoqTCTU/H gNoOer7RHNBL2QRt4MohKoKa+5k0e9/mlxTTEi9FwQzIvzm0Rbsz51+fP96LOW6DPnHX 05uSaQetM+9Go2oOvqDBytp4CvuO6n3VzqLZKrHu2budn1/kEeKL8NTPppqWKXNpTcrn X+rmNT2bTqgRXXuHPd/fkOh4j7Bm0bmnqf6zdFijlf0Vk0xdvAvbvLD7F/uxoFzH71MO ddrrId13KK6sGCIgj+H+lZv4m+x8EzWRPUqUZdyMk/kIKxMxJrotHZGNe54y3GLlSDre 2QJA== Sender: swupdate@googlegroups.com X-Forwarded-Encrypted: i=2; AJvYcCUQbBss90N5x9Mde6JDSm8sYYUDqcw4A5dfHy5jO+k6wIU/nvFhrDqnnTpZMhoWLs+oYJtUc9njCg==@patchwork.ozlabs.org X-Gm-Message-State: AOJu0YzzJwbf624xWa4pPGV02AMRqTPQtpY8pZwqWzBFkj2iPXJw8MXV W4UY5lPpRAF/Yly8HuuFuZ3WVHnLWKjGatbG29q1SRPWLWAZbSe8 X-Google-Smtp-Source: AGHT+IGFqQwgLgrWjVqlbDaCuhOHHbOSjFhzKvZyAFwgbvYLXoqY31OfSLUxZcb2rBSJ/CHUYGdgZQ== X-Received: by 2002:a05:6820:22a8:b0:5e7:c8d9:95f1 with SMTP id 006d021491bc7-5eb8b70379fmr207528eaf.7.1729201517381; Thu, 17 Oct 2024 14:45:17 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6820:34a:b0:5e9:8cbc:8a74 with SMTP id 006d021491bc7-5eb6b8bbc70ls945926eaf.0.-pod-prod-09-us; Thu, 17 Oct 2024 14:45:16 -0700 (PDT) X-Received: by 2002:a05:6808:1b25:b0:3e3:e0d6:1430 with SMTP id 5614622812f47-3e602cfa5a5mr112703b6e.28.1729201516565; Thu, 17 Oct 2024 14:45:16 -0700 (PDT) Received: by 2002:aca:1714:0:b0:3e0:34ec:bb48 with SMTP id 5614622812f47-3e60148ecb0msb6e; Thu, 17 Oct 2024 14:08:19 -0700 (PDT) X-Received: by 2002:a05:6e02:1aa8:b0:39e:6e47:814d with SMTP id e9e14a558f8ab-3a3f4050940mr1591165ab.2.1729199298487; Thu, 17 Oct 2024 14:08:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1729199298; cv=none; d=google.com; s=arc-20240605; b=VIpSD6oUP7mAfES8NTQZnKUhBrfPZ4c/Dpu9aKi+9qNp/FDb8V1yCqiLgHBgt9NcS/ ZU4bYjqjAad5UPs4tyq6ZZ+/84F+MsQEgZHvfNfMXLUXWYQd+XdZxmvhh4HRZRVAE29q ZwXE1uMg6P0xOsdLOSzBsdtjGYfdCjcQ+e8J4/bQeckVVmFHA9Y7wWbMJus10iJzw3rD OAGedEfs6yQkqqHNZ0veq6lv19pEX5g8fphWjnv8C1KhnvEyVUpM09wes4wM/TYlXAfw ojuNLjfIu7TJ4iJlh8B5rXC27iGCjI0IsCCS5BGkhAPIMLwpdtrzxDdLZvzje4/MFHzm kiGw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=8GvLz3XSGntsQI8FOTrA9OY32hHwp7sE5hkpmUW22Nc=; fh=nvZsCFpxgpf+fsVXzjnWA8g1K3V/kNbRAKogjNDW4HY=; b=Y9a86PCk/af0TnuyahfYNLezpFp0yQucOiyrLm/ttET1VYhE8bQrK2nzCeOw1vqLnW CS322+KbW5hFUqSv0W5cES7AKjxAe7LXn4yY0UrGXGzZn6Ebnp1nm/TRBbU9wpS/ehni wD+k8p2ZAkX+ySuA8jaQkn/dRiSYmQoDnKghZvsRJ13JPmyG2i0AreWx/pwyOu3CkiP1 JQ6hqSgmaruag4BtEU/8X3Bwc2EMFhzMd78pbcQ/2VlKtYsZkIxYrpqnYdcIZkSgdfjo Fn2ZI9evcA4f76TgJwxILvtsJ6XfiBd2Gl4n/iqrJNJw3yANvrmV7Av2eC+B/LYwHQvK usvQ==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=k6lWvkBg; spf=pass (google.com: domain of zachar.matej@gmail.com designates 2607:f8b0:4864:20::52c as permitted sender) smtp.mailfrom=zachar.matej@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com Received: from mail-pg1-x52c.google.com (mail-pg1-x52c.google.com. [2607:f8b0:4864:20::52c]) by gmr-mx.google.com with ESMTPS id e9e14a558f8ab-3a3f3fe9da1si47685ab.2.2024.10.17.14.08.18 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 17 Oct 2024 14:08:18 -0700 (PDT) Received-SPF: pass (google.com: domain of zachar.matej@gmail.com designates 2607:f8b0:4864:20::52c as permitted sender) client-ip=2607:f8b0:4864:20::52c; Received: by mail-pg1-x52c.google.com with SMTP id 41be03b00d2f7-7ea9739647bso972385a12.0 for ; Thu, 17 Oct 2024 14:08:18 -0700 (PDT) X-Received: by 2002:a05:6a21:e91:b0:1d9:1a77:3875 with SMTP id adf61e73a8af0-1d92c5839e5mr296384637.42.1729199297400; Thu, 17 Oct 2024 14:08:17 -0700 (PDT) MIME-Version: 1.0 From: Matej Zachar Date: Thu, 17 Oct 2024 23:08:06 +0200 Message-ID: Subject: [swupdate] [PATCH] Increased PKCS#11 decryption performance with p11-kit To: swupdate@googlegroups.com X-Original-Sender: zachar.matej@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=k6lWvkBg; spf=pass (google.com: domain of zachar.matej@gmail.com designates 2607:f8b0:4864:20::52c as permitted sender) smtp.mailfrom=zachar.matej@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com; dara=pass header.i=@googlegroups.com Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , Hi, I had poor decryption performance with my board which is using opTee + pkcs11 TA backed by RPMB storage when using encrypted .swu images. After digging a bit deeper I found out that wolfSSL is not keeping the pkcs11 decryption context as it is using "C_Decrypt" function internally for each decryption block instead of calling "C_DecryptUpdate" and after all the blocks are processed "C_DecryptFinal". I created another PKCS#11 decryption implementation using pure p11-kit APIs where the context is kept during decryption. This resulted in reducing flash time from ~50minutes to ~3minutes. I also added test using softhsm2 for PKCS#11 decryption If I missed something just let me know From 14061da90bf9c1e6a5907d3e26b1a2ac99c2f6b9 Mon Sep 17 00:00:00 2001 From: Matej Zachar Date: Thu, 17 Oct 2024 22:27:45 +0200 Subject: [PATCH] Increased PKCS#11 decryption performance with p11-kit On platforms using "opTee + pkcs11 TA + RPMB" the decryption speed is increased by order of magnitude - as the C_DecryptInit context is not lost between decryption updates (C_DecryptUpdate). On my board (iMX8MP) it went from 50min with wolfSSL to 3min with p11-kit Signed-off-by: Matej Zachar --- Kconfig | 28 +- Makefile.flags | 2 +- corelib/Makefile | 12 +- corelib/swupdate_decrypt_pkcs11_p11kit.c | 290 ++++++++++++++++++ ...11.c => swupdate_decrypt_pkcs11_wolfssl.c} | 0 include/sslapi.h | 23 +- test/Makefile | 31 +- test/data/token/softhsm.conf | 2 + test/test_crypt_pkcs11.c | 99 ++++++ 9 files changed, 475 insertions(+), 12 deletions(-) create mode 100644 corelib/swupdate_decrypt_pkcs11_p11kit.c rename corelib/{swupdate_decrypt_pkcs11.c => swupdate_decrypt_pkcs11_wolfssl.c} (100%) create mode 100644 test/data/token/softhsm.conf create mode 100644 test/test_crypt_pkcs11.c + +int main(void) +{ + const struct CMUnitTest crypt_pkcs11_tests[] = { + cmocka_unit_test(test_crypt_pkcs11_256) + }; + return cmocka_run_group_tests_name("crypt_pkcs11", crypt_pkcs11_tests, NULL, NULL); +} \ No newline at end of file diff --git a/Kconfig b/Kconfig index 7139617c..1ee70cb9 100644 --- a/Kconfig +++ b/Kconfig @@ -516,11 +516,33 @@ config ENCRYPTED_IMAGES_HARDEN_LOGGING config PKCS11 bool "Enable PKCS#11 cryptographic operations" default n - depends on HAVE_WOLFSSL && HAVE_P11KIT && ENCRYPTED_IMAGES + depends on HAVE_P11KIT && ENCRYPTED_IMAGES help Enable using PKCS#11 for AES decryption instead of having the plain - key available in a file. This is implemented with wolfSSL independent - from the SSL implementation and replaces the plain key method. + key available in a file. + +choice + prompt "PKCS#11 implementation" + depends on PKCS11 + default PKCS11_IMPL_WOLFSSL + help + Select PKCS#11 implementation provider + + config PKCS11_IMPL_WOLFSSL + bool "wolfSSL" + depends on HAVE_WOLFSSL && HAVE_P11KIT && ENCRYPTED_IMAGES + help + Enable using PKCS#11 for AES decryption instead of having the plain + key available in a file. This is implemented with wolfSSL independent + from the SSL implementation and replaces the plain key method. + + config PKCS11_IMPL_P11KIT + bool "P11-KIT" + depends on HAVE_P11KIT && ENCRYPTED_IMAGES + help + Enable using PKCS#11 for AES decryption instead of having the plain + key available in a file. This is implemented with p11-kit api +endchoice comment "Compressors (zlib always on)" diff --git a/Makefile.flags b/Makefile.flags index 8598f38d..ae0e13ed 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -149,7 +149,7 @@ endif ifeq ($(CONFIG_SSL_IMPL_WOLFSSL),y) KBUILD_CPPFLAGS += -DOPENSSL_ALL LDLIBS += wolfssl -else ifeq ($(CONFIG_PKCS11),y) +else ifeq ($(CONFIG_PKCS11_IMPL_WOLFSSL),y) LDLIBS += wolfssl endif diff --git a/corelib/Makefile b/corelib/Makefile index 5917e379..ea510fe5 100644 --- a/corelib/Makefile +++ b/corelib/Makefile @@ -11,8 +11,10 @@ lib-$(CONFIG_MTD) += mtd-interface.o lib-$(CONFIG_LUA) += lua_interface.o lua_compat.o ifeq ($(CONFIG_SSL_IMPL_OPENSSL)$(CONFIG_SSL_IMPL_WOLFSSL),y) lib-$(CONFIG_HASH_VERIFY) += verify_signature.o -ifeq ($(CONFIG_PKCS11),y) -lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11.o +ifeq ($(CONFIG_PKCS11_IMPL_WOLFSSL),y) +lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11_wolfssl.o +else ifeq ($(CONFIG_PKCS11_IMPL_P11KIT),y) +lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11_p11kit.o else lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_openssl.o endif @@ -27,8 +29,10 @@ lib-$(CONFIG_SIGALG_CMS) += swupdate_pkcs7_verify.o endif ifeq ($(CONFIG_SSL_IMPL_MBEDTLS),y) lib-$(CONFIG_HASH_VERIFY) += verify_signature_mbedtls.o -ifeq ($(CONFIG_PKCS11),y) -lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11.o +ifeq ($(CONFIG_PKCS11_IMPL_WOLFSSL),y) +lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11_wolfssl.o +else ifeq ($(CONFIG_PKCS11_IMPL_P11KIT),y) +lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_pkcs11_p11kit.o else lib-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_mbedtls.o endif diff --git a/corelib/swupdate_decrypt_pkcs11_p11kit.c b/corelib/swupdate_decrypt_pkcs11_p11kit.c new file mode 100644 index 00000000..49cd929a --- /dev/null +++ b/corelib/swupdate_decrypt_pkcs11_p11kit.c @@ -0,0 +1,290 @@ +// SPDX-FileCopyrightText: 2024 Matej Zachar +// +// SPDX-License-Identifier: GPL-2.0-only +/* + * Inspired by the wolfssl implementation done by Bastian Germann + */ + +#include +#include +#include +#include +#include "swupdate.h" +#include "sslapi.h" +#include "util.h" + +static CK_SLOT_ID find_slot(CK_FUNCTION_LIST_PTR module, P11KitUri *uri) +{ + CK_RV rv; + + CK_SLOT_ID slot_id = p11_kit_uri_get_slot_id(uri); + if (slot_id != (CK_SLOT_ID)-1) + return slot_id; + + size_t slot_count; + rv = module->C_GetSlotList(1, NULL_PTR, &slot_count); + if (rv != CKR_OK) + return (CK_SLOT_ID)-1; + + CK_SLOT_ID slot_ids[slot_count]; + rv = module->C_GetSlotList(1, &slot_ids[0], &slot_count); + if (rv != CKR_OK) + return (CK_SLOT_ID)-1; + + CK_TOKEN_INFO token_info; + for (int i = 0; i < slot_count; ++i) { + slot_id = slot_ids[i]; + + rv = module->C_GetTokenInfo(slot_id, &token_info); + if (rv != CKR_OK) + return (CK_SLOT_ID)-1; + + if (p11_kit_uri_match_token_info(uri, &token_info)) + return slot_id; + } + + return (CK_SLOT_ID)-1; +} + +static CK_RV find_key(CK_FUNCTION_LIST_PTR module, CK_SESSION_HANDLE session, + CK_ATTRIBUTE_PTR key_id, CK_OBJECT_HANDLE *key_handle) +{ + CK_RV rv; + + CK_ATTRIBUTE find_template[] = { + { CKA_ID, key_id->pValue, key_id->ulValueLen } + }; + + rv = module->C_FindObjectsInit(session, find_template, 1); + if (rv != CKR_OK) { + return rv; + } + + CK_ULONG object_count; + rv = module->C_FindObjects(session, key_handle, 1, &object_count); + if (rv != CKR_OK) { + return rv; + } + + rv = module->C_FindObjectsFinal(session); + if (rv != CKR_OK) { + return rv; + } + + if (object_count == 0) { + return CKR_DATA_INVALID; + } + + return CKR_OK; +} + +struct swupdate_digest *swupdate_DECRYPT_init(unsigned char *uri, + char __attribute__ ((__unused__)) keylen, unsigned char *iv) +{ + struct swupdate_digest *dgst; + CK_SLOT_ID slot_id; + CK_ATTRIBUTE_PTR key_id; + const char *pin; + const char *module_path; + const char *msg; + int err = 0; + CK_RV rv; + + 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->uri = p11_kit_uri_new(); + err = p11_kit_uri_parse((const char*)uri, P11_KIT_URI_FOR_OBJECT_ON_TOKEN_AND_MODULE, dgst->uri); + if (err) { + msg = p11_kit_uri_message(err); + ERROR("PKCS#11 URI: %s", msg); + goto free_digest; + } + + key_id = p11_kit_uri_get_attribute(dgst->uri, CKA_ID); + pin = p11_kit_uri_get_pin_value(dgst->uri); + module_path = p11_kit_uri_get_module_path(dgst->uri); + if (key_id == NULL || pin == NULL || module_path == NULL) { + ERROR("PKCS#11 URI must contain id, pin-value and module-path."); + goto free_digest; + } + + dgst->module = p11_kit_module_load(module_path, 0); + if (dgst->module == NULL) { + msg = p11_kit_message(); + ERROR("Failed to load PKCS#11 module [%s]: %s\n", module_path, msg); + goto free_digest; + } + + rv = dgst->module->C_Initialize(NULL_PTR); + if (rv != CKR_OK) + goto err_msg; + + slot_id = find_slot(dgst->module, dgst->uri); + if (slot_id == -1) { + ERROR("PKCS#11 URI must contain slot-id or token identification such as token, model, serial, manufacturer."); + goto free_digest; + } + + rv = dgst->module->C_OpenSession(slot_id, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL_PTR, NULL_PTR, &dgst->session); + if (rv != CKR_OK) + goto err_msg; + + rv = dgst->module->C_Login(dgst->session, CKU_USER, (unsigned char *)pin, strnlen(pin, 32)); + if (rv != CKR_OK) + goto err_msg; + + CK_OBJECT_HANDLE key; + rv = find_key(dgst->module, dgst->session, key_id, &key); + if (rv != CKR_OK) + goto err_msg; + + // Setup a valid PKCS#7 block plus one state octet + for (int i = 0; i <= AES_BLK_SIZE; ++i) { + dgst->last[i] = AES_BLK_SIZE; + } + + // Setup IV vector & mechanism + memcpy(dgst->iv, iv, AES_BLOCK_SIZE); + dgst->mechanism.mechanism = CKM_AES_CBC; + dgst->mechanism.pParameter = dgst->iv; + dgst->mechanism.ulParameterLen = AES_BLOCK_SIZE; + + rv = dgst->module->C_DecryptInit(dgst->session, &dgst->mechanism, key); + if (rv != CKR_OK) + goto err_msg; + + INFO("PKCS#11 key set up successfully."); + return dgst; + +err_msg: + msg = p11_kit_strerror(rv); + ERROR("PKCS#11 initialization failed: %s", msg); + +free_digest: + if (dgst->uri) + p11_kit_uri_free(dgst->uri); + + if (dgst->session) + dgst->module->C_CloseSession(dgst->session); + + if (dgst->module) { + dgst->module->C_Finalize(NULL_PTR); + p11_kit_module_release(dgst->module); + } + + free(dgst); + + return NULL; +} + +int swupdate_DECRYPT_update(struct swupdate_digest *dgst, unsigned char *buf, + int *outlen, const unsigned char *cryptbuf, int inlen) +{ + // precondition: len(buf) >= inlen + AES_BLK_SIZE + unsigned long buf_len = inlen + AES_BLOCK_SIZE; + CK_RV rv; + + if (inlen < AES_BLK_SIZE) + return -EFAULT; + + if (dgst->last[AES_BLOCK_SIZE]) { + dgst->last[AES_BLOCK_SIZE] = 0; + // first run - there is no block to append + *outlen = 0; + } else { + // append previously decrypted last AES block + memcpy(buf, dgst->last, AES_BLOCK_SIZE); + buf += AES_BLOCK_SIZE; + *outlen = AES_BLOCK_SIZE; + } + + rv = dgst->module->C_DecryptUpdate(dgst->session, (unsigned char*)cryptbuf, inlen, buf, &buf_len); + if (rv != CKR_OK) { + ERROR("PKCS#11 AES decryption failed: %s", p11_kit_strerror(rv)); + return -EFAULT; + } + + // strip and remember last AES block from decoded buffer + // it will get appended either in the next call to DECRYPT_update or DECRYPT_final + buf_len -= AES_BLOCK_SIZE; + memcpy(dgst->last, &buf[buf_len], AES_BLOCK_SIZE); + + // update iv for the next block + memcpy(dgst->iv, cryptbuf + inlen - AES_BLOCK_SIZE, AES_BLOCK_SIZE); + + *outlen += (int)buf_len; + return 0; +} + +int swupdate_DECRYPT_final(struct swupdate_digest *dgst, unsigned char *buf, int *outlen) +{ + CK_RV rv; + unsigned long extra_len = 0; + + if (dgst->last[AES_BLOCK_SIZE]) { +#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING + ERROR("AES: At least one call to swupdate_DECRYPT_update was expected"); +#endif + return -EINVAL; + } + + // append previously decrypted last AES block if any + memcpy(buf, dgst->last, AES_BLOCK_SIZE); + + rv = dgst->module->C_DecryptFinal(dgst->session, &buf[AES_BLOCK_SIZE], &extra_len); + if (rv != CKR_OK) + return -EFAULT; + + // obtain last AES block after C_DecryptFinal + CK_BYTE_PTR last = &buf[extra_len]; + + // Handle manual PKCS#7 padding removal + CK_BYTE padding_value = last[AES_BLOCK_SIZE - 1]; + + if (padding_value <= 0 || padding_value > AES_BLOCK_SIZE) { +#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING + ERROR("AES: Invalid PKCS#7 padding value [%u]", padding_value); +#endif + return -EFAULT; + } + + // Verify that padding is correct + for (CK_BYTE i = 0; i < padding_value; ++i) { + if (last[AES_BLOCK_SIZE - 1 - i] != padding_value) { +#ifndef CONFIG_ENCRYPTED_IMAGES_HARDEN_LOGGING + ERROR("AES: Invalid PKCS#7 padding value [%u] at offset %u", padding_value, i); +#endif + return -EINVAL; + } + } + + *outlen = (int)extra_len + AES_BLOCK_SIZE - padding_value; + return 0; +} + +void swupdate_DECRYPT_cleanup(struct swupdate_digest *dgst) +{ + if (dgst) { + if (dgst->uri) + p11_kit_uri_free(dgst->uri); + + if (dgst->session) + dgst->module->C_CloseSession(dgst->session); + + if (dgst->module) { + dgst->module->C_Finalize(NULL_PTR); + p11_kit_module_release(dgst->module); + } + + free(dgst); + dgst = NULL; + } +} diff --git a/corelib/swupdate_decrypt_pkcs11.c b/corelib/swupdate_decrypt_pkcs11_wolfssl.c similarity index 100% rename from corelib/swupdate_decrypt_pkcs11.c rename to corelib/swupdate_decrypt_pkcs11_wolfssl.c diff --git a/include/sslapi.h b/include/sslapi.h index 64640184..184ee0db 100644 --- a/include/sslapi.h +++ b/include/sslapi.h @@ -19,6 +19,7 @@ #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_ENCRYPTED_IMAGES) #ifdef CONFIG_PKCS11 +#ifdef CONFIG_PKCS11_IMPL_WOLFSSL #include #include #include @@ -26,6 +27,10 @@ // Exclude p11-kit's pkcs11.h to prevent conflicting with wolfssl's #define PKCS11_H 1 #include +#elif defined(CONFIG_PKCS11_IMPL_P11KIT) +#include +#include +#endif #endif #ifdef CONFIG_SSL_IMPL_OPENSSL @@ -99,12 +104,19 @@ 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; -#ifdef CONFIG_PKCS11 +#ifdef CONFIG_PKCS11_IMPL_WOLFSSL unsigned char last_decr[AES_BLOCK_SIZE + 1]; P11KitUri *p11uri; Aes ctxdec; Pkcs11Dev pkdev; Pkcs11Token pktoken; +#elif defined(CONFIG_PKCS11_IMPL_P11KIT) + P11KitUri *uri; + CK_FUNCTION_LIST_PTR module; + CK_SESSION_HANDLE session; + CK_MECHANISM mechanism; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_BYTE last[AES_BLOCK_SIZE + 1]; #elif OPENSSL_VERSION_NUMBER < 0x10100000L EVP_CIPHER_CTX ctxdec; #else @@ -155,12 +167,19 @@ struct swupdate_digest { #ifdef CONFIG_SIGNED_IMAGES mbedtls_pk_context mbedtls_pk_context; #endif /* CONFIG_SIGNED_IMAGES */ -#ifdef CONFIG_PKCS11 +#ifdef CONFIG_PKCS11_IMPL_WOLFSSL unsigned char last_decr[AES_BLOCK_SIZE + 1]; P11KitUri *p11uri; Aes ctxdec; Pkcs11Dev pkdev; Pkcs11Token pktoken; +#elif defined(CONFIG_PKCS11_IMPL_P11KIT) + P11KitUri *uri; + CK_FUNCTION_LIST_PTR module; + CK_SESSION_HANDLE session; + CK_MECHANISM mechanism; + CK_BYTE iv[AES_BLOCK_SIZE]; + CK_BYTE last[AES_BLOCK_SIZE + 1]; #elif defined(CONFIG_ENCRYPTED_IMAGES) mbedtls_cipher_context_t mbedtls_cipher_context; #endif /* CONFIG_PKCS11 */ diff --git a/test/Makefile b/test/Makefile index ad26b40d..af7e3e39 100644 --- a/test/Makefile +++ b/test/Makefile @@ -17,7 +17,9 @@ ## along with this program; if not, write to the Free Software ## Foundation, Inc. -ifneq ($(CONFIG_PKCS11),y) +ifeq ($(CONFIG_PKCS11),y) +tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt_pkcs11 +else tests-$(CONFIG_ENCRYPTED_IMAGES) += test_crypt endif tests-$(CONFIG_HASH_VERIFY) += test_hash @@ -56,7 +58,7 @@ quiet_cmd_linktestexe = LD $(basename $@) "$(SWLIBS)" \ "$(LDLIBS) cmocka" -EXECUTE_TEST = echo "RUN $(subst $(obj)/,,$(var))"; LD_LIBRARY_PATH=$(objtree) CMOCKA_MESSAGE_OUTPUT=TAP $(var) +EXECUTE_TEST = echo "RUN $(subst $(obj)/,,$(var))"; LD_LIBRARY_PATH=$(objtree) CMOCKA_MESSAGE_OUTPUT=TAP SOFTHSM2_CONF=$(DATADIR)/token/softhsm.conf $(var) PHONY += default default: @@ -97,4 +99,29 @@ $(DATADIR)/signing-secret.pem: $(if $(Q),@echo " GEN $@") $(Q)openssl genrsa -out $@ 2>/dev/null +ifeq ($(CONFIG_PKCS11),y) +$(obj)/test_crypt_pkcs11.o: $(DATADIR)/softshm + +TOKEN_AES_KEY := dd020ce5ebd5c468556288d6a75169c88a5b335d9f569e30751c50401467d230 +TOKEN_AES_IV := c1f390d21dd06118cbd333144a3318ca + +.INTERMEDIATE: $(DATADIR)/softshm +$(DATADIR)/softshm: export SOFTHSM2_CONF=$(DATADIR)/token/softhsm.conf +$(DATADIR)/softshm: $(DATADIR)/token/softhsm.conf + $(if $(Q),@echo " INIT $@") + $(Q)rm -rf $(DATADIR)/token/*/ + + $(if $(Q),@echo " GEN $(DATADIR)/token/original.data") + $(Q)openssl rand 131075 > $(DATADIR)/token/original.data + + $(if $(Q),@echo " ENCRYPT $(DATADIR)/token/original.data") + $(Q)openssl enc -aes-256-cbc -in $(DATADIR)/token/original.data -out $(DATADIR)/token/encrypted.data -K $(TOKEN_AES_KEY) -iv $(TOKEN_AES_IV) + $(Q)echo -n "$(TOKEN_AES_IV)" | xxd -p -r > $(DATADIR)/token/encrypted.data.iv + + $(if $(Q),@echo " IMPORT $(DATADIR)/token/aes.key") + $(Q)echo -n "$(TOKEN_AES_KEY)" | xxd -p -r > $(DATADIR)/token/aes.key + $(Q)softhsm2-util --init-token --slot 0 --label "TestToken" --so-pin 123456 --pin 1234 + $(Q)softhsm2-util --import $(DATADIR)/token/aes.key --aes --token "TestToken" --label "AES key" --id A1B2 --pin 1234 +endif + .PHONY: $(PHONY) diff --git a/test/data/token/softhsm.conf b/test/data/token/softhsm.conf new file mode 100644 index 00000000..bd43fe45 --- /dev/null +++ b/test/data/token/softhsm.conf @@ -0,0 +1,2 @@ +directories.tokendir = test/data/token +objectstore.backend = file \ No newline at end of file diff --git a/test/test_crypt_pkcs11.c b/test/test_crypt_pkcs11.c new file mode 100644 index 00000000..6ed4b84d --- /dev/null +++ b/test/test_crypt_pkcs11.c @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2024 Matej Zachar +// +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE (AES_BLOCK_SIZE * 1024) +#define TOKENDIR "test/data/token" + +static int read_file(const char *path, unsigned char *buffer, size_t *size) +{ + FILE *fp = fopen(path, "r"); + if (!fp) { + fprintf(stderr, "Failed to open file '%s'\n", path); + return -1; + } + + size_t len = fread(buffer, sizeof(char), *size, fp); + if (ferror(fp) != 0) { + fprintf(stderr, "Error reading file '%s'\n", path); + fclose(fp); + return -1; + } + + *size = len; + fclose(fp); + + return 0; +} + +static void test_crypt_pkcs11_256(void **state) +{ + (void) state; + int err; + + const char * uri = "pkcs11:token=TestToken;id=%A1%B2?pin-value=1234&module-path=/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so"; + + size_t original_data_len = 128 * 1024;/* 128KiB */ + unsigned char original_data[original_data_len]; + err = read_file(TOKENDIR "/original.data", &original_data[0], &original_data_len); + assert_true(err == 0); + + size_t encrypted_data_len = 128 * 1024 + AES_BLOCK_SIZE;/* 128KiB + AES_BLOCK_SIZE(16B) */ + unsigned char encrypted_data[encrypted_data_len]; + err = read_file(TOKENDIR "/encrypted.data", &encrypted_data[0], &encrypted_data_len); + assert_true(err == 0); + + unsigned char decrypted_data[encrypted_data_len]; + + size_t iv_size = 16; + unsigned char iv[iv_size]; + err = read_file(TOKENDIR "/encrypted.data.iv", &iv[0], &iv_size); + assert_true(err == 0); + + unsigned char buffer[BUFFER_SIZE + AES_BLOCK_SIZE]; + + struct swupdate_digest *dgst = swupdate_DECRYPT_init((unsigned char *)uri, 0, &iv[0]); + assert_non_null(dgst); + + int len; + size_t e_offset = 0; + size_t d_offset = 0; + while (e_offset < encrypted_data_len) { + size_t chunk_size = (encrypted_data_len - e_offset > BUFFER_SIZE) ? BUFFER_SIZE : encrypted_data_len - e_offset; + + err = swupdate_DECRYPT_update(dgst, buffer, &len, encrypted_data + e_offset, chunk_size); + assert_true(err == 0); + assert_true(len >= AES_BLOCK_SIZE && len <= chunk_size); + e_offset += chunk_size; + + memcpy(&decrypted_data[d_offset], buffer, len); + d_offset += len; + } + + err = swupdate_DECRYPT_final(dgst, buffer, &len); + assert_true(err == 0); + assert_true(len == 3); /* as the size is 128*1024+3 */ + + memcpy(&decrypted_data[d_offset], buffer, len); + d_offset += len; + + assert_true(strncmp((const char *)decrypted_data, (const char *)original_data, original_data_len) == 0); +} +