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:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
490
src/x509.c
490
src/x509.c
@@ -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;
|
||||
|
||||
398
tests/api.c
398
tests/api.c
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user