diff --git a/tests/api/test_mldsa.c b/tests/api/test_mldsa.c index 132b797c9..873a085c9 100644 --- a/tests/api/test_mldsa.c +++ b/tests/api/test_mldsa.c @@ -16658,219 +16658,7 @@ int test_wc_dilithium_verify_kats(void) return EXPECT_RESULT(); } -#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) +int test_mldsa_pkcs8(void) { EXPECT_DECLS; #if !defined(NO_ASN) && defined(HAVE_PKCS8) && \ @@ -16888,8 +16676,10 @@ int test_mldsa_pkcs8_export_import_wolfSSL_form(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 { @@ -16956,6 +16746,43 @@ int test_mldsa_pkcs8_export_import_wolfSSL_form(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); diff --git a/tests/api/test_mldsa.h b/tests/api/test_mldsa.h index 488c3a2b3..d1322e571 100644 --- a/tests/api/test_mldsa.h +++ b/tests/api/test_mldsa.h @@ -35,26 +35,22 @@ 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_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_pkcs8(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_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), \ +#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), \ TEST_DECL_GROUP("mldsa", test_mldsa_pkcs12) #endif /* WOLFCRYPT_TEST_MLDSA_H */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 5daa44312..bea0cd351 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -36991,7 +36991,6 @@ 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 }, @@ -37002,13 +37001,9 @@ 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_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 }, +/* PKEY_MLDSASEQ */ { 2, ASN_SEQUENCE, 1, 0, 2 }, /* attributes */ /* ATTRS */ { 1, ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_ATTRS, 1, 1, 1 }, /* publicKey */ @@ -37021,10 +37016,7 @@ enum { PRIVKEYASN_IDX_PKEYALGO_OID, PRIVKEYASN_IDX_PKEY, PRIVKEYASN_IDX_PKEY_CURVEPKEY, - PRIVKEYASN_IDX_PKEY_SEED_ONLY, - PRIVKEYASN_IDX_PKEY_BOTH_SEQ, - PRIVKEYASN_IDX_PKEY_BOTH_SEED, - PRIVKEYASN_IDX_PKEY_BOTH_KEY, + PRIVKEYASN_IDX_PKEY_MLDSASEQ, PRIVKEYASN_IDX_ATTRS, PRIVKEYASN_IDX_PUBKEY }; @@ -37041,11 +37033,9 @@ 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; @@ -37058,27 +37048,14 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz, #endif if (input == NULL || inOutIdx == NULL || inSz == 0 || - privKey == NULL || privKeyLen == NULL || - pubKey == NULL || pubKeyLen == NULL || - inOutKeyType == NULL) { + privKey == NULL || privKeyLen == 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; @@ -37106,7 +37083,13 @@ int DecodeAsymKey_Assign(const byte* input, word32* inOutIdx, word32 inSz, return ASN_PARSE_E; if (GetOctetString(input, inOutIdx, &privSz, inSz) < 0) { - return ASN_PARSE_E; + 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; + } } priv = input + *inOutIdx; @@ -37167,70 +37150,54 @@ 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) { - /* 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, dataASN, privateKeyASN_Length, 1, input, + inOutIdx, inSz); + if (ret != 0) { + /* Parse just the OCTET_STRING. */ ret = GetASN_Items(&privateKeyASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY], - &dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY], - PRIVKEYASN_IDX_ATTRS - PRIVKEYASN_IDX_PKEY_CURVEPKEY, 0, - input, inOutIdx, inSz); + &dataASN[PRIVKEYASN_IDX_PKEY_CURVEPKEY], 1, 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; - } - /* 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 { + 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; } - } - - if (ret == 0) { - if (dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.length != 0) { - /* Import public value. */ - *pubKeyLen = dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.length; - *pubKey = dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.data; - } else { - /* Set public length to 0 as not seen. */ - *pubKeyLen = 0; - *pubKey = NULL; + /* Import private value. */ + *privKeyLen = dataASN[PRIVKEYASN_IDX_PKEY_MLDSASEQ].data.ref.length; + *privKey = dataASN[PRIVKEYASN_IDX_PKEY_MLDSASEQ].data.ref.data; } } + 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) + *pubKeyLen = dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.length; + if (pubKey != NULL && pubKeyLen != NULL) + *pubKey = dataASN[PRIVKEYASN_IDX_PUBKEY].data.ref.data; + } FREE_ASNGETDATA(dataASN, NULL); return ret; @@ -37252,8 +37219,8 @@ int DecodeAsymKey(const byte* input, word32* inOutIdx, word32 inSz, } if (ret == 0) { - ret = DecodeAsymKey_Assign(input, inOutIdx, inSz, NULL, NULL, - &privKeyPtr, &privKeyPtrLen, &pubKeyPtr, &pubKeyPtrLen, &keyType); + ret = DecodeAsymKey_Assign(input, inOutIdx, inSz, &privKeyPtr, + &privKeyPtrLen, &pubKeyPtr, &pubKeyPtrLen, &keyType); } if ((ret == 0) && (privKeyPtrLen > *privKeyLen)) { ret = BUFFER_E; @@ -37639,11 +37606,10 @@ 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); diff --git a/wolfcrypt/src/dilithium.c b/wolfcrypt/src/dilithium.c index ea0219c48..ac8e5d810 100644 --- a/wolfcrypt/src/dilithium.c +++ b/wolfcrypt/src/dilithium.c @@ -9659,6 +9659,31 @@ int dilithium_get_oid_sum(dilithium_key* key, int* keyFormat) { #if defined(WOLFSSL_DILITHIUM_PRIVATE_KEY) +/* OCT OCT */ +#define ALT_PRIV_DER_PREFIX (2 + 32 + 4) +/* SEQ [ OCT OCT ] */ +#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. @@ -9683,14 +9708,11 @@ 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)) { @@ -9734,45 +9756,34 @@ 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, &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) { + &pubKey, &pubKeyLen, &keyType); + if (ret == 0 +#ifdef WOLFSSL_WC_DILITHIUM + && key->params == NULL +#endif + ) { /* Set the security level based on the decoded key. */ - ret = mapOidToSecLevel(autoKeyType); + ret = mapOidToSecLevel(keyType); if (ret > 0) { ret = wc_dilithium_set_level(key, (byte)ret); } } - else if (keyType != ANONk && autoKeyType != ANONk) { - if (keyType == autoKeyType) + /* 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; 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) @@ -9817,39 +9828,32 @@ 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) { - /* 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; + /* Check whether public key data was found. */ +#if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY) + if (pubKeyLen == 0) #endif + { + /* No public key data, only import private key data. */ + ret = wc_dilithium_import_private(privKey, privKeyLen, key); } #if defined(WOLFSSL_DILITHIUM_PUBLIC_KEY) - /* Check whether public key data was found. */ - else if (pubKeyLen != 0 && privKeyLen != 0) { + else { /* 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; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 74a849fbc..2657bbc06 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -204,10 +204,7 @@ enum ASN_Tags { /* OneAsymmetricKey Fields */ ASN_ASYMKEY_ATTRS = 0x00, - ASN_ASYMKEY_PUBKEY = 0x01, - - /* PKEY Fields */ - ASN_PKEY_SEED = 0x00 + ASN_ASYMKEY_PUBKEY = 0x01 }; /* NOTE: If ASN_UTC_TIME_SIZE or ASN_GENERALIZED_TIME_SIZE are ever modified @@ -2730,9 +2727,8 @@ 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** seed, word32* seedLen, const byte** privKey, - word32* privKeyLen, const byte** pubKey, word32* pubKeyLen, - int* inOutKeyType); + word32 inSz, 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,