2223 lines
62 KiB
C
2223 lines
62 KiB
C
/**
|
|
* @file tls13DecodeExt.c
|
|
* @version $Format:%h%d$
|
|
*
|
|
* Functions for decoding TLS 1.3 extensions
|
|
*/
|
|
/*
|
|
* Copyright (c) 2013-2019 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"
|
|
|
|
# ifdef USE_TLS_1_3
|
|
|
|
# ifndef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
/* # define DEBUG_TLS_1_3_DECODE_EXTENSIONS */
|
|
# endif
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
# warning "DEBUG_TLS_1_3_DECODE_EXTENSIONS will leak secrets into logs!"
|
|
# endif
|
|
|
|
static
|
|
psBool_t tls13WeRecognizeExtension(uint16_t extType)
|
|
{
|
|
switch (extType)
|
|
{
|
|
case EXT_SERVER_NAME:
|
|
case EXT_MAX_FRAGMENT_LEN:
|
|
case EXT_TRUSTED_CA_KEYS:
|
|
case EXT_TRUNCATED_HMAC:
|
|
case EXT_STATUS_REQUEST:
|
|
case EXT_SUPPORTED_GROUPS:
|
|
case EXT_ELLIPTIC_POINTS:
|
|
case EXT_SIGNATURE_ALGORITHMS:
|
|
case EXT_ALPN:
|
|
case EXT_SIGNED_CERTIFICATE_TIMESTAMP:
|
|
case EXT_EXTENDED_MASTER_SECRET:
|
|
case EXT_SESSION_TICKET:
|
|
case EXT_KEY_SHARE_PRE_DRAFT_23:
|
|
case EXT_PRE_SHARED_KEY:
|
|
case EXT_EARLY_DATA:
|
|
case EXT_SUPPORTED_VERSIONS:
|
|
case EXT_COOKIE:
|
|
case EXT_PSK_KEY_EXCHANGE_MODES:
|
|
case EXT_CERTIFICATE_AUTHORITIES:
|
|
case EXT_OID_FILTERS:
|
|
case EXT_POST_HANDSHAKE_AUTH:
|
|
case EXT_SIGNATURE_ALGORITHMS_CERT:
|
|
case EXT_KEY_SHARE:
|
|
case EXT_RENEGOTIATION_INFO:
|
|
return PS_TRUE;
|
|
default:
|
|
return PS_FALSE;
|
|
}
|
|
}
|
|
|
|
psBool_t tls13ExtensionAllowedInMessage(ssl_t *ssl,
|
|
uint16_t extType,
|
|
unsigned char hsMsgType)
|
|
{
|
|
if (!tls13WeRecognizeExtension(extType))
|
|
{
|
|
/* Unrecognized extensions MUST be ignored regardless
|
|
of where they appear. */
|
|
return PS_TRUE;
|
|
}
|
|
/* We recognize extType. */
|
|
|
|
/* Based on table in section 4.2. of draft 24. */
|
|
switch (hsMsgType)
|
|
{
|
|
case SSL_HS_CLIENT_HELLO:
|
|
/* All extensions allowed in CH, except oid_filters. */
|
|
if (extType == EXT_OID_FILTERS)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
break;
|
|
case SSL_HS_SERVER_HELLO:
|
|
/* Cookie only allowed in HRR. */
|
|
if (extType == EXT_COOKIE &&
|
|
!ssl->tls13IncorrectDheKeyShare)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
if (extType != EXT_KEY_SHARE &&
|
|
extType != EXT_KEY_SHARE_PRE_DRAFT_23 &&
|
|
extType != EXT_PRE_SHARED_KEY &&
|
|
extType != EXT_SUPPORTED_VERSIONS &&
|
|
extType != EXT_COOKIE)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
break;
|
|
case SSL_HS_ENCRYPTED_EXTENSION:
|
|
if (extType != EXT_SERVER_NAME &&
|
|
extType != EXT_MAX_FRAGMENT_LEN &&
|
|
extType != EXT_SUPPORTED_GROUPS &&
|
|
extType != EXT_ALPN &&
|
|
extType != EXT_EARLY_DATA)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
break;
|
|
case SSL_HS_NEW_SESSION_TICKET:
|
|
if (extType != EXT_EARLY_DATA)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
break;
|
|
case SSL_HS_CERTIFICATE:
|
|
if (extType != EXT_STATUS_REQUEST)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
break;
|
|
default:
|
|
psTraceErrr("Error: no extensions allowed in ");
|
|
psTracePrintHsMsgType(hsMsgType, PS_TRUE);
|
|
}
|
|
|
|
return PS_TRUE;
|
|
}
|
|
|
|
# if defined(USE_IDENTITY_CERTIFICATES) && defined(USE_OCSP_RESPONSE)
|
|
int32_t tls13ParseStatusRequest(ssl_t *ssl,
|
|
psParseBuf_t *extBuf)
|
|
{
|
|
unsigned char type = 0;
|
|
unsigned char *resp;
|
|
psSizeL_t respLen;
|
|
psOcspResponse_t ocspResp;
|
|
psX509Cert_t *cert;
|
|
int32_t rc;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_STATUS_REQUEST);
|
|
|
|
if (MATRIX_IS_SERVER(ssl))
|
|
{
|
|
/*
|
|
Server parses the client request:
|
|
|
|
struct {
|
|
CertificateStatusType status_type = ocsp(1);
|
|
ResponderID responder_id_list<0..2^16-1>;
|
|
Extensions request_extensions;
|
|
} CertificateStatusRequest;
|
|
|
|
Currently ignoring the request contents.
|
|
*/
|
|
ssl->extFlags.status_request = 1;
|
|
return PS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Client parses the server response:
|
|
|
|
struct {
|
|
CertificateStatusType status_type;
|
|
select (status_type) {
|
|
case ocsp: OCSPResponse;
|
|
} response;
|
|
} CertificateStatus;
|
|
*/
|
|
|
|
if (ssl->keys == NULL
|
|
|| ssl->keys->CAcerts == NULL
|
|
|| ssl->sec.cert == NULL)
|
|
{
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/* We are currently parsing the extensions of the certificate
|
|
we parsed last. So the revocation information concerns
|
|
the last parsed certificate. */
|
|
cert = ssl->sec.cert;
|
|
while (cert->next)
|
|
{
|
|
cert = cert->next;
|
|
}
|
|
|
|
if (!psParseOctet(extBuf, &type))
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
if (type != 0x01)
|
|
{
|
|
psTraceErrr("Invalid status_type in status_request\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/* opaque OCSPResponse<1..2^24-1>; */
|
|
rc = psParseBufParseTlsVector(extBuf,
|
|
1, (1 << 24) - 1,
|
|
&respLen);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Malformed status_request extension\n");
|
|
goto out_decode_error;
|
|
}
|
|
resp = extBuf->buf.start;
|
|
|
|
/* Parse and validate the response. */
|
|
rc = psOcspParseResponse(ssl->hsPool,
|
|
respLen,
|
|
&resp,
|
|
resp + respLen,
|
|
&ocspResp);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Unable to parse OCSPResponse\n");
|
|
goto out_decode_error;
|
|
}
|
|
rc = psOcspResponseValidateOld(ssl->hsPool,
|
|
ssl->keys->CAcerts,
|
|
cert,
|
|
&ocspResp);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Unable to validate OCSPResponse\n");
|
|
psX509FreeCert(ocspResp.OCSPResponseCert);
|
|
goto out_bad_certificate_status_response;
|
|
}
|
|
psTraceInfo("OCSP response OK\n");
|
|
psX509FreeCert(ocspResp.OCSPResponseCert);
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
out_decode_error:
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_bad_certificate_status_response:
|
|
ssl->err = SSL_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
# endif /* USE_IDENTITY_CERTIFICATES && USE_OCSP_RESPONSE */
|
|
|
|
/*
|
|
Parses a single extension:
|
|
struct {
|
|
ExtensionType extension_type;
|
|
opaque extension_data<0..2^16-1>;
|
|
} Extension;
|
|
*/
|
|
int32_t tls13ParseSingleExtension(ssl_t *ssl,
|
|
psParseBuf_t *extBuf,
|
|
unsigned char hsMsgType,
|
|
psBool_t allowStateChange)
|
|
{
|
|
psParseBuf_t extDataBuf;
|
|
psSizeL_t extDataLen;
|
|
uint16_t extType;
|
|
uint32_t maxEarlyData;
|
|
int32_t rc;
|
|
|
|
/* ExtensionType extension_type; */
|
|
rc = psParseBufTryParseBigEndianUint16(extBuf,
|
|
&extType);
|
|
if (rc != 2)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
|
|
/*
|
|
4.2.
|
|
"If the received extension is not specified for the message
|
|
in which it appears, we MUST abort the handshake with an
|
|
illegal_parameter alert."
|
|
|
|
A very important check, as the code below no longer takes
|
|
into account the type of the handshake message we are parsing.
|
|
*/
|
|
if (!tls13ExtensionAllowedInMessage(ssl, extType, hsMsgType))
|
|
{
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/*
|
|
opaque extension_data<0..2^16-1>;
|
|
*/
|
|
rc = psParseBufParseTlsVector(extBuf,
|
|
0, (1 << 16) - 1,
|
|
&extDataLen);
|
|
if (rc <= 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
(void)psParseBufFromStaticData(&extDataBuf,
|
|
extBuf->buf.start, extDataLen);
|
|
psParseTryForward(extBuf, extDataLen);
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("extension_data", extDataBuf.buf.start,
|
|
extDataLen);
|
|
# endif
|
|
|
|
if (extType != EXT_SUPPORTED_VERSIONS && !allowStateChange)
|
|
{
|
|
/* If we are not allowed to change state, ignore the extension
|
|
data, unless it's supported_versions, which we want to
|
|
check for version negotiation purposes. */
|
|
rc = psParseTryForward(&extDataBuf, extDataLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
goto skip_parse;
|
|
}
|
|
|
|
switch (extType)
|
|
{
|
|
case EXT_SERVER_NAME:
|
|
rc = tls13ParseServerName(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
# if defined(USE_IDENTITY_CERTIFICATES) && defined(USE_OCSP_RESPONSE)
|
|
case EXT_STATUS_REQUEST:
|
|
rc = tls13ParseStatusRequest(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
# endif
|
|
# ifdef USE_SERVER_SIDE_SSL
|
|
# if defined(USE_TLS_1_2) || defined(USE_TLS_1_3)
|
|
# ifdef USE_ECC_CIPHER_SUITE
|
|
case EXT_SUPPORTED_GROUPS:
|
|
rc = tlsParseSupportedGroups(ssl,
|
|
(const unsigned char *)extDataBuf.buf.start,
|
|
extDataLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
# endif
|
|
# endif
|
|
# endif
|
|
case EXT_SIGNATURE_ALGORITHMS:
|
|
case EXT_SIGNATURE_ALGORITHMS_CERT:
|
|
rc = tls13ParseSignatureAlgorithms(ssl,
|
|
(const unsigned char **)&extDataBuf.buf.start,
|
|
extDataLen,
|
|
(extType == EXT_SIGNATURE_ALGORITHMS_CERT) ? \
|
|
PS_TRUE : PS_FALSE);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
case EXT_PRE_SHARED_KEY:
|
|
rc = tls13ParsePreSharedKey(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
case EXT_EARLY_DATA:
|
|
rc = tls13ParseEarlyData(ssl, &extDataBuf, &maxEarlyData);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
case EXT_SUPPORTED_VERSIONS:
|
|
rc = tls13ParseSupportedVersions(ssl,
|
|
(const unsigned char **)&extDataBuf.buf.start,
|
|
extDataLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
case EXT_COOKIE:
|
|
rc = tls13ParseCookie(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
case EXT_PSK_KEY_EXCHANGE_MODES:
|
|
rc = tls13ParsePskKeyExchangeModes(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
# ifndef USE_ONLY_PSK_CIPHER_SUITE
|
|
case EXT_KEY_SHARE:
|
|
rc = tls13ParseKeyShare(ssl,
|
|
&extDataBuf,
|
|
allowStateChange);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
|
|
default:
|
|
psTraceIntInfo("Ignoring unknown extension: %hu\n", extType);
|
|
}
|
|
|
|
skip_parse:
|
|
return PS_SUCCESS;
|
|
|
|
out_decode_error:
|
|
psTraceErrr("Invalid extension format\n");
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_illegal_parameter:
|
|
psTraceErrr("Forbidden extension in message\n");
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/*
|
|
Parses:
|
|
Extensions extensions<0..2^16-1>
|
|
*/
|
|
int32_t tls13ParseExtensions(ssl_t *ssl,
|
|
psParseBuf_t *pb,
|
|
unsigned char hsMsgType,
|
|
psBool_t allowStateChange)
|
|
{
|
|
psParseBuf_t extBuf;
|
|
psSizeL_t extensionsLen;
|
|
int32_t rc;
|
|
|
|
/* Extension extensions<0..2^16-2>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 2,
|
|
&extensionsLen);
|
|
if (rc <= 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
(void)psParseBufFromStaticData(&extBuf,
|
|
pb->buf.start, extensionsLen);
|
|
|
|
/*
|
|
Minimum length of an Extension is 4
|
|
= 2 (extension_type) + 2 (extension_data length octets)
|
|
*/
|
|
while (psParseCanRead(&extBuf, 4))
|
|
{
|
|
rc = tls13ParseSingleExtension(ssl,
|
|
&extBuf,
|
|
hsMsgType,
|
|
allowStateChange);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/* Return number of bytes consumed from pb. */
|
|
return extensionsLen + 2;
|
|
|
|
out_decode_error:
|
|
psTraceErrr("Invalid extension vector\n");
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/** Parse supported_versions extension.
|
|
Advance parse pointer c.
|
|
Return number of parsed octets.
|
|
*/
|
|
psSize_t tls13ParseSupportedVersions(ssl_t *ssl,
|
|
const unsigned char **c,
|
|
psSize_t len)
|
|
{
|
|
psSize_t dataLen;
|
|
int32 i = 0;
|
|
unsigned char majVer, minVer;
|
|
psProtocolVersion_t ver;
|
|
const unsigned char *p = *c;
|
|
psSize_t parsedLen;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_SUPPORTED_VERSIONS);
|
|
|
|
/*
|
|
uint16 ProtocolVersion;
|
|
struct {
|
|
select (Handshake.msg_type) {
|
|
case client_hello:
|
|
ProtocolVersion versions<2..254>;
|
|
case server_hello:
|
|
ProtocolVersion selected_version;
|
|
};
|
|
} SupportedVersions;
|
|
*/
|
|
|
|
/* Minimum length: 1 (versions length) + 2 (ProtocolVersion). */
|
|
if (len < 3)
|
|
{
|
|
psTraceErrr("Malformed supported_versions extension\n");
|
|
goto out_decode_error;
|
|
}
|
|
dataLen = *p; p++;
|
|
len--;
|
|
if (dataLen != len)
|
|
{
|
|
psTraceErrr("Malformed supported_versions extension\n");
|
|
goto out_decode_error;
|
|
}
|
|
ssl->extFlags.got_supported_versions = 1;
|
|
ssl->peerSupportedVersionsPriorityLen = 0;
|
|
while(len > 0)
|
|
{
|
|
majVer = *p; p++;
|
|
minVer = *p; p++;
|
|
len -= 2;
|
|
ver = psVerFromEncodingMajMin(majVer, minVer);
|
|
|
|
if (ver != v_undefined)
|
|
{
|
|
ADD_PEER_SUPP_VER(ssl, ver);
|
|
ADD_PEER_SUPP_VER_PRIORITY(ssl, ver);
|
|
psTracePrintProtocolVersion(INDENT_EXTENSION,
|
|
NULL,
|
|
majVer,
|
|
minVer,
|
|
1);
|
|
}
|
|
i++;
|
|
|
|
if (i >= TLS_MAX_SUPPORTED_VERSIONS)
|
|
{
|
|
psTraceErrr("Error: supported_versions list too big\n");
|
|
goto out_internal_error;
|
|
}
|
|
}
|
|
|
|
parsedLen = (p - *c);
|
|
*c = p;
|
|
|
|
return parsedLen;
|
|
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_decode_error:
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
static
|
|
int32_t tls13ParseServerSupportedVersions(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
unsigned char maj, min;
|
|
psProtocolVersion_t ver;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_SUPPORTED_VERSIONS);
|
|
|
|
if (!psParseOctet(pb, &maj) || !psParseOctet(pb, &min))
|
|
{
|
|
return PS_PARSE_FAIL;
|
|
}
|
|
ver = psVerFromEncodingMajMin(maj, min);
|
|
|
|
psTracePrintProtocolVersion(INDENT_EXTENSION,
|
|
"selected_version",
|
|
maj, min, 1);
|
|
|
|
if (!SUPP_VER(ssl, ver))
|
|
{
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
psTraceIntInfo("Unsupported server version: %u", min);
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
SET_NGTD_VER(ssl, ver);
|
|
|
|
if (ver & v_tls_1_3_any)
|
|
{
|
|
return PS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Try the <1.3 code path. */
|
|
return SSL_NO_TLS_1_3;
|
|
}
|
|
}
|
|
|
|
# ifndef USE_ONLY_PSK_CIPHER_SUITE
|
|
static
|
|
int32_t tls13ParseServerKeyShare(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
uint16_t serverGroup;
|
|
psSizeL_t keyExchangeLen;
|
|
int32_t rc;
|
|
psPubKey_t *privKey;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_KEY_SHARE);
|
|
|
|
ssl->extFlags.got_key_share = 1;
|
|
|
|
rc = psParseBufTryParseBigEndianUint16(pb,
|
|
&serverGroup);
|
|
if (rc != 2)
|
|
{
|
|
psTraceErrr("Error: malformed server key_share\n");
|
|
goto out_decode_error;
|
|
}
|
|
|
|
psTracePrintTls13NamedGroup(INDENT_EXTENSION,
|
|
"server_share",
|
|
serverGroup, PS_TRUE);
|
|
|
|
/* Is this key_share in HelloRetryRequest */
|
|
if (ssl->tls13IncorrectDheKeyShare)
|
|
{
|
|
/* Check (1) from spec chapter 4.2.8:
|
|
"the selected_group field corresponds to a group
|
|
which was provided in the "supported_groups" extension in the
|
|
original ClientHello;" */
|
|
if (!tls13WeSupportGroup(ssl, serverGroup))
|
|
{
|
|
psTraceErrr("Server sent key_share in HelloRetryRequest" \
|
|
" and selected group that was not included in"
|
|
" our supported_groups extension\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/* Check (2) in spec chapter 4.2.8:
|
|
"the selected_group field does not correspond to
|
|
a group which was provided in the key_share extension
|
|
in the original ClientHello" */
|
|
if (tls13GetGroupKey(ssl, serverGroup) != NULL)
|
|
{
|
|
|
|
psTraceErrr("Server sent key_share in HelloRetryRequest" \
|
|
" but didn't change the group\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
ssl->tls13NegotiatedGroup = serverGroup;
|
|
|
|
/* Need to trigger ClientHello sending again. */
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
privKey = tls13GetGroupKey(ssl, serverGroup);
|
|
if (privKey == NULL)
|
|
{
|
|
psTraceErrr("Server chose an unsupported group or a group we did not" \
|
|
" generate a key share for.\n");
|
|
goto out_handshake_failure;
|
|
}
|
|
|
|
/* opaque key_exchange<1..2^16-1>; */
|
|
/* Consume the length */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 1,
|
|
&keyExchangeLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
/* Both sides have agreement on the used group */
|
|
ssl->tls13NegotiatedGroup = serverGroup;
|
|
|
|
rc = tls13ImportPublicValue(ssl,
|
|
pb->buf.start,
|
|
keyExchangeLen,
|
|
serverGroup);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_decode_error:
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_handshake_failure:
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
int32_t tls13ParseKeyShare(ssl_t *ssl,
|
|
psParseBuf_t *pb,
|
|
psBool_t allowStateChange)
|
|
{
|
|
int32_t rc;
|
|
const unsigned char *c = pb->buf.start;
|
|
psSize_t extLen = pb->buf.end - pb->buf.start;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_KEY_SHARE);
|
|
|
|
/*
|
|
enum {
|
|
unallocated_RESERVED(0x0000),
|
|
|
|
// Elliptic Curve Groups (ECDHE)
|
|
obsolete_RESERVED(0x0001..0x0016),
|
|
secp256r1(0x0017), secp384r1(0x0018), secp521r1(0x0019),
|
|
obsolete_RESERVED(0x001A..0x001C),
|
|
x25519(0x001D), x448(0x001E),
|
|
|
|
// Finite Field Groups (DHE)
|
|
ffdhe2048(0x0100), ffdhe3072(0x0101), ffdhe4096(0x0102),
|
|
ffdhe6144(0x0103), ffdhe8192(0x0104),
|
|
|
|
// Reserved Code Points
|
|
ffdhe_private_use(0x01FC..0x01FF),
|
|
ecdhe_private_use(0xFE00..0xFEFF),
|
|
obsolete_RESERVED(0xFF01..0xFF02),
|
|
(0xFFFF)
|
|
} NamedGroup;
|
|
|
|
struct {
|
|
NamedGroup group;
|
|
opaque key_exchange<1..2^16-1>;
|
|
} KeyShareEntry;
|
|
|
|
struct {
|
|
KeyShareEntry client_shares<0..2^16-1>;
|
|
} KeyShareClientHello;
|
|
*/
|
|
|
|
/*
|
|
Minimum length: 7 ==
|
|
2 (client_shares length)
|
|
+ 2 (NamedGroup)
|
|
+ 2 (key_exchange length)
|
|
+ 1 (min bytes in key_exchange data)
|
|
*/
|
|
if (extLen < 7)
|
|
{
|
|
psTraceErrr("Malformed key_share extension\n");
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
/* KeyShareEntry client_shares<0..2^16-1>; */
|
|
psSizeL_t clientSharesLen = 0;
|
|
psBool_t importedPeerPubValue = PS_FALSE;
|
|
psSize_t n = psParseTlsVariableLengthVec(c, c + extLen,
|
|
0, (1 << 16) - 1,
|
|
&clientSharesLen);
|
|
|
|
psTraceIndent(INDENT_EXTENSION,
|
|
"Groups in ClientHello.key_share:\n");
|
|
|
|
if (n <= 0 || clientSharesLen < 1)
|
|
{
|
|
psTraceErrr("Malformed key_share extension\n");
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
c += n;
|
|
extLen -= n;
|
|
|
|
while (clientSharesLen > 0)
|
|
{
|
|
psSizeL_t keyExchangeLen = 0;
|
|
psSize_t n;
|
|
psBool_t foundSupportedCurve = PS_FALSE;
|
|
unsigned short groupName;
|
|
|
|
/* 2-byte NamedGroup ID */
|
|
if (extLen < 2)
|
|
{
|
|
psTraceErrr("Malformed key_share extension\n");
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
groupName = *c << 8; c++;
|
|
groupName += *c; c++;
|
|
extLen -= 2;
|
|
clientSharesLen -= 2;
|
|
|
|
psTracePrintTls13NamedGroup(INDENT_EXTENSION + 1,
|
|
NULL, groupName, PS_TRUE);
|
|
if (tls13AddPeerKeyShareGroup(ssl, groupName) < 0)
|
|
{
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
if (tls13WeSupportGroup(ssl, groupName))
|
|
{
|
|
psTracePrintTls13NamedGroup(INDENT_NEGOTIATED_PARAM,
|
|
"Found supported group",
|
|
groupName,
|
|
PS_TRUE);
|
|
foundSupportedCurve = PS_TRUE;
|
|
}
|
|
|
|
/* opaque key_exchange<1..2^16-1>; */
|
|
n = psParseTlsVariableLengthVec(c, c + extLen,
|
|
1, (1 << 16) - 1,
|
|
&keyExchangeLen);
|
|
if (n <= 0 || keyExchangeLen < 1)
|
|
{
|
|
psTraceErrr("Malformed key_share extension\n");
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
c += n;
|
|
extLen -= n;
|
|
clientSharesLen -= n;
|
|
|
|
/* Import the first public value that we can support. */
|
|
if (foundSupportedCurve && !importedPeerPubValue)
|
|
{
|
|
if (allowStateChange)
|
|
{
|
|
rc = tls13ImportPublicValue(ssl,
|
|
c,
|
|
keyExchangeLen,
|
|
groupName);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/* We will still iterate over the rest of the entries,
|
|
but will not try to import another public value. */
|
|
importedPeerPubValue = PS_TRUE;
|
|
ssl->tls13NegotiatedGroup = groupName;
|
|
}
|
|
|
|
c += keyExchangeLen;
|
|
extLen -= keyExchangeLen;
|
|
clientSharesLen -= keyExchangeLen;
|
|
}
|
|
}
|
|
|
|
if (allowStateChange)
|
|
{
|
|
ssl->extFlags.got_key_share = 1;
|
|
}
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
}
|
|
# endif /* USE_ONLY_PSK_CIPHER_SUITE */
|
|
|
|
static
|
|
int32_t tls13VerifyBinder(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
int32_t rc, hmacAlg, hmacLen;
|
|
psSize_t remLen;
|
|
psSizeL_t len;
|
|
unsigned char *peerBinder = NULL;
|
|
psSize_t binderLen = 0;
|
|
uint16_t ix;
|
|
unsigned char ourBinder[MAX_TLS_1_3_HASH_SIZE];
|
|
unsigned char binderKey[MAX_TLS_1_3_HASH_SIZE];
|
|
psSize_t binderKeyLen;
|
|
psHmac_t ctx;
|
|
|
|
hmacAlg = tls13GetPskHmacAlg(ssl->sec.tls13ChosenPsk);
|
|
hmacLen = tls13GetPskHashLen(ssl->sec.tls13ChosenPsk);
|
|
if (hmacAlg == 0 || hmacLen <= 0 || hmacLen > MAX_TLS_1_3_HASH_SIZE)
|
|
{
|
|
psTraceErrr("Invalid TLS 1.3 PSK binder hash algorithm\n");
|
|
goto out_decode_error;
|
|
}
|
|
|
|
/*
|
|
The ClientHello transcript hash is split at the start of the
|
|
binders vector. tls13BindersLen is attacker-controlled through the
|
|
pre_shared_key extension, while tls13CHLen is the length of the
|
|
buffered ClientHello. MatrixSSL 4.x used to subtract these values
|
|
without checking for wraparound. Since psSize_t is 16 bit on this
|
|
code base, a malformed extension could make the subtraction wrap and
|
|
cause hashing beyond the ClientHello buffer (CVE-2023-24609).
|
|
*/
|
|
if (ssl->sec.tls13CHStart == NULL ||
|
|
ssl->sec.tls13BindersLen < 2 ||
|
|
ssl->sec.tls13BindersLen > ssl->sec.tls13CHLen)
|
|
{
|
|
psTraceErrr("Invalid TLS 1.3 PSK binder length\n");
|
|
goto out_decode_error;
|
|
}
|
|
|
|
rc = tls13TranscriptHashUpdate(ssl,
|
|
ssl->sec.tls13CHStart,
|
|
ssl->sec.tls13CHLen - ssl->sec.tls13BindersLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
rc = tls13TranscriptHashSnapshot(ssl,
|
|
ssl->sec.tls13TrHashSnapshotCHWithoutBinders);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
rc = tls13TranscriptHashUpdate(ssl,
|
|
ssl->sec.tls13CHStart +
|
|
ssl->sec.tls13CHLen - ssl->sec.tls13BindersLen,
|
|
ssl->sec.tls13BindersLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
/* Find the binder corresponding to the PSK we have chosen. */
|
|
ix = 0;
|
|
remLen = ssl->sec.tls13BindersLen - 2;
|
|
while (peerBinder == NULL
|
|
&& ix <= ssl->sec.tls13SelectedIdentityIndex
|
|
&& remLen > 0
|
|
&& psParseCanRead(pb, remLen) )
|
|
{
|
|
/* opaque PskBinderEntry<32..255>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
32, 255,
|
|
&len);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
if (ix == ssl->sec.tls13SelectedIdentityIndex)
|
|
{
|
|
peerBinder = pb->buf.start;
|
|
binderLen = len;
|
|
}
|
|
/* forward over this binder */
|
|
rc = psParseTryForward(pb, len);
|
|
if (rc != len)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
remLen -= (len + 1); /* account for binder data and length byte */
|
|
ix++;
|
|
}
|
|
|
|
if (peerBinder == NULL || len == 0)
|
|
{
|
|
psTraceErrr("Binder for chosen PSK missing\n");
|
|
goto out_decrypt_error;
|
|
}
|
|
if (binderLen != hmacLen)
|
|
{
|
|
psTraceErrr("Binder for chosen PSK has incorrect length\n");
|
|
goto out_decrypt_error;
|
|
}
|
|
|
|
/* Generate the binder_key.*/
|
|
rc = tls13DeriveEarlySecrets(ssl, ssl->sec.tls13ChosenPsk);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("early_secret", ssl->sec.tls13EarlySecret, hmacLen);
|
|
psTraceBytes("binder_secret", ssl->sec.tls13ExtBinderSecret, hmacLen);
|
|
#endif
|
|
|
|
rc = tls13DeriveBinderKey(ssl,
|
|
hmacAlg,
|
|
ssl->sec.tls13ExtBinderSecret,
|
|
hmacLen,
|
|
binderKey,
|
|
&binderKeyLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("binder key", binderKey, binderKeyLen);
|
|
psTraceBytes("snapshot hs hash",
|
|
ssl->sec.tls13TrHashSnapshotCHWithoutBinders,
|
|
hmacLen);
|
|
# endif
|
|
|
|
/*
|
|
binder value =
|
|
HMAC(binderKey, Transcript-Hash(Truncate(ClientHello))
|
|
*/
|
|
rc = psHmacSingle(&ctx,
|
|
hmacAlg,
|
|
binderKey,
|
|
hmacLen,
|
|
ssl->sec.tls13TrHashSnapshotCHWithoutBinders,
|
|
hmacLen,
|
|
ourBinder);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("binder value", ourBinder, hmacLen);
|
|
# endif
|
|
if (memcmpct(peerBinder, ourBinder, hmacLen) == 0)
|
|
{
|
|
psTraceInfo("Binder OK\n");
|
|
}
|
|
else
|
|
{
|
|
psTraceErrr("Binder did not validate\n");
|
|
goto out_decrypt_error;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_decode_error:
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_decrypt_error:
|
|
ssl->err = SSL_ALERT_DECRYPT_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/** Called after the server has parsed a negotiable PSK from the client's
|
|
pre_shared_key extension. Negotiable means that the server either
|
|
has the same PSK in its run-time PSK cache, or the PSK was decrypted
|
|
from a ticket the server had encrypted earlier. */
|
|
static
|
|
psBool_t tls13ServerFoundSupportedPsk(ssl_t *ssl,
|
|
psTls13Psk_t *psk,
|
|
uint16_t indexInClientPreSharedKey)
|
|
{
|
|
psProtocolVersion_t pskVer;
|
|
uint8_t majVer, minVer;
|
|
const sslCipherSpec_t *cipher;
|
|
|
|
(void)pskVer;
|
|
|
|
psTraceInfo("Server recognized a PSK in pre_shared_key\n");
|
|
if (psk->isResumptionPsk)
|
|
{
|
|
psTraceInfo(" Trying to resume the associated session\n");
|
|
}
|
|
|
|
ssl->sec.tls13UsingPsk = PS_TRUE;
|
|
ssl->sec.tls13ChosenPsk = psk;
|
|
ssl->sec.tls13SelectedIdentityIndex = indexInClientPreSharedKey;
|
|
if (psk->params != NULL)
|
|
{
|
|
majVer = psk->params->majVer;
|
|
minVer = psk->params->minVer;
|
|
if (minVer == 0)
|
|
{
|
|
minVer = TLS_1_2_MIN_VER;
|
|
}
|
|
pskVer = psVerFromEncodingMajMin(majVer, minVer);
|
|
|
|
/* If the PSK is associated with a ciphersuite, take that
|
|
suite into use. Otherwise, use whathever we may have
|
|
negotiated. */
|
|
cipher = sslGetCipherSpec(ssl, psk->params->cipherId);
|
|
if (cipher == NULL)
|
|
{
|
|
psTraceInfo("Error: PSK is associated with an unsupported " \
|
|
"ciphersuite\n");
|
|
return PS_FALSE;
|
|
}
|
|
else if (cipher->ident != SSL_NULL_WITH_NULL_NULL)
|
|
{
|
|
ssl->cipher = cipher;
|
|
}
|
|
psTracePrintProtocolVersionNew(INDENT_EXTENSION,
|
|
"PSK is associated with protocol version",
|
|
pskVer,
|
|
PS_TRUE);
|
|
psTracePrintCiphersuiteName(INDENT_EXTENSION,
|
|
"PSK is associated with ciphersuite",
|
|
cipher->ident,
|
|
PS_TRUE);
|
|
}
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("PSK identity", psk->pskId, psk->pskIdLen);
|
|
psTraceBytes("PSK key", psk->pskKey, psk->pskLen);
|
|
# endif /* DEBUG_TLS_1_3_DECODE_EXTENSIONS */
|
|
return PS_TRUE;
|
|
}
|
|
|
|
int32_t tls13ParsePreSharedKey(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
int32_t rc;
|
|
uint16_t ix;
|
|
uint32_t obfuscatedTicketAge = 0;
|
|
uint32_t clientTicketAge;
|
|
uint32_t serverTicketAge;
|
|
psTime_t now;
|
|
psSizeL_t idsLen, remIdsLen;
|
|
psSizeL_t bindersLen = 0, identityLen;
|
|
psParseBuf_t idBuf;
|
|
psBool_t foundPsk = PS_FALSE;
|
|
psTls13Psk_t *psk;
|
|
uint16_t selectedIdentity = 0;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_PRE_SHARED_KEY);
|
|
|
|
/*
|
|
struct {
|
|
opaque identity<1..2^16-1>;
|
|
uint32 obfuscated_ticket_age;
|
|
} PskIdentity;
|
|
|
|
opaque PskBinderEntry<32..255>;
|
|
|
|
struct {
|
|
PskIdentity identities<7..2^16-1>;
|
|
PskBinderEntry binders<33..2^16-1>;
|
|
} OfferedPsks;
|
|
|
|
struct {
|
|
select (Handshake.msg_type) {
|
|
case client_hello: OfferedPsks;
|
|
case server_hello: uint16 selected_identity;
|
|
};
|
|
} PreSharedKeyExtension;
|
|
*/
|
|
|
|
if (!SUPP_VER(ssl, v_tls_1_3_any))
|
|
{
|
|
tlsTraceIndent(INDENT_EXTENSION,
|
|
"Ignoring this TLS 1.3 specific extension, " \
|
|
"since TLS 1.3 not enabled\n");
|
|
return MATRIXSSL_SUCCESS;
|
|
}
|
|
|
|
if (MATRIX_IS_SERVER(ssl))
|
|
{
|
|
/* PskIdentity identities<7..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
7, (1 << 16) - 1,
|
|
&idsLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
|
|
/* Start parsing the PskIdentities. */
|
|
(void)psParseBufFromStaticData(&idBuf,
|
|
pb->buf.start, idsLen);
|
|
remIdsLen = idsLen;
|
|
ix = 0;
|
|
|
|
while (remIdsLen > 0 && psParseCanRead(&idBuf, remIdsLen))
|
|
{
|
|
/* opaque identity<1..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(&idBuf,
|
|
1, (1 << 16) - 1,
|
|
&identityLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
remIdsLen -= rc;
|
|
|
|
if (!psParseCanRead(&idBuf, identityLen))
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
|
|
psTracePrintPskIdentity(INDENT_EXTENSION,
|
|
"psk_identity",
|
|
idBuf.buf.start,
|
|
identityLen,
|
|
ssl,
|
|
PS_TRUE);
|
|
|
|
if (!foundPsk)
|
|
{
|
|
/*
|
|
Check whether the PSK is negotiable, i.e. that we
|
|
recognize (i.e. have) it and it is compatible with the
|
|
ciphersuite.
|
|
|
|
The ciphersuite has been negotiated already, we can follow
|
|
the RFC 8446 recommendation (4.2.11) and exclude any
|
|
non-compatible PSKs.
|
|
*/
|
|
psk = NULL;
|
|
rc = tls13FindSessionPsk(ssl,
|
|
idBuf.buf.start, identityLen,
|
|
&psk);
|
|
if (rc == PS_SUCCESS && psk != NULL &&
|
|
tls13GetPskHmacAlg(psk) ==
|
|
tls13CipherIdToHmacAlg(ssl->cipher->ident))
|
|
{
|
|
foundPsk = tls13ServerFoundSupportedPsk(ssl, psk, ix);
|
|
}
|
|
}
|
|
|
|
rc = psParseTryForward(&idBuf, identityLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
remIdsLen -= identityLen;
|
|
|
|
/* uint32 obfuscated_ticket_age; */
|
|
rc = psParseBufTryParseBigEndianUint32(&idBuf,
|
|
&obfuscatedTicketAge);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
/* See if early_data can be enabled. */
|
|
if (foundPsk == PS_TRUE &&
|
|
ssl->extFlags.got_early_data == 1 &&
|
|
ssl->sec.tls13ChosenPsk->isResumptionPsk == PS_TRUE &&
|
|
ssl->sec.tls13ChosenPsk->params != NULL &&
|
|
ssl->sec.tls13ChosenPsk->params->maxEarlyData > 0 &&
|
|
ssl->sec.tls13SelectedIdentityIndex == 0 &&
|
|
ssl->tls13IncorrectDheKeyShare != PS_TRUE)
|
|
{
|
|
/* Check ticket age */
|
|
clientTicketAge = obfuscatedTicketAge -
|
|
ssl->sec.tls13ChosenPsk->params->ticketAgeAdd;
|
|
psGetTime(&now, NULL);
|
|
serverTicketAge = psDiffMsecs(
|
|
ssl->sec.tls13ChosenPsk->params->timestamp,
|
|
now,
|
|
NULL);
|
|
if (abs(clientTicketAge - serverTicketAge) <=
|
|
TLS_1_3_EARLY_DATA_TICKET_AGE_WINDOW)
|
|
{
|
|
ssl->tls13ServerEarlyDataEnabled = PS_TRUE;
|
|
}
|
|
}
|
|
remIdsLen -= rc;
|
|
ix++;
|
|
} /* End of PskIdentity parsing. */
|
|
|
|
pb->buf.start = idBuf.buf.start;
|
|
|
|
/* PskBinderEntry binders<33..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
33, (1 << 16) - 1,
|
|
&bindersLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
|
|
if (foundPsk)
|
|
{
|
|
if (bindersLen > (psSizeL_t) ((psSize_t) ~0) - 2)
|
|
{
|
|
psTraceErrr("TLS 1.3 PSK binders vector too large\n");
|
|
goto out_decode_error;
|
|
}
|
|
ssl->sec.tls13BindersLen = (psSize_t) bindersLen + 2;
|
|
|
|
rc = tls13VerifyBinder(ssl, pb);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = psParseTryForward(pb, bindersLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
psTraceInfo("Did not recognize any PSKs in pre_shared_key.");
|
|
psTraceInfo(" Continuing normal handshake...\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = psParseBufTryParseBigEndianUint16(pb, &selectedIdentity);
|
|
if (rc < 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
psTraceIntInfo("Server selected_identity: %hu\n", selectedIdentity);
|
|
ix = 0;
|
|
psk = ssl->sec.tls13SessionPskList;
|
|
while (psk)
|
|
{
|
|
if (ix == selectedIdentity)
|
|
{
|
|
foundPsk = PS_TRUE;
|
|
ssl->sec.tls13ChosenPsk = psk;
|
|
ssl->sec.tls13UsingPsk = PS_TRUE;
|
|
ssl->sec.tls13SelectedIdentityIndex = selectedIdentity;
|
|
}
|
|
psk = psk->next;
|
|
ix++;
|
|
}
|
|
if (!foundPsk)
|
|
{
|
|
psTraceErrr("Server selected_identity out of range\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
}
|
|
|
|
ssl->extFlags.got_pre_shared_key = 1;
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
|
|
out_decode_error:
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
int32_t tls13ParsePskKeyExchangeModes(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
psParseBuf_t modesBuf;
|
|
psSizeL_t modesLen, remModesLen;
|
|
uint8_t modeVal = 0;
|
|
int32_t rc;
|
|
psk_key_exchange_mode_e mode;
|
|
psSize_t i, k;
|
|
psBool_t gotPskKe = PS_FALSE;
|
|
psBool_t gotPskDheKe = PS_FALSE;
|
|
|
|
psAssert(MATRIX_IS_SERVER(ssl));
|
|
psTracePrintExtensionParse(ssl, EXT_PSK_KEY_EXCHANGE_MODES);
|
|
|
|
/*
|
|
enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode;
|
|
|
|
struct {
|
|
PskKeyExchangeMode ke_modes<1..255>;
|
|
} PskKeyExchangeModes;
|
|
*/
|
|
|
|
/* PskKeyExchangeMode ke_modes<1..255>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
1, 255,
|
|
&modesLen);
|
|
if (rc < 0)
|
|
{
|
|
goto out_handshake_failure;
|
|
}
|
|
|
|
/* Start parsing the PskKeyExchangeModes. */
|
|
(void)psParseBufFromStaticData(&modesBuf,
|
|
pb->buf.start, modesLen);
|
|
remModesLen = modesLen;
|
|
|
|
i = 0;
|
|
k = 0;
|
|
while (remModesLen > 0 && psParseCanRead(&modesBuf, 1))
|
|
{
|
|
if (psParseOctet(&modesBuf, &modeVal) < 0)
|
|
{
|
|
goto out_handshake_failure;
|
|
}
|
|
if (i == 0)
|
|
{
|
|
tlsTraceIndent(INDENT_EXTENSION,
|
|
"psk_key_exchange_modes:\n");
|
|
}
|
|
psTracePrintPskKeyExchangeMode(INDENT_EXTENSION + 1,
|
|
NULL,
|
|
modeVal+1, PS_TRUE);
|
|
psAssert(k < 2);
|
|
|
|
if (modeVal == 0 && !gotPskKe)
|
|
{
|
|
mode = psk_keyex_mode_psk_ke;
|
|
ssl->sec.tls13ClientPskModes[k++] = mode;
|
|
ssl->sec.tls13ClientPskModesLen = k;
|
|
gotPskKe = PS_TRUE;
|
|
}
|
|
else if (modeVal == 1 && !gotPskDheKe)
|
|
{
|
|
mode = psk_keyex_mode_psk_dhe_ke;
|
|
ssl->sec.tls13ClientPskModes[k++] = mode;
|
|
ssl->sec.tls13ClientPskModesLen = k;
|
|
gotPskDheKe = PS_TRUE;
|
|
}
|
|
|
|
/* Ignore unknown modes and duplicates. */
|
|
i++;
|
|
}
|
|
|
|
if (!gotPskDheKe && !gotPskKe)
|
|
{
|
|
psTraceErrr("Cannot support any PSK key exchange modes offered " \
|
|
"by the client.\n");
|
|
goto out_handshake_failure;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_handshake_failure:
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return PS_PARSE_FAIL;
|
|
}
|
|
|
|
int32_t tls13ParseCookie(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
psSizeL_t cookieLen;
|
|
psSize_t copiedLen;
|
|
int32_t rc;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_COOKIE);
|
|
|
|
/*
|
|
struct {
|
|
opaque cookie<1..2^16-1>;
|
|
} Cookie;
|
|
*/
|
|
/* opaque cookie<1..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 1,
|
|
&cookieLen);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Error parsing Cookie extension\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/*
|
|
Server are allowed send cookies only in HelloRetryRequest messages,
|
|
not in ordinary ServerHellos. Clients are only allowed to send
|
|
a cookie when responding to a HelloRetryRequest.
|
|
*/
|
|
if (!ssl->tls13IncorrectDheKeyShare)
|
|
{
|
|
psTraceErrr("Got unexpected cookie extension\n");
|
|
goto out_unsupported_extension;
|
|
}
|
|
|
|
if (MATRIX_IS_SERVER(ssl))
|
|
{
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("Parsed ClientHello.cookie",
|
|
pb->buf.start,
|
|
cookieLen);
|
|
# endif
|
|
|
|
/*
|
|
"When sending the new ClientHello, the client MUST copy
|
|
the contents of the extension received in the HelloRetryRequest into
|
|
a "cookie" extension in the new ClientHello."
|
|
*/
|
|
if (cookieLen != psGetOutputBlockLength(tls13GetCipherHmacAlg(ssl)) ||
|
|
Memcmp(ssl->sec.tls13TrHashSnapshotCH1,
|
|
pb->buf.start,
|
|
cookieLen))
|
|
{
|
|
psTraceBytes("Client sent back invalid cookie",
|
|
pb->buf.start,
|
|
cookieLen);
|
|
goto out_decrypt_error;
|
|
}
|
|
else
|
|
{
|
|
psTraceInfo("Client cookie OK\n");
|
|
ssl->sec.tls13ClientCookieOk = PS_TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("Parsed HelloRetryRequest.cookie",
|
|
pb->buf.start,
|
|
cookieLen);
|
|
# endif
|
|
/* As client, we simply store the value we received from the server. */
|
|
if (ssl->sec.tls13CookieFromServer)
|
|
{
|
|
psFree(ssl->sec.tls13CookieFromServer, ssl->hsPool);
|
|
ssl->sec.tls13CookieFromServer = NULL;
|
|
ssl->sec.tls13CookieFromServerLen = 0;
|
|
}
|
|
ssl->sec.tls13CookieFromServer = psMalloc(ssl->hsPool, cookieLen);
|
|
if (ssl->sec.tls13CookieFromServer == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
copiedLen = cookieLen;
|
|
|
|
rc = psParseBufCopyNPsSize(pb,
|
|
cookieLen,
|
|
ssl->sec.tls13CookieFromServer,
|
|
&copiedLen);
|
|
if (rc != PS_SUCCESS)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
psAssert(copiedLen == cookieLen);
|
|
(void)copiedLen;
|
|
ssl->sec.tls13CookieFromServerLen = cookieLen;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_decrypt_error:
|
|
ssl->err = SSL_ALERT_DECRYPT_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_unsupported_extension:
|
|
ssl->err = SSL_ALERT_UNSUPPORTED_EXTENSION;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
int32_t tls13ParseServerName(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
# ifdef USE_SERVER_SIDE_SSL
|
|
int32_t rc;
|
|
psSizeL_t serverNameListLen, hostNameLen;
|
|
unsigned char nameType = 0;
|
|
size_t copiedLen;
|
|
# endif
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_SERVER_NAME);
|
|
|
|
/*
|
|
struct {
|
|
NameType name_type;
|
|
select (name_type) {
|
|
case host_name: HostName;
|
|
} name;
|
|
} ServerName;
|
|
|
|
enum {
|
|
host_name(0), (255)
|
|
} NameType;
|
|
|
|
opaque HostName<1..2^16-1>;
|
|
|
|
struct {
|
|
ServerName server_name_list<1..2^16-1>
|
|
} ServerNameList;
|
|
*/
|
|
|
|
# ifdef USE_SERVER_SIDE_SSL
|
|
if (MATRIX_IS_SERVER(ssl))
|
|
{
|
|
/* ServerName server_name_list<1..2^16-1> */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
1, (1 << 16) - 1,
|
|
&serverNameListLen);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Error parsing server_name_list\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
if (!psParseCanRead(pb, serverNameListLen))
|
|
{
|
|
psTraceErrr("Error parsing server_name_list\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/* NameType name_type; */
|
|
rc = psParseOctet(pb, &nameType);
|
|
if (rc < 0 || nameType != 0) /* We only support host_name(0). */
|
|
{
|
|
psTraceErrr("Invalid NameType\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
/* opaque HostName<1..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
1, (1 << 16) - 1,
|
|
&hostNameLen);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Error parsing HostName\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
if (!psParseCanRead(pb, hostNameLen))
|
|
{
|
|
psTraceErrr("Error parsing HostName\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
if (ssl->expectedName)
|
|
{
|
|
psFree(ssl->expectedName, ssl->sPool);
|
|
}
|
|
ssl->expectedName = psMalloc(ssl->sPool, hostNameLen + 1);
|
|
if (ssl->expectedName == NULL)
|
|
{
|
|
psTraceErrr("Out of mem\n");
|
|
goto out_internal_error;
|
|
}
|
|
psParseBufCopyN(pb,
|
|
hostNameLen,
|
|
(unsigned char*)ssl->expectedName,
|
|
&copiedLen);
|
|
(void)copiedLen;
|
|
ssl->expectedName[hostNameLen] = '\0';
|
|
psTracePrintServerName(INDENT_EXTENSION,
|
|
"HostName",
|
|
ssl->expectedName,
|
|
PS_TRUE);
|
|
ssl->extFlags.sni_in_last_client_hello = 1;
|
|
}
|
|
# endif
|
|
# ifdef USE_CLIENT_SIDE_SSL
|
|
if (!MATRIX_IS_SERVER(ssl))
|
|
{
|
|
/* Solicited or not? */
|
|
if (ssl->extFlags.req_sni == 0)
|
|
{
|
|
psTraceErrr("Server sent unsolicited server_name extension\n");
|
|
goto out_unsupported_extension;
|
|
}
|
|
|
|
/* Only an empty server_name is allowed from the server. */
|
|
if (psParseCanRead(pb, 1))
|
|
{
|
|
psTraceErrr("Server's server_name extension not empty\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
psTraceInfo("Received empty server_name in EncryptedExtensions\n");
|
|
}
|
|
# endif
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
# ifdef USE_SERVER_SIDE_SSL
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
# endif /* USE_SERVER_SIDE_SSL */
|
|
# ifdef USE_CLIENT_SIDE_SSL
|
|
out_unsupported_extension:
|
|
ssl->err = SSL_ALERT_UNSUPPORTED_EXTENSION;
|
|
return MATRIXSSL_ERROR;
|
|
# endif /* USE_CLIENT_SIDE_SSL */
|
|
}
|
|
|
|
int32_t tls13ParseEarlyData(ssl_t *ssl,
|
|
psParseBuf_t *pb,
|
|
uint32_t *maxEarlyData)
|
|
{
|
|
int32_t rc;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_EARLY_DATA);
|
|
|
|
if (MATRIX_IS_SERVER(ssl))
|
|
{
|
|
if (!ssl->tls13IncorrectDheKeyShare)
|
|
{
|
|
ssl->extFlags.got_early_data = 1;
|
|
}
|
|
else
|
|
{
|
|
/* early_data extension should not be included to CH after HRR
|
|
so ignore it */
|
|
ssl->extFlags.got_early_data = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Handle the client-side case (i.e. parsing the server's
|
|
early_data extension sent in NewSessionTicket.)
|
|
*/
|
|
psAssert(!MATRIX_IS_SERVER(ssl));
|
|
rc = psParseBufTryParseBigEndianUint32(pb,
|
|
maxEarlyData);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
/** Parse signature_algorithms or signature_algorithms_cert extension.
|
|
Advance parse pointer c.
|
|
isCert parameter specifies whether the extension is normal
|
|
signature_algorithms or signature_algorithms_cert.
|
|
*/
|
|
int32_t tls13ParseSignatureAlgorithms(ssl_t *ssl,
|
|
const unsigned char **c,
|
|
psSize_t len,
|
|
psBool_t isCert)
|
|
{
|
|
int rc;
|
|
psParseBuf_t pb;
|
|
uint16_t sigAlg;
|
|
psSize_t algsLen;
|
|
psSize_t parsedLen = 0;
|
|
int32_t i = 0;
|
|
uint16_t mask;
|
|
|
|
if (isCert)
|
|
{
|
|
psTracePrintExtensionParse(ssl, EXT_SIGNATURE_ALGORITHMS_CERT);
|
|
}
|
|
else
|
|
{
|
|
psTracePrintExtensionParse(ssl, EXT_SIGNATURE_ALGORITHMS);
|
|
}
|
|
|
|
|
|
(void)psParseBufFromStaticData(&pb, *c, len);
|
|
/* Move the supplied pointer forwards to the end
|
|
of this extension */
|
|
*c += len;
|
|
|
|
rc = psParseBufTryParseBigEndianUint16(&pb,
|
|
&algsLen);
|
|
if (rc != 2)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
if (isCert)
|
|
{
|
|
# ifdef USE_IDENTITY_CERTIFICATES
|
|
ssl->sec.keySelect.peerCertSigAlgsLen = 0;
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
ssl->sec.keySelect.peerSigAlgsLen = 0;
|
|
}
|
|
|
|
while (parsedLen < algsLen)
|
|
{
|
|
rc = psParseBufTryParseBigEndianUint16(&pb,
|
|
&sigAlg);
|
|
if (rc != 2)
|
|
{
|
|
return rc;
|
|
}
|
|
parsedLen += 2;
|
|
if (i >= TLS_MAX_SIGNATURE_ALGORITHMS)
|
|
{
|
|
psTraceInfo("Warning: Ignored signature_algorithm. " \
|
|
"Increase TLS_1_3_MAX_SIGNATURE_ALGORITHMS.\n");
|
|
break;
|
|
}
|
|
/* Save the algoritm based on which extension this is */
|
|
if (isCert)
|
|
{
|
|
# ifdef USE_IDENTITY_CERTIFICATES
|
|
/* Make sure this sig_alg_cert is in our supported list */
|
|
if (findFromUint16Array(
|
|
ssl->tls13SupportedSigAlgsCert,
|
|
ssl->tls13SupportedSigAlgsCertLen,
|
|
sigAlg) != PS_FAILURE
|
|
# ifdef USE_SM2
|
|
&& !(sigAlg != sigalg_sm2sig_sm3 &&
|
|
ssl->tls13SelectedSMSuite)
|
|
# endif
|
|
)
|
|
{
|
|
mask = HASH_SIG_MASK(((sigAlg >> 8) & 0xff),
|
|
(sigAlg & 0xff));
|
|
ssl->sec.keySelect.peerCertSigAlgs[i] = sigAlg;
|
|
ssl->sec.keySelect.peerCertSigAlgsLen++;
|
|
ssl->sec.keySelect.peerCertSigAlgMask |= mask;
|
|
i++;
|
|
}
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
/* Make sure this sig_alg is in our supported list */
|
|
if (findFromUint16Array(
|
|
ssl->supportedSigAlgs,
|
|
ssl->supportedSigAlgsLen,
|
|
sigAlg) != PS_FAILURE
|
|
# ifdef USE_SM2
|
|
&& !(sigAlg != sigalg_sm2sig_sm3 &&
|
|
ssl->tls13SelectedSMSuite)
|
|
# endif
|
|
)
|
|
{
|
|
mask = HASH_SIG_MASK(((sigAlg >> 8) & 0xff),
|
|
(sigAlg & 0xff));
|
|
ssl->sec.keySelect.peerSigAlgs[i] = sigAlg;
|
|
ssl->sec.keySelect.peerSigAlgsLen++;
|
|
ssl->sec.keySelect.peerSigAlgMask |= mask;
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isCert)
|
|
{
|
|
# ifdef USE_IDENTITY_CERTIFICATES
|
|
/* signature_algorithms_cert only defined in TLS 1.3. */
|
|
psTracePrintTls13SigAlgList(INDENT_EXTENSION,
|
|
"Parsed signature_algorithms_cert",
|
|
ssl->sec.keySelect.peerCertSigAlgs,
|
|
ssl->sec.keySelect.peerCertSigAlgsLen,
|
|
PS_TRUE);
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
psTracePrintTls13SigAlgList(INDENT_EXTENSION,
|
|
"Parsed signature_algorithms",
|
|
ssl->sec.keySelect.peerSigAlgs,
|
|
ssl->sec.keySelect.peerSigAlgsLen,
|
|
PS_TRUE);
|
|
}
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
}
|
|
# ifdef USE_IDENTITY_CERTIFICATES
|
|
psRes_t tls13ParseCertificateAuthorities(ssl_t *ssl,
|
|
const unsigned char **start,
|
|
psSizeL_t len)
|
|
{
|
|
sslKeySelectInfo_t *keySelect = &ssl->sec.keySelect;
|
|
|
|
psRes_t rc;
|
|
size_t nCas, off;
|
|
const unsigned char *data;
|
|
psParseBuf_t pb;
|
|
psSizeL_t caNamesLen = 0, caNameLen;
|
|
|
|
psTracePrintExtensionParse(ssl, EXT_CERTIFICATE_AUTHORITIES);
|
|
|
|
/*
|
|
opaque DistinguishedName<1..2^16-1>;
|
|
struct {
|
|
DistinguishedName authorities<3..2^16-1>;
|
|
} CertificateAuthoritiesExtension;
|
|
*/
|
|
|
|
/* Notice input start and advance to end of extension */
|
|
data = *start;
|
|
*start += len;
|
|
|
|
(void)psParseBufFromStaticData(&pb, data, len);
|
|
rc = psParseBufParseTlsVector(&pb, 3, (1 << 16) - 1, &caNamesLen);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr(" failed to parse CA names\n");
|
|
return rc;
|
|
}
|
|
|
|
/* Count how many issuer names we have. */
|
|
for (nCas = 0, off = 0; off < caNamesLen; nCas += 1, off += (2 + caNameLen))
|
|
{
|
|
rc = psParseBufParseTlsVector(&pb, 1, (1<<16) - 1, &caNameLen);
|
|
if (rc < 0)
|
|
{
|
|
break;
|
|
}
|
|
rc = psParseTryForward(&pb, caNameLen);
|
|
if (rc != caNameLen)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Allocate space for the issuer names and their lengths. */
|
|
keySelect->nCas = nCas;
|
|
keySelect->caNames = psCalloc(pool, nCas, sizeof(keySelect->caNames[0]));
|
|
keySelect->caNameLens = psCalloc(pool, nCas, sizeof(keySelect->caNameLens[0]));
|
|
if (keySelect->caNames == NULL || keySelect->caNameLens == NULL)
|
|
{
|
|
psTraceErrr(" failed to allocate space for CA names\n");
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
/* Rewind and fill - the parseBuf calls have been successful above, and
|
|
they don't allocate memory, therefore they can't fail now. Note:
|
|
pointer to parse buf internal memory - the keySelect content is thus
|
|
only valid during validity of the contained packet. */
|
|
(void)psParseBufFromStaticData(&pb, data, len);
|
|
(void)psParseBufParseTlsVector(&pb, 3, (1 << 16) - 1, &caNamesLen);
|
|
for (nCas = 0, off = 0;
|
|
off < caNamesLen && nCas < keySelect->nCas;
|
|
nCas += 1, off += (2 + caNameLen))
|
|
{
|
|
(void)psParseBufParseTlsVector(&pb, 1, (1<<16) - 1, &caNameLen);
|
|
keySelect->caNames[nCas] = pb.buf.start;
|
|
keySelect->caNameLens[nCas] = caNameLen;
|
|
(void)psParseTryForward(&pb, caNameLen);
|
|
}
|
|
psTraceIntInfo(" got %d CA names\n", keySelect->nCas);
|
|
return PS_SUCCESS;
|
|
}
|
|
# endif
|
|
|
|
int32_t tls13ParseEncryptedExtensions(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
int32_t rc;
|
|
psSizeL_t vecDataLen, extDataLen;
|
|
uint16_t extensionType;
|
|
psParseBuf_t extBuf, extDataBuf;
|
|
|
|
psTracePrintHsMessageParse(ssl, SSL_HS_ENCRYPTED_EXTENSION);
|
|
|
|
/*
|
|
struct {
|
|
ExtensionType extension_type;
|
|
opaque extension_data<0..2^16-1>;
|
|
} Extension;
|
|
|
|
struct {
|
|
Extension extensions<0..2^16-1>;
|
|
} EncryptedExtensions;
|
|
*/
|
|
|
|
/* Extension extensions<0..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 1,
|
|
&vecDataLen);
|
|
if (rc <= 0)
|
|
{
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return PS_PARSE_FAIL;
|
|
}
|
|
|
|
/*
|
|
Init sub buffer with the bytes of extensions<0..2^16-1>.
|
|
*/
|
|
(void)psParseBufFromStaticData(&extBuf,
|
|
pb->buf.start, vecDataLen);
|
|
|
|
while (psParseCanRead(&extBuf, 4))
|
|
{
|
|
/* ExtensionType extension_type; */
|
|
rc = psParseBufTryParseBigEndianUint16(&extBuf,
|
|
&extensionType);
|
|
if (rc != 2)
|
|
{
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return PS_PARSE_FAIL;
|
|
}
|
|
|
|
/* 4.2. If the received extension is not specified for the message
|
|
in which it appears, we MUST abort the handshake with an
|
|
illegal_parameter alert. */
|
|
if (!tls13ExtensionAllowedInMessage(ssl,
|
|
extensionType,
|
|
SSL_HS_ENCRYPTED_EXTENSION))
|
|
{
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/* opaque extension_data<0..2^16-1>;
|
|
Note: this will only consume the length octets from extBuf. */
|
|
rc = psParseBufParseTlsVector(&extBuf,
|
|
0, (1 << 16) - 1,
|
|
&extDataLen);
|
|
if (rc <= 0)
|
|
{
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return PS_PARSE_FAIL;
|
|
}
|
|
(void)psParseBufFromStaticData(&extDataBuf,
|
|
extBuf.buf.start, extDataLen);
|
|
psParseTryForward(&extBuf, extDataLen);
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("extension_data", extDataBuf.buf.start,
|
|
extDataLen);
|
|
# endif
|
|
|
|
|
|
switch (extensionType)
|
|
{
|
|
case EXT_SERVER_NAME:
|
|
rc = tls13ParseServerName(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
case EXT_EARLY_DATA:
|
|
psTracePrintExtensionParse(ssl, extensionType);
|
|
if (ssl->sec.tls13SelectedIdentityIndex != 0)
|
|
{
|
|
/* Spec 4.2.11: If selected identity is not 0 and server has
|
|
included EARLY_DATA extension then abort with
|
|
illegal_parameter alert */
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
if (ssl->tls13EarlyDataStatus == MATRIXSSL_EARLY_DATA_SENT)
|
|
{
|
|
ssl->tls13EarlyDataStatus = MATRIXSSL_EARLY_DATA_ACCEPTED;
|
|
}
|
|
ssl->extFlags.got_early_data = 1;
|
|
break;
|
|
|
|
default:
|
|
psTraceIntInfo("Ignoring unknown EE extension: %hu\n",
|
|
extensionType);
|
|
}
|
|
}
|
|
pb->buf.start = extBuf.buf.start;
|
|
if (ssl->extFlags.got_early_data == 0)
|
|
{
|
|
if (ssl->tls13EarlyDataStatus == MATRIXSSL_EARLY_DATA_SENT)
|
|
{
|
|
ssl->tls13EarlyDataStatus = MATRIXSSL_EARLY_DATA_REJECTED;
|
|
}
|
|
ssl->tls13ClientEarlyDataEnabled = PS_FALSE;
|
|
}
|
|
return MATRIXSSL_SUCCESS;
|
|
}
|
|
|
|
int32_t tls13ParseServerHelloExtensions(ssl_t *ssl,
|
|
psParseBuf_t *pb)
|
|
{
|
|
int32_t rc;
|
|
psSizeL_t vecDataLen, extDataLen;
|
|
uint16_t extensionType;
|
|
psParseBuf_t extBuf, extDataBuf;
|
|
psBool_t gotSupportedVersions = PS_FALSE;
|
|
psBool_t gotForbiddenExtension = PS_FALSE;
|
|
psBool_t gotKeyShare = PS_FALSE;
|
|
psBool_t gotPreSharedKey = PS_FALSE;
|
|
|
|
/* Minimum length is 0 for the vector here since this could still
|
|
be < TLS1.3 ServerHello which might not have extensions.
|
|
Extension extensions<0..2^16-1>; */
|
|
rc = psParseBufParseTlsVector(pb,
|
|
0, (1 << 16) - 1,
|
|
&vecDataLen);
|
|
if (rc <= 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
|
|
/*
|
|
Init sub buffer with the bytes of extensions<6..2^16-1>.
|
|
*/
|
|
(void)psParseBufFromStaticData(&extBuf,
|
|
pb->buf.start, vecDataLen);
|
|
|
|
while (psParseCanRead(&extBuf, 4))
|
|
{
|
|
/* ExtensionType extension_type; */
|
|
rc = psParseBufTryParseBigEndianUint16(&extBuf,
|
|
&extensionType);
|
|
if (rc != 2)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
|
|
/*
|
|
4.2. If the received extension is not specified for the message
|
|
in which it appears, we MUST abort the handshake with an
|
|
illegal_parameter alert.
|
|
|
|
However (!) this might actually be a TLS 1.2 ServerHello, for
|
|
which the set of allowed extensions is different. Store
|
|
the error, and let it take effect only after supported_versions
|
|
has been found and TLS 1.3 negotiated. We will drop to <1.3
|
|
code path if we could not negotiate 1.3.
|
|
*/
|
|
if (!tls13ExtensionAllowedInMessage(ssl,
|
|
extensionType,
|
|
SSL_HS_SERVER_HELLO))
|
|
{
|
|
gotForbiddenExtension = PS_TRUE;
|
|
}
|
|
|
|
/* opaque extension_data<0..2^16-1>;
|
|
Note: this will only consume the length octets from extBuf. */
|
|
rc = psParseBufParseTlsVector(&extBuf,
|
|
0, (1 << 16) - 1,
|
|
&extDataLen);
|
|
if (rc <= 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
(void)psParseBufFromStaticData(&extDataBuf,
|
|
extBuf.buf.start, extDataLen);
|
|
psParseTryForward(&extBuf, extDataLen);
|
|
# ifdef DEBUG_TLS_1_3_DECODE_EXTENSIONS
|
|
psTraceBytes("extension_data", extDataBuf.buf.start,
|
|
extDataLen);
|
|
# endif
|
|
|
|
switch (extensionType)
|
|
{
|
|
# ifndef USE_ONLY_PSK_CIPHER_SUITE
|
|
case EXT_KEY_SHARE_PRE_DRAFT_23:
|
|
case EXT_KEY_SHARE:
|
|
rc = tls13ParseServerKeyShare(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
gotKeyShare = PS_TRUE;
|
|
break;
|
|
# endif
|
|
case EXT_PRE_SHARED_KEY:
|
|
rc = tls13ParsePreSharedKey(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
gotPreSharedKey = PS_TRUE;
|
|
break;
|
|
case EXT_SUPPORTED_VERSIONS:
|
|
rc = tls13ParseServerSupportedVersions(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
gotSupportedVersions = PS_TRUE;
|
|
break;
|
|
case EXT_COOKIE:
|
|
rc = tls13ParseCookie(ssl, &extDataBuf);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
break;
|
|
default:
|
|
psTraceIntInfo("Unknown or forbidden ServerHello extension: %hu\n",
|
|
extensionType);
|
|
}
|
|
}
|
|
|
|
pb->buf.start = extBuf.buf.start;
|
|
|
|
if (!gotKeyShare)
|
|
{
|
|
ssl->sec.tls13ChosenPskMode = psk_keyex_mode_psk_ke;
|
|
}
|
|
|
|
if (!gotSupportedVersions)
|
|
{
|
|
ssl->hsState = SSL_HS_SERVER_HELLO;
|
|
return SSL_NO_TLS_1_3;
|
|
}
|
|
|
|
/* We should have negotiated 1.3 if we get here. */
|
|
psAssert(NGTD_VER(ssl, v_tls_1_3_any));
|
|
|
|
if (gotForbiddenExtension)
|
|
{
|
|
/* We delayed setting the alert until after we are sure TLS 1.3
|
|
has been negotiated. Now we can be sure that the 1.3 set of
|
|
allowed extensions must be enforced. Send the alert now. */
|
|
psTraceErrr("Error: forbidden extension in TLS 1.3 ServerHello\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
if (!gotKeyShare && !gotPreSharedKey)
|
|
{
|
|
psTraceErrr("Error: no key_share or pre_shared_key " \
|
|
"in TLS 1.3 ServerHello\n");
|
|
goto out_illegal_parameter;
|
|
}
|
|
|
|
if (ssl->tls13IncorrectDheKeyShare)
|
|
{
|
|
/* This was a HelloRetryRequest. Need to trigger sending of
|
|
ClientHello2. */
|
|
return SSL_ENCODE_RESPONSE;
|
|
}
|
|
else
|
|
{
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
out_decode_error:
|
|
ssl->err = SSL_ALERT_DECODE_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
out_illegal_parameter:
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
# endif
|