|
23 | 23 |
|
24 | 24 | #include <tests/api/api.h> |
25 | 25 | #include <tests/api/test_asn.h> |
| 26 | +#include <tests/api/test_oom.h> |
26 | 27 |
|
27 | 28 | #include <wolfssl/wolfcrypt/asn.h> |
28 | 29 | #include <wolfssl/wolfcrypt/asn_public.h> |
@@ -3051,3 +3052,207 @@ int test_wc_AsnFeatureCoverage(void) |
3051 | 3052 | #endif /* !NO_ASN && HAVE_ECC && USE_CERT_BUFFERS_256 && !HAVE_FIPS */ |
3052 | 3053 | return EXPECT_RESULT(); |
3053 | 3054 | } |
| 3055 | + |
| 3056 | +#if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_NO_MALLOC) && \ |
| 3057 | + !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_MEM_FAIL_COUNT) && \ |
| 3058 | + !defined(WOLFSSL_FORCE_MALLOC_FAIL_TEST) && !defined(NO_ASN) && \ |
| 3059 | + defined(HAVE_ECC) && !defined(NO_ECC_MAKE_PUB) && !defined(WC_NO_RNG) && \ |
| 3060 | + !defined(WOLFSSL_NO_ECC_DERIVE_PUB_ON_DECODE) && \ |
| 3061 | + defined(HAVE_ECC_KEY_EXPORT) && \ |
| 3062 | + defined(USE_CERT_BUFFERS_256) && !defined(HAVE_FIPS) && \ |
| 3063 | + !defined(HAVE_SELFTEST) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ |
| 3064 | + !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ |
| 3065 | + !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_CRYPTOCELL) && \ |
| 3066 | + !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLFSSL_KCAPI_ECC) && \ |
| 3067 | + !defined(WOLFSSL_QNX_CAAM) && !defined(WOLFSSL_IMXRT1170_CAAM) |
| 3068 | +/* Fail Nth alloc to target public key derive. */ |
| 3069 | +WOLFSSL_TEST_OOM_CALLBACKS(ecc_oom) |
| 3070 | +#endif /* USE_WOLFSSL_MEMORY && ... */ |
| 3071 | + |
| 3072 | +/* Decode should best-effort derive omitted SEC1 public point. */ |
| 3073 | +int test_wc_EccPrivateKeyDecode_derive_pub(void) |
| 3074 | +{ |
| 3075 | + EXPECT_DECLS; |
| 3076 | +#if !defined(NO_ASN) && defined(HAVE_ECC) && !defined(NO_ECC_MAKE_PUB) && \ |
| 3077 | + !defined(WC_NO_RNG) && \ |
| 3078 | + !defined(WOLFSSL_NO_ECC_DERIVE_PUB_ON_DECODE) && \ |
| 3079 | + defined(HAVE_ECC_KEY_EXPORT) && \ |
| 3080 | + defined(USE_CERT_BUFFERS_256) && !defined(HAVE_FIPS) && \ |
| 3081 | + !defined(HAVE_SELFTEST) && !defined(WOLF_CRYPTO_CB_ONLY_ECC) && \ |
| 3082 | + !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) && \ |
| 3083 | + !defined(WOLFSSL_MICROCHIP_TA100) && !defined(WOLFSSL_CRYPTOCELL) && \ |
| 3084 | + !defined(WOLFSSL_SILABS_SE_ACCEL) && !defined(WOLFSSL_KCAPI_ECC) && \ |
| 3085 | + !defined(WOLFSSL_QNX_CAAM) && !defined(WOLFSSL_IMXRT1170_CAAM) |
| 3086 | + ecc_key fullKey; |
| 3087 | + ecc_key privOnlyKey; |
| 3088 | + WC_RNG rng; |
| 3089 | + word32 idx; |
| 3090 | + byte privOnlyDer[256]; |
| 3091 | + int privOnlyDerSz = 0; |
| 3092 | + byte fullPub[256]; |
| 3093 | + word32 fullPubSz = sizeof(fullPub); |
| 3094 | + byte derivedPub[256]; |
| 3095 | + word32 derivedPubSz = sizeof(derivedPub); |
| 3096 | + |
| 3097 | + XMEMSET(&fullKey, 0, sizeof(fullKey)); |
| 3098 | + XMEMSET(&privOnlyKey, 0, sizeof(privOnlyKey)); |
| 3099 | + /* wc_FreeRng() below runs unconditionally, so rng must be safe to free |
| 3100 | + * even if wc_InitRng() fails. */ |
| 3101 | + XMEMSET(&rng, 0, sizeof(rng)); |
| 3102 | + |
| 3103 | + ExpectIntEQ(wc_InitRng(&rng), 0); |
| 3104 | + |
| 3105 | + ExpectIntEQ(wc_ecc_init(&fullKey), 0); |
| 3106 | + idx = 0; |
| 3107 | + ExpectIntEQ(wc_EccPrivateKeyDecode(ecc_clikey_der_256, &idx, &fullKey, |
| 3108 | + sizeof_ecc_clikey_der_256), 0); |
| 3109 | + ExpectIntEQ(fullKey.type, ECC_PRIVATEKEY); |
| 3110 | + PRIVATE_KEY_UNLOCK(); |
| 3111 | + ExpectIntEQ(wc_ecc_export_x963(&fullKey, fullPub, &fullPubSz), 0); |
| 3112 | + PRIVATE_KEY_LOCK(); |
| 3113 | + |
| 3114 | + /* Re-encode as private-key-only SEC1 DER. */ |
| 3115 | + ExpectIntGT(privOnlyDerSz = wc_EccPrivateKeyToDer(&fullKey, privOnlyDer, |
| 3116 | + sizeof(privOnlyDer)), 0); |
| 3117 | + |
| 3118 | + /* No RNG set: derivation still runs, but with key->rng NULL the |
| 3119 | + * projective-coordinate randomization is skipped even when |
| 3120 | + * ECC_TIMING_RESISTANT is on - EccDerivePubBestEffort() does not stand |
| 3121 | + * up a temporary RNG. */ |
| 3122 | + ExpectIntEQ(wc_ecc_init(&privOnlyKey), 0); |
| 3123 | + idx = 0; |
| 3124 | + ExpectIntEQ(wc_EccPrivateKeyDecode(privOnlyDer, &idx, &privOnlyKey, |
| 3125 | + (word32)privOnlyDerSz), 0); |
| 3126 | + ExpectIntEQ(privOnlyKey.type, ECC_PRIVATEKEY); |
| 3127 | + PRIVATE_KEY_UNLOCK(); |
| 3128 | + ExpectIntEQ(wc_ecc_export_x963(&privOnlyKey, derivedPub, &derivedPubSz), |
| 3129 | + 0); |
| 3130 | + PRIVATE_KEY_LOCK(); |
| 3131 | + ExpectIntEQ(derivedPubSz, fullPubSz); |
| 3132 | + ExpectBufEQ(derivedPub, fullPub, fullPubSz); |
| 3133 | + wc_ecc_free(&privOnlyKey); |
| 3134 | + |
| 3135 | + /* Setting an RNG blinds the scalar mult; same derived point. */ |
| 3136 | + derivedPubSz = sizeof(derivedPub); |
| 3137 | + ExpectIntEQ(wc_ecc_init(&privOnlyKey), 0); |
| 3138 | + ExpectIntEQ(wc_ecc_set_rng(&privOnlyKey, &rng), 0); |
| 3139 | + idx = 0; |
| 3140 | + ExpectIntEQ(wc_EccPrivateKeyDecode(privOnlyDer, &idx, &privOnlyKey, |
| 3141 | + (word32)privOnlyDerSz), 0); |
| 3142 | + |
| 3143 | + /* Public point derived, key fully usable. */ |
| 3144 | + ExpectIntEQ(privOnlyKey.type, ECC_PRIVATEKEY); |
| 3145 | + PRIVATE_KEY_UNLOCK(); |
| 3146 | + ExpectIntEQ(wc_ecc_export_x963(&privOnlyKey, derivedPub, &derivedPubSz), |
| 3147 | + 0); |
| 3148 | + PRIVATE_KEY_LOCK(); |
| 3149 | + ExpectIntEQ(derivedPubSz, fullPubSz); |
| 3150 | + ExpectBufEQ(derivedPub, fullPub, fullPubSz); |
| 3151 | + |
| 3152 | + wc_ecc_free(&privOnlyKey); |
| 3153 | + wc_ecc_free(&fullKey); |
| 3154 | + |
| 3155 | +#if defined(PLUTON_CRYPTO_ECC) || defined(WOLF_CRYPTO_CB) |
| 3156 | + /* devId key left ECC_PRIVATEKEY_ONLY: device derives it. */ |
| 3157 | + ExpectIntEQ(wc_ecc_init_ex(&privOnlyKey, NULL, 1), 0); |
| 3158 | + ExpectIntEQ(wc_ecc_set_rng(&privOnlyKey, &rng), 0); |
| 3159 | + idx = 0; |
| 3160 | + ExpectIntEQ(wc_EccPrivateKeyDecode(privOnlyDer, &idx, &privOnlyKey, |
| 3161 | + (word32)privOnlyDerSz), 0); |
| 3162 | + ExpectIntEQ(privOnlyKey.type, ECC_PRIVATEKEY_ONLY); |
| 3163 | + wc_ecc_free(&privOnlyKey); |
| 3164 | +#endif |
| 3165 | + |
| 3166 | +#if defined(USE_WOLFSSL_MEMORY) && !defined(WOLFSSL_NO_MALLOC) && \ |
| 3167 | + !defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFSSL_MEM_FAIL_COUNT) && \ |
| 3168 | + !defined(WOLFSSL_FORCE_MALLOC_FAIL_TEST) |
| 3169 | + { |
| 3170 | + wolfSSL_Malloc_cb prevMalloc = NULL; |
| 3171 | + wolfSSL_Free_cb prevFree = NULL; |
| 3172 | + wolfSSL_Realloc_cb prevRealloc = NULL; |
| 3173 | + int allocatorsSet = 0; |
| 3174 | + int totalAllocCount = 0; |
| 3175 | + int i; |
| 3176 | + |
| 3177 | + ExpectIntEQ(wolfSSL_GetAllocators(&prevMalloc, &prevFree, &prevRealloc), |
| 3178 | + 0); |
| 3179 | + ExpectIntEQ(wolfSSL_SetAllocators(ecc_oom_malloc_cb, ecc_oom_free_cb, |
| 3180 | + ecc_oom_realloc_cb), 0); |
| 3181 | + if (EXPECT_SUCCESS()) { |
| 3182 | + allocatorsSet = 1; |
| 3183 | + } |
| 3184 | + |
| 3185 | + /* Count the allocations one decode-with-derive makes. Injection is |
| 3186 | + * armed only around the decode so wc_ecc_init() is never starved. */ |
| 3187 | + ecc_oom_count = 0; |
| 3188 | + ecc_oom_fail_at = 0; |
| 3189 | + ecc_oom_failed = 0; |
| 3190 | + ExpectIntEQ(wc_ecc_init(&privOnlyKey), 0); |
| 3191 | + idx = 0; |
| 3192 | + ecc_oom_active = 1; |
| 3193 | + ExpectIntEQ(wc_EccPrivateKeyDecode(privOnlyDer, &idx, &privOnlyKey, |
| 3194 | + (word32)privOnlyDerSz), 0); |
| 3195 | + ecc_oom_active = 0; |
| 3196 | + totalAllocCount = ecc_oom_count; |
| 3197 | + wc_ecc_free(&privOnlyKey); |
| 3198 | + /* The armed window must actually have allocated something, or the |
| 3199 | + * loop below passes vacuously without exercising any OOM path. */ |
| 3200 | + ExpectIntGE(totalAllocCount, 1); |
| 3201 | + |
| 3202 | + /* Fail each allocation in turn. Whatever fails, decode must never |
| 3203 | + * report a derived public key it does not have: the key comes back |
| 3204 | + * either fully derived and correct, or still ECC_PRIVATEKEY_ONLY. */ |
| 3205 | + for (i = 1; EXPECT_SUCCESS() && (i <= totalAllocCount); i++) { |
| 3206 | + int decodeRet; |
| 3207 | + |
| 3208 | + ecc_oom_count = 0; |
| 3209 | + ecc_oom_fail_at = i; |
| 3210 | + ecc_oom_failed = 0; |
| 3211 | + derivedPubSz = sizeof(derivedPub); |
| 3212 | + |
| 3213 | + ExpectIntEQ(wc_ecc_init(&privOnlyKey), 0); |
| 3214 | + idx = 0; |
| 3215 | + ecc_oom_active = 1; |
| 3216 | + decodeRet = wc_EccPrivateKeyDecode(privOnlyDer, &idx, &privOnlyKey, |
| 3217 | + (word32)privOnlyDerSz); |
| 3218 | + ecc_oom_active = 0; |
| 3219 | + /* The injection must actually have fired, otherwise this |
| 3220 | + * iteration passes vacuously without exercising any OOM path. */ |
| 3221 | + ExpectIntEQ(ecc_oom_failed, 1); |
| 3222 | + |
| 3223 | + /* A failure inside the decode itself is fine; only the |
| 3224 | + * best-effort derivation is required to be non-fatal. */ |
| 3225 | + if (decodeRet == 0) { |
| 3226 | + ExpectIntNE(privOnlyKey.type, ECC_PUBLICKEY); |
| 3227 | + if (privOnlyKey.type == ECC_PRIVATEKEY) { |
| 3228 | + PRIVATE_KEY_UNLOCK(); |
| 3229 | + ExpectIntEQ(wc_ecc_export_x963(&privOnlyKey, derivedPub, |
| 3230 | + &derivedPubSz), 0); |
| 3231 | + PRIVATE_KEY_LOCK(); |
| 3232 | + ExpectIntEQ(derivedPubSz, fullPubSz); |
| 3233 | + ExpectBufEQ(derivedPub, fullPub, fullPubSz); |
| 3234 | + } |
| 3235 | + else { |
| 3236 | + ExpectIntEQ(privOnlyKey.type, ECC_PRIVATEKEY_ONLY); |
| 3237 | + } |
| 3238 | + } |
| 3239 | + |
| 3240 | + wc_ecc_free(&privOnlyKey); |
| 3241 | + } |
| 3242 | + |
| 3243 | + ecc_oom_active = 0; |
| 3244 | + ecc_oom_fail_at = 0; |
| 3245 | + |
| 3246 | + if (allocatorsSet) { |
| 3247 | + (void)wolfSSL_SetAllocators(prevMalloc, prevFree, prevRealloc); |
| 3248 | + } |
| 3249 | + } |
| 3250 | +#endif /* USE_WOLFSSL_MEMORY */ |
| 3251 | + |
| 3252 | + wc_FreeRng(&rng); |
| 3253 | +#endif /* !NO_ASN && HAVE_ECC && !NO_ECC_MAKE_PUB && |
| 3254 | + * !WOLFSSL_NO_ECC_DERIVE_PUB_ON_DECODE && HAVE_ECC_KEY_EXPORT && |
| 3255 | + * USE_CERT_BUFFERS_256 && !HAVE_FIPS && !HAVE_SELFTEST && |
| 3256 | + * !WOLF_CRYPTO_CB_ONLY_ECC */ |
| 3257 | + return EXPECT_RESULT(); |
| 3258 | +} |
0 commit comments