Support importing seed of ML-DSA key

This commit is contained in:
Koji Takeda
2025-07-14 10:35:31 +09:00
parent cc2f7927ec
commit a82d1a6b12
5 changed files with 376 additions and 165 deletions

View File

@@ -16658,7 +16658,219 @@ int test_wc_dilithium_verify_kats(void)
return EXPECT_RESULT();
}
int test_mldsa_pkcs8(void)
#if !defined(NO_ASN) && defined(HAVE_PKCS8) && \
defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE)
static struct {
const char* fileName;
byte level;
/* 0: Unsupported, 1: Supported*/
int p8_lv; /* Support PKCS8 format with specifying level */
int p8_nolv; /* Support PKCS8 format without specifying level */
int trad_lv; /* Support traditional format with specifying level */
int trad_nolv; /* Support traditional format without specifying level */
} ossl_form[] = {
/*
* Generated test files with the following commands:
* openssl genpkey -outform DER -algorithm ${ALGO} \
* -provparam ml-dsa.output_formats=${OUT_FORM} -out ${OUT_FILE}
*/
/* ALGO=ML-DSA-44, OUT_FORM=seed-only, OUT_FILE=mldsa44_seed-only.der */
{"certs/mldsa/mldsa44_seed-only.der", WC_ML_DSA_44, 1, 1, 1, 0},
/* ALGO=ML-DSA-44, OUT_FORM=priv-only, OUT_FILE=mldsa44_priv-only.der */
{"certs/mldsa/mldsa44_priv-only.der", WC_ML_DSA_44, 1, 1, 1, 0},
/* ALGO=ML-DSA-44, OUT_FORM=seed-priv, OUT_FILE=mldsa44_seed-priv.der */
{"certs/mldsa/mldsa44_seed-priv.der", WC_ML_DSA_44, 1, 1, 1, 0},
/* ALGO=ML-DSA-44, OUT_FORM=oqskeypair, OUT_FILE=mldsa44_oqskeypair.der */
{"certs/mldsa/mldsa44_oqskeypair.der", WC_ML_DSA_44, 1, 1, 1, 0},
/* ALGO=ML-DSA-44, OUT_FORM=bare-seed, OUT_FILE=mldsa44_bare-seed.der */
{"certs/mldsa/mldsa44_bare-seed.der", WC_ML_DSA_44, 0, 0, 0, 0},
/* ALGO=ML-DSA-44, OUT_FORM=bare-priv, OUT_FILE=mldsa44_bare-priv.der */
{"certs/mldsa/mldsa44_bare-priv.der", WC_ML_DSA_44, 0, 0, 0, 0},
/* ALGO=ML-DSA-65, OUT_FORM=seed-only, OUT_FILE=mldsa65_seed-only.der */
{"certs/mldsa/mldsa65_seed-only.der", WC_ML_DSA_65, 1, 1, 1, 0},
/* ALGO=ML-DSA-65, OUT_FORM=priv-only, OUT_FILE=mldsa65_priv-only.der */
{"certs/mldsa/mldsa65_priv-only.der", WC_ML_DSA_65, 1, 1, 1, 0},
/* ALGO=ML-DSA-65, OUT_FORM=seed-priv, OUT_FILE=mldsa65_seed-priv.der */
{"certs/mldsa/mldsa65_seed-priv.der", WC_ML_DSA_65, 1, 1, 1, 0},
/* ALGO=ML-DSA-65, OUT_FORM=oqskeypair, OUT_FILE=mldsa65_oqskeypair.der */
{"certs/mldsa/mldsa65_oqskeypair.der", WC_ML_DSA_65, 1, 1, 1, 0},
/* ALGO=ML-DSA-65, OUT_FORM=bare-seed, OUT_FILE=mldsa65_bare-seed.der */
{"certs/mldsa/mldsa65_bare-seed.der", WC_ML_DSA_65, 0, 0, 0, 0},
/* ALGO=ML-DSA-65, OUT_FORM=bare-priv, OUT_FILE=mldsa65_bare-priv.der */
{"certs/mldsa/mldsa65_bare-priv.der", WC_ML_DSA_65, 0, 0, 0, 0},
/* ALGO=ML-DSA-87, OUT_FORM=seed-only, OUT_FILE=mldsa87_seed-only.der */
{"certs/mldsa/mldsa87_seed-only.der", WC_ML_DSA_87, 1, 1, 1, 0},
/* ALGO=ML-DSA-87, OUT_FORM=priv-only, OUT_FILE=mldsa87_priv-only.der */
{"certs/mldsa/mldsa87_priv-only.der", WC_ML_DSA_87, 1, 1, 1, 0},
/* ALGO=ML-DSA-87, OUT_FORM=seed-priv, OUT_FILE=mldsa87_seed-priv.der */
{"certs/mldsa/mldsa87_seed-priv.der", WC_ML_DSA_87, 1, 1, 1, 0},
/* ALGO=ML-DSA-87, OUT_FORM=oqskeypair, OUT_FILE=mldsa87_oqskeypair.der */
{"certs/mldsa/mldsa87_oqskeypair.der", WC_ML_DSA_87, 1, 1, 1, 0},
/* ALGO=ML-DSA-87, OUT_FORM=bare-seed, OUT_FILE=mldsa87_bare-seed.der */
{"certs/mldsa/mldsa87_bare-seed.der", WC_ML_DSA_87, 0, 0, 0, 0},
/* ALGO=ML-DSA-87, OUT_FORM=bare-priv, OUT_FILE=mldsa87_bare-priv.der */
{"certs/mldsa/mldsa87_bare-priv.der", WC_ML_DSA_87, 0, 0, 0, 0}
};
#endif
int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void)
{
EXPECT_DECLS;
#if !defined(NO_ASN) && defined(HAVE_PKCS8) && \
defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE)
byte* der = NULL;
size_t derMaxSz = ML_DSA_LEVEL5_BOTH_KEY_DER_SIZE;
size_t derSz = 0;
FILE* fp = NULL;
word32 inOutIdx = 0;
word32 inOutIdx2 = 0;
dilithium_key key;
int expect = 0;
int pkeySz = 0;
byte level = 0;
ExpectNotNull(der = (byte*) XMALLOC(derMaxSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
for (size_t i = 0; i < sizeof(ossl_form) / sizeof(ossl_form[0]); ++i) {
ExpectNotNull(fp = XFOPEN(ossl_form[i].fileName, "rb"));
ExpectIntGT(derSz = XFREAD(der, 1, derMaxSz, fp), 0);
ExpectIntEQ(XFCLOSE(fp), 0);
/* Specify a level with PKCS8 format */
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_dilithium_init(&key), 0);
ExpectIntEQ(wc_dilithium_set_level(&key, ossl_form[i].level), 0);
inOutIdx = 0;
expect = ossl_form[i].p8_lv ? 0 : ASN_PARSE_E;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &inOutIdx, &key,
(word32)derSz), expect);
if (expect == 0) {
ExpectIntEQ(wc_dilithium_get_level(&key, &level), 0);
ExpectIntEQ(level, ossl_form[i].level);
}
wc_dilithium_free(&key);
/* Not specify a level with PKCS8 format */
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_dilithium_init(&key), 0);
inOutIdx = 0;
expect = ossl_form[i].p8_nolv ? 0 : ASN_PARSE_E;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &inOutIdx, &key,
(word32)derSz), expect);
if (expect == 0) {
ExpectIntEQ(wc_dilithium_get_level(&key, &level), 0);
ExpectIntEQ(level, ossl_form[i].level);
}
wc_dilithium_free(&key);
/* Specify a level with traditional format */
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_dilithium_init(&key), 0);
ExpectIntEQ(wc_dilithium_set_level(&key, ossl_form[i].level), 0);
inOutIdx = 0;
expect = ossl_form[i].trad_lv ? 0 : ASN_PARSE_E;
ExpectIntGT(pkeySz = wc_GetPkcs8TraditionalOffset(der, &inOutIdx,
(word32)derSz), 0);
inOutIdx2 = 0;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der + inOutIdx, &inOutIdx2,
&key, (word32)pkeySz), expect);
if (expect == 0) {
ExpectIntEQ(wc_dilithium_get_level(&key, &level), 0);
ExpectIntEQ(level, ossl_form[i].level);
}
wc_dilithium_free(&key);
/* Not specify a level with traditional format */
XMEMSET(&key, 0, sizeof(key));
ExpectIntEQ(wc_dilithium_init(&key), 0);
inOutIdx = 0;
expect = ossl_form[i].trad_nolv ? 0 : ASN_PARSE_E;
ExpectIntGT(pkeySz = wc_GetPkcs8TraditionalOffset(der, &inOutIdx,
(word32)derSz), 0);
inOutIdx2 = 0;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der + inOutIdx, &inOutIdx2,
&key, (word32)pkeySz), expect);
if (expect == 0) {
ExpectIntEQ(wc_dilithium_get_level(&key, &level), 0);
ExpectIntEQ(level, ossl_form[i].level);
}
wc_dilithium_free(&key);
}
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
return EXPECT_RESULT();
}
int test_mldsa_pkcs8_import_OpenSSL_form(void)
{
EXPECT_DECLS;
#if !defined(NO_ASN) && defined(HAVE_PKCS8) && \
defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE) && \
!defined(NO_TLS) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER))
byte* der = NULL;
size_t derMaxSz = ML_DSA_LEVEL5_BOTH_KEY_DER_SIZE;
size_t derSz = 0;
WOLFSSL_CTX* ctx = NULL;
FILE* fp = NULL;
#ifdef WOLFSSL_DER_TO_PEM
byte* pem = NULL;
size_t pemMaxSz = ML_DSA_LEVEL5_BOTH_KEY_PEM_SIZE;
size_t pemSz = 0;
#endif /* WOLFSSL_DER_TO_PEM */
int expect = 0;
ExpectNotNull(der = (byte*) XMALLOC(derMaxSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
#ifdef WOLFSSL_DER_TO_PEM
ExpectNotNull(pem = (byte*) XMALLOC(pemMaxSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
#endif /* WOLFSSL_DER_TO_PEM */
#ifndef NO_WOLFSSL_SERVER
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
#else
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_client_method()));
#endif /* NO_WOLFSSL_SERVER */
for (size_t i = 0; i < sizeof(ossl_form) / sizeof(ossl_form[0]); ++i) {
ExpectNotNull(fp = XFOPEN(ossl_form[i].fileName, "rb"));
ExpectIntGT(derSz = XFREAD(der, 1, derMaxSz, fp), 0);
ExpectIntEQ(XFCLOSE(fp), 0);
/* DER */
expect = ossl_form[i].p8_nolv ? WOLFSSL_SUCCESS : WOLFSSL_BAD_FILE;
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz,
WOLFSSL_FILETYPE_ASN1), expect);
#ifdef WOLFSSL_DER_TO_PEM
/* PEM */
ExpectIntGT(pemSz = wc_DerToPem(der, (word32)derSz, pem,
(word32)pemMaxSz, PKCS8_PRIVATEKEY_TYPE), 0);
expect = ossl_form[i].p8_nolv ? WOLFSSL_SUCCESS : ASN_PARSE_E;
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, pem, pemSz,
WOLFSSL_FILETYPE_PEM), expect);
#endif /* WOLFSSL_DER_TO_PEM */
}
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_DER_TO_PEM
XFREE(pem, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif /* WOLFSSL_DER_TO_PEM */
#endif
return EXPECT_RESULT();
}
int test_mldsa_pkcs8_export_import_wolfSSL_form(void)
{
EXPECT_DECLS;
#if !defined(NO_ASN) && defined(HAVE_PKCS8) && \
@@ -16676,10 +16888,8 @@ int test_mldsa_pkcs8(void)
byte* temp = NULL; /* Store PEM or intermediate key */
word32 derSz = 0;
word32 pemSz = 0;
word32 keySz = 0;
dilithium_key mldsa_key;
WC_RNG rng;
word32 size;
int ret;
struct {
@@ -16746,43 +16956,6 @@ int test_mldsa_pkcs8(void)
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_DER_TO_PEM
ExpectIntGT(pemSz = wc_DerToPem(der, derSz, temp, tempMaxSz,
PKCS8_PRIVATEKEY_TYPE), 0);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, temp, pemSz,
WOLFSSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
#endif /* WOLFSSL_DER_TO_PEM */
}
/* Test private + public key (integrated format) */
for (i = 0; i < sizeof(test_variant) / sizeof(test_variant[0]); ++i) {
ExpectIntEQ(wc_dilithium_set_level(&mldsa_key, test_variant[i].wcId),
0);
ExpectIntEQ(wc_dilithium_make_key(&mldsa_key, &rng), 0);
if (EXPECT_FAIL())
break;
keySz = 0;
temp[0] = 0x04; /* ASN.1 OCTET STRING */
temp[1] = 0x82; /* 2 bytes length field */
temp[2] = (test_variant[i].keySz >> 8) & 0xff; /* MSB of the length */
temp[3] = test_variant[i].keySz & 0xff; /* LSB of the length */
keySz += 4;
size = tempMaxSz - keySz;
ExpectIntEQ(wc_dilithium_export_private(&mldsa_key, temp + keySz,
&size), 0);
keySz += size;
size = tempMaxSz - keySz;
ExpectIntEQ(wc_dilithium_export_public(&mldsa_key, temp + keySz, &size),
0);
keySz += size;
derSz = derMaxSz;
ExpectIntGT(wc_CreatePKCS8Key(der, &derSz, temp, keySz,
test_variant[i].oidSum, NULL, 0), 0);
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey_buffer(ctx, der, derSz,
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);
#ifdef WOLFSSL_DER_TO_PEM
ExpectIntGT(pemSz = wc_DerToPem(der, derSz, temp, tempMaxSz,
PKCS8_PRIVATEKEY_TYPE), 0);

View File

@@ -35,22 +35,26 @@ int test_wc_dilithium_der(void);
int test_wc_dilithium_make_key_from_seed(void);
int test_wc_dilithium_sig_kats(void);
int test_wc_dilithium_verify_kats(void);
int test_mldsa_pkcs8(void);
int test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form(void);
int test_mldsa_pkcs8_import_OpenSSL_form(void);
int test_mldsa_pkcs8_export_import_wolfSSL_form(void);
int test_mldsa_pkcs12(void);
#define TEST_MLDSA_DECLS \
TEST_DECL_GROUP("mldsa", test_wc_dilithium), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_make_key), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_sign), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_sign_vfy), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_check_key), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_public_der_decode), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_der), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_make_key_from_seed), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_sig_kats), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify_kats), \
TEST_DECL_GROUP("mldsa", test_mldsa_pkcs8), \
#define TEST_MLDSA_DECLS \
TEST_DECL_GROUP("mldsa", test_wc_dilithium), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_make_key), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_sign), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_sign_vfy), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_check_key), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_public_der_decode), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_der), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_make_key_from_seed), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_sig_kats), \
TEST_DECL_GROUP("mldsa", test_wc_dilithium_verify_kats), \
TEST_DECL_GROUP("mldsa", test_wc_Dilithium_PrivateKeyDecode_OpenSSL_form), \
TEST_DECL_GROUP("mldsa", test_mldsa_pkcs8_import_OpenSSL_form), \
TEST_DECL_GROUP("mldsa", test_mldsa_pkcs8_export_import_wolfSSL_form), \
TEST_DECL_GROUP("mldsa", test_mldsa_pkcs12)
#endif /* WOLFCRYPT_TEST_MLDSA_H */

View File

@@ -36991,6 +36991,7 @@ int wc_EccKeyToPKCS8(ecc_key* key, byte* output,
/* ASN.1 template for a general asymmetric private key: Ed25519, Ed448,
* falcon, dilithium, etc.
* RFC 8410, 7 - Private Key Format (but public value is EXPLICIT OCTET_STRING)
* Check draft-ietf-lamps-dilithium-certificates of draft RFC also.
*/
static const ASNItem privateKeyASN[] = {
/* SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
@@ -37001,9 +37002,13 @@ static const ASNItem privateKeyASN[] = {
/* PKEYALGO_OID */ { 2, ASN_OBJECT_ID, 0, 0, 1 },
/* privateKey */
/* PKEY */ { 1, ASN_OCTET_STRING, 0, 1, 0 },
/* CurvePrivateKey */
/* CurvePrivateKey */
/* PKEY_CURVEPKEY */ { 2, ASN_OCTET_STRING, 0, 0, 2 },
/* PKEY_MLDSASEQ */ { 2, ASN_SEQUENCE, 1, 0, 2 },
/* PKEY_SEED_ONLY */ { 2, ASN_CONTEXT_SPECIFIC | ASN_PKEY_SEED,
0, 0, 2 },
/* PKEY_BOTH_SEQ */ { 2, ASN_SEQUENCE, 1, 1, 2 },
/* PKEY_BOTH_SEED */ { 3, ASN_OCTET_STRING, 0, 0, 0 },
/* PKEY_BOTH_KEY */ { 3, ASN_OCTET_STRING, 0, 0, 0 },
/* attributes */
/* ATTRS */ { 1, ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_ATTRS, 1, 1, 1 },
/* publicKey */
@@ -37016,7 +37021,10 @@ enum {
PRIVKEYASN_IDX_PKEYALGO_OID,
PRIVKEYASN_IDX_PKEY,
PRIVKEYASN_IDX_PKEY_CURVEPKEY,
PRIVKEYASN_IDX_PKEY_MLDSASEQ,
PRIVKEYASN_IDX_PKEY_SEED_ONLY,
PRIVKEYASN_IDX_PKEY_BOTH_SEQ,
PRIVKEYASN_IDX_PKEY_BOTH_SEED,
PRIVKEYASN_IDX_PKEY_BOTH_KEY,
PRIVKEYASN_IDX_ATTRS,
PRIVKEYASN_IDX_PUBKEY
};
@@ -37033,9 +37041,11 @@ enum {
int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
const byte** seed, word32* seedLen,
const byte** privKey, word32* privKeyLen,
const byte** pubKey, word32* pubKeyLen, int* inOutKeyType)
{
int allowSeed = 0;
#ifndef WOLFSSL_ASN_TEMPLATE
word32 oid;
int version, length, endKeyIdx, privSz, pubSz;
@@ -37048,14 +37058,27 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
#endif
if (input == NULL || inOutIdx == NULL || inSz == 0 ||
privKey == NULL || privKeyLen == NULL || inOutKeyType == NULL) {
privKey == NULL || privKeyLen == NULL ||
pubKey == NULL || pubKeyLen == NULL ||
inOutKeyType == NULL) {
#ifdef WOLFSSL_ASN_TEMPLATE
FREE_ASNGETDATA(dataASN, NULL);
#endif
return BAD_FUNC_ARG;
}
if ((seed == NULL && seedLen != NULL) ||
(seed != NULL && seedLen == NULL)) {
return BAD_FUNC_ARG;
}
allowSeed = (seed != NULL && seedLen != NULL);
#ifndef WOLFSSL_ASN_TEMPLATE
/* The seed can't be parsed without WOLF_ASN_TEMPLATE */
if (allowSeed) {
return ASN_PARSE_E;
}
if (GetSequence(input, inOutIdx, &length, inSz) >= 0) {
endKeyIdx = (int)*inOutIdx + length;
@@ -37083,13 +37106,7 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
return ASN_PARSE_E;
if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) {
if (oid != ML_DSA_LEVEL2k && oid != ML_DSA_LEVEL3k &&
oid != ML_DSA_LEVEL5k) {
return ASN_PARSE_E;
}
if (GetSequence(input, inOutIdx, &privSz, inSz) < 0) {
return ASN_PARSE_E;
}
return ASN_PARSE_E;
}
priv = input + *inOutIdx;
@@ -37150,53 +37167,69 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz,
}
/* Parse full private key. */
ret = GetASN_Items(privateKeyASN, dataASN, privateKeyASN_Length, 1, input,
inOutIdx, inSz);
if (ret != 0) {
/* Parse just the OCTET_STRING. */
ret = GetASN_Items(privateKeyASN, dataASN, privateKeyASN_Length, 1,
input, inOutIdx, inSz);
if (ret == 0) {
/* Store detected OID if requested */
if (ret == 0 && *inOutKeyType == ANONk) {
*inOutKeyType =
(int)dataASN[PRIVKEYASN_IDX_PKEYALGO_OID].data.oid.sum;
}
}
/* Parse traditional format (a part of full private key). */
else if (ret != 0) {
ret = GetASN_Items(&privateKeyASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY],
&dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY], 1, 0, input,
inOutIdx, inSz);
&dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY],
PRIVKEYASN_IDX_ATTRS - PRIVKEYASN_IDX_PKEY_CURVEPKEY, 0,
input, inOutIdx, inSz);
if (ret != 0) {
ret = ASN_PARSE_E;
}
}
/* Store detected OID if requested */
if (ret == 0 && *inOutKeyType == ANONk) {
*inOutKeyType =
(int)dataASN[PRIVKEYASN_IDX_PKEYALGO_OID].data.oid.sum;
}
if (ret == 0) {
/* priv-only */
if (dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length != 0) {
if (allowSeed) {
*seedLen = 0;
*seed = NULL;
}
*privKeyLen
= dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length;
*privKey = dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY].data.ref.data;
}
}
if (ret == 0 && dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length != 0) {
/* Import private value. */
*privKeyLen = dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY].data.ref.length;
*privKey = dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY].data.ref.data;
}
else if (ret == 0 &&
dataASN[PRIVKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length != 0) {
if (*inOutKeyType != ML_DSA_LEVEL2k &&
*inOutKeyType != ML_DSA_LEVEL3k &&
*inOutKeyType != ML_DSA_LEVEL5k) {
ret = ASN_PARSE_E;
/* seed-only */
else if (allowSeed &&
dataASN[PRIVKEYASN_IDX_PKEY_SEED_ONLY].data.ref.length != 0) {
*seedLen = dataASN[PRIVKEYASN_IDX_PKEY_SEED_ONLY].data.ref.length;
*seed = dataASN[PRIVKEYASN_IDX_PKEY_SEED_ONLY].data.ref.data;
*privKeyLen = 0;
*privKey = NULL;
}
/* seed-priv */
else if (allowSeed &&
dataASN[PRIVKEYASN_IDX_PKEY_BOTH_SEQ].data.ref.length != 0) {
*seedLen = dataASN[PRIVKEYASN_IDX_PKEY_BOTH_SEED].data.ref.length;
*seed = dataASN[PRIVKEYASN_IDX_PKEY_BOTH_SEED].data.ref.data;
*privKeyLen = dataASN[PRIVKEYASN_IDX_PKEY_BOTH_KEY].data.ref.length;
*privKey = dataASN[PRIVKEYASN_IDX_PKEY_BOTH_KEY].data.ref.data;
}
else {
/* Import private value. */
*privKeyLen = dataASN[PRIVKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length;
*privKey = dataASN[PRIVKEYASN_IDX_PKEY_MLDSASEQ].data.ref.data;
ret = ASN_PARSE_E;
}
}
if ((ret == 0) && dataASN[PRIVKEYASN_IDX_PUBKEY].tag == 0) {
/* Set public length to 0 as not seen. */
if (pubKeyLen != NULL)
*pubKeyLen = 0;
}
else if (ret == 0) {
/* Import public value. */
if (pubKeyLen != NULL)
if (ret == 0) {
if (dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.length != 0) {
/* Import public value. */
*pubKeyLen = dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.length;
if (pubKey != NULL && pubKeyLen != NULL)
*pubKey = dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.data;
}
else {
/* Set public length to 0 as not seen. */
*pubKeyLen = 0;
*pubKey = NULL;
}
}
FREE_ASNGETDATA(dataASN, NULL);
@@ -37219,8 +37252,8 @@ int DecodeAsymKey(const byte* input, word32* inOutIdx, word32 inSz,
}
if (ret == 0) {
ret = DecodeAsymKey_Assign(input, inOutIdx, inSz, &privKeyPtr,
&privKeyPtrLen, &pubKeyPtr, &pubKeyPtrLen, &keyType);
ret = DecodeAsymKey_Assign(input, inOutIdx, inSz, NULL, NULL,
&privKeyPtr, &privKeyPtrLen, &pubKeyPtr, &pubKeyPtrLen, &keyType);
}
if ((ret == 0) && (privKeyPtrLen > *privKeyLen)) {
ret = BUFFER_E;
@@ -37606,10 +37639,11 @@ int SetAsymKeyDer(const byte* privKey, word32 privKeyLen,
oidKeyType);
/* Leave space for private key. */
SetASN_Buffer(&dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY], NULL, privKeyLen);
/* Don't write ML-DSA specific things. */
SetASNItem_NoOut(dataASN, PRIVKEYASN_IDX_PKEY_SEED_ONLY,
PRIVKEYASN_IDX_ATTRS);
/* Don't write out attributes. */
dataASN[PRIVKEYASN_IDX_ATTRS].noOut = 1;
/* Don't write sequence. */
dataASN[PRIVKEYASN_IDX_PKEY_MLDSASEQ].noOut = 1;
if (pubKey) {
/* Leave space for public key. */
SetASN_Buffer(&dataASN[PRIVKEYASN_IDX_PUBKEY], NULL, pubKeyLen);

View File

@@ -9659,31 +9659,6 @@ int dilithium_get_oid_sum(dilithium_key* key, int* keyFormat) {
#if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY)
/* OCT <seed of 32 bytes> OCT <private key data of more than 256 bytes> */
#define ALT_PRIV_DER_PREFIX (2 + 32 + 4)
/* SEQ [ OCT <seed of 32 bytes> OCT <private key data> ] */
#define ALT_PRIV_DER_PREFIX_SEQ (4 + 2 + 32 + 4)
/* Get the private only key size for the ML-DSA level/parameter id.
*
* @param [in] level Level of the ML-DSA key.
* @return Private key only encoding size for key level on success.
* @return 0 on failure.
*/
static word32 dilithium_get_priv_size(int level)
{
switch (level) {
case WC_ML_DSA_44:
return ML_DSA_LEVEL2_KEY_SIZE;
case WC_ML_DSA_65:
return ML_DSA_LEVEL3_KEY_SIZE;
case WC_ML_DSA_87:
return ML_DSA_LEVEL5_KEY_SIZE;
default:
return 0;
}
}
/* Decode the DER encoded Dilithium key.
*
* @param [in] input Array holding DER encoded data.
@@ -9708,11 +9683,14 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
dilithium_key* key, word32 inSz)
{
int ret = 0;
const byte* seed = NULL;
const byte* privKey = NULL;
const byte* pubKey = NULL;
word32 seedLen = 0;
word32 privKeyLen = 0;
word32 pubKeyLen = 0;
int keyType = 0;
int autoKeyType = ANONk;
/* Validate parameters. */
if ((input == NULL) || (inOutIdx == NULL) || (key == NULL) || (inSz == 0)) {
@@ -9756,34 +9734,45 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
if (ret == 0) {
/* Decode the asymmetric key and get out private and public key data. */
#ifndef WOLFSSL_ASN_TEMPLATE
ret = DecodeAsymKey_Assign(input, inOutIdx, inSz,
NULL, NULL,
&privKey, &privKeyLen,
&pubKey, &pubKeyLen, &keyType);
if (ret == 0
#ifdef WOLFSSL_WC_DILITHIUM
&& key->params == NULL
#endif
) {
&pubKey, &pubKeyLen, &autoKeyType);
#else
ret = DecodeAsymKey_Assign(input, inOutIdx, inSz,
&seed, &seedLen,
&privKey, &privKeyLen,
&pubKey, &pubKeyLen, &autoKeyType);
#endif /* WOLFSSL_ASN_TEMPLATE */
}
if (ret == 0) {
if (keyType == ANONk && autoKeyType != ANONk) {
/* Set the security level based on the decoded key. */
ret = mapOidToSecLevel(keyType);
ret = mapOidToSecLevel(autoKeyType);
if (ret > 0) {
ret = wc_dilithium_set_level(key, (byte)ret);
}
}
/* If it failed to decode try alternative DER encoding. */
else if (ret != 0) {
word32 levelSize = dilithium_get_priv_size(key->level);
privKey = input + *inOutIdx;
privKeyLen = inSz - *inOutIdx;
/* Check for an alternative DER encoding. */
if (privKeyLen == ALT_PRIV_DER_PREFIX_SEQ + levelSize) {
privKey += ALT_PRIV_DER_PREFIX_SEQ;
privKeyLen -= ALT_PRIV_DER_PREFIX_SEQ;
else if (keyType != ANONk && autoKeyType != ANONk) {
if (keyType == autoKeyType)
ret = 0;
}
else
ret = ASN_PARSE_E;
}
else if (keyType != ANONk && autoKeyType == ANONk) {
ret = 0;
}
else { /* keyType == ANONk && autoKeyType == ANONk */
/*
* When decoding traditional format with not specifying a level will
* cause this error.
*/
ret = ASN_PARSE_E;
}
}
if ((ret == 0) && (pubKey == NULL) && (pubKeyLen == 0)) {
/* Check if the public key is included in the private key. */
#if defined(WOLFSSL_DILITHIUM_FIPS204_DRAFT)
@@ -9828,32 +9817,39 @@ int wc_Dilithium_PrivateKeyDecode(const byte* input, word32* inOutIdx,
pubKeyLen = ML_DSA_LEVEL5_PUB_KEY_SIZE;
privKeyLen -= ML_DSA_LEVEL5_PUB_KEY_SIZE;
}
else {
word32 levelSize = dilithium_get_priv_size(key->level);
if (privKeyLen == ALT_PRIV_DER_PREFIX + levelSize) {
privKey += ALT_PRIV_DER_PREFIX;
privKeyLen -= ALT_PRIV_DER_PREFIX;
}
}
}
if (ret == 0) {
/* Check whether public key data was found. */
#if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
if (pubKeyLen == 0)
/* Generate a key pair if seed exists and decoded key pair is ignored */
if (seedLen != 0) {
#if defined(WOLFSSL_WC_DILITHIUM)
if (seedLen == DILITHIUM_SEED_SZ) {
ret = wc_dilithium_make_key_from_seed(key, seed);
}
else {
ret = ASN_PARSE_E;
}
#else
ret = NOT_COMPILED_IN;
#endif
{
/* No public key data, only import private key data. */
ret = wc_dilithium_import_private(privKey, privKeyLen, key);
}
#if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
else {
/* Check whether public key data was found. */
else if (pubKeyLen != 0 && privKeyLen != 0) {
/* Import private and public key data. */
ret = wc_dilithium_import_key(privKey, privKeyLen, pubKey,
pubKeyLen, key);
}
#endif
else if (pubKeyLen == 0 && privKeyLen != 0)
{
/* No public key data, only import private key data. */
ret = wc_dilithium_import_private(privKey, privKeyLen, key);
}
else {
/* Not a problem of ASN.1 structure, but the contents is invalid */
ret = ASN_PARSE_E;
}
}
(void)pubKey;

View File

@@ -204,7 +204,10 @@ enum ASN_Tags {
/* OneAsymmetricKey Fields */
ASN_ASYMKEY_ATTRS = 0x00,
ASN_ASYMKEY_PUBKEY = 0x01
ASN_ASYMKEY_PUBKEY = 0x01,
/* PKEY Fields */
ASN_PKEY_SEED = 0x00
};
/* NOTE: If ASN_UTC_TIME_SIZE or ASN_GENERALIZED_TIME_SIZE are ever modified
@@ -2727,8 +2730,9 @@ WOLFSSL_LOCAL int VerifyX509Acert(const byte* cert, word32 certSz,
|| (defined(HAVE_CURVE448) && defined(HAVE_CURVE448_KEY_IMPORT)) \
|| defined(HAVE_FALCON) || defined(HAVE_DILITHIUM) || defined(HAVE_SPHINCS))
WOLFSSL_LOCAL int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx,
word32 inSz, const byte** privKey, word32* privKeyLen, const byte** pubKey,
word32* pubKeyLen, int* inOutKeyType);
word32 inSz, const byte** seed, word32* seedLen, const byte** privKey,
word32* privKeyLen, const byte** pubKey, word32* pubKeyLen,
int* inOutKeyType);
WOLFSSL_LOCAL int DecodeAsymKey(const byte* input, word32* inOutIdx,
word32 inSz, byte* privKey, word32* privKeyLen, byte* pubKey,