/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #include #include #include "nss.h" #include "pk11pub.h" #include "prerror.h" #include "secerr.h" #include "ssl.h" #include "sslerr.h" extern "C" { #include "sslimpl.h" #include "selfencrypt.h" } #include "databuffer.h" #include "gtest_utils.h" #include "nss_scoped_ptrs.h" namespace nss_test { static const uint8_t kAesKey1Buf[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; static const DataBuffer kAesKey1(kAesKey1Buf, sizeof(kAesKey1Buf)); static const uint8_t kAesKey2Buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; static const DataBuffer kAesKey2(kAesKey2Buf, sizeof(kAesKey2Buf)); static const uint8_t kHmacKey1Buf[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; static const DataBuffer kHmacKey1(kHmacKey1Buf, sizeof(kHmacKey1Buf)); static const uint8_t kHmacKey2Buf[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}; static const DataBuffer kHmacKey2(kHmacKey2Buf, sizeof(kHmacKey2Buf)); static const uint8_t* kKeyName1 = reinterpret_cast("KEY1KEY1KEY1KEY1"); static const uint8_t* kKeyName2 = reinterpret_cast("KEY2KEY2KEY2KEY2"); static void ImportKey(const DataBuffer& key, PK11SlotInfo* slot, CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE cka, ScopedPK11SymKey* to) { SECItem key_item = {siBuffer, const_cast(key.data()), static_cast(key.len())}; PK11SymKey* inner = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, cka, &key_item, nullptr); ASSERT_NE(nullptr, inner); to->reset(inner); } extern "C" { extern char ssl_trace; extern FILE* ssl_trace_iob; } class SelfEncryptTestBase : public ::testing::Test { public: SelfEncryptTestBase(size_t message_size) : aes1_(), aes2_(), hmac1_(), hmac2_(), message_(), slot_(PK11_GetInternalSlot()) { EXPECT_NE(nullptr, slot_); char* ev = getenv("SSLTRACE"); if (ev && ev[0]) { ssl_trace = atoi(ev); ssl_trace_iob = stderr; } message_.Allocate(message_size); for (size_t i = 0; i < message_.len(); ++i) { message_.data()[i] = i; } } void SetUp() { message_.Allocate(100); for (size_t i = 0; i < 100; ++i) { message_.data()[i] = i; } ImportKey(kAesKey1, slot_.get(), CKM_AES_CBC, CKA_ENCRYPT, &aes1_); ImportKey(kAesKey2, slot_.get(), CKM_AES_CBC, CKA_ENCRYPT, &aes2_); ImportKey(kHmacKey1, slot_.get(), CKM_SHA256_HMAC, CKA_SIGN, &hmac1_); ImportKey(kHmacKey2, slot_.get(), CKM_SHA256_HMAC, CKA_SIGN, &hmac2_); } void SelfTest( const uint8_t* writeKeyName, const ScopedPK11SymKey& writeAes, const ScopedPK11SymKey& writeHmac, const uint8_t* readKeyName, const ScopedPK11SymKey& readAes, const ScopedPK11SymKey& readHmac, PRErrorCode protect_error_code = 0, PRErrorCode unprotect_error_code = 0, std::function mutate = nullptr) { uint8_t ciphertext[1000]; unsigned int ciphertext_len; uint8_t plaintext[1000]; unsigned int plaintext_len; SECStatus rv = ssl_SelfEncryptProtectInt( writeAes.get(), writeHmac.get(), writeKeyName, message_.data(), message_.len(), ciphertext, &ciphertext_len, sizeof(ciphertext)); if (rv != SECSuccess) { std::cerr << "Error: " << PORT_ErrorToName(PORT_GetError()) << std::endl; } if (protect_error_code) { ASSERT_EQ(protect_error_code, PORT_GetError()); return; } ASSERT_EQ(SECSuccess, rv); if (mutate) { mutate(ciphertext, &ciphertext_len); } rv = ssl_SelfEncryptUnprotectInt(readAes.get(), readHmac.get(), readKeyName, ciphertext, ciphertext_len, plaintext, &plaintext_len, sizeof(plaintext)); if (rv != SECSuccess) { std::cerr << "Error: " << PORT_ErrorToName(PORT_GetError()) << std::endl; } if (!unprotect_error_code) { ASSERT_EQ(SECSuccess, rv); EXPECT_EQ(message_.len(), plaintext_len); EXPECT_EQ(0, memcmp(message_.data(), plaintext, message_.len())); } else { ASSERT_EQ(SECFailure, rv); EXPECT_EQ(unprotect_error_code, PORT_GetError()); } } protected: ScopedPK11SymKey aes1_; ScopedPK11SymKey aes2_; ScopedPK11SymKey hmac1_; ScopedPK11SymKey hmac2_; DataBuffer message_; private: ScopedPK11SlotInfo slot_; }; class SelfEncryptTestVariable : public SelfEncryptTestBase, public ::testing::WithParamInterface { public: SelfEncryptTestVariable() : SelfEncryptTestBase(GetParam()) {} }; class SelfEncryptTest128 : public SelfEncryptTestBase { public: SelfEncryptTest128() : SelfEncryptTestBase(128) {} }; TEST_P(SelfEncryptTestVariable, SuccessCase) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_); } TEST_P(SelfEncryptTestVariable, WrongMacKey) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac2_, 0, SEC_ERROR_BAD_DATA); } TEST_P(SelfEncryptTestVariable, WrongKeyName) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName2, aes1_, hmac1_, 0, SEC_ERROR_NOT_A_RECIPIENT); } TEST_P(SelfEncryptTestVariable, AddAByte) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { (*ciphertext_len)++; }); } TEST_P(SelfEncryptTestVariable, SubtractAByte) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { (*ciphertext_len)--; }); } TEST_P(SelfEncryptTestVariable, BogusIv) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { ciphertext[16]++; }); } TEST_P(SelfEncryptTestVariable, BogusCiphertext) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { ciphertext[32]++; }); } TEST_P(SelfEncryptTestVariable, BadMac) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { ciphertext[*ciphertext_len - 1]++; }); } TEST_F(SelfEncryptTest128, DISABLED_BadPadding) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes2_, hmac1_, 0, SEC_ERROR_BAD_DATA); } TEST_F(SelfEncryptTest128, ShortKeyName) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { *ciphertext_len = 15; }); } TEST_F(SelfEncryptTest128, ShortIv) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { *ciphertext_len = 31; }); } TEST_F(SelfEncryptTest128, ShortCiphertextLen) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { *ciphertext_len = 32; }); } TEST_F(SelfEncryptTest128, ShortCiphertext) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, SEC_ERROR_BAD_DATA, [](uint8_t* ciphertext, unsigned int* ciphertext_len) { *ciphertext_len -= 17; }); } TEST_F(SelfEncryptTest128, MacWithAESKeyEncrypt) { SelfTest(kKeyName1, aes1_, aes1_, kKeyName1, aes1_, hmac1_, SEC_ERROR_LIBRARY_FAILURE); } TEST_F(SelfEncryptTest128, AESWithMacKeyEncrypt) { SelfTest(kKeyName1, hmac1_, hmac1_, kKeyName1, aes1_, hmac1_, SEC_ERROR_INVALID_KEY); } TEST_F(SelfEncryptTest128, MacWithAESKeyDecrypt) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, aes1_, 0, SEC_ERROR_LIBRARY_FAILURE); } TEST_F(SelfEncryptTest128, AESWithMacKeyDecrypt) { SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, hmac1_, hmac1_, 0, SEC_ERROR_INVALID_KEY); } INSTANTIATE_TEST_SUITE_P(VariousSizes, SelfEncryptTestVariable, ::testing::Values(0, 15, 16, 31, 255, 256, 257)); } // namespace nss_test