mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-07 15:00:48 +02:00
evp: support ML-DSA in wolfSSL_EVP_PKCS82PKEY() and wolfSSL_X509_check_private_key()
This commit is contained in:
+11
-6
@@ -1360,7 +1360,12 @@ int test_wc_DecodeObjectId(void)
|
||||
#if defined(HAVE_PKCS8) && !defined(NO_ASN) && \
|
||||
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
||||
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN)) && \
|
||||
(defined(HAVE_ED25519) || defined(HAVE_ED448) || defined(HAVE_DILITHIUM))
|
||||
(defined(HAVE_ED25519) || \
|
||||
(defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
|
||||
defined(WOLFSSL_KEY_GEN)) || \
|
||||
(defined(HAVE_DILITHIUM) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_ASN1)))
|
||||
/* Run ToTraditional_ex() on a copy of der and assert the algId, returned
|
||||
* length, and the inner OCTET STRING tag/length at the start of the
|
||||
* (in-place rewritten) buffer. */
|
||||
@@ -1676,8 +1681,8 @@ int test_ToTraditional_ex_negative(void)
|
||||
((size_t)derSz + 2 + ED25519_PUB_KEY_SIZE <= sizeof(copy))) {
|
||||
word32 trailerSz = 2 + ED25519_PUB_KEY_SIZE;
|
||||
XMEMCPY(copy, der, (size_t)derSz);
|
||||
ExpectTrue(copy[1] + trailerSz < 0x80);
|
||||
if (EXPECT_SUCCESS() && (copy[1] + trailerSz < 0x80)) {
|
||||
ExpectTrue(copy[1] < (byte)(0x80 - trailerSz));
|
||||
if (EXPECT_SUCCESS() && copy[1] < (byte)(0x80 - trailerSz)) {
|
||||
copy[1] = (byte)(copy[1] + trailerSz);
|
||||
copy[derSz] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
||||
copy[derSz + 1] = ED25519_PUB_KEY_SIZE;
|
||||
@@ -1742,7 +1747,7 @@ int test_ToTraditional_ex_mldsa_bad_params(void)
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(mldsaOid) + 2 + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = sizeof(mldsaOid);
|
||||
der[sz++] = (byte)sizeof(mldsaOid);
|
||||
XMEMCPY(der + sz, mldsaOid, sizeof(mldsaOid)); sz += sizeof(mldsaOid);
|
||||
/* Disallowed, NULL parameter after the ML-DSA OID. */
|
||||
der[sz++] = ASN_TAG_NULL;
|
||||
@@ -1769,11 +1774,11 @@ int test_ToTraditional_ex_mldsa_bad_params(void)
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(mldsaOid) + 2 + sizeof(extraOid) + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = sizeof(mldsaOid);
|
||||
der[sz++] = (byte)sizeof(mldsaOid);
|
||||
XMEMCPY(der + sz, mldsaOid, sizeof(mldsaOid)); sz += sizeof(mldsaOid);
|
||||
/* Disallowed, OBJECT_ID parameter after the ML-DSA OID. */
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = sizeof(extraOid);
|
||||
der[sz++] = (byte)sizeof(extraOid);
|
||||
XMEMCPY(der + sz, extraOid, sizeof(extraOid)); sz += sizeof(extraOid);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)(privKeySz + 2);
|
||||
|
||||
@@ -71,6 +71,114 @@ int test_wolfSSL_X509_check_private_key(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* EVP_PKCS82PKEY() must populate pkey.ptr/pkey_sz for ML-DSA so
|
||||
* X509_check_private_key() (wc_CheckPrivateKey) can redecode the DER, and
|
||||
* d2i_PKCS8_PKEY() must keep the full PKCS#8 wrapper for ML-DSA level recovery
|
||||
* from the AlgorithmIdentifier. */
|
||||
int test_wolfSSL_X509_check_private_key_mldsa(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
|
||||
!defined(NO_BIO) && !defined(NO_CHECK_PRIVATE_KEY) && \
|
||||
defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
||||
(defined(OPENSSL_ALL) || defined(WOLFSSL_WPAS_SMALL)) && \
|
||||
(!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65) || \
|
||||
!defined(WOLFSSL_NO_ML_DSA_87))
|
||||
static const struct {
|
||||
const char* keyPath;
|
||||
const char* certPath;
|
||||
const char* mismatchCertPath; /* NULL if no other level available */
|
||||
} cases[] = {
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_44)
|
||||
{ "./certs/mldsa/mldsa44-key.pem",
|
||||
"./certs/mldsa/mldsa44-cert.der",
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_65)
|
||||
"./certs/mldsa/mldsa65-cert.der"
|
||||
#elif !defined(WOLFSSL_NO_ML_DSA_87)
|
||||
"./certs/mldsa/mldsa87-cert.der"
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_65)
|
||||
{ "./certs/mldsa/mldsa65-key.pem",
|
||||
"./certs/mldsa/mldsa65-cert.der",
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_87)
|
||||
"./certs/mldsa/mldsa87-cert.der"
|
||||
#elif !defined(WOLFSSL_NO_ML_DSA_44)
|
||||
"./certs/mldsa/mldsa44-cert.der"
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_87)
|
||||
{ "./certs/mldsa/mldsa87-key.pem",
|
||||
"./certs/mldsa/mldsa87-cert.der",
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_44)
|
||||
"./certs/mldsa/mldsa44-cert.der"
|
||||
#elif !defined(WOLFSSL_NO_ML_DSA_65)
|
||||
"./certs/mldsa/mldsa65-cert.der"
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
||||
PKCS8_PRIV_KEY_INFO* pt = NULL;
|
||||
EVP_PKEY* pkey = NULL;
|
||||
X509* x509 = NULL;
|
||||
X509* mismatchX509 = NULL;
|
||||
BIO* bio = NULL;
|
||||
byte* buf = NULL;
|
||||
size_t sz = 0;
|
||||
|
||||
ExpectIntEQ(load_file(cases[i].keyPath, &buf, &sz), 0);
|
||||
|
||||
ExpectNotNull(bio = BIO_new_mem_buf((void*)buf, (int)sz));
|
||||
ExpectNotNull(pt = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL));
|
||||
|
||||
ExpectNotNull(pkey = EVP_PKCS82PKEY(pt));
|
||||
if (pkey != NULL) {
|
||||
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
|
||||
/* pkey.ptr must hold the DER so that X509_check_private_key() to
|
||||
* wc_CheckPrivateKey() can re-decode it. */
|
||||
ExpectNotNull(pkey->pkey.ptr);
|
||||
ExpectIntGT(pkey->pkey_sz, 0);
|
||||
}
|
||||
|
||||
ExpectNotNull(x509 = X509_load_certificate_file(
|
||||
cases[i].certPath, SSL_FILETYPE_ASN1));
|
||||
ExpectIntEQ(X509_check_private_key(x509, pkey), 1);
|
||||
|
||||
if (cases[i].mismatchCertPath != NULL) {
|
||||
ExpectNotNull(mismatchX509 = X509_load_certificate_file(
|
||||
cases[i].mismatchCertPath, SSL_FILETYPE_ASN1));
|
||||
ExpectIntEQ(X509_check_private_key(mismatchX509, pkey), 0);
|
||||
}
|
||||
|
||||
/* Negative check, corrupt the outer SEQ tag so the key DER fails */
|
||||
if (EXPECT_SUCCESS() && (pkey != NULL) && (pkey->pkey.ptr != NULL)) {
|
||||
pkey->pkey.ptr[0] ^= 0xFF;
|
||||
ExpectIntEQ(X509_check_private_key(x509, pkey), 0);
|
||||
}
|
||||
|
||||
X509_free(mismatchX509);
|
||||
X509_free(x509);
|
||||
EVP_PKEY_free(pkey);
|
||||
PKCS8_PRIV_KEY_INFO_free(pt);
|
||||
BIO_free(bio);
|
||||
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_wolfSSL_X509_verify(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <tests/api/api_decl.h>
|
||||
|
||||
int test_wolfSSL_X509_check_private_key(void);
|
||||
int test_wolfSSL_X509_check_private_key_mldsa(void);
|
||||
int test_wolfSSL_X509_verify(void);
|
||||
int test_wolfSSL_X509_sign(void);
|
||||
int test_wolfSSL_X509_sign2(void);
|
||||
@@ -32,6 +33,8 @@ int test_wolfSSL_make_cert(void);
|
||||
|
||||
#define TEST_OSSL_X509_CRYPTO_DECLS \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_check_private_key), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", \
|
||||
test_wolfSSL_X509_check_private_key_mldsa), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_verify), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_sign), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_sign2), \
|
||||
|
||||
+33
-3
@@ -942,7 +942,8 @@ static int d2iTryDilithiumKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_DILITHIUM);
|
||||
/* Copy the consumed DER into pkey->pkey.ptr when the input was DER */
|
||||
return d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DILITHIUM);
|
||||
}
|
||||
#endif /* HAVE_DILITHIUM */
|
||||
|
||||
@@ -1696,6 +1697,10 @@ WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY(
|
||||
DerBuffer rawDer;
|
||||
EncryptedInfo info;
|
||||
int advanceLen = 0;
|
||||
#ifdef HAVE_DILITHIUM
|
||||
word32 outerIdx = 0;
|
||||
int outerLen = 0;
|
||||
#endif
|
||||
|
||||
/* Clear the encryption information and DER buffer. */
|
||||
XMEMSET(&info, 0, sizeof(info));
|
||||
@@ -1737,15 +1742,40 @@ WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY(
|
||||
}
|
||||
if (algId == DHk) {
|
||||
/* Special case for DH as we expect the DER buffer to be always
|
||||
* be in PKCS8 format */
|
||||
* in PKCS8 format */
|
||||
rawDer.buffer = pkcs8Der->buffer;
|
||||
rawDer.length = inOutIdx + (word32)ret;
|
||||
}
|
||||
#ifdef HAVE_DILITHIUM
|
||||
else if (
|
||||
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
||||
(algId == DILITHIUM_LEVEL2k) ||
|
||||
(algId == DILITHIUM_LEVEL3k) ||
|
||||
(algId == DILITHIUM_LEVEL5k) ||
|
||||
#endif
|
||||
(algId == ML_DSA_LEVEL2k) ||
|
||||
(algId == ML_DSA_LEVEL3k) ||
|
||||
(algId == ML_DSA_LEVEL5k)) {
|
||||
|
||||
/* Keep full PKCS#8 wrapper for level recovery from
|
||||
* AlgorithmIdentifier parameters */
|
||||
rawDer.buffer = pkcs8Der->buffer;
|
||||
if (GetSequence(pkcs8Der->buffer, &outerIdx, &outerLen,
|
||||
pkcs8Der->length) < 0) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
else {
|
||||
rawDer.length = outerIdx + (word32)outerLen;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
rawDer.buffer = pkcs8Der->buffer + inOutIdx;
|
||||
rawDer.length = (word32)ret;
|
||||
}
|
||||
ret = 0; /* good DER */
|
||||
if (ret >= 0) {
|
||||
ret = 0; /* good DER */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user