809 lines
19 KiB
C
809 lines
19 KiB
C
/**
|
|
* @file tls13Resume.c
|
|
* @version $Format:%h%d$
|
|
*
|
|
* TLS 1.3 session resumption.
|
|
*/
|
|
/*
|
|
* Copyright (c) 2018 Rambus Inc.
|
|
* Copyright (c) PeerSec Networks, 2002-2011
|
|
* All Rights Reserved
|
|
*
|
|
* The latest version of this code is available at http://www.matrixssl.org
|
|
*
|
|
* This software is open source; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This General Public License does NOT permit incorporating this software
|
|
* into proprietary programs. If you are unable to comply with the GPL, a
|
|
* commercial license for this software may be purchased from Rambus at
|
|
* http://www.rambus.com/
|
|
*
|
|
* This program is distributed in WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
*/
|
|
|
|
#include "matrixsslImpl.h"
|
|
|
|
# ifndef DEBUG_TLS_1_3_RESUMPTION
|
|
/* # define DEBUG_TLS_1_3_RESUMPTION */
|
|
# endif
|
|
|
|
#ifdef USE_TLS_1_3
|
|
/* Derive a new PSK from the resumption master secret and
|
|
a nonce. */
|
|
int32_t tls13DeriveResumptionPsk(ssl_t *ssl,
|
|
int32_t hmacAlg,
|
|
unsigned char *nonce,
|
|
psSize_t nonceLen,
|
|
unsigned char *pskOut,
|
|
psSize_t pskOutLen)
|
|
{
|
|
psSize_t secretLen;
|
|
int32_t rc = psGetOutputBlockLength(hmacAlg);
|
|
|
|
if (rc < 0)
|
|
{ /* this is an error code */
|
|
return rc;
|
|
}
|
|
secretLen = rc;
|
|
|
|
if (pskOutLen < secretLen)
|
|
{
|
|
return PS_OUTPUT_LENGTH;
|
|
}
|
|
|
|
|
|
rc = psHkdfExpandLabel(ssl->hsPool,
|
|
hmacAlg,
|
|
ssl->sec.tls13ResumptionMasterSecret,
|
|
secretLen,
|
|
"resumption",
|
|
10,
|
|
nonce,
|
|
nonceLen,
|
|
secretLen,
|
|
pskOut);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("Derived new PSK", pskOut, secretLen);
|
|
# endif
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
void tls13GetCurrSessParams(ssl_t *ssl,
|
|
psTls13SessionParams_t *params)
|
|
{
|
|
params->sni = NULL;
|
|
params->sniLen = 0;
|
|
params->alpn = NULL;
|
|
params->alpnLen = 0;
|
|
params->majVer = psEncodeVersionMaj(GET_ACTV_VER(ssl));
|
|
params->minVer = psEncodeVersionMin(GET_ACTV_VER(ssl));
|
|
params->cipherId = ssl->cipher->ident;
|
|
psGetTime(¶ms->timestamp, ssl->userPtr);
|
|
params->maxEarlyData = ssl->tls13SessionMaxEarlyData;
|
|
}
|
|
|
|
int32_t tls13StorePsk(ssl_t *ssl,
|
|
const unsigned char *psk,
|
|
psSize_t pskLen,
|
|
const unsigned char *pskId,
|
|
psSize_t pskIdLen,
|
|
psBool_t isResumptionPsk,
|
|
const psTls13SessionParams_t *params)
|
|
{
|
|
psTls13SessionParams_t defaultParams;
|
|
int32_t rc;
|
|
|
|
if (params == NULL)
|
|
{
|
|
tls13GetCurrSessParams(ssl, &defaultParams);
|
|
/* By default don't support early data. It must be explicitly
|
|
enabled */
|
|
defaultParams.maxEarlyData = 0;
|
|
params = &defaultParams;
|
|
}
|
|
|
|
/* Add the new PSK to our database. */
|
|
rc = tls13AddSessionPsk(ssl,
|
|
psk,
|
|
pskLen,
|
|
pskId,
|
|
pskIdLen,
|
|
isResumptionPsk,
|
|
params);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Create a new session ticket.
|
|
*/
|
|
int32_t tls13NewTicket(ssl_t *ssl,
|
|
int32_t hmacAlg,
|
|
uint32_t lifetime,
|
|
uint32_t ageAdd,
|
|
unsigned char *nonce,
|
|
psSize_t nonceLen,
|
|
unsigned char **ticketOut,
|
|
psSizeL_t *ticketOutLen)
|
|
{
|
|
int32_t rc;
|
|
psResSize_t pskValLen = psGetOutputBlockLength(hmacAlg);
|
|
unsigned char pskVal[MAX_TLS_1_3_HASH_SIZE];
|
|
psSize_t pskIdLen;
|
|
unsigned char pskId[32], iv[12];
|
|
psDynBuf_t buf;
|
|
psSessionTicketKeys_t *key;
|
|
psAesGcm_t ctx;
|
|
unsigned char *state, *tag, *out;
|
|
psSizeL_t stateLen, outLen;
|
|
psTls13Psk_t *psk;
|
|
psTls13SessionParams_t params;
|
|
int32_t tagLen = AEAD_TAG_LEN(ssl);
|
|
|
|
if (pskValLen < 0)
|
|
{ /* this is an error code */
|
|
return pskValLen;
|
|
}
|
|
|
|
/* Derive the PSK value. */
|
|
rc = tls13DeriveResumptionPsk(ssl,
|
|
hmacAlg,
|
|
nonce,
|
|
nonceLen,
|
|
pskVal,
|
|
pskValLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
/* Generate a new random ID for the PSK.*/
|
|
pskIdLen = sizeof(pskId);
|
|
rc = psGetPrng(NULL, pskId, pskIdLen, NULL);
|
|
if (rc != pskIdLen)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
/* Make a new PSK object and associate it with the current
|
|
session parameters. */
|
|
tls13GetCurrSessParams(ssl, ¶ms);
|
|
params.ticketLifetime = lifetime;
|
|
params.ticketAgeAdd = ageAdd;
|
|
psk = tls13NewPsk(pskVal,
|
|
pskValLen,
|
|
pskId,
|
|
pskIdLen,
|
|
PS_TRUE,
|
|
¶ms);
|
|
if (psk == NULL)
|
|
{
|
|
return PS_MEM_FAIL;
|
|
}
|
|
|
|
/*
|
|
Use the recommended ticket format from RFC 5077, adapted
|
|
for AES-GCM:
|
|
|
|
struct {
|
|
opaque key_name[16];
|
|
opaque iv[12];
|
|
opaque encrypted_state<0..2^16-1>
|
|
opaque tag[16];
|
|
} ticket;
|
|
|
|
Use the first key in ssl->keys->sessTickets.
|
|
|
|
encrypted_state is the serialized and encrypted PSK struct
|
|
containing the PSK and the session parameters.
|
|
*/
|
|
|
|
key = ssl->keys->sessTickets;
|
|
if (key == NULL)
|
|
{
|
|
psTraceErrr("Error: no session ticket keys loaded\n");
|
|
tls13FreePsk(psk, ssl->hsPool);
|
|
return PS_FAILURE;
|
|
}
|
|
|
|
psDynBufInit(ssl->hsPool, &buf, 512);
|
|
psDynBufAppendOctets(&buf, key->name, 16);
|
|
|
|
psAesInitGCM(&ctx, key->symkey, key->symkeyLen);
|
|
rc = psAesReadyGCMRandomIV(&ctx, iv, NULL, 0, NULL);
|
|
if (rc < 0)
|
|
{
|
|
tls13FreePsk(psk, ssl->hsPool);
|
|
psAesClearGCM(&ctx);
|
|
return rc;
|
|
}
|
|
|
|
psDynBufAppendOctets(&buf, iv, 12);
|
|
|
|
rc = tls13ExportState(ssl,
|
|
psk,
|
|
&state,
|
|
&stateLen);
|
|
if (rc < 0)
|
|
{
|
|
tls13FreePsk(psk, ssl->hsPool);
|
|
psAesClearGCM(&ctx);
|
|
return rc;
|
|
}
|
|
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("pt", state, stateLen);
|
|
psTraceBytes("IV", iv, 12);
|
|
psTraceBytes("key", key->symkey, key->symkeyLen);
|
|
# endif
|
|
|
|
psAesEncryptGCM(&ctx,
|
|
state,
|
|
state,
|
|
stateLen);
|
|
psDynBufAppendTlsVector(&buf,
|
|
0, (1 << 16) - 1,
|
|
state,
|
|
stateLen);
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("ct", state, stateLen);
|
|
# endif
|
|
|
|
tag = psMalloc(ssl->hsPool, tagLen);
|
|
psAesGetGCMTag(&ctx,
|
|
tagLen,
|
|
tag);
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("tag", tag, tagLen);
|
|
# endif
|
|
|
|
psDynBufAppendOctets(&buf, tag, tagLen);
|
|
|
|
psAesClearGCM(&ctx);
|
|
|
|
out = psDynBufDetach(&buf, &outLen);
|
|
if (out == NULL)
|
|
{
|
|
tls13FreePsk(psk, ssl->hsPool);
|
|
psFree(state, ssl->hsPool);
|
|
psFree(tag, ssl->hsPool);
|
|
return PS_MEM_FAIL;
|
|
}
|
|
|
|
*ticketOut = out;
|
|
*ticketOutLen = outLen;
|
|
|
|
tls13FreePsk(psk, ssl->hsPool);
|
|
psFree(state, ssl->hsPool);
|
|
psFree(tag, ssl->hsPool);
|
|
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("New ticket", *ticketOut, *ticketOutLen);
|
|
# endif
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
int32_t tls13DecryptTicket(ssl_t *ssl,
|
|
psSessionTicketKeys_t *key,
|
|
const unsigned char *ticket,
|
|
psSizeL_t ticketLen,
|
|
psTls13Psk_t **pskOut)
|
|
{
|
|
psAesGcm_t ctx;
|
|
int32_t rc;
|
|
const unsigned char *ivStart, *encStart;
|
|
unsigned char *pt;
|
|
psSizeL_t encStateLen, ptLen;
|
|
psParseBuf_t encStateBuf;
|
|
const unsigned char *ticketEnd = ticket + ticketLen;
|
|
psTls13Psk_t *psk;
|
|
int32_t tagLen = AEAD_TAG_LEN(ssl);
|
|
|
|
/*
|
|
struct {
|
|
opaque key_name[16];
|
|
opaque iv[12];
|
|
opaque encrypted_state<0..2^16-1>
|
|
opaque tag[16];
|
|
} ticket;
|
|
|
|
encrypted_state is the serialized and encrypted PSK struct
|
|
containing the PSK and the session parameters.
|
|
*/
|
|
|
|
if (ticketLen < 16 + 12 + 1 + 16)
|
|
{
|
|
psTraceErrr("Ticket too short\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
if (Memcmp(ticket, key->name, 16))
|
|
{
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
ivStart = ticket + 16;
|
|
encStart = ivStart + 12;
|
|
|
|
(void)psParseBufFromStaticData(&encStateBuf,
|
|
encStart,
|
|
ticketEnd - encStart);
|
|
|
|
/* opaque encrypted_state<0..2^16-1> */
|
|
rc = psParseBufParseTlsVector(&encStateBuf,
|
|
0, (1 << 16) - 1,
|
|
&encStateLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_illegal_parameter;
|
|
}
|
|
if (encStateLen < 1 ||
|
|
!psParseCanRead(&encStateBuf, encStateLen + tagLen))
|
|
{
|
|
psTrace("Decrypted ticket too short\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
ptLen = encStateLen;
|
|
pt = psMalloc(ssl->hsPool, ptLen);
|
|
|
|
rc = psAesInitGCM(&ctx, key->symkey, key->symkeyLen);
|
|
if (rc < 0)
|
|
{
|
|
psFree(pt, ssl->hsPool);
|
|
goto out_internal_error;
|
|
}
|
|
psAesReadyGCM(&ctx, ivStart, NULL, 0);
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("iv", ivStart, 12);
|
|
psTraceBytes("key", key->symkey, key->symkeyLen);
|
|
psTraceBytes("ct", encStateBuf.buf.start, encStateLen);
|
|
# endif
|
|
|
|
rc = psAesDecryptGCM(&ctx,
|
|
encStateBuf.buf.start,
|
|
encStateLen + tagLen,
|
|
pt,
|
|
ptLen);
|
|
|
|
psAesClearGCM(&ctx);
|
|
if (rc < 0)
|
|
{
|
|
psTrace("Ticket decryption failed\n");
|
|
psFree(pt, ssl->hsPool);
|
|
goto out_bad_record_mac;
|
|
}
|
|
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("Decrypted ticket", pt, ptLen);
|
|
# endif
|
|
rc = tls13ImportState(ssl,
|
|
pt,
|
|
ptLen,
|
|
&psk);
|
|
if (rc < 0)
|
|
{
|
|
psFree(pt, ssl->hsPool);
|
|
goto out_internal_error;
|
|
}
|
|
|
|
psFree(pt, ssl->hsPool);
|
|
|
|
*pskOut = psk;
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
out_bad_record_mac:
|
|
ssl->err = SSL_ALERT_BAD_RECORD_MAC;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/** Serialize a PSK. */
|
|
int32_t tls13ExportState(ssl_t *ssl,
|
|
psTls13Psk_t *psk,
|
|
unsigned char **out,
|
|
psSizeL_t *outLen)
|
|
{
|
|
psDynBuf_t buf, paramsBuf;
|
|
unsigned char *paramsData;
|
|
psSizeL_t paramsDataLen;
|
|
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("Exporting PSK with value", psk->pskKey, psk->pskLen);
|
|
# endif
|
|
|
|
/*
|
|
Serialize the PSK and associated session params as follows:
|
|
|
|
struct {
|
|
opaque sni<0..2^16-1>;
|
|
opaque alpn<0..2^16-1>;
|
|
uint8 majVer;
|
|
uint8 minVer;
|
|
uint16 cipherId;
|
|
uint32 ticketLifetime;
|
|
uint32 ticketAgeAdd;
|
|
psTime_t timestamp;
|
|
uint32 maxEarlyDataSize;
|
|
} MatrixSessionParams;
|
|
|
|
struct {
|
|
opaque psk<0..2^16-1>;
|
|
opaque psk_id<0..2^16-1>;
|
|
MatrixSessionParams params<0..2^16-1>;
|
|
} MatrixSession;
|
|
*/
|
|
psDynBufInit(ssl->hsPool, &buf, 256);
|
|
psDynBufAppendTlsVector(&buf,
|
|
0, (1 << 16) - 1,
|
|
psk->pskKey,
|
|
psk->pskLen);
|
|
psDynBufAppendTlsVector(&buf,
|
|
0, (1 << 16) - 1,
|
|
psk->pskId,
|
|
psk->pskIdLen);
|
|
|
|
psDynBufInit(ssl->hsPool, ¶msBuf, 256);
|
|
psDynBufAppendTlsVector(¶msBuf,
|
|
0, (1 << 16) - 1,
|
|
psk->params->sni,
|
|
psk->params->sniLen);
|
|
psDynBufAppendTlsVector(¶msBuf,
|
|
0, (1 << 16) - 1,
|
|
psk->params->alpn,
|
|
psk->params->alpnLen);
|
|
psDynBufAppendByte(¶msBuf,
|
|
psEncodeVersionMaj(ssl->activeVersion));
|
|
psDynBufAppendByte(¶msBuf,
|
|
psEncodeVersionMin(ssl->activeVersion));
|
|
psDynBufAppendAsBigEndianUint16(¶msBuf, psk->params->cipherId);
|
|
|
|
psDynBufAppendAsBigEndianUint32(¶msBuf, psk->params->ticketLifetime);
|
|
psDynBufAppendAsBigEndianUint32(¶msBuf, psk->params->ticketAgeAdd);
|
|
|
|
psDynBufAppendOctets(¶msBuf,
|
|
&psk->params->timestamp,
|
|
sizeof(psTime_t));
|
|
|
|
psDynBufAppendAsBigEndianUint32(¶msBuf, psk->params->maxEarlyData);
|
|
|
|
paramsData = psDynBufDetach(¶msBuf,
|
|
¶msDataLen);
|
|
if (paramsData == NULL)
|
|
{
|
|
return PS_MEM_FAIL;
|
|
}
|
|
psDynBufAppendTlsVector(&buf,
|
|
0, (1 << 16) - 1,
|
|
paramsData,
|
|
paramsDataLen);
|
|
psFree(paramsData, ssl->hsPool);
|
|
|
|
*out = psDynBufDetach(&buf,
|
|
outLen);
|
|
if (*out == NULL)
|
|
{
|
|
return PS_MEM_FAIL;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
static
|
|
int32_t tls13ParseMatrixSessionParams(ssl_t *ssl,
|
|
psParseBuf_t *pb,
|
|
psSizeL_t inLen,
|
|
psTls13SessionParams_t *params)
|
|
{
|
|
size_t copiedLen = sizeof(psTime_t);
|
|
psSizeL_t sniLen, alpnLen;
|
|
unsigned char majVer = 0, minVer = 0;
|
|
uint16_t cipherId = 0;
|
|
uint32_t ticketLifetime = 0;
|
|
uint32_t ticketAgeAdd = 0;
|
|
psTime_t timestamp;
|
|
uint32_t maxEarlyData = 0;
|
|
int32_t rc;
|
|
|
|
/*
|
|
struct {
|
|
opaque sni<0..2^16-1>;
|
|
opaque alpn<0..2^16-1>;
|
|
uint8 majVer;
|
|
uint8 minVer;
|
|
uint16 cipherId;
|
|
uint32 ticketLifetime;
|
|
uint32 tiecketAgeAdd;
|
|
psTime_t timestamp;
|
|
uint32 maxEarlyDataSize;
|
|
} MatrixSessionParams;
|
|
*/
|
|
|
|
Memset(params, 0, sizeof(*params));
|
|
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 1,
|
|
&sniLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
if (sniLen > 0)
|
|
{
|
|
Memcpy(params->sni, pb->buf.start, sniLen);
|
|
}
|
|
rc = psParseTryForward(pb, sniLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 1,
|
|
&alpnLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
if (alpnLen > 0)
|
|
{
|
|
Memcpy(params->alpn, pb->buf.start, alpnLen);
|
|
}
|
|
rc = psParseTryForward(pb, alpnLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = psParseOctet(pb, &majVer);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->majVer = majVer;
|
|
|
|
rc = psParseOctet(pb, &minVer);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->minVer = minVer;
|
|
|
|
rc = psParseBufTryParseBigEndianUint16(pb,
|
|
&cipherId);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->cipherId = cipherId;
|
|
|
|
|
|
rc = psParseBufTryParseBigEndianUint32(pb,
|
|
&ticketLifetime);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->ticketLifetime = ticketLifetime;
|
|
|
|
|
|
rc = psParseBufTryParseBigEndianUint32(pb,
|
|
&ticketAgeAdd);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->ticketAgeAdd = ticketAgeAdd;
|
|
|
|
rc = psParseBufCopyN(pb,
|
|
sizeof(psTime_t),
|
|
(unsigned char *)×tamp,
|
|
&copiedLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
rc = psParseTryForward(pb, copiedLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->timestamp = timestamp;
|
|
|
|
rc = psParseBufTryParseBigEndianUint32(pb,
|
|
&maxEarlyData);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
params->maxEarlyData = maxEarlyData;
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
int32_t tls13ValidateSessionParams(ssl_t *ssl,
|
|
psTls13SessionParams_t *params)
|
|
{
|
|
psProtocolVersion_t ver;
|
|
|
|
ver = psVerFromEncodingMajMin(params->majVer, params->minVer);
|
|
if (ver != VER_GET_RAW(ssl->activeVersion))
|
|
{
|
|
psTraceErrr("Decrypted session: version mismatch\n");
|
|
psTracePrintProtocolVersionNew(INDENT_ERROR,
|
|
"Got",
|
|
ver,
|
|
PS_TRUE);
|
|
psTracePrintProtocolVersionNew(INDENT_ERROR,
|
|
"Expected",
|
|
ssl->activeVersion,
|
|
PS_TRUE);
|
|
goto out_handshake_failure;
|
|
}
|
|
|
|
if (params->cipherId != ssl->cipher->ident)
|
|
{
|
|
psTraceErrr("Decrypted session: cipher mismatch\n");
|
|
psTraceIntInfo("Got %hu ", params->cipherId);
|
|
psTraceIntInfo("Expected: %hu\n",
|
|
ssl->cipher->ident);
|
|
goto out_handshake_failure;
|
|
}
|
|
|
|
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_handshake_failure:
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
int32_t tls13ImportState(ssl_t *ssl,
|
|
const unsigned char *in,
|
|
psSizeL_t inLen,
|
|
psTls13Psk_t **pskOut)
|
|
{
|
|
psParseBuf_t pb;
|
|
unsigned char *pskVal, *pskId;
|
|
psSizeL_t pskValLen, pskIdLen, paramsLen;
|
|
int32_t rc;
|
|
psTls13Psk_t *psk = NULL;
|
|
psTls13SessionParams_t params;
|
|
|
|
(void)psParseBufFromStaticData(&pb, in, inLen);
|
|
|
|
/*
|
|
De-serialize the PSK and associated session params as follows:
|
|
|
|
struct {
|
|
opaque sni<0..2^16-1>;
|
|
opaque alpn<0..2^16-1>;
|
|
uint8 majVer;
|
|
uint8 minVer;
|
|
uint16 cipherId;
|
|
uint32 timestamp;
|
|
uint32 maxEarlyDataSize;
|
|
} MatrixSessionParams;
|
|
|
|
struct {
|
|
opaque psk<0..2^16-1>;
|
|
opaque psk_id<0..2^16-1>;
|
|
MatrixSessionParams params<0..2^16-1>;
|
|
} MatrixSession;
|
|
*/
|
|
|
|
rc = psParseBufParseTlsVector(&pb,
|
|
0, (1 << 16) - 1,
|
|
&pskValLen);
|
|
if (rc < 0)
|
|
{
|
|
/* Using internal errors for parse failures here, because
|
|
the ticket format is decided by us and not by the protocol
|
|
spec. */
|
|
goto out_internal_error;
|
|
}
|
|
pskVal = pb.buf.start;
|
|
psParseForward(&pb, pskValLen);
|
|
|
|
rc = psParseBufParseTlsVector(&pb,
|
|
0, (1 << 16) - 1,
|
|
&pskIdLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
pskId = pb.buf.start;
|
|
psParseForward(&pb, pskIdLen);
|
|
|
|
rc = psParseBufParseTlsVector(&pb,
|
|
0, (1 << 16) - 1,
|
|
¶msLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
rc = tls13ParseMatrixSessionParams(ssl,
|
|
&pb,
|
|
paramsLen,
|
|
¶ms);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
/* Postpone validation of the decrypted session parameters
|
|
until after we have negotiated the parameters for the current
|
|
handshake. */
|
|
|
|
rc = tls13StorePsk(ssl,
|
|
pskVal,
|
|
pskValLen,
|
|
pskId,
|
|
pskIdLen,
|
|
PS_TRUE,
|
|
¶ms);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
rc = tls13FindSessionPsk(ssl,
|
|
pskId,
|
|
pskIdLen,
|
|
&psk);
|
|
if (rc < 0 || psk == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
*pskOut = psk;
|
|
|
|
# ifdef DEBUG_TLS_1_3_RESUMPTION
|
|
psTraceBytes("Imported PSK with value", psk->pskKey, psk->pskLen);
|
|
# endif
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/* Clear the current handshake state. Any resumed handshakes
|
|
must start from scratch (until session params are restored
|
|
from e.g. a ticket.) */
|
|
void tls13ClearHsState(ssl_t *ssl)
|
|
{
|
|
Memset(&ssl->extFlags, 0, sizeof(ssl->extFlags));
|
|
}
|
|
#endif
|