lib/ssl/tls13con.c
author EKR <ekr@rtfm.com>
Wed, 03 Feb 2016 08:44:16 -0800
changeset 11843 775ed89344d614c6925bb19d82628347dc351f2b
parent 11842 6c3d579ee42229e9a6f4f64b8e514aa6fdcdcf67
child 11850 2388858af96dcb99b4845674ff90292e6baa08e1
permissions -rw-r--r--
Bustage fix. r=me

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * TLS 1.3 Protocol
 *
 * 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 "stdarg.h"
#include "cert.h"
#include "ssl.h"
#include "keyhi.h"
#include "pk11func.h"
#include "secitem.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "sslerr.h"
#include "tls13hkdf.h"
#include "tls13con.h"

typedef enum {
    TrafficKeyEarlyData,
    TrafficKeyHandshake,
    TrafficKeyApplicationData
} TrafficKeyType;

typedef enum {
    InstallCipherSpecRead,
    InstallCipherSpecWrite,
    InstallCipherSpecBoth
} InstallCipherSpecDirection;

#define MAX_FINISHED_SIZE 64

static SECStatus tls13_InstallCipherSpec(
    sslSocket *ss, InstallCipherSpecDirection direction);
static SECStatus tls13_InitCipherSpec(
    sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install);
static SECStatus tls13_AESGCM(
    ssl3KeyMaterial *keys,
    PRBool doDecrypt,
    unsigned char *out, int *outlen, int maxout,
    const unsigned char *in, int inlen,
    const unsigned char *additionalData, int additionalDataLen);
static SECStatus tls13_SendEncryptedExtensions(sslSocket *ss);
static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b,
                                                 PRUint32 length);
static SECStatus tls13_HandleCertificate(
    sslSocket *ss, SSL3Opaque *b, PRUint32 length);
static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b,
                                                PRUint32 length);
static SECStatus tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b,
                                               PRUint32 length);
static SECStatus tls13_HandleCertificateVerify(
    sslSocket *ss, SSL3Opaque *b, PRUint32 length,
    SSL3Hashes *hashes);
static SECStatus tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey* key,
                                            SharedSecretType keyType);
static SECStatus tls13_SendFinished(sslSocket *ss);
static SECStatus tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
                                      const SSL3Hashes *hashes);
static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b,
                                              PRUint32 length);
static SECStatus tls13_ComputeSecrets1(sslSocket *ss);
static SECStatus tls13_ComputeFinished(
    sslSocket *ss, const SSL3Hashes *hashes,
    PRBool sending,
    PRUint8 *output, unsigned int *outputLen,
    unsigned int maxOutputLen);
static SECStatus tls13_SendClientSecondRound(sslSocket *ss);
static SECStatus tls13_FinishHandshake(sslSocket *ss);

const char kHkdfLabelExpandedSs[] = "expanded static secret";
const char kHkdfLabelExpandedEs[] = "expanded ephemeral secret";
const char kHkdfLabelMasterSecret[] = "master secret";
const char kHkdfLabelTrafficSecret[] = "traffic secret";
const char kHkdfLabelClientFinishedSecret[] = "client finished";
const char kHkdfLabelServerFinishedSecret[] = "server finished";
const char kHkdfLabelResumptionMasterSecret[] = "resumption master secret";
const char kHkdfLabelExporterMasterSecret[] = "exporter master secret";
const char kHkdfPhaseEarlyHandshakeDataKeys[] = "early handshake key expansion";
const char kHkdfPhaseEarlyApplicationDataKeys[] = "early application data key expansion";
const char kHkdfPhaseHandshakeKeys[] = "handshake key expansion";
const char kHkdfPhaseApplicationDataKeys[] = "application data key expansion";
const char kHkdfPurposeClientWriteKey[] = "client write key";
const char kHkdfPurposeServerWriteKey[] = "server write key";
const char kHkdfPurposeClientWriteIv[] = "client write iv";
const char kHkdfPurposeServerWriteIv[] = "server write iv";
const char kClientFinishedLabel[] = "client finished";
const char kServerFinishedLabel[] = "server finished";

const SSL3ProtocolVersion kRecordVersion = 0x0301U;

#define FATAL_ERROR(ss, prError, desc) do { \
    SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \
                SSL_GETPID(), ss->fd, prError, __func__, __FILE__, __LINE__)); \
    tls13_FatalError(ss, prError, desc); \
} while(0)

#define UNIMPLEMENTED() do { \
    SSL_TRC(3, ("%d: TLS13[%d]: unimplemented feature in %s (%s:%d)", \
                SSL_GETPID(), ss->fd, __func__, __FILE__, __LINE__)); \
    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); \
    PORT_Assert(0); \
} while(0)

void
tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc)
{
    PORT_Assert(desc != internal_error);  /* These should never happen */
    (void)SSL3_SendAlert(ss, alert_fatal, desc);
    PORT_SetError(prError);
}

#ifdef TRACE
#define STATE_CASE(a) case a: return #a
static char *
tls13_HandshakeState(SSL3WaitState st)
{
    switch(st) {
        STATE_CASE(wait_client_hello);
        STATE_CASE(wait_client_cert);
        STATE_CASE(wait_cert_verify);
        STATE_CASE(wait_finished);
        STATE_CASE(wait_server_hello);
        STATE_CASE(wait_certificate_status);
        STATE_CASE(wait_server_cert);
        STATE_CASE(wait_cert_request);
        STATE_CASE(wait_encrypted_extensions);
        STATE_CASE(idle_handshake);
        default:
            break;
    }
    PORT_Assert(0);
    return "unknown";
}
#endif

#define TLS13_WAIT_STATE_MASK 0x80

#define TLS13_BASE_WAIT_STATE(ws) (ws & ~TLS13_WAIT_STATE_MASK)
/* We don't mask idle_handshake because other parts of the code use it*/
#define TLS13_WAIT_STATE(ws) (ws == idle_handshake ? ws :\
                              ws | TLS13_WAIT_STATE_MASK)
#define TLS13_CHECK_HS_STATE(ss, err, ...) \
    tls13_CheckHsState(ss, err, #err, __func__, __FILE__, __LINE__, \
                       __VA_ARGS__,                                 \
                       wait_invalid)
void
tls13_SetHsState(sslSocket *ss, SSL3WaitState ws,
                 const char *func, const char *file, int line)
{
#ifdef TRACE
    const char *new_state_name =
            tls13_HandshakeState(ws);

    SSL_TRC(3, ("%d: TLS13[%d]: state change from %s->%s in %s (%s:%d)",
                SSL_GETPID(), ss->fd,
                tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
                new_state_name,
                func, file, line));
#endif

    ss->ssl3.hs.ws = TLS13_WAIT_STATE(ws);
}

static PRBool
tls13_InHsStateV(sslSocket *ss, va_list ap)
{
    SSL3WaitState ws;

    while ((ws = va_arg(ap, SSL3WaitState)) != wait_invalid ) {
        if (ws == TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)) {
            return PR_TRUE;
        }
    }
    return PR_FALSE;
}

PRBool
tls13_InHsState(sslSocket *ss, ...)
{
    PRBool found;
    va_list ap;

    va_start(ap, ss);
    found = tls13_InHsStateV(ss, ap);
    va_end(ap);

    return found;
}

static SECStatus
tls13_CheckHsState(sslSocket *ss, int err, const char *error_name,
                   const char *func, const char *file, int line,
                   ...)
{
    va_list ap;
    va_start(ap, line);
    if (tls13_InHsStateV(ss, ap)) {
        va_end(ap);
        return SECSuccess;
    }
    va_end(ap);

    SSL_TRC(3, ("%d: TLS13[%d]: error %s state is (%s) at %s (%s:%d)",
                SSL_GETPID(), ss->fd,
                error_name,
                tls13_HandshakeState(TLS13_BASE_WAIT_STATE(ss->ssl3.hs.ws)),
                func, file, line));
    tls13_FatalError(ss, err, unexpected_message);
    return SECFailure;
}

SSLHashType
tls13_GetHash(sslSocket *ss)
{
    /* TODO(ekr@rtfm.com): This needs to actually be looked up. */
    return ssl_hash_sha256;
}

CK_MECHANISM_TYPE
tls13_GetHkdfMechanism(sslSocket *ss)
{
    /* TODO(ekr@rtfm.com): This needs to actually be looked up. */
    return CKM_NSS_HKDF_SHA256;
}

static CK_MECHANISM_TYPE
tls13_GetHmacMechanism(sslSocket *ss)
{
    /* TODO(ekr@rtfm.com): This needs to actually be looked up. */
    return CKM_SHA256_HMAC;
}

/*
 * Called from ssl3_SendClientHello
 */
SECStatus
tls13_SetupClientHello(sslSocket *ss)
{
    SECStatus rv;
    /* TODO(ekr@rtfm.com): Handle multiple curves here. */
    ECName curves_to_try[] = { ec_secp256r1 };

    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));

    PORT_Assert(!ss->ephemeralECDHKeyPair);

    rv = ssl3_CreateECDHEphemeralKeyPair(curves_to_try[0],
                                         &ss->ephemeralECDHKeyPair);
    if (rv != SECSuccess)
        return rv;

    return SECSuccess;
}

static SECStatus tls13_HandleECDHEKeyShare(sslSocket *ss,
                                           TLS13KeyShareEntry *entry,
                                           SECKEYPrivateKey *privKey,
                                           SharedSecretType type)
{
    SECStatus rv;
    SECKEYPublicKey *peerKey;
    PK11SymKey *shared;

    peerKey = tls13_ImportECDHKeyShare(ss, entry->key_exchange.data,
                                       entry->key_exchange.len,
                                       entry->group);
    if (!peerKey)
        return SECFailure;  /* Error code set already. */

    /* Compute shared key. */
    shared = tls13_ComputeECDHSharedKey(ss, privKey, peerKey);
    SECKEY_DestroyPublicKey(peerKey);
    if (!shared) {
        return SECFailure;  /* Error code set already. */
    }

    /* Extract key. */
    rv = tls13_HkdfExtractSharedKey(ss, shared, type);
    PK11_FreeSymKey(shared);

    return rv;
}

SECStatus
tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b,
                                     PRUint32 length, SSL3Hashes *hashesPtr)
{
    /* TODO(ekr@rtfm.com): Would it be better to check all the states here? */
    switch (ss->ssl3.hs.msg_type) {
    case certificate:
	return tls13_HandleCertificate(ss, b, length);

    case certificate_status:
	return tls13_HandleCertificateStatus(ss, b, length);

    case certificate_request:
        return tls13_HandleCertificateRequest(ss, b, length);

    case certificate_verify:
	return tls13_HandleCertificateVerify(ss, b, length, hashesPtr);

    case encrypted_extensions:
	return tls13_HandleEncryptedExtensions(ss, b, length);

    case new_session_ticket:
        return tls13_HandleNewSessionTicket(ss, b, length);

    case finished:
        return tls13_HandleFinished(ss, b, length, hashesPtr);

    default:
        FATAL_ERROR(ss, SSL_ERROR_RX_UNKNOWN_HANDSHAKE, unexpected_message);
        return SECFailure;
    }

    PORT_Assert(0); /* Unreached */
    return SECFailure;
}

/* Called from ssl3_HandleClientHello.
 *
 * Caller must hold Handshake and RecvBuf locks.
 */
SECStatus
tls13_HandleClientKeyShare(sslSocket *ss)
{
    ECName expectedGroup;
    SECStatus rv;
    TLS13KeyShareEntry* found = NULL;
    PRCList *cur_p;

    SSL_TRC(3, ("%d: TLS13[%d]: handle client_key_share handshake",
		SSL_GETPID(), ss->fd));

    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    rv = ssl3_SetupPendingCipherSpec(ss);
    if (rv != SECSuccess)
        return SECFailure; /* Error code set below */

    /* Figure out what group we expect */
    switch (ss->ssl3.hs.kea_def->exchKeyType) {
#ifndef NSS_DISABLE_ECC
    case ssl_kea_ecdh:
        expectedGroup = ssl3_GetCurveNameForServerSocket(ss);
        if (!expectedGroup) {
            FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP,
                        handshake_failure);
            return SECFailure;
        }
        break;
#endif
    default:
        /* Got an unknown or unsupported Key Exchange Algorithm.
         * Can't happen. */
        FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG,
                    internal_error);
        return SECFailure;
    }

    /* Now walk through the keys until we find one for our group */
    cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares);
    while (cur_p != &ss->ssl3.hs.remoteKeyShares) {
        TLS13KeyShareEntry *offer = (TLS13KeyShareEntry*)cur_p;

        if (offer->group == expectedGroup) {
            found = offer;
            break;
        }
        cur_p = PR_NEXT_LINK(cur_p);
    }

    if (!found) {
        /* No acceptable group. In future, we will need to correct the client.
         * Currently just generate an error.
         * TODO(ekr@rtfm.com): Write code to correct client.
         */
        FATAL_ERROR(ss, SSL_ERROR_NO_CYPHER_OVERLAP, handshake_failure);
        return SECFailure;
    }

    /* Generate our key */
    rv = ssl3_CreateECDHEphemeralKeyPair(expectedGroup, &ss->ephemeralECDHKeyPair);
    if (rv != SECSuccess)
        return rv;

    ss->sec.keaType  = ss->ssl3.hs.kea_def->exchKeyType;
    ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(
        ss->ephemeralECDHKeyPair->pubKey);

    /* Register the sender */
    rv = ssl3_RegisterServerHelloExtensionSender(ss, ssl_tls13_key_share_xtn,
                                                 tls13_ServerSendKeyShareXtn);
    if (rv != SECSuccess)
        return SECFailure;  /* Error code set below */

    rv = tls13_HandleECDHEKeyShare(ss, found,
                                   ss->ephemeralECDHKeyPair->privKey,
                                   EphemeralSharedSecret);
    if (rv != SECSuccess)
        return SECFailure;  /* Error code set below */

    return SECSuccess;
}


/*
 *     [draft-ietf-tls-tls13-11] Section 6.3.3.2
 *
 *     opaque DistinguishedName<1..2^16-1>;
 *
 *     struct {
 *         opaque certificate_extension_oid<1..2^8-1>;
 *         opaque certificate_extension_values<0..2^16-1>;
 *     } CertificateExtension;
 *
 *     struct {
 *         opaque certificate_request_context<0..2^8-1>;
 *         SignatureAndHashAlgorithm
 *           supported_signature_algorithms<2..2^16-2>;
 *         DistinguishedName certificate_authorities<0..2^16-1>;
 *         CertificateExtension certificate_extensions<0..2^16-1>;
 *     } CertificateRequest;
 */
static SECStatus
tls13_SendCertificateRequest(sslSocket *ss)
{
    SECStatus rv;
    int calen;
    SECItem *names;
    int nnames;
    SECItem *name;
    int i;
    PRUint8 sigAlgs[MAX_SIGNATURE_ALGORITHMS * 2];
    unsigned int sigAlgsLength = 0;
    int length;

    SSL_TRC(3, ("%d: TLS13[%d]: begin send certificate_request",
		SSL_GETPID(), ss->fd));


    /* Fixed context value. */
    ss->ssl3.hs.certReqContext[0] = 0;
    ss->ssl3.hs.certReqContextLen = 1;

    rv = ssl3_EncodeCertificateRequestSigAlgs(ss, sigAlgs, sizeof(sigAlgs),
                                              &sigAlgsLength);
    if (rv != SECSuccess) {
        return rv;
    }

    ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames);
    length = 1 + ss->ssl3.hs.certReqContextLen
             + 2 + sigAlgsLength + 2 + calen + 2;

    rv = ssl3_AppendHandshakeHeader(ss, certificate_request, length);
    if (rv != SECSuccess) {
	return rv; 		/* err set by AppendHandshake. */
    }
    rv = ssl3_AppendHandshakeVariable(ss, ss->ssl3.hs.certReqContext,
                                      ss->ssl3.hs.certReqContextLen, 1);
    if (rv != SECSuccess) {
        return rv; 		/* err set by AppendHandshake. */
    }
    rv = ssl3_AppendHandshakeVariable(ss, sigAlgs, sigAlgsLength, 2);
    if (rv != SECSuccess) {
        return rv; 		/* err set by AppendHandshake. */
    }
    rv = ssl3_AppendHandshakeNumber(ss, calen, 2);
    if (rv != SECSuccess) {
	return rv; 		/* err set by AppendHandshake. */
    }
    for (i = 0, name = names; i < nnames; i++, name++) {
	rv = ssl3_AppendHandshakeVariable(ss, name->data, name->len, 2);
	if (rv != SECSuccess) {
	    return rv; 		/* err set by AppendHandshake. */
	}
    }
    rv = ssl3_AppendHandshakeNumber(ss, 0, 2);
    if (rv != SECSuccess) {
	return rv; 		/* err set by AppendHandshake. */
    }

    return SECSuccess;
}

static SECStatus
tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
    SECStatus rv;
    SECItem context = {siBuffer, NULL, 0};
    SECItem algorithms  = {siBuffer, NULL, 0};
    PLArenaPool *arena;
    CERTDistNames ca_list;
    PRInt32 extensionsLength;

    SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence",
		SSL_GETPID(), ss->fd));

    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    /* Client */
    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST, wait_cert_request);
    if (rv != SECSuccess) {
	return SECFailure;
    }

    PORT_Assert(ss->ssl3.clientCertChain == NULL);
    PORT_Assert(ss->ssl3.clientCertificate == NULL);
    PORT_Assert(ss->ssl3.clientPrivateKey == NULL);

    rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
    if (rv != SECSuccess)
        return SECFailure;
    PR_STATIC_ASSERT(sizeof(ss->ssl3.hs.certReqContext) == 255);
    PORT_Memcpy(ss->ssl3.hs.certReqContext, context.data, context.len);
    ss->ssl3.hs.certReqContextLen = context.len;

    rv = ssl3_ConsumeHandshakeVariable(ss, &algorithms, 2, &b, &length);
    if (rv != SECSuccess)
        return SECFailure;

    if (algorithms.len == 0 || (algorithms.len & 1) != 0) {
	FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
                    illegal_parameter);
	return SECFailure;
    }

    arena = ca_list.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if (!arena) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    rv = ssl3_ParseCertificateRequestCAs(ss, &b, &length, arena, &ca_list);
    if (rv != SECSuccess)
        goto loser; /* alert sent below */

    /* Verify that the extensions length is correct. */
    extensionsLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length);
    if (extensionsLength < 0) {
        goto loser; /* alert sent below */
    }
    if (extensionsLength != length) {
	FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST,
                    illegal_parameter);
        goto loser;
    }

    TLS13_SET_HS_STATE(ss, wait_server_cert);

    rv = ssl3_CompleteHandleCertificateRequest(ss, &algorithms, &ca_list);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        goto loser;
    }

    return SECSuccess;

loser:
    PORT_FreeArena(arena, PR_FALSE);
    return SECFailure;
}

static SECStatus
tls13_InitializeHandshakeEncryption(sslSocket *ss)
{
    SECStatus rv;

    /* For all present cipher suites, SS = ES.
     * TODO(ekr@rtfm.com): Revisit for 0-RTT. */
    ss->ssl3.hs.xSS = PK11_ReferenceSymKey(ss->ssl3.hs.xES);
    if (!ss->ssl3.hs.xSS) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    rv = tls13_InitCipherSpec(ss, TrafficKeyHandshake,
                              InstallCipherSpecBoth);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_INIT_CIPHER_SUITE_FAILURE, internal_error);
        return SECFailure;
    }

    return rv;
}

/* Called from:  ssl3_HandleClientHello */
SECStatus
tls13_SendServerHelloSequence(sslSocket *ss)
{
    SECStatus rv;
    SSL3KEAType certIndex;

    SSL_TRC(3, ("%d: TLS13[%d]: begin send server_hello sequence",
		SSL_GETPID(), ss->fd));

    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );

    rv = ssl3_SendServerHello(ss);
    if (rv != SECSuccess) {
	return rv;	/* err code is set. */
    }

    rv = tls13_InitializeHandshakeEncryption(ss);
    if (rv != SECSuccess) {
        return SECFailure;      /* error code is set. */
    }

    rv = tls13_SendEncryptedExtensions(ss);
    if (rv != SECSuccess) {
	return SECFailure;	/* error code is set. */
    }

    if (ss->opt.requestCertificate) {
	rv = tls13_SendCertificateRequest(ss);
	if (rv != SECSuccess) {
	    return SECFailure;		/* error code is set. */
	}
    }
    rv = ssl3_SendCertificate(ss);
    if (rv != SECSuccess) {
	return SECFailure;	/* error code is set. */
    }
    rv = ssl3_SendCertificateStatus(ss);
    if (rv != SECSuccess) {
	return SECFailure;	/* error code is set. */
    }

    /* This was copied from: ssl3_SendCertificate.
     * TODO(ekr@rtfm.com): Verify that this selection logic is correct.
     * Bug 1237514.
    */
    if ((ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa) ||
        (ss->ssl3.hs.kea_def->kea == kea_dhe_rsa)) {
        certIndex = kt_rsa;
    } else {
        certIndex = ss->ssl3.hs.kea_def->exchKeyType;
    }
    rv = ssl3_SendCertificateVerify(ss, ss->serverCerts[certIndex].SERVERKEY);
    if (rv != SECSuccess) {
        return rv;		/* err code is set. */
    }

    /* Compute the rest of the secrets except for the resumption
     * and exporter secret. */
    rv = tls13_ComputeSecrets1(ss);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    rv = tls13_SendFinished(ss);
    if (rv != SECSuccess) {
	return rv;	/* error code is set. */
    }

    TLS13_SET_HS_STATE(ss, ss->opt.requestCertificate ?
                       wait_client_cert : wait_finished);

    return SECSuccess;
}

/*
 * Called from ssl3_HandleServerHello.
 *
 * Caller must hold Handshake and RecvBuf locks.
 */
SECStatus
tls13_HandleServerKeyShare(sslSocket *ss)
{
    SECStatus rv;
    ECName expectedGroup;
    PRCList *cur_p;
    TLS13KeyShareEntry *entry;

    SSL_TRC(3, ("%d: TLS13[%d]: handle server_key_share handshake",
		SSL_GETPID(), ss->fd));
    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    switch (ss->ssl3.hs.kea_def->exchKeyType) {
#ifndef NSS_DISABLE_ECC
    case ssl_kea_ecdh:
        expectedGroup = ssl3_PubKey2ECName(ss->ephemeralECDHKeyPair->pubKey);
        break;
#endif /* NSS_DISABLE_ECC */
    default:
        FATAL_ERROR(ss, SEC_ERROR_UNSUPPORTED_KEYALG, handshake_failure);
        return SECFailure;
    }

    /* This list should have one entry. */
    cur_p = PR_NEXT_LINK(&ss->ssl3.hs.remoteKeyShares);
    if (!cur_p) {
        FATAL_ERROR(ss, SSL_ERROR_MISSING_KEY_SHARE, missing_extension);
        return SECFailure;
    }
    PORT_Assert(PR_NEXT_LINK(cur_p) == &ss->ssl3.hs.remoteKeyShares);

    entry = (TLS13KeyShareEntry*)cur_p;
    if (entry->group != expectedGroup) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_KEY_SHARE, illegal_parameter);
        return SECFailure;
    }

    rv = tls13_HandleECDHEKeyShare(ss, entry,
                                   ss->ephemeralECDHKeyPair->privKey,
                                   EphemeralSharedSecret);

    ss->sec.keaType  = ss->ssl3.hs.kea_def->exchKeyType;
    ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(
        ss->ephemeralECDHKeyPair->pubKey);

    if (rv != SECSuccess)
        return SECFailure;  /* Error code set below */

    return tls13_InitializeHandshakeEncryption(ss);
}

/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
 * tls13 Certificate message.
 * Caller must hold Handshake and RecvBuf locks.
 */
static SECStatus
tls13_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
    SECStatus rv;
    SECItem context = {siBuffer, NULL, 0};

    SSL_TRC(3, ("%d: TLS13[%d]: handle certificate handshake",
		SSL_GETPID(), ss->fd));
    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    if (ss->sec.isServer) {
        rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
                                  wait_client_cert);
    } else {
        rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERTIFICATE,
                                  wait_cert_request, wait_server_cert);
    }
    if (rv != SECSuccess)
        return SECFailure;

    /* Process the context string */
    rv = ssl3_ConsumeHandshakeVariable(ss, &context, 1, &b, &length);
    if (rv != SECSuccess)
        return SECFailure;
    if (!ss->sec.isServer) {
        if (context.len) {
            /* The server's context string MUST be empty */
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE,
                        illegal_parameter);
            return SECFailure;
        }
    } else {
        if (!context.len || context.len != ss->ssl3.hs.certReqContextLen ||
            (NSS_SecureMemcmp(ss->ssl3.hs.certReqContext,
                              context.data, context.len) != 0)) {
            FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE,
                        illegal_parameter);
            return SECFailure;
        }
        context.len = 0; /* Belt and suspenders. Zero out the context. */
    }


    return ssl3_CompleteHandleCertificate(ss, b, length);
}

/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
 * ssl3 CertificateStatus message.
 * Caller must hold Handshake and RecvBuf locks.
 */
static SECStatus
tls13_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
    SECStatus rv;

    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_STATUS,
                              wait_certificate_status);
    if (rv != SECSuccess)
        return rv;

    return ssl3_CompleteHandleCertificateStatus(ss, b, length);
}

/*
 * TODO(ekr@rtfm.com): This install logic needs renaming since it's
 * what happens at various stages of cipher spec setup. Legacy from ssl3con.c.
 */
int
tls13_InstallCipherSpec(sslSocket *ss, InstallCipherSpecDirection direction)
{
    SSL_TRC(3, ("%d: TLS13[%d]: Installing new cipher specs direction = %s",
		SSL_GETPID(), ss->fd,
                direction == InstallCipherSpecRead ? "read" : "write"));

    PORT_Assert(!IS_DTLS(ss));  /* TODO(ekr@rtfm.com): Update for DTLS */
    /* TODO(ekr@rtfm.com): Holddown timer for DTLS. */
    ssl_GetSpecWriteLock(ss);	/**************************************/

    /* Flush out any old stuff in the handshake buffers */
    switch (direction) {
        case InstallCipherSpecWrite:
            {
                ssl3CipherSpec *pwSpec;
                pwSpec = ss->ssl3.pwSpec;

                ss->ssl3.pwSpec = ss->ssl3.cwSpec;
                ss->ssl3.cwSpec = pwSpec;
                break;
            }
            break;
        case InstallCipherSpecRead:
            {
                ssl3CipherSpec *prSpec;

                prSpec = ss->ssl3.prSpec;
                ss->ssl3.prSpec  = ss->ssl3.crSpec;
                ss->ssl3.crSpec  = prSpec;
            }
            break;
        default:
            PORT_Assert(0);
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
            ssl_ReleaseSpecWriteLock(ss); /**************************************/
            return SECFailure;
    }

    /* If we are really through with the old cipher prSpec
     * (Both the read and write sides have changed) destroy it.
     */
    if (ss->ssl3.prSpec == ss->ssl3.pwSpec) {
    	ssl3_DestroyCipherSpec(ss->ssl3.prSpec, PR_FALSE/*freeSrvName*/);
    }
    ssl_ReleaseSpecWriteLock(ss); /**************************************/

    return SECSuccess;
}

/* Add context to the hash functions as described in 
   [draft-ietf-tls-tls13; Section 4.9.1] */
SECStatus
tls13_AddContextToHashes(sslSocket *ss, SSL3Hashes *hashes /* IN/OUT */,
                         SSLHashType algorithm, PRBool sending)
{
    SECStatus rv = SECSuccess;
    PK11Context* ctx;
    const unsigned char context_padding[] = {
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
        0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
    };
    const char *client_cert_verify_string = "TLS 1.3, client CertificateVerify";
    const char *server_cert_verify_string = "TLS 1.3, server CertificateVerify";
    const char *context_string = (sending ^ ss->sec.isServer) ?
            client_cert_verify_string : server_cert_verify_string;
    unsigned int hashlength;

    /* Double check that we are doing SHA-256 for the handshake hash.*/
    PORT_Assert(hashes->hashAlg == ssl_hash_sha256);
    if (hashes->hashAlg != ssl_hash_sha256) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        goto loser;
    }
    PORT_Assert(hashes->len == 32);

    ctx = PK11_CreateDigestContext(ssl3_TLSHashAlgorithmToOID(algorithm));
    if (!ctx) {
        PORT_SetError(SEC_ERROR_NO_MEMORY);
        goto loser;
    }

    PR_STATIC_ASSERT(SECFailure);
    PR_STATIC_ASSERT(!SECSuccess);

    rv |= PK11_DigestBegin(ctx);
    rv |= PK11_DigestOp(ctx, context_padding, sizeof(context_padding));
    rv |= PK11_DigestOp(ctx, (unsigned char *)context_string,
                        strlen(context_string) + 1); /* +1 includes the terminating 0 */
    rv |= PK11_DigestOp(ctx, hashes->u.raw, hashes->len);
    /* Update the hash in-place */
    rv |= PK11_DigestFinal(ctx, hashes->u.raw, &hashlength, sizeof(hashes->u.raw));
    PK11_DestroyContext(ctx, PR_TRUE);
    PRINT_BUF(90, (NULL, "TLS 1.3 hash with context", hashes->u.raw, hashlength));

    hashes->len = hashlength;
    hashes->hashAlg = algorithm;

    if (rv) {
        ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
        goto loser;
    }
    return SECSuccess;

loser:
    return SECFailure;
}

static SECStatus
tls13_HkdfExtractSharedKey(sslSocket *ss, PK11SymKey* key,
                           SharedSecretType keyType)
{
    PK11SymKey** destp;

    switch(keyType) {
        case EphemeralSharedSecret:
            destp = &ss->ssl3.hs.xES;
            break;
        case StaticSharedSecret:
            destp = &ss->ssl3.hs.xSS;
            break;
        default:
            PORT_Assert(0);
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
            return SECFailure;
    }

    PORT_Assert(!*destp);
    return tls13_HkdfExtract(NULL, key, tls13_GetHash(ss), destp);
}

static SECStatus
tls13_DeriveTrafficKeys(sslSocket *ss, ssl3CipherSpec *pwSpec,
                        TrafficKeyType type)
{
    size_t keySize = pwSpec->cipher_def->key_size;
    size_t ivSize = pwSpec->cipher_def->iv_size +
            pwSpec->cipher_def->explicit_nonce_size; /* This isn't always going to
                                                      * work, but it does for
                                                      * AES-GCM */
    CK_MECHANISM_TYPE bulkAlgorithm = ssl3_Alg2Mech(pwSpec->cipher_def->calg);
    SSL3Hashes hashes;
    PK11SymKey *prk = NULL;
    const char *phase;
    char label[256]; /* Arbitrary buffer large enough to hold the label */
    SECStatus rv;

#define FORMAT_LABEL(phase_, purpose_) do { \
        PRUint32 n = PR_snprintf(label, sizeof(label), "%s, %s", phase_, purpose_); \
        /* Check for getting close. */                                  \
        if ((n+1) >= sizeof(label)) {                                   \
                PORT_Assert(0);                                         \
                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);               \
                goto loser;                                             \
        }                                                               \
    } while(0)
#define EXPAND_TRAFFIC_KEY(purpose_, target_)                           \
    do {                                                                \
        FORMAT_LABEL(phase, purpose_);                                  \
        rv = tls13_HkdfExpandLabel(prk, tls13_GetHash(ss),              \
                                   hashes.u.raw, hashes.len,            \
                                   label, strlen(label),                \
                                   bulkAlgorithm, keySize, &pwSpec->target_); \
        if (rv != SECSuccess) {                                         \
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);                   \
            PORT_Assert(0);                                             \
            goto loser;                                                 \
        }                                                               \
    } while (0)

#define EXPAND_TRAFFIC_IV(purpose_, target_)                    \
    do {                                                        \
        FORMAT_LABEL(phase, purpose_);                          \
        rv = tls13_HkdfExpandLabelRaw(prk, tls13_GetHash(ss),   \
                                      hashes.u.raw, hashes.len, \
                                      label, strlen(label),     \
                                      pwSpec->target_, ivSize); \
        if (rv != SECSuccess) {                                 \
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);           \
            PORT_Assert(0);                                     \
            goto loser;                                         \
        }                                                       \
    } while (0)


    PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
    PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
    PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);

    rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0);
    if (rv != SECSuccess) {
        PORT_Assert(0);  /* Should never fail */
        ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
        return SECFailure;
    }
    PRINT_BUF(60, (ss, "Deriving traffic keys. Session hash=", hashes.u.raw,
                   hashes.len));

    switch (type) {
        case TrafficKeyHandshake:
            phase = kHkdfPhaseHandshakeKeys;
            prk = ss->ssl3.hs.xES;
            break;
        case TrafficKeyApplicationData:
            phase = kHkdfPhaseApplicationDataKeys;
            prk = ss->ssl3.hs.trafficSecret;
            break;
        default:
            PORT_Assert(0);
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
            return SECFailure;
    }
    PORT_Assert(prk != NULL);

    SSL_TRC(3, ("%d: TLS13[%d]: deriving traffic keys phase='%s'",
                SSL_GETPID(), ss->fd, phase));

    EXPAND_TRAFFIC_KEY(kHkdfPurposeClientWriteKey, client.write_key);
    EXPAND_TRAFFIC_KEY(kHkdfPurposeServerWriteKey, server.write_key);
    EXPAND_TRAFFIC_IV(kHkdfPurposeClientWriteIv, client.write_iv);
    EXPAND_TRAFFIC_IV(kHkdfPurposeServerWriteIv, server.write_iv);

    return SECSuccess;

loser:
    return SECFailure;
}

/* Set up a cipher spec with keys. If install is nonzero, then also install
 * it as the current cipher spec for each value in the mask. */
SECStatus
tls13_InitCipherSpec(sslSocket *ss, TrafficKeyType type, InstallCipherSpecDirection install)
{
    ssl3CipherSpec *pwSpec;
    ssl3CipherSpec *cwSpec;
    SECStatus rv;
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));

    if (install == InstallCipherSpecWrite ||
        install == InstallCipherSpecBoth) {
        ssl_GetXmitBufLock(ss);

        rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
        ssl_ReleaseXmitBufLock(ss);
        if (rv != SECSuccess) {
            goto loser;
        }
    }

    ssl_GetSpecWriteLock(ss);	/**************************************/

    PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec);

    pwSpec = ss->ssl3.pwSpec;
    cwSpec = ss->ssl3.cwSpec;

    switch(pwSpec->cipher_def->calg) {
        case calg_aes_gcm:
            pwSpec->aead = tls13_AESGCM;
            break;
        default:
            PORT_Assert(0);
            goto loser;
            break;
    }

    /* Generic behaviors -- common to all crypto methods */
    if (!IS_DTLS(ss)) {
	pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0;
    } else {
	if (cwSpec->epoch == PR_UINT16_MAX) {
	    /* The problem here is that we have rehandshaked too many
	     * times (you are not allowed to wrap the epoch). The
	     * spec says you should be discarding the connection
	     * and start over, so not much we can do here. */
	    rv = SECFailure;
            goto loser;
	}
	/* The sequence number has the high 16 bits as the epoch. */
	pwSpec->epoch = cwSpec->epoch + 1;
	pwSpec->read_seq_num.high = pwSpec->write_seq_num.high =
	    pwSpec->epoch << 16;

	dtls_InitRecvdRecords(&pwSpec->recvdRecords);
    }
    pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0;

    rv = tls13_DeriveTrafficKeys(ss, pwSpec, type);
    if (rv != SECSuccess) {
        goto loser;
    }
    if (install == InstallCipherSpecWrite ||
        install == InstallCipherSpecBoth) {
        rv = tls13_InstallCipherSpec(ss, InstallCipherSpecWrite);
        if (rv != SECSuccess) {
            goto loser;
        }
    }
    if (install == InstallCipherSpecRead ||
        install == InstallCipherSpecBoth) {
        rv = tls13_InstallCipherSpec(ss, InstallCipherSpecRead);
        if (rv != SECSuccess) {
            goto loser;
        }
    }
    ssl_ReleaseSpecWriteLock(ss);	/**************************************/

    return SECSuccess;

loser:
    ssl_ReleaseSpecWriteLock(ss);	/**************************************/
    PORT_SetError(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE);
    return SECFailure;
}

static SECStatus
tls13_ComputeSecrets1(sslSocket *ss)
{
    SECStatus rv;
    PK11SymKey *mSS = NULL;
    PK11SymKey *mES = NULL;
    PK11SymKey *masterSecret = NULL;
    SSL3Hashes hashes;

    rv = ssl3_SetupPendingCipherSpec(ss);
    if (rv != SECSuccess) {
        return rv;  /* error code set below. */
    }

    rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.pwSpec, &hashes, 0);
    if (rv != SECSuccess) {
        PORT_Assert(0);  /* Should never fail */
        ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
        return SECFailure;
    }

    PORT_Assert(ss->ssl3.hs.xSS);
    PORT_Assert(ss->ssl3.hs.xES);

    rv = tls13_HkdfExpandLabel(ss->ssl3.hs.xSS,
                               tls13_GetHash(ss),
                               hashes.u.raw, hashes.len,
                               kHkdfLabelExpandedSs,
                               strlen(kHkdfLabelExpandedSs),
                               tls13_GetHkdfMechanism(ss),
                               hashes.len, &mSS);
    if (rv != SECSuccess) {
        goto loser;
    }

    rv = tls13_HkdfExpandLabel(ss->ssl3.hs.xES,
                               tls13_GetHash(ss),
                               hashes.u.raw, hashes.len,
                               kHkdfLabelExpandedEs,
                               strlen(kHkdfLabelExpandedEs),
                               tls13_GetHkdfMechanism(ss),
                               hashes.len, &mES);
    if (rv != SECSuccess) {
        goto loser;
    }

    rv = tls13_HkdfExtract(mSS, mES,
                           tls13_GetHash(ss),
                           &masterSecret);

    if (rv != SECSuccess) {
        goto loser;
    }

    rv = tls13_HkdfExpandLabel(masterSecret,
                               tls13_GetHash(ss),
                               hashes.u.raw, hashes.len,
                               kHkdfLabelTrafficSecret,
                               strlen(kHkdfLabelTrafficSecret),
                               tls13_GetHkdfMechanism(ss),
                               hashes.len, &ss->ssl3.hs.trafficSecret);
    if (rv != SECSuccess) {
        goto loser;
    }

    rv = tls13_HkdfExpandLabel(masterSecret,
                               tls13_GetHash(ss),
                               NULL, 0,
                               kHkdfLabelClientFinishedSecret,
                               strlen(kHkdfLabelClientFinishedSecret),
                               tls13_GetHmacMechanism(ss),
                               hashes.len, &ss->ssl3.hs.clientFinishedSecret);
    if (rv != SECSuccess) {
        goto loser;
    }

    rv = tls13_HkdfExpandLabel(masterSecret,
                               tls13_GetHash(ss),
                               NULL, 0,
                               kHkdfLabelServerFinishedSecret,
                               strlen(kHkdfLabelServerFinishedSecret),
                               tls13_GetHmacMechanism(ss),
                               hashes.len, &ss->ssl3.hs.serverFinishedSecret);
    if (rv != SECSuccess) {
        goto loser;
    }

loser:
    PK11_FreeSymKey(ss->ssl3.hs.xSS);
    PK11_FreeSymKey(ss->ssl3.hs.xES);

    if (mSS) {
        PK11_FreeSymKey(mSS);
    }
    if (mES) {
        PK11_FreeSymKey(mES);
    }
    if (masterSecret) {
        PK11_FreeSymKey(masterSecret);
    }

    return rv;
}

void
tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *offer)
{
    SECITEM_ZfreeItem(&offer->key_exchange, PR_FALSE);
    PORT_ZFree(offer, sizeof(offer));
}

void
tls13_DestroyKeyShares(PRCList *list)
{
    PRCList *cur_p;

    while (!PR_CLIST_IS_EMPTY(list)) {
        cur_p = PR_LIST_TAIL(list);
        PR_REMOVE_LINK(cur_p);
        tls13_DestroyKeyShareEntry((TLS13KeyShareEntry *)cur_p);
    }
}

/* Implement the SSLAEADCipher interface defined in sslimpl.h.
 *
 * That interface mixes the AD and the sequence number, but in
 * TLS 1.3 there is no additional data so this value is just the
 * encoded sequence number and we call it |seqNumBuf|.
 */
static SECStatus
tls13_AESGCM(ssl3KeyMaterial *keys,
             PRBool doDecrypt,
             unsigned char *out,
             int *outlen,
             int maxout,
             const unsigned char *in,
             int inlen,
             const unsigned char *seqNumBuf,
             int seqNumLen)
{
    SECItem param;
    SECStatus rv = SECFailure;
    unsigned char nonce[12];
    size_t i;
    unsigned int uOutLen;
    CK_GCM_PARAMS gcmParams;
    static const int tagSize = 16;

    PORT_Assert(seqNumLen == 8);

    /* draft-ietf-tls-tls13 Section 5.2.2 specifies the following
     * nonce algorithm:
     *
     * The length of the per-record nonce (iv_length) is set to max(8 bytes,
     * N_MIN) for the AEAD algorithm (see [RFC5116] Section 4).  An AEAD
     * algorithm where N_MAX is less than 8 bytes MUST NOT be used with TLS.
     * The per-record nonce for the AEAD construction is formed as follows:
     *
     * 1.  The 64-bit record sequence number is padded to the left with
     *     zeroes to iv_length.
     *
     * 2.  The padded sequence number is XORed with the static
     *     client_write_iv or server_write_iv, depending on the role.
     *
     * The resulting quantity (of length iv_length) is used as the per-
     * record nonce.
     *
     * Per RFC 5288: N_MIN = N_MAX = 12 bytes.
     *
     */
    memcpy(nonce, keys->write_iv, sizeof(nonce));
    for (i=0; i < 8; ++i) {
        nonce[4 + i] ^= seqNumBuf[i];
    }

    param.type = siBuffer;
    param.data = (unsigned char *) &gcmParams;
    param.len = sizeof(gcmParams);
    gcmParams.pIv = nonce;
    gcmParams.ulIvLen = sizeof(nonce);
    gcmParams.pAAD = NULL;
    gcmParams.ulAADLen = 0;
    gcmParams.ulTagBits = tagSize * 8;

    if (doDecrypt) {
	rv = PK11_Decrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
			  maxout, in, inlen);
    } else {
	rv = PK11_Encrypt(keys->write_key, CKM_AES_GCM, &param, out, &uOutLen,
			  maxout, in, inlen);
    }
    *outlen = (int)uOutLen;

    return rv;
}

static SECStatus
tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
    SECStatus rv;

    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    SSL_TRC(3, ("%d: TLS13[%d]: handle encrypted extensions",
    	SSL_GETPID(), ss->fd));

    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_ENCRYPTED_EXTENSIONS,
                              wait_encrypted_extensions);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    rv = ssl3_HandleHelloExtensions(ss, &b, &length, encrypted_extensions);
    if (rv != SECSuccess) {
        return SECFailure;  /* Error code set below */
    }

    TLS13_SET_HS_STATE(ss, wait_cert_request);
    return SECSuccess;
}

static SECStatus
tls13_SendEncryptedExtensions(sslSocket *ss)
{
    SECStatus rv;
    PRInt32 extensions_len = 0;
    PRInt32 sent_len = 0;
    PRUint32 maxBytes = 65535;

    SSL_TRC(3, ("%d: TLS13[%d]: send encrypted extensions handshake",
                SSL_GETPID(), ss->fd));

    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );

    extensions_len = ssl3_CallHelloExtensionSenders(
        ss, PR_FALSE, maxBytes, &ss->xtnData.encryptedExtensionsSenders[0]);

    rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, extensions_len);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    sent_len = ssl3_CallHelloExtensionSenders(
        ss, PR_TRUE, extensions_len, &ss->xtnData.encryptedExtensionsSenders[0]);
    PORT_Assert(sent_len == extensions_len);
    if (sent_len != extensions_len) {
        PORT_Assert(sent_len == 0);
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    return SECSuccess;
}

/* Called from tls13_CompleteHandleHandshakeMessage() when it has deciphered a complete
 * tls13 CertificateVerify message
 * Caller must hold Handshake and RecvBuf locks.
 */
SECStatus
tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
                              SSL3Hashes *hashes)
{
    SECItem              signed_hash = {siBuffer, NULL, 0};
    SECStatus            rv;
    SSLSignatureAndHashAlg sigAndHash;

    SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_verify handshake",
		SSL_GETPID(), ss->fd));
    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY,
                              wait_cert_verify);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    if (!hashes) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    /* We only support CertificateVerify messages that use the handshake
     * hash.
     * TODO(ekr@rtfm.com): This should be easy to relax in TLS 1.3 by
     * reading the client's hash algorithm first, but there may
     * be subtleties so retain the restriction for now.
     */
    rv = tls13_AddContextToHashes(ss, hashes, hashes->hashAlg, PR_FALSE);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_DIGEST_FAILURE, internal_error);
        return SECFailure;
    }

    rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length,
                                               &sigAndHash);
    if (rv != SECSuccess) {
        PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
	return SECFailure;
    }

    rv = ssl3_CheckSignatureAndHashAlgorithmConsistency(
        ss, &sigAndHash, ss->sec.peerCert);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decrypt_error);
        return SECFailure;
    }

    /* We only support CertificateVerify messages that use the handshake
     * hash. */
    if (sigAndHash.hashAlg != hashes->hashAlg) {
        FATAL_ERROR(ss, SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM, decrypt_error);
        return SECFailure;
    }

    rv = ssl3_ConsumeHandshakeVariable(ss, &signed_hash, 2, &b, &length);
    if (rv != SECSuccess) {
        PORT_SetError(SSL_ERROR_RX_MALFORMED_CERT_VERIFY);
	return SECFailure;
    }

    if (length != 0) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_VERIFY, decode_error);
        return SECFailure;
    }

    rv = ssl3_VerifySignedHashes(hashes, ss->sec.peerCert, &signed_hash,
				 PR_TRUE, ss->pkcs11PinArg);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, PORT_GetError(), decrypt_error);
        return SECFailure;
    }

    if (!ss->sec.isServer) {
        /* Compute the rest of the secrets except for the resumption
         * and exporter secret. */
        rv = tls13_ComputeSecrets1(ss);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
            return SECFailure;
        }
    }
    TLS13_SET_HS_STATE(ss, wait_finished);

    return SECSuccess;
}

static SECStatus
tls13_ComputeFinished(sslSocket *ss, const SSL3Hashes *hashes, PRBool sending,
                      PRUint8 *output, unsigned int *outputLen, unsigned int maxOutputLen)
{
    SECStatus rv;
    PK11Context *hmacCtx = NULL;
    CK_MECHANISM_TYPE macAlg = tls13_GetHmacMechanism(ss);
    SECItem param = { siBuffer, NULL, 0 };
    unsigned int outputLenUint;
    PK11SymKey *secret = (ss->sec.isServer ^ sending) ?
            ss->ssl3.hs.clientFinishedSecret : ss->ssl3.hs.serverFinishedSecret;

    PORT_Assert(secret);
    PRINT_BUF(90, (NULL, "Handshake hash", hashes->u.raw, hashes->len));

    hmacCtx = PK11_CreateContextBySymKey(macAlg, CKA_SIGN,
                                         secret, &param);
    if (!hmacCtx) {
        goto abort;
    }

    rv = PK11_DigestBegin(hmacCtx);
    if (rv != SECSuccess)
        goto abort;

    rv = PK11_DigestOp(hmacCtx, hashes->u.raw, hashes->len);
    if (rv != SECSuccess)
        goto abort;

    PORT_Assert(maxOutputLen >= hashes->len);
    rv = PK11_DigestFinal(hmacCtx, output, &outputLenUint, maxOutputLen);
    if (rv != SECSuccess)
        goto abort;
    *outputLen = outputLenUint;

    PK11_DestroyContext(hmacCtx, PR_TRUE);
    return SECSuccess;

abort:
    if (hmacCtx) {
        PK11_DestroyContext(hmacCtx, PR_TRUE);
    }

    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
    return SECFailure;
}

static SECStatus
tls13_SendFinished(sslSocket *ss)
{
    SECStatus rv;
    PRUint8 finishedBuf[MAX_FINISHED_SIZE];
    unsigned int finishedLen;
    SSL3Hashes hashes;
    int errCode;

    SSL_TRC(3, ("%d: TLS13[%d]: send finished handshake", SSL_GETPID(), ss->fd));

    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));

    rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    ssl_GetSpecReadLock(ss);
    rv = tls13_ComputeFinished(ss, &hashes, PR_TRUE,
                               finishedBuf, &finishedLen, sizeof(finishedBuf));
    ssl_ReleaseSpecReadLock(ss);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    rv = ssl3_AppendHandshakeHeader(ss, finished, finishedLen);
    if (rv != SECSuccess) {
        errCode = PR_GetError();
        goto alert_loser;
    }

    rv = ssl3_AppendHandshake(ss, finishedBuf, finishedLen);
    if (rv != SECSuccess) {
        errCode = PR_GetError();
        goto alert_loser;
    }

    rv = ssl3_FlushHandshake(ss, 0);
    if (rv != SECSuccess) {
        errCode = PR_GetError();
        goto alert_loser;
    }

    if (!ss->sec.isServer) {
        rv = tls13_InitCipherSpec(ss, TrafficKeyApplicationData,
                                  InstallCipherSpecBoth);
        if (rv != SECSuccess) {
            errCode = PR_GetError();
            goto alert_loser;
        }
    }

    /* TODO(ekr@rtfm.com): Record key log */
    return SECSuccess;

  alert_loser:
    (void)SSL3_SendAlert(ss, alert_fatal, internal_error);
    PORT_SetError(errCode);  /* Restore error code */
    return rv;
}

static SECStatus
tls13_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length,
                     const SSL3Hashes *hashes)
{
    SECStatus rv;
    PRUint8 finishedBuf[MAX_FINISHED_SIZE];
    unsigned int finishedLen;

    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    SSL_TRC(3, ("%d: TLS13[%d]: handle finished handshake",
    	SSL_GETPID(), ss->fd));

    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_FINISHED, wait_finished);
    if (rv != SECSuccess) {
	return SECFailure;
    }
    if (!hashes) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
        return SECFailure;
    }

    ssl_GetSpecReadLock(ss);
    rv = tls13_ComputeFinished(ss, hashes, PR_FALSE,
                               finishedBuf, &finishedLen, sizeof(finishedBuf));
    ssl_ReleaseSpecReadLock(ss);
    if (rv != SECSuccess) {
        FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
	return SECFailure;
    }

    if (length != finishedLen) {
        FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_FINISHED, decode_error);
        return SECFailure;
    }

    if (NSS_SecureMemcmp(b, finishedBuf, finishedLen) != 0) {
        FATAL_ERROR(ss, SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE,
                    decrypt_error);
        return SECFailure;
    }

    /* Server is now finished.
     * Client sends second flight
     */
    /* TODO(ekr@rtfm.com): Send NewSession Ticket if server. */
    if (ss->sec.isServer) {
        rv = tls13_InitCipherSpec(ss, TrafficKeyApplicationData,
                                  InstallCipherSpecBoth);
        if (rv != SECSuccess) {
            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
            return SECFailure;
        }

        rv = tls13_FinishHandshake(ss);
    } else {
        if (ss->ssl3.hs.authCertificatePending) {
            /* TODO(ekr@rtfm.com): Handle pending auth */
            FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
            PORT_Assert(0);
            return SECFailure;
        }
        rv = tls13_SendClientSecondRound(ss);
        if (rv != SECSuccess)
            return SECFailure;  /* Error code and alerts handled below */
    }

    return rv;
}

static SECStatus
tls13_FinishHandshake(sslSocket *ss)
{
    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );
    PORT_Assert( ss->ssl3.hs.restartTarget == NULL );

    /* The first handshake is now completed. */
    ss->handshake           = NULL;

    TLS13_SET_HS_STATE(ss, idle_handshake);

    ssl_FinishHandshake(ss);

    return SECSuccess;
}

static SECStatus
tls13_SendClientSecondRound(sslSocket *ss)
{
    SECStatus rv;
    PRBool sendClientCert;

    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
    PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) );

    sendClientCert = !ss->ssl3.sendEmptyCert &&
		     ss->ssl3.clientCertChain  != NULL &&
		     ss->ssl3.clientPrivateKey != NULL;

    /* Defer client authentication sending if we are still
     * waiting for server authentication. See the long block
     * comment in ssl3_SendClientSecondRound for more detail.
     */
    if (ss->ssl3.hs.restartTarget) {
	PR_NOT_REACHED("unexpected ss->ssl3.hs.restartTarget");
	PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
	return SECFailure;
    }
    if (ss->ssl3.hs.authCertificatePending && (sendClientCert ||
                                               ss->ssl3.sendEmptyCert)) {
	SSL_TRC(3, ("%d: TLS13[%p]: deferring ssl3_SendClientSecondRound because"
		    " certificate authentication is still pending.",
		    SSL_GETPID(), ss->fd));
	ss->ssl3.hs.restartTarget = tls13_SendClientSecondRound;
	return SECWouldBlock;
    }

    ssl_GetXmitBufLock(ss);		/*******************************/
    if (ss->ssl3.sendEmptyCert) {
	ss->ssl3.sendEmptyCert = PR_FALSE;
	rv = ssl3_SendEmptyCertificate(ss);
	/* Don't send verify */
	if (rv != SECSuccess) {
	    goto loser;	/* error code is set. */
    	}
    } else if (sendClientCert) {
	rv = ssl3_SendCertificate(ss);
	if (rv != SECSuccess) {
	    goto loser;	/* error code is set. */
    	}
    }

    if (sendClientCert) {
	rv = ssl3_SendCertificateVerify(ss, ss->ssl3.clientPrivateKey);
        SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey);
        ss->ssl3.clientPrivateKey = NULL;
	if (rv != SECSuccess) {
	    goto loser;	/* err is set. */
        }
    }

    rv = tls13_SendFinished(ss);
    if (rv != SECSuccess) {
	goto loser;	/* err code was set. */
    }
    ssl_ReleaseXmitBufLock(ss);		/*******************************/

    /* The handshake is now finished */
    return tls13_FinishHandshake(ss);

loser:
    ssl_ReleaseXmitBufLock(ss);		/*******************************/
    return SECFailure;
}

static SECStatus
tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length)
{
    SECStatus rv;

    rv = TLS13_CHECK_HS_STATE(ss, SSL_ERROR_RX_UNEXPECTED_NEW_SESSION_TICKET,
                              idle_handshake);
    if (rv != SECSuccess) {
        return SECFailure;
    }

    UNIMPLEMENTED();

    /* Ignore */
    return SECSuccess;
}


typedef enum {
    ExtensionNotUsed,
    ExtensionClientOnly,
    ExtensionSendClear,
    ExtensionSendEncrypted,
    ExtensionUnknown,
} Tls13ExtensionStatus;

static const struct {
    SSLExtensionType ex_value;
    Tls13ExtensionStatus status;
} KnownExtensions[] = {
    {
        ssl_server_name_xtn,
        ExtensionSendEncrypted
    },
    {
        ssl_cert_status_xtn,
        ExtensionNotUsed /* TODO(ekr@rtfm.com): Disabled because broken
                            in TLS 1.3. */
        /* ExtensionSendEncrypted */
    },
    {
        ssl_elliptic_curves_xtn,
        ExtensionSendClear
    },
    {
        ssl_ec_point_formats_xtn,
        ExtensionNotUsed
    },
    {
        ssl_signature_algorithms_xtn,
        ExtensionClientOnly
    },
    {
        ssl_use_srtp_xtn,
        ExtensionSendEncrypted
    },
    {
        ssl_app_layer_protocol_xtn,
        ExtensionSendEncrypted
    },
    {
        ssl_padding_xtn,
        ExtensionNotUsed
    },
    {
        ssl_extended_master_secret_xtn,
        ExtensionNotUsed
    },
    {
        ssl_session_ticket_xtn,
        ExtensionClientOnly
    },
    {
        ssl_tls13_key_share_xtn,
        ExtensionSendClear
    },
    {
        ssl_next_proto_nego_xtn,
        ExtensionNotUsed
    },
    {
        ssl_renegotiation_info_xtn,
        ExtensionNotUsed
    },
    {
        ssl_tls13_draft_version_xtn,
        ExtensionClientOnly
    }
};

PRBool
tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message)
{
    unsigned int i;

    PORT_Assert((message == client_hello) ||
                (message == server_hello) ||
                (message == encrypted_extensions));

    for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) {
        if (KnownExtensions[i].ex_value == extension) {
            break;
        }
    }

    switch(KnownExtensions[i].status) {
        case ExtensionNotUsed:
            return PR_FALSE;
        case ExtensionClientOnly:
            return message == client_hello;
        case ExtensionSendClear:
            return message == client_hello ||
                    message == server_hello;
        case ExtensionSendEncrypted:
            return message == client_hello ||
                    message == encrypted_extensions;
        case ExtensionUnknown:
            return PR_TRUE;
    }

    PORT_Assert(0);

    /* Not reached */
    return PR_TRUE;
}

/* Helper function to encode a uint32 into a buffer */
unsigned char *
tls13_EncodeUintX(PRUint32 value, unsigned int bytes, unsigned char *to)
{
    PORT_Assert(bytes > 0 && bytes <= 4);

    PRUint32 encoded = PR_htonl(value);
    memcpy(to, ((unsigned char *)(&encoded)) + (4-bytes), bytes);
    return to + bytes;
}

/* TLS 1.3 doesn't actually have additional data but the aead function
 * signature overloads additional data to carry the record sequence
 * number and that's what we put here. The TLS 1.3 AEAD functions
 * just use this input as the sequence number and not as additional
 * data. */
static void
tls13_FormatAdditionalData(unsigned char *aad, unsigned int length,
                           SSL3SequenceNumber seqNum)
{
    unsigned char *ptr = aad;

    PORT_Assert(length == 8);
    ptr = tls13_EncodeUintX(seqNum.high, 4, ptr);
    ptr = tls13_EncodeUintX(seqNum.low, 4, ptr);
    PORT_Assert((ptr - aad) == length);
}

SECStatus
tls13_ProtectRecord(sslSocket *ss,
                    SSL3ContentType type,
                    const SSL3Opaque *pIn,
                    PRUint32 contentLen,
                    sslBuffer *wrBuf)
{
    ssl3CipherSpec *cwSpec = ss->ssl3.cwSpec;
    const ssl3BulkCipherDef* cipher_def = cwSpec->cipher_def;
    SECStatus rv;
    PRUint16 headerLen;
    int cipherBytes = 0;
    const int tagLen = cipher_def->tag_size;

    SSL_TRC(3, ("%d: TLS13[%d]: protect record of length %u, seq=0x%0x%0x",
                SSL_GETPID(), ss->fd, contentLen,
                cwSpec->write_seq_num.high,
                cwSpec->write_seq_num.low
        ));

    headerLen = IS_DTLS(ss) ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH;

    if (headerLen + contentLen + 1 + tagLen > wrBuf->space) {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }

    /* Copy the data into the wrBuf. We're going to encrypt in-place
     * in the AEAD branch anyway */
    PORT_Memcpy(wrBuf->buf + headerLen, pIn, contentLen);

    if (cipher_def->calg == ssl_calg_null) {
        /* Shortcut for plaintext */
        cipherBytes = contentLen;
    } else {
        unsigned char aad[8];
        PORT_Assert(cipher_def->type == type_aead);

        /* Add the content type at the end. */
        wrBuf->buf[headerLen + contentLen] = type;

        /* Stomp the content type to be application_data */
        type = content_application_data;

        tls13_FormatAdditionalData(aad, sizeof(aad),
                                   cwSpec->write_seq_num);
        cipherBytes = contentLen + 1; /* Room for the content type on the end. */
        rv = cwSpec->aead(
            ss->sec.isServer ? &cwSpec->server : &cwSpec->client,
            PR_FALSE,                                   /* do encrypt */
            wrBuf->buf + headerLen,                     /* output  */
            &cipherBytes,                               /* out len */
            wrBuf->space - headerLen,                   /* max out */
            wrBuf->buf + headerLen, contentLen + 1,     /* input   */
            aad, sizeof(aad));
        if (rv != SECSuccess) {
            PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
            return SECFailure;
        }
    }

    PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 256);

    wrBuf->len = cipherBytes + headerLen;
    wrBuf->buf[0] = type;

    if (IS_DTLS(ss)) {
        (void)tls13_EncodeUintX(2, dtls_TLSVersionToDTLSVersion(kRecordVersion),
                    &wrBuf->buf[1]);
        (void)tls13_EncodeUintX(cwSpec->write_seq_num.high, 4, &wrBuf->buf[3]);
        (void)tls13_EncodeUintX(cwSpec->write_seq_num.low, 4, &wrBuf->buf[7]);
        (void)tls13_EncodeUintX(cipherBytes, 2, &wrBuf->buf[11]);
    } else {
        (void)tls13_EncodeUintX(kRecordVersion, 2, &wrBuf->buf[1]);
        (void)tls13_EncodeUintX(cipherBytes, 2, &wrBuf->buf[3]);
    }
    ssl3_BumpSequenceNumber(&cwSpec->write_seq_num);

    return SECSuccess;
}


/* Unprotect a TLS 1.3 record and leave the result in plaintext.
 *
 * Called by ssl3_HandleRecord. Caller must hold the spec read lock.
 * Therefore, we MUST not call SSL3_SendAlert().
 *
 * If SECFailure is returned, we:
 * 1. Set |*alert| to the alert to be sent.
 * 2. Call PORT_SetError() witn an appropriate code.
 */
SECStatus
tls13_UnprotectRecord(sslSocket* ss, SSL3Ciphertext *cText, sslBuffer *plaintext,
                      SSL3AlertDescription* alert)
{
    ssl3CipherSpec *crSpec = ss->ssl3.crSpec;
    const ssl3BulkCipherDef *cipher_def = crSpec->cipher_def;
    unsigned char aad[8];
    SECStatus rv;

    *alert = bad_record_mac; /* Default alert for most issues. */

    SSL_TRC(3, ("%d: TLS13[%d]: unprotect record of length %u",
		SSL_GETPID(), ss->fd, cText->buf->len));

    /* We can perform this test in variable time because the record's total
     * length and the ciphersuite are both public knowledge. */
    if (cText->buf->len < cipher_def->tag_size) {
        PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG);
	return SECFailure;
    }

    /* Check the version number in the record */
    if (cText->version != kRecordVersion) {
        /* Do we need a better error here? */
        PORT_SetError(SSL_ERROR_BAD_MAC_READ);
        return SECFailure;
    }

    /* Decrypt */
    PORT_Assert(cipher_def->type == type_aead);
    tls13_FormatAdditionalData(aad, sizeof(aad),
                               IS_DTLS(ss) ?
                               cText->seq_num :
                               crSpec->read_seq_num);
    rv = crSpec->aead(
        ss->sec.isServer ? &crSpec->client : &crSpec->server,
        PR_TRUE,                          /* do decrypt */
        plaintext->buf,                   /* out */
        (int*) &plaintext->len,           /* outlen */
        plaintext->space,                 /* maxout */
        cText->buf->buf,                  /* in */
        cText->buf->len,                  /* inlen */
        aad, sizeof(aad));
    if (rv != SECSuccess) {
        PORT_SetError(SSL_ERROR_BAD_MAC_READ);
        return SECFailure;
    }

    /* The record is right-padded with 0s, followed by the true
     * content type, so read from the right until we receive a
     * nonzero byte. */
    while (plaintext->len > 0 && !(plaintext->buf[plaintext->len-1])) {
        --plaintext->len;
    }

    /* Bogus padding. */
    if (plaintext->len < 1) {
        /* It's safe to report this specifically because it happened
         * after the MAC has been verified. */
        PORT_SetError(SSL_ERROR_BAD_BLOCK_PADDING);
        return SECFailure;
    }

    /* Record the type. */
    cText->type = plaintext->buf[plaintext->len-1];
    --plaintext->len;

    return SECSuccess;
}