| Message ID | 20260408075540.53309-2-hpa@redhat.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series |
|
| Related | show |
Hi 2026. 04. 08. 9:55 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. Is there any point in keeping the RSA path in libcamera? Regards, Barnabás Pőcze > > 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 | 55 ++++++++++++++++++++++++++++++++++++--- > 1 file changed, 52 insertions(+), 3 deletions(-) > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > index f1d73a5c..20f13600 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,30 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > return false; > > #if HAVE_CRYPTO > + > +#if WITH_FIPS > + /* 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); > + LOG(PubKey, Error) << "Verify with ML-DSA-65: " << ret; > + return ret == 1; > +#else > + /* RSA with SHA-256 */ > + > /* > * Create and initialize a public key algorithm context for signature > * verification. > @@ -117,7 +154,11 @@ 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); > + > + LOG(PubKey, Error) << "Verify with RSA-SHA256: " << ret; > return ret == 1; > +#endif > + > #elif HAVE_GNUTLS > const gnutls_datum_t gnuTlsData{ > const_cast<unsigned char *>(data.data()), > @@ -129,9 +170,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_FIPS > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_MLDSA65, 0, > &gnuTlsData, &gnuTlsSig); > + LOG(PubKey, Error) << "Verify with ML-DSA-65: " << ret; > + return ret >= 0; > +#else > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, > + 0, &gnuTlsData, &gnuTlsSig); > + LOG(PubKey, Error) << "Verify with RSA-SHA256: " << ret; > return ret >= 0; > +#endif > #else > return false; > #endif
Hi Barnabás, On Mon, Apr 13, 2026 at 5:18 PM Barnabás Pőcze <barnabas.pocze@ideasonboard.com> wrote: > > Hi > > 2026. 04. 08. 9:55 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. > > Is there any point in keeping the RSA path in libcamera? Thank you for reviewing this work. RSA is expected to be deprecated by 2035, so I think keeping both algorithms for now is better. Keeping RSA gives more room to the Linux distributor to prepare the PQC migration. After 2035, RSA can be entirely dropped :) > > > Regards, > Barnabás Pőcze > > > > > 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 | 55 ++++++++++++++++++++++++++++++++++++--- > > 1 file changed, 52 insertions(+), 3 deletions(-) > > > > diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp > > index f1d73a5c..20f13600 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,30 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, > > return false; > > > > #if HAVE_CRYPTO > > + > > +#if WITH_FIPS > > + /* 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); > > + LOG(PubKey, Error) << "Verify with ML-DSA-65: " << ret; > > + return ret == 1; > > +#else > > + /* RSA with SHA-256 */ > > + > > /* > > * Create and initialize a public key algorithm context for signature > > * verification. > > @@ -117,7 +154,11 @@ 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); > > + > > + LOG(PubKey, Error) << "Verify with RSA-SHA256: " << ret; > > return ret == 1; > > +#endif > > + > > #elif HAVE_GNUTLS > > const gnutls_datum_t gnuTlsData{ > > const_cast<unsigned char *>(data.data()), > > @@ -129,9 +170,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_FIPS > > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_MLDSA65, 0, > > &gnuTlsData, &gnuTlsSig); > > + LOG(PubKey, Error) << "Verify with ML-DSA-65: " << ret; > > + return ret >= 0; > > +#else > > + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, > > + 0, &gnuTlsData, &gnuTlsSig); > > + LOG(PubKey, Error) << "Verify with RSA-SHA256: " << ret; > > return ret >= 0; > > +#endif > > #else > > return false; > > #endif >
diff --git a/src/libcamera/pub_key.cpp b/src/libcamera/pub_key.cpp index f1d73a5c..20f13600 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,30 @@ bool PubKey::verify([[maybe_unused]] Span<const uint8_t> data, return false; #if HAVE_CRYPTO + +#if WITH_FIPS + /* 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); + LOG(PubKey, Error) << "Verify with ML-DSA-65: " << ret; + return ret == 1; +#else + /* RSA with SHA-256 */ + /* * Create and initialize a public key algorithm context for signature * verification. @@ -117,7 +154,11 @@ 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); + + LOG(PubKey, Error) << "Verify with RSA-SHA256: " << ret; return ret == 1; +#endif + #elif HAVE_GNUTLS const gnutls_datum_t gnuTlsData{ const_cast<unsigned char *>(data.data()), @@ -129,9 +170,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_FIPS + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_MLDSA65, 0, &gnuTlsData, &gnuTlsSig); + LOG(PubKey, Error) << "Verify with ML-DSA-65: " << ret; + return ret >= 0; +#else + int ret = gnutls_pubkey_verify_data2(pubkey_, GNUTLS_SIGN_RSA_SHA256, + 0, &gnuTlsData, &gnuTlsSig); + LOG(PubKey, Error) << "Verify with RSA-SHA256: " << ret; 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 | 55 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-)