From patchwork Fri Sep 22 15:20:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: amy.fong.3142@gmail.com X-Patchwork-Id: 1838282 X-Patchwork-Delegate: sbabic@denx.de 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=Ss3w/iFK; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=N8Er9ZZx; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2607:f8b0:4864:20::f38; helo=mail-qv1-xf38.google.com; envelope-from=swupdate+bncbdu4fe6qrmgrb7hbw2uamgqect2b3ga@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-qv1-xf38.google.com (mail-qv1-xf38.google.com [IPv6:2607:f8b0:4864:20::f38]) (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 4Rsbb45QPJz1ynH for ; Sat, 23 Sep 2023 01:21:35 +1000 (AEST) Received: by mail-qv1-xf38.google.com with SMTP id 6a1803df08f44-6563871e72dsf20739216d6.3 for ; Fri, 22 Sep 2023 08:21:35 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1695396093; cv=pass; d=google.com; s=arc-20160816; b=1EVL13tSg7p5mqemVmtKdYmN8qyLrIxS+tGEurbBfGyKH6+8l/bWoj5q1Hbshdzv6D LM3bfBadyVR7qzFeCsNrYA8W9GMic77aN+jPIyvT2uJK2QsySiak3ENevqx8QRBvHhm0 +D+h154W9Nw6QHT9gcODuP/vvY77Scwcok1cGCVSGHuCAkSMAAx1g83dwRstQr6nL62R k/96ugyY011i5b45c1J2o5wxkQDKz+3gACsdCD4LTtGVP530JsnKcT9kOpiIO5qMjDNd 8Z98HSHxsN7U/w3Y9WGaa/RSk1b7UbMI6dbthH9mz/bcZL6DUyKM9opD2ETsZ1r7n+EN Z8Sg== 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:reply-to:message-id :date:subject:cc:to:from:sender:dkim-signature:dkim-signature; bh=EFgfQL7X8I2lmJJiHPtdd5pnuxahea4SQ/rYqXW4XCk=; fh=tUC4qYxnJeA7+O+/WQCoFUmd+pUfHX4EpA/OX8BQcSU=; b=0qNFpo4LdoOITic7KXz/jAafTlfBsMN3wNmd4sqrQCYJlS/ydOI506l63Zg8CY/zCg Do7NUkQvb+aiTWAvRSXGvfUzHjCcDzYnMpw7r2y/3+NB7QXE0upl+6yH4mweeYDFII7h CrtdfCxRLSMyyNP1JEw4DfLlp2o+2ljMSaAxGJoBf+K66sgHq4w2swd5Xy/dygmcxZ8f lWN7HlDNw3Mjsf+4rEfyUM2fV2FDt2XzVFr4BIzeMoPdBKkCvbVkFFg+lMCcL1PispB0 i8361NTA/MWsctmTefR396PoDRTeQjx2si03D9HJbdOkQK++KPObo/JONm8knRGJ1H3Q uQOA== ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=eRQnKygQ; spf=pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::f2a as permitted sender) smtp.mailfrom=amy.fong.3142@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20230601; t=1695396093; x=1696000893; 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:mime-version:reply-to:message-id:date:subject:cc :to:from:sender:from:to:cc:subject:date:message-id:reply-to; bh=EFgfQL7X8I2lmJJiHPtdd5pnuxahea4SQ/rYqXW4XCk=; b=Ss3w/iFKyxxqDrx6XnzNbakVgeyY/IkHZvLC2TvNdD2ZGXsO6Wvz70djU5JLmqz9v8 kMOcchsJa6cirS3kZkNp4ph8Ay+/Flfs1mIo63/tNX72LBnwg48OkUTGDJoq3C8D4/Pg a043nym6UEfc2TYnbfWQyrlgVj9+rBjiM7Fq6CzsLokdizROrcDhC3RIQYCFMA5WUTA6 HEhY2Gql1bSy/7hCpSgyR+d+BydAZ1gPLefW9NXfcK/REExdDSxUzVfD2TQuYnsZN1Uc ChEpkn1k4kmldZllnFkb33PZT7X+W4vpdqoESbVV5xOe2ylEjRfBH/2v98IHznt1DSmt eFfA== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1695396093; x=1696000893; 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:mime-version:reply-to:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=EFgfQL7X8I2lmJJiHPtdd5pnuxahea4SQ/rYqXW4XCk=; b=N8Er9ZZxaJdxYJFknXdKA7G5U65LjxyOWZLtALs7FwF8k02s4UtYQ8RHPRXqeZ4zIa a2mRPrxSzsgKlMzzcsgVlYUrxSQayrC8oPyLiLRKgk8epMoWym4RRXvfdI6snhp6sLMK knHktH/6kEyWwocKH6X7aE1U3nMBzMXwdQcqPX1MC3HwIHdqcE8k19Wovb7F4nriK3lo FAlpupMIakb8PbW+BFgWphZSBV98sS6XUivC29TrDDiwGsxg/zwVu71MPVL8msyB5r+D FwG3kz3B7gUskDp8KtoDmaZ3gLT+H/RxUOiVm/5d5/TlcGwf8YyzCDGDBTUh38PmnpnV QQ/g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695396093; x=1696000893; 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 :reply-to:message-id:date:subject:cc:to:from:x-beenthere :x-gm-message-state:sender:from:to:cc:subject:date:message-id :reply-to; bh=EFgfQL7X8I2lmJJiHPtdd5pnuxahea4SQ/rYqXW4XCk=; b=J5MJI6+bAGTbb8veQwmV97jGO6HibqnIsNthCxfCce0Qs5dI5c2/v9o3tZHvDaiBLR dducz7Fx5XL6iQIucUJvGOkalpVBpoRBk06ZssToaKRnXpp5al18EkVb8++t4c8SGeiv /9Vj3TRzSNsKNC2JadMqg/zXWnw1VjBCpV/srRykmEOGmT/Cevk/MdksILyWch2DSyQR bQeTAwgxRAsDoLwLsSZSHn37gHovxGeC3pmv11ggao6NonH212IRCAotAXA1xlgO3jUD rmsOf2L0JF/ioLExh8xaTGIV4/DYmg4HmF9ymCJwoD8u8fxp5OMfVaX6m2HPMtrp8D++ djLw== Sender: swupdate@googlegroups.com X-Gm-Message-State: AOJu0YxIa1Oho81vZxDv14vwN/l7BR1/ntMQPQIbzmfizDUqpkGKjub3 EWVD/xiSjzlqNOsYnILkLLg= X-Google-Smtp-Source: AGHT+IGHDeEDA4MbBFsnGPBkKKkToinJbZxgHwwE+w+Qz1sNrWjxUpk++QEIE0iQ04Wig8bKNICsjw== X-Received: by 2002:ad4:5984:0:b0:626:f3d:9e46 with SMTP id ek4-20020ad45984000000b006260f3d9e46mr8738116qvb.18.1695396093190; Fri, 22 Sep 2023 08:21:33 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a0c:f210:0:b0:656:fdc:a7bc with SMTP id h16-20020a0cf210000000b006560fdca7bcls1903759qvk.2.-pod-prod-02-us; Fri, 22 Sep 2023 08:21:32 -0700 (PDT) X-Received: by 2002:a67:bc09:0:b0:44e:9614:39bf with SMTP id t9-20020a67bc09000000b0044e961439bfmr9802793vsn.6.1695396092204; Fri, 22 Sep 2023 08:21:32 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695396092; cv=none; d=google.com; s=arc-20160816; b=pZTyf6f0svbl45cqNuROsrmsnsccr5UtdJIRpUoIKMA+FMbKxPdEEFbVMVCnmkigRy 50C8NYxQ9jkjYjK18uOB2RUcK1IQPrMEpqecF26n3JjRxBFCN8wPEdXWITjaIo57uJNr qqbRl9woiZ7o4/z3JHnlgkIUpAAKEP+/p9EdEC7XKHXQ9rzcrIOiVmPaoNCSk26R5p5Q /CRL8OTfxmDOp/dl7ouEjzrcCTkxyKy66B1cBABWNvzXbYDVhPGOzokScXrB3HE9REuf bj/0gU+IrModVy2sykBfYBTTOcItayCmTLaynUX19O764q+OYRgk6AerXz5nB0lW3w4i Lcvw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:reply-to:message-id:date :subject:cc:to:from:dkim-signature; bh=j595MrlY+O/1VbT0Vx63MxgyVf1dZyoFJefcBaD/iD8=; fh=tUC4qYxnJeA7+O+/WQCoFUmd+pUfHX4EpA/OX8BQcSU=; b=T4DhtWxItR1FSG7F9g+Daq2QhqnN4/DJGStFgkqBYTOs3o70SaEQVl5zIs5Ak+xrfR axv8a0pjvjgg7dC4zUdgvtNi0fDc3p6I+myNeKhZggrGHriFvbtZ+mNRxJFtSW09v5S+ 1wWCpDZcgtcp1OXD7sfGTjjP/vnwoP70a3mRvdXkaK19RB/NBm0UJzs53v/qoTM0oKMt uNp8Wwc7eIHAWZZKWJSJbIYE9JRt+VjBTO3PGi9Z2pWEsJ0O5+aenTfRE/OM94oRIAin AaeoBXE99SmOC5bEkudhJ3b32pkFQ8RwvBndFIbn7uSrtrxw0OFgkCn2fiGk13Fhf0zU SsCQ== ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=eRQnKygQ; spf=pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::f2a as permitted sender) smtp.mailfrom=amy.fong.3142@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from mail-qv1-xf2a.google.com (mail-qv1-xf2a.google.com. [2607:f8b0:4864:20::f2a]) by gmr-mx.google.com with ESMTPS id h40-20020a0561023da800b004508d6fcf6csi777282vsv.1.2023.09.22.08.21.32 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Fri, 22 Sep 2023 08:21:32 -0700 (PDT) Received-SPF: pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::f2a as permitted sender) client-ip=2607:f8b0:4864:20::f2a; Received: by mail-qv1-xf2a.google.com with SMTP id 6a1803df08f44-65896b9aa09so12452246d6.1 for ; Fri, 22 Sep 2023 08:21:32 -0700 (PDT) X-Received: by 2002:a0c:a801:0:b0:658:2a37:aba8 with SMTP id w1-20020a0ca801000000b006582a37aba8mr8603175qva.28.1695396091388; Fri, 22 Sep 2023 08:21:31 -0700 (PDT) Received: from localhost.localdomain (198-84-204-38.cpe.teksavvy.com. [198.84.204.38]) by smtp.gmail.com with ESMTPSA id h15-20020a37de0f000000b0076ef3e6e6a4sm1476432qkj.42.2023.09.22.08.21.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 22 Sep 2023 08:21:30 -0700 (PDT) From: amy.fong.3142@gmail.com To: swupdate@googlegroups.com Cc: Amy Fong Subject: [swupdate] [PATCH v2] gpg: add optional gpg signing verification Date: Fri, 22 Sep 2023 11:20:12 -0400 Message-Id: <20230922152011.1721101-1-amy.fong@siemens.com> X-Mailer: git-send-email 2.39.2 Reply-To: amy.fong@siemens.com MIME-Version: 1.0 X-Original-Sender: amy.fong.3142@gmail.com X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=eRQnKygQ; spf=pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::f2a as permitted sender) smtp.mailfrom=amy.fong.3142@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com 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: , From: Amy Fong This change introduces a Kconfig parameter allowing gpg verification. The environment variable GPG_HOMEDIR, if set, is used to specify the home directory. Signed-off-by: Amy Fong --- Kconfig | 3 +- Makefile.flags | 5 ++ core/parser.c | 5 ++ core/swupdate.c | 27 ++++++ corelib/Makefile | 1 + corelib/swupdate_gpg_verify.c | 164 ++++++++++++++++++++++++++++++++++ doc/source/signed_images.rst | 61 +++++++++++-- include/sslapi.h | 3 + include/swupdate.h | 2 + 9 files changed, 265 insertions(+), 6 deletions(-) create mode 100644 corelib/swupdate_gpg_verify.c diff --git a/Kconfig b/Kconfig index 636c4ac..bd4ce04 100644 --- a/Kconfig +++ b/Kconfig @@ -430,7 +430,6 @@ choice config SSL_IMPL_MBEDTLS bool "mbedTLS" depends on HAVE_MBEDTLS - endchoice @@ -477,6 +476,8 @@ choice bool "Cryptographic Message Syntax (CMS) / PKCS#7" depends on SSL_IMPL_OPENSSL || SSL_IMPL_WOLFSSL + config SIGALG_GPG + bool "GPG signing" endchoice menu "CMS / PKCS#7 signature verification options" diff --git a/Makefile.flags b/Makefile.flags index 2d27a8f..5046a69 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -305,3 +305,8 @@ endif # (we stole scripts/checkstack.pl from the kernel... thanks guys!) # Reduced from 20k to 16k in 1.9.0. FLTFLAGS += -s 16000 + +ifeq ($(CONFIG_SIGALG_GPG),y) +LDLIBS += gpgme +endif + diff --git a/core/parser.c b/core/parser.c index 50d9957..bbb7535 100644 --- a/core/parser.c +++ b/core/parser.c @@ -143,8 +143,13 @@ int parse(struct swupdate_cfg *sw, const char *descfile) strcpy(sigfile, descfile); strcat(sigfile, ".sig"); +#ifdef CONFIG_SIGALG_GPG + ret = swupdate_verify_file_gpg(sw->gpg_home_directory, sigfile, descfile, + sw->verbose, sw->gpgme_protocol); +#else ret = swupdate_verify_file(sw->dgst, sigfile, descfile, sw->forced_signer_name); +#endif free(sigfile); if (ret) diff --git a/core/swupdate.c b/core/swupdate.c index 6b536b8..d8a644c 100644 --- a/core/swupdate.c +++ b/core/swupdate.c @@ -95,6 +95,7 @@ static struct option long_options[] = { {"key", required_argument, NULL, 'k'}, {"ca-path", required_argument, NULL, 'k'}, {"cert-purpose", required_argument, NULL, '1'}, + {"gpg-home-dir", required_argument, NULL, 'G'}, #if defined(CONFIG_SIGALG_CMS) && !defined(CONFIG_SSL_IMPL_WOLFSSL) {"forced-signer-name", required_argument, NULL, '2'}, #endif @@ -150,6 +151,7 @@ static void usage(char *programname) " -l, --loglevel : logging level\n" " -L, --syslog : enable syslog logger\n" #ifdef CONFIG_SIGNED_IMAGES +#ifndef CONFIG_SIGALG_GPG " -k, --key : file with public key to verify images\n" " --cert-purpose : set expected certificate purpose\n" " [emailProtection|codeSigning] (default: emailProtection)\n" @@ -157,6 +159,10 @@ static void usage(char *programname) " --forced-signer-name : set expected common name of signer certificate\n" #endif " --ca-path : path to the Certificate Authority (PEM)\n" +#else + " -G, --gpg-home-dir\n" + " : GnuPG home directory\n" +#endif #endif #ifdef CONFIG_ENCRYPTED_IMAGES " -K, --key-aes : the file contains the symmetric key to be used\n" @@ -338,6 +344,10 @@ static int read_globals_settings(void *elem, void *data) char software_select[SWUPDATE_GENERAL_STRING_SIZE] = ""; GET_FIELD_STRING(LIBCFG_PARSER, elem, "select", software_select); + GET_FIELD_STRING(LIBCFG_PARSER, elem, + "gpg-home-dir", sw->gpg_home_directory); + GET_FIELD_STRING(LIBCFG_PARSER, elem, + "gpgme-protocol", sw->gpgme_protocol); if (software_select[0] != '\0') { /* by convention, errors in a configuration section are ignored */ (void)parse_image_selector(software_select, sw); @@ -470,8 +480,12 @@ int main(int argc, char **argv) strcat(main_options, "H:"); #endif #ifdef CONFIG_SIGNED_IMAGES +#ifndef CONFIG_SIGALG_GPG strcat(main_options, "k:"); public_key_mandatory = 1; +#else + strcat(main_options, "G:"); +#endif #endif #ifdef CONFIG_ENCRYPTED_IMAGES strcat(main_options, "K:"); @@ -620,6 +634,11 @@ int main(int argc, char **argv) optarg, sizeof(swcfg.publickeyfname)); break; + case 'G': + strlcpy(swcfg.gpg_home_directory, + optarg, + sizeof(swcfg.gpg_home_directory)); + break; case '1': swcfg.cert_purpose = parse_cert_purpose(optarg); break; @@ -746,6 +765,14 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } +#ifdef CONFIG_SIGALG_GPG + if (!strlen(swcfg.gpg_home_directory)) { + fprintf(stderr, + "Error: SWUpdate is built for signed images, provide a GnuPG home directory.\n"); + exit(EXIT_FAILURE); + } +#endif + if (opt_c && !opt_i) { fprintf(stderr, "Error: Checking local images requires -i .\n"); diff --git a/corelib/Makefile b/corelib/Makefile index 5f6f8e9..f5dda73 100644 --- a/corelib/Makefile +++ b/corelib/Makefile @@ -32,6 +32,7 @@ endif lib-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify_mbedtls.o lib-$(CONFIG_SIGALG_RSAPSS) += swupdate_rsa_verify_mbedtls.o endif +lib-$(CONFIG_SIGALG_GPG) += swupdate_gpg_verify.o lib-$(CONFIG_LIBCONFIG) += swupdate_settings.o \ parsing_library_libconfig.o lib-$(CONFIG_JSON) += parsing_library_libjson.o server_utils.o diff --git a/corelib/swupdate_gpg_verify.c b/corelib/swupdate_gpg_verify.c new file mode 100644 index 0000000..24bebbc --- /dev/null +++ b/corelib/swupdate_gpg_verify.c @@ -0,0 +1,164 @@ +/* + * Author: Amy Fong + * Copyright (C) 2023, Siemens AG + * + * SPDX-License-Identifier: GPL-2.0-only + */ +#include +#include +#include +#include +#include "swupdate.h" +#include "sslapi.h" +#include "util.h" + +#include +#include +#include + +static gpg_error_t +status_cb(void *opaque, const char *keyword, const char *value) +{ + (void)opaque; + DEBUG("status_cb: %s %s", keyword, value); + return 0; +} + +#define MSGBUF_LEN 256 + +int swupdate_verify_file_gpg(const char *gpg_home_dir, const char *sigfile, + const char *file, int verbose, const char *protocol_req) +{ + gpgme_ctx_t ctx; + gpgme_error_t err; + gpgme_data_t image_sig, image; + FILE *fp_sig = NULL; + FILE *fp = NULL; + gpgme_signature_t sig; + int status = 0; + gpgme_protocol_t protocol; + gpgme_verify_result_t result; + char msg[MSGBUF_LEN]; + int r; + const char *tmp; + + tmp = gpgme_check_version(NULL); + if (tmp == NULL) { + ERROR("Failed to check gpgme library version"); + status = -EFAULT; + goto out; + } + + err = gpgme_new(&ctx); + if (err) { + ERROR("Failed to create new gpg context"); + r = gpgme_strerror_r(err, msg, MSGBUF_LEN); + if (r == 0) { + ERROR("Reason: %s", msg); + } + status = -EFAULT; + goto out; + } + + protocol = GPGME_PROTOCOL_OpenPGP; + if (protocol_req != NULL) { + DEBUG("gpg: Enabling protocol %s", protocol_req); + if (!strcmp(protocol_req, "default")) { + TRACE("GPGME: using protocol OpenPGP"); + protocol = GPGME_PROTOCOL_OpenPGP; + } else { + ERROR("Unsupported protocol! %s", protocol_req); + status = -EFAULT; + goto out; + } + } + gpgme_set_protocol(ctx, protocol); + gpgme_set_status_cb(ctx, status_cb, NULL); + if (verbose == 1) { + gpgme_set_ctx_flag(ctx, "full-status", "1"); + } + gpgme_set_locale(ctx, LC_ALL, setlocale(LC_ALL, "")); + + fp_sig = fopen(sigfile, "rb"); + if (!fp_sig) { + ERROR("Failed to open %s", sigfile); + status = -EBADF; + goto out; + } + err = gpgme_data_new_from_stream(&image_sig, fp_sig); + if (err) { + ERROR("error allocating data object"); + r = gpgme_strerror_r(err, msg, MSGBUF_LEN); + if (r == 0) { + ERROR("Reason: %s", msg); + } + status = -ENOMEM; + goto out; + } + + fp = fopen(file, "rb"); + if (!fp) { + ERROR("Failed to open %s", file); + status = -EBADF; + goto out; + } + err = gpgme_data_new_from_stream(&image, fp); + if (err) { + ERROR("error allocating data object"); + r = gpgme_strerror_r(err, msg, MSGBUF_LEN); + if (r == 0) { + ERROR("Reason: %s", msg); + } + status = -ENOMEM; + goto out; + } + + if (gpg_home_dir != NULL) { + err = gpgme_ctx_set_engine_info(ctx, protocol, NULL, gpg_home_dir); + if (err) { + ERROR("Something went wrong while setting the engine info"); + r = gpgme_strerror_r(err, msg, MSGBUF_LEN); + if (r == 0) { + ERROR("Reason: %s", msg); + } + status = -EFAULT; + goto out; + } + } + + err = gpgme_op_verify(ctx, image_sig, image, NULL); + result = gpgme_op_verify_result(ctx); + if (err) { + ERROR("verify failed"); + r = gpgme_strerror_r(err, msg, MSGBUF_LEN); + if (r == 0) { + ERROR("Reason: %s", msg); + } + status = -EBADMSG; + goto out; + } + + if (result) { + for (sig = result->signatures; sig; sig = sig->next) { + if (sig->status == GPG_ERR_NO_ERROR) { + TRACE("Verified OK"); + status = 0; + goto out; + } + } + } + TRACE("Verification failed"); + status = -EBADMSG; + + out: + gpgme_data_release(image); + gpgme_data_release(image_sig); + gpgme_release(ctx); + + if (fp) + fclose(fp); + if (fp_sig) + fclose(fp_sig); + + return status; +} diff --git a/doc/source/signed_images.rst b/doc/source/signed_images.rst index 581196d..2aa37c5 100644 --- a/doc/source/signed_images.rst +++ b/doc/source/signed_images.rst @@ -53,16 +53,20 @@ selected via menuconfig. Currently, the following mechanisms are implemented: - RSA Public / private key. The private key belongs to the build system, while the public key must be installed on the target. - CMS using certificates +- GPG key signing -Key or certificate is passed to SWUpdate with the `-k` parameter. +For RSA and CMS algorithms, key or certificate is passed to SWUpdate +with the `-k` parameter. Tool to generate keys / certificates ------------------------------------ -The `openssl` tool is used to generate the keys. This is part of the -OpenSSL project. A complete documentation can be found at +For RSA and CMS signing, the `openssl` tool is used to generate the keys. +This is part of the OpenSSL project. A complete documentation can be found at the `openSSL Website `_. +For GPG, `gpg` can be used to generate the keys and to sign the images. A complete +documentation can be found at the `GnuPG Website `_. Usage with RSA PKCS#1.5 or RSA PSS ---------------------------------- @@ -158,6 +162,42 @@ Signing the image is simple as in the previous case: -inkey mycert.key.pem -outform DER -nosmimecap -binary +Usage with GNU PG +----------------- + +Generating a new keypair +........................ + + +First, a primary keypair needs to be generated + +:: + gpg --gen-key + +The generated keys can be listed as follows + +:: + gpg -k + +Check the documentation for more information about parameters. + +How to sign with gpg +..................... + +Signing the image is very simple: + +:: + gpg --batch --output sw-description.sig + --detach-sig sw-description + +For an alternative GnuPG home directory, and if there are multiple keypairs, +the following can be used to specify. In this example, the GnuPG home directory +is in GPG_HOMEDIR, while the signing key is found in GPG_KEY. + +:: + gpg --batch --homedir "${GPG_HOMEDIR}" --default-key "${GPG_KEY}" --output sw-description.sig + --detach-sig sw-description + Building a signed SWU image --------------------------- @@ -187,6 +227,9 @@ A simple script to create a signed image can be: elif if [ x"$MODE" == "xRSA-PSS" ]; then openssl dgst -sha256 -sign priv.pem -sigopt rsa_padding_mode:pss \ -sigopt rsa_pss_saltlen:-2 sw-description > sw-description.sig + elif if [ x"$MODE" == "xGPG" ]; then + gpg --batch --homedir "${GPG_HOME_DIR}" --default-key "${GPG_KEY}" \ + --output sw-description.sig --detach-sig sw-description else openssl cms -sign -in sw-description -out sw-description.sig -signer mycert.cert.pem \ -inkey mycert.key.pem -outform DER -nosmimecap -binary @@ -233,5 +276,13 @@ Running SWUpdate with signed images Verification is activated by setting CONFIG_SIGNED_IMAGES in SWUpdate's configuration. If activated, SWUpdate will always check the compound image. For security reasons, -it is not possible to disable the check at runtime. The -k parameter (public key file) -is mandatory and the program stops if the public key is not passed. +it is not possible to disable the check at runtime. + +For RSA and CMS signing, the -k parameter (public key file) is mandatory and the program stops +if the public key is not passed. + +For GPG signing, CONFIG_SIGALG_GPG needs to be enabled. The -G parameter +(gpg-home-dir in swupdate.cfg) should be used to specify the GnuPG home directory. +Currently, the only protocol supported is GPGME_PROTOCOL_OpenPGP, the mechanism for supporting +other protocols can be specified by specifying gpgme-protocol in the config file, currently, +only "default" is handled. diff --git a/include/sslapi.h b/include/sslapi.h index a24a152..a04d942 100644 --- a/include/sslapi.h +++ b/include/sslapi.h @@ -178,6 +178,8 @@ 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(const unsigned char *hash1, const unsigned char *hash2); +int swupdate_verify_file_gpg(const char *gpg_home_dir, const char *sigfile, + const char *file, int verbose, const char *gpgme_protocol); #else @@ -188,6 +190,7 @@ int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2 #define swupdate_HASH_final(p, result, len) (-1) #define swupdate_HASH_cleanup(sw) #define swupdate_HASH_compare(hash1,hash2) (0) +#define swupdate_verify_file_gpg(gpg_home_dir, sigfile, file, verbose, gpgme_protocol) ( 0 ) #endif #ifdef CONFIG_ENCRYPTED_IMAGES diff --git a/include/swupdate.h b/include/swupdate.h index e473e41..83d61c6 100644 --- a/include/swupdate.h +++ b/include/swupdate.h @@ -93,6 +93,8 @@ struct swupdate_cfg { void *dgst; /* Structure for signed images */ struct swupdate_parms parms; const char *embscript; + char gpg_home_directory[SWUPDATE_GENERAL_STRING_SIZE]; + char gpgme_protocol[SWUPDATE_GENERAL_STRING_SIZE]; }; #define SEARCH_FILE(img, list, found, offs) do { \