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