1
0
mirror of https://github.com/wolfSSL/wolfssl.git synced 2026-10-24 04:09:07 +03:00

Merge pull request #11598 from sebastian-carpenter/ml-dsa-x509

X509 support for ML-DSA and dual-alg certs
This commit is contained in:
Tobias Frauenschläger
2026-10-09 10:10:26 +02:00
committed by GitHub
10 changed files with 1112 additions and 166 deletions

View File

@@ -15637,6 +15637,23 @@ static int CopyDecodedPubKey(WOLFSSL_X509* x509, DecodedCert* dCert, int ret)
WC_EVP_PKEY_ED448, NULL, dCert->publicKey,
dCert->pubKeySize);
break;
#endif
#if defined(WOLFSSL_HAVE_MLDSA) && \
defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && \
defined(WC_ENABLE_ASYM_KEY_EXPORT)
#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
case DILITHIUM_LEVEL2k:
case DILITHIUM_LEVEL3k:
case DILITHIUM_LEVEL5k:
#endif
case ML_DSA_44k:
case ML_DSA_65k:
case ML_DSA_87k:
/* Raw key size does not distinguish draft from final, so
* encode with the certificate's key OID */
x509->key.pkey = wolfSSL_X509_get_pubkey(x509);
break;
#endif
default:
x509->key.pkey = wolfSSL_d2i_PUBKEY(NULL,

View File

@@ -4984,6 +4984,15 @@ const WOLFSSL_ObjectInfo wolfssl_object_info[] = {
"nameConstraints", "X509v3 Name Constraints"},
{ WC_NID_certificate_policies, CERT_POLICY_OID, oidCertExtType,
"certificatePolicies", "X509v3 Certificate Policies"},
#ifdef WOLFSSL_DUAL_ALG_CERTS
{ WC_NID_subject_alt_public_key_info, SUBJ_ALT_PUB_KEY_INFO_OID,
oidCertExtType, "subjectAltPublicKeyInfo",
"X509v3 Subject Alternative Public Key Info"},
{ WC_NID_alt_signature_algorithm, ALT_SIG_ALG_OID, oidCertExtType,
"altSignatureAlgorithm", "X509v3 Alternative Signature Algorithm"},
{ WC_NID_alt_signature_value, ALT_SIG_VAL_OID, oidCertExtType,
"altSignatureValue", "X509v3 Alternative Signature Value"},
#endif /* WOLFSSL_DUAL_ALG_CERTS */
#if defined(WOLFSSL_APACHE_HTTPD) && defined(OPENSSL_EXTRA)
/* "1.3.6.1.4.1.311.20.2.3" */
{ WC_NID_ms_upn, WOLFSSL_MS_UPN_SUM, oidCertExtType, WOLFSSL_SN_MS_UPN,

View File

@@ -6934,6 +6934,31 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509)
}
}
#endif /* HAVE_ED25519 */
/* re-encode ML-DSA key */
#if defined(WOLFSSL_HAVE_MLDSA) && \
defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && \
defined(WC_ENABLE_ASYM_KEY_EXPORT) && \
(defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL))
if (key->type == WC_EVP_PKEY_DILITHIUM) {
byte* spki = NULL;
word32 spkiSz = 0;
/* The buffer holds the raw key. Encode to SPKI so the i2d
* functions work fine */
if (wolfssl_i_mldsa_raw_pub_to_der((const byte*)key->pkey.ptr,
(word32)key->pkey_sz, x509->pubKeyOID, &spki, &spkiSz,
x509->heap) != 0) {
WOLFSSL_MSG("wolfssl_i_mldsa_raw_pub_to_der failed");
wolfSSL_EVP_PKEY_free(key);
return NULL;
}
XFREE(key->pkey.ptr, x509->heap, DYNAMIC_TYPE_PUBLIC_KEY);
key->pkey.ptr = (char*)spki;
key->pkey_sz = (int)spkiSz;
}
#endif /* WOLFSSL_HAVE_MLDSA */
}
}
return key;
@@ -7746,6 +7771,236 @@ static int X509PrintSubjAltName(WOLFSSL_BIO* bio, WOLFSSL_X509* x509,
return X509_print_name_entry(bio, x509->altNames, indent);
}
/* print out the signature value in human readable format for use with
* X509PrintSignature_ex() and X509PrintAltSigVal()
*
* return WOLFSSL_SUCCESS on success
*/
static int X509PrintSigHex(WOLFSSL_BIO* bio, byte* sig, int sigSz,
int indent)
{
int i;
int tmpLen = 0;
char tmp[100];
if ((tmpLen = XSNPRINTF(tmp, sizeof(tmp), "%*s", indent, ""))
>= (int)sizeof(tmp) || tmpLen < 0) {
return WOLFSSL_FAILURE;
}
for (i = 0; i < sigSz; i++) {
char val[6];
int valLen;
if (i == 0) {
if ((valLen = XSNPRINTF(val, sizeof(val), "%02x", sig[i]))
>= (int)sizeof(val)) {
return WOLFSSL_FAILURE;
}
}
else if (((i % 18) == 0)) {
if (wolfSSL_BIO_write(bio, tmp, tmpLen)
<= 0) {
return WOLFSSL_FAILURE;
}
if ((tmpLen = XSNPRINTF(tmp, sizeof(tmp), ":\n%*s",
indent, "")) >= (int)sizeof(tmp)) {
return WOLFSSL_FAILURE;
}
if ((valLen = XSNPRINTF(val, sizeof(val), "%02x", sig[i]))
>= (int)sizeof(val)) {
return WOLFSSL_FAILURE;
}
}
else {
if ((valLen = XSNPRINTF(val, sizeof(val), ":%02x", sig[i]))
>= (int)sizeof(val)) {
return WOLFSSL_FAILURE;
}
}
if ((tmpLen < 0) || (valLen < 0) ||
(valLen >= ((int)sizeof(tmp) - tmpLen - 1))) {
return WOLFSSL_FAILURE;
}
XMEMCPY(tmp + tmpLen, val, valLen);
tmpLen += valLen;
tmp[tmpLen] = 0;
}
/* print out remaining sig values */
if (tmpLen > 0 && wolfSSL_BIO_write(bio, tmp, tmpLen) <= 0) {
return WOLFSSL_FAILURE;
}
return WOLFSSL_SUCCESS;
}
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* print the OID of an unsupported algorithm
* return WOLFSSL_SUCCESS on success
*/
static int X509PrintAlgOid(WOLFSSL_BIO* bio, const byte* algId, int algIdSz,
int indent)
{
char scratch[MAX_WIDTH];
word32 idx = 0;
int len;
int oidSz;
byte tag;
/* AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, ... } */
if (GetSequence(algId, &idx, &oidSz, (word32)algIdSz) < 0) {
return WOLFSSL_FAILURE;
}
if ((GetASNTag(algId, &idx, &tag, (word32)algIdSz) != 0) ||
(tag != ASN_OBJECT_ID)) {
return WOLFSSL_FAILURE;
}
if (GetLength(algId, &idx, &oidSz, (word32)algIdSz) < 0) {
return WOLFSSL_FAILURE;
}
/* indent buffer so the OID can be decoded into scratch */
len = XSNPRINTF(scratch, MAX_WIDTH, "%*s", indent, "");
if (len < 0 || len >= MAX_WIDTH) {
return WOLFSSL_FAILURE;
}
oidSz = DecodePolicyOID(scratch + len, (word32)(MAX_WIDTH - len),
algId + idx, (word32)oidSz);
if (oidSz <= 0) {
return WOLFSSL_FAILURE;
}
len += oidSz;
if (len + 1 >= MAX_WIDTH) {
return WOLFSSL_FAILURE;
}
scratch[len++] = '\n';
if (wolfSSL_BIO_write(bio, scratch, len) <= 0) {
return WOLFSSL_FAILURE;
}
return WOLFSSL_SUCCESS;
}
/* print out the alternative public key in human readable format for use with
* wolfSSL_X509_print()
* return WOLFSSL_SUCCESS on success
*/
static int X509PrintAltPubKey(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
{
const unsigned char* der;
WOLFSSL_EVP_PKEY* pubKey;
char scratch[MAX_WIDTH];
int len;
int ret;
if (x509->sapkiDer == NULL || x509->sapkiLen <= 0) {
return WOLFSSL_FAILURE;
}
/* convert der to pkey for printing */
der = (const unsigned char*)x509->sapkiDer;
pubKey = wolfSSL_d2i_PUBKEY(NULL, &der, x509->sapkiLen);
if (pubKey != NULL) {
ret = wolfSSL_EVP_PKEY_print_public(bio, pubKey, indent, NULL);
wolfSSL_EVP_PKEY_free(pubKey);
if (ret == WOLFSSL_SUCCESS) {
return WOLFSSL_SUCCESS;
}
if (ret != WC_NO_ERR_TRACE(WOLFSSL_UNKNOWN)) {
return WOLFSSL_FAILURE;
}
}
/* if the alg is unhandled then still try to print the rest of the cert */
len = XSNPRINTF(scratch, MAX_WIDTH, "%*sprint not supported\n", indent, "");
if (len < 0 || len >= MAX_WIDTH) {
return WOLFSSL_FAILURE;
}
if (wolfSSL_BIO_write(bio, scratch, len) <= 0) {
return WOLFSSL_FAILURE;
}
return WOLFSSL_SUCCESS;
}
/* print out the alternative signature algorithm in human readable format for
* use with wolfSSL_X509_print()
* return WOLFSSL_SUCCESS on success
*/
static int X509PrintAltSigAlg(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
{
char scratch[MAX_WIDTH];
const char* nameStr;
word32 idx = 0;
word32 oid = 0;
int len;
int ret;
if (x509->altSigAlgDer == NULL || x509->altSigAlgLen <= 0) {
return WOLFSSL_FAILURE;
}
/* have an AlgorithmIdentifier, so look up the algo name */
ret = GetAlgoId(x509->altSigAlgDer, &idx, &oid, oidSigType,
(word32)x509->altSigAlgLen);
if (ret == WC_NO_ERR_TRACE(ASN_UNKNOWN_OID_E)) {
/* encoding is well formed, so print the OID */
return X509PrintAlgOid(bio, x509->altSigAlgDer, x509->altSigAlgLen,
indent);
}
if (ret < 0) {
return WOLFSSL_FAILURE;
}
nameStr = wolfSSL_OBJ_nid2ln(oid2nid(oid, oidSigType));
if (nameStr == NULL) {
/* no name, so print the OID instead */
return X509PrintAlgOid(bio, x509->altSigAlgDer, x509->altSigAlgLen,
indent);
}
len = XSNPRINTF(scratch, MAX_WIDTH, "%*s%s\n", indent, "", nameStr);
if (len < 0 || len >= MAX_WIDTH) {
return WOLFSSL_FAILURE;
}
if (wolfSSL_BIO_write(bio, scratch, len) <= 0) {
return WOLFSSL_FAILURE;
}
return WOLFSSL_SUCCESS;
}
/* print out the alternative signature value in human readable format for use
* with wolfSSL_X509_print()
* return WOLFSSL_SUCCESS on success
*/
static int X509PrintAltSigVal(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
{
if (x509->altSigValDer == NULL || x509->altSigValLen <= 0) {
return WOLFSSL_FAILURE;
}
/* DecodeAltSigVal() already stepped over the BIT STRING header */
if (X509PrintSigHex(bio, x509->altSigValDer, x509->altSigValLen, indent)
!= WOLFSSL_SUCCESS) {
return WOLFSSL_FAILURE;
}
/* X509PrintSigHex omits the trailing newline */
if (wolfSSL_BIO_write(bio, "\n", 1) <= 0) {
return WOLFSSL_FAILURE;
}
return WOLFSSL_SUCCESS;
}
#endif /* WOLFSSL_DUAL_ALG_CERTS */
/* iterate through certificate extensions printing them out in human readable
* form
* return WOLFSSL_SUCCESS on success
@@ -7967,6 +8222,20 @@ static int X509PrintExtensions(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
ret = X509PrintExtendedKeyUsage(bio, x509, indent + 8);
break;
#ifdef WOLFSSL_DUAL_ALG_CERTS
case WC_NID_subject_alt_public_key_info:
ret = X509PrintAltPubKey(bio, x509, indent + 8);
break;
case WC_NID_alt_signature_algorithm:
ret = X509PrintAltSigAlg(bio, x509, indent + 8);
break;
case WC_NID_alt_signature_value:
ret = X509PrintAltSigVal(bio, x509, indent + 8);
break;
#endif
default:
/* extension nid not yet supported */
if ((scratchLen = XSNPRINTF(
@@ -7991,7 +8260,6 @@ static int X509PrintExtensions(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
return ret;
}
/* print out the signature in human readable format for use with
* wolfSSL_X509_print()
* return WOLFSSL_SUCCESS on success
@@ -8055,76 +8323,7 @@ static int X509PrintSignature_ex(WOLFSSL_BIO* bio, byte* sig,
}
if (ret == WOLFSSL_SUCCESS) {
if ((tmpLen = XSNPRINTF(tmp, sizeof(tmp), "%*s", indent + 5, ""))
>= (int)sizeof(tmp))
{
ret = WOLFSSL_FAILURE;
}
}
if (ret == WOLFSSL_SUCCESS) {
int i;
for (i = 0; i < sigSz; i++) {
char val[6];
int valLen;
if (i == 0) {
if ((valLen = XSNPRINTF(val, sizeof(val), "%02x", sig[i]))
>= (int)sizeof(val))
{
ret = WOLFSSL_FAILURE;
break;
}
}
else if (((i % 18) == 0)) {
if (wolfSSL_BIO_write(bio, tmp, tmpLen)
<= 0) {
ret = WOLFSSL_FAILURE;
break;
}
if ((tmpLen = XSNPRINTF(tmp, sizeof(tmp), ":\n%*s",
indent + 5, ""))
>= (int)sizeof(tmp))
{
ret = WOLFSSL_FAILURE;
break;
}
if ((valLen = XSNPRINTF(val, sizeof(val), "%02x", sig[i]))
>= (int)sizeof(val))
{
ret = WOLFSSL_FAILURE;
break;
}
}
else {
if ((valLen = XSNPRINTF(val, sizeof(val), ":%02x", sig[i]))
>= (int)sizeof(val))
{
ret = WOLFSSL_FAILURE;
break;
}
}
if ((tmpLen < 0) || (valLen < 0) ||
(valLen >= ((int)sizeof(tmp) - tmpLen - 1))) {
ret = WOLFSSL_FAILURE;
break;
}
XMEMCPY(tmp + tmpLen, val, valLen);
tmpLen += valLen;
tmp[tmpLen] = 0;
}
}
/* print out remaining sig values */
if (ret == WOLFSSL_SUCCESS) {
if (tmpLen > 0) {
if (wolfSSL_BIO_write(bio, tmp, tmpLen)
<= 0)
{
ret = WOLFSSL_FAILURE;
}
}
ret = X509PrintSigHex(bio, sig, sigSz, indent + 5);
}
if (obj != NULL)
@@ -8181,6 +8380,7 @@ static int X509PrintSignature(WOLFSSL_BIO* bio, WOLFSSL_X509* x509,
static int X509PrintPubKey(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
{
char scratch[MAX_WIDTH];
const char* nameStr;
WOLFSSL_EVP_PKEY* pubKey;
int len;
int ret = WOLFSSL_SUCCESS;
@@ -8193,36 +8393,22 @@ static int X509PrintPubKey(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
len = XSNPRINTF(scratch, MAX_WIDTH, "%*sSubject Public Key Info:\n", indent,
"");
if (len >= MAX_WIDTH)
if (len < 0 || len >= MAX_WIDTH)
return WOLFSSL_FAILURE;
if (wolfSSL_BIO_write(bio, scratch, len) <= 0)
return WOLFSSL_FAILURE;
switch (x509->pubKeyOID) {
#ifndef NO_RSA
case RSAk:
len = XSNPRINTF(scratch, MAX_WIDTH,
"%*sPublic Key Algorithm: rsaEncryption\n", indent + 4, "");
if (len >= MAX_WIDTH)
return WOLFSSL_FAILURE;
if (wolfSSL_BIO_write(bio, scratch, len) <= 0)
return WOLFSSL_FAILURE;
break;
#endif
#ifdef HAVE_ECC
case ECDSAk:
len = XSNPRINTF(scratch, MAX_WIDTH,
"%*sPublic Key Algorithm: EC\n", indent + 4, "");
if ((len < 0) || (len >= MAX_WIDTH))
return WOLFSSL_FAILURE;
if (wolfSSL_BIO_write(bio, scratch, len) <= 0)
return WOLFSSL_FAILURE;
break;
#endif
default:
WOLFSSL_MSG("Unknown key type");
return WOLFSSL_FAILURE;
}
/* get the alg string associated with the OID */
nameStr = wolfSSL_OBJ_nid2ln(oid2nid((word32)x509->pubKeyOID, oidKeyType));
if (nameStr == NULL)
return WOLFSSL_FAILURE;
len = XSNPRINTF(scratch, MAX_WIDTH, "%*sPublic Key Algorithm: %s\n",
indent + 4, "", nameStr);
if (len < 0 || len >= MAX_WIDTH)
return WOLFSSL_FAILURE;
if (wolfSSL_BIO_write(bio, scratch, len) <= 0)
return WOLFSSL_FAILURE;
pubKey = wolfSSL_X509_get_pubkey(x509);
if (pubKey == NULL)
@@ -8232,7 +8418,20 @@ static int X509PrintPubKey(WOLFSSL_BIO* bio, WOLFSSL_X509* x509, int indent)
wolfSSL_EVP_PKEY_free(pubKey);
return ret;
if (ret == WOLFSSL_SUCCESS)
return WOLFSSL_SUCCESS;
if (ret != WC_NO_ERR_TRACE(WOLFSSL_UNKNOWN))
return WOLFSSL_FAILURE;
/* if the alg is unhandled then still try to print the rest of the cert */
len = XSNPRINTF(scratch, MAX_WIDTH, "%*sprint not supported\n", indent + 8,
"");
if (len < 0 || len >= MAX_WIDTH)
return WOLFSSL_FAILURE;
if (wolfSSL_BIO_write(bio, scratch, len) <= 0)
return WOLFSSL_FAILURE;
return WOLFSSL_SUCCESS;
}
@@ -12004,12 +12203,57 @@ WOLFSSL_X509_PUBKEY* wolfSSL_X509_get_X509_PUBKEY(const WOLFSSL_X509* x509)
return (WOLFSSL_X509_PUBKEY*)&x509->key;
}
/* Step over SubjectPublicKeyInfo to its subjectPublicKey BIT STRING.
*
* @param [in, out] der On in, the SPKI. On out, the BIT STRING contents.
* @param [in, out] derSz On in, size of the encoding. On out, size of the
* BIT STRING contents.
* @return 0 on success.
* @return WOLFSSL_FATAL_ERROR when the encoding does not parse.
*/
static int x509_pubkey_bit_string(const unsigned char** der, int* derSz)
{
word32 idx = 0;
int len = 0;
if ((*der == NULL) || (*derSz <= 0)) {
return WOLFSSL_FATAL_ERROR;
}
if (GetSequence(*der, &idx, &len, (word32)*derSz) < 0) {
return WOLFSSL_FATAL_ERROR;
}
/* spki length must span the whole encoding */
if (idx + (word32)len != (word32)*derSz) {
return WOLFSSL_FATAL_ERROR;
}
/* step over AlgorithmIdentifier */
if (GetSequence(*der, &idx, &len, (word32)*derSz) < 0) {
return WOLFSSL_FATAL_ERROR;
}
idx += (word32)len;
/* subjectPublicKey is the last field */
if (CheckBitString(*der, &idx, &len, (word32)*derSz, 1, NULL) < 0) {
return WOLFSSL_FATAL_ERROR;
}
if (idx + (word32)len != (word32)*derSz) {
return WOLFSSL_FATAL_ERROR;
}
*der += idx;
*derSz = len;
return 0;
}
/* Sets ppkalg pointer to X509_PUBKEY algorithm. Returns WOLFSSL_SUCCESS on
success or WOLFSSL_FAILURE on error. */
int wolfSSL_X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg,
const unsigned char **pk, int *ppklen, WOLFSSL_X509_ALGOR **pa,
WOLFSSL_X509_PUBKEY *pub)
{
const unsigned char* bitStr;
int bitStrSz;
WOLFSSL_ENTER("wolfSSL_X509_PUBKEY_get0_param");
if (!pub || !pub->pubKeyOID) {
@@ -12032,10 +12276,22 @@ int wolfSSL_X509_PUBKEY_get0_param(WOLFSSL_ASN1_OBJECT **ppkalg,
*pa = pub->algor;
if (ppkalg)
*ppkalg = pub->algor->algorithm;
if (pk)
*pk = (unsigned char*)pub->pkey->pkey.ptr;
if (ppklen)
*ppklen = pub->pkey->pkey_sz;
if ((pk != NULL) || (ppklen != NULL)) {
bitStr = (const unsigned char*)pub->pkey->pkey.ptr;
bitStrSz = pub->pkey->pkey_sz;
/* try to parse BIT STRING from SPKI, otherwise return the
* pointer as is */
if (x509_pubkey_bit_string(&bitStr, &bitStrSz) != 0) {
WOLFSSL_MSG("No SubjectPublicKeyInfo wrapper found");
}
if (pk)
*pk = bitStr;
if (ppklen)
*ppklen = bitStrSz;
}
return WOLFSSL_SUCCESS;
}
@@ -12180,7 +12436,7 @@ int wolfSSL_i2d_X509_PUBKEY(WOLFSSL_X509_PUBKEY* x509_PubKey,
{
if (x509_PubKey == NULL)
return WOLFSSL_FATAL_ERROR;
return wolfSSL_i2d_PublicKey(x509_PubKey->pkey, der);
return wolfSSL_i2d_PUBKEY(x509_PubKey->pkey, der);
}
#endif /* OPENSSL_EXTRA && !NO_CERTS && !NO_ASN */
@@ -13659,7 +13915,7 @@ cleanup:
/* DER buffer size for certificate/CSR signing: chosen from the signing
* key type, plus the subject public key held in the x509 so that a
* large (e.g. ML-DSA) SPKI fits under a classic signing key too. */
* large (e.g. ML-DSA) public key fits under a classic signing key too. */
static int x509_gen_buf_sz(const WOLFSSL_X509* x509,
const WOLFSSL_EVP_PKEY* pkey)
{
@@ -17197,7 +17453,6 @@ int wolfSSL_X509_set_serialNumber(WOLFSSL_X509* x509, WOLFSSL_ASN1_INTEGER* s)
return WOLFSSL_SUCCESS;
}
int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
{
byte* p = NULL;
@@ -17290,6 +17545,7 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
/* Decode key DER (private or public) and export public part. */
wc_MlDsaKey* mldsa;
word32 idx = 0;
word32 rawLen = 0;
int oidSum = 0;
int decodeOk = 0;
@@ -17337,8 +17593,7 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
}
/* Map the parameter set to its OID with mldsa_get_oid_sum():
* unlike wc_MlDsaKey_GetParams() it distinguishes FIPS204-draft
* levels, keeping pubKeyOID consistent with the SPKI encoded
* by wc_MlDsaKey_PublicKeyToDer(). */
* levels, keeping pubKeyOID consistent with the exported key. */
if (mldsa_get_oid_sum(mldsa, &oidSum) != 0) {
WOLFSSL_MSG("Error getting ML-DSA OID");
wc_MlDsaKey_Free(mldsa);
@@ -17346,7 +17601,13 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
return WOLFSSL_FAILURE;
}
derSz = MLDSA_MAX_PUB_KEY_DER_SIZE;
/* Store the RAW public key */
if (wc_MlDsaKey_GetPubLen(mldsa, &derSz) != 0) {
WOLFSSL_MSG("Error getting ML-DSA public key length");
wc_MlDsaKey_Free(mldsa);
XFREE(mldsa, cert->heap, DYNAMIC_TYPE_MLDSA);
return WOLFSSL_FAILURE;
}
p = (byte*)XMALLOC(derSz, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
if (p == NULL) {
WOLFSSL_MSG("malloc error");
@@ -17354,14 +17615,17 @@ int wolfSSL_X509_set_pubkey(WOLFSSL_X509 *cert, WOLFSSL_EVP_PKEY *pkey)
XFREE(mldsa, cert->heap, DYNAMIC_TYPE_MLDSA);
return WOLFSSL_FAILURE;
}
derSz = wc_MlDsaKey_PublicKeyToDer(mldsa, p, (word32)derSz, 1);
wc_MlDsaKey_Free(mldsa);
XFREE(mldsa, cert->heap, DYNAMIC_TYPE_MLDSA);
if (derSz <= 0) {
WOLFSSL_MSG("Error making ML-DSA public key DER");
rawLen = (word32)derSz;
if (wc_MlDsaKey_ExportPubRaw(mldsa, p, &rawLen) != 0) {
WOLFSSL_MSG("Error exporting ML-DSA public key");
wc_MlDsaKey_Free(mldsa);
XFREE(mldsa, cert->heap, DYNAMIC_TYPE_MLDSA);
XFREE(p, cert->heap, DYNAMIC_TYPE_PUBLIC_KEY);
return WOLFSSL_FAILURE;
}
wc_MlDsaKey_Free(mldsa);
XFREE(mldsa, cert->heap, DYNAMIC_TYPE_MLDSA);
derSz = (int)rawLen;
cert->pubKeyOID = oidSum;
}
break;

View File

@@ -1114,7 +1114,7 @@ static int do_dual_alg_root_certgen(byte **out, char *caKeyFile,
strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
CTC_DATE_SIZE);
newCert.beforeDateSz = 17;
strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
strncpy((char*)newCert.afterDate, "\x18\x0f""20491231115959Z",
CTC_DATE_SIZE);
newCert.afterDateSz = 17;
newCert.sigType = CTC_SHA256wRSA;
@@ -1157,6 +1157,140 @@ static int do_dual_alg_root_certgen(byte **out, char *caKeyFile,
return outSz;
}
#if defined(OPENSSL_EXTRA) && defined(XSNPRINTF) && defined(HAVE_ECC) && \
defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \
defined(WOLFSSL_MLDSA_PRIVATE_KEY) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \
!defined(WOLFSSL_NO_ML_DSA_44) && defined(WC_ENABLE_ASYM_KEY_IMPORT) && \
!defined(NO_BIO)
/* do_dual_alg_root_certgen() with ECC as the base algorithm and ML-DSA as the
* alternative one. */
static int do_dual_alg_root_certgen_mldsa(byte **out, char *caKeyFile,
char *sapkiFile, char *altPrivFile)
{
EXPECT_DECLS;
FILE* file = NULL;
Cert newCert;
DecodedCert preTBS;
/* holds the CA key, then the alternative key, then the scratch cert */
byte caKeyBuf[LARGE_TEMP_SZ];
word32 caKeySz = LARGE_TEMP_SZ;
byte sapkiBuf[ML_DSA_LEVEL2_PUB_KEY_DER_SIZE];
word32 sapkiSz = ML_DSA_LEVEL2_PUB_KEY_DER_SIZE;
word32 altPrivSz = LARGE_TEMP_SZ;
byte altSigAlgBuf[MAX_ALGO_SZ];
word32 altSigAlgSz = MAX_ALGO_SZ;
word32 scratchSz = LARGE_TEMP_SZ;
byte preTbsBuf[LARGE_TEMP_SZ];
word32 preTbsSz = LARGE_TEMP_SZ;
/* the signature wrapped in a BIT STRING */
byte altSigValBuf[ML_DSA_LEVEL2_SIG_SIZE + ASN_TAG_SZ + MAX_LENGTH_SZ + 1];
word32 altSigValSz = (word32)sizeof(altSigValBuf);
byte *outBuf = NULL;
/* the ML-DSA public key and signature do not fit in LARGE_TEMP_SZ */
word32 outSz = 2 * LARGE_TEMP_SZ;
WC_RNG rng;
ecc_key caKey;
wc_MlDsaKey altCaKey;
word32 idx = 0;
XMEMSET(&rng, 0, sizeof(WC_RNG));
XMEMSET(&caKey, 0, sizeof(ecc_key));
XMEMSET(&altCaKey, 0, sizeof(wc_MlDsaKey));
ExpectNotNull(outBuf = (byte*)XMALLOC(outSz, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectIntEQ(wc_InitRng(&rng), 0);
XMEMSET(caKeyBuf, 0, caKeySz);
ExpectNotNull(file = fopen(caKeyFile, "rb"));
ExpectIntGT(caKeySz = (word32)fread(caKeyBuf, 1, caKeySz, file), 0);
if (file) {
fclose(file);
file = NULL;
}
ExpectIntEQ(wc_ecc_init(&caKey), 0);
idx = 0;
ExpectIntEQ(wc_EccPrivateKeyDecode(caKeyBuf, &idx, &caKey, caKeySz), 0);
XMEMSET(sapkiBuf, 0, sapkiSz);
ExpectNotNull(file = fopen(sapkiFile, "rb"));
ExpectIntGT(sapkiSz = (word32)fread(sapkiBuf, 1, sapkiSz, file), 0);
if (file) {
fclose(file);
file = NULL;
}
XMEMSET(caKeyBuf, 0, altPrivSz);
ExpectNotNull(file = fopen(altPrivFile, "rb"));
ExpectIntGT(altPrivSz = (word32)fread(caKeyBuf, 1, altPrivSz, file), 0);
if (file) {
fclose(file);
file = NULL;
}
ExpectIntEQ(wc_MlDsaKey_Init(&altCaKey, NULL, INVALID_DEVID), 0);
ExpectIntEQ(wc_MlDsaKey_SetParams(&altCaKey, WC_ML_DSA_44), 0);
idx = 0;
ExpectIntEQ(wc_MlDsaKey_PrivateKeyDecode(&altCaKey, caKeyBuf, altPrivSz,
&idx), 0);
XMEMSET(altSigAlgBuf, 0, altSigAlgSz);
ExpectIntGT(altSigAlgSz = SetAlgoID(CTC_ML_DSA_44, altSigAlgBuf,
oidSigType, 0), 0);
wc_InitCert(&newCert);
strncpy(newCert.subject.country, "US", CTC_NAME_SIZE);
strncpy(newCert.subject.state, "MT", CTC_NAME_SIZE);
strncpy(newCert.subject.locality, "Bozeman", CTC_NAME_SIZE);
strncpy(newCert.subject.org, "wolfSSL", CTC_NAME_SIZE);
strncpy(newCert.subject.unit, "Engineering", CTC_NAME_SIZE);
strncpy(newCert.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
strncpy(newCert.subject.email, "root@wolfssl.com", CTC_NAME_SIZE);
strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
CTC_DATE_SIZE);
newCert.beforeDateSz = 17;
strncpy((char*)newCert.afterDate, "\x18\x0f""20491231115959Z",
CTC_DATE_SIZE);
newCert.afterDateSz = 17;
newCert.sigType = CTC_SHA256wECDSA;
newCert.isCA = 1;
ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.72", sapkiBuf,
sapkiSz), 0);
ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.73", altSigAlgBuf,
altSigAlgSz), 0);
XMEMSET(caKeyBuf, 0, scratchSz);
ExpectIntGT(wc_MakeCert_ex(&newCert, caKeyBuf, scratchSz, ECC_TYPE,
&caKey, &rng), 0);
ExpectIntGT(scratchSz = wc_SignCert_ex(newCert.bodySz, newCert.sigType,
caKeyBuf, scratchSz, ECC_TYPE, &caKey, &rng), 0);
wc_InitDecodedCert(&preTBS, caKeyBuf, scratchSz, 0);
ExpectIntEQ(wc_ParseCert(&preTBS, CERT_TYPE, NO_VERIFY, NULL), 0);
XMEMSET(preTbsBuf, 0, preTbsSz);
ExpectIntGT(preTbsSz = wc_GeneratePreTBS(&preTBS, preTbsBuf, preTbsSz), 0);
XMEMSET(altSigValBuf, 0, altSigValSz);
ExpectIntGT(altSigValSz = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz,
CTC_ML_DSA_44, preTbsBuf, preTbsSz, ML_DSA_44_TYPE, &altCaKey,
&rng), 0);
ExpectIntEQ(wc_SetCustomExtension(&newCert, 0, "2.5.29.74", altSigValBuf,
altSigValSz), 0);
/* Finally, generate the new certificate. */
if (outBuf != NULL) {
XMEMSET(outBuf, 0, outSz);
}
ExpectIntGT(wc_MakeCert_ex(&newCert, outBuf, outSz, ECC_TYPE, &caKey,
&rng), 0);
ExpectIntGT(outSz = wc_SignCert_ex(newCert.bodySz, newCert.sigType, outBuf,
outSz, ECC_TYPE, &caKey, &rng), 0);
*out = outBuf;
wc_ecc_free(&caKey);
wc_MlDsaKey_Free(&altCaKey);
wc_FreeRng(&rng);
wc_FreeDecodedCert(&preTBS);
return outSz;
}
#endif /* HAVE_ECC && WOLFSSL_HAVE_MLDSA && ... */
static int do_dual_alg_server_certgen(byte **out, char *caKeyFile,
char *sapkiFile, char *altPrivFile,
char *serverKeyFile,
@@ -1254,7 +1388,7 @@ static int do_dual_alg_server_certgen(byte **out, char *caKeyFile,
strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
CTC_DATE_SIZE);
newCert.beforeDateSz = 17;
strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
strncpy((char*)newCert.afterDate, "\x18\x0f""20491231115959Z",
CTC_DATE_SIZE);
newCert.afterDateSz = 17;
@@ -1434,7 +1568,7 @@ static int do_dual_alg_root_certgen_crit(byte **out, char *caKeyFile,
strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
CTC_DATE_SIZE);
newCert.beforeDateSz = 17;
strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
strncpy((char*)newCert.afterDate, "\x18\x0f""20491231115959Z",
CTC_DATE_SIZE);
newCert.afterDateSz = 17;
newCert.sigType = CTC_SHA256wRSA;
@@ -1606,7 +1740,7 @@ static int do_dual_alg_server_certgen_crit(byte **out, char *caKeyFile,
strncpy((char*)newCert.beforeDate, "\x18\x0f""20250101000000Z",
CTC_DATE_SIZE);
newCert.beforeDateSz = 17;
strncpy((char*)newCert.afterDate, "\x18\x0f""20493112115959Z",
strncpy((char*)newCert.afterDate, "\x18\x0f""20491231115959Z",
CTC_DATE_SIZE);
newCert.afterDateSz = 17;
@@ -1893,7 +2027,8 @@ static int test_dual_alg_ecdsa_mldsa(void)
defined(HAVE_ECC) && !defined(WC_NO_RNG) && \
!defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && \
!defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WOLFSSL_SMALL_STACK)
!defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WOLFSSL_SMALL_STACK) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT)
WOLFSSL_CERT_MANAGER * cm = NULL;
wc_MlDsaKey alt_ca_key;
ecc_key ca_key;
@@ -32596,6 +32731,254 @@ static int test_wolfSSL_X509_print_dir_altname(void)
return EXPECT_RESULT();
}
/* X509_print() renders a certificate whose subject key is ML-DSA */
static int test_wolfSSL_X509_print_mldsa(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
defined(XSNPRINTF) && defined(WOLFSSL_HAVE_MLDSA) && \
defined(WOLFSSL_MLDSA_PUBLIC_KEY) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \
defined(WC_ENABLE_ASYM_KEY_IMPORT) && \
defined(WC_ENABLE_ASYM_KEY_EXPORT) && !defined(WOLFSSL_NO_ML_DSA_44)
X509* x509 = NULL;
BIO* bio = NULL;
char* data = NULL;
char* p = NULL;
ExpectNotNull(x509 = X509_load_certificate_file(
"./certs/mldsa/mldsa44-cert.der", SSL_FILETYPE_ASN1));
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);
X509_free(x509);
/* Memory BIO data is not NUL-terminated, terminate it to search in place */
ExpectIntEQ(BIO_write(bio, "", 1), 1);
ExpectIntGT(BIO_get_mem_data(bio, &data), 0);
if (data != NULL) {
ExpectNotNull(p = XSTRSTR(data, "Public Key Algorithm: ML-DSA 44"));
ExpectNotNull(p = XSTRSTR(p, "ML-DSA 44 Public-Key:"));
}
BIO_free(bio);
#endif
return EXPECT_RESULT();
}
/* X509_print() renders the rest of the certificate when the subject key is
* not one this build can print */
static int test_wolfSSL_X509_print_unsupported(void)
{
EXPECT_DECLS;
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
defined(XSNPRINTF) && defined(HAVE_ED25519) && \
defined(HAVE_ED25519_KEY_IMPORT)
X509* x509 = NULL;
BIO* bio = NULL;
char* data = NULL;
char* p = NULL;
ExpectNotNull(x509 = X509_load_certificate_file(
"./certs/ed25519/server-ed25519.der", SSL_FILETYPE_ASN1));
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);
X509_free(x509);
/* Memory BIO data is not NUL-terminated, terminate it to search in place */
ExpectIntEQ(BIO_write(bio, "", 1), 1);
ExpectIntGT(BIO_get_mem_data(bio, &data), 0);
if (data != NULL) {
ExpectNotNull(p = XSTRSTR(data, "Public Key Algorithm: ED25519"));
ExpectNotNull(p = XSTRSTR(p, "print not supported"));
/* the rest of the certificate is still printed */
ExpectNotNull(p = XSTRSTR(p, "Signature Algorithm: ED25519"));
}
BIO_free(bio);
#endif
return EXPECT_RESULT();
}
/* X509_print() renders the X9.146 extensions of a dual algorithm certificate */
static int test_wolfSSL_X509_print_dual_alg(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(OPENSSL_EXTRA) && \
!defined(NO_FILESYSTEM) && defined(XSNPRINTF)
char keyFile[] = "./certs/ca-key.der";
char sapkiFile[] = "./certs/ecc-keyPub.der";
char altPrivFile[] = "./certs/ecc-key.der";
static const int dualAlgNids[] = {
WC_NID_subject_alt_public_key_info,
WC_NID_alt_signature_algorithm,
WC_NID_alt_signature_value
};
static const char* dualAlgOids[] = {
"2.5.29.72",
"2.5.29.73",
"2.5.29.74"
};
byte* root = NULL;
int rootSz = 0;
X509* x509 = NULL;
BIO* bio = NULL;
ASN1_OBJECT* obj = NULL;
char oidTxt[16];
char* data = NULL;
char* p = NULL;
int i;
if (EXPECT_SUCCESS()) {
rootSz = do_dual_alg_root_certgen(&root, keyFile, sapkiFile,
altPrivFile);
}
ExpectNotNull(root);
ExpectIntGT(rootSz, 0);
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_buffer(root, rootSz,
WOLFSSL_FILETYPE_ASN1));
XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);
/* the NIDs' objects carry the OID */
for (i = 0; i < (int)(sizeof(dualAlgNids) / sizeof(*dualAlgNids)); i++) {
ExpectNotNull(obj = OBJ_nid2obj(dualAlgNids[i]));
ExpectIntGT(OBJ_obj2txt(oidTxt, (int)sizeof(oidTxt), obj, 1), 0);
ExpectStrEQ(oidTxt, dualAlgOids[i]);
ASN1_OBJECT_free(obj);
obj = NULL;
}
X509_free(x509);
/* Memory BIO data is not NUL-terminated, terminate it to search in place */
ExpectIntEQ(BIO_write(bio, "", 1), 1);
ExpectIntGT(BIO_get_mem_data(bio, &data), 0);
if (data != NULL) {
ExpectNotNull(p = XSTRSTR(data,
"Public Key Algorithm: rsaEncryption"));
ExpectNotNull(p = XSTRSTR(p,
"X509v3 Subject Alternative Public Key Info"));
ExpectNotNull(p = XSTRSTR(p, "ASN1 OID: prime256v1"));
ExpectNotNull(p = XSTRSTR(p, "X509v3 Alternative Signature Algorithm"));
ExpectNotNull(p = XSTRSTR(p, "sha256WithECDSA"));
ExpectNotNull(p = XSTRSTR(p, "X509v3 Alternative Signature Value"));
}
BIO_free(bio);
#endif
return EXPECT_RESULT();
}
/* X509_print() renders an ML-DSA alternative key and signature */
static int test_wolfSSL_X509_print_dual_alg_mldsa(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(OPENSSL_EXTRA) && \
!defined(NO_FILESYSTEM) && defined(XSNPRINTF) && defined(HAVE_ECC) && \
defined(WOLFSSL_HAVE_MLDSA) && !defined(WOLFSSL_MLDSA_NO_ASN1) && \
defined(WOLFSSL_MLDSA_PRIVATE_KEY) && !defined(WOLFSSL_MLDSA_NO_SIGN) && \
defined(WOLFSSL_MLDSA_PUBLIC_KEY) && !defined(WOLFSSL_NO_ML_DSA_44) && \
defined(WC_ENABLE_ASYM_KEY_IMPORT) && defined(WC_ENABLE_ASYM_KEY_EXPORT)
char keyFile[] = "./certs/ecc-key.der";
char sapkiFile[] = "./certs/mldsa/mldsa44_pub-spki.der";
char altPrivFile[] = "./certs/mldsa/mldsa44_priv-only.der";
byte* root = NULL;
int rootSz = 0;
X509* x509 = NULL;
BIO* bio = NULL;
char* data = NULL;
char* p = NULL;
if (EXPECT_SUCCESS()) {
rootSz = do_dual_alg_root_certgen_mldsa(&root, keyFile, sapkiFile,
altPrivFile);
}
ExpectNotNull(root);
ExpectIntGT(rootSz, 0);
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_buffer(root, rootSz,
WOLFSSL_FILETYPE_ASN1));
XFREE(root, NULL, DYNAMIC_TYPE_TMP_BUFFER);
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);
X509_free(x509);
/* Memory BIO data is not NUL-terminated, terminate it to search in place */
ExpectIntEQ(BIO_write(bio, "", 1), 1);
ExpectIntGT(BIO_get_mem_data(bio, &data), 0);
if (data != NULL) {
ExpectNotNull(p = XSTRSTR(data,
"Public Key Algorithm: id-ecPublicKey"));
ExpectNotNull(p = XSTRSTR(p,
"X509v3 Subject Alternative Public Key Info"));
ExpectNotNull(p = XSTRSTR(p, "ML-DSA 44 Public-Key:"));
ExpectNotNull(p = XSTRSTR(p, "X509v3 Alternative Signature Algorithm"));
ExpectNotNull(p = XSTRSTR(p, "ML-DSA 44"));
ExpectNotNull(p = XSTRSTR(p, "X509v3 Alternative Signature Value"));
}
BIO_free(bio);
#endif
return EXPECT_RESULT();
}
/* X509_print() renders the rest of the certificate when the alternative key
* and signature algorithm are not ones this build can print */
static int test_wolfSSL_X509_print_dual_alg_unsupported(void)
{
EXPECT_DECLS;
#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(OPENSSL_EXTRA) && \
defined(XSNPRINTF) && defined(HAVE_ECC) && !defined(NO_SHA256) && \
(!defined(NO_ECC256) || defined(HAVE_ALL_CURVES))
/* Dual algorithm CA:
* The main algorithm is supported (sha256WithECDSA)
* subjectAltPublicKeyInfo and altSignatureAlgorithm carry the unassigned
* OID 2.16.840.1.101.3.4.3.99
* the altSignatureValue is just '0x21', to save space
* Expires in 2050
*/
static const char unsupportedAltCertPem[] =
"-----BEGIN CERTIFICATE-----\n"
"MIICKTCCAc+gAwIBAgIQSfq5f4sYoCxjvdh6fvKWbzAKBggqhkjOPQQDAjBuMQsw\n"
"CQYDVQQGEwJVUzELMAkGA1UECAwCTVQxEDAOBgNVBAcMB0JvemVtYW4xEDAOBgNV\n"
"BAoMB3dvbGZTU0wxEDAOBgNVBAsMB1Rlc3RpbmcxHDAaBgNVBAMME2NoaW1lcmEt\n"
"dW5zdXBwb3J0ZWQwHhcNMjYwOTIyMTYwNzE5WhcNNDkxMjMxMjM1OTU5WjBuMQsw\n"
"CQYDVQQGEwJVUzELMAkGA1UECAwCTVQxEDAOBgNVBAcMB0JvemVtYW4xEDAOBgNV\n"
"BAoMB3dvbGZTU0wxEDAOBgNVBAsMB1Rlc3RpbmcxHDAaBgNVBAMME2NoaW1lcmEt\n"
"dW5zdXBwb3J0ZWQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQC09lu1gGORci5\n"
"kDHlwEzjnq0pOJi6ENbpCSqAqS4XKrmKvzODRuOVC+R3QLU7Q0UzD2FTfDdEwcv8\n"
"gMroQ+qno08wTTAMBgNVHRMEBTADAQH/MBoGA1UdSAQTMBEwCwYJYIZIAWUDBANj\n"
"AwIApDAUBgNVHUkEDTALBglghkgBZQMEA2MwCwYDVR1KBAQDAgAhMAoGCCqGSM49\n"
"BAMCA0gAMEUCIHbL2VSvgCCZGx8t3oja3VPFqCSeK/1109ga4lOEytz7AiEA8E6l\n"
"HUu6WKCIDbgQcopra7y2TELfcDTT2IWOUQEJ5tw=\n"
"-----END CERTIFICATE-----\n";
X509* x509 = NULL;
BIO* bio = NULL;
char* data = NULL;
char* p = NULL;
int len = 0;
char buf[8192];
ExpectNotNull(x509 = wolfSSL_X509_load_certificate_buffer(
(const unsigned char*)unsupportedAltCertPem,
(int)XSTRLEN(unsupportedAltCertPem), WOLFSSL_FILETYPE_PEM));
ExpectNotNull(bio = BIO_new(BIO_s_mem()));
ExpectIntEQ(X509_print(bio, x509), SSL_SUCCESS);
/* Memory BIO data is not NUL-terminated, copy into a bounded buffer */
ExpectIntGT((len = BIO_get_mem_data(bio, &data)), 0);
ExpectIntLT(len, (int)sizeof(buf));
if ((data != NULL) && (len > 0) && (len < (int)sizeof(buf))) {
XMEMCPY(buf, data, (size_t)len);
buf[len] = '\0';
/* SAPKI prints a not supported message, but continues */
ExpectNotNull(p = XSTRSTR(buf,
"X509v3 Subject Alternative Public Key Info"));
ExpectNotNull(p = XSTRSTR(p, "print not supported"));
/* altSigAlg prints the OID */
ExpectNotNull(p = XSTRSTR(p, "X509v3 Alternative Signature Algorithm"));
ExpectNotNull(p = XSTRSTR(p, "2.16.840.1.101.3.4.3.99"));
/* altSigVal is still printed */
ExpectNotNull(p = XSTRSTR(p,
"X509v3 Alternative Signature Value: \n 21\n"));
}
BIO_free(bio);
X509_free(x509);
#endif
return EXPECT_RESULT();
}
static int test_wolfSSL_X509_CRL_print(void)
{
EXPECT_DECLS;
@@ -44570,6 +44953,11 @@ TEST_CASE testCases[] = {
TEST_DECL(test_wolfSSL_X509_print_basic_constraints),
TEST_DECL(test_wolfSSL_X509_print_ext_key_usage),
TEST_DECL(test_wolfSSL_X509_print_dir_altname),
TEST_DECL(test_wolfSSL_X509_print_mldsa),
TEST_DECL(test_wolfSSL_X509_print_unsupported),
TEST_DECL(test_wolfSSL_X509_print_dual_alg),
TEST_DECL(test_wolfSSL_X509_print_dual_alg_mldsa),
TEST_DECL(test_wolfSSL_X509_print_dual_alg_unsupported),
TEST_DECL(test_wolfSSL_X509_CRL_print),
#endif

View File

@@ -66,6 +66,7 @@ int test_wolfSSL_X509_PUBKEY_RSA(void)
EVP_PKEY* evpKey = NULL;
byte buf[1024];
byte* tmp;
int derSz = 0;
const unsigned char *pk = NULL;
int ppklen;
@@ -87,7 +88,11 @@ int test_wolfSSL_X509_PUBKEY_RSA(void)
ExpectIntEQ(wolfSSL_i2d_X509_PUBKEY(NULL, NULL), WOLFSSL_FATAL_ERROR);
ExpectIntEQ(wolfSSL_i2d_X509_PUBKEY(NULL, &tmp), WOLFSSL_FATAL_ERROR);
ExpectIntEQ(wolfSSL_i2d_X509_PUBKEY(pubKey, NULL), 294);
ExpectIntEQ(wolfSSL_i2d_X509_PUBKEY(pubKey, &tmp), 294);
ExpectIntEQ(derSz = wolfSSL_i2d_X509_PUBKEY(pubKey, &tmp), 294);
/* SPKI wraps tmp, so it ends with the same bytes that pk points to */
ExpectIntGT(derSz, ppklen);
ExpectIntEQ(XMEMCMP(buf + derSz - ppklen, pk, ppklen), 0);
ExpectIntEQ(OBJ_obj2nid(obj), NID_rsaEncryption);
@@ -129,6 +134,9 @@ int test_wolfSSL_X509_PUBKEY_EC(void)
X509_PUBKEY* pubKey = NULL;
X509_PUBKEY* pubKey2 = NULL;
EVP_PKEY* evpKey = NULL;
byte der[256];
byte* tmp;
int derSz = 0;
const unsigned char *pk = NULL;
int ppklen;
@@ -147,6 +155,14 @@ int test_wolfSSL_X509_PUBKEY_EC(void)
ExpectNotNull(pk);
ExpectNotNull(pa);
ExpectIntGT(ppklen, 0);
tmp = der;
ExpectIntGT(derSz = wolfSSL_i2d_X509_PUBKEY(pubKey2, &tmp), 0);
/* SPKI wraps tmp, so it ends with the same bytes that pk points to */
ExpectIntGT(derSz, ppklen);
ExpectIntEQ(XMEMCMP(der + derSz - ppklen, pk, ppklen), 0);
X509_ALGOR_get0(&pa_oid, &pptype, &pval, pa);
ExpectNotNull(pa_oid);
ExpectNotNull(pval);
@@ -235,6 +251,53 @@ int test_wolfSSL_X509_PUBKEY_DSA(void)
return EXPECT_RESULT();
}
int test_wolfSSL_X509_PUBKEY_MLDSA(void)
{
EXPECT_DECLS;
#if (defined(OPENSSL_ALL) || defined(WOLFSSL_APACHE_HTTPD)) && \
defined(WOLFSSL_HAVE_MLDSA) && defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT) && \
!defined(WOLFSSL_NO_ML_DSA_44) && !defined(NO_FILESYSTEM)
X509* x509 = NULL;
X509_PUBKEY* pubKey = NULL;
ASN1_OBJECT* obj = NULL;
X509_ALGOR* pa = NULL;
const unsigned char* pk = NULL;
int ppklen;
unsigned char* der = NULL;
int derSz = 0;
EVP_PKEY* pkey = NULL;
unsigned char* der2 = NULL;
ExpectNotNull(x509 = X509_load_certificate_file(
"./certs/mldsa/mldsa44-cert.pem", SSL_FILETYPE_PEM));
ExpectNotNull(pubKey = X509_get_X509_PUBKEY(x509));
/* pk is the subjectPublicKey BIT STRING the certificate carries */
ExpectIntEQ(X509_PUBKEY_get0_param(&obj, &pk, &ppklen, &pa, pubKey), 1);
ExpectNotNull(pk);
ExpectIntGT(ppklen, 0);
/* the SPKI wraps that key, so it ends with those bytes */
ExpectIntGT(derSz = wolfSSL_i2d_X509_PUBKEY(pubKey, &der), ppklen);
ExpectNotNull(der);
ExpectIntEQ(XMEMCMP(der + derSz - ppklen, pk, ppklen), 0);
/* X509_get_pubkey() builds a separate EVP PKEY, so it must encode to the
* same SubjectPublicKeyInfo */
ExpectNotNull(pkey = X509_get_pubkey(x509));
ExpectIntEQ(wolfSSL_i2d_PUBKEY(pkey, &der2), derSz);
ExpectNotNull(der2);
ExpectIntEQ(XMEMCMP(der2, der, derSz), 0);
XFREE(der2, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
EVP_PKEY_free(pkey);
XFREE(der, NULL, DYNAMIC_TYPE_PUBLIC_KEY);
X509_free(x509);
#endif
return EXPECT_RESULT();
}
int test_wolfSSL_X509_PUBKEY_get(void)
{
EXPECT_DECLS;
@@ -390,6 +453,20 @@ int test_wolfSSL_X509_set_pubkey(void)
ExpectNotNull(pubkey = wolfSSL_X509_get_pubkey(x509));
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pubkey),
WC_EVP_PKEY_DILITHIUM);
#if !defined(NO_CHECK_PRIVATE_KEY) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && \
!defined(WOLFSSL_MLDSA_NO_VERIFY) && \
defined(WOLFSSL_MLDSA_CHECK_KEY)
/* trickles down to wc_CheckPrivateKey() which depends on
* the pubKey buffer being raw */
ExpectIntEQ(wolfSSL_X509_check_private_key(x509, pkey),
WOLFSSL_SUCCESS);
/* a public key should fail */
ExpectIntEQ(wolfSSL_X509_check_private_key(x509, pubkey),
WC_NO_ERR_TRACE(WOLFSSL_FAILURE));
#endif
wolfSSL_EVP_PKEY_free(pubkey);
pubkey = NULL;
@@ -479,10 +556,10 @@ int test_wolfSSL_X509_set_pubkey(void)
wolfSSL_EVP_PKEY_free(pkey);
pkey = NULL;
/* PKCS#8 shapes: a seed-carrying key derives the public half so
* set_pubkey succeeds. For a private-only blob the outcome tracks
* whether wolfCrypt can derive the public half on demand in
* wc_MlDsaKey_PublicKeyToDer() (added by PR #10985). */
/* PKCS#8 shapes:
* - a seed-carrying key derives the public half so set_pubkey succeeds
* - A private-only blob fails
*/
{
unsigned char* der = NULL;
int derSz = 0;
@@ -515,42 +592,12 @@ int test_wolfSSL_X509_set_pubkey(void)
XFCLOSE(f);
f = XBADFILE;
}
{
wc_MlDsaKey* rawKey = NULL;
byte* pubDer = NULL;
word32 kidx = 0;
int expected = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
int keyRet = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
ExpectNotNull(pubDer = (byte*)XMALLOC(
MLDSA_MAX_PUB_KEY_DER_SIZE, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
ExpectNotNull(rawKey = (wc_MlDsaKey*)XMALLOC(sizeof(*rawKey),
NULL, DYNAMIC_TYPE_TMP_BUFFER));
ExpectIntEQ(keyRet = wc_MlDsaKey_Init(rawKey, NULL,
INVALID_DEVID), 0);
PRIVATE_KEY_UNLOCK();
ExpectIntEQ(wc_MlDsaKey_PrivateKeyDecode(rawKey, der,
(word32)derSz, &kidx), 0);
if (EXPECT_SUCCESS() &&
wc_MlDsaKey_PublicKeyToDer(rawKey, pubDer,
MLDSA_MAX_PUB_KEY_DER_SIZE, 1) > 0) {
expected = WOLFSSL_SUCCESS;
}
PRIVATE_KEY_LOCK();
if (keyRet == 0) {
wc_MlDsaKey_Free(rawKey);
}
XFREE(rawKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(pubDer, NULL, DYNAMIC_TYPE_TMP_BUFFER);
pp = der;
ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(
WC_EVP_PKEY_DILITHIUM, NULL, &pp, (long)derSz));
ExpectIntEQ(wolfSSL_X509_set_pubkey(x509, pkey), expected);
wolfSSL_EVP_PKEY_free(pkey);
pkey = NULL;
}
pp = der;
ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(
WC_EVP_PKEY_DILITHIUM, NULL, &pp, (long)derSz));
ExpectIntEQ(wolfSSL_X509_set_pubkey(x509, pkey), WOLFSSL_FAILURE);
wolfSSL_EVP_PKEY_free(pkey);
pkey = NULL;
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
@@ -558,9 +605,9 @@ int test_wolfSSL_X509_set_pubkey(void)
!defined(WOLFSSL_MLDSA_VERIFY_ONLY) && defined(WOLFSSL_CERT_GEN) && \
!defined(WOLFSSL_MLDSA_NO_SIGN) && \
!defined(WOLFSSL_MLDSA_NO_VERIFY) && !defined(WOLFSSL_NO_ML_DSA_44)
/* FIPS204-draft Dilithium key: set_pubkey must keep pubKeyOID
* consistent with the draft-OID SPKI emitted by
* wc_MlDsaKey_PublicKeyToDer(), or the subsequent sign fails. */
/* FIPS204-draft Dilithium key: set_pubkey must record the draft OID
* in pubKeyOID alongside the raw key, or the subsequent sign
* fails. */
{
wc_MlDsaKey* draftKey = NULL;
WC_RNG rng;
@@ -569,6 +616,13 @@ int test_wolfSSL_X509_set_pubkey(void)
const unsigned char* dp;
int rngRet = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
int keyRet = WC_NO_ERR_TRACE(BAD_FUNC_ARG);
#ifdef OPENSSL_ALL
WOLFSSL_X509* parsed = NULL;
WOLFSSL_EVP_PKEY* parsedPub = NULL;
unsigned char* certDer = NULL;
const unsigned char* cp;
int certDerSz = 0;
#endif
ExpectNotNull(draftDer = (byte*)XMALLOC(4096, NULL,
DYNAMIC_TYPE_TMP_BUFFER));
@@ -581,7 +635,7 @@ int test_wolfSSL_X509_set_pubkey(void)
0);
ExpectIntEQ(wc_MlDsaKey_MakeKey(draftKey, &rng), 0);
/* KeyToDer (priv+pub): the decode of a priv-only PKCS#8 does
* not derive the public part needed by PublicKeyToDer. */
* not derive the public part needed by ExportPubRaw. */
PRIVATE_KEY_UNLOCK();
ExpectIntGT(draftDerSz = wc_MlDsaKey_KeyToDer(draftKey,
draftDer, 4096), 0);
@@ -602,6 +656,26 @@ int test_wolfSSL_X509_set_pubkey(void)
ExpectIntGT(wolfSSL_X509_sign(x509, pkey, NULL), 0);
ExpectNotNull(pubkey = wolfSSL_X509_get_pubkey(x509));
ExpectIntEQ(wolfSSL_X509_verify(x509, pubkey), WOLFSSL_SUCCESS);
#ifdef OPENSSL_ALL
/* A parsed draft certificate's X509_PUBKEY must keep the draft
* OID, or it verifies with the final ML-DSA-44 parameters. */
ExpectIntGT(certDerSz = wolfSSL_i2d_X509(x509, &certDer), 0);
cp = certDer;
ExpectNotNull(parsed = wolfSSL_d2i_X509(NULL, &cp, certDerSz));
ExpectNotNull(parsedPub = wolfSSL_X509_PUBKEY_get(
wolfSSL_X509_get_X509_PUBKEY(parsed)));
if (EXPECT_SUCCESS()) {
ExpectIntEQ(WOLFSSL_ATOMIC_LOAD(parsedPub->mldsaOID),
WOLFSSL_ATOMIC_LOAD(pubkey->mldsaOID));
}
ExpectIntEQ(wolfSSL_X509_verify(parsed, parsedPub),
WOLFSSL_SUCCESS);
wolfSSL_EVP_PKEY_free(parsedPub);
wolfSSL_X509_free(parsed);
XFREE(certDer, NULL, DYNAMIC_TYPE_OPENSSL);
#endif
wolfSSL_EVP_PKEY_free(pubkey);
pubkey = NULL;
wolfSSL_EVP_PKEY_free(pkey);

View File

@@ -28,6 +28,7 @@ int test_wolfSSL_X509_get_X509_PUBKEY(void);
int test_wolfSSL_X509_PUBKEY_RSA(void);
int test_wolfSSL_X509_PUBKEY_EC(void);
int test_wolfSSL_X509_PUBKEY_DSA(void);
int test_wolfSSL_X509_PUBKEY_MLDSA(void);
int test_wolfSSL_X509_PUBKEY_get(void);
int test_wolfSSL_X509_set_pubkey(void);
@@ -36,6 +37,7 @@ int test_wolfSSL_X509_set_pubkey(void);
TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_RSA), \
TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_EC), \
TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_DSA), \
TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_MLDSA), \
TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_PUBKEY_get), \
TEST_DECL_GROUP("ossl_x509_pk", test_wolfSSL_X509_set_pubkey)

View File

@@ -5439,6 +5439,11 @@ static const byte extCrlNumberOid[] = {85, 29, 20};
#ifdef WOLFSSL_SUBJ_INFO_ACC
static const byte extSubjInfoAccessOid[] = {43, 6, 1, 5, 5, 7, 1, 11};
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
static const byte extSapkiOid[] = {85, 29, 72};
static const byte extAltSigAlgOid[] = {85, 29, 73};
static const byte extAltSigValOid[] = {85, 29, 74};
#endif
/* certAuthInfoType */
static const byte extAuthInfoOcspOid[] = {43, 6, 1, 5, 5, 7, 48, 1};
@@ -6625,6 +6630,20 @@ const byte* OidFromId(word32 id, word32 type, word32* oidSz)
oid = extSubjInfoAccessOid;
*oidSz = sizeof(extSubjInfoAccessOid);
break;
#endif
#ifdef WOLFSSL_DUAL_ALG_CERTS
case SUBJ_ALT_PUB_KEY_INFO_OID:
oid = extSapkiOid;
*oidSz = sizeof(extSapkiOid);
break;
case ALT_SIG_ALG_OID:
oid = extAltSigAlgOid;
*oidSz = sizeof(extAltSigAlgOid);
break;
case ALT_SIG_VAL_OID:
oid = extAltSigValOid;
*oidSz = sizeof(extAltSigValOid);
break;
#endif
default:
break;

View File

@@ -13561,9 +13561,87 @@ static int PrintPubKeyDH(WOLFSSL_BIO* out, const byte* pkey, int pkeySz,
}
#endif /* WOLFSSL_DH_EXTRA */
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT) && \
defined(WC_ENABLE_ASYM_KEY_IMPORT)
/* PrintPubKeyMlDsa is a helper function for wolfSSL_EVP_PKEY_print_public
* to parse a DER format ML-DSA public key specified in the second parameter.
* Parameters:
* out bio to output dump data
* pkey buffer holding public key data
* pkeySz public key data size
* indent the number of spaces for indent
* pctx context(not used)
* Returns 1 on success, 0 on failure.
*/
static int PrintPubKeyMlDsa(WOLFSSL_BIO* out, const byte* pkey, int pkeySz,
int indent, WOLFSSL_ASN1_PCTX* pctx)
{
const byte* pub = NULL;
const char* nameStr = NULL;
word32 pubSz = 0;
word32 inOutIdx = 0;
int keyType = ANONk;
int res = WOLFSSL_SUCCESS;
char line[32] = { 0 };
(void)pctx;
if (out == NULL || pkey == NULL || pkeySz <= 0) {
return WOLFSSL_FAILURE;
}
/* the cached key is a SubjectPublicKeyInfo, its OID gives the level */
if (DecodeAsymKeyPublic_Assign(pkey, &inOutIdx, (word32)pkeySz, &pub,
&pubSz, &keyType) != 0) {
res = WOLFSSL_FAILURE;
}
if (res == WOLFSSL_SUCCESS) {
res = keyType == ML_DSA_44k ||
keyType == ML_DSA_65k ||
keyType == ML_DSA_87k
#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
|| keyType == DILITHIUM_LEVEL2k
|| keyType == DILITHIUM_LEVEL3k
|| keyType == DILITHIUM_LEVEL5k
#endif
;
}
if (res == WOLFSSL_SUCCESS) {
nameStr = wolfSSL_OBJ_nid2ln(oid2nid((word32)keyType, oidKeyType));
res = nameStr != NULL;
}
if (res == WOLFSSL_SUCCESS) {
res = Indent(out, indent) >= 0;
}
if (res == WOLFSSL_SUCCESS) {
res = wolfSSL_BIO_write(out, nameStr, (int)XSTRLEN(nameStr)) > 0;
}
if (res == WOLFSSL_SUCCESS) {
XSTRNCPY(line, " Public-Key:\n", sizeof(line));
res = wolfSSL_BIO_write(out, line, (int)XSTRLEN(line)) > 0;
}
if (res == WOLFSSL_SUCCESS) {
res = Indent(out, indent) >= 0;
}
if (res == WOLFSSL_SUCCESS) {
/* print pub element */
XSTRNCPY(line, "pub:\n", sizeof(line));
res = wolfSSL_BIO_write(out, line, (int)XSTRLEN(line)) > 0;
}
if (res == WOLFSSL_SUCCESS) {
/* upper case */
res = PrintHexWithColon(out, pub, (int)pubSz, indent + 4, 0);
}
return res;
}
#endif /* WOLFSSL_HAVE_MLDSA && WOLFSSL_MLDSA_PUBLIC_KEY &&
* !WOLFSSL_MLDSA_NO_ASN1 && WC_ENABLE_ASYM_KEY_EXPORT &&
* WC_ENABLE_ASYM_KEY_IMPORT */
/* wolfSSL_EVP_PKEY_print_public parses the specified key then
* outputs public key info in human readable format to the specified BIO.
* White spaces of the same number which 'indent" gives, will be added to
* White spaces of the same number which 'indent' gives, will be added to
* each line to output and ignores pctx parameter.
* Parameters:
* out bio to output dump data
@@ -13572,7 +13650,7 @@ static int PrintPubKeyDH(WOLFSSL_BIO* out, const byte* pkey, int pkeySz,
* pctx context(not used)
* Returns 1 on success, 0 or negative on error, -2 means specified key
* algo is not supported.
* Can handle RSA, ECC, DSA and DH public keys.
* Can handle RSA, ECC, DSA, DH and ML-DSA public keys.
*/
int wolfSSL_EVP_PKEY_print_public(WOLFSSL_BIO* out,
const WOLFSSL_EVP_PKEY* pkey, int indent, WOLFSSL_ASN1_PCTX* pctx)
@@ -13589,7 +13667,10 @@ int wolfSSL_EVP_PKEY_print_public(WOLFSSL_BIO* out,
return 0;
}
#if !defined(NO_RSA) || defined(HAVE_ECC) || !defined(NO_DSA) || \
defined(WOLFSSL_DH_EXTRA)
defined(WOLFSSL_DH_EXTRA) || \
(defined(WOLFSSL_HAVE_MLDSA) && defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT) && \
defined(WC_ENABLE_ASYM_KEY_IMPORT))
if (indent < 0) {
indent = 0;
}
@@ -13663,6 +13744,22 @@ int wolfSSL_EVP_PKEY_print_public(WOLFSSL_BIO* out,
#endif
break;
case WC_EVP_PKEY_DILITHIUM:
#if defined(WOLFSSL_HAVE_MLDSA) && defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \
!defined(WOLFSSL_MLDSA_NO_ASN1) && defined(WC_ENABLE_ASYM_KEY_EXPORT) && \
defined(WC_ENABLE_ASYM_KEY_IMPORT)
res = PrintPubKeyMlDsa(
out,
(byte*)(pkey->pkey.ptr), /* buffer for pkey raw data */
pkey->pkey_sz, /* raw pkey size */
indent, /* indent size */
pctx); /* not used */
#else
res = WOLFSSL_UNKNOWN; /* not supported algo */
#endif
break;
default:
res = WOLFSSL_UNKNOWN; /* not supported algo */
break;

View File

@@ -1152,6 +1152,66 @@ static int wolfssl_i_mldsa_raw_to_der(wc_MlDsaKey* key, int priv, byte** der,
return 0;
}
#if defined(WOLFSSL_MLDSA_PUBLIC_KEY) && defined(WC_ENABLE_ASYM_KEY_EXPORT)
/* Encode raw ML-DSA public key bytes as SubjectPublicKeyInfo
*
* @param [in] raw Raw public key bytes.
* @param [in] rawSz Number of raw bytes.
* @param [in] oid Key OID sum giving the parameter set.
* @param [out] der Allocated buffer holding the DER encoding.
* @param [out] derSz Size of the DER encoding in bytes.
* @param [in] heap Heap hint for the allocation.
* @return 0 on success.
* @return WOLFSSL_FATAL_ERROR on failure.
*/
static int wolfssl_i_mldsa_raw_pub_to_der(const byte* raw, word32 rawSz,
int oid, byte** der, word32* derSz, void* heap)
{
int ret = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);
byte level;
WC_DECLARE_VAR(mldsa, wc_MlDsaKey, 1, heap);
switch (oid) {
#ifdef WOLFSSL_MLDSA_FIPS204_DRAFT
case DILITHIUM_LEVEL2k:
level = WC_ML_DSA_44_DRAFT;
break;
case DILITHIUM_LEVEL3k:
level = WC_ML_DSA_65_DRAFT;
break;
case DILITHIUM_LEVEL5k:
level = WC_ML_DSA_87_DRAFT;
break;
#endif
case ML_DSA_44k:
level = WC_ML_DSA_44;
break;
case ML_DSA_65k:
level = WC_ML_DSA_65;
break;
case ML_DSA_87k:
level = WC_ML_DSA_87;
break;
default:
return WOLFSSL_FATAL_ERROR;
}
WC_ALLOC_VAR_EX(mldsa, wc_MlDsaKey, 1, heap, DYNAMIC_TYPE_MLDSA,
return WOLFSSL_FATAL_ERROR);
if (wc_MlDsaKey_Init(mldsa, heap, INVALID_DEVID) == 0) {
if ((wc_MlDsaKey_SetParams(mldsa, level) == 0) &&
(wc_MlDsaKey_ImportPubRaw(mldsa, raw, rawSz) == 0)) {
ret = wolfssl_i_mldsa_raw_to_der(mldsa, 0, der, derSz, heap);
}
wc_MlDsaKey_Free(mldsa);
}
WC_FREE_VAR_EX(mldsa, heap, DYNAMIC_TYPE_MLDSA);
return ret;
}
#endif /* WOLFSSL_MLDSA_PUBLIC_KEY && WC_ENABLE_ASYM_KEY_EXPORT */
#endif /* !WOLFSSL_MLDSA_NO_ASN1 */
/**

View File

@@ -1056,6 +1056,19 @@ extern const WOLFSSL_ObjectInfo wolfssl_object_info[];
#define WC_NID_name_constraints NAME_CONS_OID /* 2.5.29.30 */
#define WC_NID_crl_distribution_points CRL_DIST_OID /* 2.5.29.31 */
#define WC_NID_certificate_policies CERT_POLICY_OID
/* Under WOLFSSL_OLD_OID_SUM, SUBJ_ALT_PUB_KEY_INFO_OID and ALT_SIG_VAL_OID
* collide with ECC_SECP256K1_OID and dhSinglePass_stdDH_sha224kdf_scheme, so
* OID sum to NID lookups without a group resolve to the dual-alg NIDs. */
#define WC_NID_subject_alt_public_key_info \
SUBJ_ALT_PUB_KEY_INFO_OID /* 2.5.29.72 */
#define WC_NID_alt_signature_algorithm ALT_SIG_ALG_OID /* 2.5.29.73 */
#ifdef WOLFSSL_OLD_OID_SUM
#define WC_NID_alt_signature_value 1300 /* 2.5.29.74, changed to not conflict
* with the NID of
* dhSinglePass_stdDH_sha224kdf_scheme*/
#else
#define WC_NID_alt_signature_value ALT_SIG_VAL_OID /* 2.5.29.74 */
#endif
#define WC_NID_policy_mappings POLICY_MAP_OID
#define WC_NID_policy_constraints POLICY_CONST_OID
#define WC_NID_inhibit_any_policy INHIBIT_ANY_OID /* 2.5.29.54 */
@@ -1195,6 +1208,9 @@ extern const WOLFSSL_ObjectInfo wolfssl_object_info[];
#define NID_info_access WC_NID_info_access
#define NID_sinfo_access WC_NID_sinfo_access
#define NID_name_constraints WC_NID_name_constraints
#define NID_subject_alt_public_key_info WC_NID_subject_alt_public_key_info
#define NID_alt_signature_algorithm WC_NID_alt_signature_algorithm
#define NID_alt_signature_value WC_NID_alt_signature_value
#define NID_crl_distribution_points WC_NID_crl_distribution_points
#define NID_certificate_policies WC_NID_certificate_policies
#define NID_policy_mappings WC_NID_policy_mappings