Skip to content

Commit 6589f91

Browse files
panvaanonrig
authored andcommitted
crypto: support ML-DSA KeyObject, sign, and verify
PR-URL: nodejs/node#59259 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent 7690da9 commit 6589f91

File tree

2 files changed

+83
-2
lines changed

2 files changed

+83
-2
lines changed

include/ncrypto.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030

3131
#if OPENSSL_VERSION_MAJOR >= 3
3232
#define OSSL3_CONST const
33+
#if OPENSSL_VERSION_MINOR >= 5
34+
#include <openssl/core_names.h>
35+
#endif
3336
#else
3437
#define OSSL3_CONST
3538
#endif
@@ -834,6 +837,10 @@ class EVPKeyPointer final {
834837
const Buffer<const unsigned char>& data);
835838
static EVPKeyPointer NewRawPrivate(int id,
836839
const Buffer<const unsigned char>& data);
840+
#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
841+
static EVPKeyPointer NewRawSeed(int id,
842+
const Buffer<const unsigned char>& data);
843+
#endif
837844
static EVPKeyPointer NewDH(DHPointer&& dh);
838845
static EVPKeyPointer NewRSA(RSAPointer&& rsa);
839846

@@ -927,6 +934,10 @@ class EVPKeyPointer final {
927934
DataPointer rawPrivateKey() const;
928935
BIOPointer derPublicKey() const;
929936

937+
#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
938+
DataPointer rawSeed() const;
939+
#endif
940+
930941
Result<BIOPointer, bool> writePrivateKey(
931942
const PrivateKeyEncodingConfig& config) const;
932943
Result<BIOPointer, bool> writePublicKey(

src/ncrypto.cpp

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,6 +2035,31 @@ EVPKeyPointer EVPKeyPointer::NewRawPrivate(
20352035
EVP_PKEY_new_raw_private_key(id, nullptr, data.data, data.len));
20362036
}
20372037

2038+
#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
2039+
EVPKeyPointer EVPKeyPointer::NewRawSeed(
2040+
int id, const Buffer<const unsigned char>& data) {
2041+
if (id == 0) return {};
2042+
2043+
OSSL_PARAM params[] = {
2044+
OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_ML_DSA_SEED,
2045+
const_cast<unsigned char*>(data.data),
2046+
data.len),
2047+
OSSL_PARAM_END};
2048+
2049+
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(id, nullptr);
2050+
if (ctx == nullptr) return {};
2051+
2052+
EVP_PKEY* pkey = nullptr;
2053+
if (ctx == nullptr || EVP_PKEY_fromdata_init(ctx) <= 0 ||
2054+
EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) <= 0) {
2055+
EVP_PKEY_CTX_free(ctx);
2056+
return {};
2057+
}
2058+
2059+
return EVPKeyPointer(pkey);
2060+
}
2061+
#endif
2062+
20382063
EVPKeyPointer EVPKeyPointer::NewDH(DHPointer&& dh) {
20392064
#ifndef NCRYPTO_NO_EVP_DH
20402065
if (!dh) return {};
@@ -2092,7 +2117,16 @@ EVP_PKEY* EVPKeyPointer::release() {
20922117

20932118
int EVPKeyPointer::id(const EVP_PKEY* key) {
20942119
if (key == nullptr) return 0;
2095-
return EVP_PKEY_id(key);
2120+
int type = EVP_PKEY_id(key);
2121+
#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
2122+
// https://github.com/openssl/openssl/issues/27738#issuecomment-3013215870
2123+
if (type == -1) {
2124+
if (EVP_PKEY_is_a(key, "ML-DSA-44")) return EVP_PKEY_ML_DSA_44;
2125+
if (EVP_PKEY_is_a(key, "ML-DSA-65")) return EVP_PKEY_ML_DSA_65;
2126+
if (EVP_PKEY_is_a(key, "ML-DSA-87")) return EVP_PKEY_ML_DSA_87;
2127+
}
2128+
#endif
2129+
return type;
20962130
}
20972131

20982132
int EVPKeyPointer::base_id(const EVP_PKEY* key) {
@@ -2148,6 +2182,31 @@ DataPointer EVPKeyPointer::rawPublicKey() const {
21482182
return {};
21492183
}
21502184

2185+
#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
2186+
DataPointer EVPKeyPointer::rawSeed() const {
2187+
if (!pkey_) return {};
2188+
switch (id()) {
2189+
case EVP_PKEY_ML_DSA_44:
2190+
case EVP_PKEY_ML_DSA_65:
2191+
case EVP_PKEY_ML_DSA_87:
2192+
break;
2193+
default:
2194+
unreachable();
2195+
}
2196+
2197+
size_t seed_len = 32;
2198+
if (auto data = DataPointer::Alloc(seed_len)) {
2199+
const Buffer<unsigned char> buf = data;
2200+
size_t len = data.size();
2201+
if (EVP_PKEY_get_octet_string_param(
2202+
get(), OSSL_PKEY_PARAM_ML_DSA_SEED, buf.data, len, &seed_len) != 1)
2203+
return {};
2204+
return data;
2205+
}
2206+
return {};
2207+
}
2208+
#endif
2209+
21512210
DataPointer EVPKeyPointer::rawPrivateKey() const {
21522211
if (!pkey_) return {};
21532212
if (auto data = DataPointer::Alloc(rawPrivateKeySize())) {
@@ -2598,7 +2657,18 @@ bool EVPKeyPointer::isRsaVariant() const {
25982657
bool EVPKeyPointer::isOneShotVariant() const {
25992658
if (!pkey_) return false;
26002659
int type = id();
2601-
return type == EVP_PKEY_ED25519 || type == EVP_PKEY_ED448;
2660+
switch (type) {
2661+
case EVP_PKEY_ED25519:
2662+
case EVP_PKEY_ED448:
2663+
#if OPENSSL_VERSION_MAJOR >= 3 && OPENSSL_VERSION_MINOR >= 5
2664+
case EVP_PKEY_ML_DSA_44:
2665+
case EVP_PKEY_ML_DSA_65:
2666+
case EVP_PKEY_ML_DSA_87:
2667+
#endif
2668+
return true;
2669+
default:
2670+
return false;
2671+
}
26022672
}
26032673

26042674
bool EVPKeyPointer::isSigVariant() const {

0 commit comments

Comments
 (0)