@@ -2481,3 +2481,229 @@ 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(WOLFSSL_ATECC508A ) && !defined(WOLFSSL_ATECC608A ) && \
2564+ !defined(WOLFSSL_MICROCHIP_TA100 ) && !defined(WOLFSSL_CRYPTOCELL ) && \
2565+ !defined(WOLFSSL_SILABS_SE_ACCEL ) && !defined(WOLFSSL_KCAPI_ECC ) && \
2566+ !defined(WOLFSSL_QNX_CAAM ) && !defined(WOLFSSL_IMXRT1170_CAAM )
2567+ ecc_key fullKey ;
2568+ ecc_key privOnlyKey ;
2569+ WC_RNG rng ;
2570+ word32 idx ;
2571+ byte privOnlyDer [256 ];
2572+ int privOnlyDerSz = 0 ;
2573+ byte fullPub [256 ];
2574+ word32 fullPubSz = sizeof (fullPub );
2575+ byte derivedPub [256 ];
2576+ word32 derivedPubSz = sizeof (derivedPub );
2577+
2578+ XMEMSET (& fullKey , 0 , sizeof (fullKey ));
2579+ XMEMSET (& privOnlyKey , 0 , sizeof (privOnlyKey ));
2580+
2581+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
2582+
2583+ ExpectIntEQ (wc_ecc_init (& fullKey ), 0 );
2584+ idx = 0 ;
2585+ ExpectIntEQ (wc_EccPrivateKeyDecode (ecc_clikey_der_256 , & idx , & fullKey ,
2586+ sizeof_ecc_clikey_der_256 ), 0 );
2587+ ExpectIntEQ (fullKey .type , ECC_PRIVATEKEY );
2588+ PRIVATE_KEY_UNLOCK ();
2589+ ExpectIntEQ (wc_ecc_export_x963 (& fullKey , fullPub , & fullPubSz ), 0 );
2590+ PRIVATE_KEY_LOCK ();
2591+
2592+ /* Re-encode as a private-key-only SEC1 DER (no public point). */
2593+ ExpectIntGT (privOnlyDerSz = wc_EccPrivateKeyToDer (& fullKey , privOnlyDer ,
2594+ sizeof (privOnlyDer )), 0 );
2595+
2596+ #ifdef ECC_TIMING_RESISTANT
2597+ /* Without an RNG set, decode must not derive unblinded: the key is
2598+ * left as ECC_PRIVATEKEY_ONLY, same as before auto-derivation existed. */
2599+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2600+ idx = 0 ;
2601+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2602+ (word32 )privOnlyDerSz ), 0 );
2603+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY_ONLY );
2604+ wc_ecc_free (& privOnlyKey );
2605+ #endif
2606+
2607+ /* Opting into blinding (as every other blinded ECC op in this library
2608+ * requires) makes decode derive and cache the public point. */
2609+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2610+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2611+ idx = 0 ;
2612+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2613+ (word32 )privOnlyDerSz ), 0 );
2614+
2615+ /* The public point should have been derived automatically, making the
2616+ * key fully usable rather than left as ECC_PRIVATEKEY_ONLY. */
2617+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY );
2618+ PRIVATE_KEY_UNLOCK ();
2619+ ExpectIntEQ (wc_ecc_export_x963 (& privOnlyKey , derivedPub , & derivedPubSz ),
2620+ 0 );
2621+ PRIVATE_KEY_LOCK ();
2622+ ExpectIntEQ (derivedPubSz , fullPubSz );
2623+ ExpectBufEQ (derivedPub , fullPub , fullPubSz );
2624+
2625+ wc_ecc_free (& privOnlyKey );
2626+ wc_ecc_free (& fullKey );
2627+
2628+ #if defined(USE_WOLFSSL_MEMORY ) && !defined(WOLFSSL_NO_MALLOC ) && \
2629+ !defined(WOLFSSL_STATIC_MEMORY )
2630+ {
2631+ wolfSSL_Malloc_cb prevMalloc = NULL ;
2632+ wolfSSL_Free_cb prevFree = NULL ;
2633+ wolfSSL_Realloc_cb prevRealloc = NULL ;
2634+ int allocatorsSet = 0 ;
2635+ int baseAllocCount = 0 ;
2636+ int totalAllocCount = 0 ;
2637+
2638+ ExpectIntEQ (wolfSSL_GetAllocators (& prevMalloc , & prevFree , & prevRealloc ),
2639+ 0 );
2640+ ExpectIntEQ (wolfSSL_SetAllocators (ecc_oom_malloc_cb , ecc_oom_free_cb ,
2641+ ecc_oom_realloc_cb ), 0 );
2642+ if (EXPECT_SUCCESS ()) {
2643+ allocatorsSet = 1 ;
2644+ }
2645+
2646+ /* Count (without failing) allocations for a decode that never
2647+ * derives -- ecc_clikey_der_256 already has its public point, so
2648+ * wc_ecc_derive_pub_best_effort() is a no-op. This is the baseline
2649+ * allocation count to skip past below. */
2650+ ecc_oom_count = 0 ;
2651+ ecc_oom_fail_at = 0 ;
2652+ ecc_oom_inject = 1 ;
2653+ ExpectIntEQ (wc_ecc_init (& fullKey ), 0 );
2654+ idx = 0 ;
2655+ ExpectIntEQ (wc_EccPrivateKeyDecode (ecc_clikey_der_256 , & idx , & fullKey ,
2656+ sizeof_ecc_clikey_der_256 ), 0 );
2657+ ecc_oom_inject = 0 ;
2658+ wc_ecc_free (& fullKey );
2659+ baseAllocCount = ecc_oom_count ;
2660+
2661+ /* Count allocations for a decode that does derive, for comparison. */
2662+ ecc_oom_count = 0 ;
2663+ ecc_oom_inject = 1 ;
2664+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2665+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2666+ idx = 0 ;
2667+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2668+ (word32 )privOnlyDerSz ), 0 );
2669+ ecc_oom_inject = 0 ;
2670+ wc_ecc_free (& privOnlyKey );
2671+ totalAllocCount = ecc_oom_count ;
2672+
2673+ /* Only derivation allocates more than the baseline -- if it
2674+ * allocates nothing (e.g. stack-only math build) there is nothing
2675+ * to fault-inject into. */
2676+ if (totalAllocCount > baseAllocCount ) {
2677+ /* Test that a derivation failure leaves the key as
2678+ * ECC_PRIVATEKEY_ONLY but does not fail the overall decode. */
2679+ ecc_oom_failed = 0 ;
2680+ ecc_oom_count = 0 ;
2681+ ecc_oom_fail_at = baseAllocCount + 1 ;
2682+
2683+ ExpectIntEQ (wc_ecc_init (& privOnlyKey ), 0 );
2684+ ExpectIntEQ (wc_ecc_set_rng (& privOnlyKey , & rng ), 0 );
2685+
2686+ idx = 0 ;
2687+ ecc_oom_inject = 1 ;
2688+ /* Decode should succeed, but leave the key as
2689+ * ECC_PRIVATEKEY_ONLY. */
2690+ ExpectIntEQ (wc_EccPrivateKeyDecode (privOnlyDer , & idx , & privOnlyKey ,
2691+ (word32 )privOnlyDerSz ), 0 );
2692+ ExpectIntEQ (ecc_oom_failed , 1 );
2693+ ExpectIntEQ (privOnlyKey .type , ECC_PRIVATEKEY_ONLY );
2694+
2695+ wc_ecc_free (& privOnlyKey );
2696+ ecc_oom_inject = 0 ;
2697+ }
2698+
2699+ if (allocatorsSet ) {
2700+ (void )wolfSSL_SetAllocators (prevMalloc , prevFree , prevRealloc );
2701+ }
2702+ }
2703+ #endif /* USE_WOLFSSL_MEMORY */
2704+
2705+ wc_FreeRng (& rng );
2706+ #endif /* !NO_ASN && HAVE_ECC && !NO_ECC_MAKE_PUB && USE_CERT_BUFFERS_256 &&
2707+ * !HAVE_FIPS */
2708+ return EXPECT_RESULT ();
2709+ }
0 commit comments