Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions tests/api/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,5 +252,77 @@ typedef struct testVector {

extern int testDevId;

/* Skip past outer SEQ header of a PKCS#8 / RFC 5958 OneAsymmetricKey DER blob,
* return version byte (0=v1, 1=v2) or -1 on malformed input. */
#ifdef WC_ENABLE_ASYM_KEY_EXPORT
static WC_INLINE int test_pkcs8_get_version_byte(const byte* der, word32 derSz)
{
word32 idx = 0;
word32 nBytes = 0;

/* SEQ tag + short len + INT tag + INT len + version = 5 */
if (der == NULL || derSz < 5) {
return -1;
}
/* SEQUENCE */
if (der[idx++] != 0x30) {
return -1;
}
if (idx >= derSz) {
return -1;
}
if ((der[idx] & 0x80) == 0) {
/* short-form length */
idx += 1;
}
else {
/* long-form length */
nBytes = (word32)(der[idx] & 0x7F);
if (nBytes == 0 || nBytes > 4) {
return -1;
}
idx += (1 + nBytes);
}
if (idx + 3 > derSz) {
return -1;
}
/* INTEGER, len 1 */
if (der[idx] != 0x02 || der[idx + 1] != 0x01) {
return -1;
}

return (int)der[idx + 2];
}

/* Overwrite OneAsymmetricKey version byte. Return the patched offset or
* -1 on malformed input. */
static WC_INLINE int test_pkcs8_patch_version_byte(byte* der, word32 derSz,
byte newVer)
{
word32 idx = 0;
word32 nBytes = 0;

if (der == NULL || derSz < 5 || der[idx++] != 0x30) {
return -1;
}
if ((der[idx] & 0x80) == 0) {
idx += 1;
}
else {
nBytes = (word32)(der[idx] & 0x7F);
if (nBytes == 0 || nBytes > 4) {
return -1;
}
idx += (1 + nBytes);
}
if (idx + 3 > derSz || der[idx] != 0x02 || der[idx + 1] != 0x01) {
return -1;
}
der[idx + 2] = newVer;

return (int)(idx + 2);
}
#endif /* WC_ENABLE_ASYM_KEY_EXPORT */

#endif /* WOLFCRYPT_TEST_API_H */

161 changes: 161 additions & 0 deletions tests/api/test_asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@

#include <tests/unit.h>

#include <tests/api/api.h>
#include <tests/api/test_asn.h>

#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/rsa.h>
#ifdef HAVE_ED25519
#include <wolfssl/wolfcrypt/ed25519.h>
#endif

#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && defined(HAVE_ED25519)
static int test_SetAsymKeyDer_once(byte* privKey, word32 privKeySz, byte* pubKey,
Expand Down Expand Up @@ -55,6 +61,9 @@ int test_SetAsymKeyDer(void)
#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && defined(HAVE_ED25519)
/* We can't access the keyEd25519Oid variable, so declare it instead */
byte algId[] = {43, 101, 112};
/* RFC 5958: version is v1 (0) for private only, v2 (1) when public key
* bundled. Conditions 1-5 are private only, 6-8 include pub key and
* mutate version[0] = 0x1 before building trueDer. */
byte version[] = {0x0};
byte keyPat = 0xcc;

Expand Down Expand Up @@ -286,6 +295,7 @@ int test_SetAsymKeyDer(void)
privKeySz = 32;
pubKeySz = 32;
trueDerSz = 82;
version[0] = 0x1; /* publicKey present (v2) */

/* SEQ */
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
Expand Down Expand Up @@ -328,6 +338,7 @@ int test_SetAsymKeyDer(void)
privKeySz = 32;
pubKeySz = 128;
trueDerSz = 180;
version[0] = 0x1; /* publicKey present (v2) */

/* SEQ */
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
Expand Down Expand Up @@ -372,6 +383,7 @@ int test_SetAsymKeyDer(void)
privKeySz = 32;
pubKeySz = 256;
trueDerSz = 310;
version[0] = 0x1; /* publicKey present (v2) */

/* SEQ */
trueDer[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
Expand Down Expand Up @@ -413,6 +425,155 @@ int test_SetAsymKeyDer(void)

}

/* RFC 5958 leniency: parser must accept all four variants:
* {v=0,v=1} x {publicKey absent, present}. */
int test_DecodeAsymKey_lenient_versions(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) && \
defined(HAVE_ED25519_KEY_IMPORT) && defined(WOLFSSL_KEY_GEN)
ed25519_key key;
ed25519_key parsed;
WC_RNG rng;
byte bundled[256]; /* v=1 + publicKey */
byte privOnly[256]; /* v=0, no publicKey */
byte tmp[256];
int bundledSz = 0;
int privOnlySz = 0;
word32 idx;

XMEMSET(&key, 0, sizeof(key));
XMEMSET(&parsed, 0, sizeof(parsed));
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(bundledSz = wc_Ed25519KeyToDer(&key, bundled,
(word32)sizeof(bundled)), 0);
ExpectIntGT(privOnlySz = wc_Ed25519PrivateKeyToDer(&key, privOnly,
(word32)sizeof(privOnly)), 0);

if (EXPECT_SUCCESS() &&
((bundledSz > 0) && ((size_t)bundledSz <= sizeof(bundled)) &&
(privOnlySz > 0) && ((size_t)privOnlySz <= sizeof(privOnly)))) {

/* v=1 + publicKey */
XMEMCPY(tmp, bundled, (size_t)bundledSz);
XMEMSET(&parsed, 0, sizeof(parsed));
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)bundledSz), 0);
wc_ed25519_free(&parsed);

/* v=0 + publicKey: patch version byte, [1] publicKey field present. */
XMEMCPY(tmp, bundled, (size_t)bundledSz);
ExpectIntGT(test_pkcs8_patch_version_byte(tmp, (word32)bundledSz, 0),
0);
XMEMSET(&parsed, 0, sizeof(parsed));
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)bundledSz), 0);
wc_ed25519_free(&parsed);

/* v=0, no publicKey */
XMEMCPY(tmp, privOnly, (size_t)privOnlySz);
XMEMSET(&parsed, 0, sizeof(parsed));
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)privOnlySz), 0);
wc_ed25519_free(&parsed);

/* v=1, no publicKey */
XMEMCPY(tmp, privOnly, (size_t)privOnlySz);
ExpectIntGT(test_pkcs8_patch_version_byte(tmp, (word32)privOnlySz, 1),
0);
XMEMSET(&parsed, 0, sizeof(parsed));
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntEQ(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)privOnlySz), 0);
wc_ed25519_free(&parsed);
}

wc_ed25519_free(&key);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}

int test_DecodeAsymKey_negative(void)
{
EXPECT_DECLS;
#if defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_EXPORT) && \
defined(HAVE_ED25519_KEY_IMPORT) && defined(WOLFSSL_KEY_GEN)
ed25519_key key;
ed25519_key parsed;
WC_RNG rng;
byte good[256];
byte tmp[256];
int goodSz = 0;
word32 idx;

XMEMSET(&key, 0, sizeof(key));
XMEMSET(&parsed, 0, sizeof(parsed));
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(goodSz = wc_Ed25519KeyToDer(&key, good,
(word32)sizeof(good)), 0);

if (EXPECT_SUCCESS() &&
(goodSz > 0 && (size_t)goodSz <= sizeof(good))) {

/* Truncated buffer */
XMEMCPY(tmp, good, (size_t)goodSz);
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntLT(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)(goodSz - 1)), 0);
wc_ed25519_free(&parsed);

/* Outer length too big. Patch low-order length byte (long form: bump
* the last byte of the multi-byte length encoding). */
XMEMCPY(tmp, good, (size_t)goodSz);
if ((good[1] & 0x80) == 0) {
tmp[1] = (byte)(good[1] + 1);
}
else {
word32 nBytes = (word32)(good[1] & 0x7F);
tmp[1 + nBytes] = (byte)(good[1 + nBytes] + 1);
}
XMEMSET(&parsed, 0, sizeof(parsed));
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntLT(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)goodSz), 0);
wc_ed25519_free(&parsed);

/* Outer tag not SEQUENCE */
XMEMCPY(tmp, good, (size_t)goodSz);
tmp[0] = 0x02;
XMEMSET(&parsed, 0, sizeof(parsed));
ExpectIntEQ(wc_ed25519_init(&parsed), 0);
idx = 0;
ExpectIntLT(wc_Ed25519PrivateKeyDecode(tmp, &idx, &parsed,
(word32)goodSz), 0);
wc_ed25519_free(&parsed);
}

wc_ed25519_free(&key);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}

#ifndef NO_ASN
static int test_GetSetShortInt_once(word32 val, byte* valDer, word32 valDerSz)
{
Expand Down
4 changes: 4 additions & 0 deletions tests/api/test_asn.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <tests/api/api_decl.h>

int test_SetAsymKeyDer(void);
int test_DecodeAsymKey_lenient_versions(void);
int test_DecodeAsymKey_negative(void);
int test_GetSetShortInt(void);
int test_wc_IndexSequenceOf(void);
int test_wolfssl_local_MatchBaseName(void);
Expand All @@ -34,6 +36,8 @@ int test_wc_DecodeObjectId(void);

#define TEST_ASN_DECLS \
TEST_DECL_GROUP("asn", test_SetAsymKeyDer), \
TEST_DECL_GROUP("asn", test_DecodeAsymKey_lenient_versions), \
TEST_DECL_GROUP("asn", test_DecodeAsymKey_negative), \
TEST_DECL_GROUP("asn", test_GetSetShortInt), \
TEST_DECL_GROUP("asn", test_wc_IndexSequenceOf), \
TEST_DECL_GROUP("asn", test_wolfssl_local_MatchBaseName), \
Expand Down
58 changes: 58 additions & 0 deletions tests/api/test_curve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,3 +608,61 @@ int test_wc_curve25519_priv_clamp_check(void)
return EXPECT_RESULT();
} /* END test_wc_curve25519_priv_clamp_check */

/*
* RFC 5958 OneAsymmetricKey: version=v2 (1) when publicKey is bundled,
* version=v1 (0) for private only.
*/
int test_wc_Curve25519KeyToDer_oneasymkey_version(void)
{
EXPECT_DECLS;
#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_EXPORT) && \
defined(HAVE_CURVE25519_KEY_IMPORT)
curve25519_key key;
curve25519_key key2;
WC_RNG rng;
byte ref[256]; /* reference DER (bundled, then private only) */
byte rt[256]; /* re-export target for memcmp */
int refSz = 0;
int rtSz = 0;
word32 idx;

XMEMSET(&key, 0, sizeof(key));
XMEMSET(&key2, 0, sizeof(key2));
XMEMSET(&rng, 0, sizeof(rng));

ExpectIntEQ(wc_InitRng(&rng), 0);
ExpectIntEQ(wc_curve25519_init(&key), 0);
ExpectIntEQ(wc_curve25519_init(&key2), 0);
ExpectIntEQ(wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &key), 0);

/* make_key sets both priv and pub: KeyToDer bundles both (v=1).
* Use wc_Curve25519KeyDecode so the publicKey field is preserved in key2 */
ExpectIntGT(refSz = wc_Curve25519KeyToDer(&key, ref,
(word32)sizeof(ref), 1), 0);
ExpectIntEQ(test_pkcs8_get_version_byte(ref, (word32)refSz), 1);
idx = 0;
ExpectIntEQ(wc_Curve25519KeyDecode(ref, &idx, &key2, (word32)refSz), 0);
ExpectIntEQ(rtSz = wc_Curve25519KeyToDer(&key2, rt, (word32)sizeof(rt), 1),
refSz);
ExpectIntEQ(XMEMCMP(ref, rt, (size_t)refSz), 0);

/* Private only creates v=0. Reuse ref/rt. */
XMEMSET(&key2, 0, sizeof(key2));
ExpectIntEQ(wc_curve25519_init(&key2), 0);
ExpectIntGT(refSz = wc_Curve25519PrivateKeyToDer(&key, ref,
(word32)sizeof(ref)), 0);
ExpectIntEQ(test_pkcs8_get_version_byte(ref, (word32)refSz), 0);
idx = 0;
ExpectIntEQ(wc_Curve25519PrivateKeyDecode(ref, &idx, &key2,
(word32)refSz), 0);
ExpectIntEQ(rtSz = wc_Curve25519PrivateKeyToDer(&key2, rt,
(word32)sizeof(rt)), refSz);
ExpectIntEQ(XMEMCMP(ref, rt, (size_t)refSz), 0);

wc_curve25519_free(&key);
wc_curve25519_free(&key2);
wc_FreeRng(&rng);
#endif
return EXPECT_RESULT();
}

4 changes: 3 additions & 1 deletion tests/api/test_curve25519.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ int test_wc_curve25519_export_private_raw_ex(void);
int test_wc_curve25519_import_private_raw_ex(void);
int test_wc_curve25519_import_private(void);
int test_wc_curve25519_priv_clamp_check(void);
int test_wc_Curve25519KeyToDer_oneasymkey_version(void);

#define TEST_CURVE25519_DECLS \
TEST_DECL_GROUP("curve25519", test_wc_curve25519_init), \
Expand All @@ -49,6 +50,7 @@ int test_wc_curve25519_priv_clamp_check(void);
TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_private_raw_ex), \
TEST_DECL_GROUP("curve25519", test_wc_curve25519_import_private_raw_ex), \
TEST_DECL_GROUP("curve25519", test_wc_curve25519_import_private), \
TEST_DECL_GROUP("curve25519", test_wc_curve25519_priv_clamp_check)
TEST_DECL_GROUP("curve25519", test_wc_curve25519_priv_clamp_check), \
TEST_DECL_GROUP("curve25519", test_wc_Curve25519KeyToDer_oneasymkey_version)

#endif /* WOLFCRYPT_TEST_CURVE25519_H */
Loading
Loading