diff --git a/src/we_aes_block.c b/src/we_aes_block.c index 4e02bb9..61374ed 100644 --- a/src/we_aes_block.c +++ b/src/we_aes_block.c @@ -248,7 +248,7 @@ static int we_aes_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) /* Get the AES-CBC data to work with. */ aes = (we_AesBlock *)EVP_CIPHER_CTX_get_cipher_data(ctx); - if (aes != NULL) { + if (aes == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_CTX_get_cipher_data", aes); ret = 0; @@ -428,7 +428,7 @@ static int we_aes_ecb_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, ret = 0; } - if ((ret == 1) && (key == NULL)) { + if ((ret == 1) && (key != NULL)) { WOLFENGINE_MSG(WE_LOG_CIPHER, "Initializing wolfCrypt Aes structure: %p", &aes->aes); rc = wc_AesInit(&aes->aes, NULL, INVALID_DEVID); @@ -436,6 +436,16 @@ static int we_aes_ecb_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesInit", rc); ret = 0; } + if (ret == 1) { + WOLFENGINE_MSG(WE_LOG_CIPHER, "Setting AES key (%d bytes)", + EVP_CIPHER_CTX_key_length(ctx)); + rc = wc_AesSetKey(&aes->aes, key, EVP_CIPHER_CTX_key_length(ctx), + NULL, enc ? AES_ENCRYPTION : AES_DECRYPTION); + if (rc != 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetKey", rc); + ret = 0; + } + } } if (ret == 1) { @@ -444,17 +454,6 @@ static int we_aes_ecb_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, aes->enc = enc; } - if ((ret == 1) && (key != NULL)) { - WOLFENGINE_MSG(WE_LOG_CIPHER, "Setting AES key (%d bytes)", - EVP_CIPHER_CTX_key_length(ctx)); - rc = wc_AesSetKey(&aes->aes, key, EVP_CIPHER_CTX_key_length(ctx), - NULL, enc ? AES_ENCRYPTION : AES_DECRYPTION); - if (rc != 0) { - WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetKey", rc); - ret = 0; - } - } - WOLFENGINE_LEAVE(WE_LOG_CIPHER, "we_aes_ecb_init", ret); return ret; @@ -732,7 +731,7 @@ static int we_aes_ecb_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) /* Get the AES-ECB data to work with. */ aes = (we_AesBlock *)EVP_CIPHER_CTX_get_cipher_data(ctx); - if (aes != NULL) { + if (aes == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_CTX_get_cipher_data", aes); ret = 0; diff --git a/src/we_aes_cbc_hmac.c b/src/we_aes_cbc_hmac.c index 8256269..0feb123 100644 --- a/src/we_aes_cbc_hmac.c +++ b/src/we_aes_cbc_hmac.c @@ -297,8 +297,14 @@ static int we_aes_cbc_hmac_dec(we_AesCbcHmac* aes, unsigned char *out, ret = -1; } if (ret != -1) { - /* Remove padding and MAC length. */ - ret -= pb + 1 + SHA256_DIGEST_LENGTH; + /* Record must hold the padding and MAC or the length underflows. */ + if (ret < pb + 1 + SHA256_DIGEST_LENGTH) { + ret = -1; + } + else { + /* Remove padding and MAC length. */ + ret -= pb + 1 + SHA256_DIGEST_LENGTH; + } } /* Update record header to have correct message length. */ @@ -577,10 +583,10 @@ int we_init_aescbc_hmac_meths(void) /* AES128-CBC HMAC-SHA256 */ we_aes128_cbc_hmac_ciph = EVP_CIPHER_meth_new(NID_aes_128_cbc_hmac_sha256, WC_AES_BLOCK_SIZE, AES_128_KEY_SIZE); - if (we_aes128_cbc_ciph == NULL) { + if (we_aes128_cbc_hmac_ciph == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_meth_new - AES-128-CBC " - "HMAC SHA256", we_aes128_cbc_ciph); + "HMAC SHA256", we_aes128_cbc_hmac_ciph); ret = 0; } if (ret == 1) { @@ -591,10 +597,10 @@ int we_init_aescbc_hmac_meths(void) if (ret == 1) { we_aes256_cbc_hmac_ciph = EVP_CIPHER_meth_new( NID_aes_256_cbc_hmac_sha256, WC_AES_BLOCK_SIZE, AES_256_KEY_SIZE); - if (we_aes256_cbc_ciph == NULL) { + if (we_aes256_cbc_hmac_ciph == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_meth_new - AES-256-CBC " - "HMAC SHA256", we_aes256_cbc_ciph); + "HMAC SHA256", we_aes256_cbc_hmac_ciph); ret = 0; } } diff --git a/src/we_aes_ctr.c b/src/we_aes_ctr.c index 69c9eda..11ced4e 100644 --- a/src/we_aes_ctr.c +++ b/src/we_aes_ctr.c @@ -94,7 +94,7 @@ static int we_aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, rc = wc_AesSetIV(&aes->aes, iv); if (rc != 0) { WOLFENGINE_ERROR_FUNC(WE_LOG_CIPHER, "wc_AesSetIV", rc); - ret = -1; + ret = 0; } else { /* @@ -150,7 +150,7 @@ static int we_aes_ctr_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, } else { unsigned int num = EVP_CIPHER_CTX_num(ctx); - num = (num + len) % AES_128_KEY_SIZE; + num = (num + len) % WC_AES_BLOCK_SIZE; EVP_CIPHER_CTX_set_num(ctx, num); XMEMCPY(EVP_CIPHER_CTX_iv_noconst(ctx), aes->aes.reg, diff --git a/src/we_aes_gcm.c b/src/we_aes_gcm.c index 3daa8ee..5ba5c75 100644 --- a/src/we_aes_gcm.c +++ b/src/we_aes_gcm.c @@ -168,7 +168,7 @@ static int we_aes_gcm_cleanup(EVP_CIPHER_CTX *ctx) OPENSSL_free(aes->aad); } if (aes->tmp != NULL) { - OPENSSL_free(aes->tmp); + OPENSSL_clear_free(aes->tmp, aes->tmpLen); aes->tmp = NULL; } aes->tmpLen = 0; @@ -328,19 +328,19 @@ static int we_aes_gcm_update(we_AesGcm* aes, const unsigned char* in, "out = %p]", aes, in, len, out); if (len != 0 && in != NULL) { - aes->tmp = (unsigned char*)OPENSSL_malloc(len); - if (aes->tmp == NULL) { - WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "OPENSSL_malloc", - aes->tmp); + unsigned char *newTmp = (unsigned char*)OPENSSL_malloc(len); + if (newTmp == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "OPENSSL_malloc", newTmp); ret = -1; } else { - /* - * All encryption/decryption is deferred to we_aes_gcm_final. We - * just save the input data and the address of the output buffer - * here. - */ - XMEMCPY(aes->tmp, in, len); + /* Swap in the new buffer only on success so a failed allocation + * leaves the previously buffered state unchanged. */ + if (aes->tmp != NULL) { + OPENSSL_clear_free(aes->tmp, aes->tmpLen); + } + XMEMCPY(newTmp, in, len); + aes->tmp = newTmp; aes->tmpLen = (int)len; aes->outputBuf = out; /* Return length of buffered input data. */ @@ -430,7 +430,7 @@ static int we_aes_gcm_final(we_AesGcm* aes) } if (aes->tmp != NULL) { - OPENSSL_free(aes->tmp); + OPENSSL_clear_free(aes->tmp, aes->tmpLen); aes->tmp = NULL; } aes->tmpLen = 0; @@ -443,7 +443,7 @@ static int we_aes_gcm_final(we_AesGcm* aes) if (aes->ivInc) { int i; - for (i = aes->ivLen - 1; i >= aes->ivLen - 8; i--) { + for (i = aes->ivLen - 1; (i >= 0) && (i >= aes->ivLen - 8); i--) { if ((++aes->iv[i]) != 0) { break; } @@ -649,7 +649,8 @@ static int we_aes_gcm_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) * arg [in] size of generated IV/nonce * ptr [in] generated IV/nonce data */ - if ((arg <= 0) || (arg > GCM_NONCE_MAX_SZ)) { + if ((arg <= 0) || (arg > GCM_NONCE_MAX_SZ) || (ptr == NULL) || + (arg > aes->ivLen)) { XSNPRINTF(errBuff, sizeof(errBuff), "Invalid nonce length " "%d", arg); WOLFENGINE_ERROR_MSG(WE_LOG_CIPHER, errBuff); diff --git a/src/we_des3_cbc.c b/src/we_des3_cbc.c index 3942e40..efc6a2f 100644 --- a/src/we_des3_cbc.c +++ b/src/we_des3_cbc.c @@ -280,7 +280,7 @@ static int we_des3_cbc_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) /* Get the DES3-CBC data to work with. */ des3 = (we_Des3Cbc *)EVP_CIPHER_CTX_get_cipher_data(ctx); - if (des3 != NULL) { + if (des3 == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_CIPHER, "EVP_CIPHER_CTX_get_cipher_data", des3); ret = 0; diff --git a/src/we_dh.c b/src/we_dh.c index dbcfa79..92c03df 100644 --- a/src/we_dh.c +++ b/src/we_dh.c @@ -349,6 +349,8 @@ static int we_dh_generate_key_int(DH *dh, we_Dh *engineDh) unsigned int pubLen = 0; BIGNUM *privBn = NULL; BIGNUM *pubBn = NULL; + unsigned char *gBuf = NULL; + int gBufLen = 0; #ifndef WE_DH_USE_GLOBAL_RNG WC_RNG *pRng = &engineDh->rng; #else @@ -397,9 +399,6 @@ static int we_dh_generate_key_int(DH *dh, we_Dh *engineDh) if (ret == 1) { /* Check if private key already set. */ if ((privBn = (BIGNUM *)DH_get0_priv_key(dh)) != NULL) { - unsigned char *gBuf; - int gBufLen; - /* Get private key into buffer. */ privLen = BN_bn2bin(privBn, priv); /* Get generator into buffer. */ @@ -494,6 +493,9 @@ static int we_dh_generate_key_int(DH *dh, we_Dh *engineDh) if (pub != NULL) { OPENSSL_free(pub); } + if (gBuf != NULL) { + OPENSSL_free(gBuf); + } WOLFENGINE_LEAVE(WE_LOG_KE, "we_dh_generate_key_int", ret); @@ -1258,7 +1260,11 @@ static int we_dh_pkey_paramgen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) if (ret == 1) { /* Assign OpenSSL DH object to PKEY. */ - EVP_PKEY_assign_DH(pkey, dh); + if (EVP_PKEY_assign_DH(pkey, dh) != 1) { + WOLFENGINE_ERROR_FUNC(WE_LOG_KE, "EVP_PKEY_assign_DH", 0); + DH_free(dh); + ret = 0; + } } if (ret == 1) { @@ -1313,6 +1319,7 @@ static int we_dh_pkey_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) ret = EVP_PKEY_assign_DH(pkey, dh); if (ret != 1) { WOLFENGINE_ERROR_FUNC(WE_LOG_KE, "EVP_PKEY_assign_DH", ret); + DH_free(dh); } } diff --git a/src/we_digest.c b/src/we_digest.c index 6899071..ea49637 100644 --- a/src/we_digest.c +++ b/src/we_digest.c @@ -981,9 +981,15 @@ static int we_init_digest_meth(EVP_MD *method) if (ret == 1) { const int *nids; int cnt; + int maxCnt; + maxCnt = (int)(sizeof(method->required_pkey_type) / + sizeof(method->required_pkey_type[0])); cnt = we_pkey_get_nids(&nids); - XMEMCPY(method->required_pkey_type, nids, cnt); + if (cnt > maxCnt) { + cnt = maxCnt; + } + XMEMCPY(method->required_pkey_type, nids, cnt * sizeof(*nids)); method->flags |= EVP_MD_FLAG_PKEY_METHOD_SIGNATURE; } #endif diff --git a/src/we_ecc.c b/src/we_ecc.c index 8934a9e..c39bb3a 100644 --- a/src/we_ecc.c +++ b/src/we_ecc.c @@ -834,8 +834,12 @@ static int we_pkey_ecdsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, } } /* wolfSSL FIPS is not checking SEQUENCE length. */ - if ((ret == 1) && (sig[0] == 0x30)) { - size_t len; + if ((ret == 1) && ((sig == NULL) || (sigLen < 2))) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Signature too short"); + ret = -1; + } + else if ((ret == 1) && (sig[0] == 0x30)) { + size_t len = 0; int o = 1; /* Check for indefinite length - length not specified. */ @@ -846,10 +850,17 @@ static int we_pkey_ecdsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, /* Check for multi-byte length. */ else if (sig[o] > 0x80) { byte cnt = (sig[o++]) & 0x7f; - len = 0; - while ((cnt--) > 0) { - len <<= 8; - len += sig[o++]; + /* Length bytes must be present and fit in the length variable. */ + if ((cnt == 0) || (cnt > sizeof(len)) || + ((size_t)o + cnt > sigLen)) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Signature length invalid"); + ret = -1; + } + else { + while ((cnt--) > 0) { + len <<= 8; + len += sig[o++]; + } } } /* Length in byte. */ @@ -858,7 +869,7 @@ static int we_pkey_ecdsa_verify(EVP_PKEY_CTX *ctx, const unsigned char *sig, } /* Check signature length is: * SEQUENCE header length + SQUENCE data length */ - if ((ret == 1) && (o + len != sigLen)) { + if ((ret == 1) && ((size_t)o + len != sigLen)) { WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Signature length invalid"); ret = -1; } @@ -2106,14 +2117,6 @@ static ECDSA_SIG* we_ecdsa_do_sign_ex(const unsigned char *d, int dlen, } } - if (err == 0) { - rc = mp_init_multi(&sig_r, &sig_s, NULL, NULL, NULL, NULL); - if (rc != MP_OKAY) { - WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "mp_init_multi", rc); - err = 1; - } - } - /* Sign hash with ECDSA */ if (err == 0) { #if defined(WE_ECC_USE_GLOBAL_RNG) && !defined(WE_SINGLE_THREADED) diff --git a/src/we_hkdf.c b/src/we_hkdf.c index b824a01..3c7fd5e 100644 --- a/src/we_hkdf.c +++ b/src/we_hkdf.c @@ -101,7 +101,7 @@ static void we_hkdf_cleanup(EVP_PKEY_CTX *ctx) } /* Clear and free salt. */ if (hkdf->salt != NULL) { - OPENSSL_free(hkdf->salt); + OPENSSL_clear_free(hkdf->salt, hkdf->saltSz); } /* Clear info - sensitive data. */ OPENSSL_cleanse(hkdf->info, hkdf->infoSz); @@ -298,7 +298,7 @@ static int we_hkdf_ctrl(EVP_PKEY_CTX *ctx, int type, int num, void *ptr) hkdf->salt = OPENSSL_memdup(ptr, num); if (hkdf->salt == NULL) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_PK, - "OPENSSL_memdup(salt)", hkdf->key); + "OPENSSL_memdup(salt)", hkdf->salt); ret = 0; } } @@ -399,10 +399,16 @@ static int we_hkdf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, } #endif else if (XSTRNCMP(type, "md", 3) == 0) { + const EVP_MD *md = EVP_get_digestbyname(value); hkdf = (we_Hkdf *)EVP_PKEY_CTX_get_data(ctx); /* Cannot get here without initialization succeeding. */ - hkdf->mdType = - we_nid_to_wc_hash_type(EVP_MD_type(EVP_get_digestbyname(value))); + if (md == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Unsupported digest name"); + ret = 0; + } + else { + hkdf->mdType = we_nid_to_wc_hash_type(EVP_MD_type(md)); + } } else if (XSTRNCMP(type, "key", 4) == 0) { ret = EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_HKDF_KEY, value); diff --git a/src/we_internal.c b/src/we_internal.c index cd0612c..d7527d9 100644 --- a/src/we_internal.c +++ b/src/we_internal.c @@ -1148,7 +1148,8 @@ static int wolfengine_destroy(ENGINE *e) EVP_MD_meth_free(we_ecdsa_sha1_md); we_ecdsa_sha1_md = NULL; #endif -#if defined(WE_HAVE_ECC) || defined(WE_HAVE_AESGCM) || defined(WE_HAVE_RSA) +#if defined(WE_HAVE_ECC) || defined(WE_HAVE_AESGCM) || defined(WE_HAVE_RSA) || \ + defined(WE_HAVE_DH) || defined(WE_HAVE_RANDOM) we_final_random(); #endif diff --git a/src/we_logging.c b/src/we_logging.c index 96f8cd7..dc256e0 100644 --- a/src/we_logging.c +++ b/src/we_logging.c @@ -358,7 +358,7 @@ void WOLFENGINE_BUFFER(int component, const unsigned char* buffer, unsigned int length) { int i, buflen = (int)length, bufidx; - char line[(WOLFENGINE_LINE_LEN * 4) + 3]; /* \t00..0F | chars...chars\0 */ + char line[(WOLFENGINE_LINE_LEN * 4) + 4]; /* \t00..0F | chars...chars\0 */ if (!loggingEnabled) { return; @@ -386,7 +386,7 @@ void WOLFENGINE_BUFFER(int component, const unsigned char* buffer, } XSNPRINTF(&line[bufidx], sizeof(line)-bufidx, "| "); - bufidx++; + bufidx += 2; for (i = 0; i < WOLFENGINE_LINE_LEN; i++) { if (i < buflen) { diff --git a/src/we_mac.c b/src/we_mac.c index 6ee7fc4..4e50886 100644 --- a/src/we_mac.c +++ b/src/we_mac.c @@ -287,17 +287,22 @@ static int we_mac_hmac_init(EVP_PKEY_CTX *ctx, we_Mac *mac) } } if (ret == 1 && mac->keySz < blockSize) { + unsigned char *newKey; /* If the key is smaller than the block size of the underlying hash - * algorithm, we need to pad the key with zeroes to the block - * size. */ - mac->key = OPENSSL_realloc(mac->key, blockSize); - if (mac->key == NULL) { - WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "OPENSSL_realloc", - mac->key); + * algorithm, we need to pad the key with zeroes to the block size. + * Pad into a fresh buffer so the old key bytes can be wiped. */ + newKey = (unsigned char *)OPENSSL_malloc(blockSize); + if (newKey == NULL) { + WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "OPENSSL_malloc", newKey); ret = 0; } else { - XMEMSET(mac->key + mac->keySz, 0, blockSize - mac->keySz); + if (mac->keySz > 0) { + XMEMCPY(newKey, mac->key, mac->keySz); + } + XMEMSET(newKey + mac->keySz, 0, blockSize - mac->keySz); + OPENSSL_clear_free(mac->key, mac->keySz); + mac->key = newKey; mac->keySz = blockSize; } } @@ -747,7 +752,11 @@ static int we_hmac_pkey_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) } if (ret == 1) { /* Assign algorithm and key to PKEY. */ - EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, key); + if (EVP_PKEY_assign(pkey, EVP_PKEY_HMAC, key) != 1) { + WOLFENGINE_ERROR_FUNC(WE_LOG_MAC, "EVP_PKEY_assign", 0); + ASN1_OCTET_STRING_free(key); + ret = 0; + } } WOLFENGINE_LEAVE(WE_LOG_MAC, "we_hmac_pkey_keygen", ret); @@ -1314,6 +1323,10 @@ static int we_hmac_pkey_asn1_set_priv_key(EVP_PKEY *pkey, if (EVP_PKEY_get0(pkey) != NULL) { ret = 0; } + /* Reject a NULL key or a length that would not fit in an int. */ + if ((ret == 1) && ((priv == NULL) || (len > INT_MAX))) { + ret = 0; + } if (ret == 1) { /* Allocate a new ASN.1 octet string to assign to pkey. */ asn1 = ASN1_OCTET_STRING_new(); @@ -1685,8 +1698,10 @@ static int we_cmac_pkey_update(EVP_MD_CTX *ctx, const void *data, size_t dataSz) WOLFENGINE_MSG_VERBOSE(WE_LOG_MAC, "ARGS [ctx = %p, data = %p, " "dataSz = %zu]", ctx, data, dataSz); - /* Validate parameters. */ - if ((ctx == NULL) || (data == NULL)) { + /* Validate parameters. A zero-length update is a no-op (matching OpenSSL + * and the HMAC path), so a NULL data pointer is only an error when there + * is data to process. */ + if ((ctx == NULL) || ((data == NULL) && (dataSz != 0))) { WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, "we_cmac_pkey_update, ctx: ", ctx); WOLFENGINE_ERROR_FUNC_NULL(WE_LOG_MAC, @@ -1713,7 +1728,7 @@ static int we_cmac_pkey_update(EVP_MD_CTX *ctx, const void *data, size_t dataSz) } } - if (ret == 1) { + if ((ret == 1) && (dataSz != 0)) { /* Update the wolfCrypt CMAC object with more data. */ rc = wc_CmacUpdate(&mac->state.cmac, (const byte*)data, (word32)dataSz); if (rc != 0) { diff --git a/src/we_openssl_bc.c b/src/we_openssl_bc.c index 35698df..e49624b 100644 --- a/src/we_openssl_bc.c +++ b/src/we_openssl_bc.c @@ -326,11 +326,11 @@ int EC_KEY_oct2priv(EC_KEY *eckey, const unsigned char *buf, size_t len) return 0; if (EC_KEY_set_private_key(eckey, priv_key) == 0) { - BN_free(priv_key); + BN_clear_free(priv_key); return 0; } - - BN_free(priv_key); + + BN_clear_free(priv_key); return 1; } @@ -626,7 +626,7 @@ int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) dh->pub_key = pub_key; } if (priv_key != NULL) { - BN_free(dh->priv_key); + BN_clear_free(dh->priv_key); dh->priv_key = priv_key; } diff --git a/src/we_pbe.c b/src/we_pbe.c index 2388129..bf56072 100644 --- a/src/we_pbe.c +++ b/src/we_pbe.c @@ -190,6 +190,7 @@ static int we_pbkdf2_keygen(EVP_CIPHER_CTX *ctx, const char *passwd, /* Free allocated data. */ PBKDF2PARAM_free(kdf); + OPENSSL_cleanse(key, sizeof(key)); WOLFENGINE_LEAVE(WE_LOG_PBE, "we_pbkdf2_keygen", ret); @@ -395,6 +396,8 @@ static int we_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const char *passwd, OPENSSL_clear_free(uniPass, uniLen); } PBEPARAM_free(params); + OPENSSL_cleanse(key, sizeof(key)); + OPENSSL_cleanse(iv, sizeof(iv)); WOLFENGINE_LEAVE(WE_LOG_PBE, "we_pbe_keyivgen", ret); @@ -485,8 +488,9 @@ static int we_pbes2_keyivgen(EVP_CIPHER_CTX *ctx, const char *passwd, if (ret == 1) { /* Set the BER encoded encryption parameters. */ rc = EVP_CIPHER_asn1_to_param(ctx, pbe2->encryption->parameter); - if (rc < 0) { + if (rc <= 0) { WOLFENGINE_ERROR_FUNC(WE_LOG_PBE, "EVP_CIPHER_asn1_to_param", rc); + ret = 0; } } if (ret == 1) { diff --git a/src/we_random.c b/src/we_random.c index 2723951..d372c7b 100644 --- a/src/we_random.c +++ b/src/we_random.c @@ -446,4 +446,4 @@ RAND_METHOD we_rand_method ={ */ RAND_METHOD *we_random_method = &we_rand_method; -#endif /* WE_HAVE_DH */ +#endif /* WE_HAVE_RANDOM */ diff --git a/src/we_rsa.c b/src/we_rsa.c index bf5272c..2768a56 100644 --- a/src/we_rsa.c +++ b/src/we_rsa.c @@ -2032,6 +2032,7 @@ static int we_rsa_pkey_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) ret = EVP_PKEY_assign_RSA(pkey, rsa); if (ret == 0) { WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "EVP_PKEY_assign_RSA", ret); + RSA_free(rsa); } } @@ -2215,8 +2216,10 @@ static int we_rsa_pkey_ctrl(EVP_PKEY_CTX *ctx, int type, int num, void *ptr) "when padding mode isn't PSS."); ret = 0; } - /* Store salt length to use with RSA-PSS. */ - rsa->saltLen = num; + if (ret == 1) { + /* Store salt length to use with RSA-PSS. */ + rsa->saltLen = num; + } break; case EVP_PKEY_CTRL_GET_RSA_PSS_SALTLEN: WOLFENGINE_MSG(WE_LOG_PK, @@ -3127,7 +3130,18 @@ static int we_rsa_pkey_decrypt(EVP_PKEY_CTX *ctx, unsigned char *plaintext, } #endif - if (ret == 1) { + if ((ret == 1) && (plaintext == NULL)) { + /* Only return the length when no output buffer passed in. */ + rc = wc_RsaEncryptSize(&rsa->key); + if (rc < 0) { + WOLFENGINE_ERROR_FUNC(WE_LOG_PK, "wc_RsaEncryptSize", rc); + ret = 0; + } + else { + *plainLen = rc; + } + } + else if (ret == 1) { /* Perform decryption operation. */ rc = we_rsa_priv_dec_int(cipherLen, ciphertext, *plainLen, plaintext, rsa); diff --git a/src/we_tls_prf.c b/src/we_tls_prf.c index 49d0749..1019b53 100644 --- a/src/we_tls_prf.c +++ b/src/we_tls_prf.c @@ -305,8 +305,15 @@ static int we_tls1_prf_ctrl_str(EVP_PKEY_CTX *ctx, const char *type, } else if (XSTRNCMP(type, "md", 3) == 0) { we_Tls1_Prf *tls1Prf = (we_Tls1_Prf *)EVP_PKEY_CTX_get_data(ctx); + const EVP_MD *md = EVP_get_digestbyname(value); /* Cannot get here without initialization succeeding. */ - tls1Prf->mdType = EVP_MD_type(EVP_get_digestbyname(value)); + if (md == NULL) { + WOLFENGINE_ERROR_MSG(WE_LOG_PK, "Unsupported digest name"); + ret = 0; + } + else { + tls1Prf->mdType = EVP_MD_type(md); + } } else if (XSTRNCMP(type, "secret", 7) == 0) { ret = EVP_PKEY_CTX_str2ctrl(ctx, EVP_PKEY_CTRL_TLS_SECRET, value); diff --git a/test/test_aestag.c b/test/test_aestag.c index e0d409d..3cbac9b 100644 --- a/test/test_aestag.c +++ b/test/test_aestag.c @@ -727,6 +727,48 @@ int test_aes_gcm_evp_cipher(ENGINE *e, void *data) return err; } +int test_aes128_gcm_iv_gen_bounds(ENGINE *e, void *data) +{ +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + (void)e; + (void)data; + return 0; +#else + int err = 0; + EVP_CIPHER_CTX *ctx = NULL; + unsigned char key[16]; + unsigned char gen[16]; + + (void)data; + + XMEMSET(key, 0, sizeof(key)); + XMEMSET(gen, 0, sizeof(gen)); + + err = (ctx = EVP_CIPHER_CTX_new()) == NULL; + if (err == 0) { + err = EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), e, NULL, NULL) != 1; + } + if (err == 0) { + /* Set an IV length shorter than the nonce we will ask to generate. */ + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, 1, NULL) != 1; + } + if (err == 0) { + err = EVP_EncryptInit_ex(ctx, NULL, e, key, NULL) != 1; + } + if (err == 0) { + /* Generating a nonce larger than the IV length must be rejected, not + * read from before the IV buffer. */ + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_IV_GEN, 12, gen) > 0; + } + + if (ctx != NULL) { + EVP_CIPHER_CTX_free(ctx); + } + + return err; +#endif /* HAVE_FIPS || HAVE_FIPS_VERSION */ +} + #endif /* WE_HAVE_AESGCM */ /******************************************************************************/ diff --git a/test/test_cipher.c b/test/test_cipher.c index d3cc3b6..34436b2 100644 --- a/test/test_cipher.c +++ b/test/test_cipher.c @@ -481,6 +481,106 @@ int test_aes256_cbc_stream(ENGINE *e, void *data) return err; } +/******************************************************************************/ + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(HAVE_FIPS) && !defined(HAVE_FIPS_VERSION) +int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) +{ + int err = 0; + int outLen = 0; + int decLen = 0; + EVP_CIPHER_CTX *encCtx = NULL; + EVP_CIPHER_CTX *ctx = NULL; + const EVP_CIPHER *cipher = EVP_aes_128_cbc_hmac_sha256(); + unsigned char key[16]; + unsigned char macKey[SHA256_DIGEST_LENGTH]; + unsigned char iv[16]; + unsigned char zero[16]; + unsigned char record[32]; + unsigned char out[32]; + unsigned char aad[EVP_AEAD_TLS1_AAD_LEN]; + + (void)data; + + /* OpenSSL only provides the stitched AES-CBC-HMAC-SHA256 cipher on + * platforms where it has a hand-written assembly implementation (e.g. + * AES-NI x86_64); elsewhere EVP_aes_128_cbc_hmac_sha256() returns NULL, + * so there is nothing to exercise. */ + if (cipher == NULL) { + return 0; + } + + XMEMSET(key, 0, sizeof(key)); + XMEMSET(macKey, 0, sizeof(macKey)); + XMEMSET(iv, 0, sizeof(iv)); + XMEMSET(zero, 0, sizeof(zero)); + XMEMSET(out, 0, sizeof(out)); + XMEMSET(aad, 0, sizeof(aad)); + + /* Explicit IV is the first block of the record. */ + XMEMCPY(record, iv, sizeof(iv)); + + /* Craft a single ciphertext block that decrypts to all zeros so the + * recovered pad byte is 0 and the padding check passes. */ + err = (encCtx = EVP_CIPHER_CTX_new()) == NULL; + if (err == 0) { + err = EVP_EncryptInit_ex(encCtx, EVP_aes_128_cbc(), NULL, key, iv) != 1; + } + if (err == 0) { + err = EVP_CIPHER_CTX_set_padding(encCtx, 0) != 1; + } + if (err == 0) { + err = EVP_EncryptUpdate(encCtx, record + 16, &outLen, zero, + sizeof(zero)) != 1; + } + EVP_CIPHER_CTX_free(encCtx); + + /* TLS 1.2 record header so the stitched cipher takes the explicit-IV + * path. */ + aad[9] = (unsigned char)(TLS1_2_VERSION >> 8); + aad[10] = (unsigned char)(TLS1_2_VERSION); + aad[11] = 0; + aad[12] = 16; + + if (err == 0) { + err = (ctx = EVP_CIPHER_CTX_new()) == NULL; + } + if (err == 0) { + err = EVP_DecryptInit_ex(ctx, cipher, e, key, iv) != 1; + } + if (err == 0) { + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_MAC_KEY, + sizeof(macKey), macKey) != 1; + } + if (err == 0) { + err = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_TLS1_AAD, + EVP_AEAD_TLS1_AAD_LEN, aad) + != SHA256_DIGEST_LENGTH; + } + if (err == 0) { + /* Undersized, block-aligned record: explicit IV plus a single block, + * which is smaller than IV + pad + MAC. The engine must reject it and + * must not underflow the record length. */ + decLen = EVP_Cipher(ctx, out, record, sizeof(record)); + err = (decLen > 0); + } + + EVP_CIPHER_CTX_free(ctx); + + return err; +} +#else +int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data) +{ + /* Stitched AES-CBC-HMAC is not a FIPS-validated cipher, so this path is + * not exercised under FIPS. */ + (void)e; + (void)data; + return 0; +} +#endif + #endif /* WE_HAVE_AESCBC */ /******************************************************************************/ diff --git a/test/test_hkdf.c b/test/test_hkdf.c index 86bd524..dcfb09a 100644 --- a/test/test_hkdf.c +++ b/test/test_hkdf.c @@ -453,6 +453,34 @@ int test_hkdf(ENGINE *e, void *data) return err; } +int test_hkdf_bad_md(ENGINE *e, void *data) +{ +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + (void)e; + (void)data; + return 0; +#else + int err = 0; + EVP_PKEY_CTX *ctx = NULL; + + (void)data; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, e); + err = ctx == NULL; + if (err == 0) { + err = EVP_PKEY_derive_init(ctx) != 1; + } + if (err == 0) { + /* Unknown digest name must fail, not dereference a NULL digest. */ + err = EVP_PKEY_CTX_ctrl_str(ctx, "md", "notadigest") > 0; + } + + EVP_PKEY_CTX_free(ctx); + + return err; +#endif +} + #endif /* WE_HAVE_HKDF */ diff --git a/test/test_rsa.c b/test/test_rsa.c index 255513c..eb0d0eb 100644 --- a/test/test_rsa.c +++ b/test/test_rsa.c @@ -1188,6 +1188,54 @@ int test_rsa_enc_dec_no_pad(ENGINE *e, void *data) RSA_NO_PADDING, NULL, NULL); } +int test_rsa_dec_no_pad_size_query(ENGINE *e, void *data) +{ +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + /* RSA_NO_PADDING with a sub-2048-bit key is not a FIPS-approved path. */ + (void)e; + (void)data; + return 0; +#else + int err = 0; + EVP_PKEY *pkey = NULL; + EVP_PKEY_CTX *ctx = NULL; + const unsigned char *der = rsa_key_der_1024; + unsigned char ct[128]; + size_t ctLen = sizeof(ct); + size_t outLen = 0; + + (void)data; + + XMEMSET(ct, 0, sizeof(ct)); + + pkey = d2i_PrivateKey(EVP_PKEY_RSA, NULL, &der, + (long)sizeof(rsa_key_der_1024)); + err = pkey == NULL; + if (err == 0) { + err = (ctx = EVP_PKEY_CTX_new(pkey, e)) == NULL; + } + if (err == 0) { + err = EVP_PKEY_decrypt_init(ctx) != 1; + } + if (err == 0) { + err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0; + } + if (err == 0) { + /* NULL output is a length query: must return the RSA output size and + * succeed, not hand a NULL buffer to wolfCrypt. */ + err = EVP_PKEY_decrypt(ctx, NULL, &outLen, ct, ctLen) != 1; + } + if (err == 0) { + err = outLen != (size_t)EVP_PKEY_size(pkey); + } + + EVP_PKEY_CTX_free(ctx); + EVP_PKEY_free(pkey); + + return err; +#endif /* HAVE_FIPS || HAVE_FIPS_VERSION */ +} + int test_rsa_enc_dec_oaep(ENGINE *e, void *data) { int err = 0; diff --git a/test/test_tls1_prf.c b/test/test_tls1_prf.c index b853431..7ecf943 100644 --- a/test/test_tls1_prf.c +++ b/test/test_tls1_prf.c @@ -383,6 +383,34 @@ int test_tls1_prf(ENGINE *e, void *data) return err; } +int test_tls1_prf_bad_md(ENGINE *e, void *data) +{ +#if defined(HAVE_FIPS) || defined(HAVE_FIPS_VERSION) + (void)e; + (void)data; + return 0; +#else + int err = 0; + EVP_PKEY_CTX *ctx = NULL; + + (void)data; + + ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, e); + err = ctx == NULL; + if (err == 0) { + err = EVP_PKEY_derive_init(ctx) != 1; + } + if (err == 0) { + /* Unknown digest name must fail, not dereference a NULL digest. */ + err = EVP_PKEY_CTX_ctrl_str(ctx, "md", "notadigest") > 0; + } + + EVP_PKEY_CTX_free(ctx); + + return err; +#endif +} + #endif /* WE_HAVE_TLS1_PRF */ diff --git a/test/unit.c b/test/unit.c index aad13f9..8f7c52e 100644 --- a/test/unit.c +++ b/test/unit.c @@ -89,9 +89,11 @@ TEST_CASE test_case[] = { #endif #ifdef WE_HAVE_TLS1_PRF TEST_DECL(test_tls1_prf, NULL), + TEST_DECL(test_tls1_prf_bad_md, NULL), #endif #ifdef WE_HAVE_HKDF TEST_DECL(test_hkdf, NULL), + TEST_DECL(test_hkdf_bad_md, NULL), #endif #ifdef WE_HAVE_DES3CBC TEST_DECL(test_des3_cbc, NULL), @@ -112,6 +114,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_aes128_cbc_stream, NULL), TEST_DECL(test_aes192_cbc_stream, NULL), TEST_DECL(test_aes256_cbc_stream, NULL), + TEST_DECL(test_aes128_cbc_hmac_tls_short, NULL), #endif #ifdef WE_HAVE_AESCTR TEST_DECL(test_aes128_ctr_stream, NULL), @@ -127,6 +130,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_aes128_gcm_fixed, NULL), TEST_DECL(test_aes128_gcm_tls, NULL), TEST_DECL(test_aes_gcm_evp_cipher, NULL), + TEST_DECL(test_aes128_gcm_iv_gen_bounds, NULL), #endif #ifdef WE_HAVE_AESCCM TEST_DECL(test_aes128_ccm, NULL), @@ -186,6 +190,7 @@ TEST_CASE test_case[] = { TEST_DECL(test_rsa_sign_verify_pss, NULL), TEST_DECL(test_rsa_enc_dec_pkcs1, NULL), TEST_DECL(test_rsa_enc_dec_no_pad, NULL), + TEST_DECL(test_rsa_dec_no_pad_size_query, NULL), TEST_DECL(test_rsa_enc_dec_oaep, NULL), TEST_DECL(test_rsa_pkey_keygen, NULL), TEST_DECL(test_rsa_pkey_invalid_key_size, NULL), diff --git a/test/unit.h b/test/unit.h index 9e7b5e4..9068e7d 100644 --- a/test/unit.h +++ b/test/unit.h @@ -118,10 +118,12 @@ int test_hmac_create(ENGINE *e, void *data); #ifdef WE_HAVE_TLS1_PRF int test_tls1_prf(ENGINE *e, void *data); +int test_tls1_prf_bad_md(ENGINE *e, void *data); #endif #ifdef WE_HAVE_HKDF int test_hkdf(ENGINE *e, void *data); +int test_hkdf_bad_md(ENGINE *e, void *data); #endif #ifdef WE_HAVE_DES3CBC @@ -148,6 +150,7 @@ int test_aes256_cbc(ENGINE *e, void *data); int test_aes128_cbc_stream(ENGINE *e, void *data); int test_aes192_cbc_stream(ENGINE *e, void *data); int test_aes256_cbc_stream(ENGINE *e, void *data); +int test_aes128_cbc_hmac_tls_short(ENGINE *e, void *data); #endif @@ -170,6 +173,7 @@ int test_aes256_gcm(ENGINE *e, void *data); int test_aes128_gcm_fixed(ENGINE *e, void *data); int test_aes128_gcm_tls(ENGINE *e, void *data); int test_aes_gcm_evp_cipher(ENGINE *e, void *data); +int test_aes128_gcm_iv_gen_bounds(ENGINE *e, void *data); #endif /* WE_HAVE_AESGCM */ @@ -236,6 +240,7 @@ int test_rsa_sign_verify_no_pad(ENGINE *e, void *data); int test_rsa_sign_verify_pss(ENGINE *e, void *data); int test_rsa_enc_dec_pkcs1(ENGINE *e, void *data); int test_rsa_enc_dec_no_pad(ENGINE *e, void *data); +int test_rsa_dec_no_pad_size_query(ENGINE *e, void *data); int test_rsa_enc_dec_oaep(ENGINE *e, void *data); int test_rsa_pkey_keygen(ENGINE *e, void *data); int test_rsa_pkey_invalid_key_size(ENGINE *e, void *data);