mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 13:40:49 +02:00
Merge pull request #10483 from cconlon/pkcs8V1PublicKeyParse
ML-DSA: PKCS#8 parsing + EVP_PKCS82PKEY support
This commit is contained in:
@@ -31,6 +31,12 @@
|
||||
#ifdef HAVE_ED25519
|
||||
#include <wolfssl/wolfcrypt/ed25519.h>
|
||||
#endif
|
||||
#ifdef HAVE_ED448
|
||||
#include <wolfssl/wolfcrypt/ed448.h>
|
||||
#endif
|
||||
#ifdef HAVE_DILITHIUM
|
||||
#include <wolfssl/wolfcrypt/dilithium.h>
|
||||
#endif
|
||||
|
||||
#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && defined(HAVE_ED25519)
|
||||
static int test_SetAsymKeyDer_once(byte* privKey, word32 privKeySz, byte* pubKey,
|
||||
@@ -1363,3 +1369,440 @@ int test_wc_DecodeObjectId(void)
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
#if defined(HAVE_PKCS8) && !defined(NO_ASN) && \
|
||||
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
||||
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN)) && \
|
||||
(defined(HAVE_ED25519) || \
|
||||
(defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
|
||||
defined(WOLFSSL_KEY_GEN)) || \
|
||||
(defined(HAVE_DILITHIUM) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_ASN1)))
|
||||
/* Run ToTraditional_ex() on a copy of der and assert the algId, returned
|
||||
* length, and the inner OCTET STRING tag/length at the start of the
|
||||
* (in-place rewritten) buffer. */
|
||||
static int test_ToTraditional_ex_once(const byte* der, word32 derSz,
|
||||
word32 expectAlgId, word32 expectPrivKeySz)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
byte* copy = NULL;
|
||||
word32 algId = 0;
|
||||
int ret;
|
||||
|
||||
copy = (byte*)XMALLOC(derSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
ExpectNotNull(copy);
|
||||
if (copy != NULL) {
|
||||
XMEMCPY(copy, der, derSz);
|
||||
ret = ToTraditional_ex(copy, derSz, &algId);
|
||||
ExpectIntGT(ret, 0);
|
||||
ExpectIntEQ(algId, expectAlgId);
|
||||
if (ret > 0) {
|
||||
/* wolfSSL writes nested OCTET STRING, but accept raw bytes
|
||||
* too per RFC 5958. */
|
||||
if (copy[0] == ASN_OCTET_STRING) {
|
||||
if (expectPrivKeySz < 0x80) {
|
||||
ExpectIntEQ(copy[1], (byte)expectPrivKeySz);
|
||||
}
|
||||
else if (expectPrivKeySz < 0x100) {
|
||||
ExpectIntEQ(copy[1], 0x81);
|
||||
ExpectIntEQ(copy[2], (byte)expectPrivKeySz);
|
||||
}
|
||||
else {
|
||||
ExpectIntEQ(copy[1], 0x82);
|
||||
ExpectIntEQ(((word32)copy[2] << 8) | copy[3],
|
||||
expectPrivKeySz);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ExpectIntEQ(ret, (int)expectPrivKeySz);
|
||||
}
|
||||
}
|
||||
}
|
||||
XFREE(copy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Hand crafted PKCS#8 v0 and v1 Ed25519 buffers to test parser directly. */
|
||||
int test_ToTraditional_ex_handcrafted(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_PKCS8) && defined(HAVE_ED25519) && \
|
||||
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
||||
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
||||
/* Ed25519 algorithm OID body (1.3.101.112). */
|
||||
static const byte algId[] = { 43, 101, 112 };
|
||||
const word32 privKeySz = ED25519_KEY_SIZE;
|
||||
const word32 pubKeySz = ED25519_PUB_KEY_SIZE;
|
||||
byte der[128];
|
||||
word32 sz;
|
||||
word32 outerLenIdx;
|
||||
/* Filler bytes for the dummy private/public key bodies */
|
||||
const byte keyPat = 0xCC;
|
||||
const byte pubPat = 0xDD;
|
||||
|
||||
/* v0: SEQ { INTEGER 0, SEQ { OID }, OCTET STRING { OCTET STRING priv } } */
|
||||
sz = 0;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
outerLenIdx = sz;
|
||||
der[sz++] = 0; /* outer length, filled in below */
|
||||
der[sz++] = ASN_INTEGER;
|
||||
der[sz++] = 1;
|
||||
der[sz++] = 0x00;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(algId) + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = (byte)sizeof(algId);
|
||||
XMEMCPY(der + sz, algId, sizeof(algId)); sz += sizeof(algId);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)(privKeySz + 2);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)privKeySz;
|
||||
XMEMSET(der + sz, keyPat, privKeySz); sz += privKeySz;
|
||||
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
||||
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, sz, ED25519k, privKeySz));
|
||||
|
||||
/* v1: same plus [1] publicKey trailer. */
|
||||
sz = 0;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
outerLenIdx = sz;
|
||||
der[sz++] = 0;
|
||||
der[sz++] = ASN_INTEGER;
|
||||
der[sz++] = 1;
|
||||
der[sz++] = 0x01;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(algId) + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = (byte)sizeof(algId);
|
||||
XMEMCPY(der + sz, algId, sizeof(algId)); sz += sizeof(algId);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)(privKeySz + 2);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)privKeySz;
|
||||
XMEMSET(der + sz, keyPat, privKeySz); sz += privKeySz;
|
||||
/* [1] publicKey trailer */
|
||||
der[sz++] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
||||
der[sz++] = (byte)pubKeySz;
|
||||
XMEMSET(der + sz, pubPat, pubKeySz); sz += pubKeySz;
|
||||
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
||||
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, sz, ED25519k, privKeySz));
|
||||
|
||||
/* v1 without publicKey: should still accept per RFC 5958. */
|
||||
sz = 0;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
outerLenIdx = sz;
|
||||
der[sz++] = 0;
|
||||
der[sz++] = ASN_INTEGER;
|
||||
der[sz++] = 1;
|
||||
der[sz++] = 0x01;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(algId) + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = (byte)sizeof(algId);
|
||||
XMEMCPY(der + sz, algId, sizeof(algId)); sz += sizeof(algId);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)(privKeySz + 2);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)privKeySz;
|
||||
XMEMSET(der + sz, keyPat, privKeySz); sz += privKeySz;
|
||||
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
||||
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, sz, ED25519k, privKeySz));
|
||||
#endif /* HAVE_PKCS8 && HAVE_ED25519 */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Encoder/parser round trip: ToTraditional_ex() must accept both forms created
|
||||
* by SetAsymKeyDer() (v0 with PrivateKeyToDer, v1 with KeyToDer). */
|
||||
int test_ToTraditional_ex_roundtrip(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_PKCS8) && \
|
||||
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
||||
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
||||
|
||||
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) && \
|
||||
defined(WOLFSSL_KEY_GEN)
|
||||
{
|
||||
ed25519_key key;
|
||||
WC_RNG rng;
|
||||
byte der[256];
|
||||
int derSz = 0;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&rng, 0, sizeof(rng));
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_ed25519_init(&key), 0);
|
||||
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectIntGT(derSz = wc_Ed25519KeyToDer(&key, der, sizeof(der)), 0);
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED25519k,
|
||||
ED25519_KEY_SIZE));
|
||||
|
||||
derSz = wc_Ed25519PrivateKeyToDer(&key, der, sizeof(der));
|
||||
ExpectIntGT(derSz, 0);
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED25519k,
|
||||
ED25519_KEY_SIZE));
|
||||
}
|
||||
|
||||
wc_ed25519_free(&key);
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
#endif /* HAVE_ED25519 */
|
||||
|
||||
#if defined(HAVE_ED448) && defined(HAVE_ED448_KEY_EXPORT) && \
|
||||
defined(WOLFSSL_KEY_GEN)
|
||||
{
|
||||
ed448_key key;
|
||||
WC_RNG rng;
|
||||
byte der[256];
|
||||
int derSz = 0;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&rng, 0, sizeof(rng));
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_ed448_init(&key), 0);
|
||||
ExpectIntEQ(wc_ed448_make_key(&rng, ED448_KEY_SIZE, &key), 0);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectIntGT(derSz = wc_Ed448KeyToDer(&key, der, sizeof(der)), 0);
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED448k,
|
||||
ED448_KEY_SIZE));
|
||||
|
||||
derSz = wc_Ed448PrivateKeyToDer(&key, der, sizeof(der));
|
||||
ExpectIntGT(derSz, 0);
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz, ED448k,
|
||||
ED448_KEY_SIZE));
|
||||
}
|
||||
|
||||
wc_ed448_free(&key);
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
#endif /* HAVE_ED448 */
|
||||
|
||||
#if defined(HAVE_DILITHIUM) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_ASN1) && \
|
||||
(!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65) || \
|
||||
!defined(WOLFSSL_NO_ML_DSA_87))
|
||||
{
|
||||
static const struct {
|
||||
int wcLevel;
|
||||
word32 oidSum;
|
||||
word32 privKeySz;
|
||||
} variants[] = {
|
||||
#ifndef WOLFSSL_NO_ML_DSA_44
|
||||
{ WC_ML_DSA_44, ML_DSA_LEVEL2k, ML_DSA_LEVEL2_KEY_SIZE },
|
||||
#endif
|
||||
#ifndef WOLFSSL_NO_ML_DSA_65
|
||||
{ WC_ML_DSA_65, ML_DSA_LEVEL3k, ML_DSA_LEVEL3_KEY_SIZE },
|
||||
#endif
|
||||
#ifndef WOLFSSL_NO_ML_DSA_87
|
||||
{ WC_ML_DSA_87, ML_DSA_LEVEL5k, ML_DSA_LEVEL5_KEY_SIZE },
|
||||
#endif
|
||||
};
|
||||
|
||||
const word32 derMaxSz = DILITHIUM_MAX_BOTH_KEY_DER_SIZE;
|
||||
byte* der = NULL;
|
||||
WC_RNG rng;
|
||||
size_t i;
|
||||
int derSz;
|
||||
|
||||
XMEMSET(&rng, 0, sizeof(rng));
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectNotNull(der = (byte*)XMALLOC(derMaxSz, NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER));
|
||||
|
||||
for (i = 0; i < sizeof(variants) / sizeof(variants[0]); i++) {
|
||||
dilithium_key key;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
ExpectIntEQ(wc_dilithium_init(&key), 0);
|
||||
ExpectIntEQ(wc_dilithium_set_level(&key, variants[i].wcLevel), 0);
|
||||
ExpectIntEQ(wc_dilithium_make_key(&key, &rng), 0);
|
||||
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectIntGT(derSz = wc_Dilithium_KeyToDer(&key, der, derMaxSz),
|
||||
0);
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz,
|
||||
variants[i].oidSum, variants[i].privKeySz));
|
||||
|
||||
derSz = wc_Dilithium_PrivateKeyToDer(&key, der, derMaxSz);
|
||||
ExpectIntGT(derSz, 0);
|
||||
EXPECT_TEST(test_ToTraditional_ex_once(der, (word32)derSz,
|
||||
variants[i].oidSum, variants[i].privKeySz));
|
||||
}
|
||||
|
||||
wc_dilithium_free(&key);
|
||||
}
|
||||
|
||||
XFREE(der, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wc_FreeRng(&rng);
|
||||
}
|
||||
#endif /* HAVE_DILITHIUM */
|
||||
|
||||
#endif /* HAVE_PKCS8 */
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Trailing garbage that is neither [0] attributes nor [1] publicKey must
|
||||
* still be rejected. */
|
||||
int test_ToTraditional_ex_negative(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_PKCS8) && defined(HAVE_ED25519) && \
|
||||
defined(HAVE_ED25519_KEY_EXPORT) && defined(WOLFSSL_KEY_GEN) && \
|
||||
defined(WOLFSSL_ASN_TEMPLATE) && \
|
||||
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
||||
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
||||
ed25519_key key;
|
||||
WC_RNG rng;
|
||||
byte der[256];
|
||||
byte copy[256];
|
||||
int derSz = 0;
|
||||
word32 algId;
|
||||
|
||||
XMEMSET(&key, 0, sizeof(key));
|
||||
XMEMSET(&rng, 0, sizeof(rng));
|
||||
ExpectIntEQ(wc_InitRng(&rng), 0);
|
||||
ExpectIntEQ(wc_ed25519_init(&key), 0);
|
||||
ExpectIntEQ(wc_ed25519_make_key(&rng, ED25519_KEY_SIZE, &key), 0);
|
||||
ExpectIntGT(derSz = wc_Ed25519PrivateKeyToDer(&key, der, sizeof(der)), 0);
|
||||
|
||||
if (EXPECT_SUCCESS() && (derSz > 0) &&
|
||||
((size_t)derSz + 1 <= sizeof(copy))) {
|
||||
/* Append one byte of trailing data, grow outer SEQ length to cover.
|
||||
* Ed25519 PKCS#8 outer SEQ is under 128 bytes, expect DER short form
|
||||
* so the negative path is always exercised. */
|
||||
XMEMCPY(copy, der, (size_t)derSz);
|
||||
ExpectTrue(copy[1] < 0x80);
|
||||
if (EXPECT_SUCCESS() && copy[1] < 0x80) {
|
||||
copy[1] = (byte)(copy[1] + 1);
|
||||
copy[derSz] = 0x05;
|
||||
algId = 0;
|
||||
ExpectIntLT(ToTraditional_ex(copy, (word32)(derSz + 1), &algId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* publicKey trailer is permitted only when version == v1 */
|
||||
if (EXPECT_SUCCESS() && (derSz > 0) &&
|
||||
((size_t)derSz + 2 + ED25519_PUB_KEY_SIZE <= sizeof(copy))) {
|
||||
word32 trailerSz = 2 + ED25519_PUB_KEY_SIZE;
|
||||
XMEMCPY(copy, der, (size_t)derSz);
|
||||
ExpectTrue(copy[1] < (byte)(0x80 - trailerSz));
|
||||
if (EXPECT_SUCCESS() && copy[1] < (byte)(0x80 - trailerSz)) {
|
||||
copy[1] = (byte)(copy[1] + trailerSz);
|
||||
copy[derSz] = ASN_CONTEXT_SPECIFIC | ASN_ASYMKEY_PUBKEY;
|
||||
copy[derSz + 1] = ED25519_PUB_KEY_SIZE;
|
||||
XMEMSET(copy + derSz + 2, 0xDD, ED25519_PUB_KEY_SIZE);
|
||||
algId = 0;
|
||||
ExpectIntLT(ToTraditional_ex(copy,
|
||||
(word32)(derSz + (int)trailerSz), &algId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* v1 buffer (with publicKey) plus extra trailing garbage. */
|
||||
ExpectIntGT(derSz = wc_Ed25519KeyToDer(&key, der, sizeof(der)), 0);
|
||||
if (EXPECT_SUCCESS() && (derSz > 0) &&
|
||||
((size_t)derSz + 1 <= sizeof(copy))) {
|
||||
XMEMCPY(copy, der, (size_t)derSz);
|
||||
ExpectTrue(copy[1] < 0x80);
|
||||
if (EXPECT_SUCCESS() && copy[1] < 0x80) {
|
||||
copy[1] = (byte)(copy[1] + 1);
|
||||
copy[derSz] = 0x05;
|
||||
algId = 0;
|
||||
ExpectIntLT(ToTraditional_ex(copy, (word32)(derSz + 1), &algId), 0);
|
||||
}
|
||||
}
|
||||
|
||||
wc_ed25519_free(&key);
|
||||
wc_FreeRng(&rng);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* ML-DSA AlgorithmIdentifier has no parameters per FIPS 204. Verify
|
||||
* ToTraditional_ex() rejects a PKCS#8 whose algoSeq carries trailing NULL
|
||||
* or OBJECT_ID parameters. Template parser only (legacy is lenient). */
|
||||
int test_ToTraditional_ex_mldsa_bad_params(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(HAVE_PKCS8) && defined(HAVE_DILITHIUM) && \
|
||||
defined(WOLFSSL_ASN_TEMPLATE) && \
|
||||
(defined(WOLFSSL_TEST_CERT) || defined(OPENSSL_EXTRA) || \
|
||||
defined(OPENSSL_EXTRA_X509_SMALL) || defined(WOLFSSL_PUBLIC_ASN))
|
||||
/* ML-DSA-65 OID body: 2.16.840.1.101.3.4.3.18 */
|
||||
static const byte mldsaOid[] = { 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
|
||||
0x04, 0x03, 0x12 };
|
||||
/* Single-arc OID body, used only to occupy the OBJECT_ID slot. */
|
||||
static const byte extraOid[] = { 0x01 };
|
||||
byte der[64];
|
||||
byte copy[64];
|
||||
word32 sz;
|
||||
word32 outerLenIdx;
|
||||
word32 algId;
|
||||
const word32 privKeySz = 4;
|
||||
const byte privBody = 0xAA;
|
||||
|
||||
/* Bad case, algoSeq = { OID, NULL } */
|
||||
sz = 0;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
outerLenIdx = sz;
|
||||
der[sz++] = 0; /* outer length, filled in below */
|
||||
der[sz++] = ASN_INTEGER;
|
||||
der[sz++] = 1;
|
||||
der[sz++] = 0x00;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(mldsaOid) + 2 + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = (byte)sizeof(mldsaOid);
|
||||
XMEMCPY(der + sz, mldsaOid, sizeof(mldsaOid)); sz += sizeof(mldsaOid);
|
||||
/* Disallowed, NULL parameter after the ML-DSA OID. */
|
||||
der[sz++] = ASN_TAG_NULL;
|
||||
der[sz++] = 0;
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)(privKeySz + 2);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)privKeySz;
|
||||
XMEMSET(der + sz, privBody, privKeySz); sz += privKeySz;
|
||||
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
||||
|
||||
XMEMCPY(copy, der, sz);
|
||||
algId = 0;
|
||||
ExpectIntLT(ToTraditional_ex(copy, sz, &algId), 0);
|
||||
|
||||
/* Bad case, algoSeq = { OID, OBJECT_ID } */
|
||||
sz = 0;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
outerLenIdx = sz;
|
||||
der[sz++] = 0;
|
||||
der[sz++] = ASN_INTEGER;
|
||||
der[sz++] = 1;
|
||||
der[sz++] = 0x00;
|
||||
der[sz++] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
||||
der[sz++] = (byte)(sizeof(mldsaOid) + 2 + sizeof(extraOid) + 2);
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = (byte)sizeof(mldsaOid);
|
||||
XMEMCPY(der + sz, mldsaOid, sizeof(mldsaOid)); sz += sizeof(mldsaOid);
|
||||
/* Disallowed, OBJECT_ID parameter after the ML-DSA OID. */
|
||||
der[sz++] = ASN_OBJECT_ID;
|
||||
der[sz++] = (byte)sizeof(extraOid);
|
||||
XMEMCPY(der + sz, extraOid, sizeof(extraOid)); sz += sizeof(extraOid);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)(privKeySz + 2);
|
||||
der[sz++] = ASN_OCTET_STRING;
|
||||
der[sz++] = (byte)privKeySz;
|
||||
XMEMSET(der + sz, privBody, privKeySz); sz += privKeySz;
|
||||
der[outerLenIdx] = (byte)(sz - outerLenIdx - 1);
|
||||
|
||||
XMEMCPY(copy, der, sz);
|
||||
algId = 0;
|
||||
ExpectIntLT(ToTraditional_ex(copy, sz, &algId), 0);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -34,6 +34,10 @@ int test_wc_DecodeRsaPssParams(void);
|
||||
int test_SerialNumber0_RootCA(void);
|
||||
int test_DecodeAltNames_length_underflow(void);
|
||||
int test_wc_DecodeObjectId(void);
|
||||
int test_ToTraditional_ex_handcrafted(void);
|
||||
int test_ToTraditional_ex_roundtrip(void);
|
||||
int test_ToTraditional_ex_negative(void);
|
||||
int test_ToTraditional_ex_mldsa_bad_params(void);
|
||||
|
||||
#define TEST_ASN_DECLS \
|
||||
TEST_DECL_GROUP("asn", test_SetAsymKeyDer), \
|
||||
@@ -45,6 +49,10 @@ int test_wc_DecodeObjectId(void);
|
||||
TEST_DECL_GROUP("asn", test_wc_DecodeRsaPssParams), \
|
||||
TEST_DECL_GROUP("asn", test_SerialNumber0_RootCA), \
|
||||
TEST_DECL_GROUP("asn", test_DecodeAltNames_length_underflow), \
|
||||
TEST_DECL_GROUP("asn", test_wc_DecodeObjectId)
|
||||
TEST_DECL_GROUP("asn", test_wc_DecodeObjectId), \
|
||||
TEST_DECL_GROUP("asn", test_ToTraditional_ex_handcrafted), \
|
||||
TEST_DECL_GROUP("asn", test_ToTraditional_ex_roundtrip), \
|
||||
TEST_DECL_GROUP("asn", test_ToTraditional_ex_negative), \
|
||||
TEST_DECL_GROUP("asn", test_ToTraditional_ex_mldsa_bad_params)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_ASN_H */
|
||||
|
||||
@@ -71,6 +71,114 @@ int test_wolfSSL_X509_check_private_key(void)
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* EVP_PKCS82PKEY() must populate pkey.ptr/pkey_sz for ML-DSA so
|
||||
* X509_check_private_key() (wc_CheckPrivateKey) can redecode the DER, and
|
||||
* d2i_PKCS8_PKEY() must keep the full PKCS#8 wrapper for ML-DSA level recovery
|
||||
* from the AlgorithmIdentifier. */
|
||||
int test_wolfSSL_X509_check_private_key_mldsa(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM) && \
|
||||
!defined(NO_BIO) && !defined(NO_CHECK_PRIVATE_KEY) && \
|
||||
defined(HAVE_DILITHIUM) && !defined(WOLFSSL_DILITHIUM_NO_SIGN) && \
|
||||
!defined(WOLFSSL_DILITHIUM_NO_VERIFY) && \
|
||||
(defined(OPENSSL_ALL) || defined(WOLFSSL_WPAS_SMALL)) && \
|
||||
(!defined(WOLFSSL_NO_ML_DSA_44) || !defined(WOLFSSL_NO_ML_DSA_65) || \
|
||||
!defined(WOLFSSL_NO_ML_DSA_87))
|
||||
static const struct {
|
||||
const char* keyPath;
|
||||
const char* certPath;
|
||||
const char* mismatchCertPath; /* NULL if no other level available */
|
||||
} cases[] = {
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_44)
|
||||
{ "./certs/mldsa/mldsa44-key.pem",
|
||||
"./certs/mldsa/mldsa44-cert.der",
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_65)
|
||||
"./certs/mldsa/mldsa65-cert.der"
|
||||
#elif !defined(WOLFSSL_NO_ML_DSA_87)
|
||||
"./certs/mldsa/mldsa87-cert.der"
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_65)
|
||||
{ "./certs/mldsa/mldsa65-key.pem",
|
||||
"./certs/mldsa/mldsa65-cert.der",
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_87)
|
||||
"./certs/mldsa/mldsa87-cert.der"
|
||||
#elif !defined(WOLFSSL_NO_ML_DSA_44)
|
||||
"./certs/mldsa/mldsa44-cert.der"
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_87)
|
||||
{ "./certs/mldsa/mldsa87-key.pem",
|
||||
"./certs/mldsa/mldsa87-cert.der",
|
||||
#if !defined(WOLFSSL_NO_ML_DSA_44)
|
||||
"./certs/mldsa/mldsa44-cert.der"
|
||||
#elif !defined(WOLFSSL_NO_ML_DSA_65)
|
||||
"./certs/mldsa/mldsa65-cert.der"
|
||||
#else
|
||||
NULL
|
||||
#endif
|
||||
},
|
||||
#endif
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
|
||||
PKCS8_PRIV_KEY_INFO* pt = NULL;
|
||||
EVP_PKEY* pkey = NULL;
|
||||
X509* x509 = NULL;
|
||||
X509* mismatchX509 = NULL;
|
||||
BIO* bio = NULL;
|
||||
byte* buf = NULL;
|
||||
size_t sz = 0;
|
||||
|
||||
ExpectIntEQ(load_file(cases[i].keyPath, &buf, &sz), 0);
|
||||
|
||||
ExpectNotNull(bio = BIO_new_mem_buf((void*)buf, (int)sz));
|
||||
ExpectNotNull(pt = d2i_PKCS8_PRIV_KEY_INFO_bio(bio, NULL));
|
||||
|
||||
ExpectNotNull(pkey = EVP_PKCS82PKEY(pt));
|
||||
if (pkey != NULL) {
|
||||
ExpectIntEQ(EVP_PKEY_id(pkey), EVP_PKEY_DILITHIUM);
|
||||
/* pkey.ptr must hold the DER so that X509_check_private_key() to
|
||||
* wc_CheckPrivateKey() can re-decode it. */
|
||||
ExpectNotNull(pkey->pkey.ptr);
|
||||
ExpectIntGT(pkey->pkey_sz, 0);
|
||||
}
|
||||
|
||||
ExpectNotNull(x509 = X509_load_certificate_file(
|
||||
cases[i].certPath, SSL_FILETYPE_ASN1));
|
||||
ExpectIntEQ(X509_check_private_key(x509, pkey), 1);
|
||||
|
||||
if (cases[i].mismatchCertPath != NULL) {
|
||||
ExpectNotNull(mismatchX509 = X509_load_certificate_file(
|
||||
cases[i].mismatchCertPath, SSL_FILETYPE_ASN1));
|
||||
ExpectIntEQ(X509_check_private_key(mismatchX509, pkey), 0);
|
||||
}
|
||||
|
||||
/* Negative check, corrupt the outer SEQ tag so the key DER fails */
|
||||
if (EXPECT_SUCCESS() && (pkey != NULL) && (pkey->pkey.ptr != NULL)) {
|
||||
pkey->pkey.ptr[0] ^= 0xFF;
|
||||
ExpectIntEQ(X509_check_private_key(x509, pkey), 0);
|
||||
}
|
||||
|
||||
X509_free(mismatchX509);
|
||||
X509_free(x509);
|
||||
EVP_PKEY_free(pkey);
|
||||
PKCS8_PRIV_KEY_INFO_free(pt);
|
||||
BIO_free(bio);
|
||||
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
}
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_wolfSSL_X509_verify(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <tests/api/api_decl.h>
|
||||
|
||||
int test_wolfSSL_X509_check_private_key(void);
|
||||
int test_wolfSSL_X509_check_private_key_mldsa(void);
|
||||
int test_wolfSSL_X509_verify(void);
|
||||
int test_wolfSSL_X509_sign(void);
|
||||
int test_wolfSSL_X509_sign2(void);
|
||||
@@ -32,6 +33,8 @@ int test_wolfSSL_make_cert(void);
|
||||
|
||||
#define TEST_OSSL_X509_CRYPTO_DECLS \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_check_private_key), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", \
|
||||
test_wolfSSL_X509_check_private_key_mldsa), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_verify), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_sign), \
|
||||
TEST_DECL_GROUP("ossl_x509_crypto", test_wolfSSL_X509_sign2), \
|
||||
|
||||
+83
-18
@@ -8743,9 +8743,8 @@ int wc_RsaPrivateKeyValidate(const byte* input, word32* inOutIdx, int* keySz,
|
||||
#endif /* NO_RSA */
|
||||
|
||||
#ifdef WOLFSSL_ASN_TEMPLATE
|
||||
/* ASN.1 template for a PKCS #8 key.
|
||||
* Ignoring optional attributes and public key.
|
||||
* PKCS #8: RFC 5958, 2 - PrivateKeyInfo
|
||||
/* ASN.1 template for a PKCS #8 PrivateKeyInfo / RFC 5958 OneAsymmetricKey.
|
||||
* Includes the optional [0] attributes and [1] publicKey trailing fields.
|
||||
*/
|
||||
static const ASNItem pkcs8KeyASN[] = {
|
||||
/* SEQ */ { 0, ASN_SEQUENCE, 1, 1, 0 },
|
||||
@@ -8758,9 +8757,10 @@ static const ASNItem pkcs8KeyASN[] = {
|
||||
/* PKEY_ALGO_PARAM_SEQ */ { 2, ASN_SEQUENCE, 1, 0, 1 },
|
||||
#endif
|
||||
/* PKEY_DATA */ { 1, ASN_OCTET_STRING, 0, 0, 0 },
|
||||
/* OPTIONAL Attributes IMPLICIT [0] */
|
||||
/* Attributes [0] OPTIONAL */
|
||||
{ 1, ASN_CONTEXT_SPECIFIC | 0, 1, 0, 1 },
|
||||
/* [[2: publicKey [1] PublicKey OPTIONAL ]] */
|
||||
/* publicKey [1] OPTIONAL */
|
||||
{ 1, ASN_CONTEXT_SPECIFIC | 1, 0, 0, 1 },
|
||||
};
|
||||
enum {
|
||||
PKCS8KEYASN_IDX_SEQ = 0,
|
||||
@@ -8774,6 +8774,7 @@ enum {
|
||||
#endif
|
||||
PKCS8KEYASN_IDX_PKEY_DATA,
|
||||
PKCS8KEYASN_IDX_PKEY_ATTRIBUTES,
|
||||
PKCS8KEYASN_IDX_PKEY_PUBKEY,
|
||||
WOLF_ENUM_DUMMY_LAST_ELEMENT(PKCS8KEYASN_IDX)
|
||||
};
|
||||
|
||||
@@ -8833,13 +8834,15 @@ int ToTraditionalInline_ex2(const byte* input, word32* inOutIdx, word32 sz,
|
||||
/* Key type OID. */
|
||||
oid = dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_OID_KEY].data.oid.sum;
|
||||
|
||||
/* Version 1 includes an optional public key.
|
||||
* If public key is included then the parsing will fail as it did not
|
||||
* use all the data.
|
||||
*/
|
||||
/* Only v1(0) and v2(1) are supported (RFC 5958). The [1] publicKey
|
||||
* trailer is permitted only when version == v1. */
|
||||
if (version > PKCS8v1) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
else if ((version < PKCS8v1) &&
|
||||
(dataASN[PKCS8KEYASN_IDX_PKEY_PUBKEY].tag != 0)) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
}
|
||||
if (ret == 0) {
|
||||
switch (oid) {
|
||||
@@ -8935,9 +8938,71 @@ int ToTraditionalInline_ex2(const byte* input, word32* inOutIdx, word32 sz,
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
/* DSAk not supported. */
|
||||
/* Falcon, Dilithium and SLH-DSA not supported. */
|
||||
/* Ignore OID lookup failures. */
|
||||
#ifdef HAVE_FALCON
|
||||
case FALCON_LEVEL1k:
|
||||
case FALCON_LEVEL5k:
|
||||
/* Neither NULL item nor OBJECT_ID item allowed. */
|
||||
if ((dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_NULL].tag != 0) ||
|
||||
(dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_OID_CURVE].tag != 0)) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_DILITHIUM
|
||||
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
||||
case DILITHIUM_LEVEL2k:
|
||||
case DILITHIUM_LEVEL3k:
|
||||
case DILITHIUM_LEVEL5k:
|
||||
#endif
|
||||
case ML_DSA_LEVEL2k:
|
||||
case ML_DSA_LEVEL3k:
|
||||
case ML_DSA_LEVEL5k:
|
||||
/* Neither NULL item nor OBJECT_ID item allowed. */
|
||||
if ((dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_NULL].tag != 0) ||
|
||||
(dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_OID_CURVE].tag != 0)) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_HAVE_SLHDSA
|
||||
case SLH_DSA_SHA2_128Sk:
|
||||
case SLH_DSA_SHA2_128Fk:
|
||||
case SLH_DSA_SHA2_192Sk:
|
||||
case SLH_DSA_SHA2_192Fk:
|
||||
case SLH_DSA_SHA2_256Sk:
|
||||
case SLH_DSA_SHA2_256Fk:
|
||||
case SLH_DSA_SHAKE_128Sk:
|
||||
case SLH_DSA_SHAKE_128Fk:
|
||||
case SLH_DSA_SHAKE_192Sk:
|
||||
case SLH_DSA_SHAKE_192Fk:
|
||||
case SLH_DSA_SHAKE_256Sk:
|
||||
case SLH_DSA_SHAKE_256Fk:
|
||||
/* Neither NULL item nor OBJECT_ID item allowed. */
|
||||
if ((dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_NULL].tag != 0) ||
|
||||
(dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_OID_CURVE].tag != 0)) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_HAVE_LMS
|
||||
case HSS_LMSk:
|
||||
/* Neither NULL item nor OBJECT_ID item allowed. */
|
||||
if ((dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_NULL].tag != 0) ||
|
||||
(dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_OID_CURVE].tag != 0)) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#ifdef WOLFSSL_HAVE_XMSS
|
||||
case XMSSk:
|
||||
/* Neither NULL item nor OBJECT_ID item allowed. */
|
||||
if ((dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_NULL].tag != 0) ||
|
||||
(dataASN[PKCS8KEYASN_IDX_PKEY_ALGO_OID_CURVE].tag != 0)) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
/* Other OIDs (DSAk), no parameter validation. */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -9037,9 +9102,9 @@ int wc_GetPkcs8TraditionalOffset(byte* input, word32* inOutIdx, word32 sz)
|
||||
int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz,
|
||||
int algoID, const byte* curveOID, word32 oidSz)
|
||||
{
|
||||
/* pkcs8KeyASN_Length-1, the -1 is because we are not adding the optional
|
||||
* set of attributes */
|
||||
DECL_ASNSETDATA(dataASN, pkcs8KeyASN_Length-1);
|
||||
/* pkcs8KeyASN_Length-2, the -2 is because we are not adding the optional
|
||||
* set of attributes or publicKey */
|
||||
DECL_ASNSETDATA(dataASN, pkcs8KeyASN_Length-2);
|
||||
word32 sz = 0;
|
||||
int ret = 0;
|
||||
word32 keyIdx = 0;
|
||||
@@ -9066,7 +9131,7 @@ int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz,
|
||||
#endif
|
||||
|
||||
if (ret == 0)
|
||||
CALLOC_ASNSETDATA(dataASN, pkcs8KeyASN_Length-1, ret, NULL);
|
||||
CALLOC_ASNSETDATA(dataASN, pkcs8KeyASN_Length-2, ret, NULL);
|
||||
|
||||
if (ret == 0) {
|
||||
/* Only support default PKCS #8 format - v0. */
|
||||
@@ -9092,7 +9157,7 @@ int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz,
|
||||
SetASN_Buffer(&dataASN[PKCS8KEYASN_IDX_PKEY_DATA], key, keySz);
|
||||
|
||||
/* Get the size of the DER encoding. */
|
||||
ret = SizeASN_Items(pkcs8KeyASN, dataASN, pkcs8KeyASN_Length-1, &sz);
|
||||
ret = SizeASN_Items(pkcs8KeyASN, dataASN, pkcs8KeyASN_Length-2, &sz);
|
||||
}
|
||||
if ((ret == 0) || (ret == WC_NO_ERR_TRACE(LENGTH_ONLY_E))) {
|
||||
/* Always return the calculated size. */
|
||||
@@ -9105,7 +9170,7 @@ int wc_CreatePKCS8Key(byte* out, word32* outSz, byte* key, word32 keySz,
|
||||
}
|
||||
if (ret == 0) {
|
||||
/* Encode PKCS #8 key into buffer. */
|
||||
SetASN_Items(pkcs8KeyASN, dataASN, pkcs8KeyASN_Length-1, out);
|
||||
SetASN_Items(pkcs8KeyASN, dataASN, pkcs8KeyASN_Length-2, out);
|
||||
ret = (int)sz;
|
||||
}
|
||||
|
||||
|
||||
+33
-3
@@ -942,7 +942,8 @@ static int d2iTryMlDsaKey(WOLFSSL_EVP_PKEY** out, const unsigned char* mem,
|
||||
return WOLFSSL_FATAL_ERROR;
|
||||
}
|
||||
|
||||
return d2i_make_pkey(out, NULL, 0, priv, WC_EVP_PKEY_DILITHIUM);
|
||||
/* Copy the consumed DER into pkey->pkey.ptr when the input was DER */
|
||||
return d2i_make_pkey(out, mem, keyIdx, priv, WC_EVP_PKEY_DILITHIUM);
|
||||
}
|
||||
#endif /* WOLFSSL_HAVE_MLDSA */
|
||||
|
||||
@@ -1696,6 +1697,10 @@ WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY(
|
||||
DerBuffer rawDer;
|
||||
EncryptedInfo info;
|
||||
int advanceLen = 0;
|
||||
#ifdef HAVE_DILITHIUM
|
||||
word32 outerIdx = 0;
|
||||
int outerLen = 0;
|
||||
#endif
|
||||
|
||||
/* Clear the encryption information and DER buffer. */
|
||||
XMEMSET(&info, 0, sizeof(info));
|
||||
@@ -1737,15 +1742,40 @@ WOLFSSL_PKCS8_PRIV_KEY_INFO* wolfSSL_d2i_PKCS8_PKEY(
|
||||
}
|
||||
if (algId == DHk) {
|
||||
/* Special case for DH as we expect the DER buffer to be always
|
||||
* be in PKCS8 format */
|
||||
* in PKCS8 format */
|
||||
rawDer.buffer = pkcs8Der->buffer;
|
||||
rawDer.length = inOutIdx + (word32)ret;
|
||||
}
|
||||
#ifdef HAVE_DILITHIUM
|
||||
else if (
|
||||
#ifdef WOLFSSL_DILITHIUM_FIPS204_DRAFT
|
||||
(algId == DILITHIUM_LEVEL2k) ||
|
||||
(algId == DILITHIUM_LEVEL3k) ||
|
||||
(algId == DILITHIUM_LEVEL5k) ||
|
||||
#endif
|
||||
(algId == ML_DSA_LEVEL2k) ||
|
||||
(algId == ML_DSA_LEVEL3k) ||
|
||||
(algId == ML_DSA_LEVEL5k)) {
|
||||
|
||||
/* Keep full PKCS#8 wrapper for level recovery from
|
||||
* AlgorithmIdentifier parameters */
|
||||
rawDer.buffer = pkcs8Der->buffer;
|
||||
if (GetSequence(pkcs8Der->buffer, &outerIdx, &outerLen,
|
||||
pkcs8Der->length) < 0) {
|
||||
ret = ASN_PARSE_E;
|
||||
}
|
||||
else {
|
||||
rawDer.length = outerIdx + (word32)outerLen;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
rawDer.buffer = pkcs8Der->buffer + inOutIdx;
|
||||
rawDer.length = (word32)ret;
|
||||
}
|
||||
ret = 0; /* good DER */
|
||||
if (ret >= 0) {
|
||||
ret = 0; /* good DER */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user