@@ -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(-)