-
Notifications
You must be signed in to change notification settings - Fork 115
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
36e0307
commit 1b1e2f6
Showing
4 changed files
with
414 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 OR ISC | ||
|
||
#include <gtest/gtest.h> | ||
|
||
#include <openssl/bio.h> | ||
#include <openssl/bytestring.h> | ||
#include <openssl/rand.h> | ||
#include <openssl/x509.h> | ||
|
||
#include "../../test/test_util.h" | ||
#include "../internal.h" | ||
|
||
struct MessageDigestParams { | ||
const char name[40]; | ||
const EVP_MD *(*md)(void); | ||
}; | ||
|
||
static const struct MessageDigestParams MessageDigests[] = { | ||
{"MD5", EVP_md5}, | ||
{"SHA1", EVP_sha1}, | ||
{"SHA224", EVP_sha224}, | ||
{"SHA256", EVP_sha256}, | ||
{"SHA284", EVP_sha384}, | ||
{"SHA512", EVP_sha512}, | ||
{"SHA512_224", EVP_sha512_224}, | ||
{"SHA512_256", EVP_sha512_256}, | ||
{"SHA3_224", EVP_sha3_224}, | ||
{"SHA3_256", EVP_sha3_256}, | ||
{"SHA3_384", EVP_sha3_384}, | ||
{"SHA3_512", EVP_sha3_512}, | ||
}; | ||
|
||
class BIODeprecatedTest : public testing::TestWithParam<MessageDigestParams> {}; | ||
|
||
INSTANTIATE_TEST_SUITE_P( | ||
PKCS7Test, BIODeprecatedTest, testing::ValuesIn(MessageDigests), | ||
[](const testing::TestParamInfo<MessageDigestParams> ¶ms) | ||
-> std::string { return params.param.name; }); | ||
|
||
TEST_P(BIODeprecatedTest, MessageDigestBasic) { | ||
uint8_t message[1024 * 8]; | ||
uint8_t buf[16 * 1024]; | ||
std::vector<uint8_t> message_vec; | ||
std::vector<uint8_t> buf_vec; | ||
bssl::UniquePtr<BIO> bio; | ||
bssl::UniquePtr<BIO> bio_md; | ||
bssl::UniquePtr<BIO> bio_mem; | ||
bssl::UniquePtr<EVP_MD_CTX> ctx; | ||
|
||
OPENSSL_memset(message, 'A', sizeof(message)); | ||
OPENSSL_memset(buf, '\0', sizeof(buf)); | ||
|
||
const EVP_MD *md = GetParam().md(); | ||
ASSERT_TRUE(md); | ||
|
||
// Simple initialization and error cases | ||
bio_md.reset(BIO_new(BIO_f_md())); | ||
ASSERT_TRUE(bio_md); | ||
EXPECT_FALSE(BIO_reset(bio_md.get())); | ||
EXPECT_TRUE(BIO_set_md(bio_md.get(), (EVP_MD *)md)); | ||
EVP_MD_CTX *ctx_tmp; // |bio_md| owns the context, we just take a ref here | ||
EXPECT_TRUE(BIO_get_md_ctx(bio_md.get(), &ctx_tmp)); | ||
EXPECT_EQ(EVP_MD_type(md), EVP_MD_CTX_type(ctx_tmp)); | ||
EXPECT_EQ(md, EVP_MD_CTX_md(ctx_tmp)); // for static *EVP_MD_CTX, ptrs equal | ||
EXPECT_FALSE(BIO_ctrl(bio_md.get(), BIO_C_GET_MD, 0, nullptr)); | ||
EXPECT_FALSE(BIO_ctrl(bio_md.get(), BIO_C_SET_MD_CTX, 0, nullptr)); | ||
EXPECT_FALSE(BIO_ctrl(bio_md.get(), BIO_C_DO_STATE_MACHINE, 0, nullptr)); | ||
EXPECT_FALSE(BIO_ctrl(bio_md.get(), BIO_CTRL_DUP, 0, nullptr)); | ||
EXPECT_FALSE(BIO_ctrl(bio_md.get(), BIO_CTRL_GET_CALLBACK, 0, nullptr)); | ||
EXPECT_FALSE(BIO_ctrl(bio_md.get(), BIO_CTRL_SET_CALLBACK, 0, nullptr)); | ||
EXPECT_FALSE(BIO_read(bio_md.get(), buf, 0)); | ||
EXPECT_FALSE(BIO_write(bio_md.get(), buf, 0)); | ||
EXPECT_EQ(0UL, BIO_number_read(bio_md.get())); | ||
EXPECT_EQ(0UL, BIO_number_written(bio_md.get())); | ||
EXPECT_FALSE(BIO_gets(bio_md.get(), (char *)buf, EVP_MD_size(md) - 1)); | ||
|
||
// Write-through digest BIO | ||
bio_md.reset(BIO_new(BIO_f_md())); | ||
ASSERT_TRUE(bio_md); | ||
EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); | ||
bio_mem.reset(BIO_new(BIO_s_mem())); | ||
ASSERT_TRUE(bio_mem); | ||
bio.reset(BIO_push(bio_md.get(), bio_mem.get())); | ||
ASSERT_TRUE(bio); | ||
EXPECT_TRUE(BIO_write(bio.get(), message, sizeof(message))); | ||
unsigned digest_len = BIO_gets(bio_md.get(), (char *)buf, sizeof(buf)); | ||
buf_vec.clear(); | ||
buf_vec.insert(buf_vec.begin(), buf, buf + digest_len); | ||
OPENSSL_memset(buf, '\0', sizeof(buf)); | ||
message_vec.clear(); | ||
int rsize; | ||
while ((rsize = BIO_read(bio_mem.get(), buf, sizeof(buf))) > 0) { | ||
message_vec.insert(message_vec.end(), buf, buf + rsize); | ||
} | ||
ctx.reset(EVP_MD_CTX_new()); | ||
ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), md, NULL)); | ||
ASSERT_TRUE( | ||
EVP_DigestUpdate(ctx.get(), message_vec.data(), message_vec.size())); | ||
ASSERT_TRUE(EVP_DigestFinal_ex(ctx.get(), buf, &digest_len)); | ||
EXPECT_EQ(Bytes(buf_vec.data(), buf_vec.size()), Bytes(buf, digest_len)); | ||
bio_md.release(); // |bio| took ownership | ||
bio_mem.release(); // |bio| took ownership | ||
|
||
// Read-through digest BIO | ||
bio_md.reset(BIO_new(BIO_f_md())); | ||
ASSERT_TRUE(bio_md); | ||
EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); | ||
bio_mem.reset(BIO_new_mem_buf(message, sizeof(message))); | ||
ASSERT_TRUE(bio_mem); | ||
bio.reset(BIO_push(bio_md.get(), bio_mem.get())); | ||
ASSERT_TRUE(bio); | ||
message_vec.clear(); | ||
OPENSSL_memset(buf, '\0', sizeof(buf)); | ||
while ((rsize = BIO_read(bio.get(), buf, sizeof(buf))) > 0) { | ||
message_vec.insert(message_vec.begin(), buf, buf + rsize); | ||
} | ||
EXPECT_EQ(Bytes(message_vec.data(), message_vec.size()), | ||
Bytes(message, sizeof(message))); | ||
digest_len = BIO_gets(bio_md.get(), (char *)buf, sizeof(buf)); | ||
buf_vec.clear(); | ||
buf_vec.insert(buf_vec.begin(), buf, buf + digest_len); | ||
ctx.reset(EVP_MD_CTX_new()); | ||
ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), md, NULL)); | ||
ASSERT_TRUE( | ||
EVP_DigestUpdate(ctx.get(), message_vec.data(), message_vec.size())); | ||
ASSERT_TRUE(EVP_DigestFinal_ex(ctx.get(), buf, &digest_len)); | ||
EXPECT_EQ(Bytes(buf, digest_len), Bytes(buf_vec.data(), buf_vec.size())); | ||
EXPECT_EQ(Bytes(buf_vec.data(), buf_vec.size()), Bytes(buf, digest_len)); | ||
// Resetting |bio_md| should reset digest state, elicit different digest | ||
// output | ||
EXPECT_TRUE(BIO_reset(bio.get())); | ||
digest_len = BIO_gets(bio_md.get(), (char *)buf, sizeof(buf)); | ||
EXPECT_NE(Bytes(buf_vec.data(), buf_vec.size()), Bytes(buf, digest_len)); | ||
bio_md.release(); // |bio| took ownership | ||
bio_mem.release(); // |bio| took ownership | ||
} | ||
|
||
TEST_P(BIODeprecatedTest, MessageDigestRandomized) { | ||
uint8_t message_buf[8 * 1024]; | ||
uint8_t digest_buf[EVP_MAX_MD_SIZE]; | ||
std::vector<uint8_t> message; | ||
std::vector<uint8_t> expected_digest; | ||
bssl::UniquePtr<BIO> bio; | ||
bssl::UniquePtr<BIO> bio_md; | ||
bssl::UniquePtr<BIO> bio_mem; | ||
bssl::UniquePtr<EVP_MD_CTX> ctx; | ||
|
||
const EVP_MD *md = GetParam().md(); | ||
ASSERT_TRUE(md); | ||
|
||
const size_t block_size = EVP_MD_block_size(md); | ||
std::vector<std::vector<size_t>> io_patterns = { | ||
{}, | ||
{0}, | ||
{1}, | ||
{8, 8, 8, 8}, | ||
{block_size - 1, 1, block_size + 1, block_size, block_size - 1}, | ||
{4, 1, 5, 3, 2, 0, 1, sizeof(message_buf), 133, 4555, 22, 4, 7964, 1234}, | ||
}; | ||
|
||
for (auto io_pattern : io_patterns) { | ||
message.clear(); | ||
expected_digest.clear(); | ||
ctx.reset(EVP_MD_CTX_new()); | ||
EVP_DigestInit_ex(ctx.get(), md, NULL); | ||
// Construct overall message and its expected expected_digest | ||
for (auto io_size : io_pattern) { | ||
ASSERT_LE(io_size, sizeof(message_buf)); | ||
RAND_bytes(message_buf, io_size); | ||
message.insert(message.end(), &message_buf[0], &message_buf[io_size]); | ||
} | ||
EVP_DigestUpdate(ctx.get(), message.data(), message.size()); | ||
unsigned digest_size; | ||
EVP_DigestFinal_ex(ctx.get(), digest_buf, &digest_size); | ||
ASSERT_EQ(EVP_MD_CTX_size(ctx.get()), digest_size); | ||
expected_digest.insert(expected_digest.begin(), &digest_buf[0], | ||
&digest_buf[digest_size]); | ||
OPENSSL_cleanse(digest_buf, sizeof(digest_buf)); | ||
|
||
// Write-through digest BIO, check against expectation | ||
bio_md.reset(BIO_new(BIO_f_md())); | ||
ASSERT_TRUE(bio_md); | ||
EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); | ||
bio_mem.reset(BIO_new(BIO_s_mem())); | ||
ASSERT_TRUE(bio_mem); | ||
bio.reset(BIO_push(bio_md.get(), bio_mem.get())); | ||
ASSERT_TRUE(bio); | ||
int pos = 0; | ||
for (auto io_size : io_pattern) { | ||
int wsize = BIO_write(bio.get(), (char *)(message.data() + pos), io_size); | ||
EXPECT_EQ((int)io_size, wsize); | ||
pos += io_size; | ||
} | ||
digest_size = | ||
BIO_gets(bio_md.get(), (char *)digest_buf, sizeof(digest_buf)); | ||
ASSERT_EQ(EVP_MD_CTX_size(ctx.get()), digest_size); | ||
EXPECT_EQ(Bytes(expected_digest.data(), expected_digest.size()), | ||
Bytes(digest_buf, digest_size)); | ||
OPENSSL_cleanse(digest_buf, sizeof(digest_buf)); | ||
bio_md.release(); // |bio| took ownership | ||
bio_mem.release(); // |bio| took ownership | ||
|
||
// Read-through digest BIO, check against expectation | ||
bio_md.reset(BIO_new(BIO_f_md())); | ||
ASSERT_TRUE(bio_md); | ||
EXPECT_TRUE(BIO_set_md(bio_md.get(), (void *)md)); | ||
bio_mem.reset(BIO_new_mem_buf(message.data(), message.size())); | ||
ASSERT_TRUE(bio_mem); | ||
bio.reset(BIO_push(bio_md.get(), bio_mem.get())); | ||
ASSERT_TRUE(bio); | ||
for (auto io_size : io_pattern) { | ||
int rsize = BIO_read(bio.get(), message_buf, io_size); | ||
EXPECT_EQ((int)io_size, rsize); | ||
} | ||
EXPECT_TRUE(BIO_eof(bio.get())); | ||
digest_size = | ||
BIO_gets(bio_md.get(), (char *)digest_buf, sizeof(digest_buf)); | ||
ASSERT_EQ(EVP_MD_CTX_size(ctx.get()), digest_size); | ||
EXPECT_EQ(Bytes(expected_digest.data(), expected_digest.size()), | ||
Bytes(digest_buf, digest_size)); | ||
OPENSSL_cleanse(digest_buf, sizeof(digest_buf)); | ||
bio_md.release(); // |bio| took ownership | ||
bio_mem.release(); // |bio| took ownership | ||
} | ||
} |
Oops, something went wrong.