| Message ID | 20260519030020.408693-2-hpa@redhat.com |
|---|---|
| State | Changes Requested |
| Headers | show |
| Series |
|
| Related | show |
Hi Kate, Thank you for the patch. On Tue, May 19, 2026 at 11:00:17AM +0800, Kate Hsuan wrote: > As quantum computing advances, traditional signature algorithms are > becoming vulnerable. To ensure long-term data security, this change > implements ML-DSA-65, the primary Post-Quantum Cryptography (PQC) > standard finalized by NIST. This addition prepares for the transition > away from RSA, which is slated for deprecation by 2035. Not that this is a reason not to integrate ML-DSA support, but this series shows in my opinion how blindly designing and applying regulations makes no sense. Quantum computing attacks against the libcamera IPA module signing is not a security concern at all. > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria) > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf > Signed-off-by: Kate Hsuan <hpa@redhat.com> > > ../src/libcamera/pub_key.cpp fix > --- > src/libcamera/pub_key.cpp | 48 ++++++++++++++++++++++++++++++++++++--- > 1 file changed, 45 insertions(+), 3 deletions(-) > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > index f1d73a5c..a169cf7a 100644 > --- a/src/libcamera/pub_key.cpp > +++ b/src/libcamera/pub_key.cpp > @@ -14,8 +14,13 @@ > #include <openssl/x509.h> > #elif HAVE_GNUTLS > #include <gnutls/abstract.h> > +#include <gnutls/gnutls.h> > #endif > > +#include "libcamera/internal/pub_key.h" > +#include <libcamera/base/log.h> > +#include <libcamera/base/utils.h> checkstyle.py reports a warning. > + > /** > * \file pub_key.h > * \brief Public key signature verification > @@ -28,12 +33,18 @@ namespace libcamera { > * \brief Public key wrapper for signature verification > * > * The PubKey class wraps a public key and implements signature verification. It > - * only supports RSA keys and the RSA-SHA256 signature algorithm. > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys > + * as specified in NIST FIPS 204. The signature algorithm is determined in s/in$/at/ > + * compile time. > */ > > /** > * \brief Construct a PubKey from key data > * \param[in] key Key data encoded in DER format > + * > + * The signature algorithm is determined in the compile Incomplete sentence ? We could drop this paragraph as it's already mentioned above in the class documentation. > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65 > + * (verified as ML-DSA-65 according to FIPS 204). > */ > PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key) > : valid_(false) > @@ -83,7 +94,8 @@ PubKey::~PubKey() > * \param[in] sig The signature > * > * Verify that the signature \a sig matches the signed \a data for the public > - * key. The signture algorithm is hardcoded to RSA-SHA256. > + * key. The signature algorithm is determined in compile time. RSA keys use > + * RSA-SHA256, while ML-DSA keys use ML-DSA-65 mentioned in FIPS 204. Here too we could drop the RSA-SHA256 mention. > * > * \return True if the signature is valid, false otherwise > */ > @@ -94,6 +106,25 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > return false; > > #if HAVE_CRYPTO > + > +#if WITH_PQC I would prefer naming this HAVE_CRYPTO_ML_DSA_65. It's more explicit and matches the HAVE_* prefix of other config macros. > + /* ML-DSA */ > + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); > + if (!ctx) > + return false; > + > + utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); }); > + > + if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr, > + pubkey_) <= 0) { Stray curly bracket. > + return false; > + > + int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(), > + data.data(), data.size()); According to the man pages, those functions support RSA with SHA-256. I tested using them with RSA-SHA256 and they seem to work. I think you can drop the existing RSA-SHA-256 code and replace it with EVP_DigestVerify() unconditionally. > + return ret == 1; > +#else > + /* RSA with SHA-256 */ > + > /* > * Create and initialize a public key algorithm context for signature > * verification. > @@ -117,7 +148,10 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest, > SHA256_DIGEST_LENGTH); > EVP_PKEY_CTX_free(ctx); > + > return ret == 1; > +#endif > + > #elif HAVE_GNUTLS > const gnutls_datum_t gnuTlsData{ > const_cast<unsigned char *>(data.data()), > @@ -129,9 +163,17 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > static_cast<unsigned int>(sig.size()) > }; > > - int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0, > +#if WITH_PQC > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_MLDSA65, 0, > &gnuTlsData, &gnuTlsSig); > + > return ret >= 0; > +#else > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, > + 0, &gnuTlsData, &gnuTlsSig); > + > + return ret >= 0; > +#endif Let's minimize the conditional compilation coverage: constexpr gnutls_sign_algorithm_t algo = #if WITH_PQC GNUTLS_SIGN_MLDSA65; #else GNUTLS_SIGN_RSA_SHA256; #endif int ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0, &gnuTlsData, &gnuTlsSig); > #else > return false; > #endif
Hi Laurent, Thank you for reviewing this work. On Mon, Jun 15, 2026 at 10:40 PM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote: > > Hi Kate, > > Thank you for the patch. > > On Tue, May 19, 2026 at 11:00:17AM +0800, Kate Hsuan wrote: > > As quantum computing advances, traditional signature algorithms are > > becoming vulnerable. To ensure long-term data security, this change > > implements ML-DSA-65, the primary Post-Quantum Cryptography (PQC) > > standard finalized by NIST. This addition prepares for the transition > > away from RSA, which is slated for deprecation by 2035. > > Not that this is a reason not to integrate ML-DSA support, but this > series shows in my opinion how blindly designing and applying > regulations makes no sense. Quantum computing attacks against the > libcamera IPA module signing is not a security concern at all. I'll change this and focus on RSA deprecation, such as 1. The RSA is slated for deprecation by 2035. The IPA signature algorithm should be migrated from RSA to a PQC-specified algorithm. 2. Primary Post-Quantum Cryptography (PQC) standard finalized by NIST and the ML-DSA is used for signature. 3. ML-DSA includes ML-DSA-44, ML-DSA-65, and ML-DSA-87 covers different level of data integraty protection. ML-DSA-65 is a balanced option for general purposes, so it is selected to sign the IPA. > > > Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria) > > Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf > > Signed-off-by: Kate Hsuan <hpa@redhat.com> > > > > ../src/libcamera/pub_key.cpp fix > > --- > > src/libcamera/pub_key.cpp | 48 ++++++++++++++++++++++++++++++++++++--- > > 1 file changed, 45 insertions(+), 3 deletions(-) > > > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > > index f1d73a5c..a169cf7a 100644 > > --- a/src/libcamera/pub_key.cpp > > +++ b/src/libcamera/pub_key.cpp > > @@ -14,8 +14,13 @@ > > #include <openssl/x509.h> > > #elif HAVE_GNUTLS > > #include <gnutls/abstract.h> > > +#include <gnutls/gnutls.h> > > #endif > > > > +#include "libcamera/internal/pub_key.h" > > +#include <libcamera/base/log.h> > > +#include <libcamera/base/utils.h> > > checkstyle.py reports a warning. I'll check the style again with checkstyle.py. > > > + > > /** > > * \file pub_key.h > > * \brief Public key signature verification > > @@ -28,12 +33,18 @@ namespace libcamera { > > * \brief Public key wrapper for signature verification > > * > > * The PubKey class wraps a public key and implements signature verification. It > > - * only supports RSA keys and the RSA-SHA256 signature algorithm. > > + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys > > + * as specified in NIST FIPS 204. The signature algorithm is determined in > > s/in$/at/ The signature algorithm is determined at > > > + * compile time. > > */ > > > > /** > > * \brief Construct a PubKey from key data > > * \param[in] key Key data encoded in DER format > > + * > > + * The signature algorithm is determined in the compile > > Incomplete sentence ? Yes :( > > We could drop this paragraph as it's already mentioned above in the > class documentation. Okay. > > > + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65 > > + * (verified as ML-DSA-65 according to FIPS 204). > > */ > > PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key) > > : valid_(false) > > @@ -83,7 +94,8 @@ PubKey::~PubKey() > > * \param[in] sig The signature > > * > > * Verify that the signature \a sig matches the signed \a data for the public > > - * key. The signture algorithm is hardcoded to RSA-SHA256. > > + * key. The signature algorithm is determined in compile time. RSA keys use > > + * RSA-SHA256, while ML-DSA keys use ML-DSA-65 mentioned in FIPS 204. > > Here too we could drop the RSA-SHA256 mention. Okay. > > > * > > * \return True if the signature is valid, false otherwise > > */ > > @@ -94,6 +106,25 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > > return false; > > > > #if HAVE_CRYPTO > > + > > +#if WITH_PQC > > I would prefer naming this HAVE_CRYPTO_ML_DSA_65. It's more explicit and > matches the HAVE_* prefix of other config macros. Discussed in the patch [4/4]. > > > + /* ML-DSA */ > > + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); > > + if (!ctx) > > + return false; > > + > > + utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); }); > > + > > + if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr, > > + pubkey_) <= 0) { > > Stray curly bracket. I'll remove it. > > > + return false; > > + > > + int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(), > > + data.data(), data.size()); > > According to the man pages, those functions support RSA with SHA-256. I > tested using them with RSA-SHA256 and they seem to work. I think you can > drop the existing RSA-SHA-256 code and replace it with > EVP_DigestVerify() unconditionally. Okay > > > + return ret == 1; > > +#else > > + /* RSA with SHA-256 */ > > + > > /* > > * Create and initialize a public key algorithm context for signature > > * verification. > > @@ -117,7 +148,10 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > > int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest, > > SHA256_DIGEST_LENGTH); > > EVP_PKEY_CTX_free(ctx); > > + > > return ret == 1; > > +#endif > > + > > #elif HAVE_GNUTLS > > const gnutls_datum_t gnuTlsData{ > > const_cast<unsigned char *>(data.data()), > > @@ -129,9 +163,17 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > > static_cast<unsigned int>(sig.size()) > > }; > > > > - int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0, > > +#if WITH_PQC > > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_MLDSA65, 0, > > &gnuTlsData, &gnuTlsSig); > > + > > return ret >= 0; > > +#else > > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, > > + 0, &gnuTlsData, &gnuTlsSig); > > + > > + return ret >= 0; > > +#endif > > Let's minimize the conditional compilation coverage: Discussed in the patch [4/4]. > > constexpr gnutls_sign_algorithm_t algo = > #if WITH_PQC > GNUTLS_SIGN_MLDSA65; > #else > GNUTLS_SIGN_RSA_SHA256; > #endif > > int ret = gnutls_pubkey_verify_data2(pubkey_, algo, 0, &gnuTlsData, > &gnuTlsSig); > > > #else > > return false; > > #endif > > -- > Regards, > > Laurent Pinchart >
diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp index f1d73a5c..a169cf7a 100644 --- a/src/libcamera/pub_key.cpp +++ b/src/libcamera/pub_key.cpp @@ -14,8 +14,13 @@ #include <openssl/x509.h> #elif HAVE_GNUTLS #include <gnutls/abstract.h> +#include <gnutls/gnutls.h> #endif +#include "libcamera/internal/pub_key.h" +#include <libcamera/base/log.h> +#include <libcamera/base/utils.h> + /** * \file pub_key.h * \brief Public key signature verification @@ -28,12 +33,18 @@ namespace libcamera { * \brief Public key wrapper for signature verification * * The PubKey class wraps a public key and implements signature verification. It - * only supports RSA keys and the RSA-SHA256 signature algorithm. + * supports RSA keys with the RSA-SHA256 signature algorithm, or ML-DSA-65 keys + * as specified in NIST FIPS 204. The signature algorithm is determined in + * compile time. */ /** * \brief Construct a PubKey from key data * \param[in] key Key data encoded in DER format + * + * The signature algorithm is determined in the compile + * Supported key types are RSA (verified with RSA-SHA256) and ML-DSA-65 + * (verified as ML-DSA-65 according to FIPS 204). */ PubKey::PubKey([[maybe_unused]] Span<const uint8_t> key) : valid_(false) @@ -83,7 +94,8 @@ PubKey::~PubKey() * \param[in] sig The signature * * Verify that the signature \a sig matches the signed \a data for the public - * key. The signture algorithm is hardcoded to RSA-SHA256. + * key. The signature algorithm is determined in compile time. RSA keys use + * RSA-SHA256, while ML-DSA keys use ML-DSA-65 mentioned in FIPS 204. * * \return True if the signature is valid, false otherwise */ @@ -94,6 +106,25 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, return false; #if HAVE_CRYPTO + +#if WITH_PQC + /* ML-DSA */ + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + if (!ctx) + return false; + + utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx); }); + + if (EVP_DigestVerifyInit(ctx, nullptr, nullptr, nullptr, + pubkey_) <= 0) { + return false; + + int ret = EVP_DigestVerify(ctx, sig.data(), sig.size(), + data.data(), data.size()); + return ret == 1; +#else + /* RSA with SHA-256 */ + /* * Create and initialize a public key algorithm context for signature * verification. @@ -117,7 +148,10 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, int ret = EVP_PKEY_verify(ctx, sig.data(), sig.size(), digest, SHA256_DIGEST_LENGTH); EVP_PKEY_CTX_free(ctx); + return ret == 1; +#endif + #elif HAVE_GNUTLS const gnutls_datum_t gnuTlsData{ const_cast<unsigned char *>(data.data()), @@ -129,9 +163,17 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, static_cast<unsigned int>(sig.size()) }; - int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, 0, +#if WITH_PQC + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_MLDSA65, 0, &gnuTlsData, &gnuTlsSig); + return ret >= 0; +#else + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, + 0, &gnuTlsData, &gnuTlsSig); + + return ret >= 0; +#endif #else return false; #endif
As quantum computing advances, traditional signature algorithms are becoming vulnerable. To ensure long-term data security, this change implements ML-DSA-65, the primary Post-Quantum Cryptography (PQC) standard finalized by NIST. This addition prepares for the transition away from RSA, which is slated for deprecation by 2035. Link: https://csrc.nist.gov/projects/post-quantum-cryptography/post-quantum-cryptography-standardization/evaluation-criteria/security-(evaluation-criteria) Link: https://nvlpubs.nist.gov/nistpubs/ir/2024/NIST.IR.8547.ipd.pdf Signed-off-by: Kate Hsuan <hpa@redhat.com> ../src/libcamera/pub_key.cpp fix --- src/libcamera/pub_key.cpp | 48 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-)