diff options
-rw-r--r-- | cpputil/scoped_ptrs_ssl.h | 2 | ||||
-rw-r--r-- | gtests/ssl_gtest/manifest.mn | 1 | ||||
-rw-r--r-- | gtests/ssl_gtest/ssl_gtest.gyp | 1 | ||||
-rw-r--r-- | gtests/ssl_gtest/ssl_primitive_unittest.cc | 186 | ||||
-rw-r--r-- | gtests/ssl_gtest/tls_hkdf_unittest.cc | 23 | ||||
-rw-r--r-- | gtests/ssl_gtest/tls_protect.cc | 154 | ||||
-rw-r--r-- | gtests/ssl_gtest/tls_protect.h | 48 | ||||
-rw-r--r-- | lib/ssl/manifest.mn | 1 | ||||
-rw-r--r-- | lib/ssl/ssl.gyp | 1 | ||||
-rw-r--r-- | lib/ssl/ssl3con.c | 63 | ||||
-rw-r--r-- | lib/ssl/sslexp.h | 51 | ||||
-rw-r--r-- | lib/ssl/sslimpl.h | 21 | ||||
-rw-r--r-- | lib/ssl/sslprimitive.c | 188 | ||||
-rw-r--r-- | lib/ssl/sslsock.c | 4 | ||||
-rw-r--r-- | lib/ssl/sslspec.h | 16 | ||||
-rw-r--r-- | lib/ssl/tls13con.c | 88 | ||||
-rw-r--r-- | lib/ssl/tls13con.h | 6 | ||||
-rw-r--r-- | lib/ssl/tls13esni.c | 4 | ||||
-rw-r--r-- | lib/ssl/tls13esni.h | 4 | ||||
-rw-r--r-- | lib/ssl/tls13exthandle.c | 4 |
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_, ¶m, out, &uoutlen, maxlen, in, inlen); - } else { - rv = PK11_Encrypt(key_, mech_, ¶m, 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, ¶m, - out, &uOutLen, maxout, in, inlen); - } else { - rv = PK11_Encrypt(keys->key, mechanism, ¶m, - out, &uOutLen, maxout, in, inlen); + return PK11_Decrypt(keys->key, mechanism, ¶m, + out, outlen, maxout, in, inlen); } - *outlen = (int)uOutLen; - - return rv; + return PK11_Encrypt(keys->key, mechanism, ¶m, + 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. */ |