/* -*- 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 <memory>
#include "keyhi.h"
#include "pk11pub.h"
#include "secerr.h"
#include "ssl.h"
#include "sslerr.h"
#include "sslexp.h"
#include "sslproto.h"
#include "gtest_utils.h"
#include "nss_scoped_ptrs.h"
#include "scoped_ptrs_ssl.h"
#include "tls_connect.h"
namespace nss_test {
// From tls_hkdf_unittest.cc:
extern size_t GetHashLength(SSLHashType ht);
class AeadTest :
public ::testing::Test {
public:
AeadTest() : slot_(PK11_GetInternalSlot()) {}
void InitSecret(SSLHashType hash_type) {
static const uint8_t kData[
64] = {
's',
'e',
'c',
'r',
'e',
't'};
SECItem key_item = {siBuffer,
const_cast<uint8_t *>(kData),
static_cast<
unsigned int>(GetHashLength(hash_type))};
PK11SymKey *s =
PK11_ImportSymKey(slot_.get(), CKM_SSL3_MASTER_KEY_DERIVE,
PK11_OriginUnwrap, CKA_DERIVE, &key_item, NULL);
ASSERT_NE(nullptr, s);
secret_.reset(s);
}
void SetUp() override {
InitSecret(ssl_hash_sha256);
PORT_SetError(
0);
}
protected:
static void EncryptDecrypt(
const ScopedSSLAeadContext &ctx,
const uint8_t *ciphertext, size_t ciphertext_len) {
static const uint8_t kAad[] = {
'a',
'a',
'd'};
static const uint8_t kPlaintext[] = {
't',
'e',
'x',
't'};
static const size_t kMaxSize =
32;
ASSERT_GE(kMaxSize, ciphertext_len);
ASSERT_LT(
0U, ciphertext_len);
uint8_t output[kMaxSize] = {
0};
unsigned int output_len =
0;
EXPECT_EQ(SECSuccess, SSL_AeadEncrypt(ctx.get(),
0, kAad,
sizeof(kAad),
kPlaintext,
sizeof(kPlaintext),
output, &output_len,
sizeof(output)));
ASSERT_EQ(ciphertext_len,
static_cast<size_t>(output_len));
EXPECT_EQ(
0, memcmp(ciphertext, output, ciphertext_len));
memset(output,
0,
sizeof(output));
EXPECT_EQ(SECSuccess, SSL_AeadDecrypt(ctx.get(),
0, kAad,
sizeof(kAad),
ciphertext, ciphertext_len, output,
&output_len,
sizeof(output)));
ASSERT_EQ(
sizeof(kPlaintext),
static_cast<size_t>(output_len));
EXPECT_EQ(
0, memcmp(kPlaintext, output,
sizeof(kPlaintext)));
// Now for some tests of decryption failure.
// Truncate the input.
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(),
0, kAad,
sizeof(kAad),
ciphertext, ciphertext_len -
1,
output, &output_len,
sizeof(output)));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
// Skip the first byte of the AAD.
EXPECT_EQ(
SECFailure,
SSL_AeadDecrypt(ctx.get(),
0, kAad +
1,
sizeof(kAad) -
1, ciphertext,
ciphertext_len, output, &output_len,
sizeof(output)));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
uint8_t input[kMaxSize] = {
0};
// Toggle a byte of the input.
memcpy(input, ciphertext, ciphertext_len);
input[
0] ^=
9;
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(),
0, kAad,
sizeof(kAad),
input, ciphertext_len, output,
&output_len,
sizeof(output)));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
// Toggle the last byte (the auth tag).
memcpy(input, ciphertext, ciphertext_len);
input[ciphertext_len -
1] ^=
77;
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(),
0, kAad,
sizeof(kAad),
input, ciphertext_len, output,
&output_len,
sizeof(output)));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
// Toggle some of the AAD.
memcpy(input, kAad,
sizeof(kAad));
input[
1] ^=
23;
EXPECT_EQ(SECFailure, SSL_AeadDecrypt(ctx.get(),
0, input,
sizeof(kAad),
ciphertext, ciphertext_len, output,
&output_len,
sizeof(output)));
EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError());
}
protected:
ScopedPK11SymKey secret_;
private:
ScopedPK11SlotInfo slot_;
};
// These tests all use fixed inputs: a fixed secret, a fixed label, and fixed
// inputs. So they have fixed outputs.
static const char *kLabel =
"test ";
static const uint8_t kCiphertextAes128Gcm[] = {
0x11,
0x14,
0xfc,
0x58,
0x4f,
0x44,
0xff,
0x8c,
0xb6,
0xd8,
0x20,
0xb3,
0xfb,
0x50,
0xd9,
0x3b,
0xd4,
0xc6,
0xe1,
0x14};
static const uint8_t kCiphertextAes256Gcm[] = {
0xf7,
0x27,
0x35,
0x80,
0x88,
0xaf,
0x99,
0x85,
0xf2,
0x83,
0xca,
0xbb,
0x95,
0x42,
0x09,
0x3f,
0x9c,
0xf3,
0x29,
0xf0};
static const uint8_t kCiphertextChaCha20Poly1305[] = {
0x4e,
0x89,
0x2c,
0xfa,
0xfc,
0x8c,
0x40,
0x55,
0x6d,
0x7e,
0x99,
0xac,
0x8e,
0x54,
0x58,
0xb1,
0x18,
0xd2,
0x66,
0x22};
TEST_F(AeadTest, AeadBadVersion) {
SSLAeadContext *ctx = nullptr;
ASSERT_EQ(SECFailure,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_2, TLS_AES_128_GCM_SHA256,
secret_.get(), kLabel, strlen(kLabel), &ctx));
EXPECT_EQ(nullptr, ctx);
}
TEST_F(AeadTest, AeadUnsupportedCipher) {
SSLAeadContext *ctx = nullptr;
ASSERT_EQ(SECFailure,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_NULL_MD5,
secret_.get(), kLabel, strlen(kLabel), &ctx));
EXPECT_EQ(nullptr, ctx);
}
TEST_F(AeadTest, AeadOlderCipher) {
SSLAeadContext *ctx = nullptr;
ASSERT_EQ(
SECFailure,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_RSA_WITH_AES_128_CBC_SHA,
secret_.get(), kLabel, strlen(kLabel), &ctx));
EXPECT_EQ(nullptr, ctx);
}
TEST_F(AeadTest, AeadNoLabel) {
SSLAeadContext *ctx = nullptr;
ASSERT_EQ(SECFailure,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
secret_.get(), nullptr,
12, &ctx));
EXPECT_EQ(nullptr, ctx);
}
TEST_F(AeadTest, AeadLongLabel) {
SSLAeadContext *ctx = nullptr;
ASSERT_EQ(SECFailure,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
secret_.get(),
"",
254, &ctx));
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
EXPECT_EQ(nullptr, ctx);
}
TEST_F(AeadTest, AeadNoPointer) {
SSLAeadContext *ctx = nullptr;
ASSERT_EQ(SECFailure,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
secret_.get(), kLabel, strlen(kLabel), nullptr));
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
EXPECT_EQ(nullptr, ctx);
}
TEST_F(AeadTest, AeadAes128Gcm) {
SSLAeadContext *ctxInit = nullptr;
ASSERT_EQ(SECSuccess,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_128_GCM_SHA256,
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
ScopedSSLAeadContext ctx(ctxInit);
EXPECT_NE(nullptr, ctx);
EncryptDecrypt(ctx, kCiphertextAes128Gcm,
sizeof(kCiphertextAes128Gcm));
}
TEST_F(AeadTest, AeadAes256Gcm) {
SSLAeadContext *ctxInit = nullptr;
ASSERT_EQ(SECSuccess,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_AES_256_GCM_SHA384,
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
ScopedSSLAeadContext ctx(ctxInit);
EXPECT_NE(nullptr, ctx);
EncryptDecrypt(ctx, kCiphertextAes256Gcm,
sizeof(kCiphertextAes256Gcm));
}
TEST_F(AeadTest, AeadChaCha20Poly1305) {
SSLAeadContext *ctxInit = nullptr;
ASSERT_EQ(
SECSuccess,
SSL_MakeAead(SSL_LIBRARY_VERSION_TLS_1_3, TLS_CHACHA20_POLY1305_SHA256,
secret_.get(), kLabel, strlen(kLabel), &ctxInit));
ScopedSSLAeadContext ctx(ctxInit);
EXPECT_NE(nullptr, ctx);
EncryptDecrypt(ctx, kCiphertextChaCha20Poly1305,
sizeof(kCiphertextChaCha20Poly1305));
}
}
// namespace nss_test