Skip to content

Commit

Permalink
tmp: add additional tests, work out read failure inducement
Browse files Browse the repository at this point in the history
  • Loading branch information
WillChilds-Klein committed Sep 11, 2024
1 parent a7e3d1a commit e85e166
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 19 deletions.
76 changes: 57 additions & 19 deletions crypto/pkcs7/pkcs7_internal_bio_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ TEST(PKCS7Test, CipherBIO) {
ASSERT_TRUE(bio_mem);
ASSERT_TRUE(BIO_push(bio_cipher.get(), bio_mem.get()));
std::vector<uint8_t> pt_vec, ct_vec, decrypted_pt_vec;
uint8_t buff[1024*1024];
for (size_t wsize : (size_t[]){1, 3, 7, 8, 64, 7, 0, 923, sizeof(buff), 1, 8}) {
ASSERT_TRUE(RAND_bytes(buff, wsize));
uint8_t buff[1024 * 1024];
ASSERT_TRUE(RAND_bytes(buff, sizeof(buff)));
for (size_t wsize :
(size_t[]){1, 3, 7, 8, 64, 7, 0, 923, sizeof(buff), 1, 8}) {
pt_vec.insert(pt_vec.end(), buff, buff + wsize);
EXPECT_TRUE(BIO_write(bio_cipher.get(), buff, wsize) || wsize == 0);
}
Expand All @@ -136,55 +137,92 @@ TEST(PKCS7Test, CipherBIO) {
ct_vec.insert(ct_vec.end(), buff, buff + bytes_read);
}
EXPECT_TRUE(BIO_reset(bio_cipher.get())); // also resets owned |bio_mem|
EXPECT_TRUE(BIO_write(bio_mem.get(), ct_vec.data(), ct_vec.size())); // replace ct
EXPECT_TRUE(
BIO_write(bio_mem.get(), ct_vec.data(), ct_vec.size())); // replace ct
bio_mem.release(); // |bio_cipher| took ownership
EXPECT_TRUE(BIO_get_cipher_ctx(bio_cipher.get(), &ctx));
ASSERT_TRUE(
EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv, /*enc*/ 0));
decrypted_pt_vec.resize(pt_vec.size());
// TODO [childw] variable read sizes?
EXPECT_TRUE(BIO_read(bio_cipher.get(), decrypted_pt_vec.data(), decrypted_pt_vec.size()));
for (size_t rsize :
(size_t[]){1, 3, 7, 8, 64, 7, 0, 923, sizeof(buff), 1, 8}) {
EXPECT_TRUE(BIO_read(bio_cipher.get(), buff, rsize) || rsize == 0);
decrypted_pt_vec.insert(decrypted_pt_vec.end(), buff, buff + rsize);
}
EXPECT_TRUE(BIO_get_cipher_status(bio_cipher.get()));
EXPECT_EQ(pt_vec.size(), decrypted_pt_vec.size());
EXPECT_EQ(Bytes(pt_vec.data(), pt_vec.size()),
Bytes(decrypted_pt_vec.data(), decrypted_pt_vec.size()));

// TODO [childw] explain induce write failure
pt_vec.clear();
ct_vec.clear();
decrypted_pt_vec.clear();
bio_cipher.reset(BIO_new(BIO_f_cipher()));
ASSERT_TRUE(bio_cipher);
EXPECT_TRUE(BIO_get_cipher_ctx(bio_cipher.get(), &ctx));
ASSERT_TRUE(
EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv, /*enc*/ 1));
bio_mem.reset(BIO_new(BIO_s_mem()));
bio_mem.reset(BIO_new(BIO_s_mock()));
ASSERT_TRUE(bio_mem);
ASSERT_TRUE(BIO_push(bio_cipher.get(), bio_mem.get()));
const int wsize = 16;
pt_vec.insert(pt_vec.end(), buff, buff + wsize);
EXPECT_TRUE(BIO_write(bio_cipher.get(), buff, wsize));
const int io_size = 64;
pt_vec.insert(pt_vec.end(), buff, buff + io_size);
EXPECT_EQ(io_size, BIO_write(bio_cipher.get(), buff, io_size));
// |bio_mem| is writeable, so shouldn't have any buffered data
EXPECT_EQ(0UL, BIO_wpending(bio_cipher.get()));
// Set underlying BIO to r/o to induce buffering in |bio_cipher|
BIO_set_flags(bio_mem.get(), BIO_FLAGS_MEM_RDONLY);
pt_vec.insert(pt_vec.end(), buff, buff + wsize);
EXPECT_TRUE(BIO_write(bio_cipher.get(), buff, wsize));
pt_vec.insert(pt_vec.end(), buff, buff + io_size);
// Write to |bio_cipher| should still succeed while it can buffer
EXPECT_LT(0, BIO_write(bio_cipher.get(), buff, io_size));
BIO_clear_flags(bio_mem.get(), BIO_FLAGS_MEM_RDONLY);
// Now that we there's buffered data, |BIO_wpending| should be positive
EXPECT_LT(0UL, BIO_wpending(bio_cipher.get()));
EXPECT_TRUE(BIO_flush(bio_cipher.get()));
// Flush should empty the buffered data
EXPECT_EQ(0UL, BIO_wpending(bio_cipher.get()));
EXPECT_TRUE(BIO_get_cipher_status(bio_cipher.get()));
EXPECT_TRUE(BIO_get_cipher_ctx(bio_cipher.get(), &ctx));

// TODO [childw] reset BIOs before testing read failures?
while (!BIO_eof(bio_mem.get())) {
size_t bytes_read = BIO_read(bio_mem.get(), buff, sizeof(buff));
ct_vec.insert(ct_vec.end(), buff, buff + bytes_read);
}
EXPECT_TRUE(BIO_reset(bio_cipher.get())); // also resets owned |bio_mem|
EXPECT_TRUE(
BIO_write(bio_mem.get(), ct_vec.data(), ct_vec.size())); // replace ct
auto disable_reads = [](BIO *bio, int oper, const char *argp, size_t len,
int argi, long argl, int bio_ret,
size_t *processed) -> long {
return !(oper & BIO_CB_RETURN) && (oper & BIO_CB_READ);
};
ASSERT_TRUE(
EVP_CipherInit_ex(ctx, EVP_aes_128_gcm(), NULL, key, iv, /*enc*/ 0));
decrypted_pt_vec.resize(pt_vec.size());
// Must seek back to beginning of file before reading
ASSERT_EQ(0, BIO_seek(bio_mem.get(), 0)); // 0 indicates success here
EXPECT_TRUE(BIO_read(bio_cipher.get(), decrypted_pt_vec.data(), decrypted_pt_vec.size()));
EXPECT_EQ(decrypted_pt_vec.size(), BIO_pending(bio_cipher.get()));
//BIO_set_callback_ex(bio_mem.get(), disable_reads);
//EXPECT_EQ(0, BIO_read(bio_cipher.get(), decrypted_pt_vec.data() + io_size,
//io_size));
//BIO_set_callback_ex(bio_mem.get(), nullptr);
EXPECT_EQ(io_size,
BIO_read(bio_cipher.get(), decrypted_pt_vec.data(), io_size));
EXPECT_EQ(decrypted_pt_vec.size() - io_size, BIO_pending(bio_cipher.get()));
// Disable reads from underlying BIO
BIO_set_callback_ex(bio_mem.get(), disable_reads);
// BIO_set_flags(bio_mem.get(), BIO_FLAGS_MEM_RDONLY);
EXPECT_GE(io_size, BIO_read(bio_cipher.get(), decrypted_pt_vec.data() + io_size,
io_size));
EXPECT_EQ(0UL, BIO_pending(bio_cipher.get()));
// Re-enable reads from underlying BIO
BIO_set_callback_ex(bio_mem.get(), nullptr);
// BIO_clear_flags(bio_mem.get(), BIO_FLAGS_MEM_RDONLY);
EXPECT_EQ(-1, BIO_read(bio_cipher.get(),
decrypted_pt_vec.data() + io_size, io_size));
EXPECT_EQ(0UL, BIO_pending(bio_cipher.get()));
EXPECT_TRUE(BIO_get_cipher_status(bio_cipher.get()));
EXPECT_EQ(pt_vec.size(), decrypted_pt_vec.size());
EXPECT_EQ(Bytes(pt_vec.data(), pt_vec.size()),
Bytes(decrypted_pt_vec.data(), decrypted_pt_vec.size()));
bio_mem.release(); // |bio_cipher| took ownership


// TODO [childw] induce read failures?
}
44 changes: 44 additions & 0 deletions crypto/test/test_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -156,3 +156,47 @@ void CustomDataFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
free(ptr);
}

static int bio_mock_new(BIO *bio) {
BIO *ret = BIO_new(BIO_s_mem());
if (ret) {
*bio = *ret;
return 1;
}
return 0;
}

static int bio_mock_free(BIO *bio) { return BIO_free(bio); }

static int bio_mock_read(BIO *bio, char *out, int outl) {
printf("FOOBAR\n");
if (BIO_test_flags(bio, BIO_FLAGS_MEM_RDONLY)) {
return 0;
}
return BIO_read(bio, out, outl);
}

static int bio_mock_write(BIO *bio, const char *in, int inl) {
printf("BARFOO\n");
if (BIO_test_flags(bio, BIO_FLAGS_MEM_RDONLY)) {
return 0;
}
return BIO_write(bio, in, inl);
}

static int bio_mock_gets(BIO *bio, char *buf, int size) {
return BIO_gets(bio, buf, size);
}

static long bio_mock_ctrl(BIO *bio, int cmd, long num, void *ptr) {
return BIO_ctrl(bio, cmd, num, ptr);
}

static const BIO_METHOD bio_mock_method = {
BIO_TYPE_MEM, "mock with memory buffer",
bio_mock_write, bio_mock_read,
NULL /* puts */, bio_mock_gets,
bio_mock_ctrl, bio_mock_new,
bio_mock_free, NULL /* callback_ctrl */,
};

const BIO_METHOD *BIO_s_mock(void) { return &bio_mock_method; }
2 changes: 2 additions & 0 deletions crypto/test/test_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,6 @@ typedef struct {
void CustomDataFree(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
int index, long argl, void *argp);

const BIO_METHOD *BIO_s_mock(void);

#endif // OPENSSL_HEADER_CRYPTO_TEST_TEST_UTIL_H

0 comments on commit e85e166

Please sign in to comment.