From 8cb4c934437a4da0048e41c921296bb31b081443 Mon Sep 17 00:00:00 2001 From: EKR Date: Fri, 2 Dec 2016 14:43:49 -0500 Subject: [PATCH] Bug 1372001 - Refactor out encrypt-to-self into a self-contained interface. r=mt Summary: This cleans up the ticket encryption code and also prepares us for encrypt-to-self for hash state with HRR. Note that I eventually plan to move the self encrypt management functions from sslsnce.c, but I want to do it in a followup patch to make seeing the changes here (mostly rename in that block) easier. Reviewers: mt Differential Revision: https://nss-review.dev.mozaws.net/D329 --- gtests/ssl_gtest/libssl_internals.c | 12 +- gtests/ssl_gtest/libssl_internals.h | 3 +- gtests/ssl_gtest/manifest.mn | 1 + gtests/ssl_gtest/selfencrypt_unittest.cc | 279 +++++++++++++ gtests/ssl_gtest/ssl_fuzz_unittest.cc | 9 +- gtests/ssl_gtest/ssl_gtest.gyp | 1 + gtests/ssl_gtest/ssl_resumption_unittest.cc | 26 +- gtests/ssl_gtest/tls_connect.cc | 6 +- lib/ssl/manifest.mn | 2 + lib/ssl/selfencrypt.c | 314 ++++++++++++++ lib/ssl/selfencrypt.h | 33 ++ lib/ssl/ssl.gyp | 2 + lib/ssl/ssl.h | 3 + lib/ssl/ssl3con.c | 13 - lib/ssl/ssl3encode.c | 85 ++++ lib/ssl/ssl3encode.h | 26 ++ lib/ssl/ssl3exthandle.c | 434 ++------------------ lib/ssl/ssl3prot.h | 15 +- lib/ssl/sslcert.c | 2 +- lib/ssl/sslimpl.h | 17 +- lib/ssl/sslsnce.c | 223 +++++----- 21 files changed, 958 insertions(+), 548 deletions(-) create mode 100644 gtests/ssl_gtest/selfencrypt_unittest.cc create mode 100644 lib/ssl/selfencrypt.c create mode 100644 lib/ssl/selfencrypt.h create mode 100644 lib/ssl/ssl3encode.c create mode 100644 lib/ssl/ssl3encode.h diff --git a/gtests/ssl_gtest/libssl_internals.c b/gtests/ssl_gtest/libssl_internals.c index 32ffcb6f4a..97b8354aec 100644 --- a/gtests/ssl_gtest/libssl_internals.c +++ b/gtests/ssl_gtest/libssl_internals.c @@ -10,6 +10,7 @@ #include "nss.h" #include "pk11pub.h" #include "seccomon.h" +#include "selfencrypt.h" SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd) { sslSocket *ss = ssl_FindSocket(fd); @@ -55,7 +56,16 @@ PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) { return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext)); } -void SSLInt_ClearSessionTicketKey() { ssl_ResetSessionTicketKeys(); } +void SSLInt_ClearSelfEncryptKey() { ssl_ResetSelfEncryptKeys(); } + +sslSelfEncryptKeys *ssl_GetSelfEncryptKeysInt(); + +void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key) { + sslSelfEncryptKeys *keys = ssl_GetSelfEncryptKeysInt(); + + PK11_FreeSymKey(keys->macKey); + keys->macKey = key; +} SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu) { sslSocket *ss = ssl_FindSocket(fd); diff --git a/gtests/ssl_gtest/libssl_internals.h b/gtests/ssl_gtest/libssl_internals.h index 531c31ffc7..33709c4b4e 100644 --- a/gtests/ssl_gtest/libssl_internals.h +++ b/gtests/ssl_gtest/libssl_internals.h @@ -22,7 +22,8 @@ SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd, size_t msg_len); PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext); -void SSLInt_ClearSessionTicketKey(); +void SSLInt_ClearSelfEncryptKey(); +void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key); PRInt32 SSLInt_CountTls13CipherSpecs(PRFileDesc *fd); void SSLInt_PrintTls13CipherSpecs(PRFileDesc *fd); void SSLInt_ForceTimerExpiry(PRFileDesc *fd); diff --git a/gtests/ssl_gtest/manifest.mn b/gtests/ssl_gtest/manifest.mn index e3775cc044..00e63cbc31 100644 --- a/gtests/ssl_gtest/manifest.mn +++ b/gtests/ssl_gtest/manifest.mn @@ -40,6 +40,7 @@ CPPSRCS = \ ssl_v2_client_hello_unittest.cc \ ssl_version_unittest.cc \ ssl_versionpolicy_unittest.cc \ + selfencrypt_unittest.cc \ test_io.cc \ tls_agent.cc \ tls_connect.cc \ diff --git a/gtests/ssl_gtest/selfencrypt_unittest.cc b/gtests/ssl_gtest/selfencrypt_unittest.cc new file mode 100644 index 0000000000..059c4abb0f --- /dev/null +++ b/gtests/ssl_gtest/selfencrypt_unittest.cc @@ -0,0 +1,279 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include +#include +#include "nss.h" +#include "pk11pub.h" +#include "prerror.h" +#include "secerr.h" +#include "sslerr.h" +extern "C" { +#include "selfencrypt.h" +} + +#include "databuffer.h" +#include "gtest_utils.h" +#include "scoped_ptrs.h" + +namespace nss_test { + +static const uint8_t kAesKey1Buf[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f}; +static const DataBuffer kAesKey1(kAesKey1Buf, sizeof(kAesKey1Buf)); + +static const uint8_t kAesKey2Buf[] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1f}; +static const DataBuffer kAesKey2(kAesKey2Buf, sizeof(kAesKey2Buf)); + +static const uint8_t kHmacKey1Buf[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}; +static const DataBuffer kHmacKey1(kHmacKey1Buf, sizeof(kHmacKey1Buf)); + +static const uint8_t kHmacKey2Buf[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, + 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f}; +static const DataBuffer kHmacKey2(kHmacKey2Buf, sizeof(kHmacKey2Buf)); + +static const uint8_t* kKeyName1 = + reinterpret_cast("KEY1KEY1KEY1KEY1"); +static const uint8_t* kKeyName2 = + reinterpret_cast("KEY2KEY2KEY2KEY2"); + +static void ImportKey(const DataBuffer& key, PK11SlotInfo* slot, + CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TYPE cka, + ScopedPK11SymKey* to) { + SECItem key_item = {siBuffer, const_cast(key.data()), + static_cast(key.len())}; + + PK11SymKey* inner = + PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, cka, &key_item, nullptr); + ASSERT_NE(nullptr, inner); + to->reset(inner); +} + +extern "C" { +extern char ssl_trace; +extern FILE* ssl_trace_iob; +} + +class SelfEncryptTestBase : public ::testing::Test { + public: + SelfEncryptTestBase(size_t message_size) + : aes1_(), + aes2_(), + hmac1_(), + hmac2_(), + message_(), + slot_(PK11_GetInternalSlot()) { + EXPECT_NE(nullptr, slot_); + char* ev = getenv("SSLTRACE"); + if (ev && ev[0]) { + ssl_trace = atoi(ev); + ssl_trace_iob = stderr; + } + message_.Allocate(message_size); + for (size_t i = 0; i < message_.len(); ++i) { + message_.data()[i] = i; + } + } + + void SetUp() { + message_.Allocate(100); + for (size_t i = 0; i < 100; ++i) { + message_.data()[i] = i; + } + ImportKey(kAesKey1, slot_.get(), CKM_AES_CBC, CKA_ENCRYPT, &aes1_); + ImportKey(kAesKey2, slot_.get(), CKM_AES_CBC, CKA_ENCRYPT, &aes2_); + ImportKey(kHmacKey1, slot_.get(), CKM_SHA256_HMAC, CKA_SIGN, &hmac1_); + ImportKey(kHmacKey2, slot_.get(), CKM_SHA256_HMAC, CKA_SIGN, &hmac2_); + } + + void SelfTest( + const uint8_t* writeKeyName, const ScopedPK11SymKey& writeAes, + const ScopedPK11SymKey& writeHmac, const uint8_t* readKeyName, + const ScopedPK11SymKey& readAes, const ScopedPK11SymKey& readHmac, + PRErrorCode protect_error_code = 0, PRErrorCode unprotect_error_code = 0, + std::function + mutate = nullptr) { + uint8_t ciphertext[1000]; + unsigned int ciphertext_len; + uint8_t plaintext[1000]; + unsigned int plaintext_len; + + SECStatus rv = ssl_SelfEncryptProtectInt( + writeAes.get(), writeHmac.get(), writeKeyName, message_.data(), + message_.len(), ciphertext, &ciphertext_len, sizeof(ciphertext)); + if (rv != SECSuccess) { + std::cerr << "Error: " << PORT_ErrorToName(PORT_GetError()) << std::endl; + } + if (protect_error_code) { + ASSERT_EQ(protect_error_code, PORT_GetError()); + return; + } + ASSERT_EQ(SECSuccess, rv); + + if (mutate) { + mutate(ciphertext, &ciphertext_len); + } + rv = ssl_SelfEncryptUnprotectInt(readAes.get(), readHmac.get(), readKeyName, + ciphertext, ciphertext_len, plaintext, + &plaintext_len, sizeof(plaintext)); + if (rv != SECSuccess) { + std::cerr << "Error: " << PORT_ErrorToName(PORT_GetError()) << std::endl; + } + if (!unprotect_error_code) { + ASSERT_EQ(SECSuccess, rv); + EXPECT_EQ(message_.len(), plaintext_len); + EXPECT_EQ(0, memcmp(message_.data(), plaintext, message_.len())); + } else { + ASSERT_EQ(SECFailure, rv); + EXPECT_EQ(unprotect_error_code, PORT_GetError()); + } + } + + protected: + ScopedPK11SymKey aes1_; + ScopedPK11SymKey aes2_; + ScopedPK11SymKey hmac1_; + ScopedPK11SymKey hmac2_; + DataBuffer message_; + + private: + ScopedPK11SlotInfo slot_; +}; + +class SelfEncryptTestVariable : public SelfEncryptTestBase, + public ::testing::WithParamInterface { + public: + SelfEncryptTestVariable() : SelfEncryptTestBase(GetParam()) {} +}; + +class SelfEncryptTest128 : public SelfEncryptTestBase { + public: + SelfEncryptTest128() : SelfEncryptTestBase(128) {} +}; + +TEST_P(SelfEncryptTestVariable, SuccessCase) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_); +} + +TEST_P(SelfEncryptTestVariable, WrongMacKey) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac2_, 0, + SEC_ERROR_BAD_DATA); +} + +TEST_P(SelfEncryptTestVariable, WrongKeyName) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName2, aes1_, hmac1_, 0, + SEC_ERROR_NOT_A_RECIPIENT); +} + +TEST_P(SelfEncryptTestVariable, AddAByte) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + (*ciphertext_len)++; + }); +} + +TEST_P(SelfEncryptTestVariable, SubtractAByte) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + (*ciphertext_len)--; + }); +} + +TEST_P(SelfEncryptTestVariable, BogusIv) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + ciphertext[16]++; + }); +} + +TEST_P(SelfEncryptTestVariable, BogusCiphertext) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + ciphertext[32]++; + }); +} + +TEST_P(SelfEncryptTestVariable, BadMac) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + ciphertext[*ciphertext_len - 1]++; + }); +} + +TEST_F(SelfEncryptTest128, DISABLED_BadPadding) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes2_, hmac1_, 0, + SEC_ERROR_BAD_DATA); +} + +TEST_F(SelfEncryptTest128, ShortKeyName) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + *ciphertext_len = 15; + }); +} + +TEST_F(SelfEncryptTest128, ShortIv) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + *ciphertext_len = 31; + }); +} + +TEST_F(SelfEncryptTest128, ShortCiphertextLen) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + *ciphertext_len = 32; + }); +} + +TEST_F(SelfEncryptTest128, ShortCiphertext) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, hmac1_, 0, + SEC_ERROR_BAD_DATA, + [](uint8_t* ciphertext, unsigned int* ciphertext_len) { + *ciphertext_len -= 17; + }); +} + +TEST_F(SelfEncryptTest128, MacWithAESKeyEncrypt) { + SelfTest(kKeyName1, aes1_, aes1_, kKeyName1, aes1_, hmac1_, + SEC_ERROR_LIBRARY_FAILURE); +} + +TEST_F(SelfEncryptTest128, AESWithMacKeyEncrypt) { + SelfTest(kKeyName1, hmac1_, hmac1_, kKeyName1, aes1_, hmac1_, + SEC_ERROR_INVALID_KEY); +} + +TEST_F(SelfEncryptTest128, MacWithAESKeyDecrypt) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, aes1_, aes1_, 0, + SEC_ERROR_LIBRARY_FAILURE); +} + +TEST_F(SelfEncryptTest128, AESWithMacKeyDecrypt) { + SelfTest(kKeyName1, aes1_, hmac1_, kKeyName1, hmac1_, hmac1_, 0, + SEC_ERROR_INVALID_KEY); +} + +INSTANTIATE_TEST_CASE_P(VariousSizes, SelfEncryptTestVariable, + ::testing::Values(0, 15, 16, 31, 255, 256, 257)); + +} // namespace nss_test diff --git a/gtests/ssl_gtest/ssl_fuzz_unittest.cc b/gtests/ssl_gtest/ssl_fuzz_unittest.cc index d08a0b60c1..1587b66de9 100644 --- a/gtests/ssl_gtest/ssl_fuzz_unittest.cc +++ b/gtests/ssl_gtest/ssl_fuzz_unittest.cc @@ -281,13 +281,8 @@ FUZZ_P(TlsConnectGeneric, UnencryptedSessionTickets) { offset += 1 + 1 + /* ke_modes */ 1 + 1; /* auth_modes */ } - - offset += 2 + /* ticket length */ - 16 + /* SESS_TICKET_KEY_NAME_LEN */ - 16 + /* AES-128 IV */ - 2 + /* ciphertext length */ - 2; /* TLS_EX_SESS_TICKET_VERSION */ - + offset += 2 + /* ticket length */ + 2; /* TLS_EX_SESS_TICKET_VERSION */ // Check the protocol version number. uint32_t tls_version = 0; EXPECT_TRUE(i1->buffer().Read(offset, sizeof(version_), &tls_version)); diff --git a/gtests/ssl_gtest/ssl_gtest.gyp b/gtests/ssl_gtest/ssl_gtest.gyp index f0b96d6e54..5dbe4cba5d 100644 --- a/gtests/ssl_gtest/ssl_gtest.gyp +++ b/gtests/ssl_gtest/ssl_gtest.gyp @@ -12,6 +12,7 @@ 'type': 'executable', 'sources': [ 'libssl_internals.c', + 'selfencrypt_unittest.cc', 'ssl_0rtt_unittest.cc', 'ssl_agent_unittest.cc', 'ssl_auth_unittest.cc', diff --git a/gtests/ssl_gtest/ssl_resumption_unittest.cc b/gtests/ssl_gtest/ssl_resumption_unittest.cc index 7b43870b00..ce0e3ca8db 100644 --- a/gtests/ssl_gtest/ssl_resumption_unittest.cc +++ b/gtests/ssl_gtest/ssl_resumption_unittest.cc @@ -258,6 +258,30 @@ TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtServer) { CheckConnected(); } +TEST_P(TlsConnectGeneric, ConnectResumeCorruptTicket) { + // This causes a ticket resumption. + ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); + Connect(); + SendReceive(); + + Reset(); + static const uint8_t kHmacKey1Buf[32] = {0}; + static const DataBuffer kHmacKey1(kHmacKey1Buf, sizeof(kHmacKey1Buf)); + + SECItem key_item = {siBuffer, const_cast(kHmacKey1Buf), + sizeof(kHmacKey1Buf)}; + + ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + PK11SymKey* hmac_key = + PK11_ImportSymKey(slot.get(), CKM_SHA256_HMAC, PK11_OriginUnwrap, + CKA_SIGN, &key_item, nullptr); + ASSERT_NE(nullptr, hmac_key); + SSLInt_SetSelfEncryptMacKey(hmac_key); + ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET); + ConnectExpectAlert(server_, illegal_parameter); + server_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); +} + // This callback switches out the "server" cert used on the server with // the "client" certificate, which should be the same type. static int32_t SwitchCertificates(TlsAgent* agent, const SECItem* srvNameArr, @@ -627,7 +651,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionDuplicateNST) { Connect(); // Clear the session ticket keys to invalidate the old ticket. - SSLInt_ClearSessionTicketKey(); + SSLInt_ClearSelfEncryptKey(); SSLInt_SendNewSessionTicket(server_->ssl_fd()); SendReceive(); // Need to read so that we absorb the session tickets. diff --git a/gtests/ssl_gtest/tls_connect.cc b/gtests/ssl_gtest/tls_connect.cc index 861d162ae3..c8de5a1fee 100644 --- a/gtests/ssl_gtest/tls_connect.cc +++ b/gtests/ssl_gtest/tls_connect.cc @@ -169,13 +169,13 @@ void TlsConnectTestBase::ClearStats() { void TlsConnectTestBase::ClearServerCache() { SSL_ShutdownServerSessionIDCache(); - SSLInt_ClearSessionTicketKey(); + SSLInt_ClearSelfEncryptKey(); SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str()); } void TlsConnectTestBase::SetUp() { SSL_ConfigServerSessionIDCache(1024, 0, 0, g_working_dir_path.c_str()); - SSLInt_ClearSessionTicketKey(); + SSLInt_ClearSelfEncryptKey(); SSLInt_SetTicketLifetime(30); SSLInt_SetMaxEarlyDataSize(1024); ClearStats(); @@ -187,7 +187,7 @@ void TlsConnectTestBase::TearDown() { server_ = nullptr; SSL_ClearSessionCache(); - SSLInt_ClearSessionTicketKey(); + SSLInt_ClearSelfEncryptKey(); SSL_ShutdownServerSessionIDCache(); } diff --git a/lib/ssl/manifest.mn b/lib/ssl/manifest.mn index e7564edb2b..fbb88baffa 100644 --- a/lib/ssl/manifest.mn +++ b/lib/ssl/manifest.mn @@ -25,6 +25,7 @@ CSRCS = \ sslauth.c \ sslcon.c \ ssldef.c \ + ssl3encode.c \ sslenum.c \ sslerr.c \ sslerrstrs.c \ @@ -41,6 +42,7 @@ CSRCS = \ sslver.c \ authcert.c \ cmpcert.c \ + selfencrypt.c \ sslinfo.c \ ssl3ecc.c \ tls13con.c \ diff --git a/lib/ssl/selfencrypt.c b/lib/ssl/selfencrypt.c new file mode 100644 index 0000000000..6d6e25cfc6 --- /dev/null +++ b/lib/ssl/selfencrypt.c @@ -0,0 +1,314 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * 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 "nss.h" +#include "blapit.h" +#include "pk11func.h" +#include "ssl.h" +#include "sslt.h" +#include "ssl3encode.h" +#include "sslimpl.h" +#include "selfencrypt.h" + +static SECStatus +ssl_MacBuffer(PK11SymKey *key, CK_MECHANISM_TYPE mech, + const unsigned char *in, unsigned int len, + unsigned char *mac, unsigned int *macLen, unsigned int maxMacLen) +{ + PK11Context *ctx; + SECItem macParam = { 0, NULL, 0 }; + unsigned int computedLen; + SECStatus rv; + + ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam); + if (!ctx) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + rv = PK11_DigestBegin(ctx); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + rv = PK11_DigestOp(ctx, in, len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + *macLen = maxMacLen; + PK11_DestroyContext(ctx, PR_TRUE); + return SECSuccess; + +loser: + PK11_DestroyContext(ctx, PR_TRUE); + return SECFailure; +} + +#ifdef UNSAFE_FUZZER_MODE +SECStatus +ssl_SelfEncryptProtectInt( + PK11SymKey *encKey, PK11SymKey *macKey, + const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + if (inLen > maxOutLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Memcpy(out, in, inLen); + *outLen = inLen; + + return 0; +} + +SECStatus +ssl_SelfEncryptUnprotectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + if (inLen > maxOutLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Memcpy(out, in, inLen); + *outLen = inLen; + + return 0; +} + +#else +/* + * Structure is. + * + * struct { + * opaque keyName[16]; + * opaque iv[16]; + * opaque ciphertext<16..2^16-1>; + * opaque mac[32]; + * } SelfEncrypted; + * + * We are using AES-CBC + HMAC-SHA256 in Encrypt-then-MAC mode for + * two reasons: + * + * 1. It's what we already used for tickets. + * 2. We don't have to worry about nonce collisions as much + * (the chance is lower because we have a random 128-bit nonce + * and they are less serious than with AES-GCM). + */ +SECStatus +ssl_SelfEncryptProtectInt( + PK11SymKey *encKey, PK11SymKey *macKey, + const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + unsigned int len; + unsigned char iv[AES_BLOCK_SIZE]; + SECItem ivItem = { siBuffer, iv, sizeof(iv) }; + unsigned char mac[SHA256_LENGTH]; /* SHA-256 */ + unsigned int macLen; + SECItem outItem = { siBuffer, out, maxOutLen }; + SECItem lengthBytesItem; + SECStatus rv; + + /* Generate a random IV */ + rv = PK11_GenerateRandom(iv, sizeof(iv)); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + /* Add header. */ + rv = ssl3_AppendToItem(&outItem, keyName, SELF_ENCRYPT_KEY_NAME_LEN); + if (rv != SECSuccess) { + return SECFailure; + } + rv = ssl3_AppendToItem(&outItem, iv, sizeof(iv)); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Skip forward by two so we can encode the ciphertext in place. */ + lengthBytesItem = outItem; + rv = ssl3_AppendNumberToItem(&outItem, 0, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, + outItem.data, &len, outItem.len, in, inLen); + if (rv != SECSuccess) { + return SECFailure; + } + + outItem.data += len; + outItem.len -= len; + + /* Now encode the ciphertext length. */ + rv = ssl3_AppendNumberToItem(&lengthBytesItem, len, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + /* MAC the entire output buffer and append the MAC to the end. */ + rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, + out, outItem.data - out, + mac, &macLen, sizeof(mac)); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Assert(macLen == sizeof(mac)); + + rv = ssl3_AppendToItem(&outItem, mac, macLen); + if (rv != SECSuccess) { + return SECFailure; + } + + *outLen = outItem.data - out; + return SECSuccess; +} + +SECStatus +ssl_SelfEncryptUnprotectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + unsigned char *encodedKeyName; + unsigned char *iv; + SECItem ivItem = { siBuffer, NULL, 0 }; + SECItem inItem = { siBuffer, (unsigned char *)in, inLen }; + unsigned char *cipherText; + PRUint32 cipherTextLen; + unsigned char *encodedMac; + unsigned char computedMac[SHA256_LENGTH]; + unsigned int computedMacLen; + unsigned int bytesToMac; + SECStatus rv; + + rv = ssl3_ConsumeFromItem(&inItem, &encodedKeyName, + SELF_ENCRYPT_KEY_NAME_LEN); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl3_ConsumeFromItem(&inItem, &iv, AES_BLOCK_SIZE); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl3_ConsumeNumberFromItem(&inItem, &cipherTextLen, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl3_ConsumeFromItem(&inItem, &cipherText, cipherTextLen); + if (rv != SECSuccess) { + return SECFailure; + } + bytesToMac = inItem.data - in; + + rv = ssl3_ConsumeFromItem(&inItem, &encodedMac, SHA256_LENGTH); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Make sure we're at the end of the block. */ + if (inItem.len) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + /* Now that everything is decoded, we can make progress. */ + /* 1. Check that we have the right key. */ + if (PORT_Memcmp(keyName, encodedKeyName, SELF_ENCRYPT_KEY_NAME_LEN)) { + PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT); + return SECFailure; + } + + /* 2. Check the MAC */ + rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac, + computedMac, &computedMacLen, sizeof(computedMac)); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Assert(computedMacLen == SHA256_LENGTH); + if (NSS_SecureMemcmp(computedMac, encodedMac, computedMacLen) != 0) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + /* 3. OK, it verifies, now decrypt. */ + ivItem.data = iv; + ivItem.len = AES_BLOCK_SIZE; + rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem, + out, outLen, maxOutLen, cipherText, cipherTextLen); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; +} +#endif + +SECStatus +ssl_SelfEncryptProtect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; + PK11SymKey *encKey; + PK11SymKey *macKey; + SECStatus rv; + + /* Get session ticket keys. */ + rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.", + SSL_GETPID(), ss->fd)); + return SECFailure; + } + + return ssl_SelfEncryptProtectInt(encKey, macKey, keyName, + in, inLen, out, outLen, maxOutLen); +} + +SECStatus +ssl_SelfEncryptUnprotect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; + PK11SymKey *encKey; + PK11SymKey *macKey; + SECStatus rv; + + /* Get session ticket keys. */ + rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.", + SSL_GETPID(), ss->fd)); + return SECFailure; + } + + return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName, + in, inLen, out, outLen, maxOutLen); +} diff --git a/lib/ssl/selfencrypt.h b/lib/ssl/selfencrypt.h new file mode 100644 index 0000000000..32464a02f2 --- /dev/null +++ b/lib/ssl/selfencrypt.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * 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/. */ + +#ifndef __selfencrypt_h_ +#define __selfencrypt_h_ + +#include "secmodt.h" + +typedef struct sslSocketStr sslSocket; /* Forward declaration. */ + +SECStatus ssl_SelfEncryptProtect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); +SECStatus ssl_SelfEncryptUnprotect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); + +/* Exported for use in unit tests.*/ +SECStatus ssl_SelfEncryptProtectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); +SECStatus ssl_SelfEncryptUnprotectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); + +#endif diff --git a/lib/ssl/ssl.gyp b/lib/ssl/ssl.gyp index 175d1cecfa..03b2d6014a 100644 --- a/lib/ssl/ssl.gyp +++ b/lib/ssl/ssl.gyp @@ -14,8 +14,10 @@ 'cmpcert.c', 'dtlscon.c', 'prelib.c', + 'selfencrypt.c', 'ssl3con.c', 'ssl3ecc.c', + 'ssl3encode.c', 'ssl3ext.c', 'ssl3exthandle.c', 'ssl3gthr.c', diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h index f19c2defb4..d309d8935f 100644 --- a/lib/ssl/ssl.h +++ b/lib/ssl/ssl.h @@ -942,6 +942,9 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, ** associated with a configured certificate to perform session ticket ** encryption. If this function isn't used, the keys provided with a configured ** RSA certificate are used for wrapping session ticket keys. +** +** NOTE: This key is used for all self-encryption but is named for +** session tickets for historical reasons. */ SSL_IMPORT SECStatus SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey); diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c index edad2f5186..6604930030 100644 --- a/lib/ssl/ssl3con.c +++ b/lib/ssl/ssl3con.c @@ -4394,19 +4394,6 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRUint32 bytes, return SECSuccess; } -/* Helper function to encode an unsigned integer into a buffer. */ -PRUint8 * -ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to) -{ - PRUint64 encoded; - - PORT_Assert(bytes > 0 && bytes <= sizeof(encoded)); - - encoded = PR_htonll(value); - memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes); - return to + bytes; -} - /* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value. * If the hash is not recognised, SEC_OID_UNKNOWN is returned. * diff --git a/lib/ssl/ssl3encode.c b/lib/ssl/ssl3encode.c new file mode 100644 index 0000000000..960208a0f7 --- /dev/null +++ b/lib/ssl/ssl3encode.c @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * 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 "prnetdb.h" +#include "seccomon.h" +#include "secerr.h" +#include "ssl3encode.h" + +SECStatus +ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes) +{ + if (bytes > item->len) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Memcpy(item->data, buf, bytes); + item->data += bytes; + item->len -= bytes; + return SECSuccess; +} + +SECStatus +ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize) +{ + SECStatus rv; + PRUint8 b[4]; + + ssl_EncodeUintX(num, lenSize, b); + rv = ssl3_AppendToItem(item, &b[0], lenSize); + return rv; +} + +SECStatus +ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes) +{ + if (bytes > item->len) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + *buf = item->data; + item->data += bytes; + item->len -= bytes; + return SECSuccess; +} + +SECStatus +ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, PRUint32 bytes) +{ + int i; + + if (bytes > item->len || bytes > sizeof(*num)) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + *num = 0; + for (i = 0; i < bytes; i++) { + *num = (*num << 8) + item->data[i]; + } + + item->data += bytes; + item->len -= bytes; + + return SECSuccess; +} + +/* Helper function to encode an unsigned integer into a buffer. */ +PRUint8 * +ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to) +{ + PRUint64 encoded; + + PORT_Assert(bytes > 0 && bytes <= sizeof(encoded)); + + encoded = PR_htonll(value); + memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes); + return to + bytes; +} diff --git a/lib/ssl/ssl3encode.h b/lib/ssl/ssl3encode.h new file mode 100644 index 0000000000..3b88f7e7b3 --- /dev/null +++ b/lib/ssl/ssl3encode.h @@ -0,0 +1,26 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * 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/. */ + +#ifndef __ssl3encode_h_ +#define __ssl3encode_h_ + +#include "seccomon.h" + +/* All of these functions modify the underlying SECItem, and so should + * be performed on a shallow copy.*/ +SECStatus ssl3_AppendToItem(SECItem *item, + const unsigned char *buf, PRUint32 bytes); +SECStatus ssl3_AppendNumberToItem(SECItem *item, + PRUint32 num, PRInt32 lenSize); +SECStatus ssl3_ConsumeFromItem(SECItem *item, + unsigned char **buf, PRUint32 bytes); +SECStatus ssl3_ConsumeNumberFromItem(SECItem *item, + PRUint32 *num, PRUint32 bytes); +PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to); + +#endif diff --git a/lib/ssl/ssl3exthandle.c b/lib/ssl/ssl3exthandle.c index a89d1c1b4e..370bd8b3e4 100644 --- a/lib/ssl/ssl3exthandle.c +++ b/lib/ssl/ssl3exthandle.c @@ -12,64 +12,12 @@ #include "pk11pub.h" #include "blapit.h" #include "prinit.h" +#include "selfencrypt.h" +#include "ssl3encode.h" #include "ssl3ext.h" #include "ssl3exthandle.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ -static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, - PRUint32 bytes); -static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, - PRUint32 bytes); -static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, - PRInt32 lenSize); - -PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ -#define TLS_EX_SESS_TICKET_VERSION (0x0105) -#define TLS_EX_SESS_TICKET_MAC_LENGTH 32 - -/* - * Write bytes. Using this function means the SECItem structure - * cannot be freed. The caller is expected to call this function - * on a shallow copy of the structure. - */ -static SECStatus -ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes) -{ - if (bytes > item->len) - return SECFailure; - - PORT_Memcpy(item->data, buf, bytes); - item->data += bytes; - item->len -= bytes; - return SECSuccess; -} - -/* - * Write a number in network byte order. Using this function means the - * SECItem structure cannot be freed. The caller is expected to call - * this function on a shallow copy of the structure. - */ -static SECStatus -ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize) -{ - SECStatus rv; - PRUint8 b[4]; - PRUint8 *p = b; - - switch (lenSize) { - case 4: - *p++ = (PRUint8)(num >> 24); - case 3: - *p++ = (PRUint8)(num >> 16); - case 2: - *p++ = (PRUint8)(num >> 8); - case 1: - *p = (PRUint8)num; - } - rv = ssl3_AppendToItem(item, &b[0], lenSize); - return rv; -} - /* Format an SNI extension, using the name from the socket's URL, * unless that name is a dotted decimal string. * Used by client and server. @@ -330,34 +278,6 @@ ssl3_SendSessionTicketXtn( return -1; } -static SECStatus -ssl3_ParseEncryptedSessionTicket(sslSocket *ss, const SECItem *data, - EncryptedSessionTicket *encryptedTicket) -{ - SECItem copy = *data; - - if (ssl3_ConsumeFromItem(©, &encryptedTicket->key_name, - SESS_TICKET_KEY_NAME_LEN) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeFromItem(©, &encryptedTicket->iv, - AES_BLOCK_SIZE) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeHandshakeVariable(ss, &encryptedTicket->encrypted_state, - 2, ©.data, ©.len) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeFromItem(©, &encryptedTicket->mac, - TLS_EX_SESS_TICKET_MAC_LENGTH) != - SECSuccess) - return SECFailure; - if (copy.len != 0) /* Make sure that we have consumed all bytes. */ - return SECFailure; - - return SECSuccess; -} - PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) { @@ -881,6 +801,9 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } +PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ +#define TLS_EX_SESS_TICKET_VERSION (0x0105) + /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ @@ -889,32 +812,16 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, SECItem *ticket_data) { - PRUint32 i; SECStatus rv; SECItem plaintext; SECItem plaintext_item = { 0, NULL, 0 }; - SECItem ciphertext = { 0, NULL, 0 }; - PRUint32 ciphertext_length; + PRUint32 plaintext_length; SECItem ticket_buf = { 0, NULL, 0 }; - SECItem ticket_tmp = { 0, NULL, 0 }; - SECItem macParam = { 0, NULL, 0 }; PRBool ms_is_wrapped; unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; SECItem ms_item = { 0, NULL, 0 }; - PRUint32 padding_length; - PRUint32 ticket_length; PRUint32 cert_length = 0; - PRUint8 length_buf[4]; PRUint32 now; - unsigned char key_name[SESS_TICKET_KEY_NAME_LEN]; - PK11SymKey *aes_key = NULL; - PK11SymKey *mac_key = NULL; - PK11Context *aes_ctx; - PK11Context *hmac_ctx = NULL; - unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; - unsigned int computed_mac_length; - unsigned char iv[AES_BLOCK_SIZE]; - SECItem ivItem; SECItem *srvName = NULL; CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, * must be >= 0 */ @@ -931,17 +838,6 @@ ssl3_EncodeSessionTicket(sslSocket *ss, cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len; } - /* Get IV and encryption keys */ - ivItem.data = iv; - ivItem.len = sizeof(iv); - rv = PK11_GenerateRandom(iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - - rv = ssl_GetSessionTicketKeys(ss, key_name, &aes_key, &mac_key); - if (rv != SECSuccess) - goto loser; - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { spec = ss->ssl3.cwSpec; } else { @@ -980,7 +876,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, ss->xtnData.nextProto.len == 0); alpnSelection = &ss->xtnData.nextProto; - ciphertext_length = + plaintext_length = sizeof(PRUint16) /* ticket version */ + sizeof(SSL3ProtocolVersion) /* ssl_version */ + sizeof(ssl3CipherSuite) /* ciphersuite */ @@ -999,16 +895,8 @@ ssl3_EncodeSessionTicket(sslSocket *ss, + sizeof(ticket->flags) /* ticket flags */ + 1 + alpnSelection->len /* alpn value + length field */ + 4; /* maxEarlyData */ -#ifdef UNSAFE_FUZZER_MODE - padding_length = 0; -#else - padding_length = AES_BLOCK_SIZE - - (ciphertext_length % - AES_BLOCK_SIZE); -#endif - ciphertext_length += padding_length; - if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL) + if (SECITEM_AllocItem(NULL, &plaintext_item, plaintext_length) == NULL) goto loser; plaintext = plaintext_item; @@ -1143,117 +1031,36 @@ ssl3_EncodeSessionTicket(sslSocket *ss, if (rv != SECSuccess) goto loser; - PORT_Assert(plaintext.len == padding_length); - for (i = 0; i < padding_length; i++) - plaintext.data[i] = (unsigned char)padding_length; + /* Check that we are totally full. */ + PORT_Assert(plaintext.len == 0); - if (SECITEM_AllocItem(NULL, &ciphertext, ciphertext_length) == NULL) { - rv = SECFailure; + /* 128 just gives us enough room for overhead. */ + if (SECITEM_AllocItem(NULL, &ticket_buf, plaintext_length + 128) == NULL) { goto loser; } - /* Generate encrypted portion of ticket. */ - PORT_Assert(aes_key); -#ifdef UNSAFE_FUZZER_MODE - ciphertext.len = plaintext_item.len; - PORT_Memcpy(ciphertext.data, plaintext_item.data, plaintext_item.len); -#else - aes_ctx = PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_ENCRYPT, aes_key, &ivItem); - if (!aes_ctx) - goto loser; - - rv = PK11_CipherOp(aes_ctx, ciphertext.data, - (int *)&ciphertext.len, ciphertext.len, - plaintext_item.data, plaintext_item.len); - PK11_Finalize(aes_ctx); - PK11_DestroyContext(aes_ctx, PR_TRUE); - if (rv != SECSuccess) - goto loser; -#endif - - /* Convert ciphertext length to network order. */ - (void)ssl_EncodeUintX(ciphertext.len, 2, length_buf); - - /* Compute MAC. */ - PORT_Assert(mac_key); - hmac_ctx = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, mac_key, - &macParam); - if (!hmac_ctx) - goto loser; - - rv = PK11_DigestBegin(hmac_ctx); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, (unsigned char *)length_buf, 2); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, ciphertext.data, ciphertext.len); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestFinal(hmac_ctx, computed_mac, - &computed_mac_length, sizeof(computed_mac)); - if (rv != SECSuccess) - goto loser; - - ticket_length = - +SESS_TICKET_KEY_NAME_LEN /* key_name */ - + AES_BLOCK_SIZE /* iv */ - + 2 /* length field for NewSessionTicket.ticket.encrypted_state */ - + ciphertext_length /* encrypted_state */ - + TLS_EX_SESS_TICKET_MAC_LENGTH; /* mac */ - - if (SECITEM_AllocItem(NULL, &ticket_buf, ticket_length) == NULL) { - rv = SECFailure; + /* Finally, encrypt the ticket. */ + rv = ssl_SelfEncryptProtect(ss, plaintext_item.data, plaintext_item.len, + ticket_buf.data, &ticket_buf.len, ticket_buf.len); + if (rv != SECSuccess) { goto loser; } - ticket_tmp = ticket_buf; /* Shallow copy because AppendToItem is - * destructive. */ - - rv = ssl3_AppendToItem(&ticket_tmp, key_name, SESS_TICKET_KEY_NAME_LEN); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendToItem(&ticket_tmp, iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendNumberToItem(&ticket_tmp, ciphertext.len, 2); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendToItem(&ticket_tmp, ciphertext.data, ciphertext.len); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendToItem(&ticket_tmp, computed_mac, computed_mac_length); - if (rv != SECSuccess) - goto loser; /* Give ownership of memory to caller. */ *ticket_data = ticket_buf; - ticket_buf.data = NULL; + + SECITEM_FreeItem(&plaintext_item, PR_FALSE); + return SECSuccess; loser: - if (hmac_ctx) { - PK11_DestroyContext(hmac_ctx, PR_TRUE); - } if (plaintext_item.data) { SECITEM_FreeItem(&plaintext_item, PR_FALSE); } - if (ciphertext.data) { - SECITEM_FreeItem(&ciphertext, PR_FALSE); - } if (ticket_buf.data) { SECITEM_FreeItem(&ticket_buf, PR_FALSE); } - return rv; + return SECFailure; } /* When a client receives a SessionTicket extension a NewSessionTicket @@ -1272,165 +1079,6 @@ ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } -static SECStatus -ssl_DecryptSessionTicket(sslSocket *ss, const SECItem *rawTicket, - const EncryptedSessionTicket *encryptedTicket, - SECItem *decryptedTicket) -{ - SECStatus rv; - unsigned char keyName[SESS_TICKET_KEY_NAME_LEN]; - - PK11SymKey *macKey = NULL; - PK11Context *hmacCtx; - unsigned char computedMac[TLS_EX_SESS_TICKET_MAC_LENGTH]; - unsigned int computedMacLength; - SECItem macParam = { siBuffer, NULL, 0 }; - - PK11SymKey *aesKey = NULL; -#ifndef UNSAFE_FUZZER_MODE - PK11Context *aesCtx; - SECItem ivItem; - - unsigned int i; - PRUint8 *padding; - PRUint8 paddingLength; -#endif - - PORT_Assert(!decryptedTicket->data); - PORT_Assert(!decryptedTicket->len); - if (rawTicket->len < TLS_EX_SESS_TICKET_MAC_LENGTH) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - return SECFailure; - } - - /* Get session ticket keys. */ - rv = ssl_GetSessionTicketKeys(ss, keyName, &aesKey, &macKey); - if (rv != SECSuccess) { - SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.", - SSL_GETPID(), ss->fd)); - return SECFailure; /* code already set */ - } - - /* If the ticket sent by the client was generated under a key different from - * the one we have, bypass ticket processing. This reports success, meaning - * that the handshake completes, but doesn't resume. - */ - if (PORT_Memcmp(encryptedTicket->key_name, keyName, - SESS_TICKET_KEY_NAME_LEN) != 0) { -#ifndef UNSAFE_FUZZER_MODE - SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.", - SSL_GETPID(), ss->fd)); - return SECSuccess; -#endif - } - - /* Verify the MAC on the ticket. */ - PORT_Assert(macKey); - hmacCtx = PK11_CreateContextBySymKey(CKM_SHA256_HMAC, CKA_SIGN, macKey, - &macParam); - if (!hmacCtx) { - SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.", - SSL_GETPID(), ss->fd, PORT_GetError())); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.", - SSL_GETPID(), ss->fd)); - do { - rv = PK11_DigestBegin(hmacCtx); - if (rv != SECSuccess) { - break; - } - rv = PK11_DigestOp(hmacCtx, rawTicket->data, - rawTicket->len - TLS_EX_SESS_TICKET_MAC_LENGTH); - if (rv != SECSuccess) { - break; - } - rv = PK11_DigestFinal(hmacCtx, computedMac, &computedMacLength, - sizeof(computedMac)); - } while (0); - PK11_DestroyContext(hmacCtx, PR_TRUE); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - if (NSS_SecureMemcmp(computedMac, encryptedTicket->mac, - computedMacLength) != 0) { -#ifndef UNSAFE_FUZZER_MODE - SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.", - SSL_GETPID(), ss->fd)); - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - return SECFailure; -#endif - } - - /* Decrypt the ticket. */ - - /* Plaintext is shorter than the ciphertext due to padding. */ - if (!SECITEM_AllocItem(NULL, decryptedTicket, - encryptedTicket->encrypted_state.len)) { - return SECFailure; /* code already set */ - } - - PORT_Assert(aesKey); -#ifdef UNSAFE_FUZZER_MODE - decryptedTicket->len = encryptedTicket->encrypted_state.len; - PORT_Memcpy(decryptedTicket->data, - encryptedTicket->encrypted_state.data, - encryptedTicket->encrypted_state.len); -#else - ivItem.data = encryptedTicket->iv; - ivItem.len = AES_BLOCK_SIZE; - aesCtx = PK11_CreateContextBySymKey(CKM_AES_CBC, CKA_DECRYPT, aesKey, - &ivItem); - if (!aesCtx) { - SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", - SSL_GETPID(), ss->fd)); - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - do { - rv = PK11_CipherOp(aesCtx, decryptedTicket->data, - (int *)&decryptedTicket->len, decryptedTicket->len, - encryptedTicket->encrypted_state.data, - encryptedTicket->encrypted_state.len); - if (rv != SECSuccess) { - break; - } - rv = PK11_Finalize(aesCtx); - if (rv != SECSuccess) { - break; - } - } while (0); - PK11_DestroyContext(aesCtx, PR_TRUE); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - /* Check padding. */ - paddingLength = decryptedTicket->data[decryptedTicket->len - 1]; - if (paddingLength == 0 || paddingLength > AES_BLOCK_SIZE) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - padding = &decryptedTicket->data[decryptedTicket->len - paddingLength]; - for (i = 0; i < paddingLength; i++, padding++) { - if (paddingLength != *padding) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - } - decryptedTicket->len -= paddingLength; -#endif /* UNSAFE_FUZZER_MODE */ - - return SECSuccess; -} - static SECStatus ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, SessionTicket *parsedTicket) @@ -1735,7 +1383,6 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket, SECStatus ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) { - EncryptedSessionTicket encryptedTicket; SECItem decryptedTicket = { siBuffer, NULL, 0 }; SessionTicket parsedTicket; SECStatus rv; @@ -1746,17 +1393,27 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) ss->sec.ci.sid = NULL; } - rv = ssl3_ParseEncryptedSessionTicket(ss, data, &encryptedTicket); - if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) { return SECFailure; } - rv = ssl_DecryptSessionTicket(ss, data, &encryptedTicket, - &decryptedTicket); + /* Decrypt the ticket. */ + rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len, + decryptedTicket.data, + &decryptedTicket.len, + decryptedTicket.len); if (rv != SECSuccess) { - PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); - return SECFailure; + SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); + + /* Fail with no ticket if we're not a recipient. Otherwise + * it's a hard failure. */ + if (PORT_GetError() != SEC_ERROR_NOT_A_RECIPIENT) { + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + return SECFailure; + } + + /* We didn't have the right key, so pretend we don't have a + * ticket. */ } rv = ssl_ParseSessionTicket(ss, &decryptedTicket, &parsedTicket); @@ -1823,23 +1480,6 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data); } -/* - * Read bytes. Using this function means the SECItem structure - * cannot be freed. The caller is expected to call this function - * on a shallow copy of the structure. - */ -static SECStatus -ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes) -{ - if (bytes > item->len) - return SECFailure; - - *buf = item->data; - item->data += bytes; - item->len -= bytes; - return SECSuccess; -} - /* Extension format: * Extension number: 2 bytes * Extension length: 2 bytes diff --git a/lib/ssl/ssl3prot.h b/lib/ssl/ssl3prot.h index 95cf9baca4..dede24438d 100644 --- a/lib/ssl/ssl3prot.h +++ b/lib/ssl/ssl3prot.h @@ -303,16 +303,9 @@ typedef enum { CLIENT_AUTH_CERTIFICATE = 1 } ClientAuthenticationType; -#define SESS_TICKET_KEY_NAME_LEN 16 -#define SESS_TICKET_KEY_NAME_PREFIX "NSS!" -#define SESS_TICKET_KEY_NAME_PREFIX_LEN 4 -#define SESS_TICKET_KEY_VAR_NAME_LEN 12 - -typedef struct { - unsigned char *key_name; - unsigned char *iv; - SECItem encrypted_state; - unsigned char *mac; -} EncryptedSessionTicket; +#define SELF_ENCRYPT_KEY_NAME_LEN 16 +#define SELF_ENCRYPT_KEY_NAME_PREFIX "NSS!" +#define SELF_ENCRYPT_KEY_NAME_PREFIX_LEN 4 +#define SELF_ENCRYPT_KEY_VAR_NAME_LEN 12 #endif /* __ssl3proto_h_ */ diff --git a/lib/ssl/sslcert.c b/lib/ssl/sslcert.c index 388fc09501..cc1d3c6830 100644 --- a/lib/ssl/sslcert.c +++ b/lib/ssl/sslcert.c @@ -267,7 +267,7 @@ ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair) if (SSL_CERT_IS(sc, ssl_auth_rsa_decrypt)) { /* This will update the global session ticket key pair with this * key, if a value hasn't been set already. */ - if (ssl_MaybeSetSessionTicketKeyPair(keyPair) != SECSuccess) { + if (ssl_MaybeSetSelfEncryptKeyPair(keyPair) != SECSuccess) { return SECFailure; } } diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h index aa8a244de6..64694b0df9 100644 --- a/lib/ssl/sslimpl.h +++ b/lib/ssl/sslimpl.h @@ -1229,6 +1229,14 @@ struct sslSocketStr { SSLProtocolVariant protocolVariant; }; +struct sslSelfEncryptKeysStr { + PRCallOnceType setup; + PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; + PK11SymKey *encKey; + PK11SymKey *macKey; +}; +typedef struct sslSelfEncryptKeysStr sslSelfEncryptKeys; + extern char ssl_debug; extern char ssl_trace; extern FILE *ssl_trace_iob; @@ -1705,10 +1713,11 @@ extern void ssl3_SetSIDSessionTicket(sslSessionID *sid, SECStatus ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket_input, SECItem *ticket_data); -SECStatus ssl_MaybeSetSessionTicketKeyPair(const sslKeyPair *keyPair); -SECStatus ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName, - PK11SymKey **encKey, PK11SymKey **macKey); -void ssl_ResetSessionTicketKeys(); + +SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair); +SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName, + PK11SymKey **encKey, PK11SymKey **macKey); +void ssl_ResetSelfEncryptKeys(); extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length); diff --git a/lib/ssl/sslsnce.c b/lib/ssl/sslsnce.c index cf86edcfab..3ef11f7a73 100644 --- a/lib/ssl/sslsnce.c +++ b/lib/ssl/sslsnce.c @@ -35,7 +35,7 @@ * sidCacheEntry sidCacheData[ numSIDCacheEntries]; * certCacheEntry certCacheData[numCertCacheEntries]; * SSLWrappedSymWrappingKey keyCacheData[SSL_NUM_WRAP_KEYS][SSL_NUM_WRAP_MECHS]; - * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] + * PRUint8 keyNameSuffix[SELF_ENCRYPT_KEY_VAR_NAME_LEN] * encKeyCacheEntry ticketEncKey; // Wrapped * encKeyCacheEntry ticketMacKey; // Wrapped * PRBool ticketKeysValid; @@ -57,7 +57,7 @@ #include "blapit.h" #include "nss.h" /* for NSS_RegisterShutdown */ #include "sechash.h" - +#include "selfencrypt.h" #include #if defined(XP_UNIX) || defined(XP_BEOS) @@ -983,7 +983,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, cache->ticketKeyNameSuffix = (PRUint8 *)ptr; ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix + - SESS_TICKET_KEY_VAR_NAME_LEN); + SELF_ENCRYPT_KEY_VAR_NAME_LEN); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); cache->ticketEncKey = (encKeyCacheEntry *)ptr; @@ -1600,7 +1600,7 @@ StopLockPoller(cacheDesc *cache) * Code dealing with shared wrapped symmetric wrapping keys below * ************************************************************************/ -/* The asymmetric key we use for wrapping the symmetric ticket keys. This is a +/* The asymmetric key we use for wrapping the self-encryption keys. This is a * global structure that can be initialized without a socket. Access is * synchronized on the reader-writer lock. This is setup either by calling * SSL_SetSessionTicketKeyPair() or by configuring a certificate of the @@ -1611,77 +1611,80 @@ static struct { SECKEYPublicKey *pubKey; SECKEYPrivateKey *privKey; PRBool configured; -} ssl_session_ticket_key_pair; +} ssl_self_encrypt_key_pair; -/* The symmetric ticket keys. This requires a socket to construct and requires - * that the global structure be initialized before use. */ -static struct { - PRCallOnceType setup; - unsigned char keyName[SESS_TICKET_KEY_NAME_LEN]; - PK11SymKey *encKey; - PK11SymKey *macKey; -} ssl_session_ticket_keys; +/* The symmetric self-encryption keys. This requires a socket to construct + * and requires that the global structure be initialized before use. + */ +static sslSelfEncryptKeys ssl_self_encrypt_keys; + +/* Externalize the self encrypt keys. Purely used for testing. */ +sslSelfEncryptKeys * +ssl_GetSelfEncryptKeysInt() +{ + return &ssl_self_encrypt_keys; +} static void -ssl_CleanupSessionTicketKeyPair() +ssl_CleanupSelfEncryptKeyPair() { - if (ssl_session_ticket_key_pair.pubKey) { - PORT_Assert(ssl_session_ticket_key_pair.privKey); - SECKEY_DestroyPublicKey(ssl_session_ticket_key_pair.pubKey); - SECKEY_DestroyPrivateKey(ssl_session_ticket_key_pair.privKey); + if (ssl_self_encrypt_key_pair.pubKey) { + PORT_Assert(ssl_self_encrypt_key_pair.privKey); + SECKEY_DestroyPublicKey(ssl_self_encrypt_key_pair.pubKey); + SECKEY_DestroyPrivateKey(ssl_self_encrypt_key_pair.privKey); } } void -ssl_ResetSessionTicketKeys() +ssl_ResetSelfEncryptKeys() { - if (ssl_session_ticket_keys.encKey) { - PORT_Assert(ssl_session_ticket_keys.macKey); - PK11_FreeSymKey(ssl_session_ticket_keys.encKey); - PK11_FreeSymKey(ssl_session_ticket_keys.macKey); + if (ssl_self_encrypt_keys.encKey) { + PORT_Assert(ssl_self_encrypt_keys.macKey); + PK11_FreeSymKey(ssl_self_encrypt_keys.encKey); + PK11_FreeSymKey(ssl_self_encrypt_keys.macKey); } - PORT_Memset(&ssl_session_ticket_keys, 0, - sizeof(ssl_session_ticket_keys)); + PORT_Memset(&ssl_self_encrypt_keys, 0, + sizeof(ssl_self_encrypt_keys)); } static SECStatus -ssl_SessionTicketShutdown(void *appData, void *nssData) +ssl_SelfEncryptShutdown(void *appData, void *nssData) { - ssl_CleanupSessionTicketKeyPair(); - PR_DestroyRWLock(ssl_session_ticket_key_pair.lock); - PORT_Memset(&ssl_session_ticket_key_pair, 0, - sizeof(ssl_session_ticket_key_pair)); + ssl_CleanupSelfEncryptKeyPair(); + PR_DestroyRWLock(ssl_self_encrypt_key_pair.lock); + PORT_Memset(&ssl_self_encrypt_key_pair, 0, + sizeof(ssl_self_encrypt_key_pair)); - ssl_ResetSessionTicketKeys(); + ssl_ResetSelfEncryptKeys(); return SECSuccess; } static PRStatus -ssl_SessionTicketSetup(void) +ssl_SelfEncryptSetup(void) { - SECStatus rv = NSS_RegisterShutdown(ssl_SessionTicketShutdown, NULL); + SECStatus rv = NSS_RegisterShutdown(ssl_SelfEncryptShutdown, NULL); if (rv != SECSuccess) { return PR_FAILURE; } - ssl_session_ticket_key_pair.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL); - if (!ssl_session_ticket_key_pair.lock) { + ssl_self_encrypt_key_pair.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL); + if (!ssl_self_encrypt_key_pair.lock) { return PR_FAILURE; } return PR_SUCCESS; } -/* Configure a session ticket key pair. |explicitConfig| is set to true for +/* Configure a self encryption key pair. |explicitConfig| is set to true for * calls to SSL_SetSessionTicketKeyPair(), false for implicit configuration. * This assumes that the setup has been run. */ static SECStatus -ssl_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, - SECKEYPrivateKey *privKey, - PRBool explicitConfig) +ssl_SetSelfEncryptKeyPair(SECKEYPublicKey *pubKey, + SECKEYPrivateKey *privKey, + PRBool explicitConfig) { SECKEYPublicKey *pubKeyCopy; SECKEYPrivateKey *privKeyCopy; - PORT_Assert(ssl_session_ticket_key_pair.lock); + PORT_Assert(ssl_self_encrypt_key_pair.lock); pubKeyCopy = SECKEY_CopyPublicKey(pubKey); if (!pubKeyCopy) { @@ -1696,15 +1699,17 @@ ssl_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, return SECFailure; } - PR_RWLock_Wlock(ssl_session_ticket_key_pair.lock); - ssl_CleanupSessionTicketKeyPair(); - ssl_session_ticket_key_pair.pubKey = pubKeyCopy; - ssl_session_ticket_key_pair.privKey = privKeyCopy; - ssl_session_ticket_key_pair.configured = explicitConfig; - PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock); + PR_RWLock_Wlock(ssl_self_encrypt_key_pair.lock); + ssl_CleanupSelfEncryptKeyPair(); + ssl_self_encrypt_key_pair.pubKey = pubKeyCopy; + ssl_self_encrypt_key_pair.privKey = privKeyCopy; + ssl_self_encrypt_key_pair.configured = explicitConfig; + PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock); return SECSuccess; } +/* This is really the self-encryption keys but it has the + * wrong name for historical API stability reasons. */ SECStatus SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey) @@ -1715,53 +1720,53 @@ SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, return SECFailure; } - if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup, - &ssl_SessionTicketSetup)) { + if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup, + &ssl_SelfEncryptSetup)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - return ssl_SetSessionTicketKeyPair(pubKey, privKey, PR_TRUE); + return ssl_SetSelfEncryptKeyPair(pubKey, privKey, PR_TRUE); } /* When configuring a server cert, we should save the RSA key in case it is - * needed for ticket encryption. This saves the latest copy, unless there has + * needed for self-encryption. This saves the latest copy, unless there has * been an explicit call to SSL_SetSessionTicketKeyPair(). */ SECStatus -ssl_MaybeSetSessionTicketKeyPair(const sslKeyPair *keyPair) +ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair) { PRBool configured; - if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup, - &ssl_SessionTicketSetup)) { + if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup, + &ssl_SelfEncryptSetup)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - PR_RWLock_Rlock(ssl_session_ticket_key_pair.lock); - configured = ssl_session_ticket_key_pair.configured; - PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock); + PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock); + configured = ssl_self_encrypt_key_pair.configured; + PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock); if (configured) { return SECSuccess; } - return ssl_SetSessionTicketKeyPair(keyPair->pubKey, - keyPair->privKey, PR_FALSE); + return ssl_SetSelfEncryptKeyPair(keyPair->pubKey, + keyPair->privKey, PR_FALSE); } static SECStatus -ssl_GetSessionTicketKeyPair(SECKEYPublicKey **pubKey, - SECKEYPrivateKey **privKey) +ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey, + SECKEYPrivateKey **privKey) { - if (PR_SUCCESS != PR_CallOnce(&ssl_session_ticket_key_pair.setup, - &ssl_SessionTicketSetup)) { + if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup, + &ssl_SelfEncryptSetup)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - PR_RWLock_Rlock(ssl_session_ticket_key_pair.lock); - *pubKey = ssl_session_ticket_key_pair.pubKey; - *privKey = ssl_session_ticket_key_pair.privKey; - PR_RWLock_Unlock(ssl_session_ticket_key_pair.lock); + PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock); + *pubKey = ssl_self_encrypt_key_pair.pubKey; + *privKey = ssl_self_encrypt_key_pair.privKey; + PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock); if (!*pubKey) { PORT_Assert(!*privKey); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1772,23 +1777,23 @@ ssl_GetSessionTicketKeyPair(SECKEYPublicKey **pubKey, } static PRBool -ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName, - PK11SymKey **aesKey, PK11SymKey **macKey); +ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, + PK11SymKey **aesKey, PK11SymKey **macKey); static PRStatus -ssl_GenerateSessionTicketKeysOnce(void *arg) +ssl_GenerateSelfEncryptKeysOnce(void *arg) { SECStatus rv; /* Get a copy of the session keys from shared memory. */ - PORT_Memcpy(ssl_session_ticket_keys.keyName, - SESS_TICKET_KEY_NAME_PREFIX, - sizeof(SESS_TICKET_KEY_NAME_PREFIX)); - /* This function calls ssl_GetSessionTicketKeyPair(), which initializes the + PORT_Memcpy(ssl_self_encrypt_keys.keyName, + SELF_ENCRYPT_KEY_NAME_PREFIX, + sizeof(SELF_ENCRYPT_KEY_NAME_PREFIX)); + /* This function calls ssl_GetSelfEncryptKeyPair(), which initializes the * key pair stuff. That allows this to use the same shutdown function. */ - rv = ssl_GenerateSessionTicketKeys(arg, ssl_session_ticket_keys.keyName, - &ssl_session_ticket_keys.encKey, - &ssl_session_ticket_keys.macKey); + rv = ssl_GenerateSelfEncryptKeys(arg, ssl_self_encrypt_keys.keyName, + &ssl_self_encrypt_keys.encKey, + &ssl_self_encrypt_keys.macKey); if (rv != SECSuccess) { return PR_FAILURE; } @@ -1797,25 +1802,25 @@ ssl_GenerateSessionTicketKeysOnce(void *arg) } SECStatus -ssl_GetSessionTicketKeys(sslSocket *ss, unsigned char *keyName, - PK11SymKey **encKey, PK11SymKey **macKey) +ssl_GetSelfEncryptKeys(sslSocket *ss, PRUint8 *keyName, + PK11SymKey **encKey, PK11SymKey **macKey) { - if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_session_ticket_keys.setup, - &ssl_GenerateSessionTicketKeysOnce, + if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_self_encrypt_keys.setup, + &ssl_GenerateSelfEncryptKeysOnce, ss->pkcs11PinArg)) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - if (!ssl_session_ticket_keys.encKey || !ssl_session_ticket_keys.macKey) { + if (!ssl_self_encrypt_keys.encKey || !ssl_self_encrypt_keys.macKey) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - PORT_Memcpy(keyName, ssl_session_ticket_keys.keyName, - sizeof(ssl_session_ticket_keys.keyName)); - *encKey = ssl_session_ticket_keys.encKey; - *macKey = ssl_session_ticket_keys.macKey; + PORT_Memcpy(keyName, ssl_self_encrypt_keys.keyName, + sizeof(ssl_self_encrypt_keys.keyName)); + *encKey = ssl_self_encrypt_keys.encKey; + *macKey = ssl_self_encrypt_keys.macKey; return SECSuccess; } @@ -1875,8 +1880,8 @@ ssl_GetWrappingKey(unsigned int wrapMechIndex, /* Wrap and cache a session ticket key. */ static SECStatus -WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, - const char *keyName, encKeyCacheEntry *cacheEntry) +WrapSelfEncryptKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, + const char *keyName, encKeyCacheEntry *cacheEntry) { SECItem wrappedKey = { siBuffer, NULL, 0 }; @@ -1888,7 +1893,7 @@ WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) != SECSuccess) { - SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.", + SSL_DBG(("%d: SSL[%s]: Unable to wrap self encrypt key %s.", SSL_GETPID(), "unknown", keyName)); return SECFailure; } @@ -1897,15 +1902,15 @@ WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, } static SECStatus -GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) +GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, PK11SymKey **aesKey, + PK11SymKey **macKey) { PK11SlotInfo *slot; CK_MECHANISM_TYPE mechanismArray[2]; PK11SymKey *aesKeyTmp = NULL; PK11SymKey *macKeyTmp = NULL; cacheDesc *cache = &globalCache; - PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; + PRUint8 ticketKeyNameSuffixLocal[SELF_ENCRYPT_KEY_VAR_NAME_LEN]; PRUint8 *ticketKeyNameSuffix; if (!cache->cacheMem) { @@ -1916,7 +1921,7 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, } if (PK11_GenerateRandom(ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN) != + SELF_ENCRYPT_KEY_VAR_NAME_LEN) != SECSuccess) { SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.", SSL_GETPID(), "unknown")); @@ -1940,7 +1945,7 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, SSL_GETPID(), "unknown")); goto loser; } - PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN); + PORT_Memcpy(keyName, ticketKeyNameSuffix, SELF_ENCRYPT_KEY_VAR_NAME_LEN); *aesKey = aesKeyTmp; *macKey = macKeyTmp; return SECSuccess; @@ -1954,27 +1959,27 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, } static SECStatus -GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) +GenerateAndWrapSelfEncryptKeys(SECKEYPublicKey *svrPubKey, void *pwArg, + PRUint8 *keyName, PK11SymKey **aesKey, + PK11SymKey **macKey) { PK11SymKey *aesKeyTmp = NULL; PK11SymKey *macKeyTmp = NULL; cacheDesc *cache = &globalCache; SECStatus rv; - rv = GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp); + rv = GenerateSelfEncryptKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp); if (rv != SECSuccess) { return SECFailure; } if (cache->cacheMem) { /* Export the keys to the shared cache in wrapped form. */ - rv = WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey); + rv = WrapSelfEncryptKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey); if (rv != SECSuccess) { goto loser; } - rv = WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey); + rv = WrapSelfEncryptKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey); if (rv != SECSuccess) { goto loser; } @@ -1990,8 +1995,8 @@ GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, } static SECStatus -UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, - PK11SymKey **aesKey, PK11SymKey **macKey) +UnwrapCachedSelfEncryptKeys(SECKEYPrivateKey *svrPrivKey, PRUint8 *keyName, + PK11SymKey **aesKey, PK11SymKey **macKey) { SECItem wrappedKey = { siBuffer, NULL, 0 }; PK11SymKey *aesKeyTmp = NULL; @@ -2019,7 +2024,7 @@ UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, SSL_GETPID(), "unknown")); PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN); + SELF_ENCRYPT_KEY_VAR_NAME_LEN); *aesKey = aesKeyTmp; *macKey = macKeyTmp; return SECSuccess; @@ -2033,8 +2038,8 @@ UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, } static SECStatus -ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName, - PK11SymKey **encKey, PK11SymKey **macKey) +ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, + PK11SymKey **encKey, PK11SymKey **macKey) { SECKEYPrivateKey *svrPrivKey; SECKEYPublicKey *svrPubKey; @@ -2042,11 +2047,11 @@ ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName, SECStatus rv; cacheDesc *cache = &globalCache; - rv = ssl_GetSessionTicketKeyPair(&svrPubKey, &svrPrivKey); + rv = ssl_GetSelfEncryptKeyPair(&svrPubKey, &svrPrivKey); if (rv != SECSuccess || !cache->cacheMem) { /* No key pair for wrapping, or the cache is uninitialized. Generate * keys and return them without caching. */ - return GenerateTicketKeys(pwArg, keyName, encKey, macKey); + return GenerateSelfEncryptKeys(pwArg, keyName, encKey, macKey); } now = LockSidCacheLock(cache->keyCacheLock, 0); @@ -2054,11 +2059,11 @@ ssl_GenerateSessionTicketKeys(void *pwArg, unsigned char *keyName, return SECFailure; if (*(cache->ticketKeysValid)) { - rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, encKey, macKey); + rv = UnwrapCachedSelfEncryptKeys(svrPrivKey, keyName, encKey, macKey); } else { /* Keys do not exist, create them. */ - rv = GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName, - encKey, macKey); + rv = GenerateAndWrapSelfEncryptKeys(svrPubKey, pwArg, keyName, + encKey, macKey); if (rv == SECSuccess) { *(cache->ticketKeysValid) = 1; }