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