@@ -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+
0 commit comments