Skip to content

Commit 7b81e29

Browse files
committed
Add testing for the new ED paths in EVP_PKEY layer
1 parent d385ae9 commit 7b81e29

2 files changed

Lines changed: 187 additions & 1 deletion

File tree

tests/api/test_evp_pkey.c

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2357,3 +2357,183 @@ int test_wolfSSL_EVP_PKEY_print_public(void)
23572357
return EXPECT_RESULT();
23582358
}
23592359

2360+
/* Coverage for the Ed25519 EVP_PKEY layer:
2361+
* - wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, ...) on a PKCS#8 PrivateKeyInfo
2362+
* (the path used by wolfSSL_PEM_read_bio_PrivateKey when keyFormat is
2363+
* ED25519k, e.g. OpenVPN's --key file load).
2364+
* - wolfSSL_d2i_PUBKEY on a DER-encoded SubjectPublicKeyInfo (the standard
2365+
* d2i_PUBKEY input).
2366+
* - wolfSSL_d2i_PUBKEY on a 32-byte raw Ed25519 public key (the dual-input
2367+
* fallback used by CopyDecodedToX509 where dCert->publicKey is the raw
2368+
* bytes from the SPKI BIT STRING, not a wrapped SPKI).
2369+
* - wolfSSL_EVP_PKEY_id reports the new WC_EVP_PKEY_ED25519 type.
2370+
* - wolfSSL_EVP_PKEY_free cleans up the embedded ed25519_key without leaks.
2371+
*/
2372+
int test_wolfSSL_EVP_PKEY_ed25519(void)
2373+
{
2374+
EXPECT_DECLS;
2375+
#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519)
2376+
WOLFSSL_EVP_PKEY* pkey = NULL;
2377+
const unsigned char* p;
2378+
/* 32 arbitrary bytes used as a "raw Ed25519 public key". The wolfCrypt
2379+
* import path does not validate that these encode a curve point, so any
2380+
* 32-byte input is accepted - which mirrors the bytes the X509 parser
2381+
* actually hands to d2i_PUBKEY from a real cert's SPKI BIT STRING. */
2382+
static const unsigned char rawPub[32] = {
2383+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2384+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2385+
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2386+
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
2387+
};
2388+
/* The same 32 bytes wrapped in a 44-byte Ed25519 SubjectPublicKeyInfo:
2389+
* SEQUENCE (42)
2390+
* SEQUENCE (5) AlgorithmIdentifier
2391+
* OID 1.3.101.112 (Ed25519)
2392+
* BIT STRING (33) 0 unused bits + 32 raw key bytes
2393+
*/
2394+
static const unsigned char spkiPub[] = {
2395+
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00,
2396+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2397+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2398+
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2399+
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f
2400+
};
2401+
2402+
/* d2i_PrivateKey: Ed25519 PKCS#8 PrivateKeyInfo. Exercises the new
2403+
* WC_EVP_PKEY_ED25519 case in d2i_evp_pkey() including the algId match
2404+
* for the PKCS#8 wrapper. */
2405+
p = server_ed25519_key;
2406+
ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, NULL,
2407+
&p, (long)sizeof_server_ed25519_key));
2408+
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519);
2409+
wolfSSL_EVP_PKEY_free(pkey);
2410+
pkey = NULL;
2411+
2412+
/* d2i_PUBKEY: 44-byte SubjectPublicKeyInfo. Exercises d2iTryEd25519Key's
2413+
* structured (wc_Ed25519PublicKeyDecode) branch. */
2414+
p = spkiPub;
2415+
ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(spkiPub)));
2416+
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519);
2417+
wolfSSL_EVP_PKEY_free(pkey);
2418+
pkey = NULL;
2419+
2420+
/* d2i_PUBKEY: 32-byte raw key. Exercises d2iTryEd25519Key's raw fallback
2421+
* (wc_ed25519_import_public). This is the path that nginx and OpenVPN
2422+
* hit indirectly via CopyDecodedToX509 -> wolfSSL_d2i_PUBKEY where the
2423+
* caller passes the raw bytes from the SPKI BIT STRING rather than a
2424+
* wrapped SPKI. */
2425+
p = rawPub;
2426+
ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub)));
2427+
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519);
2428+
wolfSSL_EVP_PKEY_free(pkey);
2429+
pkey = NULL;
2430+
2431+
/* Negative: garbage of an unrelated length must not be claimed by the
2432+
* Ed25519 probe (and the chain as a whole must return NULL since none
2433+
* of the other probes match either). */
2434+
{
2435+
static const unsigned char junk[16] = { 0 };
2436+
const unsigned char* jp = junk;
2437+
ExpectNull(wolfSSL_d2i_PUBKEY(NULL, &jp, (long)sizeof(junk)));
2438+
}
2439+
#endif
2440+
return EXPECT_RESULT();
2441+
}
2442+
2443+
/* End-to-end test of the OpenVPN-style flow: load an Ed25519 cert into an
2444+
* SSL_CTX, decode the matching Ed25519 private key into a WOLFSSL_EVP_PKEY
2445+
* via the new d2i_PrivateKey path, then install it via
2446+
* wolfSSL_CTX_use_PrivateKey (which now has WC_EVP_PKEY_ED25519/ED448 cases
2447+
* in its key-type switch). */
2448+
int test_wolfSSL_CTX_use_PrivateKey_ed25519(void)
2449+
{
2450+
EXPECT_DECLS;
2451+
#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519) && \
2452+
!defined(NO_WOLFSSL_SERVER) && !defined(NO_TLS)
2453+
WOLFSSL_CTX* ctx = NULL;
2454+
WOLFSSL_EVP_PKEY* pkey = NULL;
2455+
const unsigned char* p;
2456+
2457+
ExpectNotNull(ctx = wolfSSL_CTX_new(wolfSSLv23_server_method()));
2458+
2459+
/* Load the matching Ed25519 server cert via the existing buffer API
2460+
* (this path is not under test - we just need a cert installed so the
2461+
* subsequent wolfSSL_CTX_use_PrivateKey() can sanity-check the pair). */
2462+
ExpectIntEQ(wolfSSL_CTX_use_certificate_buffer(ctx, server_ed25519_cert,
2463+
(long)sizeof_server_ed25519_cert, WOLFSSL_FILETYPE_ASN1),
2464+
WOLFSSL_SUCCESS);
2465+
2466+
/* Decode the Ed25519 private key as a WOLFSSL_EVP_PKEY using the new
2467+
* code path. */
2468+
p = server_ed25519_key;
2469+
ExpectNotNull(pkey = wolfSSL_d2i_PrivateKey(EVP_PKEY_ED25519, NULL,
2470+
&p, (long)sizeof_server_ed25519_key));
2471+
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED25519);
2472+
2473+
/* Install it. Before this patch, wolfSSL_CTX_use_PrivateKey's switch
2474+
* fell through to the default arm and returned 0 for any non
2475+
* RSA/ECC/DSA type, which is what made OpenVPN print "Cannot load
2476+
* private key file". */
2477+
ExpectIntEQ(wolfSSL_CTX_use_PrivateKey(ctx, pkey), WOLFSSL_SUCCESS);
2478+
2479+
wolfSSL_EVP_PKEY_free(pkey);
2480+
wolfSSL_CTX_free(ctx);
2481+
#endif
2482+
return EXPECT_RESULT();
2483+
}
2484+
2485+
/* Coverage for the Ed448 side of the EVP_PKEY layer. There are no Ed448
2486+
* test buffers in certs_test.h, so this test only exercises d2i_PUBKEY
2487+
* with hand-constructed inputs (both SPKI-wrapped and 32+25 raw bytes). */
2488+
int test_wolfSSL_EVP_PKEY_ed448(void)
2489+
{
2490+
EXPECT_DECLS;
2491+
#if defined(OPENSSL_EXTRA) && defined(HAVE_ED448)
2492+
WOLFSSL_EVP_PKEY* pkey = NULL;
2493+
const unsigned char* p;
2494+
/* 57 arbitrary bytes used as a "raw Ed448 public key". */
2495+
static const unsigned char rawPub[57] = {
2496+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2497+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2498+
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2499+
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
2500+
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
2501+
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2502+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
2503+
0x38
2504+
};
2505+
/* The same 57 bytes wrapped in a 71-byte Ed448 SubjectPublicKeyInfo:
2506+
* SEQUENCE (67)
2507+
* SEQUENCE (5) AlgorithmIdentifier
2508+
* OID 1.3.101.113 (Ed448)
2509+
* BIT STRING (58) 0 unused bits + 57 raw key bytes
2510+
*/
2511+
static const unsigned char spkiPub[] = {
2512+
0x30, 0x43, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x03, 0x3a, 0x00,
2513+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
2514+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
2515+
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
2516+
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
2517+
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
2518+
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2519+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
2520+
0x38
2521+
};
2522+
2523+
/* SPKI path. */
2524+
p = spkiPub;
2525+
ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(spkiPub)));
2526+
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448);
2527+
wolfSSL_EVP_PKEY_free(pkey);
2528+
pkey = NULL;
2529+
2530+
/* Raw 57-byte fallback path. */
2531+
p = rawPub;
2532+
ExpectNotNull(pkey = wolfSSL_d2i_PUBKEY(NULL, &p, (long)sizeof(rawPub)));
2533+
ExpectIntEQ(wolfSSL_EVP_PKEY_id(pkey), EVP_PKEY_ED448);
2534+
wolfSSL_EVP_PKEY_free(pkey);
2535+
pkey = NULL;
2536+
#endif
2537+
return EXPECT_RESULT();
2538+
}
2539+

tests/api/test_evp_pkey.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ int test_wolfSSL_EVP_MD_ecc_signing(void);
6060
int test_wolfSSL_EVP_PKEY_encrypt(void);
6161
int test_wolfSSL_EVP_PKEY_derive(void);
6262
int test_wolfSSL_EVP_PKEY_print_public(void);
63+
int test_wolfSSL_EVP_PKEY_ed25519(void);
64+
int test_wolfSSL_CTX_use_PrivateKey_ed25519(void);
65+
int test_wolfSSL_EVP_PKEY_ed448(void);
6366

6467
#define TEST_EVP_PKEY_DECLS \
6568
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_CTX_new_id), \
@@ -97,6 +100,9 @@ int test_wolfSSL_EVP_PKEY_print_public(void);
97100
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_MD_ecc_signing), \
98101
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_encrypt), \
99102
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_derive), \
100-
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public)
103+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_print_public), \
104+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed25519), \
105+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_CTX_use_PrivateKey_ed25519), \
106+
TEST_DECL_GROUP("evp_pkey", test_wolfSSL_EVP_PKEY_ed448)
101107

102108
#endif /* WOLFCRYPT_TEST_EVP_PKEY_H */

0 commit comments

Comments
 (0)