@@ -2481,3 +2481,230 @@ int test_wc_AsnFeatureCoverage(void)
24812481#endif /* !NO_ASN && HAVE_ECC && USE_CERT_BUFFERS_256 && !HAVE_FIPS */
24822482 return EXPECT_RESULT ();
24832483}
2484+
2485+ #if defined(USE_WOLFSSL_MEMORY ) && !defined(WOLFSSL_NO_MALLOC ) && \
2486+ !defined(WOLFSSL_STATIC_MEMORY ) && !defined(NO_ASN ) && \
2487+ defined(HAVE_ECC ) && !defined(NO_ECC_MAKE_PUB ) && \
2488+ defined(USE_CERT_BUFFERS_256 ) && !defined(HAVE_FIPS ) && \
2489+ !defined(WOLFSSL_ATECC508A ) && !defined(WOLFSSL_ATECC608A ) && \
2490+ !defined(WOLFSSL_MICROCHIP_TA100 ) && !defined(WOLFSSL_CRYPTOCELL ) && \
2491+ !defined(WOLFSSL_SILABS_SE_ACCEL ) && !defined(WOLFSSL_KCAPI_ECC ) && \
2492+ !defined(WOLFSSL_QNX_CAAM ) && !defined(WOLFSSL_IMXRT1170_CAAM )
2493+ /* Rather than failing the first allocation seen after arming, count
2494+ * allocations and fail only the Nth (ecc_oom_fail_at). This lets the test
2495+ * target the allocation specific to public key derivation instead of
2496+ * whichever unrelated allocation (ASN parsing, big-int growth, etc.)
2497+ * happens to run first -- that varies by math library/build config. */
2498+ static int ecc_oom_failed = 0 ;
2499+ static int ecc_oom_inject = 0 ;
2500+ static int ecc_oom_count = 0 ;
2501+ static int ecc_oom_fail_at = 0 ;
2502+
2503+ /* Custom malloc for testing OOM.
2504+ * Returns allocated pointer or NULL on failure. */
2505+ #ifdef WOLFSSL_DEBUG_MEMORY
2506+ static void * ecc_oom_malloc_cb (size_t size , const char * func ,
2507+ unsigned int line )
2508+ {
2509+ (void )func ;
2510+ (void )line ;
2511+ #else
2512+ static void * ecc_oom_malloc_cb (size_t size )
2513+ {
2514+ #endif
2515+ if (ecc_oom_inject ) {
2516+ ecc_oom_count ++ ;
2517+ if (!ecc_oom_failed &&
2518+ (ecc_oom_fail_at != 0 ) && (ecc_oom_count == ecc_oom_fail_at )) {
2519+ ecc_oom_failed = 1 ;
2520+ return NULL ;
2521+ }
2522+ }
2523+ return malloc (size );
2524+ }
2525+
2526+ /* Custom free for testing OOM. */
2527+ #ifdef WOLFSSL_DEBUG_MEMORY
2528+ static void ecc_oom_free_cb (void * ptr , const char * func , unsigned int line )
2529+ {
2530+ (void )func ;
2531+ (void )line ;
2532+ #else
2533+ static void ecc_oom_free_cb (void * ptr )
2534+ {
2535+ #endif
2536+ free (ptr );
2537+ }
2538+
2539+ /* Custom realloc for testing OOM.
2540+ * Returns reallocated pointer or NULL on failure. */
2541+ #ifdef WOLFSSL_DEBUG_MEMORY
2542+ static void * ecc_oom_realloc_cb (void * ptr , size_t size , const char * func ,
2543+ unsigned int line )
2544+ {
2545+ (void )func ;
2546+ (void )line ;
2547+ #else
2548+ static void * ecc_oom_realloc_cb (void * ptr , size_t size )
2549+ {
2550+ #endif
2551+ return realloc (ptr , size );
2552+ }
2553+ #endif /* USE_WOLFSSL_MEMORY && ... */
2554+
2555+ /* wc_EccPrivateKeyDecode should derive and cache the public point (best
2556+ * effort) when it decodes a SEC1 private key whose optional public point
2557+ * was omitted, so the key comes out fully usable. */
2558+ int test_wc_EccPrivateKeyDecode_derive_pub (void )
2559+ {
2560+ EXPECT_DECLS ;
2561+ #if !defined(NO_ASN ) && defined(HAVE_ECC ) && !defined(NO_ECC_MAKE_PUB ) && \
2562+ defined(USE_CERT_BUFFERS_256 ) && !defined(HAVE_FIPS ) && \
2563+ !defined(HAVE_SELFTEST ) && \
2564+ !defined(WOLFSSL_ATECC508A ) && !defined(WOLFSSL_ATECC608A ) && \
2565+ !defined(WOLFSSL_MICROCHIP_TA100 ) && !defined(WOLFSSL_CRYPTOCELL ) && \
2566+ !defined(WOLFSSL_SILABS_SE_ACCEL ) && !defined(WOLFSSL_KCAPI_ECC ) && \
2567+ !defined(WOLFSSL_QNX_CAAM ) && !defined(WOLFSSL_IMXRT1170_CAAM )
2568+ ecc_key fullKey ;
2569+ ecc_key privOnlyKey ;
2570+ WC_RNG rng ;
2571+ word32 idx ;
2572+ byte privOnlyDer [256 ];
2573+ int privOnlyDerSz = 0 ;
2574+ byte fullPub [256 ];
2575+ word32 fullPubSz = sizeof (fullPub );
2576+ byte derivedPub [256 ];
2577+ word32 derivedPubSz = sizeof (derivedPub );
2578+
2579+ XMEMSET (& fullKey , 0 , sizeof (fullKey ));
2580+ XMEMSET (& privOnlyKey , 0 , sizeof (privOnlyKey ));
2581+
2582+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
2583+
2584+ ExpectIntEQ (wc_ecc_init (& fullKey ), 0 );
2585+ idx = 0 ;
2586+ ExpectIntEQ (wc_EccPrivateKeyDecode (ecc_clikey_der_256 , & idx , & fullKey ,
2587+ sizeof_ecc_clikey_der_256 ), 0 );
2588+ ExpectIntEQ (fullKey .type , ECC_PRIVATEKEY );
2589+ PRIVATE_KEY_UNLOCK ();
2590+ ExpectIntEQ (wc_ecc_export_x963 (& fullKey , fullPub , & fullPubSz ), 0 );
2591+ PRIVATE_KEY_LOCK ();
2592+
2593+ /* Re-encode as a private-key-only SEC1 DER (no public point). */
2594+ ExpectIntGT (privOnlyDerSz = wc_EccPrivateKeyToDer (& fullKey , privOnlyDer ,
2595+ sizeof (privOnlyDer )), 0 );
2596+
2597+ #ifdef ECC_TIMING_RESISTANT
2598+ /* Without an RNG set, decode must not derive unblinded: the key is
2599+ * left as ECC_PRIVATEKEY_ONLY, same as before auto-derivation existed. */
2600+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2601+ idx = 0 ;
2602+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2603+ (word32 )privOnlyDerSz ), 0 );
2604+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY_ONLY );
2605+ wc_ecc_free (& privOnlyKey );
2606+ #endif
2607+
2608+ /* Opting into blinding (as every other blinded ECC op in this library
2609+ * requires) makes decode derive and cache the public point. */
2610+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2611+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2612+ idx = 0 ;
2613+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2614+ (word32 )privOnlyDerSz ), 0 );
2615+
2616+ /* The public point should have been derived automatically, making the
2617+ * key fully usable rather than left as ECC_PRIVATEKEY_ONLY. */
2618+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY );
2619+ PRIVATE_KEY_UNLOCK ();
2620+ ExpectIntEQ (wc_ecc_export_x963 (& privOnlyKey , derivedPub , & derivedPubSz ),
2621+ 0 );
2622+ PRIVATE_KEY_LOCK ();
2623+ ExpectIntEQ (derivedPubSz , fullPubSz );
2624+ ExpectBufEQ (derivedPub , fullPub , fullPubSz );
2625+
2626+ wc_ecc_free (& privOnlyKey );
2627+ wc_ecc_free (& fullKey );
2628+
2629+ #if defined(USE_WOLFSSL_MEMORY ) && !defined(WOLFSSL_NO_MALLOC ) && \
2630+ !defined(WOLFSSL_STATIC_MEMORY )
2631+ {
2632+ wolfSSL_Malloc_cb prevMalloc = NULL ;
2633+ wolfSSL_Free_cb prevFree = NULL ;
2634+ wolfSSL_Realloc_cb prevRealloc = NULL ;
2635+ int allocatorsSet = 0 ;
2636+ int baseAllocCount = 0 ;
2637+ int totalAllocCount = 0 ;
2638+
2639+ ExpectIntEQ (wolfSSL_GetAllocators (& prevMalloc , & prevFree , & prevRealloc ),
2640+ 0 );
2641+ ExpectIntEQ (wolfSSL_SetAllocators (ecc_oom_malloc_cb , ecc_oom_free_cb ,
2642+ ecc_oom_realloc_cb ), 0 );
2643+ if (EXPECT_SUCCESS ()) {
2644+ allocatorsSet = 1 ;
2645+ }
2646+
2647+ /* Count (without failing) allocations for a decode that never
2648+ * derives -- ecc_clikey_der_256 already has its public point, so
2649+ * wc_ecc_derive_pub_best_effort() is a no-op. This is the baseline
2650+ * allocation count to skip past below. */
2651+ ecc_oom_count = 0 ;
2652+ ecc_oom_fail_at = 0 ;
2653+ ecc_oom_inject = 1 ;
2654+ ExpectIntEQ (wc_ecc_init (& fullKey ), 0 );
2655+ idx = 0 ;
2656+ ExpectIntEQ (wc_EccPrivateKeyDecode (ecc_clikey_der_256 , & idx , & fullKey ,
2657+ sizeof_ecc_clikey_der_256 ), 0 );
2658+ ecc_oom_inject = 0 ;
2659+ wc_ecc_free (& fullKey );
2660+ baseAllocCount = ecc_oom_count ;
2661+
2662+ /* Count allocations for a decode that does derive, for comparison. */
2663+ ecc_oom_count = 0 ;
2664+ ecc_oom_inject = 1 ;
2665+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2666+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2667+ idx = 0 ;
2668+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2669+ (word32 )privOnlyDerSz ), 0 );
2670+ ecc_oom_inject = 0 ;
2671+ wc_ecc_free (& privOnlyKey );
2672+ totalAllocCount = ecc_oom_count ;
2673+
2674+ /* Only derivation allocates more than the baseline -- if it
2675+ * allocates nothing (e.g. stack-only math build) there is nothing
2676+ * to fault-inject into. */
2677+ if (totalAllocCount > baseAllocCount ) {
2678+ /* Test that a derivation failure leaves the key as
2679+ * ECC_PRIVATEKEY_ONLY but does not fail the overall decode. */
2680+ ecc_oom_failed = 0 ;
2681+ ecc_oom_count = 0 ;
2682+ ecc_oom_fail_at = baseAllocCount + 1 ;
2683+
2684+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2685+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2686+
2687+ idx = 0 ;
2688+ ecc_oom_inject = 1 ;
2689+ /* Decode should succeed, but leave the key as
2690+ * ECC_PRIVATEKEY_ONLY. */
2691+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2692+ (word32 )privOnlyDerSz ), 0 );
2693+ ExpectIntEQ (ecc_oom_failed , 1 );
2694+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY_ONLY );
2695+
2696+ wc_ecc_free (& privOnlyKey );
2697+ ecc_oom_inject = 0 ;
2698+ }
2699+
2700+ if (allocatorsSet ) {
2701+ (void )wolfSSL_SetAllocators (prevMalloc , prevFree , prevRealloc );
2702+ }
2703+ }
2704+ #endif /* USE_WOLFSSL_MEMORY */
2705+
2706+ wc_FreeRng (& rng );
2707+ #endif /* !NO_ASN && HAVE_ECC && !NO_ECC_MAKE_PUB && USE_CERT_BUFFERS_256 &&
2708+ * !HAVE_FIPS && !HAVE_SELFTEST */
2709+ return EXPECT_RESULT ();
2710+ }
0 commit comments