Commit 8cb4c934 authored by EKR's avatar EKR

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
parent 1a5850c1
......@@ -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);
......
......@@ -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);
......
......@@ -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 \
......
/* -*- 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 <functional>
#include <memory>
#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<const unsigned char*>("KEY1KEY1KEY1KEY1");
static const uint8_t* kKeyName2 =
reinterpret_cast<const uint8_t*>("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<uint8_t*>(key.data()),
static_cast<unsigned int>(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<void(uint8_t* ciphertext, unsigned int* ciphertext_len)>
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<size_t> {
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
......@@ -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));
......
......@@ -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',
......
......@@ -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<uint8_t*>(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.
......
......@@ -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();
}
......
......@@ -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 \
......
/* -*- 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;
}