blob: e2328769bc01aaa5e5dfcbaccd05473842262beb [file] [log] [blame]
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* 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/. */
#define TLS13_ESNI_VERSION 0xff01
/*
* struct {
* uint16 version;
* uint8 checksum[4];
* KeyShareEntry keys<4..2^16-1>;
* CipherSuite cipher_suites<2..2^16-2>;
* uint16 padded_length;
* uint64 not_before;
* uint64 not_after;
* Extension extensions<0..2^16-1>;
* } ESNIKeys;
*/
#include "nss.h"
#include "pk11func.h"
#include "ssl.h"
#include "sslproto.h"
#include "sslimpl.h"
#include "ssl3exthandle.h"
#include "tls13esni.h"
#include "tls13exthandle.h"
#include "tls13hkdf.h"
const char kHkdfPurposeEsniKey[] = "esni key";
const char kHkdfPurposeEsniIv[] = "esni iv";
void
tls13_DestroyESNIKeys(sslEsniKeys *keys)
{
if (!keys) {
return;
}
SECITEM_FreeItem(&keys->data, PR_FALSE);
PORT_Free((void *)keys->dummySni);
tls13_DestroyKeyShares(&keys->keyShares);
ssl_FreeEphemeralKeyPair(keys->privKey);
SECITEM_FreeItem(&keys->suites, PR_FALSE);
PORT_ZFree(keys, sizeof(sslEsniKeys));
}
sslEsniKeys *
tls13_CopyESNIKeys(sslEsniKeys *okeys)
{
sslEsniKeys *nkeys;
SECStatus rv;
PORT_Assert(okeys);
nkeys = PORT_ZNew(sslEsniKeys);
if (!nkeys) {
return NULL;
}
PR_INIT_CLIST(&nkeys->keyShares);
rv = SECITEM_CopyItem(NULL, &nkeys->data, &okeys->data);
if (rv != SECSuccess) {
goto loser;
}
if (okeys->dummySni) {
nkeys->dummySni = PORT_Strdup(okeys->dummySni);
if (!nkeys->dummySni) {
goto loser;
}
}
for (PRCList *cur_p = PR_LIST_HEAD(&okeys->keyShares);
cur_p != &okeys->keyShares;
cur_p = PR_NEXT_LINK(cur_p)) {
TLS13KeyShareEntry *copy = tls13_CopyKeyShareEntry(
(TLS13KeyShareEntry *)cur_p);
if (!copy) {
goto loser;
}
PR_APPEND_LINK(&copy->link, &nkeys->keyShares);
}
if (okeys->privKey) {
nkeys->privKey = ssl_CopyEphemeralKeyPair(okeys->privKey);
if (!nkeys->privKey) {
goto loser;
}
}
rv = SECITEM_CopyItem(NULL, &nkeys->suites, &okeys->suites);
if (rv != SECSuccess) {
goto loser;
}
nkeys->paddedLength = okeys->paddedLength;
nkeys->notBefore = okeys->notBefore;
nkeys->notAfter = okeys->notAfter;
return nkeys;
loser:
tls13_DestroyESNIKeys(nkeys);
return NULL;
}
/* Checksum is a 4-byte array. */
static SECStatus
tls13_ComputeESNIKeysChecksum(const PRUint8 *buf, unsigned int len,
PRUint8 *checksum)
{
SECItem copy;
SECStatus rv;
PRUint8 sha256[32];
rv = SECITEM_MakeItem(NULL, &copy, buf, len);
if (rv != SECSuccess) {
return SECFailure;
}
/* Stomp the checksum. */
PORT_Memset(copy.data + 2, 0, 4);
rv = PK11_HashBuf(ssl3_HashTypeToOID(ssl_hash_sha256),
sha256,
copy.data, copy.len);
SECITEM_FreeItem(&copy, PR_FALSE);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Memcpy(checksum, sha256, 4);
return SECSuccess;
}
static SECStatus
tls13_DecodeESNIKeys(SECItem *data, sslEsniKeys **keysp)
{
SECStatus rv;
sslReadBuffer tmp;
PRUint64 tmpn;
sslEsniKeys *keys;
PRUint8 checksum[4];
sslReader rdr = SSL_READER(data->data, data->len);
rv = sslRead_ReadNumber(&rdr, 2, &tmpn);
if (rv != SECSuccess) {
return SECFailure;
}
if (tmpn != TLS13_ESNI_VERSION) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
return SECFailure;
}
keys = PORT_ZNew(sslEsniKeys);
if (!keys) {
return SECFailure;
}
PR_INIT_CLIST(&keys->keyShares);
/* Make a copy. */
rv = SECITEM_CopyItem(NULL, &keys->data, data);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_ComputeESNIKeysChecksum(data->data, data->len, checksum);
if (rv != SECSuccess) {
goto loser;
}
/* Read and check checksum. */
rv = sslRead_Read(&rdr, 4, &tmp);
if (rv != SECSuccess) {
goto loser;
}
if (0 != NSS_SecureMemcmp(tmp.buf, checksum, 4)) {
goto loser;
}
/* Parse the key shares. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp);
if (rv != SECSuccess) {
goto loser;
}
sslReader rdr2 = SSL_READER(tmp.buf, tmp.len);
while (SSL_READER_REMAINING(&rdr2)) {
TLS13KeyShareEntry *ks = NULL;
rv = tls13_DecodeKeyShareEntry(&rdr2, &ks);
if (rv != SECSuccess) {
goto loser;
}
if (ks) {
PR_APPEND_LINK(&ks->link, &keys->keyShares);
}
}
/* Parse cipher suites. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp);
if (rv != SECSuccess) {
goto loser;
}
/* This can't be odd. */
if (tmp.len & 1) {
goto loser;
}
rv = SECITEM_MakeItem(NULL, &keys->suites, (PRUint8 *)tmp.buf, tmp.len);
if (rv != SECSuccess) {
goto loser;
}
/* Padded Length */
rv = sslRead_ReadNumber(&rdr, 2, &tmpn);
if (rv != SECSuccess) {
goto loser;
}
keys->paddedLength = (PRUint16)tmpn;
/* Not Before */
rv = sslRead_ReadNumber(&rdr, 8, &keys->notBefore);
if (rv != SECSuccess) {
goto loser;
}
/* Not After */
rv = sslRead_ReadNumber(&rdr, 8, &keys->notAfter);
if (rv != SECSuccess) {
goto loser;
}
/* Extensions, which we ignore. */
rv = sslRead_ReadVariable(&rdr, 2, &tmp);
if (rv != SECSuccess) {
goto loser;
}
/* Check that this is empty. */
if (SSL_READER_REMAINING(&rdr) > 0) {
goto loser;
}
*keysp = keys;
return SECSuccess;
loser:
tls13_DestroyESNIKeys(keys);
PORT_SetError(SSL_ERROR_RX_MALFORMED_ESNI_KEYS);
return SECFailure;
}
/* Encode an ESNI keys structure. We only allow one key
* share. */
SECStatus
SSLExp_EncodeESNIKeys(PRUint16 *cipherSuites, unsigned int cipherSuiteCount,
SSLNamedGroup group, SECKEYPublicKey *pubKey,
PRUint16 pad, PRUint64 notBefore, PRUint64 notAfter,
PRUint8 *out, unsigned int *outlen, unsigned int maxlen)
{
unsigned int savedOffset;
SECStatus rv;
sslBuffer b = SSL_BUFFER_EMPTY;
rv = sslBuffer_AppendNumber(&b, TLS13_ESNI_VERSION, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Skip(&b, 4, &savedOffset);
if (rv != SECSuccess) {
goto loser;
}
/* Length of vector. */
rv = sslBuffer_AppendNumber(
&b, tls13_SizeOfKeyShareEntry(pubKey), 2);
if (rv != SECSuccess) {
goto loser;
}
/* Our one key share. */
rv = tls13_EncodeKeyShareEntry(&b, group, pubKey);
if (rv != SECSuccess) {
goto loser;
}
/* Cipher suites. */
rv = sslBuffer_AppendNumber(&b, cipherSuiteCount * 2, 2);
if (rv != SECSuccess) {
goto loser;
}
for (unsigned int i = 0; i < cipherSuiteCount; i++) {
rv = sslBuffer_AppendNumber(&b, cipherSuites[i], 2);
if (rv != SECSuccess) {
goto loser;
}
}
/* Padding Length. Fixed for now. */
rv = sslBuffer_AppendNumber(&b, pad, 2);
if (rv != SECSuccess) {
goto loser;
}
/* Start time. */
rv = sslBuffer_AppendNumber(&b, notBefore, 8);
if (rv != SECSuccess) {
goto loser;
}
/* End time. */
rv = sslBuffer_AppendNumber(&b, notAfter, 8);
if (rv != SECSuccess) {
goto loser;
}
/* No extensions. */
rv = sslBuffer_AppendNumber(&b, 0, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_ComputeESNIKeysChecksum(SSL_BUFFER_BASE(&b),
SSL_BUFFER_LEN(&b),
SSL_BUFFER_BASE(&b) + 2);
if (rv != SECSuccess) {
PORT_Assert(PR_FALSE);
goto loser;
}
if (SSL_BUFFER_LEN(&b) > maxlen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
PORT_Memcpy(out, SSL_BUFFER_BASE(&b), SSL_BUFFER_LEN(&b));
*outlen = SSL_BUFFER_LEN(&b);
sslBuffer_Clear(&b);
return SECSuccess;
loser:
sslBuffer_Clear(&b);
return SECFailure;
}
SECStatus
SSLExp_SetESNIKeyPair(PRFileDesc *fd,
SECKEYPrivateKey *privKey,
const PRUint8 *record, unsigned int recordLen)
{
sslSocket *ss;
SECStatus rv;
sslEsniKeys *keys = NULL;
SECKEYPublicKey *pubKey = NULL;
SECItem data = { siBuffer, CONST_CAST(PRUint8, record), recordLen };
PLArenaPool *arena = NULL;
ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in %s",
SSL_GETPID(), fd, __FUNCTION__));
return SECFailure;
}
rv = tls13_DecodeESNIKeys(&data, &keys);
if (rv != SECSuccess) {
return SECFailure;
}
/* Check the cipher suites. */
(void)ssl3_config_match_init(ss);
/* Make sure the cipher suite is OK. */
SSLVersionRange vrange = { SSL_LIBRARY_VERSION_TLS_1_3,
SSL_LIBRARY_VERSION_TLS_1_3 };
sslReader csrdr = SSL_READER(keys->suites.data,
keys->suites.len);
while (SSL_READER_REMAINING(&csrdr)) {
PRUint64 asuite;
rv = sslRead_ReadNumber(&csrdr, 2, &asuite);
if (rv != SECSuccess) {
goto loser;
}
const ssl3CipherSuiteCfg *suiteCfg =
ssl_LookupCipherSuiteCfg(asuite, ss->cipherSuites);
if (!ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
/* Illegal suite. */
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
}
if (PR_CLIST_IS_EMPTY(&keys->keyShares)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
if (PR_PREV_LINK(&keys->keyShares) != PR_NEXT_LINK(&keys->keyShares)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
TLS13KeyShareEntry *entry = (TLS13KeyShareEntry *)PR_LIST_HEAD(
&keys->keyShares);
if (entry->group->keaType != ssl_kea_ecdh) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto loser;
}
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
if (!arena) {
goto loser;
}
pubKey = PORT_ArenaZNew(arena, SECKEYPublicKey);
if (!pubKey) {
goto loser;
}
pubKey->arena = arena;
arena = NULL; /* From here, this will be destroyed with the pubkey. */
/* Dummy PKCS11 values because this key isn't on a slot. */
pubKey->pkcs11Slot = NULL;
pubKey->pkcs11ID = CK_INVALID_HANDLE;
rv = ssl_ImportECDHKeyShare(pubKey,
entry->key_exchange.data,
entry->key_exchange.len,
entry->group);
if (rv != SECSuccess) {
goto loser;
}
privKey = SECKEY_CopyPrivateKey(privKey);
if (!privKey) {
goto loser;
}
keys->privKey = ssl_NewEphemeralKeyPair(entry->group, privKey, pubKey);
if (!keys->privKey) {
goto loser;
}
pubKey = NULL;
ss->esniKeys = keys;
return SECSuccess;
loser:
PORT_FreeArena(arena, PR_FALSE);
SECKEY_DestroyPublicKey(pubKey);
tls13_DestroyESNIKeys(keys);
return SECFailure;
}
SECStatus
SSLExp_EnableESNI(PRFileDesc *fd,
const PRUint8 *esniKeys,
unsigned int esniKeysLen,
const char *dummySNI)
{
sslSocket *ss;
sslEsniKeys *keys = NULL;
SECItem data = { siBuffer, CONST_CAST(PRUint8, esniKeys), esniKeysLen };
SECStatus rv;
ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in %s",
SSL_GETPID(), fd, __FUNCTION__));
return SECFailure;
}
rv = tls13_DecodeESNIKeys(&data, &keys);
if (rv != SECSuccess) {
return SECFailure;
}
if (dummySNI) {
keys->dummySni = PORT_Strdup(dummySNI);
if (!keys->dummySni) {
tls13_DestroyESNIKeys(keys);
return SECFailure;
}
}
/* Delete in case it was set before. */
tls13_DestroyESNIKeys(ss->esniKeys);
ss->esniKeys = keys;
return SECSuccess;
}
/*
* struct {
* opaque record_digest<0..2^16-1>;
* KeyShareEntry esni_key_share;
* Random client_hello_random;
* } ESNIContents;
*/
SECStatus
tls13_ComputeESNIKeys(const sslSocket *ss,
TLS13KeyShareEntry *entry,
sslKeyPair *keyPair,
const ssl3CipherSuiteDef *suite,
const PRUint8 *esniKeysHash,
const PRUint8 *keyShareBuf,
unsigned int keyShareBufLen,
const PRUint8 *clientRandom,
ssl3KeyMaterial *keyMat)
{
PK11SymKey *Z = NULL;
PK11SymKey *Zx = NULL;
SECStatus ret = SECFailure;
PRUint8 esniContentsBuf[256]; /* Just big enough. */
sslBuffer esniContents = SSL_BUFFER(esniContentsBuf);
PRUint8 hash[64];
const ssl3BulkCipherDef *cipherDef = ssl_GetBulkCipherDef(suite);
size_t keySize = cipherDef->key_size;
size_t ivSize = cipherDef->iv_size +
cipherDef->explicit_nonce_size; /* This isn't always going to
* work, but it does for
* AES-GCM */
unsigned int hashSize = tls13_GetHashSizeForHash(suite->prf_hash);
SECStatus rv;
rv = tls13_HandleKeyShare(CONST_CAST(sslSocket, ss), entry, keyPair,
suite->prf_hash, &Z);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_HkdfExtract(NULL, Z, suite->prf_hash, &Zx);
if (rv != SECSuccess) {
goto loser;
}
/* Encode ESNIContents. */
rv = sslBuffer_AppendVariable(&esniContents,
esniKeysHash, hashSize, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Append(&esniContents, keyShareBuf, keyShareBufLen);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Append(&esniContents, clientRandom, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
PORT_Assert(hashSize <= sizeof(hash));
rv = PK11_HashBuf(ssl3_HashTypeToOID(suite->prf_hash),
hash,
SSL_BUFFER_BASE(&esniContents),
SSL_BUFFER_LEN(&esniContents));
;
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_HkdfExpandLabel(Zx, suite->prf_hash,
hash, hashSize,
kHkdfPurposeEsniKey, strlen(kHkdfPurposeEsniKey),
ssl3_Alg2Mech(cipherDef->calg),
keySize,
&keyMat->key);
if (rv != SECSuccess) {
goto loser;
}
rv = tls13_HkdfExpandLabelRaw(Zx, suite->prf_hash,
hash, hashSize,
kHkdfPurposeEsniIv, strlen(kHkdfPurposeEsniIv),
keyMat->iv, ivSize);
if (rv != SECSuccess) {
goto loser;
}
ret = SECSuccess;
loser:
PK11_FreeSymKey(Z);
PK11_FreeSymKey(Zx);
return ret;
}
/* Set up ESNI. This generates a private key as a side effect. */
SECStatus
tls13_ClientSetupESNI(sslSocket *ss)
{
ssl3CipherSuite suite;
sslEphemeralKeyPair *keyPair;
size_t i;
PRCList *cur;
SECStatus rv;
TLS13KeyShareEntry *share;
const sslNamedGroupDef *group = NULL;
PRTime now = PR_Now() / PR_USEC_PER_SEC;
if (!ss->esniKeys) {
return SECSuccess;
}
if ((ss->esniKeys->notBefore > now) || (ss->esniKeys->notAfter < now)) {
return SECSuccess;
}
/* If we're not sending SNI, don't send ESNI. */
if (!ssl_ShouldSendSNIExtension(ss, ss->url)) {
return SECSuccess;
}
/* Pick the group. */
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
for (cur = PR_NEXT_LINK(&ss->esniKeys->keyShares);
cur != &ss->esniKeys->keyShares;
cur = PR_NEXT_LINK(cur)) {
if (!ss->namedGroupPreferences[i]) {
continue;
}
share = (TLS13KeyShareEntry *)cur;
if (share->group->name == ss->namedGroupPreferences[i]->name) {
group = ss->namedGroupPreferences[i];
break;
}
}
}
if (!group) {
/* No compatible group. */
return SECSuccess;
}
rv = ssl3_NegotiateCipherSuiteInner(ss, &ss->esniKeys->suites,
SSL_LIBRARY_VERSION_TLS_1_3, &suite);
if (rv != SECSuccess) {
return SECSuccess;
}
rv = tls13_CreateKeyShare(ss, group, &keyPair);
if (rv != SECSuccess) {
return SECFailure;
}
ss->xtnData.esniPrivateKey = keyPair;
ss->xtnData.esniSuite = suite;
ss->xtnData.peerEsniShare = share;
return SECSuccess;
}
/*
* struct {
* CipherSuite suite;
* KeyShareEntry key_share;
* opaque record_digest<0..2^16-1>;
* opaque encrypted_sni<0..2^16-1>;
* } ClientEncryptedSNI;
*
* struct {
* ServerNameList sni;
* opaque zeros[ESNIKeys.padded_length - length(sni)];
* } PaddedServerNameList;
*
* struct {
* uint8 nonce[16];
* PaddedServerNameList realSNI;
* } ClientESNIInner;
*/
SECStatus
tls13_FormatEsniAADInput(sslBuffer *aadInput,
PRUint8 *keyShare, unsigned int keyShareLen)
{
SECStatus rv;
/* 8 bytes of 0 for the sequence number. */
rv = sslBuffer_AppendNumber(aadInput, 0, 8);
if (rv != SECSuccess) {
return SECFailure;
}
/* Key share. */
PORT_Assert(keyShareLen > 0);
rv = sslBuffer_Append(aadInput, keyShare, keyShareLen);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
static SECStatus
tls13_ServerGetEsniAEAD(const sslSocket *ss, PRUint64 suite,
const ssl3CipherSuiteDef **suiteDefp,
SSLAEADCipher *aeadp)
{
SECStatus rv;
const ssl3CipherSuiteDef *suiteDef;
SSLAEADCipher aead;
/* Check against the suite list for ESNI */
PRBool csMatch = PR_FALSE;
sslReader csrdr = SSL_READER(ss->esniKeys->suites.data,
ss->esniKeys->suites.len);
while (SSL_READER_REMAINING(&csrdr)) {
PRUint64 asuite;
rv = sslRead_ReadNumber(&csrdr, 2, &asuite);
if (rv != SECSuccess) {
return SECFailure;
}
if (asuite == suite) {
csMatch = PR_TRUE;
break;
}
}
if (!csMatch) {
return SECFailure;
}
suiteDef = ssl_LookupCipherSuiteDef(suite);
PORT_Assert(suiteDef);
if (!suiteDef) {
return SECFailure;
}
aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
if (!aead) {
return SECFailure;
}
*suiteDefp = suiteDef;
*aeadp = aead;
return SECSuccess;
}
SECStatus
tls13_ServerDecryptEsniXtn(const sslSocket *ss, PRUint8 *in, unsigned int inLen,
PRUint8 *out, int *outLen, int maxLen)
{
sslReader rdr = SSL_READER(in, inLen);
PRUint64 suite;
const ssl3CipherSuiteDef *suiteDef;
SSLAEADCipher aead = NULL;
TLSExtension *keyShareExtension;
TLS13KeyShareEntry *entry = NULL;
ssl3KeyMaterial keyMat = { NULL };
sslBuffer aadInput = SSL_BUFFER_EMPTY;
const PRUint8 *keyShareBuf;
sslReadBuffer buf;
unsigned int keyShareBufLen;
PRUint8 hash[64];
SECStatus rv;
/* Read the cipher suite. */
rv = sslRead_ReadNumber(&rdr, 2, &suite);
if (rv != SECSuccess) {
goto loser;
}
/* Find the AEAD */
rv = tls13_ServerGetEsniAEAD(ss, suite, &suiteDef, &aead);
if (rv != SECSuccess) {
goto loser;
}
/* Note where the KeyShare starts. */
keyShareBuf = SSL_READER_CURRENT(&rdr);
rv = tls13_DecodeKeyShareEntry(&rdr, &entry);
if (rv != SECSuccess) {
goto loser;
}
keyShareBufLen = SSL_READER_CURRENT(&rdr) - keyShareBuf;
if (!entry || entry->group->name != ss->esniKeys->privKey->group->name) {
goto loser;
}
/* The hash of the ESNIKeys structure. */
rv = sslRead_ReadVariable(&rdr, 2, &buf);
if (rv != SECSuccess) {
goto loser;
}
/* Check that the hash matches. */
unsigned int hashLen = tls13_GetHashSizeForHash(suiteDef->prf_hash);
PORT_Assert(hashLen <= sizeof(hash));
rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash),
hash,
ss->esniKeys->data.data, ss->esniKeys->data.len);
if (rv != SECSuccess) {
goto loser;
}
if (buf.len != hashLen) {
/* This is malformed. */
goto loser;
}
if (0 != NSS_SecureMemcmp(hash, buf.buf, hashLen)) {
goto loser;
}
rv = tls13_ComputeESNIKeys(ss, entry,
ss->esniKeys->privKey->keys,
suiteDef,
hash, keyShareBuf, keyShareBufLen,
((sslSocket *)ss)->ssl3.hs.client_random,
&keyMat);
if (rv != SECSuccess) {
goto loser;
}
/* Read the ciphertext. */
rv = sslRead_ReadVariable(&rdr, 2, &buf);
if (rv != SECSuccess) {
goto loser;
}
/* Check that this is empty. */
if (SSL_READER_REMAINING(&rdr) > 0) {
goto loser;
}
/* Find the key share extension. */
keyShareExtension = ssl3_FindExtension(CONST_CAST(sslSocket, ss),
ssl_tls13_key_share_xtn);
if (!keyShareExtension) {
goto loser;
}
rv = tls13_FormatEsniAADInput(&aadInput,
keyShareExtension->data.data,
keyShareExtension->data.len);
if (rv != SECSuccess) {
goto loser;
}
rv = aead(&keyMat, PR_TRUE /* Decrypt */,
out, outLen, maxLen,
buf.buf, buf.len,
SSL_BUFFER_BASE(&aadInput),
SSL_BUFFER_LEN(&aadInput));
sslBuffer_Clear(&aadInput);
if (rv != SECSuccess) {
goto loser;
}
ssl_DestroyKeyMaterial(&keyMat);
tls13_DestroyKeyShareEntry(entry);
return SECSuccess;
loser:
FATAL_ERROR(CONST_CAST(sslSocket, ss), SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
ssl_DestroyKeyMaterial(&keyMat); /* Safe because zeroed. */
if (entry) {
tls13_DestroyKeyShareEntry(entry);
}
return SECFailure;
}