@@ -2481,3 +2481,81 @@ int test_wc_AsnFeatureCoverage(void)
24812481#endif /* !NO_ASN && HAVE_ECC && USE_CERT_BUFFERS_256 && !HAVE_FIPS */
24822482 return EXPECT_RESULT ();
24832483}
2484+
2485+ /* wc_EccPrivateKeyDecode should derive and cache the public point (best
2486+ * effort) when it decodes a SEC1 private key whose optional public point
2487+ * was omitted, so the key comes out fully usable. */
2488+ int test_wc_EccPrivateKeyDecode_derive_pub (void )
2489+ {
2490+ EXPECT_DECLS ;
2491+ #if !defined(NO_ASN ) && defined(HAVE_ECC ) && !defined(NO_ECC_MAKE_PUB ) && \
2492+ defined(USE_CERT_BUFFERS_256 ) && !defined(HAVE_FIPS ) && \
2493+ !defined(WOLFSSL_ATECC508A ) && !defined(WOLFSSL_ATECC608A ) && \
2494+ !defined(WOLFSSL_MICROCHIP_TA100 ) && !defined(WOLFSSL_CRYPTOCELL ) && \
2495+ !defined(WOLFSSL_SILABS_SE_ACCEL ) && !defined(WOLFSSL_KCAPI_ECC ) && \
2496+ !defined(WOLFSSL_QNX_CAAM ) && !defined(WOLFSSL_IMXRT1170_CAAM )
2497+ ecc_key fullKey ;
2498+ ecc_key privOnlyKey ;
2499+ WC_RNG rng ;
2500+ word32 idx ;
2501+ byte privOnlyDer [256 ];
2502+ int privOnlyDerSz ;
2503+ byte fullPub [256 ];
2504+ word32 fullPubSz = sizeof (fullPub );
2505+ byte derivedPub [256 ];
2506+ word32 derivedPubSz = sizeof (derivedPub );
2507+
2508+ XMEMSET (& fullKey , 0 , sizeof (fullKey ));
2509+ XMEMSET (& privOnlyKey , 0 , sizeof (privOnlyKey ));
2510+
2511+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
2512+
2513+ ExpectIntEQ (wc_ecc_init (& fullKey ), 0 );
2514+ idx = 0 ;
2515+ ExpectIntEQ (wc_EccPrivateKeyDecode (ecc_clikey_der_256 , & idx , & fullKey ,
2516+ sizeof_ecc_clikey_der_256 ), 0 );
2517+ ExpectIntEQ (fullKey .type , ECC_PRIVATEKEY );
2518+ PRIVATE_KEY_UNLOCK ();
2519+ ExpectIntEQ (wc_ecc_export_x963 (& fullKey , fullPub , & fullPubSz ), 0 );
2520+ PRIVATE_KEY_LOCK ();
2521+
2522+ /* Re-encode as a private-key-only SEC1 DER (no public point). */
2523+ ExpectIntGT (privOnlyDerSz = wc_EccPrivateKeyToDer (& fullKey , privOnlyDer ,
2524+ sizeof (privOnlyDer )), 0 );
2525+
2526+ #ifdef ECC_TIMING_RESISTANT
2527+ /* Without an RNG set, decode must not derive unblinded: the key is
2528+ * left as ECC_PRIVATEKEY_ONLY, same as before auto-derivation existed. */
2529+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2530+ idx = 0 ;
2531+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2532+ (word32 )privOnlyDerSz ), 0 );
2533+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY_ONLY );
2534+ wc_ecc_free (& privOnlyKey );
2535+ #endif
2536+
2537+ /* Opting into blinding (as every other blinded ECC op in this library
2538+ * requires) makes decode derive and cache the public point. */
2539+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2540+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2541+ idx = 0 ;
2542+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2543+ (word32 )privOnlyDerSz ), 0 );
2544+
2545+ /* The public point should have been derived automatically, making the
2546+ * key fully usable rather than left as ECC_PRIVATEKEY_ONLY. */
2547+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY );
2548+ PRIVATE_KEY_UNLOCK ();
2549+ ExpectIntEQ (wc_ecc_export_x963 (& privOnlyKey , derivedPub , & derivedPubSz ),
2550+ 0 );
2551+ PRIVATE_KEY_LOCK ();
2552+ ExpectIntEQ (derivedPubSz , fullPubSz );
2553+ ExpectBufEQ (derivedPub , fullPub , fullPubSz );
2554+
2555+ wc_ecc_free (& privOnlyKey );
2556+ wc_ecc_free (& fullKey );
2557+ wc_FreeRng (& rng );
2558+ #endif /* !NO_ASN && HAVE_ECC && !NO_ECC_MAKE_PUB && USE_CERT_BUFFERS_256 &&
2559+ * !HAVE_FIPS */
2560+ return EXPECT_RESULT ();
2561+ }
0 commit comments