From patchwork Tue Oct 10 18:02:14 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: 1846031 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=mEAWmWHI; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256 header.s=20230601 header.b=FdJeCeCD; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=googlegroups.com (client-ip=2001:4860:4864:20::3f; helo=mail-oa1-x3f.google.com; envelope-from=swupdate+bncbdu4fe6qrmgrbrnds2uqmgqeal5sfvi@googlegroups.com; receiver=patchwork.ozlabs.org) Received: from mail-oa1-x3f.google.com (mail-oa1-x3f.google.com [IPv6:2001:4860:4864:20::3f]) (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 4S4kJn5CvDz1ypX for ; Wed, 11 Oct 2023 05:02:48 +1100 (AEDT) Received: by mail-oa1-x3f.google.com with SMTP id 586e51a60fabf-1dd8e6a7a86sf9803047fac.1 for ; Tue, 10 Oct 2023 11:02:48 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1696960966; cv=pass; d=google.com; s=arc-20160816; b=d6B4ctDdiWGIjTeni159tOjefMJu6sG4bUh3+WLGWpcNjwoYyJeADLcnlCTa1IZuQH uKlb+JWTEergBChzBMvtLkxWlAmSvK6b/trhgJFDwD2V26LSDMz4Fb1oxn1YroyDRFKx xEHFa0XV22ONkB9ToU+7I0x0sJqogdS039TigYF4oAp4+J1RbN1afydisIrZZkv1MqrZ arwqFo5Yjqfbxl0xMdxAnQQe1NtLEzNq3Cfsg7wfrQjKs9ReOgkZI/hfKyaCt4CpMXTi ws9m/JuDGuRh2UwAkoqOLZp1kSvFrB7YZR4lt62k7SZufEJOU3pfRTlFNCqOgKf+rAED vcyw== 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:message-id:date :subject:cc:to:from:sender:dkim-signature:dkim-signature; bh=HY6Sr0aFvjaxiBptoupA0wsvlvxSW+QM8j3rL4xbvWM=; fh=tUC4qYxnJeA7+O+/WQCoFUmd+pUfHX4EpA/OX8BQcSU=; b=QyDqEonIiB/n1pWvMgQJlX2IgWeJ5OkBj30RzzrvsnMnPd1fXtcJj4Ax7YUmG5fjwi aYfChPQfxVi82qt8vvYuZprqbCP+tUfvJLlX305N8ZXyBxsSM5CU16FZyJlYrpgCW3Zh KvZ9PJRgqDMKjrGXgJaR3SA4JQa8YK7XD+8EyW0lu2fVHjQDADUFfc1DROx3JWouRpJ+ iKrlK+41hS52UU2BNK5MYz2MPYqasV27ctj6VhOGs4iQE3dZbJQeCLgKKvkEDbrrNM1W lxrJSipaZCD4BNUu2Oi4HrT/xb1Uad4qOpZf+evJfMQ6oL6Z/1DgBG6KJ63PKFPNPuRR QZjg== ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=RHfgCsg0; spf=pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::22f 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=1696960966; x=1697565766; 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:message-id:date:subject:cc:to:from :sender:from:to:cc:subject:date:message-id:reply-to; bh=HY6Sr0aFvjaxiBptoupA0wsvlvxSW+QM8j3rL4xbvWM=; b=mEAWmWHIsNyhCwEU+d3ltv6gSf8eZC58beK7nKctAcmzJSonh79xjmCJ/DXhXwgHn1 /YWNmQwSw82lU/x9fZ4MOjT4erD9JbIqHSL6wzyAbX/RN5WwuWQIJ9FRowVkwI92fyGb yR1mEKt3lwGAqYLx5dnqCNBqIcua0L1aHDaQVymu/SnjHlufqCqTGYkDuqbrBQFCp4+u JMYjbuDORxYFRmUFIGvDDeCMTaUlHiCNYar1xDXdOGuJ6MdcBFGZkJe4dt1zGwPiOWiM 52BFgY1TB0/ClYCHE/m3pu5XnIvyq/ZuUmILh8SM0x7d3B3tjV7dMj67Tr/ENhTFEvBc YkhQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1696960966; x=1697565766; 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:message-id:date:subject:cc:to:from :from:to:cc:subject:date:message-id:reply-to; bh=HY6Sr0aFvjaxiBptoupA0wsvlvxSW+QM8j3rL4xbvWM=; b=FdJeCeCDjXeYGbnOohf0pO3WJDINNajhxXzxG2/KNt6egksXL3ZjNULcn+QH3/NYFV IRnaVhtgKUmYx/TevmDs7w/+o8GuyJnjQwKcq3ju/j63joU90TLvWw9IFi7GI3I+tEUv FQzgMU0byO05C9l0zx9oQe+NpKUvFHBxSc/iue31hqmkG3hfj2yuI7AoknW7Y0iKEkGt aT5OPj0H/vxjSAk7gcgCfC2I93jbRT+0laJObR4+rA6mU+D3WuXhkEEB+FOSSurZdPox SSlpQWONHsIkmxGdH3+khV1EUx4GhB7QzUt1+hMCM4f4rJMMDqu+r8fZQB/yhq2M6zHl rFrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1696960966; x=1697565766; 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 :message-id:date:subject:cc:to:from:x-beenthere:x-gm-message-state :sender:from:to:cc:subject:date:message-id:reply-to; bh=HY6Sr0aFvjaxiBptoupA0wsvlvxSW+QM8j3rL4xbvWM=; b=eiXFY2/H3ePiyiMq1WfkZVSEaP8O1WWsqiOXwXN234SmAxeTggXP4zP4cV7zcxym5r Dihob/LIPv2H45BLjoccera/aJG+FtPDls4Shtd59YVxOXnPkKmNpvRF8cIEc1ESSW71 LQoPFmHDWNSTMSquYjf99Ny8ztJ3y0ZiHW64dq+vQVG9v3PmtaXb0In4oMeDr4u09xIG 8is9jsfUtBy4zmoBOBT0dCRJ7OanFhjTydM9llIhFjys+Z/LsfDV1yX2kM/yfHqXgSl3 Uz7oRgU+ezGXdJhO/AXOYvQ8kaZ89SKY/h0orufsdQOnt1yRJa03i5f1EEnjROuAmV1H x5Ow== Sender: swupdate@googlegroups.com X-Gm-Message-State: AOJu0YyZtloWy33zHontsyAy5VWTcugHeZ5U+9a8I4ctHz6EKfYADVO4 85eynviT3HfkVWmd0jhJN14= X-Google-Smtp-Source: AGHT+IEOkjZXltAhrtnhwEnbij0DD7+8jrJs7AJO43DBKXoVJWZCjFxj9aEltjYAltAsr/r98W3oEQ== X-Received: by 2002:a05:6870:b246:b0:1d5:a303:5f47 with SMTP id b6-20020a056870b24600b001d5a3035f47mr23699680oam.17.1696960965756; Tue, 10 Oct 2023 11:02:45 -0700 (PDT) X-BeenThere: swupdate@googlegroups.com Received: by 2002:a05:6871:2211:b0:1e9:88a0:a67c with SMTP id sc17-20020a056871221100b001e988a0a67cls221509oab.2.-pod-prod-01-us; Tue, 10 Oct 2023 11:02:44 -0700 (PDT) X-Received: by 2002:a05:6358:722:b0:14b:9537:b18e with SMTP id e34-20020a056358072200b0014b9537b18emr19464406rwj.7.1696960964654; Tue, 10 Oct 2023 11:02:44 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1696960964; cv=none; d=google.com; s=arc-20160816; b=Q+2piy5ahpUWO57yH5DbrCZtljSzYLQ0pAM5FVGX5+d5q71CgtWfUJZmKcgBXjluXG HxmtVW6yigVvENhog7LxjUHv9yUvlQkoaxtsfv6rkhyLaFtBn+5q6hWBEp+rIbzcvfTL +Hz40NbxRO5KyLd85b/b+EefT5yR0mWwT5wWm4eCJ2Tjx5rYpVqBPWXISVTcAovhJkDp n4pf+su0NkPobHvTzxpNLQb1IkBLKE28vU7TvezwppPN0MgxMc+fTLmsVzlDt6uu1tnn FonhSAEDWWsiz/YQ6xYgEqTTikH69e7qA9qSxpAIlVFRNYSmuEVWaQ3cPwdjcngIeaMd E4Qw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dkim-signature; bh=IW/TrMkTq+0OI75Ed8YwKLeLiXd6HQz+qqI2kQ9Ho7E=; fh=tUC4qYxnJeA7+O+/WQCoFUmd+pUfHX4EpA/OX8BQcSU=; b=o81wOyOZ9XXEkoUPaNpoquxpR2J5yhBUrj+Ec+ACjffrmFs/xswSbYKq4Evfqc074I R4g1mWpvKKAB8wBab2ZkTGDOCtJ+dk/8YWnYlBC0mkXt+4MSbbqyG5D1ClYdE65uLKSy GhMBodOGhMLh7jACvn2SInsH4dsuAXzVOqo2wEp2ShTafA0rL+1TZS228kvTj9+UsAkn eIGMC34KqW9p+2+X45Q8ELPPjG4GJbDINEs7ZbCOZgtUaBYYqookI9tO1FpI+iWQspnh Wv0bGuEaVjcOOL/NkDXTXtVQNilvIlUMg3oIPYNYAiJt2ui1mWN+pFe7nlipYLWQnUhp 7F0w== ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=RHfgCsg0; spf=pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::22f 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-oi1-x22f.google.com (mail-oi1-x22f.google.com. [2607:f8b0:4864:20::22f]) by gmr-mx.google.com with ESMTPS id dw19-20020a056a00369300b0068e35848ad4si834899pfb.5.2023.10.10.11.02.44 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Tue, 10 Oct 2023 11:02:44 -0700 (PDT) Received-SPF: pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::22f as permitted sender) client-ip=2607:f8b0:4864:20::22f; Received: by mail-oi1-x22f.google.com with SMTP id 5614622812f47-3af604c3f8fso4199757b6e.1 for ; Tue, 10 Oct 2023 11:02:44 -0700 (PDT) X-Received: by 2002:a05:6808:1484:b0:3af:6c30:f206 with SMTP id e4-20020a056808148400b003af6c30f206mr26396591oiw.10.1696960963615; Tue, 10 Oct 2023 11:02:43 -0700 (PDT) Received: from localhost.localdomain (198-84-204-38.cpe.teksavvy.com. [198.84.204.38]) by smtp.gmail.com with ESMTPSA id e30-20020a0caa5e000000b0065b1b5cd70csm5008368qvb.31.2023.10.10.11.02.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Oct 2023 11:02:42 -0700 (PDT) From: amy.fong.3142@gmail.com To: swupdate@googlegroups.com Cc: Amy Fong Subject: [swupdate] [PATCH v3] gpg: add optional gpg signing verification Date: Tue, 10 Oct 2023 14:02:14 -0400 Message-Id: <20231010180212.1369429-1-amy.fong@siemens.com> X-Mailer: git-send-email 2.39.2 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=RHfgCsg0; spf=pass (google.com: domain of amy.fong.3142@gmail.com designates 2607:f8b0:4864:20::22f 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 - To enable, configure with CONFIG_SIGALG_GPG - Runtime configuration requirements: - gpg home directory: gpg-home-dir in swupdate.cfg - gpgme signing protocol: gpgme-protocol in swupdate.cfg (supported openpgp or cms) Signed-off-by: Amy Fong --- Kconfig | 3 +- Makefile.flags | 4 + core/swupdate.c | 23 ++++- corelib/Makefile | 1 + corelib/swupdate_gpg_verify.c | 171 ++++++++++++++++++++++++++++++++++ corelib/verify_signature.c | 4 + doc/source/signed_images.rst | 78 +++++++++++++++- include/sslapi.h | 5 + include/swupdate.h | 2 + 9 files changed, 284 insertions(+), 7 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..6de9303 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -305,3 +305,7 @@ 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/swupdate.c b/core/swupdate.c index 6b536b8..7c9c72b 100644 --- a/core/swupdate.c +++ b/core/swupdate.c @@ -150,6 +150,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" @@ -158,6 +159,7 @@ static void usage(char *programname) #endif " --ca-path : path to the Certificate Authority (PEM)\n" #endif +#endif #ifdef CONFIG_ENCRYPTED_IMAGES " -K, --key-aes : the file contains the symmetric key to be used\n" " to decrypt images\n" @@ -338,6 +340,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,9 +476,11 @@ 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; #endif +#endif #ifdef CONFIG_ENCRYPTED_IMAGES strcat(main_options, "K:"); #endif @@ -746,6 +754,19 @@ 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); + } + if (!strlen(swcfg.gpgme_protocol)) { + fprintf(stderr, + "Error: SWUpdate is built for signed images, please specify GnuPG protocol.\n"); + exit(EXIT_FAILURE); + } +#endif + if (opt_c && !opt_i) { fprintf(stderr, "Error: Checking local images requires -i .\n"); @@ -767,7 +788,7 @@ int main(int argc, char **argv) swupdate_crypto_init(); - if (strlen(swcfg.publickeyfname)) { + if (strlen(swcfg.publickeyfname) || strlen(swcfg.gpg_home_directory)) { if (swupdate_dgst_init(&swcfg, swcfg.publickeyfname)) { fprintf(stderr, "Error: Crypto cannot be initialized.\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..8a00f20 --- /dev/null +++ b/corelib/swupdate_gpg_verify.c @@ -0,0 +1,171 @@ +/* + * 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(struct swupdate_digest *dgst, const char *sigfile, + const char *file, const char *signer_name) +{ + 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; + } + + if (dgst->gpgme_protocol != NULL) { + DEBUG("gpg: Enabling protocol %s", dgst->gpgme_protocol); + if (!strcmp(dgst->gpgme_protocol, "openpgp")) { + TRACE("gpg: using protocol OpenPGP"); + protocol = GPGME_PROTOCOL_OpenPGP; + } else if (!strcmp(dgst->gpgme_protocol, "cms")) { + TRACE("gpg: using protocol cms"); + protocol = GPGME_PROTOCOL_CMS; + } else { + ERROR("gpg: unsupported protocol! %s", dgst->gpgme_protocol); + status = -EFAULT; + goto out; + } + } else { + ERROR("gpg protocol unspecified!"); + status = -EFAULT; + goto out; + } + + gpgme_set_protocol(ctx, protocol); + gpgme_set_status_cb(ctx, status_cb, NULL); + if (dgst->verbose == 1) { + gpgme_set_ctx_flag(ctx, "full-status", "1"); + } + gpgme_set_locale(ctx, LC_ALL, setlocale(LC_ALL, "")); + + if (dgst->gpg_home_directory != NULL) { + err = gpgme_ctx_set_engine_info(ctx, protocol, NULL, dgst->gpg_home_directory); + 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; + } + } + + 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; + } + + 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/corelib/verify_signature.c b/corelib/verify_signature.c index 69989fe..227b3b5 100644 --- a/corelib/verify_signature.c +++ b/corelib/verify_signature.c @@ -174,6 +174,10 @@ int swupdate_dgst_init(struct swupdate_cfg *sw, const char *keyfile) } #endif +#elif defined(CONFIG_SIGALG_GPG) + dgst->gpg_home_directory = sw->gpg_home_directory; + dgst->gpgme_protocol = sw->gpgme_protocol; + dgst->verbose = sw->verbose; #else TRACE("public key / cert %s ignored, you need to set SIGALG", keyfile); #endif diff --git a/doc/source/signed_images.rst b/doc/source/signed_images.rst index 581196d..b17aa3a 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,30 @@ 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 GPG key will +need to be imported to the device's GnuPG home directory. To do this, the +key will need to be exported: + +:: + gpg --export --output + +You can then copy it onto the device and import it into your public keyring: + +:: + gpg --import + +To verify that the key has been imported successfully: + +:: + gpg --list-keys + +SWUpdate will need need to be configured with the following parameters: + +:: + GnuPG Home directory: gpg-home-dir in swupdate.cfg + GPGME Protocol: gpgme-protocol in swupdate.cfg: openpgp or cms diff --git a/include/sslapi.h b/include/sslapi.h index a24a152..4668fe7 100644 --- a/include/sslapi.h +++ b/include/sslapi.h @@ -156,6 +156,11 @@ struct swupdate_digest { #elif defined(CONFIG_ENCRYPTED_IMAGES) mbedtls_cipher_context_t mbedtls_cipher_context; #endif /* CONFIG_PKCS11 */ +#ifdef CONFIG_SIGALG_GPG + char *gpg_home_directory; + int verbose + char *gpgme_protocol; +#endif }; #else /* CONFIG_SSL_IMPL */ 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 { \