From patchwork Tue Mar 21 13:07:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bastian Germann X-Patchwork-Id: 1759425 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2a00:1450:4864:20::53c; helo=mail-ed1-x53c.google.com; envelope-from=swupdate+bncbc4z7bgub4ii5whguadbubapmzjci@googlegroups.com; receiver=) 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=20210112 header.b=YzrnsUmL; dkim-atps=neutral Received: from mail-ed1-x53c.google.com (mail-ed1-x53c.google.com [IPv6:2a00:1450:4864:20::53c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PgsMm5NZPz247k for ; Wed, 22 Mar 2023 00:07:31 +1100 (AEDT) Received: by mail-ed1-x53c.google.com with SMTP id k30-20020a50ce5e000000b00500544ebfb1sf12336328edj.7 for ; Tue, 21 Mar 2023 06:07:31 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1679404047; cv=pass; d=google.com; s=arc-20160816; b=NLup36EiuvpyL8+PDQWqOS0jIN49zmfD4eCewma8u2BiSuAbA5a7PIy1AAufvcfhX6 qV0LdsJWGoCyUnBcr/Vo+FgKFreGRUQqRV1l45ifl7PDOONZ3SGLDkwxRrsvqlHKu1tu I3B0KJQ7kNmnjSeqYpLV2c6OeSsuF15jeSzB3JHW6HdSrGAhCccNsftJEqyovP5dZ+Gd 2Y4c4HlHotLj4T6EzTz6Z+LmfeHHpyTj8v/t3OIf2sIpijgy+D19iVqKhnbuBnLNly74 9kAn9bdFtAugoBZiIz/ODnud2Cf8hf5u5nesBCGWoi/qHne8KlsmelNqRXtHnLjbNKvn 5bEw== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:sender:dkim-signature; bh=dJ84oDw5AYL1rLIpz/q+zpL32IjLtcmDy2fcnLbxiH8=; b=Kvu6uBE7gU1clGLPkdPu1ycT61LNpzgBwMObbapb/m9pg+g0gllCY+MC3gDvlaZKzJ Qv/XlIiB3Q+2Nk01PGrSlmKDi6s8evLb4/ixuOb9uNUGuEpWfy4TR/BVSw3P1Ld8UIvd S0KRPjR45QnbzWrneVziAMQmJO1HU4eM9FPHt8FtsKmDV+MQSYF91FNqWpPLtL6BW+cU 6z0gjfVVuc7AncT3tjq0ecC/zhfRu8KLZVRlH/ESOnsQ5vWQpgLeV9mKRqJIacEv2AY2 ga4PdbwXGev6bIHI6K+nUFQWPwOklC74eHW+SF7XOfUkGBMwc+yYPchFGAHYec79PnSk wAoQ== ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@debian.org header.s=smtpauto.stravinsky header.b=YE2149Kj; spf=none (google.com: debian.org does not designate permitted sender hosts) smtp.mailfrom=bage@debian.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20210112; t=1679404047; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:x-original-authentication-results :x-original-sender:mime-version:references:in-reply-to:message-id :date:subject:cc:to:from:sender:from:to:cc:subject:date:message-id :reply-to; bh=dJ84oDw5AYL1rLIpz/q+zpL32IjLtcmDy2fcnLbxiH8=; b=YzrnsUmLBKAjq69PZaofVPKjkGPKg+5EeziOAOjvb6qEsHn7QNfkQa800oFaiZ6m0R GkqbtkDZ/9ajVHI/vRSfvTPcePZ09mn+ErxdhzRPXpTatuN5kTEyrM3+5hY7l4AJzhto DJpsfkGshdkNzYoUoUhUhEAV+oAxp7kmqjt6LtWy0u6FLtBqRXGTqus8JTFn7YQeN6LW aNBgG4Gy7oFypQDB0WoFTaAAfe/1YgDCJiZz34JECbsDdkITg077u1JECnQR9FZ6QaLD DmZY8vHjncy7l9nWGzNZAm6CELUC/JUU5RKT/1QVJrmwpDxHC7ENAy/zCAj0bAbE5fyc Vlhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1679404047; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :x-spam-checked-in-group:list-id:mailing-list:precedence :x-original-authentication-results:x-original-sender:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :x-gm-message-state:sender:from:to:cc:subject:date:message-id :reply-to; bh=dJ84oDw5AYL1rLIpz/q+zpL32IjLtcmDy2fcnLbxiH8=; b=eIhsXyitSq5F5L5QKr7WcmMbC0tpOqWoqf+Rn01Xv+ekYVYRz8oItuFQTMbaffZMtE H3ztrv4lLUurNWAXNve+jyH5g66O+8//cOBZI+HoC76TWgkpOP0J0kCUoaxnfkurXVuz nKl+UcM7Y3hFcT1yxie25MmvIp0I2+EUbzeCxn+PrmUQr1kfdVKfR3QGbeu48wh7biDm 9PROr+FTjiMHsqVzzXQ7YMO5NYZACsfXczGDcNZU2ErRi5c0N/nMU+Ls/+XQsiiR/IPX iQfyEdsaZxmvWlddCH5HMMWpM72KbJciY8Gpfr9R+eIgXM1mqmtEWEHcGeMeremZG3o0 PjDw== Sender: swupdate@googlegroups.com X-Gm-Message-State: AO0yUKUFnqbvjygjhdzajqEVrKy8lqtuiRjy/GKmaNeBDogs5dWD4pD8 Qb718JxbOpVcAkDKxOnSTbM= X-Google-Smtp-Source: AK7set+LoUiMjpld0AhWg2DXAaWrRpw4F1HZs2lSxE5bubQiFNiN1x6nDpfzzK/Ih6EgcVvjHsvYHw== X-Received: by 2002:a50:9b4a:0:b0:4fc:fc86:5f76 with SMTP id a10-20020a509b4a000000b004fcfc865f76mr1601057edj.6.1679404046902; Tue, 21 Mar 2023 06:07:26 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6402:3807:b0:4ac:d2bc:e0cb with SMTP id es7-20020a056402380700b004acd2bce0cbls1291451edb.0.-pod-prod-gmail; Tue, 21 Mar 2023 06:07:25 -0700 (PDT) X-Received: by 2002:aa7:cb03:0:b0:4fd:1fda:8491 with SMTP id s3-20020aa7cb03000000b004fd1fda8491mr2701270edt.24.1679404045251; Tue, 21 Mar 2023 06:07:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679404045; cv=none; d=google.com; s=arc-20160816; b=PSXeTg9cC1QhKBZguLwVp6fcHsTPjZ3gQJCACqrp+lfz2fXAgh7bzGrIT5+ndq+KtV Ph4iielzXCCSx3lKJ5fFlkHAXH95i/iBTB+JnizyvIfqQxhxtLHt8o4vh+akB/JZpIjv yG2o1mDR2fFifLv9Ro5R3JIohakj4f4QDDDLGdpWeMN96c99pTsANj3neZaPYaP47AOX IdYn8tqphHErn1Ym10MhCLy87GOxxqOgEh6LhViJ45g1/DMhbN3KUhVcUtDRJ/Lm8SnU h56UK9GnCAsvI+Agu83Oj21RKYx0RzPteacAqo88cQKUsrrL1574cmy4dMqAD7nTtRWB MrLg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=JfKpAtG9zeYbDGx5FFjtYyOKp+OTnKiQ2lCuR8lQDj4=; b=an8vH43M1yFKMmd4AuZ+8joWuAYYSPz7Jb28GsFSouH8rUuZ1YUXxIEfM79Yt1LT8/ fBJLD6R69Qc0M/Z5sxPg7WFSSe1jPACzZemlyIl3fpdFxbpbPmYDWlpnW4MRpNxzV2dG Y5rDWsmuG4dFVmcPqxiBvSqAV9R4n9TUiz0odpA2tqe+SRR5BNgTgKHmlIvGkJ/v0fbR dKGeBytcs1kOf6braK2gT9sklYB3+WOEbs/UAD3bHjiy+qaD902E5seYprU8MHtxHgcs A0nSDxA3X2nA1i29pQicdDeA33KI35eNqsQYdgXnepx0ljydhhpDCOY1iTtIj2ByAszk OxvQ== ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@debian.org header.s=smtpauto.stravinsky header.b=YE2149Kj; spf=none (google.com: debian.org does not designate permitted sender hosts) smtp.mailfrom=bage@debian.org Received: from stravinsky.debian.org (stravinsky.debian.org. [2001:41b8:202:deb::311:108]) by gmr-mx.google.com with ESMTPS id f14-20020a056402194e00b004fd1ef6d039si518059edz.3.2023.03.21.06.07.25 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Mar 2023 06:07:25 -0700 (PDT) Received-SPF: none (google.com: debian.org does not designate permitted sender hosts) client-ip=2001:41b8:202:deb::311:108; Received: from authenticated user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.94.2) (envelope-from ) id 1pebi0-00FHfq-Iy; Tue, 21 Mar 2023 13:07:24 +0000 From: Bastian Germann To: swupdate@googlegroups.com Cc: Bastian Germann Subject: [swupdate] [PATCH 1/2] Add PKCS#7 verification for wolfSSL Date: Tue, 21 Mar 2023 14:07:12 +0100 Message-Id: <20230321130713.5203-2-bage@debian.org> X-Mailer: git-send-email 2.39.2 In-Reply-To: <20230321130713.5203-1-bage@debian.org> References: <20230321130713.5203-1-bage@debian.org> MIME-Version: 1.0 X-Debian-User: bage X-Original-Sender: bage@debian.org X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@debian.org header.s=smtpauto.stravinsky header.b=YE2149Kj; spf=none (google.com: debian.org does not designate permitted sender hosts) smtp.mailfrom=bage@debian.org Precedence: list Mailing-list: list swupdate@googlegroups.com; contact swupdate+owners@googlegroups.com List-ID: X-Spam-Checked-In-Group: swupdate@googlegroups.com X-Google-Group-Id: 605343134186 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , wolfSSL has a PKCS#7 implementation that has mostly the same features like CMS. Add signature verification based on the existing swupdate_cms_verify module. It can only deal with one signature and cannot deal with X509 purposes, which is why CMS_SKIP_UNKNOWN_SIGNERS and CMS_IGNORE_CERTIFICATE_PURPOSE are forcibly set with PKCS#7. Wire up the new module in the build system. Signed-off-by: Bastian Germann --- Kconfig | 13 ++- corelib/Makefile | 4 +- corelib/swupdate_cms_verify.c | 2 + corelib/swupdate_pkcs7_verify.c | 173 ++++++++++++++++++++++++++++++ corelib/swupdate_verify_private.h | 2 + corelib/verify_signature.c | 3 + include/sslapi.h | 3 +- 7 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 corelib/swupdate_pkcs7_verify.c diff --git a/Kconfig b/Kconfig index 48325bf..0c497fe 100644 --- a/Kconfig +++ b/Kconfig @@ -415,6 +415,8 @@ choice config SSL_IMPL_WOLFSSL bool "wolfSSL (with OpenSSL compatibility layer)" depends on HAVE_WOLFSSL + select CMS_IGNORE_CERTIFICATE_PURPOSE + select CMS_SKIP_UNKNOWN_SIGNERS config SSL_IMPL_MBEDTLS bool "mbedTLS" @@ -451,7 +453,10 @@ choice default SIGALG_RAWRSA help Select if the signature algorithm for signed images is a raw RSA signature - (following PKCS#1.5) or if it uses Cryptographic Message Syntax (CMS). + (following PKCS#1.5) or if it uses Cryptographic Message Syntax (CMS) with + OpenSSL/LibreSSL or PKCS#7 with wolfSSL. + wolfSSL's PKCS#7 implementation can only deal with one signature and cannot + deal with X509 purposes. config SIGALG_RAWRSA bool "RSA PKCS#1.5" @@ -460,12 +465,12 @@ choice bool "RSA PSS" config SIGALG_CMS - bool "Cryptographic Message Syntax (CMS)" - depends on SSL_IMPL_OPENSSL + bool "Cryptographic Message Syntax (CMS) / PKCS#7" + depends on SSL_IMPL_OPENSSL || SSL_IMPL_WOLFSSL endchoice -menu "CMS signature verification options" +menu "CMS / PKCS#7 signature verification options" depends on SIGALG_CMS config CMS_IGNORE_EXPIRED_CERTIFICATE diff --git a/corelib/Makefile b/corelib/Makefile index d6ea6a2..fb0a989 100644 --- a/corelib/Makefile +++ b/corelib/Makefile @@ -17,9 +17,11 @@ lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify.o lib-$(CONFIG_SIGALG_RSAPSS) += swupdate_rsa_verify.o endif ifeq ($(CONFIG_SSL_IMPL_OPENSSL),y) -# wolfSSL does not support CMS in the compatibility layer yet lib-$(CONFIG_SIGALG_CMS) += swupdate_cms_verify.o endif +ifeq ($(CONFIG_SSL_IMPL_WOLFSSL),y) +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) diff --git a/corelib/swupdate_cms_verify.c b/corelib/swupdate_cms_verify.c index 2c0ba39..49e3548 100644 --- a/corelib/swupdate_cms_verify.c +++ b/corelib/swupdate_cms_verify.c @@ -22,6 +22,7 @@ #define VERIFY_UNKNOWN_SIGNER_FLAGS (0) #endif +#ifndef CONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE int check_code_sign(const X509_PURPOSE *xp, const X509 *crt, int ca) { X509 *x = (X509 *)crt; @@ -47,6 +48,7 @@ int check_code_sign(const X509_PURPOSE *xp, const X509 *crt, int ca) return (ex_flags & EXFLAG_XKUSAGE) && (ex_xkusage & XKU_CODE_SIGN); } +#endif static int cms_verify_callback(int ok, X509_STORE_CTX *ctx) { int cert_error = X509_STORE_CTX_get_error(ctx); diff --git a/corelib/swupdate_pkcs7_verify.c b/corelib/swupdate_pkcs7_verify.c new file mode 100644 index 0000000..3263fcd --- /dev/null +++ b/corelib/swupdate_pkcs7_verify.c @@ -0,0 +1,173 @@ +/* + * (C) Copyright 2019 + * Stefano Babic, DENX Software Engineering, sbabic@denx.de. + * (C) Copyright 2023 + * Bastian Germann + * + * SPDX-License-Identifier: GPL-2.0-only + * + * Code mostly taken from openssl examples + */ + +#include +#include +#include +#include +#include "swupdate.h" +#include "sslapi.h" +#include "util.h" +#include "swupdate_verify_private.h" + +static int store_verify_callback(int ok, X509_STORE_CTX *ctx) { + int cert_error = X509_STORE_CTX_get_error(ctx); + + if (!ok) { + switch (cert_error) { +#if defined(CONFIG_CMS_IGNORE_EXPIRED_CERTIFICATE) + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CERT_NOT_YET_VALID: + ok = 1; + break; +#endif +#if defined(CONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE) + case X509_V_ERR_INVALID_PURPOSE: + ok = 1; + break; +#endif + default: + break; + } + } + + return ok; +} + +X509_STORE *load_cert_chain(const char *file) +{ + X509_STORE *castore = X509_STORE_new(); + if (!castore) { + return NULL; + } + + /* + * Set error callback function for verification of CRTs and CRLs in order + * to ignore some errors depending on configuration + */ + X509_STORE_set_verify_cb(castore, store_verify_callback); + + BIO *castore_bio = BIO_new_file(file, "r"); + if (!castore_bio) { + TRACE("failed: BIO_new_file(%s)", file); + return NULL; + } + + int crt_count = 0; + X509 *crt = NULL; + do { + crt = PEM_read_bio_X509(castore_bio, NULL, 0, NULL); + if (crt) { + crt_count++; + char *subj = X509_NAME_oneline(X509_get_subject_name(crt), NULL, 0); + char *issuer = X509_NAME_oneline(X509_get_issuer_name(crt), NULL, 0); + TRACE("Read PEM #%d: %s %s", crt_count, issuer, subj); + free(subj); + free(issuer); + if (X509_STORE_add_cert(castore, crt) == 0) { + TRACE("Adding certificate to X509_STORE failed"); + BIO_free(castore_bio); + X509_STORE_free(castore); + return NULL; + } + } + } while (crt); + BIO_free(castore_bio); + + if (crt_count == 0) { + X509_STORE_free(castore); + return NULL; + } + + return castore; +} + +static int check_signer_name(const char *name) +{ + // TODO work around wolfSSL's PKCS7_get0_signers always returning NULL + if (name) + WARN("The X.509 common name might not be equal to %s.", name); + return 0; +} + +int swupdate_verify_file(struct swupdate_digest *dgst, const char *sigfile, + const char *file, const char *signer_name) +{ + int status = -EFAULT; + WOLFSSL_PKCS7* pkcs7 = (WOLFSSL_PKCS7 *)PKCS7_new(); + BIO *bio_mem = NULL; + BIO *content_bio = NULL; + + /* Open detached signature that needs to be checked */ + BIO *sigfile_bio = BIO_new_file(sigfile, "rb"); + if (!sigfile_bio) { + ERROR("%s cannot be opened", sigfile); + status = -EBADF; + goto out; + } + + pkcs7->len = wolfSSL_BIO_get_len(sigfile_bio); + pkcs7->data = calloc(1, pkcs7->len); + BIO_read(sigfile_bio, pkcs7->data, pkcs7->len); + if (!pkcs7->data) { + ERROR("%s cannot be parsed as DER-encoded PKCS#7 signature blob", sigfile); + status = -EFAULT; + goto out; + } + + /* Open the content file (data which was signed) */ + content_bio = BIO_new_file(file, "rb"); + if (!content_bio) { + ERROR("%s cannot be opened", file); + status = -EBADF; + goto out; + } + long content_len = wolfSSL_BIO_get_len(content_bio); + char *content = calloc(1, content_len); + BIO_read(content_bio, content, content_len); + bio_mem = BIO_new_mem_buf(content, content_len); + + /* Then try to verify signature. The BIO* in parameter has to be a mem BIO. + See https://github.com/wolfSSL/wolfssl/issues/6174. */ + if (!PKCS7_verify((PKCS7 *)pkcs7, NULL, dgst->certs, bio_mem, + NULL, PKCS7_BINARY)) { + ERR_print_errors_fp(stderr); + ERROR("Signature verification failed"); + status = -EBADMSG; + goto out; + } + + if (check_signer_name(signer_name)) { + ERROR("failed to verify signer name"); + status = -EFAULT; + goto out; + } + + TRACE("Verified OK"); + + /* Signature is valid */ + status = 0; +out: + + if (pkcs7) { + PKCS7_free((PKCS7 *)pkcs7); + } + if (bio_mem) { + BIO_free(bio_mem); + } + if (content_bio) { + BIO_free(content_bio); + } + if (sigfile_bio) { + BIO_free(sigfile_bio); + } + return status; +} diff --git a/corelib/swupdate_verify_private.h b/corelib/swupdate_verify_private.h index db2c4c7..cd3c7e5 100644 --- a/corelib/swupdate_verify_private.h +++ b/corelib/swupdate_verify_private.h @@ -16,7 +16,9 @@ EVP_PKEY *load_pubkey(const char *file); #endif #ifdef CONFIG_SIGALG_CMS +#ifndef CONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE int check_code_sign(const X509_PURPOSE *xp, const X509 *crt, int ca); +#endif X509_STORE *load_cert_chain(const char *file); #endif diff --git a/corelib/verify_signature.c b/corelib/verify_signature.c index d91a0bf..69989fe 100644 --- a/corelib/verify_signature.c +++ b/corelib/verify_signature.c @@ -153,6 +153,7 @@ int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile) goto dgst_init_error; } +#ifndef CONFIG_CMS_IGNORE_CERTIFICATE_PURPOSE { static char code_sign_name[] = "Code signing"; static char code_sign_sname[] = "codesign"; @@ -171,6 +172,8 @@ int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile) ret = -EINVAL; goto dgst_init_error; } +#endif + #else TRACE("public key / cert %s ignored, you need to set SIGALG", keyfile); #endif diff --git a/include/sslapi.h b/include/sslapi.h index accf3c4..50f6a96 100644 --- a/include/sslapi.h +++ b/include/sslapi.h @@ -38,6 +38,7 @@ #include #include #include +#include #elif defined(CONFIG_SSL_IMPL_WOLFSSL) #include #include @@ -50,12 +51,12 @@ #include #include #include +#include #endif #if defined(CONFIG_SSL_IMPL_OPENSSL) || defined(CONFIG_SSL_IMPL_WOLFSSL) #ifdef CONFIG_SIGALG_CMS -#include static inline uint32_t SSL_X509_get_extension_flags(X509 *x) {