summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cpputil/scoped_ptrs_ssl.h2
-rw-r--r--gtests/ssl_gtest/manifest.mn1
-rw-r--r--gtests/ssl_gtest/ssl_gtest.gyp1
-rw-r--r--gtests/ssl_gtest/ssl_primitive_unittest.cc186
-rw-r--r--gtests/ssl_gtest/tls_hkdf_unittest.cc23
-rw-r--r--gtests/ssl_gtest/tls_protect.cc154
-rw-r--r--gtests/ssl_gtest/tls_protect.h48
-rw-r--r--lib/ssl/manifest.mn1
-rw-r--r--lib/ssl/ssl.gyp1
-rw-r--r--lib/ssl/ssl3con.c63
-rw-r--r--lib/ssl/sslexp.h51
-rw-r--r--lib/ssl/sslimpl.h21
-rw-r--r--lib/ssl/sslprimitive.c188
-rw-r--r--lib/ssl/sslsock.c4
-rw-r--r--lib/ssl/sslspec.h16
-rw-r--r--lib/ssl/tls13con.c88
-rw-r--r--lib/ssl/tls13con.h6
-rw-r--r--lib/ssl/tls13esni.c4
-rw-r--r--lib/ssl/tls13esni.h4
-rw-r--r--lib/ssl/tls13exthandle.c4
20 files changed, 588 insertions, 278 deletions
diff --git a/cpputil/scoped_ptrs_ssl.h b/cpputil/scoped_ptrs_ssl.h
index 7eeae8f8f..581fe423a 100644
--- a/cpputil/scoped_ptrs_ssl.h
+++ b/cpputil/scoped_ptrs_ssl.h
@@ -14,6 +14,7 @@ struct ScopedDeleteSSL {
void operator()(SSLResumptionTokenInfo* token) {
SSL_DestroyResumptionTokenInfo(token);
}
+ void operator()(SSLAeadContext* ctx) { SSL_DestroyAead(ctx); }
};
template <class T>
@@ -29,6 +30,7 @@ struct ScopedMaybeDeleteSSL {
#define SCOPED(x) typedef std::unique_ptr<x, ScopedMaybeDeleteSSL<x> > Scoped##x
SCOPED(SSLResumptionTokenInfo);
+SCOPED(SSLAeadContext);
#undef SCOPED
diff --git a/gtests/ssl_gtest/manifest.mn b/gtests/ssl_gtest/manifest.mn
index 9df798b64..13883712e 100644
--- a/gtests/ssl_gtest/manifest.mn
+++ b/gtests/ssl_gtest/manifest.mn
@@ -35,6 +35,7 @@ CPPSRCS = \
ssl_keyupdate_unittest.cc \
ssl_loopback_unittest.cc \
ssl_misc_unittest.cc \
+ ssl_primitive_unittest.cc \
ssl_record_unittest.cc \
ssl_recordsep_unittest.cc \
ssl_recordsize_unittest.cc \
diff --git a/gtests/ssl_gtest/ssl_gtest.gyp b/gtests/ssl_gtest/ssl_gtest.gyp
index 2fb6c3138..8dbd9fa34 100644
--- a/gtests/ssl_gtest/ssl_gtest.gyp
+++ b/gtests/ssl_gtest/ssl_gtest.gyp
@@ -36,6 +36,7 @@
'ssl_keyupdate_unittest.cc',
'ssl_loopback_unittest.cc',
'ssl_misc_unittest.cc',
+ 'ssl_primitive_unittest.cc',
'ssl_record_unittest.cc',
'ssl_recordsep_unittest.cc',
'ssl_recordsize_unittest.cc',
diff --git a/gtests/ssl_gtest/ssl_primitive_unittest.cc b/gtests/ssl_gtest/ssl_primitive_unittest.cc
new file mode 100644
index 000000000..b46a3d97f
--- /dev/null
+++ b/gtests/ssl_gtest/ssl_primitive_unittest.cc
@@ -0,0 +1,186 @@
+/* -*- 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);
+
+ uint8_t output[kMaxSize];
+ 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, AeadNoLabel) {
+ SSLAeadContext *ctx = nullptr;
+ ASSERT_EQ(SECFailure, SSL_MakeAead(secret_.get(), TLS_AES_128_GCM_SHA256,
+ nullptr, 12, &ctx));
+ EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadLongLabel) {
+ SSLAeadContext *ctx = nullptr;
+ ASSERT_EQ(SECFailure,
+ SSL_MakeAead(secret_.get(), TLS_AES_128_GCM_SHA256, "", 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(secret_.get(), TLS_AES_128_GCM_SHA256,
+ kLabel, strlen(kLabel), nullptr));
+ EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
+ EXPECT_EQ(nullptr, ctx);
+}
+
+TEST_F(AeadTest, AeadAes128Gcm) {
+ SSLAeadContext *ctxInit;
+ ASSERT_EQ(SECSuccess, SSL_MakeAead(secret_.get(), TLS_AES_128_GCM_SHA256,
+ kLabel, strlen(kLabel), &ctxInit));
+ ScopedSSLAeadContext ctx(ctxInit);
+ EXPECT_NE(nullptr, ctx);
+
+ EncryptDecrypt(ctx, kCiphertextAes128Gcm, sizeof(kCiphertextAes128Gcm));
+}
+
+TEST_F(AeadTest, AeadAes256Gcm) {
+ SSLAeadContext *ctxInit;
+ ASSERT_EQ(SECSuccess, SSL_MakeAead(secret_.get(), TLS_AES_256_GCM_SHA384,
+ kLabel, strlen(kLabel), &ctxInit));
+ ScopedSSLAeadContext ctx(ctxInit);
+ EXPECT_NE(nullptr, ctx);
+
+ EncryptDecrypt(ctx, kCiphertextAes256Gcm, sizeof(kCiphertextAes256Gcm));
+}
+
+TEST_F(AeadTest, AeadChaCha20Poly1305) {
+ SSLAeadContext *ctxInit;
+ ASSERT_EQ(SECSuccess,
+ SSL_MakeAead(secret_.get(), TLS_CHACHA20_POLY1305_SHA256, kLabel,
+ strlen(kLabel), &ctxInit));
+ ScopedSSLAeadContext ctx(ctxInit);
+ EXPECT_NE(nullptr, ctx);
+
+ EncryptDecrypt(ctx, kCiphertextChaCha20Poly1305,
+ sizeof(kCiphertextChaCha20Poly1305));
+}
+
+} // namespace nss_test
diff --git a/gtests/ssl_gtest/tls_hkdf_unittest.cc b/gtests/ssl_gtest/tls_hkdf_unittest.cc
index 004da3b1c..2e82baafd 100644
--- a/gtests/ssl_gtest/tls_hkdf_unittest.cc
+++ b/gtests/ssl_gtest/tls_hkdf_unittest.cc
@@ -56,6 +56,15 @@ const size_t kHashLength[] = {
64, /* ssl_hash_sha512 */
};
+size_t GetHashLength(SSLHashType hash) {
+ size_t i = static_cast<size_t>(hash);
+ if (i >= 0 && i < PR_ARRAY_SIZE(kHashLength)) {
+ return kHashLength[i];
+ }
+ ADD_FAILURE() << "Unknown hash: " << hash;
+ return 0;
+}
+
const std::string kHashName[] = {"None", "MD5", "SHA-1", "SHA-224",
"SHA-256", "SHA-384", "SHA-512"};
@@ -64,7 +73,7 @@ static void ImportKey(ScopedPK11SymKey* to, const DataBuffer& key,
ASSERT_LT(hash_type, sizeof(kHashLength));
ASSERT_LE(kHashLength[hash_type], key.len());
SECItem key_item = {siBuffer, const_cast<uint8_t*>(key.data()),
- static_cast<unsigned int>(kHashLength[hash_type])};
+ static_cast<unsigned int>(GetHashLength(hash_type))};
PK11SymKey* inner =
PK11_ImportSymKey(slot, CKM_SSL3_MASTER_KEY_DERIVE, PK11_OriginUnwrap,
@@ -175,7 +184,7 @@ TEST_P(TlsHkdfTest, HkdfNullNull) {
0x10, 0xba, 0x18, 0xe2, 0x35, 0x7e, 0x71, 0x69, 0x71, 0xf9, 0x36, 0x2f,
0x2c, 0x2f, 0xe2, 0xa7, 0x6b, 0xfd, 0x78, 0xdf, 0xec, 0x4e, 0xa9, 0xb5}};
- const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+ const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
HkdfExtract(nullptr, nullptr, hash_type_, expected_data);
}
@@ -193,7 +202,7 @@ TEST_P(TlsHkdfTest, HkdfKey1Only) {
0x57, 0xc2, 0x76, 0x9f, 0x3f, 0x83, 0x45, 0x2f, 0xf6, 0xf3, 0x56, 0x1f,
0x58, 0x63, 0xdb, 0x88, 0xda, 0x40, 0xce, 0x63, 0x7d, 0x24, 0x37, 0xf3}};
- const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+ const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
HkdfExtract(k1_, nullptr, hash_type_, expected_data);
}
@@ -211,7 +220,7 @@ TEST_P(TlsHkdfTest, HkdfKey2Only) {
0xd4, 0x6a, 0xf6, 0xe5, 0xec, 0xea, 0xf8, 0x7d, 0x91, 0x71, 0x81, 0xf1,
0xdb, 0x3b, 0xaf, 0xbf, 0xde, 0x71, 0x61, 0x15, 0xeb, 0xb5, 0x5f, 0x68}};
- const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+ const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
HkdfExtract(nullptr, k2_, hash_type_, expected_data);
}
@@ -229,7 +238,7 @@ TEST_P(TlsHkdfTest, HkdfKey1Key2) {
0x1c, 0x5b, 0x98, 0x0b, 0x02, 0x92, 0x3f, 0xfd, 0x73, 0x5a, 0x6f, 0x2a,
0x95, 0xa3, 0xee, 0xf6, 0xd6, 0x8e, 0x6f, 0x86, 0xea, 0x63, 0xf8, 0x33}};
- const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
+ const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
HkdfExtract(k1_, k2_, hash_type_, expected_data);
}
@@ -247,8 +256,8 @@ TEST_P(TlsHkdfTest, HkdfExpandLabel) {
0x74, 0xf7, 0x8b, 0x06, 0x38, 0x28, 0x06, 0x37, 0x75, 0x23, 0xa2, 0xb7,
0x34, 0xb1, 0x72, 0x2e, 0x59, 0x6d, 0x5a, 0x31, 0xf5, 0x53, 0xab, 0x99}};
- const DataBuffer expected_data(tv[hash_type_], kHashLength[hash_type_]);
- HkdfExpandLabel(&k1_, hash_type_, kSessionHash, kHashLength[hash_type_],
+ const DataBuffer expected_data(tv[hash_type_], GetHashLength(hash_type_));
+ HkdfExpandLabel(&k1_, hash_type_, kSessionHash, GetHashLength(hash_type_),
kLabelMasterSecret, strlen(kLabelMasterSecret),
expected_data);
}
diff --git a/gtests/ssl_gtest/tls_protect.cc b/gtests/ssl_gtest/tls_protect.cc
index c92b5ccf7..1e1004b5e 100644
--- a/gtests/ssl_gtest/tls_protect.cc
+++ b/gtests/ssl_gtest/tls_protect.cc
@@ -7,99 +7,8 @@
#include "tls_protect.h"
#include "tls_filter.h"
-// Do this to avoid having to re-implement HKDF.
-#include "tls13hkdf.h"
-
namespace nss_test {
-AeadCipher::~AeadCipher() {
- if (key_) {
- PK11_FreeSymKey(key_);
- }
-}
-
-bool AeadCipher::Init(PK11SymKey* key, const uint8_t* iv) {
- key_ = key;
- if (!key_) return false;
-
- memcpy(iv_, iv, sizeof(iv_));
- if (g_ssl_gtest_verbose) {
- EXPECT_EQ(SECSuccess, PK11_ExtractKeyValue(key_));
- SECItem* raw_key = PK11_GetKeyData(key_);
- std::cerr << "key: " << DataBuffer(raw_key->data, raw_key->len)
- << std::endl;
- std::cerr << "iv: " << DataBuffer(iv_, 12) << std::endl;
- }
- return true;
-}
-
-void AeadCipher::FormatNonce(uint64_t seq, uint8_t* nonce) {
- memcpy(nonce, iv_, 12);
-
- for (size_t i = 0; i < 8; ++i) {
- nonce[12 - (i + 1)] ^= seq & 0xff;
- seq >>= 8;
- }
-}
-
-bool AeadCipher::AeadInner(bool decrypt, void* params, size_t param_length,
- const uint8_t* in, size_t inlen, uint8_t* out,
- size_t* outlen, size_t maxlen) {
- SECStatus rv;
- unsigned int uoutlen = 0;
- SECItem param = {
- siBuffer, static_cast<unsigned char*>(params),
- static_cast<unsigned int>(param_length),
- };
-
- if (decrypt) {
- rv = PK11_Decrypt(key_, mech_, &param, out, &uoutlen, maxlen, in, inlen);
- } else {
- rv = PK11_Encrypt(key_, mech_, &param, out, &uoutlen, maxlen, in, inlen);
- }
- *outlen = (int)uoutlen;
-
- return rv == SECSuccess;
-}
-
-bool AeadCipherAesGcm::Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len,
- uint64_t seq, const uint8_t* in, size_t inlen,
- uint8_t* out, size_t* outlen, size_t maxlen) {
- CK_GCM_PARAMS aeadParams;
- unsigned char nonce[12];
-
- memset(&aeadParams, 0, sizeof(aeadParams));
- aeadParams.pIv = nonce;
- aeadParams.ulIvLen = sizeof(nonce);
- aeadParams.pAAD = const_cast<uint8_t*>(hdr);
- aeadParams.ulAADLen = hdr_len;
- aeadParams.ulTagBits = 128;
-
- FormatNonce(seq, nonce);
- return AeadInner(decrypt, (unsigned char*)&aeadParams, sizeof(aeadParams), in,
- inlen, out, outlen, maxlen);
-}
-
-bool AeadCipherChacha20Poly1305::Aead(bool decrypt, const uint8_t* hdr,
- size_t hdr_len, uint64_t seq,
- const uint8_t* in, size_t inlen,
- uint8_t* out, size_t* outlen,
- size_t maxlen) {
- CK_NSS_AEAD_PARAMS aeadParams;
- unsigned char nonce[12];
-
- memset(&aeadParams, 0, sizeof(aeadParams));
- aeadParams.pNonce = nonce;
- aeadParams.ulNonceLen = sizeof(nonce);
- aeadParams.pAAD = const_cast<uint8_t*>(hdr);
- aeadParams.ulAADLen = hdr_len;
- aeadParams.ulTagLen = 16;
-
- FormatNonce(seq, nonce);
- return AeadInner(decrypt, (unsigned char*)&aeadParams, sizeof(aeadParams), in,
- inlen, out, outlen, maxlen);
-}
-
static uint64_t FirstSeqno(bool dtls, uint16_t epoc) {
if (dtls) {
return static_cast<uint64_t>(epoc) << 48;
@@ -115,42 +24,15 @@ TlsCipherSpec::TlsCipherSpec(bool dtls, uint16_t epoc)
bool TlsCipherSpec::SetKeys(SSLCipherSuiteInfo* cipherinfo,
PK11SymKey* secret) {
- CK_MECHANISM_TYPE mech;
- switch (cipherinfo->symCipher) {
- case ssl_calg_aes_gcm:
- aead_.reset(new AeadCipherAesGcm());
- mech = CKM_AES_GCM;
- break;
- case ssl_calg_chacha20:
- aead_.reset(new AeadCipherChacha20Poly1305());
- mech = CKM_NSS_CHACHA20_POLY1305;
- break;
- default:
- return false;
- }
-
- PK11SymKey* key;
- const std::string kPurposeKey = "key";
- SECStatus rv = tls13_HkdfExpandLabel(
- secret, cipherinfo->kdfHash, NULL, 0, kPurposeKey.c_str(),
- kPurposeKey.length(), mech, cipherinfo->symKeyBits / 8, &key);
- if (rv != SECSuccess) {
- ADD_FAILURE() << "unable to derive key for epoch " << epoch_;
- return false;
- }
-
- // No constant for IV length, but everything we know of uses 12.
- uint8_t iv[12];
- const std::string kPurposeIv = "iv";
- rv = tls13_HkdfExpandLabelRaw(secret, cipherinfo->kdfHash, NULL, 0,
- kPurposeIv.c_str(), kPurposeIv.length(), iv,
- sizeof(iv));
+ SSLAeadContext* ctx;
+ SECStatus rv = SSL_MakeAead(secret, cipherinfo->cipherSuite, "",
+ 0, // Use the default labels.
+ &ctx);
if (rv != SECSuccess) {
- ADD_FAILURE() << "unable to derive IV for epoch " << epoch_;
return false;
}
-
- return aead_->Init(key, iv);
+ aead_.reset(ctx);
+ return true;
}
bool TlsCipherSpec::Unprotect(const TlsRecordHeader& header,
@@ -163,22 +45,23 @@ bool TlsCipherSpec::Unprotect(const TlsRecordHeader& header,
plaintext->Allocate(ciphertext.len());
auto header_bytes = header.header();
- size_t len;
+ unsigned int len;
uint64_t seqno;
if (dtls_) {
seqno = header.sequence_number();
} else {
seqno = in_seqno_;
}
- bool ret = aead_->Aead(true, header_bytes.data(), header_bytes.len(), seqno,
- ciphertext.data(), ciphertext.len(), plaintext->data(),
- &len, plaintext->len());
- if (!ret) {
+ SECStatus rv =
+ SSL_AeadDecrypt(aead_.get(), seqno, header_bytes.data(),
+ header_bytes.len(), ciphertext.data(), ciphertext.len(),
+ plaintext->data(), &len, plaintext->len());
+ if (rv != SECSuccess) {
return false;
}
RecordUnprotected(seqno);
- plaintext->Truncate(len);
+ plaintext->Truncate(static_cast<size_t>(len));
return true;
}
@@ -192,7 +75,7 @@ bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
// Make a padded buffer.
ciphertext->Allocate(plaintext.len() +
32); // Room for any plausible auth tag
- size_t len;
+ unsigned int len;
DataBuffer header_bytes;
(void)header.WriteHeader(&header_bytes, 0, plaintext.len() + 16);
@@ -203,10 +86,11 @@ bool TlsCipherSpec::Protect(const TlsRecordHeader& header,
seqno = out_seqno_;
}
- bool ret = aead_->Aead(false, header_bytes.data(), header_bytes.len(), seqno,
- plaintext.data(), plaintext.len(), ciphertext->data(),
- &len, ciphertext->len());
- if (!ret) {
+ SECStatus rv =
+ SSL_AeadEncrypt(aead_.get(), seqno, header_bytes.data(),
+ header_bytes.len(), plaintext.data(), plaintext.len(),
+ ciphertext->data(), &len, ciphertext->len());
+ if (rv != SECSuccess) {
return false;
}
diff --git a/gtests/ssl_gtest/tls_protect.h b/gtests/ssl_gtest/tls_protect.h
index ded515dbb..b1febf887 100644
--- a/gtests/ssl_gtest/tls_protect.h
+++ b/gtests/ssl_gtest/tls_protect.h
@@ -10,54 +10,16 @@
#include <cstdint>
#include <memory>
-#include "databuffer.h"
#include "pk11pub.h"
#include "sslt.h"
+#include "sslexp.h"
+
+#include "databuffer.h"
+#include "scoped_ptrs_ssl.h"
namespace nss_test {
class TlsRecordHeader;
-class AeadCipher {
- public:
- AeadCipher(CK_MECHANISM_TYPE mech) : mech_(mech), key_(nullptr) {}
- virtual ~AeadCipher();
-
- bool Init(PK11SymKey* key, const uint8_t* iv);
- virtual bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len,
- uint64_t seq, const uint8_t* in, size_t inlen, uint8_t* out,
- size_t* outlen, size_t maxlen) = 0;
-
- protected:
- void FormatNonce(uint64_t seq, uint8_t* nonce);
- bool AeadInner(bool decrypt, void* params, size_t param_length,
- const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
- size_t maxlen);
-
- CK_MECHANISM_TYPE mech_;
- PK11SymKey* key_;
- uint8_t iv_[12];
-};
-
-class AeadCipherChacha20Poly1305 : public AeadCipher {
- public:
- AeadCipherChacha20Poly1305() : AeadCipher(CKM_NSS_CHACHA20_POLY1305) {}
-
- protected:
- bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len, uint64_t seq,
- const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
- size_t maxlen);
-};
-
-class AeadCipherAesGcm : public AeadCipher {
- public:
- AeadCipherAesGcm() : AeadCipher(CKM_AES_GCM) {}
-
- protected:
- bool Aead(bool decrypt, const uint8_t* hdr, size_t hdr_len, uint64_t seq,
- const uint8_t* in, size_t inlen, uint8_t* out, size_t* outlen,
- size_t maxlen);
-};
-
// Our analog of ssl3CipherSpec
class TlsCipherSpec {
public:
@@ -89,7 +51,7 @@ class TlsCipherSpec {
uint64_t in_seqno_;
uint64_t out_seqno_;
bool record_dropped_ = false;
- std::unique_ptr<AeadCipher> aead_;
+ ScopedSSLAeadContext aead_;
};
} // namespace nss_test
diff --git a/lib/ssl/manifest.mn b/lib/ssl/manifest.mn
index fe9470bd0..201a01049 100644
--- a/lib/ssl/manifest.mn
+++ b/lib/ssl/manifest.mn
@@ -55,6 +55,7 @@ CSRCS = \
tls13replay.c \
sslcert.c \
sslgrp.c \
+ sslprimitive.c \
tls13esni.c \
$(NULL)
diff --git a/lib/ssl/ssl.gyp b/lib/ssl/ssl.gyp
index 2e28f6775..235f752d5 100644
--- a/lib/ssl/ssl.gyp
+++ b/lib/ssl/ssl.gyp
@@ -35,6 +35,7 @@
'sslinit.c',
'sslmutex.c',
'sslnonce.c',
+ 'sslprimitive.c',
'sslreveal.c',
'sslsecur.c',
'sslsnce.c',
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index b5b047228..da609fb06 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -553,10 +553,9 @@ SSL_AtomicIncrementLong(long *x)
}
}
-static PRBool
-ssl3_CipherSuiteAllowedForVersionRange(
- ssl3CipherSuite cipherSuite,
- const SSLVersionRange *vrange)
+PRBool
+ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
+ const SSLVersionRange *vrange)
{
switch (cipherSuite) {
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
@@ -912,8 +911,8 @@ count_cipher_suites(sslSocket *ss, PRUint8 policy)
* Null compression, mac and encryption functions
*/
SECStatus
-Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen,
- const unsigned char *input, int inputLen)
+Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen,
+ const unsigned char *input, unsigned int inputLen)
{
if (inputLen > maxOutputLen) {
*outputLen = 0; /* Match PK11_CipherOp in setting outputLen */
@@ -1554,15 +1553,15 @@ ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch,
}
static SECStatus
-ssl3_AESGCM(ssl3KeyMaterial *keys,
+ssl3_AESGCM(const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
SECItem param;
SECStatus rv = SECFailure;
@@ -1616,11 +1615,11 @@ ssl3_AESGCM(ssl3KeyMaterial *keys,
}
static SECStatus
-ssl3_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+ssl3_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
size_t i;
SECItem param;
@@ -2012,7 +2011,7 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
unsigned int ivLen = 0;
unsigned char pseudoHeaderBuf[13];
sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf);
- int len;
+ unsigned int len;
if (cwSpec->cipherDef->type == type_block &&
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
@@ -2130,15 +2129,15 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
memmove(SSL_BUFFER_NEXT(wrBuf) + p1Len, pIn + p1Len, oddLen);
}
if (p1Len > 0) {
- int cipherBytesPart1 = -1;
+ unsigned int cipherBytesPart1 = 0;
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf), /* output */
&cipherBytesPart1, /* actual outlen */
p1Len, /* max outlen */
pIn,
p1Len); /* input, and inputlen */
- PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int)p1Len);
- if (rv != SECSuccess || cipherBytesPart1 != (int)p1Len) {
+ PORT_Assert(rv == SECSuccess && cipherBytesPart1 == p1Len);
+ if (rv != SECSuccess || cipherBytesPart1 != p1Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
@@ -2146,15 +2145,15 @@ ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
PORT_Assert(rv == SECSuccess);
}
if (p2Len > 0) {
- int cipherBytesPart2 = -1;
+ unsigned int cipherBytesPart2 = 0;
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf),
&cipherBytesPart2, /* output and actual outLen */
p2Len, /* max outlen */
SSL_BUFFER_NEXT(wrBuf),
p2Len); /* input and inputLen*/
- PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int)p2Len);
- if (rv != SECSuccess || cipherBytesPart2 != (int)p2Len) {
+ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
+ if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
@@ -2241,7 +2240,7 @@ ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
#ifdef UNSAFE_FUZZER_MODE
{
- int len;
+ unsigned int len;
rv = Null_Cipher(NULL, SSL_BUFFER_NEXT(wrBuf), &len,
SSL_BUFFER_SPACE(wrBuf), pIn, contentLen);
if (rv != SECSuccess) {
@@ -12200,7 +12199,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
* discard it before decrypting the rest.
*/
PRUint8 iv[MAX_IV_LENGTH];
- int decoded;
+ unsigned int decoded;
ivLen = cipher_def->iv_size;
if (ivLen < 8 || ivLen > sizeof(iv)) {
@@ -12248,12 +12247,12 @@ ssl3_UnprotectRecord(sslSocket *ss,
rType, isTLS, rVersion, IS_DTLS(ss), decryptedLen, &header);
PORT_Assert(rv == SECSuccess);
rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- (int *)&plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
+ PR_TRUE, /* do decrypt */
+ plaintext->buf, /* out */
+ &plaintext->len, /* outlen */
+ plaintext->space, /* maxout */
+ cText->buf->buf, /* in */
+ cText->buf->len, /* inlen */
SSL_BUFFER_BASE(&header), SSL_BUFFER_LEN(&header));
if (rv != SECSuccess) {
good = 0;
@@ -12266,7 +12265,7 @@ ssl3_UnprotectRecord(sslSocket *ss,
/* decrypt from cText buf to plaintext. */
rv = spec->cipher(
- spec->cipherContext, plaintext->buf, (int *)&plaintext->len,
+ spec->cipherContext, plaintext->buf, &plaintext->len,
plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen);
if (rv != SECSuccess) {
goto decrypt_loser;
@@ -12548,7 +12547,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText)
rv = SECFailure;
} else {
#ifdef UNSAFE_FUZZER_MODE
- rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len,
+ rv = Null_Cipher(NULL, plaintext->buf, &plaintext->len,
plaintext->space, cText->buf->buf, cText->buf->len);
#else
/* IMPORTANT: Unprotect functions MUST NOT send alerts
diff --git a/lib/ssl/sslexp.h b/lib/ssl/sslexp.h
index 8f4720cdc..447547d2f 100644
--- a/lib/ssl/sslexp.h
+++ b/lib/ssl/sslexp.h
@@ -626,6 +626,57 @@ typedef SECStatus(PR_CALLBACK *SSLRecordWriteCallback)(
PRUint16 * _writeEpoch), \
(fd, readEpoch, writeEpoch))
+/*
+ * The following AEAD functions expose an AEAD primitive that uses a ciphersuite
+ * to set parameters. The ciphersuite determines the Hash function used by
+ * HKDF, the AEAD function, and the size of key and IV. Only TLS 1.3
+ * ciphersuites can be used.
+ *
+ * The key and IV are generated using the TLS KDF with a custom label. That is
+ * HKDF-Expand-Label(secret, labelPrefix + " key" or " iv", "", L).
+ *
+ * The encrypt and decrypt functions use a nonce construction identical to that
+ * used in TLS. The lower bits of the IV are XORed with the 64-bit counter to
+ * produce the nonce. Otherwise, this is an AEAD interface similar to that
+ * described in RFC 5116.
+ */
+typedef struct SSLAeadContextStr SSLAeadContext;
+
+#define SSL_MakeAead(secret, cipherSuite, labelPrefix, labelPrefixLen, ctx) \
+ SSL_EXPERIMENTAL_API("SSL_MakeAead", \
+ (PK11SymKey * _secret, PRUint16 _cipherSuite, \
+ const char *_labelPrefix, \
+ unsigned int _labelPrefixLen, \
+ SSLAeadContext **_ctx), \
+ (secret, cipherSuite, labelPrefix, labelPrefixLen, ctx))
+
+#define SSL_AeadEncrypt(ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen) \
+ SSL_EXPERIMENTAL_API("SSL_AeadEncrypt", \
+ (const SSLAeadContext *_ctx, PRUint64 _counter, \
+ const PRUint8 *_aad, unsigned int _aadLen, \
+ const PRUint8 *_in, unsigned int _inLen, \
+ PRUint8 *_out, unsigned int *_outLen, \
+ unsigned int _maxOut), \
+ (ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen))
+
+#define SSL_AeadDecrypt(ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen) \
+ SSL_EXPERIMENTAL_API("SSL_AeadDecrypt", \
+ (const SSLAeadContext *_ctx, PRUint64 _counter, \
+ const PRUint8 *_aad, unsigned int _aadLen, \
+ const PRUint8 *_in, unsigned int _inLen, \
+ PRUint8 *_output, unsigned int *_outLen, \
+ unsigned int _maxOut), \
+ (ctx, counter, aad, aadLen, in, inLen, \
+ output, outputLen, maxOutputLen))
+
+#define SSL_DestroyAead(ctx) \
+ SSL_EXPERIMENTAL_API("SSL_DestroyAead", \
+ (SSLAeadContext * _ctx), \
+ (ctx))
+
/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index d1bc69478..68abbdfa1 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -1209,9 +1209,9 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled);
extern SECStatus ssl3_ConstrainRangeByPolicy(void);
extern SECStatus ssl3_InitState(sslSocket *ss);
-extern SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen,
- int maxOutputLen, const unsigned char *input,
- int inputLen);
+extern SECStatus Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen,
+ unsigned int maxOutputLen, const unsigned char *input,
+ unsigned int inputLen);
extern void ssl3_RestartHandshakeHashes(sslSocket *ss);
extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
const unsigned char *b,
@@ -1663,6 +1663,8 @@ SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid,
const ssl3CipherSuiteDef *ssl_LookupCipherSuiteDef(ssl3CipherSuite suite);
const ssl3CipherSuiteCfg *ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite,
const ssl3CipherSuiteCfg *suites);
+PRBool ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
+ const SSLVersionRange *vrange);
SECStatus ssl3_SelectServerCert(sslSocket *ss);
SECStatus ssl_PickSignatureScheme(sslSocket *ss,
@@ -1758,6 +1760,19 @@ SECStatus SSLExp_GetCurrentEpoch(PRFileDesc *fd, PRUint16 *readEpoch,
#define SSLResumptionTokenVersion 2
+SECStatus SSLExp_MakeAead(PK11SymKey *secret, PRUint16 cipherSuite,
+ const char *labelPrefix, unsigned int labelPrefixLen,
+ SSLAeadContext **ctx);
+SECStatus SSLExp_DestroyAead(SSLAeadContext *ctx);
+SECStatus SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut);
+SECStatus SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut);
+
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
diff --git a/lib/ssl/sslprimitive.c b/lib/ssl/sslprimitive.c
new file mode 100644
index 000000000..72caf962f
--- /dev/null
+++ b/lib/ssl/sslprimitive.c
@@ -0,0 +1,188 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * SSL Primitives: Public HKDF and AEAD Functions
+ *
+ * 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 "keyhi.h"
+#include "pk11pub.h"
+#include "sechash.h"
+#include "ssl.h"
+#include "sslexp.h"
+#include "sslerr.h"
+#include "sslproto.h"
+
+#include "sslimpl.h"
+#include "tls13con.h"
+#include "tls13hkdf.h"
+
+struct SSLAeadContextStr {
+ CK_MECHANISM_TYPE mech;
+ ssl3KeyMaterial keys;
+};
+
+SECStatus
+SSLExp_MakeAead(PK11SymKey *secret, PRUint16 cipherSuite,
+ const char *labelPrefix, unsigned int labelPrefixLen,
+ SSLAeadContext **ctx)
+{
+ SSLAeadContext *out = NULL;
+ char label[255]; // Maximum length label.
+ static const char *const keySuffix = "key";
+ static const char *const ivSuffix = "iv";
+
+ PORT_Assert(strlen(keySuffix) >= strlen(ivSuffix));
+ if (secret == NULL || ctx == NULL ||
+ (labelPrefix == NULL && labelPrefixLen > 0) ||
+ labelPrefixLen + strlen(keySuffix) > sizeof(label)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+
+ // Lookup and check the suite.
+ SSLVersionRange tls13 = { SSL_LIBRARY_VERSION_TLS_1_3,
+ SSL_LIBRARY_VERSION_TLS_1_3 };
+ if (!ssl3_CipherSuiteAllowedForVersionRange(cipherSuite, &tls13)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ const ssl3CipherSuiteDef *suiteDef = ssl_LookupCipherSuiteDef(cipherSuite);
+ const ssl3BulkCipherDef *cipher = ssl_GetBulkCipherDef(suiteDef);
+ if (cipher->type != type_aead) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto loser;
+ }
+ SSLHashType hash = suiteDef->prf_hash;
+
+ out = PORT_ZNew(SSLAeadContext);
+ if (out == NULL) {
+ goto loser;
+ }
+ out->mech = ssl3_Alg2Mech(cipher->calg);
+
+ memcpy(label, labelPrefix, labelPrefixLen);
+ memcpy(label + labelPrefixLen, ivSuffix, strlen(ivSuffix));
+ unsigned int labelLen = labelPrefixLen + strlen(ivSuffix);
+ unsigned int ivLen = cipher->iv_size + cipher->explicit_nonce_size;
+ SECStatus rv = tls13_HkdfExpandLabelRaw(secret, hash,
+ NULL, 0, // Handshake hash.
+ label, labelLen,
+ out->keys.iv, ivLen);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ memcpy(label + labelPrefixLen, keySuffix, strlen(keySuffix));
+ labelLen = labelPrefixLen + strlen(keySuffix);
+ rv = tls13_HkdfExpandLabel(secret, hash,
+ NULL, 0, // Handshake hash.
+ label, labelLen,
+ out->mech, cipher->key_size, &out->keys.key);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ *ctx = out;
+ return SECSuccess;
+
+loser:
+ SSLExp_DestroyAead(out);
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_DestroyAead(SSLAeadContext *ctx)
+{
+ if (!ctx) {
+ return SECSuccess;
+ }
+
+ PK11_FreeSymKey(ctx->keys.key);
+ PORT_ZFree(ctx, sizeof(*ctx));
+ return SECSuccess;
+}
+
+/* Bug 1529440 exists to refactor this and the other AEAD uses. */
+static SECStatus
+ssl_AeadInner(const SSLAeadContext *ctx, PRBool decrypt, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+ if (ctx == NULL || (aad == NULL && aadLen > 0) || plaintext == NULL ||
+ out == NULL || outLen == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ // Setup the nonce.
+ PRUint8 nonce[12] = { 0 };
+ sslBuffer nonceBuf = SSL_BUFFER_FIXED(nonce + sizeof(nonce) - sizeof(counter),
+ sizeof(counter));
+ SECStatus rv = sslBuffer_AppendNumber(&nonceBuf, counter, sizeof(counter));
+ if (rv != SECSuccess) {
+ PORT_Assert(0);
+ return SECFailure;
+ }
+ for (int i = 0; i < sizeof(nonce); ++i) {
+ nonce[i] ^= ctx->keys.iv[i];
+ }
+
+ // Build AEAD parameters.
+ CK_GCM_PARAMS gcmParams = { 0 };
+ CK_NSS_AEAD_PARAMS aeadParams = { 0 };
+ unsigned char *params;
+ unsigned int paramsLen;
+ switch (ctx->mech) {
+ case CKM_AES_GCM:
+ gcmParams.pIv = nonce;
+ gcmParams.ulIvLen = sizeof(nonce);
+ gcmParams.pAAD = (unsigned char *)aad; // const cast :(
+ gcmParams.ulAADLen = aadLen;
+ gcmParams.ulTagBits = 128; // GCM measures in bits.
+ params = (unsigned char *)&gcmParams;
+ paramsLen = sizeof(gcmParams);
+ break;
+
+ case CKM_NSS_CHACHA20_POLY1305:
+ aeadParams.pNonce = nonce;
+ aeadParams.ulNonceLen = sizeof(nonce);
+ aeadParams.pAAD = (unsigned char *)aad; // const cast :(
+ aeadParams.ulAADLen = aadLen;
+ aeadParams.ulTagLen = 16; // AEAD measures in octets.
+ params = (unsigned char *)&aeadParams;
+ paramsLen = sizeof(aeadParams);
+ break;
+
+ default:
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ return tls13_AEAD(&ctx->keys, decrypt, out, outLen, maxOut,
+ plaintext, plaintextLen, ctx->mech, params, paramsLen);
+}
+
+SECStatus
+SSLExp_AeadEncrypt(const SSLAeadContext *ctx, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+ // false == encrypt
+ return ssl_AeadInner(ctx, PR_FALSE, counter, aad, aadLen,
+ plaintext, plaintextLen, out, outLen, maxOut);
+}
+
+SECStatus
+SSLExp_AeadDecrypt(const SSLAeadContext *ctx, PRUint64 counter,
+ const PRUint8 *aad, unsigned int aadLen,
+ const PRUint8 *plaintext, unsigned int plaintextLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxOut)
+{
+ // true == decrypt
+ return ssl_AeadInner(ctx, PR_TRUE, counter, aad, aadLen,
+ plaintext, plaintextLen, out, outLen, maxOut);
+}
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
index b8b75dc9c..2904ccddb 100644
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -4041,6 +4041,9 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
+ EXP(AeadDecrypt),
+ EXP(AeadEncrypt),
+ EXP(DestroyAead),
EXP(DestroyResumptionTokenInfo),
EXP(EnableESNI),
EXP(EncodeESNIKeys),
@@ -4050,6 +4053,7 @@ struct {
EXP(HelloRetryRequestCallback),
EXP(InstallExtensionHooks),
EXP(KeyUpdate),
+ EXP(MakeAead),
EXP(RecordLayerData),
EXP(RecordLayerWriteCallback),
EXP(SecretCallback),
diff --git a/lib/ssl/sslspec.h b/lib/ssl/sslspec.h
index 967e35862..ca9ef540f 100644
--- a/lib/ssl/sslspec.h
+++ b/lib/ssl/sslspec.h
@@ -101,20 +101,20 @@ typedef struct {
typedef SECStatus (*SSLCipher)(void *context,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen);
+ unsigned int inlen);
typedef SECStatus (*SSLAEADCipher)(
- ssl3KeyMaterial *keys,
+ const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen);
+ unsigned int additionalDataLen);
/* The DTLS anti-replay window in number of packets. Defined here because we
* need it in the cipher spec. Note that this is a ring buffer but left and
diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c
index 5daa48951..5e028727b 100644
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -28,18 +28,24 @@
static SECStatus tls13_SetCipherSpec(sslSocket *ss, PRUint16 epoch,
SSLSecretDirection install,
PRBool deleteSecret);
-static SECStatus tls13_AESGCM(
- ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
- const unsigned char *additionalData, int additionalDataLen);
-static SECStatus tls13_ChaCha20Poly1305(
- ssl3KeyMaterial *keys,
- PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
- const unsigned char *additionalData, int additionalDataLen);
+static SECStatus tls13_AESGCM(const ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ unsigned int *outlen,
+ unsigned int maxout,
+ const unsigned char *in,
+ unsigned int inlen,
+ const unsigned char *additionalData,
+ unsigned int additionalDataLen);
+static SECStatus tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys,
+ PRBool doDecrypt,
+ unsigned char *out,
+ unsigned int *outlen,
+ unsigned int maxout,
+ const unsigned char *in,
+ unsigned int inlen,
+ const unsigned char *additionalData,
+ unsigned int additionalDataLen);
static SECStatus tls13_SendServerHelloSequence(sslSocket *ss);
static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static void tls13_SetKeyExchangeType(sslSocket *ss, const sslNamedGroupDef *group);
@@ -293,7 +299,7 @@ tls13_GetHashSize(const sslSocket *ss)
return tls13_GetHashSizeForHash(tls13_GetHash(ss));
}
-static CK_MECHANISM_TYPE
+CK_MECHANISM_TYPE
tls13_GetHkdfMechanismForHash(SSLHashType hash)
{
switch (hash) {
@@ -3711,7 +3717,7 @@ tls13_DestroyEarlyData(PRCList *list)
* See RFC 5288 and https://tools.ietf.org/html/draft-ietf-tls-chacha20-poly1305-04#section-2
*/
static void
-tls13_WriteNonce(ssl3KeyMaterial *keys,
+tls13_WriteNonce(const ssl3KeyMaterial *keys,
const unsigned char *seqNumBuf, unsigned int seqNumLen,
unsigned char *nonce, unsigned int nonceLen)
{
@@ -3734,41 +3740,35 @@ tls13_WriteNonce(ssl3KeyMaterial *keys,
* a sequence number. In TLS 1.3 there is no additional data so this value is
* just the encoded sequence number.
*/
-static SECStatus
-tls13_AEAD(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+SECStatus
+tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
CK_MECHANISM_TYPE mechanism,
unsigned char *aeadParams, unsigned int aeadParamLength)
{
- SECStatus rv;
- unsigned int uOutLen = 0;
SECItem param = {
siBuffer, aeadParams, aeadParamLength
};
if (doDecrypt) {
- rv = PK11_Decrypt(keys->key, mechanism, &param,
- out, &uOutLen, maxout, in, inlen);
- } else {
- rv = PK11_Encrypt(keys->key, mechanism, &param,
- out, &uOutLen, maxout, in, inlen);
+ return PK11_Decrypt(keys->key, mechanism, &param,
+ out, outlen, maxout, in, inlen);
}
- *outlen = (int)uOutLen;
-
- return rv;
+ return PK11_Encrypt(keys->key, mechanism, &param,
+ out, outlen, maxout, in, inlen);
}
static SECStatus
-tls13_AESGCM(ssl3KeyMaterial *keys,
+tls13_AESGCM(const ssl3KeyMaterial *keys,
PRBool doDecrypt,
unsigned char *out,
- int *outlen,
- int maxout,
+ unsigned int *outlen,
+ unsigned int maxout,
const unsigned char *in,
- int inlen,
+ unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
CK_GCM_PARAMS gcmParams;
unsigned char nonce[12];
@@ -3789,11 +3789,11 @@ tls13_AESGCM(ssl3KeyMaterial *keys,
}
static SECStatus
-tls13_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt,
- unsigned char *out, int *outlen, int maxout,
- const unsigned char *in, int inlen,
+tls13_ChaCha20Poly1305(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
const unsigned char *additionalData,
- int additionalDataLen)
+ unsigned int additionalDataLen)
{
CK_NSS_AEAD_PARAMS aeadParams;
unsigned char nonce[12];
@@ -5145,7 +5145,7 @@ tls13_ProtectRecord(sslSocket *ss,
PRBool needsLength;
PRUint8 aad[21];
unsigned int aadLen;
- int len;
+ unsigned int len;
PORT_Assert(cipher_def->type == type_aead);
@@ -5266,12 +5266,12 @@ tls13_UnprotectRecord(sslSocket *ss,
return SECFailure;
}
rv = spec->aead(&spec->keyMaterial,
- PR_TRUE, /* do decrypt */
- plaintext->buf, /* out */
- (int *)&plaintext->len, /* outlen */
- plaintext->space, /* maxout */
- cText->buf->buf, /* in */
- cText->buf->len, /* inlen */
+ PR_TRUE, /* do decrypt */
+ plaintext->buf, /* out */
+ &plaintext->len, /* outlen */
+ plaintext->space, /* maxout */
+ cText->buf->buf, /* in */
+ cText->buf->len, /* inlen */
aad, aadLen);
if (rv != SECSuccess) {
SSL_TRC(3,
diff --git a/lib/ssl/tls13con.h b/lib/ssl/tls13con.h
index f6f52511d..4b3bb321e 100644
--- a/lib/ssl/tls13con.h
+++ b/lib/ssl/tls13con.h
@@ -52,6 +52,7 @@ SSLHashType tls13_GetHash(const sslSocket *ss);
unsigned int tls13_GetHashSizeForHash(SSLHashType hash);
unsigned int tls13_GetHashSize(const sslSocket *ss);
CK_MECHANISM_TYPE tls13_GetHkdfMechanism(sslSocket *ss);
+CK_MECHANISM_TYPE tls13_GetHkdfMechanismForHash(SSLHashType hash);
SECStatus tls13_ComputeHash(sslSocket *ss, SSL3Hashes *hashes,
const PRUint8 *buf, unsigned int len);
SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss,
@@ -130,6 +131,11 @@ SECStatus tls13_SendKeyUpdate(sslSocket *ss, tls13KeyUpdateRequest request,
SECStatus SSLExp_KeyUpdate(PRFileDesc *fd, PRBool requestUpdate);
PRBool tls13_MaybeTls13(sslSocket *ss);
SSLAEADCipher tls13_GetAead(const ssl3BulkCipherDef *cipherDef);
+SECStatus tls13_AEAD(const ssl3KeyMaterial *keys, PRBool doDecrypt,
+ unsigned char *out, unsigned int *outlen, unsigned int maxout,
+ const unsigned char *in, unsigned int inlen,
+ CK_MECHANISM_TYPE mechanism,
+ unsigned char *aeadParams, unsigned int aeadParamLength);
void tls13_SetSpecRecordVersion(sslSocket *ss, ssl3CipherSpec *spec);
SECStatus SSLExp_SendCertificateRequest(PRFileDesc *fd);
diff --git a/lib/ssl/tls13esni.c b/lib/ssl/tls13esni.c
index e2328769b..13b70de79 100644
--- a/lib/ssl/tls13esni.c
+++ b/lib/ssl/tls13esni.c
@@ -721,8 +721,8 @@ tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
}
SECStatus
-tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
- PRUint8 *out, int *outLen, int maxLen)
+tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxLen)
{
sslReader rdr = SSL_READER(in, inLen);
PRUint64 suite;
diff --git a/lib/ssl/tls13esni.h b/lib/ssl/tls13esni.h
index 6c52c9952..0fb12d25e 100644
--- a/lib/ssl/tls13esni.h
+++ b/lib/ssl/tls13esni.h
@@ -45,7 +45,7 @@ SECStatus tls13_ComputeESNIKeys(const sslSocket *ss,
SECStatus tls13_FormatEsniAADInput(sslBuffer *aadInput,
PRUint8 *keyShare, unsigned int keyShareLen);
-SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
- PRUint8 *out, int *outLen, int maxLen);
+SECStatus tls13_ServerDecryptEsniXtn(const sslSocket *ss, const PRUint8 *in, unsigned int inLen,
+ PRUint8 *out, unsigned int *outLen, unsigned int maxLen);
#endif
diff --git a/lib/ssl/tls13exthandle.c b/lib/ssl/tls13exthandle.c
index 5ecc2e796..9def16d41 100644
--- a/lib/ssl/tls13exthandle.c
+++ b/lib/ssl/tls13exthandle.c
@@ -1140,7 +1140,7 @@ tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
ssl3KeyMaterial keyMat;
SSLAEADCipher aead;
PRUint8 outBuf[1024];
- int outLen;
+ unsigned int outLen;
unsigned int sniStart;
unsigned int sniLen;
sslBuffer aadInput = SSL_BUFFER_EMPTY;
@@ -1294,7 +1294,7 @@ tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
sslReadBuffer buf;
PRUint8 *plainText = NULL;
- int ptLen;
+ unsigned int ptLen;
SECStatus rv;
/* If we are doing < TLS 1.3, then ignore this. */