Merge pull request #9000 from kojiws/import_mldsa_seed_pkcs8

Import ML-DSA's seed from PKCS8 file
This commit is contained in:
JacobBarthelmeh
2025-07-29 16:02:36 -06:00
committed by GitHub
26 changed files with 441 additions and 169 deletions

View File

@@ -152,4 +152,5 @@ include certs/dilithium/include.am
include certs/sphincs/include.am
include certs/rpk/include.am
include certs/acert/include.am
include certs/mldsa/include.am

23
certs/mldsa/include.am Normal file
View File

@@ -0,0 +1,23 @@
# vim:ft=automake
# All paths should be given relative to the root
#
EXTRA_DIST += \
certs/mldsa/mldsa44_seed-only.der \
certs/mldsa/mldsa44_priv-only.der \
certs/mldsa/mldsa44_seed-priv.der \
certs/mldsa/mldsa44_oqskeypair.der \
certs/mldsa/mldsa44_bare-seed.der \
certs/mldsa/mldsa44_bare-priv.der \
certs/mldsa/mldsa65_seed-only.der \
certs/mldsa/mldsa65_priv-only.der \
certs/mldsa/mldsa65_seed-priv.der \
certs/mldsa/mldsa65_oqskeypair.der \
certs/mldsa/mldsa65_bare-seed.der \
certs/mldsa/mldsa65_bare-priv.der \
certs/mldsa/mldsa87_seed-only.der \
certs/mldsa/mldsa87_priv-only.der \
certs/mldsa/mldsa87_seed-priv.der \
certs/mldsa/mldsa87_oqskeypair.der \
certs/mldsa/mldsa87_bare-seed.der \
certs/mldsa/mldsa87_bare-priv.der

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -3004,8 +3004,13 @@ int test_wc_dilithium_der(void)
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(NULL, NULL,
0 ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef WOLFSSL_ASN_TEMPLATE
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(key , NULL,
0 ), BAD_FUNC_ARG);
#else
ExpectIntGT(wc_Dilithium_PrivateKeyToDer(key , NULL,
0 ), 0);
#endif
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(NULL, der ,
0 ), WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(NULL, NULL,
@@ -3015,13 +3020,23 @@ int test_wc_dilithium_der(void)
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(key , der ,
0 ), WC_NO_ERR_TRACE(BUFFER_E));
/* Get length only. */
#ifndef WOLFSSL_ASN_TEMPLATE
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(key , NULL,
DILITHIUM_MAX_DER_SIZE), BAD_FUNC_ARG);
#else
ExpectIntEQ(wc_Dilithium_PrivateKeyToDer(key , NULL,
DILITHIUM_MAX_DER_SIZE), privDerLen);
#endif
ExpectIntEQ(wc_Dilithium_KeyToDer(NULL, NULL, 0 ),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
#ifndef WOLFSSL_ASN_TEMPLATE
ExpectIntEQ(wc_Dilithium_KeyToDer(key , NULL, 0 ),
BAD_FUNC_ARG);
#else
ExpectIntGT(wc_Dilithium_KeyToDer(key , NULL, 0 ),
0 );
#endif
ExpectIntEQ(wc_Dilithium_KeyToDer(NULL, der , 0 ),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
ExpectIntEQ(wc_Dilithium_KeyToDer(NULL, NULL, DILITHIUM_MAX_DER_SIZE),
@@ -3031,8 +3046,13 @@ int test_wc_dilithium_der(void)
ExpectIntEQ(wc_Dilithium_KeyToDer(key , der , 0 ),
WC_NO_ERR_TRACE(BUFFER_E));
/* Get length only. */
#ifndef WOLFSSL_ASN_TEMPLATE
ExpectIntEQ(wc_Dilithium_KeyToDer(key , NULL, DILITHIUM_MAX_DER_SIZE),
BAD_FUNC_ARG);
#else
ExpectIntEQ(wc_Dilithium_KeyToDer(key , NULL, DILITHIUM_MAX_DER_SIZE),
keyDerLen);
#endif
ExpectIntEQ(wc_Dilithium_PublicKeyDecode(NULL, NULL, NULL, 0 ),
WC_NO_ERR_TRACE(BAD_FUNC_ARG));
@@ -3081,15 +3101,25 @@ int test_wc_dilithium_der(void)
idx = 0;
ExpectIntEQ(wc_Dilithium_PublicKeyDecode(der, &idx, key, len), 0);
#ifndef WOLFSSL_ASN_TEMPLATE
ExpectIntEQ(len = wc_Dilithium_PrivateKeyToDer(key, der,
DILITHIUM_MAX_DER_SIZE), BAD_FUNC_ARG);
#else
ExpectIntEQ(len = wc_Dilithium_PrivateKeyToDer(key, der,
DILITHIUM_MAX_DER_SIZE), privDerLen);
idx = 0;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &idx, key, len), 0);
#endif
#ifndef WOLFSSL_ASN_TEMPLATE
ExpectIntEQ(len = wc_Dilithium_KeyToDer(key, der, DILITHIUM_MAX_DER_SIZE),
BAD_FUNC_ARG);
#else
ExpectIntEQ(len = wc_Dilithium_KeyToDer(key, der, DILITHIUM_MAX_DER_SIZE),
keyDerLen);
idx = 0;
ExpectIntEQ(wc_Dilithium_PrivateKeyDecode(der, &idx, key, len), 0);
#endif
wc_dilithium_free(key);
@@ -3097,6 +3127,8 @@ int test_wc_dilithium_der(void)
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
(void)keyDerLen;
#endif
return EXPECT_RESULT();
}
@@ -16658,7 +16690,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) && \
@@ -16666,7 +16910,7 @@ int test_mldsa_pkcs8(void)
(!defined(NO_WOLFSSL_CLIENT) || !defined(NO_WOLFSSL_SERVER)) && \
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
!defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
!defined(WOLFSSL_DILITHIUM_NO_ASN1)
!defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE)
WOLFSSL_CTX* ctx = NULL;
size_t i;
@@ -16676,10 +16920,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 +16988,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 WOLFSSL_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;
@@ -37550,6 +37583,11 @@ int SetAsymKeyDer(const byte* privKey, word32 privKeyLen,
}
#ifndef WOLFSSL_ASN_TEMPLATE
if (privKeyLen >= 128 || pubKeyLen >= 128) {
/* privKeyLen and pubKeyLen are assumed to be less than 128 */
return BAD_FUNC_ARG;
}
/* calculate size */
if (pubKey) {
pubSz = 2 + pubKeyLen;
@@ -37606,10 +37644,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

@@ -46932,7 +46932,7 @@ static wc_test_ret_t test_dilithium_decode_level(const byte* rawKey,
int isPublicOnlyKey)
{
int ret = 0;
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
#if !defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE)
/* Size the buffer to accommodate the largest encoded key size */
const word32 maxDerSz = DILITHIUM_MAX_PRV_KEY_DER_SIZE;
word32 derSz;
@@ -46982,7 +46982,7 @@ static wc_test_ret_t test_dilithium_decode_level(const byte* rawKey,
#endif
}
#ifndef WOLFSSL_DILITHIUM_NO_ASN1
#if !defined(WOLFSSL_DILITHIUM_NO_ASN1) && defined(WOLFSSL_ASN_TEMPLATE)
/* Export raw key as DER */
if (ret == 0) {
#ifdef WOLFSSL_DILITHIUM_PUBLIC_KEY
@@ -47056,7 +47056,7 @@ static wc_test_ret_t test_dilithium_decode_level(const byte* rawKey,
ret = WC_TEST_RET_ENC_NC;
}
#endif /* !WOLFSSL_DILITHIUM_FIPS204_DRAFT */
#endif /* WOLFSSL_DILITHIUM_NO_ASN1 */
#endif /* !WOLFSSL_DILITHIUM_NO_ASN1 && WOLFSSL_ASN_TEMPLATE */
/* Cleanup */
wc_dilithium_free(key);

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,