Skip to content

Commit

Permalink
Migrate from deprecated OpenSSL SHA256_* APIs to EVP APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
Alami-Amine committed Nov 6, 2024
1 parent 4fce9b9 commit 4ff3187
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 18 deletions.
3 changes: 3 additions & 0 deletions src/crypto/CHIPCryptoPAL.h
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,9 @@ class Hash_SHA256_stream

private:
HashSHA256OpaqueContext mContext;
#if CHIP_CRYPTO_BORINGSSL || CHIP_CRYPTO_OPENSSL
bool mInitialized = false;
#endif
};

class HKDF_sha
Expand Down
83 changes: 65 additions & 18 deletions src/crypto/CHIPCryptoPALOpenSSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,71 +433,116 @@ CHIP_ERROR Hash_SHA1(const uint8_t * data, const size_t data_length, uint8_t * o
return CHIP_NO_ERROR;
}

Hash_SHA256_stream::Hash_SHA256_stream() {}
// For OpenSSL, we store a pointer to the digest context (EVP_MD_CTX) since EVP_MD_CTX is Opaque.
static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(void *),
"kMAX_Hash_SHA256_Context_Size needs to at least be able to store a pointer");

Hash_SHA256_stream::~Hash_SHA256_stream()
// Storing a pointer to EVP_MD_CTX in HashSHA256OpaqueContext instead of the actual EVP_MD_CTX structure, as EVP_MD_CTX was made
// opaque by OpenSSL and is dynamically allocated.
static inline void set_inner_hash_evp_md_ctx(HashSHA256OpaqueContext * context, EVP_MD_CTX * evp_ctx)
{
Clear();
*SafePointerCast<EVP_MD_CTX **>(context) = evp_ctx;
}

static_assert(kMAX_Hash_SHA256_Context_Size >= sizeof(SHA256_CTX),
"kMAX_Hash_SHA256_Context_Size is too small for the size of underlying SHA256_CTX");
static inline EVP_MD_CTX * to_inner_hash_evp_md_ctx(HashSHA256OpaqueContext * context)
{
return *SafePointerCast<EVP_MD_CTX **>(context);
}

static inline SHA256_CTX * to_inner_hash_sha256_context(HashSHA256OpaqueContext * context)
Hash_SHA256_stream::Hash_SHA256_stream()
{
return SafePointerCast<SHA256_CTX *>(context);
set_inner_hash_evp_md_ctx(&mContext, nullptr);
mInitialized = false;
}

Hash_SHA256_stream::~Hash_SHA256_stream()
{
Clear();
}

CHIP_ERROR Hash_SHA256_stream::Begin()
{
SHA256_CTX * const context = to_inner_hash_sha256_context(&mContext);

const int result = SHA256_Init(context);
EVP_MD_CTX * mdctx = EVP_MD_CTX_new();
VerifyOrReturnError(mdctx != nullptr, CHIP_ERROR_INTERNAL);

set_inner_hash_evp_md_ctx(&mContext, mdctx);

const int result = EVP_DigestInit_ex(mdctx, _digestForType(DigestType::SHA256), nullptr);

VerifyOrReturnError(result == 1, CHIP_ERROR_INTERNAL);
mInitialized = true;

return CHIP_NO_ERROR;
}

CHIP_ERROR Hash_SHA256_stream::AddData(const ByteSpan data)
{
SHA256_CTX * const context = to_inner_hash_sha256_context(&mContext);
VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED);

EVP_MD_CTX * mdctx = to_inner_hash_evp_md_ctx(&mContext);
VerifyOrReturnError(mdctx != nullptr, CHIP_ERROR_INTERNAL);

const int result = EVP_DigestUpdate(mdctx, data.data(), data.size());

const int result = SHA256_Update(context, Uint8::to_const_uchar(data.data()), data.size());
VerifyOrReturnError(result == 1, CHIP_ERROR_INTERNAL);

return CHIP_NO_ERROR;
}

CHIP_ERROR Hash_SHA256_stream::GetDigest(MutableByteSpan & out_buffer)
{
SHA256_CTX * context = to_inner_hash_sha256_context(&mContext);

// Back-up context as we are about to finalize the hash to extract digest.
SHA256_CTX previous_ctx = *context;
VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED);

EVP_MD_CTX * mdctx = to_inner_hash_evp_md_ctx(&mContext);

// Back-up the context as we are about to finalize the hash to extract digest.
EVP_MD_CTX * previous_mdctx = EVP_MD_CTX_new();
VerifyOrReturnError(previous_mdctx != nullptr, CHIP_ERROR_INTERNAL);
const int copy_result = EVP_MD_CTX_copy_ex(previous_mdctx, mdctx);
VerifyOrReturnError(copy_result == 1, CHIP_ERROR_INTERNAL);

// Pad + compute digest, then finalize context. It is restored next line to continue.
CHIP_ERROR result = Finish(out_buffer);

// Restore context prior to finalization.
*context = previous_ctx;
// free the finalized context.
EVP_MD_CTX_free(mdctx);

// Restore the backed up context, to be able to get intermediate digest again if needed
set_inner_hash_evp_md_ctx(&mContext, previous_mdctx);

return result;
}

CHIP_ERROR Hash_SHA256_stream::Finish(MutableByteSpan & out_buffer)
{
unsigned int size;

VerifyOrReturnError(out_buffer.size() >= kSHA256_Hash_Length, CHIP_ERROR_BUFFER_TOO_SMALL);
VerifyOrReturnError(mInitialized, CHIP_ERROR_UNINITIALIZED);

EVP_MD_CTX * mdctx = to_inner_hash_evp_md_ctx(&mContext);

const int result = EVP_DigestFinal_ex(mdctx, out_buffer.data(), &size);

SHA256_CTX * const context = to_inner_hash_sha256_context(&mContext);
const int result = SHA256_Final(Uint8::to_uchar(out_buffer.data()), context);
VerifyOrReturnError(result == 1, CHIP_ERROR_INTERNAL);
VerifyOrReturnError(size == kSHA256_Hash_Length, CHIP_ERROR_INTERNAL);

out_buffer = out_buffer.SubSpan(0, kSHA256_Hash_Length);

return CHIP_NO_ERROR;
}

void Hash_SHA256_stream::Clear()
{
EVP_MD_CTX * mdctx = to_inner_hash_evp_md_ctx(&mContext);
if (mdctx != nullptr)
{
EVP_MD_CTX_free(mdctx);
set_inner_hash_evp_md_ctx(&mContext, nullptr);
mInitialized = false;
}
OPENSSL_cleanse(this, sizeof(*this));
}

Expand Down Expand Up @@ -1405,6 +1450,8 @@ void Spake2p_P256_SHA256_HKDF_HMAC::Clear()
BN_CTX_free(context->bn_ctx);
}

sha256_hash_ctx.Clear();

free_point(M);
free_point(N);
free_point(X);
Expand Down

0 comments on commit 4ff3187

Please sign in to comment.