From patchwork Tue Jul 4 23:44:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Pinchart X-Patchwork-Id: 18790 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id D2420BE175 for ; Tue, 4 Jul 2023 23:44:27 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id 85773628C6; Wed, 5 Jul 2023 01:44:27 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=libcamera.org; s=mail; t=1688514267; bh=iEdix/OWABLXGxrQNNTgQQnpSHQbkuYsrSoxBnMEMQw=; h=To:Date:In-Reply-To:References:Subject:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=HcgEPo3xlY4/IWHr8QAwC1J4eeMpcgDa3UM3ujumRvB05Tgn/4ebqLZ/LFGtM6XLt PgrtQG9/MYPcgo5f20gwegCVssnllpAtSp2X1hGl71XfNrzWfkGuQ6C7tk+Tw/Q2ts 2JLYJq2SsoFX7SSu+maD58VR8VzeXiusq+oCCscwwnZIf34Yy8A2pBrnOjH0YinlRw O/3THXIoqTyQp3V5k3oagbV9Pvvz15L7YRvLyU/wbss068PMPhfNA8dzfZIEi3dAxk A3lW3/sAvp9JlxioJFDJfDUfngSLnXzTnKVFVAZ6utM/xzWVnAjJgKnbuKFhW1aRZt Egk/mnW53nLow== Received: from perceval.ideasonboard.com (perceval.ideasonboard.com [213.167.242.64]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 23917628BB for ; Wed, 5 Jul 2023 01:44:25 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=ideasonboard.com header.i=@ideasonboard.com header.b="L7WH24bv"; dkim-atps=neutral Received: from pendragon.ideasonboard.com (85-160-42-71.reb.o2.cz [85.160.42.71]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 9892E8CC for ; Wed, 5 Jul 2023 01:43:40 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com; s=mail; t=1688514220; bh=iEdix/OWABLXGxrQNNTgQQnpSHQbkuYsrSoxBnMEMQw=; h=From:To:Subject:Date:In-Reply-To:References:From; b=L7WH24bvsfc1M5IjtcUFaZCydgzGhPyPDErWmGmgrLm3zXZ6aBf9F1y7PQAMwFgpp ThsZyvS+VjrhucddT5ZLnGUVSb1hamt4lT4HlS7YtOawBLKgnhZBaBy0D9K7X2c2w3 oRwoVeqOqJDRHgDfUtbO2liB5htllymKmTRpgA1E= To: libcamera-devel@lists.libcamera.org Date: Wed, 5 Jul 2023 02:44:22 +0300 Message-Id: <20230704234422.11863-3-laurent.pinchart@ideasonboard.com> X-Mailer: git-send-email 2.39.3 In-Reply-To: <20230704234422.11863-1-laurent.pinchart@ideasonboard.com> References: <20230704234422.11863-1-laurent.pinchart@ideasonboard.com> MIME-Version: 1.0 Subject: [libcamera-devel] [PATCH v2 2/2] apps: Add ipa-verify application X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Laurent Pinchart via libcamera-devel From: Laurent Pinchart Reply-To: Laurent Pinchart Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" When packaging libcamera, distributions may break IPA module signatures if the packaging process strips binaries. This can be fixed by resigning the modules, but the process is error-prone. Add a command line ipa-verify utility that tests the signature on an IPA module to help packagers. The tool takes a single argument, the path to an IPA module shared object, and expects the signature file (.sign) to be in the same directory. In order to access the public key needed for signature verification, add a static function to the IPAManager class. As the class is internal to libcamera, this doesn't affect the public API. Signed-off-by: Laurent Pinchart Reviewed-by: Umang Jain Reviewed-by: Kieran Bingham Tested-by: Javier Martinez Canillas --- include/libcamera/internal/ipa_manager.h | 7 +++ src/apps/ipa-verify/main.cpp | 64 ++++++++++++++++++++++++ src/apps/ipa-verify/meson.build | 15 ++++++ src/apps/meson.build | 2 + src/libcamera/ipa_manager.cpp | 13 +++++ 5 files changed, 101 insertions(+) create mode 100644 src/apps/ipa-verify/main.cpp create mode 100644 src/apps/ipa-verify/meson.build diff --git a/include/libcamera/internal/ipa_manager.h b/include/libcamera/internal/ipa_manager.h index 7f36e58e8bfa..bf823563c91c 100644 --- a/include/libcamera/internal/ipa_manager.h +++ b/include/libcamera/internal/ipa_manager.h @@ -47,6 +47,13 @@ public: return proxy; } +#if HAVE_IPA_PUBKEY + static const PubKey &pubKey() + { + return pubKey_; + } +#endif + private: static IPAManager *self_; diff --git a/src/apps/ipa-verify/main.cpp b/src/apps/ipa-verify/main.cpp new file mode 100644 index 000000000000..76ba5073d25a --- /dev/null +++ b/src/apps/ipa-verify/main.cpp @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023, Ideas on Board Oy + * + * ipa_verify.cpp - Verify signature on an IPA module + */ + +#include +#include + +#include +#include + +#include "libcamera/internal/ipa_manager.h" +#include "libcamera/internal/ipa_module.h" + +using namespace libcamera; + +namespace { + +bool isSignatureValid(IPAModule *ipa) +{ + File file{ ipa->path() }; + if (!file.open(File::OpenModeFlag::ReadOnly)) + return false; + + Span data = file.map(); + if (data.empty()) + return false; + + return IPAManager::pubKey().verify(data, ipa->signature()); +} + +void usage(char *argv0) +{ + std::cout << "Usage: " << basename(argv0) << " ipa_name.so" << std::endl; + std::cout << std::endl; + std::cout << "Verify the signature of an IPA module. The signature file ipa_name.so.sign is" << std::endl; + std::cout << "expected to be in the same directory as the IPA module." << std::endl; +} + +} /* namespace */ + +int main(int argc, char **argv) +{ + if (argc != 2) { + usage(argv[0]); + return EXIT_FAILURE; + } + + IPAModule module{ argv[1] }; + if (!module.isValid()) { + std::cout << "Invalid IPA module " << argv[1] << std::endl; + return EXIT_FAILURE; + } + + if (!isSignatureValid(&module)) { + std::cout << "IPA module signature is invalid" << std::endl; + return EXIT_FAILURE; + } + + std::cout << "IPA module signature is valid" << std::endl; + return 0; +} diff --git a/src/apps/ipa-verify/meson.build b/src/apps/ipa-verify/meson.build new file mode 100644 index 000000000000..7fdda3b9af4b --- /dev/null +++ b/src/apps/ipa-verify/meson.build @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: CC0-1.0 + +if not ipa_sign_module + subdir_done() +endif + +ipa_verify_sources = files([ + 'main.cpp', +]) + +ipa_verify = executable('ipa_verify', ipa_verify_sources, + dependencies : [ + libcamera_private, + ], + install : false) diff --git a/src/apps/meson.build b/src/apps/meson.build index 099876356bd1..af632b9a7b0b 100644 --- a/src/apps/meson.build +++ b/src/apps/meson.build @@ -18,3 +18,5 @@ subdir('lc-compliance') subdir('cam') subdir('qcam') + +subdir('ipa-verify') diff --git a/src/libcamera/ipa_manager.cpp b/src/libcamera/ipa_manager.cpp index ac5397003b50..7a4515d90d7b 100644 --- a/src/libcamera/ipa_manager.cpp +++ b/src/libcamera/ipa_manager.cpp @@ -279,6 +279,19 @@ IPAModule *IPAManager::module(PipelineHandler *pipe, uint32_t minVersion, * found or if the IPA proxy fails to initialize */ +#if HAVE_IPA_PUBKEY +/** + * \fn IPAManager::pubKey() + * \brief Retrieve the IPA module signing public key + * + * IPA module signature verification is normally handled internally by the + * IPAManager class. This function is meant to be used by utilities that need to + * verify signatures externally. + * + * \return The IPA module signing public key + */ +#endif + bool IPAManager::isSignatureValid([[maybe_unused]] IPAModule *ipa) const { #if HAVE_IPA_PUBKEY