[{"id":39544,"web_url":"https://patchwork.libcamera.org/comment/39544/","msgid":"<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>","date":"2026-07-01T08:56:09","subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2026. 07. 01. 6:07 keltezéssel, Kate Hsuan írta:\n> With RSA slated for deprecation by 2035, the IPA signature algorithm must\n> be migrated to a Post-Quantum Cryptography (PQC) standard. Accordingly,\n> we are adopting the NIST-finalized ML-DSA signature scheme. Among the\n> available variants, ML-DSA-44, ML-DSA-65, and ML-DSA-87, which offer\n> varying levels of data integrity protection. ML-DSA-65 has been selected\n> to sign the IPA due to its balanced performance for general-purpose\n> applications.\n> \n> Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria)\n> Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf\n> Signed-off-by: Kate Hsuan <hpa@redhat.com>\n> ---\n>   src/libcamera/pub_key.cpp | 45 ++++++++++++++++++++++-----------------\n>   1 file changed, 25 insertions(+), 20 deletions(-)\n> \n> diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp\n> index f1d73a5c..539a4e6d 100644\n> --- a/src/libcamera/pub_key.cpp\n> +++ b/src/libcamera/pub_key.cpp\n> @@ -14,8 +14,13 @@\n>   #include <openssl/x509.h>\n>   #elif HAVE_GNUTLS\n>   #include <gnutls/abstract.h>\n> +#include <gnutls/gnutls.h>\n>   #endif\n>   \n> +#include <libcamera/base/utils.h>\n> +\n> +#include \"libcamera/internal/pub_key.h\"\n> +\n>   /**\n>    * \\file pub_key.h\n>    * \\brief Public key signature verification\n> @@ -28,12 +33,17 @@ namespace libcamera {\n>    * \\brief Public key wrapper for signature verification\n>    *\n>    * The PubKey class wraps a public key and implements signature verification. It\n> - * only supports RSA keys and the RSA-SHA256 signature algorithm.\n> + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys\n> + * as specified in NIST FIPS 204. The signature algorithm is determined at\n> + * compile time.\n>    */\n>   \n>   /**\n>    * \\brief Construct a PubKey from key data\n>    * \\param[in] key Key data encoded in DER format\n> + *\n> + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65\n> + * (verified as ML-DSA-65 according to FIPS 204).\n>    */\n>   PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key)\n>   \t: valid_(false)\n> @@ -83,7 +93,7 @@ PubKey::~PubKey()\n>    * \\param[in] sig The signature\n>    *\n>    * Verify that the signature \\a sig matches the signed \\a data for the public\n> - * key. The signture algorithm is hardcoded to RSA-SHA256.\n> + * key.\n>    *\n>    * \\return True if the signature is valid, false otherwise\n>    */\n> @@ -94,30 +104,21 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n>   \t\treturn false;\n>   \n>   #if HAVE_CRYPTO\n\nJust for my understanding, the reason `IPA_MODULE_DIR_SIGNATURE_ALGO` is not checked\nwith libcrypto is because it will automatically determine the correct algorithm\n(from the public key or such?)? And I imagine that is not an option with gnutls?\n\n\n> -\t/*\n> -\t * Create and initialize a public key algorithm context for signature\n> -\t * verification.\n> -\t */\n> -\tEVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pubkey_, nullptr);\n> +\tEVP_MD_CTX *ctx = EVP_MD_CTX_new();\n>   \tif (!ctx)\n>   \t\treturn false;\n>   \n> -\tif (EVP_PKEY_verify_init(ctx) <= 0 ||\n> -\t    EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||\n> -\t    EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {\n> -\t\tEVP_PKEY_CTX_free(ctx);\n> +\tutils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); });\n> +\n> +\tif (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr,\n> +\t\t\t\t pubkey_) <= 0)\n>   \t\treturn false;\n> -\t}\n>   \n> -\t/* Calculate the SHA256 digest of the data. */\n> -\tuint8_t digest[SHA256_DIGEST_LENGTH];\n> -\tSHA256(data.data(), data.size(), digest);\n> +\tint ret = EVP_DigestVerify(ctx, sig.data(), sig.size(),\n> +\t\t\t\t   data.data(), data.size());\n>   \n> -\t/* Decrypt the signature and verify it matches the digest. */\n> -\tint ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest,\n> -\t\t\t\t  SHA256_DIGEST_LENGTH);\n> -\tEVP_PKEY_CTX_free(ctx);\n>   \treturn ret == 1;\n> +\n>   #elif HAVE_GNUTLS\n>   \tconst gnutls_datum_t gnuTlsData{\n>   \t\tconst_cast<unsigned char *>(data.data()),\n> @@ -129,8 +130,12 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n>   \t\tstatic_cast<unsigned int>(sig.size())\n>   \t};\n>   \n> -\tint ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0,\n> +\tconstexpr gnutls_sign_algorithm_t algo =\n> +\t\tstd::string(IPA_MODULE_DIR_SIGNATURE_ALGO) == std::string(\"ml-dsa-65\") ? GNUTLS_SIGN_MLDSA65 : GNUTLS_SIGN_RSA_SHA256;\n\nLet's doy\n\n\tconstexpr gnutls_sign_algorithm_t algo = [] {\n\t\tconstexpr std::string_view name = IPA_MODULE_DIR_SIGNATURE_ALGO;\n\n\t\tif constexpr (name == \"ml-dsa-65\")\n\t\t\treturn GNUTLS_SIGN_MLDSA65;\n\t\tif constexpr (name == \"rsa-sha256\")\n\t\t\treturn GNUTLS_SIGN_RSA_SHA256;\n\t} ();\n\nThis way it should be a compilation error if you use an unexpected name for some reason.\n\n> +\n> +\tint ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0,\n>   \t\t\t\t\t     &gnuTlsData, &gnuTlsSig);\n> +\n>   \treturn ret >= 0;\n>   #else\n>   \treturn false;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 6192BC3264\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  1 Jul 2026 08:56:13 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 1427565FA1;\n\tWed,  1 Jul 2026 10:56:13 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 1417C65F29\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  1 Jul 2026 10:56:12 +0200 (CEST)","from [192.168.33.33] (185.221.140.128.nat.pool.zt.hu\n\t[185.221.140.128])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8D978E91;\n\tWed,  1 Jul 2026 10:55:27 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"Yj2jaQlA\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782896127;\n\tbh=+y+aNJo5H/U9IMxKK7Pi/0TyUSCQmGyXwQNPD9p1GRc=;\n\th=Date:Subject:To:References:From:In-Reply-To:From;\n\tb=Yj2jaQlAEpxJDM+4sXqFSiEzlXGiX9Bnqe0RnxFLY1pjikYdPTn/iWmalCrYdHW0x\n\tyJ2bLX4gdiqenOIab/o2pq7MR2ldFQCF+ABh+EnPQ3yFDgoo5tQX/+Z/9PxA3aEndt\n\tZbwR6tbA2Ve/L9NvnB0crrmp2DcghJy870WuORCk=","Message-ID":"<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>","Date":"Wed, 1 Jul 2026 10:56:09 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","To":"Kate Hsuan <hpa@redhat.com>, libcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>,\n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>","References":"<20260701040721.145659-1-hpa@redhat.com>\n\t<20260701040721.145659-2-hpa@redhat.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20260701040721.145659-2-hpa@redhat.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39551,"web_url":"https://patchwork.libcamera.org/comment/39551/","msgid":"<20260701124146.GA3433808@killaraus.ideasonboard.com>","date":"2026-07-01T12:41:46","subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Jul 01, 2026 at 10:56:09AM +0200, Barnabás Pőcze wrote:\n> Hi\n> \n> 2026. 07. 01. 6:07 keltezéssel, Kate Hsuan írta:\n> > With RSA slated for deprecation by 2035, the IPA signature algorithm must\n> > be migrated to a Post-Quantum Cryptography (PQC) standard. Accordingly,\n> > we are adopting the NIST-finalized ML-DSA signature scheme. Among the\n> > available variants, ML-DSA-44, ML-DSA-65, and ML-DSA-87, which offer\n> > varying levels of data integrity protection. ML-DSA-65 has been selected\n> > to sign the IPA due to its balanced performance for general-purpose\n> > applications.\n> > \n> > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria)\n> > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf\n> > Signed-off-by: Kate Hsuan <hpa@redhat.com>\n> > ---\n> >   src/libcamera/pub_key.cpp | 45 ++++++++++++++++++++++-----------------\n> >   1 file changed, 25 insertions(+), 20 deletions(-)\n> > \n> > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp\n> > index f1d73a5c..539a4e6d 100644\n> > --- a/src/libcamera/pub_key.cpp\n> > +++ b/src/libcamera/pub_key.cpp\n> > @@ -14,8 +14,13 @@\n> >   #include <openssl/x509.h>\n> >   #elif HAVE_GNUTLS\n> >   #include <gnutls/abstract.h>\n> > +#include <gnutls/gnutls.h>\n> >   #endif\n> >   \n> > +#include <libcamera/base/utils.h>\n> > +\n> > +#include \"libcamera/internal/pub_key.h\"\n> > +\n> >   /**\n> >    * \\file pub_key.h\n> >    * \\brief Public key signature verification\n> > @@ -28,12 +33,17 @@ namespace libcamera {\n> >    * \\brief Public key wrapper for signature verification\n> >    *\n> >    * The PubKey class wraps a public key and implements signature verification. It\n> > - * only supports RSA keys and the RSA-SHA256 signature algorithm.\n> > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys\n> > + * as specified in NIST FIPS 204. The signature algorithm is determined at\n> > + * compile time.\n> >    */\n> >   \n> >   /**\n> >    * \\brief Construct a PubKey from key data\n> >    * \\param[in] key Key data encoded in DER format\n> > + *\n> > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65\n> > + * (verified as ML-DSA-65 according to FIPS 204).\n> >    */\n> >   PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key)\n> >   \t: valid_(false)\n> > @@ -83,7 +93,7 @@ PubKey::~PubKey()\n> >    * \\param[in] sig The signature\n> >    *\n> >    * Verify that the signature \\a sig matches the signed \\a data for the public\n> > - * key. The signture algorithm is hardcoded to RSA-SHA256.\n> > + * key.\n> >    *\n> >    * \\return True if the signature is valid, false otherwise\n> >    */\n> > @@ -94,30 +104,21 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> >   \t\treturn false;\n> >   \n> >   #if HAVE_CRYPTO\n> \n> Just for my understanding, the reason `IPA_MODULE_DIR_SIGNATURE_ALGO` is not checked\n> with libcrypto is because it will automatically determine the correct algorithm\n> (from the public key or such?)? And I imagine that is not an option with gnutls?\n\nThe following seems to work for gnutls (error handling left as an\nexercise for the reader):\n\n\tgnutls_digest_algorithm_t hash;\n\tgnutls_pubkey_get_preferred_hash_algorithm(pubkey_, &hash, nullptr);\n\tgnutls_pk_algorithm_t pkeyAlgo = static_cast<gnutls_pk_algorithm_t>(gnutls_pubkey_get_pk_algorithm(pubkey_, nullptr));\n        gnutls_sign_algorithm_t algo = gnutls_pk_to_sign(pkeyAlgo, hash);\n\nIt may be a bit complex and a bit fragile though.\n\n> > -\t/*\n> > -\t * Create and initialize a public key algorithm context for signature\n> > -\t * verification.\n> > -\t */\n> > -\tEVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pubkey_, nullptr);\n> > +\tEVP_MD_CTX *ctx = EVP_MD_CTX_new();\n> >   \tif (!ctx)\n> >   \t\treturn false;\n> >   \n> > -\tif (EVP_PKEY_verify_init(ctx) <= 0 ||\n> > -\t    EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||\n> > -\t    EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {\n> > -\t\tEVP_PKEY_CTX_free(ctx);\n> > +\tutils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); });\n> > +\n> > +\tif (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr,\n> > +\t\t\t\t pubkey_) <= 0)\n> >   \t\treturn false;\n> > -\t}\n> >   \n> > -\t/* Calculate the SHA256 digest of the data. */\n> > -\tuint8_t digest[SHA256_DIGEST_LENGTH];\n> > -\tSHA256(data.data(), data.size(), digest);\n> > +\tint ret = EVP_DigestVerify(ctx, sig.data(), sig.size(),\n> > +\t\t\t\t   data.data(), data.size());\n> >   \n> > -\t/* Decrypt the signature and verify it matches the digest. */\n> > -\tint ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest,\n> > -\t\t\t\t  SHA256_DIGEST_LENGTH);\n> > -\tEVP_PKEY_CTX_free(ctx);\n> >   \treturn ret == 1;\n> > +\n> >   #elif HAVE_GNUTLS\n> >   \tconst gnutls_datum_t gnuTlsData{\n> >   \t\tconst_cast<unsigned char *>(data.data()),\n> > @@ -129,8 +130,12 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> >   \t\tstatic_cast<unsigned int>(sig.size())\n> >   \t};\n> >   \n> > -\tint ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0,\n> > +\tconstexpr gnutls_sign_algorithm_t algo =\n> > +\t\tstd::string(IPA_MODULE_DIR_SIGNATURE_ALGO) == std::string(\"ml-dsa-65\") ? GNUTLS_SIGN_MLDSA65 : GNUTLS_SIGN_RSA_SHA256;\n> \n> Let's doy\n> \n> \tconstexpr gnutls_sign_algorithm_t algo = [] {\n> \t\tconstexpr std::string_view name = IPA_MODULE_DIR_SIGNATURE_ALGO;\n> \n> \t\tif constexpr (name == \"ml-dsa-65\")\n> \t\t\treturn GNUTLS_SIGN_MLDSA65;\n> \t\tif constexpr (name == \"rsa-sha256\")\n> \t\t\treturn GNUTLS_SIGN_RSA_SHA256;\n> \t} ();\n> \n> This way it should be a compilation error if you use an unexpected name for some reason.\n> \n> > +\n> > +\tint ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0,\n> >   \t\t\t\t\t     &gnuTlsData, &gnuTlsSig);\n> > +\n> >   \treturn ret >= 0;\n> >   #else\n> >   \treturn false;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 5DBF9C3306\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed,  1 Jul 2026 12:41:51 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6D3FD65FA3;\n\tWed,  1 Jul 2026 14:41:50 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id A662E65F14\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed,  1 Jul 2026 14:41:48 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-70f3-e800--a06.rev.dnainternet.fi\n\t[IPv6:2001:14ba:70f3:e800::a06])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 8EA0C1E76;\n\tWed,  1 Jul 2026 14:41:03 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"gOo0UIFM\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782909663;\n\tbh=QDqhONBZ10DuWOX+kMP7rJc2Fzd2Y5mbOdo3o3DyMZM=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=gOo0UIFM+Ikii7AOENSPzrs/UF2APGctx8zw3j2xG8skT7ILVIdnxwNxOtjkK8or5\n\twoBhxvVnnlraYYkncGVB8Vv6Ym8+D0f9OASM5Qzc2VkHO6GD6FU0pQPBjYqS2xfENb\n\te0Mp/Tf0yvFlJ+0PCQbw48ED/GmhJjF1aaYsmP1M=","Date":"Wed, 1 Jul 2026 15:41:46 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"Kate Hsuan <hpa@redhat.com>, libcamera-devel@lists.libcamera.org,\n\tKieran Bingham <kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","Message-ID":"<20260701124146.GA3433808@killaraus.ideasonboard.com>","References":"<20260701040721.145659-1-hpa@redhat.com>\n\t<20260701040721.145659-2-hpa@redhat.com>\n\t<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39556,"web_url":"https://patchwork.libcamera.org/comment/39556/","msgid":"<CAEth8oGzDKjFB0Dh95+m_fQL9TKbKq4LnwE=ani1mC0eQyksKw@mail.gmail.com>","date":"2026-07-02T03:25:52","subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","submitter":{"id":105,"url":"https://patchwork.libcamera.org/api/people/105/","name":"Kate Hsuan","email":"hpa@redhat.com"},"content":"Hi Barnabás,\n\nThank you for reviewing.\n\nOn Wed, Jul 1, 2026 at 4:56 AM Barnabás Pőcze\n<barnabas.pocze@ideasonboard.com> wrote:\n>\n> Hi\n>\n> 2026. 07. 01. 6:07 keltezéssel, Kate Hsuan írta:\n> > With RSA slated for deprecation by 2035, the IPA signature algorithm must\n> > be migrated to a Post-Quantum Cryptography (PQC) standard. Accordingly,\n> > we are adopting the NIST-finalized ML-DSA signature scheme. Among the\n> > available variants, ML-DSA-44, ML-DSA-65, and ML-DSA-87, which offer\n> > varying levels of data integrity protection. ML-DSA-65 has been selected\n> > to sign the IPA due to its balanced performance for general-purpose\n> > applications.\n> >\n> > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria)\n> > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf\n> > Signed-off-by: Kate Hsuan <hpa@redhat.com>\n> > ---\n> >   src/libcamera/pub_key.cpp | 45 ++++++++++++++++++++++-----------------\n> >   1 file changed, 25 insertions(+), 20 deletions(-)\n> >\n> > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp\n> > index f1d73a5c..539a4e6d 100644\n> > --- a/src/libcamera/pub_key.cpp\n> > +++ b/src/libcamera/pub_key.cpp\n> > @@ -14,8 +14,13 @@\n> >   #include <openssl/x509.h>\n> >   #elif HAVE_GNUTLS\n> >   #include <gnutls/abstract.h>\n> > +#include <gnutls/gnutls.h>\n> >   #endif\n> >\n> > +#include <libcamera/base/utils.h>\n> > +\n> > +#include \"libcamera/internal/pub_key.h\"\n> > +\n> >   /**\n> >    * \\file pub_key.ha\n> >    * \\brief Public key signature verification\n> > @@ -28,12 +33,17 @@ namespace libcamera {\n> >    * \\brief Public key wrapper for signature verification\n> >    *\n> >    * The PubKey class wraps a public key and implements signature verification. It\n> > - * only supports RSA keys and the RSA-SHA256 signature algorithm.\n> > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys\n> > + * as specified in NIST FIPS 204. The signature algorithm is determined at\n> > + * compile time.\n> >    */\n> >\n> >   /**\n> >    * \\brief Construct a PubKey from key data\n> >    * \\param[in] key Key data encoded in DER format\n> > + *\n> > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65\n> > + * (verified as ML-DSA-65 according to FIPS 204).\n> >    */\n> >   PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key)\n> >       : valid_(false)\n> > @@ -83,7 +93,7 @@ PubKey::~PubKey()\n> >    * \\param[in] sig The signature\n> >    *\n> >    * Verify that the signature \\a sig matches the signed \\a data for the public\n> > - * key. The signture algorithm is hardcoded to RSA-SHA256.\n> > + * key.\n> >    *\n> >    * \\return True if the signature is valid, false otherwise\n> >    */\n> > @@ -94,30 +104,21 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> >               return false;\n> >\n> >   #if HAVE_CRYPTO\n>\n> Just for my understanding, the reason `IPA_MODULE_DIR_SIGNATURE_ALGO` is not checked\n> with libcrypto is because it will automatically determine the correct algorithm\n> (from the public key or such?)? And I imagine that is not an option with gnutls?\n\nEVP_DigestVerify() works for both so IPA_MODULE_DIR_SIGNATURE_ALGO\nwasn't needed fro libcrypto.\n\n\n>\n>\n> > -     /*\n> > -      * Create and initialize a public key algorithm context for signature\n> > -      * verification.\n> > -      */\n> > -     EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pubkey_, nullptr);\n> > +     EVP_MD_CTX *ctx = EVP_MD_CTX_new();\n> >       if (!ctx)\n> >               return false;\n> >\n> > -     if (EVP_PKEY_verify_init(ctx) <= 0 ||\n> > -         EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||\n> > -         EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {\n> > -             EVP_PKEY_CTX_free(ctx);\n> > +     utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); });\n> > +\n> > +     if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr,\n> > +                              pubkey_) <= 0)\n> >               return false;\n> > -     }\n> >\n> > -     /* Calculate the SHA256 digest of the data. */\n> > -     uint8_t digest[SHA256_DIGEST_LENGTH];\n> > -     SHA256(data.data(), data.size(), digest);\n> > +     int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(),\n> > +                                data.data(), data.size());\n> >\n> > -     /* Decrypt the signature and verify it matches the digest. */\n> > -     int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest,\n> > -                               SHA256_DIGEST_LENGTH);\n> > -     EVP_PKEY_CTX_free(ctx);\n> >       return ret == 1;\n> > +\n> >   #elif HAVE_GNUTLS\n> >       const gnutls_datum_t gnuTlsData{\n> >               const_cast<unsigned char *>(data.data()),\n> > @@ -129,8 +130,12 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> >               static_cast<unsigned int>(sig.size())\n> >       };\n> >\n> > -     int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0,\n> > +     constexpr gnutls_sign_algorithm_t algo =\n> > +             std::string(IPA_MODULE_DIR_SIGNATURE_ALGO) == std::string(\"ml-dsa-65\") ? GNUTLS_SIGN_MLDSA65 : GNUTLS_SIGN_RSA_SHA256;\n>\n> Let's doy\n>\n>         constexpr gnutls_sign_algorithm_t algo = [] {\n>                 constexpr std::string_view name = IPA_MODULE_DIR_SIGNATURE_ALGO;\n>\n>                 if constexpr (name == \"ml-dsa-65\")\n>                         return GNUTLS_SIGN_MLDSA65;\n>                 if constexpr (name == \"rsa-sha256\")\n>                         return GNUTLS_SIGN_RSA_SHA256;\n>         } ();\n>\n> This way it should be a compilation error if you use an unexpected name for some reason.\nmeson already verify the algorithm string but Laurent proposed a\nbetter way to distinguish the types of the algorithm for gnutls. Let's\ntry that way.\n\n>\n> > +\n> > +     int ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0,\n> >                                            &gnuTlsData, &gnuTlsSig);\n> > +\n> >       return ret >= 0;\n> >   #else\n> >       return false;\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 17B44C3301\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  2 Jul 2026 03:26:12 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 344B665F11;\n\tThu,  2 Jul 2026 05:26:11 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id AC6AD65EFF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  2 Jul 2026 05:26:09 +0200 (CEST)","from mail-oi1-f200.google.com (mail-oi1-f200.google.com\n\t[209.85.167.200]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-64-nccP9YWbNAWxY3ipTy1P0A-1; Wed, 01 Jul 2026 23:26:05 -0400","by mail-oi1-f200.google.com with SMTP id\n\t5614622812f47-495f637105eso2126755b6e.2\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 01 Jul 2026 20:26:05 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"dSr89HKX\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1782962768;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=ljwNwtzqspbmTMNWa3VOPckltOjsMCAgoSEf+eQm570=;\n\tb=dSr89HKXJsMOz6JykWdZLpWNATXnwgLvjeHDRfk+klHuDFYDZEWNG4c7PnTPKWDhY0GJqV\n\tojJDS4b3XaSTSzSkIlTNe/uB23y1NJVBjny6bPdiVkJeGzTIVSxar/bV5uprMM7enZqd4F\n\tfhLhMnW95HvRUL4KThjvK89m0L3nXfk=","X-MC-Unique":"nccP9YWbNAWxY3ipTy1P0A-1","X-Mimecast-MFC-AGG-ID":"nccP9YWbNAWxY3ipTy1P0A_1782962764","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1782962764; x=1783567564;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n\t:to:cc:subject:date:message-id:reply-to;\n\tbh=ljwNwtzqspbmTMNWa3VOPckltOjsMCAgoSEf+eQm570=;\n\tb=sUNltX9HvziCAn4HiBCnTjOAh+yg6gKc4pNISIsFcpxTHpD3K5N6MDFDIw3sx8gN/5\n\t2MF//17Biz4aIp8ZJdOEjjvqhIrJeeYmt0CDX4+qGeoegnWMfzyYtIlmQ3obOHI2oNcP\n\tS1n5+X3mIpwO0g6q5nfvPPWKjKb6rzPY9LxPlO9HS5Wjqkhvg1pqzWSrbWbzdhEBpLaj\n\tRk5C+LrfMsOzjsYRDcctsQMKK/itnmbZa8tyBX+YqjkmSqmOJMoNso6C5RSnnpERN5G9\n\tHxUema0KhtzGGZWxwyd7lQm4SlU+lvirw+twkly+ehpxlGjzAmadM8TlA/STXm+/OFr6\n\t8Xzw==","X-Gm-Message-State":"AOJu0Yzs7TvbfU/p105VHUGiv06h+43uV3IZVRLGtC0lgaGazUetlK3b\n\t2NHx5vL+7KffmPhtqq86GTsjflng/c4b4rK+MSR8TT5NKfncOm3isq8uoBvCfyzOtVp2tBJWS7n\n\tIYTpiGK+S6sCeEfkf85T+mK5Ga3I/Ka3K4HTQcNfJAsT4FkTXrXtWawe+NaCmSQDVXSgRHfaKj5\n\t2qXuOAZqLzTgUFU0TCFr6f3wGRoqLlejfnWZ244pvBIacGUFxG2Q==","X-Gm-Gg":"AfdE7cngbOErl0Pzz+iIOeKPCsz35hxgmZ27e2Kqe41X/Q4gWzBnDnTLUzquWoIFjDW\n\tTnSGjXSS7LKfQVJ166NYwdZtuQxM/E5p4CdisMNA+OvSDM7mw1P+KCJLP9u3B4/6JySYqYKqpid\n\tSXYmgX4YONSlD+lIImJz9oANB2Bc9xU47kU94+YzmxliotrKSlBPBxKuScj/M9Fa4XEac=","X-Received":["by 2002:a05:6808:1495:b0:495:d8b:642d with SMTP id\n\t5614622812f47-4960ef205a1mr2892768b6e.25.1782962764386; \n\tWed, 01 Jul 2026 20:26:04 -0700 (PDT)","by 2002:a05:6808:1495:b0:495:d8b:642d with SMTP id\n\t5614622812f47-4960ef205a1mr2892749b6e.25.1782962763716;\n\tWed, 01 Jul 2026 20:26:03 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260701040721.145659-1-hpa@redhat.com>\n\t<20260701040721.145659-2-hpa@redhat.com>\n\t<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>","In-Reply-To":"<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>","From":"Kate Hsuan <hpa@redhat.com>","Date":"Wed, 1 Jul 2026 23:25:52 -0400","X-Gm-Features":"AVVi8CebQWdWSdBoO-7Dg8AM80azP5Vp6wKSZxJvK3zHx8VlqXqArpE28oq9TdE","Message-ID":"<CAEth8oGzDKjFB0Dh95+m_fQL9TKbKq4LnwE=ani1mC0eQyksKw@mail.gmail.com>","Subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","To":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org, \n\tKieran Bingham <kieran.bingham@ideasonboard.com>, \n\tLaurent Pinchart <laurent.pinchart@ideasonboard.com>","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"p7hZGI-foQoEGCrGnwzd4rVhaT38ugyXlIaKhxAh1tI_1782962764","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39557,"web_url":"https://patchwork.libcamera.org/comment/39557/","msgid":"<CAEth8oE5Lk_5dXmyOgqR8rOGpJNJpBJ3UXJA3z_OLFTm90bUPA@mail.gmail.com>","date":"2026-07-02T03:39:44","subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","submitter":{"id":105,"url":"https://patchwork.libcamera.org/api/people/105/","name":"Kate Hsuan","email":"hpa@redhat.com"},"content":"Hi Laurent and Barnabás\n\nOn Wed, Jul 1, 2026 at 8:41 AM Laurent Pinchart\n<laurent.pinchart@ideasonboard.com> wrote:\n>\n> On Wed, Jul 01, 2026 at 10:56:09AM +0200, Barnabás Pőcze wrote:\n> > Hi\n> >\n> > 2026. 07. 01. 6:07 keltezéssel, Kate Hsuan írta:\n> > > With RSA slated for deprecation by 2035, the IPA signature algorithm must\n> > > be migrated to a Post-Quantum Cryptography (PQC) standard. Accordingly,\n> > > we are adopting the NIST-finalized ML-DSA signature scheme. Among the\n> > > available variants, ML-DSA-44, ML-DSA-65, and ML-DSA-87, which offer\n> > > varying levels of data integrity protection. ML-DSA-65 has been selected\n> > > to sign the IPA due to its balanced performance for general-purpose\n> > > applications.\n> > >\n> > > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria)\n> > > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf\n> > > Signed-off-by: Kate Hsuan <hpa@redhat.com>\n> > > ---\n> > >   src/libcamera/pub_key.cpp | 45 ++++++++++++++++++++++-----------------\n> > >   1 file changed, 25 insertions(+), 20 deletions(-)\n> > >\n> > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp\n> > > index f1d73a5c..539a4e6d 100644\n> > > --- a/src/libcamera/pub_key.cpp\n> > > +++ b/src/libcamera/pub_key.cpp\n> > > @@ -14,8 +14,13 @@\n> > >   #include <openssl/x509.h>\n> > >   #elif HAVE_GNUTLS\n> > >   #include <gnutls/abstract.h>\n> > > +#include <gnutls/gnutls.h>\n> > >   #endif\n> > >\n> > > +#include <libcamera/base/utils.h>\n> > > +\n> > > +#include \"libcamera/internal/pub_key.h\"\n> > > +\n> > >   /**\n> > >    * \\file pub_key.h\n> > >    * \\brief Public key signature verification\n> > > @@ -28,12 +33,17 @@ namespace libcamera {\n> > >    * \\brief Public key wrapper for signature verification\n> > >    *\n> > >    * The PubKey class wraps a public key and implements signature verification. It\n> > > - * only supports RSA keys and the RSA-SHA256 signature algorithm.\n> > > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys\n> > > + * as specified in NIST FIPS 204. The signature algorithm is determined at\n> > > + * compile time.\n> > >    */\n> > >\n> > >   /**\n> > >    * \\brief Construct a PubKey from key data\n> > >    * \\param[in] key Key data encoded in DER format\n> > > + *\n> > > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65\n> > > + * (verified as ML-DSA-65 according to FIPS 204).\n> > >    */\n> > >   PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key)\n> > >     : valid_(false)\n> > > @@ -83,7 +93,7 @@ PubKey::~PubKey()\n> > >    * \\param[in] sig The signature\n> > >    *\n> > >    * Verify that the signature \\a sig matches the signed \\a data for the public\n> > > - * key. The signture algorithm is hardcoded to RSA-SHA256.\n> > > + * key.\n> > >    *\n> > >    * \\return True if the signature is valid, false otherwise\n> > >    */\n> > > @@ -94,30 +104,21 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> > >             return false;\n> > >\n> > >   #if HAVE_CRYPTO\n> >\n> > Just for my understanding, the reason `IPA_MODULE_DIR_SIGNATURE_ALGO` is not checked\n> > with libcrypto is because it will automatically determine the correct algorithm\n> > (from the public key or such?)? And I imagine that is not an option with gnutls?\n>\n> The following seems to work for gnutls (error handling left as an\n> exercise for the reader):\n>\n>         gnutls_digest_algorithm_t hash;\n>         gnutls_pubkey_get_preferred_hash_algorithm(pubkey_, &hash, nullptr);\n>         gnutls_pk_algorithm_t pkeyAlgo = static_cast<gnutls_pk_algorithm_t>(gnutls_pubkey_get_pk_algorithm(pubkey_, nullptr));\n>         gnutls_sign_algorithm_t algo = gnutls_pk_to_sign(pkeyAlgo, hash);\n>\n> It may be a bit complex and a bit fragile though.\n\nThat means fetching the algorithm from the keys and libcamera may not\nfollow the meson_option to work if two types of valid keys are\navailiable.\nI'll try to mix both suggestions and check the algorithm set via the\nmeson option.\n\n>\n> > > -   /*\n> > > -    * Create and initialize a public key algorithm context for signature\n> > > -    * verification.\n> > > -    */\n> > > -   EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pubkey_, nullptr);\n> > > +   EVP_MD_CTX *ctx = EVP_MD_CTX_new();\n> > >     if (!ctx)\n> > >             return false;\n> > >\n> > > -   if (EVP_PKEY_verify_init(ctx) <= 0 ||\n> > > -       EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||\n> > > -       EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {\n> > > -           EVP_PKEY_CTX_free(ctx);\n> > > +   utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); });\n> > > +\n> > > +   if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr,\n> > > +                            pubkey_) <= 0)\n> > >             return false;\n> > > -   }\n> > >\n> > > -   /* Calculate the SHA256 digest of the data. */\n> > > -   uint8_t digest[SHA256_DIGEST_LENGTH];\n> > > -   SHA256(data.data(), data.size(), digest);\n> > > +   int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(),\n> > > +                              data.data(), data.size());\n> > >\n> > > -   /* Decrypt the signature and verify it matches the digest. */\n> > > -   int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest,\n> > > -                             SHA256_DIGEST_LENGTH);\n> > > -   EVP_PKEY_CTX_free(ctx);\n> > >     return ret == 1;\n> > > +\n> > >   #elif HAVE_GNUTLS\n> > >     const gnutls_datum_t gnuTlsData{\n> > >             const_cast<unsigned char *>(data.data()),\n> > > @@ -129,8 +130,12 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> > >             static_cast<unsigned int>(sig.size())\n> > >     };\n> > >\n> > > -   int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0,\n> > > +   constexpr gnutls_sign_algorithm_t algo =\n> > > +           std::string(IPA_MODULE_DIR_SIGNATURE_ALGO) == std::string(\"ml-dsa-65\") ? GNUTLS_SIGN_MLDSA65 : GNUTLS_SIGN_RSA_SHA256;\n> >\n> > Let's doy\n> >\n> >       constexpr gnutls_sign_algorithm_t algo = [] {\n> >               constexpr std::string_view name = IPA_MODULE_DIR_SIGNATURE_ALGO;\n> >\n> >               if constexpr (name == \"ml-dsa-65\")\n> >                       return GNUTLS_SIGN_MLDSA65;\n> >               if constexpr (name == \"rsa-sha256\")\n> >                       return GNUTLS_SIGN_RSA_SHA256;\n> >       } ();\n> >\n> > This way it should be a compilation error if you use an unexpected name for some reason.\n> >\n> > > +\n> > > +   int ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0,\n> > >                                          &gnuTlsData, &gnuTlsSig);\n> > > +\n> > >     return ret >= 0;\n> > >   #else\n> > >     return false;\n>\n> --\n> Regards,\n>\n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id DB0C7C3302\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  2 Jul 2026 03:40:03 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id ED93F65FB4;\n\tThu,  2 Jul 2026 05:40:02 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.129.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2C80065EFF\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  2 Jul 2026 05:40:01 +0200 (CEST)","from mail-oi1-f198.google.com (mail-oi1-f198.google.com\n\t[209.85.167.198]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-149-x043fSCkNiCu5wCmAdp6pw-1; Wed, 01 Jul 2026 23:39:58 -0400","by mail-oi1-f198.google.com with SMTP id\n\t5614622812f47-48a4c610ebdso1825972b6e.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 01 Jul 2026 20:39:58 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"ZIyViuL2\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1782963600;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=FtTvygCdm8PuBWsa2dWVk7tdsl1hErD2WPbBeQlBmww=;\n\tb=ZIyViuL2ldkpmTEURJjDhYNhz/nQXc9shnIoVC1QduLtS4QdB4Z1xuloS3+kXax0jSeMCt\n\tXVoBVxu3Ha9NXijiRDE3SaA6K0sHTfyS+ly2ksmedSBwNqa3/A0sNPMaHGZDG3o1JOT0tf\n\t2c1gETbJXJO29l3IY5APi/u6x95wvtE=","X-MC-Unique":"x043fSCkNiCu5wCmAdp6pw-1","X-Mimecast-MFC-AGG-ID":"x043fSCkNiCu5wCmAdp6pw_1782963598","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1782963598; x=1783568398;\n\th=content-transfer-encoding:cc:to:subject:message-id:date:from\n\t:in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from\n\t:to:cc:subject:date:message-id:reply-to;\n\tbh=FtTvygCdm8PuBWsa2dWVk7tdsl1hErD2WPbBeQlBmww=;\n\tb=j52O1Ieug9TYinFIA7oi1RBOwMPnUAIPYAtOIdtUbEKkWNhET6Qkq4T+qQitGNuxhw\n\tTqMa7mWMKXrc8IW+QlkJUAAWBUEOh1R6ovXym4juYX4ykea9nBrJScaMiXVjJdF68ylA\n\tVxCHQKfhjrZRr49uG2nW97G65nAEwCnecmwYB4tJMLVFSd8ob6ke0pfGihZe9eSLVKzN\n\tXDhCXA9SFWyYbko4kXdDhg3dsKPotgJhKO9dlVeZveRdoMQXku0d2aIC4urs2PI63vrE\n\tN9/yOzEiV/IeLH4dvVOILjR3Gvu4pRhAS7U7e4epsUgFu9PYZuRmLu0q/7ygS1g5nkD5\n\t+Wrg==","X-Forwarded-Encrypted":"i=1;\n\tAFNElJ9ICmHIUNVyMCEAYXtaBp9wOjyA5LBUBA46gdtpHjk5vKGhtDq/VG+pKHl/sBs6ZVyLNm0Tpi9fE/MjFzvLVZo=@lists.libcamera.org","X-Gm-Message-State":"AOJu0Yxb3PPtkTDgYOSAZq+NLafsd6+4DxJYBjtfMLIRiCmmHugbjqVm\n\tM7+Kdxr9lwL2Ks0oG+vw5YJL92bplOFpZRpYGcCJuUQQ5MXSpu7hFjI17QsOtMI88xwFgjjgrS1\n\t9FA8ltgkAoGYW1otLdtfR2k6ZKWn1kNPqHmhGwVaZ/WYymrIaBg+S7GbkwHlnAb8FwrdlhQ86uA\n\tnAj6pH0/ILBv/5W8zVnRl2r0kIsrOq4p2mUPA/WCDnsbiQWoshgAUQvMbNC6Vk","X-Gm-Gg":"AfdE7cnoJBcbKDvfoEqcKPGsnO2fFL58VOsQIdiuSjNDIaBJB5M271fg+TYW8OfrWku\n\tcGp2xInp5Zeh+Do5728KGGyfXhVdS9StqsQ/AMYeKejUaSX9jUme1b5YJSSHmvaSiZscFhR0sCu\n\tnQE6OjvlnMvyZVR0HGRlZCwbBQSG1ZS3dmkyG8luVDl0yJG8TdSUnxbdRM8GJQIHuCLwo=","X-Received":["by 2002:a05:6809:387:10b0:496:fd18:402e with SMTP id\n\t5614622812f47-496fd18411fmr1390825b6e.42.1782963597726; \n\tWed, 01 Jul 2026 20:39:57 -0700 (PDT)","by 2002:a05:6809:387:10b0:496:fd18:402e with SMTP id\n\t5614622812f47-496fd18411fmr1390818b6e.42.1782963597240;\n\tWed, 01 Jul 2026 20:39:57 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260701040721.145659-1-hpa@redhat.com>\n\t<20260701040721.145659-2-hpa@redhat.com>\n\t<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>\n\t<20260701124146.GA3433808@killaraus.ideasonboard.com>","In-Reply-To":"<20260701124146.GA3433808@killaraus.ideasonboard.com>","From":"Kate Hsuan <hpa@redhat.com>","Date":"Wed, 1 Jul 2026 23:39:44 -0400","X-Gm-Features":"AVVi8CcEAK0IPQl_UqHkYp4PdXxqFDENoI9g3pdupoc5_kqZUZELtL259u7dOi4","Message-ID":"<CAEth8oE5Lk_5dXmyOgqR8rOGpJNJpBJ3UXJA3z_OLFTm90bUPA@mail.gmail.com>","Subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"ZrOeaL7dMYjZ5MNz0Vd1HOjTW4AAeFdrQ_1Rf0JduDw_1782963598","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39559,"web_url":"https://patchwork.libcamera.org/comment/39559/","msgid":"<20260702082819.GI3433808@killaraus.ideasonboard.com>","date":"2026-07-02T08:28:19","subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Wed, Jul 01, 2026 at 11:39:44PM -0400, Kate Hsuan wrote:\n> On Wed, Jul 1, 2026 at 8:41 AM Laurent Pinchart wrote:\n> > On Wed, Jul 01, 2026 at 10:56:09AM +0200, Barnabás Pőcze wrote:\n> > > 2026. 07. 01. 6:07 keltezéssel, Kate Hsuan írta:\n> > > > With RSA slated for deprecation by 2035, the IPA signature algorithm must\n> > > > be migrated to a Post-Quantum Cryptography (PQC) standard. Accordingly,\n> > > > we are adopting the NIST-finalized ML-DSA signature scheme. Among the\n> > > > available variants, ML-DSA-44, ML-DSA-65, and ML-DSA-87, which offer\n> > > > varying levels of data integrity protection. ML-DSA-65 has been selected\n> > > > to sign the IPA due to its balanced performance for general-purpose\n> > > > applications.\n> > > >\n> > > > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria)\n> > > > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf\n> > > > Signed-off-by: Kate Hsuan <hpa@redhat.com>\n> > > > ---\n> > > >   src/libcamera/pub_key.cpp | 45 ++++++++++++++++++++++-----------------\n> > > >   1 file changed, 25 insertions(+), 20 deletions(-)\n> > > >\n> > > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp\n> > > > index f1d73a5c..539a4e6d 100644\n> > > > --- a/src/libcamera/pub_key.cpp\n> > > > +++ b/src/libcamera/pub_key.cpp\n> > > > @@ -14,8 +14,13 @@\n> > > >   #include <openssl/x509.h>\n> > > >   #elif HAVE_GNUTLS\n> > > >   #include <gnutls/abstract.h>\n> > > > +#include <gnutls/gnutls.h>\n> > > >   #endif\n> > > >\n> > > > +#include <libcamera/base/utils.h>\n> > > > +\n> > > > +#include \"libcamera/internal/pub_key.h\"\n> > > > +\n> > > >   /**\n> > > >    * \\file pub_key.h\n> > > >    * \\brief Public key signature verification\n> > > > @@ -28,12 +33,17 @@ namespace libcamera {\n> > > >    * \\brief Public key wrapper for signature verification\n> > > >    *\n> > > >    * The PubKey class wraps a public key and implements signature verification. It\n> > > > - * only supports RSA keys and the RSA-SHA256 signature algorithm.\n> > > > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys\n> > > > + * as specified in NIST FIPS 204. The signature algorithm is determined at\n> > > > + * compile time.\n> > > >    */\n> > > >\n> > > >   /**\n> > > >    * \\brief Construct a PubKey from key data\n> > > >    * \\param[in] key Key data encoded in DER format\n> > > > + *\n> > > > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65\n> > > > + * (verified as ML-DSA-65 according to FIPS 204).\n> > > >    */\n> > > >   PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key)\n> > > >     : valid_(false)\n> > > > @@ -83,7 +93,7 @@ PubKey::~PubKey()\n> > > >    * \\param[in] sig The signature\n> > > >    *\n> > > >    * Verify that the signature \\a sig matches the signed \\a data for the public\n> > > > - * key. The signture algorithm is hardcoded to RSA-SHA256.\n> > > > + * key.\n> > > >    *\n> > > >    * \\return True if the signature is valid, false otherwise\n> > > >    */\n> > > > @@ -94,30 +104,21 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> > > >             return false;\n> > > >\n> > > >   #if HAVE_CRYPTO\n> > >\n> > > Just for my understanding, the reason `IPA_MODULE_DIR_SIGNATURE_ALGO` is not checked\n> > > with libcrypto is because it will automatically determine the correct algorithm\n> > > (from the public key or such?)? And I imagine that is not an option with gnutls?\n> >\n> > The following seems to work for gnutls (error handling left as an\n> > exercise for the reader):\n> >\n> >         gnutls_digest_algorithm_t hash;\n> >         gnutls_pubkey_get_preferred_hash_algorithm(pubkey_, &hash, nullptr);\n> >         gnutls_pk_algorithm_t pkeyAlgo = static_cast<gnutls_pk_algorithm_t>(gnutls_pubkey_get_pk_algorithm(pubkey_, nullptr));\n> >         gnutls_sign_algorithm_t algo = gnutls_pk_to_sign(pkeyAlgo, hash);\n> >\n> > It may be a bit complex and a bit fragile though.\n> \n> That means fetching the algorithm from the keys and libcamera may not\n> follow the meson_option to work if two types of valid keys are\n> availiable.\n> I'll try to mix both suggestions and check the algorithm set via the\n> meson option.\n\nPlease note that I'm not sure the complexity of the above code is worth\nit, especially after adding error checking. For MLDSA65 keys there's a\nsingle possible signature algorithm, but for RSA keys I think multiple\noptions are possible. gnutls_pubkey_get_preferred_hash_algorithm()\nreturns the SHA256 digest, I suppose that's not an implementation\ndetails of gnutls, but I'm not 100% sure.\n\n> > > > -   /*\n> > > > -    * Create and initialize a public key algorithm context for signature\n> > > > -    * verification.\n> > > > -    */\n> > > > -   EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pubkey_, nullptr);\n> > > > +   EVP_MD_CTX *ctx = EVP_MD_CTX_new();\n> > > >     if (!ctx)\n> > > >             return false;\n> > > >\n> > > > -   if (EVP_PKEY_verify_init(ctx) <= 0 ||\n> > > > -       EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||\n> > > > -       EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {\n> > > > -           EVP_PKEY_CTX_free(ctx);\n> > > > +   utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); });\n> > > > +\n> > > > +   if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr,\n> > > > +                            pubkey_) <= 0)\n> > > >             return false;\n> > > > -   }\n> > > >\n> > > > -   /* Calculate the SHA256 digest of the data. */\n> > > > -   uint8_t digest[SHA256_DIGEST_LENGTH];\n> > > > -   SHA256(data.data(), data.size(), digest);\n> > > > +   int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(),\n> > > > +                              data.data(), data.size());\n> > > >\n> > > > -   /* Decrypt the signature and verify it matches the digest. */\n> > > > -   int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest,\n> > > > -                             SHA256_DIGEST_LENGTH);\n> > > > -   EVP_PKEY_CTX_free(ctx);\n> > > >     return ret == 1;\n> > > > +\n> > > >   #elif HAVE_GNUTLS\n> > > >     const gnutls_datum_t gnuTlsData{\n> > > >             const_cast<unsigned char *>(data.data()),\n> > > > @@ -129,8 +130,12 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> > > >             static_cast<unsigned int>(sig.size())\n> > > >     };\n> > > >\n> > > > -   int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0,\n> > > > +   constexpr gnutls_sign_algorithm_t algo =\n> > > > +           std::string(IPA_MODULE_DIR_SIGNATURE_ALGO) == std::string(\"ml-dsa-65\") ? GNUTLS_SIGN_MLDSA65 : GNUTLS_SIGN_RSA_SHA256;\n> > >\n> > > Let's doy\n> > >\n> > >       constexpr gnutls_sign_algorithm_t algo = [] {\n> > >               constexpr std::string_view name = IPA_MODULE_DIR_SIGNATURE_ALGO;\n> > >\n> > >               if constexpr (name == \"ml-dsa-65\")\n> > >                       return GNUTLS_SIGN_MLDSA65;\n> > >               if constexpr (name == \"rsa-sha256\")\n> > >                       return GNUTLS_SIGN_RSA_SHA256;\n> > >       } ();\n> > >\n> > > This way it should be a compilation error if you use an unexpected name for some reason.\n> > >\n> > > > +\n> > > > +   int ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0,\n> > > >                                          &gnuTlsData, &gnuTlsSig);\n> > > > +\n> > > >     return ret >= 0;\n> > > >   #else\n> > > >     return false;","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 7B5A5C3302\n\tfor <parsemail@patchwork.libcamera.org>;\n\tThu,  2 Jul 2026 08:28:22 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 6763465FAD;\n\tThu,  2 Jul 2026 10:28:21 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 40070656DE\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu,  2 Jul 2026 10:28:20 +0200 (CEST)","from killaraus.ideasonboard.com\n\t(2001-14ba-70f3-e800--a06.rev.dnainternet.fi\n\t[IPv6:2001:14ba:70f3:e800::a06])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id EC0E38FA;\n\tThu,  2 Jul 2026 10:27:34 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"hNtwCcQP\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1782980855;\n\tbh=GpnNhYN9mJSlFDLUh8f5BIVRPO+LbnNZgMDy8MjwG/A=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=hNtwCcQPONsUpiVIbVNP2bPuR+4ikcjvAw1hSrAy9R1Hj+77lawOfzsu9f1MHY9U+\n\tPWtzpIsT9D6KyUbI7aipZoPPPDkXM3OSzD7py6sV1OC3NzdpBd9jgkJFfSq9ew87Br\n\tNwNckfoV6Ty3YWAzHH4XsTANrqzs2zTiF4sHanBw=","Date":"Thu, 2 Jul 2026 11:28:19 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"Kate Hsuan <hpa@redhat.com>","Cc":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>","Subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","Message-ID":"<20260702082819.GI3433808@killaraus.ideasonboard.com>","References":"<20260701040721.145659-1-hpa@redhat.com>\n\t<20260701040721.145659-2-hpa@redhat.com>\n\t<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>\n\t<20260701124146.GA3433808@killaraus.ideasonboard.com>\n\t<CAEth8oE5Lk_5dXmyOgqR8rOGpJNJpBJ3UXJA3z_OLFTm90bUPA@mail.gmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<CAEth8oE5Lk_5dXmyOgqR8rOGpJNJpBJ3UXJA3z_OLFTm90bUPA@mail.gmail.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":39709,"web_url":"https://patchwork.libcamera.org/comment/39709/","msgid":"<CAEth8oGkLp-aLUzE7taMict7+VNoWYeqPnvNPKywmYbqj4nv-w@mail.gmail.com>","date":"2026-07-15T07:55:28","subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","submitter":{"id":105,"url":"https://patchwork.libcamera.org/api/people/105/","name":"Kate Hsuan","email":"hpa@redhat.com"},"content":"Hi Laurent,\n\nOn Thu, Jul 2, 2026 at 4:28 PM Laurent Pinchart\n<laurent.pinchart@ideasonboard.com> wrote:\n>\n> On Wed, Jul 01, 2026 at 11:39:44PM -0400, Kate Hsuan wrote:\n> > On Wed, Jul 1, 2026 at 8:41 AM Laurent Pinchart wrote:\n> > > On Wed, Jul 01, 2026 at 10:56:09AM +0200, Barnabás Pőcze wrote:\n> > > > 2026. 07. 01. 6:07 keltezéssel, Kate Hsuan írta:\n> > > > > With RSA slated for deprecation by 2035, the IPA signature algorithm must\n> > > > > be migrated to a Post-Quantum Cryptography (PQC) standard. Accordingly,\n> > > > > we are adopting the NIST-finalized ML-DSA signature scheme. Among the\n> > > > > available variants, ML-DSA-44, ML-DSA-65, and ML-DSA-87, which offer\n> > > > > varying levels of data integrity protection. ML-DSA-65 has been selected\n> > > > > to sign the IPA due to its balanced performance for general-purpose\n> > > > > applications.\n> > > > >\n> > > > > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria)\n> > > > > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf\n> > > > > Signed-off-by: Kate Hsuan <hpa@redhat.com>\n> > > > > ---\n> > > > >   src/libcamera/pub_key.cpp | 45 ++++++++++++++++++++++-----------------\n> > > > >   1 file changed, 25 insertions(+), 20 deletions(-)\n> > > > >\n> > > > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp\n> > > > > index f1d73a5c..539a4e6d 100644\n> > > > > --- a/src/libcamera/pub_key.cpp\n> > > > > +++ b/src/libcamera/pub_key.cpp\n> > > > > @@ -14,8 +14,13 @@\n> > > > >   #include <openssl/x509.h>\n> > > > >   #elif HAVE_GNUTLS\n> > > > >   #include <gnutls/abstract.h>\n> > > > > +#include <gnutls/gnutls.h>\n> > > > >   #endif\n> > > > >\n> > > > > +#include <libcamera/base/utils.h>\n> > > > > +\n> > > > > +#include \"libcamera/internal/pub_key.h\"\n> > > > > +\n> > > > >   /**\n> > > > >    * \\file pub_key.h\n> > > > >    * \\brief Public key signature verification\n> > > > > @@ -28,12 +33,17 @@ namespace libcamera {\n> > > > >    * \\brief Public key wrapper for signature verification\n> > > > >    *\n> > > > >    * The PubKey class wraps a public key and implements signature verification. It\n> > > > > - * only supports RSA keys and the RSA-SHA256 signature algorithm.\n> > > > > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys\n> > > > > + * as specified in NIST FIPS 204. The signature algorithm is determined at\n> > > > > + * compile time.\n> > > > >    */\n> > > > >\n> > > > >   /**\n> > > > >    * \\brief Construct a PubKey from key data\n> > > > >    * \\param[in] key Key data encoded in DER format\n> > > > > + *\n> > > > > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65\n> > > > > + * (verified as ML-DSA-65 according to FIPS 204).\n> > > > >    */\n> > > > >   PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key)\n> > > > >     : valid_(false)\n> > > > > @@ -83,7 +93,7 @@ PubKey::~PubKey()\n> > > > >    * \\param[in] sig The signature\n> > > > >    *\n> > > > >    * Verify that the signature \\a sig matches the signed \\a data for the public\n> > > > > - * key. The signture algorithm is hardcoded to RSA-SHA256.\n> > > > > + * key.\n> > > > >    *\n> > > > >    * \\return True if the signature is valid, false otherwise\n> > > > >    */\n> > > > > @@ -94,30 +104,21 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> > > > >             return false;\n> > > > >\n> > > > >   #if HAVE_CRYPTO\n> > > >\n> > > > Just for my understanding, the reason `IPA_MODULE_DIR_SIGNATURE_ALGO` is not checked\n> > > > with libcrypto is because it will automatically determine the correct algorithm\n> > > > (from the public key or such?)? And I imagine that is not an option with gnutls?\n> > >\n> > > The following seems to work for gnutls (error handling left as an\n> > > exercise for the reader):\n> > >\n> > >         gnutls_digest_algorithm_t hash;\n> > >         gnutls_pubkey_get_preferred_hash_algorithm(pubkey_, &hash, nullptr);\n> > >         gnutls_pk_algorithm_t pkeyAlgo = static_cast<gnutls_pk_algorithm_t>(gnutls_pubkey_get_pk_algorithm(pubkey_, nullptr));\n> > >         gnutls_sign_algorithm_t algo = gnutls_pk_to_sign(pkeyAlgo, hash);\n> > >\n> > > It may be a bit complex and a bit fragile though.\n> >\n> > That means fetching the algorithm from the keys and libcamera may not\n> > follow the meson_option to work if two types of valid keys are\n> > availiable.\n> > I'll try to mix both suggestions and check the algorithm set via the\n> > meson option.\n>\n> Please note that I'm not sure the complexity of the above code is worth\n> it, especially after adding error checking. For MLDSA65 keys there's a\n> single possible signature algorithm, but for RSA keys I think multiple\n> options are possible. gnutls_pubkey_get_preferred_hash_algorithm()\n> returns the SHA256 digest, I suppose that's not an implementation\n> details of gnutls, but I'm not 100% sure.\n\nI proposed a generic way in v5 to verify both RAS and ML-DSA so the\nconditional compilation is not necessary. For now, both RSA and ML-DSA\nare supported.\nMoreover, the special case for ML-DSA is also considered. (hash\nalgorithm is GNUTLS_DIG_UNKNOWN)\nLet's see if it is a better way for the implementation.\n\n>\n> > > > > -   /*\n> > > > > -    * Create and initialize a public key algorithm context for signature\n> > > > > -    * verification.\n> > > > > -    */\n> > > > > -   EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pubkey_, nullptr);\n> > > > > +   EVP_MD_CTX *ctx = EVP_MD_CTX_new();\n> > > > >     if (!ctx)\n> > > > >             return false;\n> > > > >\n> > > > > -   if (EVP_PKEY_verify_init(ctx) <= 0 ||\n> > > > > -       EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0 ||\n> > > > > -       EVP_PKEY_CTX_set_signature_md(ctx, EVP_sha256()) <= 0) {\n> > > > > -           EVP_PKEY_CTX_free(ctx);\n> > > > > +   utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); });\n> > > > > +\n> > > > > +   if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr,\n> > > > > +                            pubkey_) <= 0)\n> > > > >             return false;\n> > > > > -   }\n> > > > >\n> > > > > -   /* Calculate the SHA256 digest of the data. */\n> > > > > -   uint8_t digest[SHA256_DIGEST_LENGTH];\n> > > > > -   SHA256(data.data(), data.size(), digest);\n> > > > > +   int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(),\n> > > > > +                              data.data(), data.size());\n> > > > >\n> > > > > -   /* Decrypt the signature and verify it matches the digest. */\n> > > > > -   int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest,\n> > > > > -                             SHA256_DIGEST_LENGTH);\n> > > > > -   EVP_PKEY_CTX_free(ctx);\n> > > > >     return ret == 1;\n> > > > > +\n> > > > >   #elif HAVE_GNUTLS\n> > > > >     const gnutls_datum_t gnuTlsData{\n> > > > >             const_cast<unsigned char *>(data.data()),\n> > > > > @@ -129,8 +130,12 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data,\n> > > > >             static_cast<unsigned int>(sig.size())\n> > > > >     };\n> > > > >\n> > > > > -   int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0,\n> > > > > +   constexpr gnutls_sign_algorithm_t algo =\n> > > > > +           std::string(IPA_MODULE_DIR_SIGNATURE_ALGO) == std::string(\"ml-dsa-65\") ? GNUTLS_SIGN_MLDSA65 : GNUTLS_SIGN_RSA_SHA256;\n> > > >\n> > > > Let's doy\n> > > >\n> > > >       constexpr gnutls_sign_algorithm_t algo = [] {\n> > > >               constexpr std::string_view name = IPA_MODULE_DIR_SIGNATURE_ALGO;\n> > > >\n> > > >               if constexpr (name == \"ml-dsa-65\")\n> > > >                       return GNUTLS_SIGN_MLDSA65;\n> > > >               if constexpr (name == \"rsa-sha256\")\n> > > >                       return GNUTLS_SIGN_RSA_SHA256;\n> > > >       } ();\n> > > >\n> > > > This way it should be a compilation error if you use an unexpected name for some reason.\n> > > >\n> > > > > +\n> > > > > +   int ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0,\n> > > > >                                          &gnuTlsData, &gnuTlsSig);\n> > > > > +\n> > > > >     return ret >= 0;\n> > > > >   #else\n> > > > >     return false;\n>\n> --\n> Regards,\n>\n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 6823FC3304\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 15 Jul 2026 07:55:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 63DE466167;\n\tWed, 15 Jul 2026 09:55:46 +0200 (CEST)","from us-smtp-delivery-124.mimecast.com\n\t(us-smtp-delivery-124.mimecast.com [170.10.133.124])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id BD2B566157\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 15 Jul 2026 09:55:44 +0200 (CEST)","from mail-oi1-f198.google.com (mail-oi1-f198.google.com\n\t[209.85.167.198]) by relay.mimecast.com with ESMTP with STARTTLS\n\t(version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id\n\tus-mta-662-i5xboKtuPeCuY6Kb7_xBJQ-1; Wed, 15 Jul 2026 03:55:42 -0400","by mail-oi1-f198.google.com with SMTP id\n\t5614622812f47-49ce04870f8so9069414b6e.0\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 15 Jul 2026 00:55:42 -0700 (PDT)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=redhat.com header.i=@redhat.com\n\theader.b=\"jG0LvmhL\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n\ts=mimecast20190719; t=1784102143;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\tto:to:cc:cc:mime-version:mime-version:content-type:content-type:\n\tcontent-transfer-encoding:content-transfer-encoding:\n\tin-reply-to:in-reply-to:references:references;\n\tbh=G9gkv4iTjfMeJpS4B+wmUo9P0Pbg14s4eBH2Sf3DeXc=;\n\tb=jG0LvmhLJmcnq26FyjbaefTTPsGTtxIGKhkf5xWzSizNuN9szrcf/uJZP/lkcxnPW51rQr\n\t+sqAh71iKqXXY6x1hInSgULHKHsXWKUdJ/7qbjELYx1UUEnbWK9jahqvsIBy+jzJ2WvnDu\n\tjQbJZQ+EOvxg/n47MU3jOaE2eU6Cycg=","X-MC-Unique":"i5xboKtuPeCuY6Kb7_xBJQ-1","X-Mimecast-MFC-AGG-ID":"i5xboKtuPeCuY6Kb7_xBJQ_1784102141","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20251104; t=1784102141; x=1784706941;\n\th=content-transfer-encoding:content-type:cc:to:subject:message-id\n\t:date:from:in-reply-to:references:mime-version:x-gm-gg\n\t:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to\n\t:content-type;\n\tbh=G9gkv4iTjfMeJpS4B+wmUo9P0Pbg14s4eBH2Sf3DeXc=;\n\tb=jeYXKbqcwU1Kie3cvVGeyJ0FX3EaXunMCOnP+wOtzpXJWr0ig1CaS1OvhN1X7zWW3o\n\tgqo0P0Pce3hz/8V1GN2n5o9qmj9MBoXKjc7ntIkTU0FBDGc5LCcnkjS59l7v/AYePBp6\n\ta8V4oTrIBH0LJO9GJeAXbLZzUc32Kk0vxTBaPGvoL45BZAIcb+i2SmndK9iZClleMoGQ\n\tOXcjPK3ROmK3XvHdtY/ir/C4fJB6ju2ZxBT7PoVLT1VzZL4C9UlcKFovRLXp/HhANTUa\n\tX4bDk4EWjqFZ66mx48vGwgJuPZOIBzPp8qQOl9TGVnTOp6PDkWijR5CGnIpApUFuD7gK\n\tFLpA==","X-Forwarded-Encrypted":"i=1;\n\tAHgh+Rqx0pHuBAWWRFz7YIgsAreyRQUtHRgZRXJmviJ+mlLq8L4t5cx8KEbfcfUOegJP0l6NEIPkqU9w6qpeKJsWSqc=@lists.libcamera.org","X-Gm-Message-State":"AOJu0Yymu1ueyUz8rQsWJMJnhhiZqwiQZljDr9wuUVIOK+id/hj4a5a7\n\t/HeM/MNvd0nQ39QYxTSqCSliTU1xoamk+W9d/joFLxJTL1o/mGPVsqEdE9vdVyjhw+zw6Q8lGCn\n\tc48di7NPvsxE+3fqsj/bvbRK2nJLIuOH66R9am9/ffElp6PrUJ7S5HkYozpr4muMDp4yJOaidXd\n\tBFN3lMHsP2xSv+xIrxXltHsnK3FcVk31vkxUpmEtS+HlL4mWXIiQ==","X-Gm-Gg":"AfdE7ckl3ZQb69Nc2XEJ+OkwBA0V+2PfeKauRPPiLQU62KvL0FRArUtjWH6e5wYGxoZ\n\tHX8ZLV5rrwH4LL4UIWSLbWYIOiUYHmBb1I4j+CKUUCk99eKTlu9G2rBtdlIKeoiyIRzC3eCoB68\n\tDIRIWUV9tffR8yBaM8Fqe29bpvXkY+lp20S9jM+gUou436SjaZJkKdZ2oRYotSguH8jOk=","X-Received":["by 2002:a05:6808:1250:b0:495:e677:1332 with SMTP id\n\t5614622812f47-4a47a662ed1mr3098317b6e.36.1784102141365; \n\tWed, 15 Jul 2026 00:55:41 -0700 (PDT)","by 2002:a05:6808:1250:b0:495:e677:1332 with SMTP id\n\t5614622812f47-4a47a662ed1mr3098294b6e.36.1784102140660;\n\tWed, 15 Jul 2026 00:55:40 -0700 (PDT)"],"MIME-Version":"1.0","References":"<20260701040721.145659-1-hpa@redhat.com>\n\t<20260701040721.145659-2-hpa@redhat.com>\n\t<eb0c5fb9-e537-4b33-9412-729b875a0b74@ideasonboard.com>\n\t<20260701124146.GA3433808@killaraus.ideasonboard.com>\n\t<CAEth8oE5Lk_5dXmyOgqR8rOGpJNJpBJ3UXJA3z_OLFTm90bUPA@mail.gmail.com>\n\t<20260702082819.GI3433808@killaraus.ideasonboard.com>","In-Reply-To":"<20260702082819.GI3433808@killaraus.ideasonboard.com>","From":"Kate Hsuan <hpa@redhat.com>","Date":"Wed, 15 Jul 2026 15:55:28 +0800","X-Gm-Features":"AUfX_mw_QJVCv7Che6A8_h8ZZi7Dyev510nlbTGG8YMqWgpX-KdJUBl-lZjsows","Message-ID":"<CAEth8oGkLp-aLUzE7taMict7+VNoWYeqPnvNPKywmYbqj4nv-w@mail.gmail.com>","Subject":"Re: [PATCH v4 1/4] libcamera: pub_key: Add ML-DSA-65 signature\n\talgorithm for PQC compliance","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org, Kieran Bingham\n\t<kieran.bingham@ideasonboard.com>","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"2aGPfErLb-n_VKl1ErcrjOpyiV8uOqL1W9AN-Y5Kv1w_1784102141","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=\"UTF-8\"","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]