| Message ID | 20260422044736.24717-2-hpa@redhat.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi 2026. 04. 22. 6:47 keltezéssel, Kate Hsuan írta: > 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> > --- One thing that I believe is worth discussing is whether to keep the RSA signature at all? I have no checked yet, but if at least the platforms in the CI all support the PQ signature, then I think there is not much point in keeping RSA? > src/libcamera/pub_key.cpp | 53 ++++++++++++++++++++++++++++++++++++--- > 1 file changed, 50 insertions(+), 3 deletions(-) > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > index f1d73a5c..71c1900b 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 > @@ -23,17 +28,24 @@ > > namespace libcamera { > > +LOG_DEFINE_CATEGORY(PubKey); > /** > * \class PubKey > * \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 +95,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 +107,29 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > return false; > > #if HAVE_CRYPTO > + > +#if WITH_PQC > + /* ML-DSA */ > + EVP_MD_CTX *ctx_dsa = EVP_MD_CTX_new(); I think this can be called `ctx` just like for rsa. > + if (!ctx_dsa) { > + LOG(PubKey, Error) << "Initialize context for ML-DSA failed"; > + return false; > + } I'd add utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx_dsa); }); here and drop the manual calls. > + > + if (EVP_DigestVerifyInit(ctx_dsa, nullptr, nullptr, nullptr, > + pubkey_) <= 0) { > + EVP_MD_CTX_free(ctx_dsa); > + LOG(PubKey, Error) << "Initialize ML-DSA verification failed"; > + return false; > + } > + > + int ret = EVP_DigestVerify(ctx_dsa, sig.data(), sig.size(), > + data.data(), data.size()); > + EVP_MD_CTX_free(ctx_dsa); > + return ret == 1; > +#else > + /* RSA with SHA-256 */ > + > /* > * Create and initialize a public key algorithm context for signature > * verification. > @@ -117,7 +153,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 +168,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 Regards, Barnabás Pőcze
On Wed, Apr 29, 2026 at 06:56:55PM +0200, Barnabás Pőcze wrote: > 2026. 04. 22. 6:47 keltezéssel, Kate Hsuan írta: > > 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> > > --- > > One thing that I believe is worth discussing is whether to keep the RSA > signature at all? I have no checked yet, but if at least the platforms in > the CI all support the PQ signature, then I think there is not much point > in keeping RSA? If ML-DSA-65 iss supported in all versions of openssl and gnutls shipped by recent-enough major distributions (that's more or less all the active LTS), then I think we can ditch RSA. > > src/libcamera/pub_key.cpp | 53 ++++++++++++++++++++++++++++++++++++--- > > 1 file changed, 50 insertions(+), 3 deletions(-) > > > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > > index f1d73a5c..71c1900b 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 > > @@ -23,17 +28,24 @@ > > > > namespace libcamera { > > > > +LOG_DEFINE_CATEGORY(PubKey); > > /** > > * \class PubKey > > * \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 +95,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 +107,29 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > > return false; > > > > #if HAVE_CRYPTO > > + > > +#if WITH_PQC > > + /* ML-DSA */ > > + EVP_MD_CTX *ctx_dsa = EVP_MD_CTX_new(); > > I think this can be called `ctx` just like for rsa. > > > > + if (!ctx_dsa) { > > + LOG(PubKey, Error) << "Initialize context for ML-DSA failed"; > > + return false; > > + } > > I'd add > > utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx_dsa); }); > > here and drop the manual calls. > > > > + > > + if (EVP_DigestVerifyInit(ctx_dsa, nullptr, nullptr, nullptr, > > + pubkey_) <= 0) { > > + EVP_MD_CTX_free(ctx_dsa); > > + LOG(PubKey, Error) << "Initialize ML-DSA verification failed"; > > + return false; > > + } > > + > > + int ret = EVP_DigestVerify(ctx_dsa, sig.data(), sig.size(), > > + data.data(), data.size()); > > + EVP_MD_CTX_free(ctx_dsa); > > + return ret == 1; > > +#else > > + /* RSA with SHA-256 */ > > + > > /* > > * Create and initialize a public key algorithm context for signature > > * verification. > > @@ -117,7 +153,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 +168,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
Hi Laurent, On Thu, Apr 30, 2026 at 4:37 AM Laurent Pinchart <laurent.pinchart@ideasonboard.com> wrote: > > On Wed, Apr 29, 2026 at 06:56:55PM +0200, Barnabás Pőcze wrote: > > 2026. 04. 22. 6:47 keltezéssel, Kate Hsuan írta: > > > 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> > > > --- > > > > One thing that I believe is worth discussing is whether to keep the RSA > > signature at all? I have no checked yet, but if at least the platforms in > > the CI all support the PQ signature, then I think there is not much point > > in keeping RSA? > > If ML-DSA-65 iss supported in all versions of openssl and gnutls shipped > by recent-enough major distributions (that's more or less all the active > LTS), then I think we can ditch RSA. Openssl started to ship PQC in OpenSSL 3.5.0 [8 Apr 2025] https://github.com/openssl/openssl/blob/69e54bee8d89f6703eaeca5f4c8b6a8822161c64/NEWS.md?plain=1#L306 gnutls started to ship PQC in release 3.8.9 (released 2025-02-07) https://github.com/gnutls/gnutls/blob/eb55810053382a6fbce7d62d245e98fca659b374/NEWS#L365 The latest releases of both gnutls and openssl are available in Fedora 43. PQC can also be found in Ubuntu 26.04 LTS and Debian 13 So, Okay, I'll drop RSA in the v3 patch. > > > > src/libcamera/pub_key.cpp | 53 ++++++++++++++++++++++++++++++++++++--- > > > 1 file changed, 50 insertions(+), 3 deletions(-) > > > > > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > > > index f1d73a5c..71c1900b 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 > > > @@ -23,17 +28,24 @@ > > > > > > namespace libcamera { > > > > > > +LOG_DEFINE_CATEGORY(PubKey); > > > /** > > > * \class PubKey > > > * \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 +95,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 +107,29 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > > > return false; > > > > > > #if HAVE_CRYPTO > > > + > > > +#if WITH_PQC > > > + /* ML-DSA */ > > > + EVP_MD_CTX *ctx_dsa = EVP_MD_CTX_new(); > > > > I think this can be called `ctx` just like for rsa. > > > > > > > + if (!ctx_dsa) { > > > + LOG(PubKey, Error) << "Initialize context for ML-DSA failed"; > > > + return false; > > > + } > > > > I'd add > > > > utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx_dsa); }); > > > > here and drop the manual calls. > > > > > > > + > > > + if (EVP_DigestVerifyInit(ctx_dsa, nullptr, nullptr, nullptr, > > > + pubkey_) <= 0) { > > > + EVP_MD_CTX_free(ctx_dsa); > > > + LOG(PubKey, Error) << "Initialize ML-DSA verification failed"; > > > + return false; > > > + } > > > + > > > + int ret = EVP_DigestVerify(ctx_dsa, sig.data(), sig.size(), > > > + data.data(), data.size()); > > > + EVP_MD_CTX_free(ctx_dsa); > > > + return ret == 1; > > > +#else > > > + /* RSA with SHA-256 */ > > > + > > > /* > > > * Create and initialize a public key algorithm context for signature > > > * verification. > > > @@ -117,7 +153,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 +168,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 > > -- > Regards, > > Laurent Pinchart >
2026. 05. 04. 5:58 keltezéssel, Kate Hsuan írta: > Hi Laurent, > > On Thu, Apr 30, 2026 at 4:37 AM Laurent Pinchart > <laurent.pinchart@ideasonboard.com> wrote: >> >> On Wed, Apr 29, 2026 at 06:56:55PM +0200, Barnabás Pőcze wrote: >>> 2026. 04. 22. 6:47 keltezéssel, Kate Hsuan írta: >>>> 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> >>>> --- >>> >>> One thing that I believe is worth discussing is whether to keep the RSA >>> signature at all? I have no checked yet, but if at least the platforms in >>> the CI all support the PQ signature, then I think there is not much point >>> in keeping RSA? >> >> If ML-DSA-65 iss supported in all versions of openssl and gnutls shipped >> by recent-enough major distributions (that's more or less all the active >> LTS), then I think we can ditch RSA. > > > Openssl started to ship PQC in OpenSSL 3.5.0 [8 Apr 2025] > https://github.com/openssl/openssl/blob/69e54bee8d89f6703eaeca5f4c8b6a8822161c64/NEWS.md?plain=1#L306 > gnutls started to ship PQC in release 3.8.9 (released 2025-02-07) > https://github.com/gnutls/gnutls/blob/eb55810053382a6fbce7d62d245e98fca659b374/NEWS#L365 > > The latest releases of both gnutls and openssl are available in Fedora 43. > PQC can also be found in Ubuntu 26.04 LTS and Debian 13 > > So, Okay, I'll drop RSA in the v3 patch. I think that will be premature sadly. I believe we want to support e.g. debian 12, which does not seem to have openssl 3.5. > > >> >>>> src/libcamera/pub_key.cpp | 53 ++++++++++++++++++++++++++++++++++++--- >>>> 1 file changed, 50 insertions(+), 3 deletions(-) >>>> >>>> diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp >>>> index f1d73a5c..71c1900b 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 >>>> @@ -23,17 +28,24 @@ >>>> >>>> namespace libcamera { >>>> >>>> +LOG_DEFINE_CATEGORY(PubKey); >>>> /** >>>> * \class PubKey >>>> * \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 +95,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 +107,29 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, >>>> return false; >>>> >>>> #if HAVE_CRYPTO >>>> + >>>> +#if WITH_PQC >>>> + /* ML-DSA */ >>>> + EVP_MD_CTX *ctx_dsa = EVP_MD_CTX_new(); >>> >>> I think this can be called `ctx` just like for rsa. >>> >>> >>>> + if (!ctx_dsa) { >>>> + LOG(PubKey, Error) << "Initialize context for ML-DSA failed"; >>>> + return false; >>>> + } >>> >>> I'd add >>> >>> utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx_dsa); }); >>> >>> here and drop the manual calls. >>> >>> >>>> + >>>> + if (EVP_DigestVerifyInit(ctx_dsa, nullptr, nullptr, nullptr, >>>> + pubkey_) <= 0) { >>>> + EVP_MD_CTX_free(ctx_dsa); >>>> + LOG(PubKey, Error) << "Initialize ML-DSA verification failed"; >>>> + return false; >>>> + } >>>> + >>>> + int ret = EVP_DigestVerify(ctx_dsa, sig.data(), sig.size(), >>>> + data.data(), data.size()); >>>> + EVP_MD_CTX_free(ctx_dsa); >>>> + return ret == 1; >>>> +#else >>>> + /* RSA with SHA-256 */ >>>> + >>>> /* >>>> * Create and initialize a public key algorithm context for signature >>>> * verification. >>>> @@ -117,7 +153,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 +168,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 >> >> -- >> Regards, >> >> Laurent Pinchart >> > >
Hi Barnabás, On Mon, May 4, 2026 at 3:49 PM Barnabás Pőcze <barnabas.pocze@ideasonboard.com> wrote: > > 2026. 05. 04. 5:58 keltezéssel, Kate Hsuan írta: > > Hi Laurent, > > > > On Thu, Apr 30, 2026 at 4:37 AM Laurent Pinchart > > <laurent.pinchart@ideasonboard.com> wrote: > >> > >> On Wed, Apr 29, 2026 at 06:56:55PM +0200, Barnabás Pőcze wrote: > >>> 2026. 04. 22. 6:47 keltezéssel, Kate Hsuan írta: > >>>> 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> > >>>> --- > >>> > >>> One thing that I believe is worth discussing is whether to keep the RSA > >>> signature at all? I have no checked yet, but if at least the platforms in > >>> the CI all support the PQ signature, then I think there is not much point > >>> in keeping RSA? > >> > >> If ML-DSA-65 iss supported in all versions of openssl and gnutls shipped > >> by recent-enough major distributions (that's more or less all the active > >> LTS), then I think we can ditch RSA. > > > > > > Openssl started to ship PQC in OpenSSL 3.5.0 [8 Apr 2025] > > https://github.com/openssl/openssl/blob/69e54bee8d89f6703eaeca5f4c8b6a8822161c64/NEWS.md?plain=1#L306 > > gnutls started to ship PQC in release 3.8.9 (released 2025-02-07) > > https://github.com/gnutls/gnutls/blob/eb55810053382a6fbce7d62d245e98fca659b374/NEWS#L365 > > > > The latest releases of both gnutls and openssl are available in Fedora 43. > > PQC can also be found in Ubuntu 26.04 LTS and Debian 13 > > > > So, Okay, I'll drop RSA in the v3 patch. > > I think that will be premature sadly. I believe we want to support > e.g. debian 12, which does not seem to have openssl 3.5. > Got it. I'll keep RSA in v3. :) > > > > > > >> > >>>> src/libcamera/pub_key.cpp | 53 ++++++++++++++++++++++++++++++++++++--- > >>>> 1 file changed, 50 insertions(+), 3 deletions(-) > >>>> > >>>> diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > >>>> index f1d73a5c..71c1900b 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 > >>>> @@ -23,17 +28,24 @@ > >>>> > >>>> namespace libcamera { > >>>> > >>>> +LOG_DEFINE_CATEGORY(PubKey); > >>>> /** > >>>> * \class PubKey > >>>> * \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 +95,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 +107,29 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > >>>> return false; > >>>> > >>>> #if HAVE_CRYPTO > >>>> + > >>>> +#if WITH_PQC > >>>> + /* ML-DSA */ > >>>> + EVP_MD_CTX *ctx_dsa = EVP_MD_CTX_new(); > >>> > >>> I think this can be called `ctx` just like for rsa. > >>> > >>> > >>>> + if (!ctx_dsa) { > >>>> + LOG(PubKey, Error) << "Initialize context for ML-DSA failed"; > >>>> + return false; > >>>> + } > >>> > >>> I'd add > >>> > >>> utils::scope_exit ctxGuard([&] { EVP_MD_CTX_free(ctx_dsa); }); > >>> > >>> here and drop the manual calls. > >>> > >>> > >>>> + > >>>> + if (EVP_DigestVerifyInit(ctx_dsa, nullptr, nullptr, nullptr, > >>>> + pubkey_) <= 0) { > >>>> + EVP_MD_CTX_free(ctx_dsa); > >>>> + LOG(PubKey, Error) << "Initialize ML-DSA verification failed"; > >>>> + return false; > >>>> + } > >>>> + > >>>> + int ret = EVP_DigestVerify(ctx_dsa, sig.data(), sig.size(), > >>>> + data.data(), data.size()); > >>>> + EVP_MD_CTX_free(ctx_dsa); > >>>> + return ret == 1; > >>>> +#else > >>>> + /* RSA with SHA-256 */ > >>>> + > >>>> /* > >>>> * Create and initialize a public key algorithm context for signature > >>>> * verification. > >>>> @@ -117,7 +153,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 +168,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 > >> > >> -- > >> Regards, > >> > >> Laurent Pinchart > >> > > > > >
diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp index f1d73a5c..71c1900b 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 @@ -23,17 +28,24 @@ namespace libcamera { +LOG_DEFINE_CATEGORY(PubKey); /** * \class PubKey * \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 +95,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 +107,29 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, return false; #if HAVE_CRYPTO + +#if WITH_PQC + /* ML-DSA */ + EVP_MD_CTX *ctx_dsa = EVP_MD_CTX_new(); + if (!ctx_dsa) { + LOG(PubKey, Error) << "Initialize context for ML-DSA failed"; + return false; + } + + if (EVP_DigestVerifyInit(ctx_dsa, nullptr, nullptr, nullptr, + pubkey_) <= 0) { + EVP_MD_CTX_free(ctx_dsa); + LOG(PubKey, Error) << "Initialize ML-DSA verification failed"; + return false; + } + + int ret = EVP_DigestVerify(ctx_dsa, sig.data(), sig.size(), + data.data(), data.size()); + EVP_MD_CTX_free(ctx_dsa); + return ret == 1; +#else + /* RSA with SHA-256 */ + /* * Create and initialize a public key algorithm context for signature * verification. @@ -117,7 +153,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 +168,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 | 53 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-)