1095 lines
26 KiB
C
1095 lines
26 KiB
C
/**
|
|
* @file tls13KeyAgree.c
|
|
* @version $Format:%h%d$
|
|
*
|
|
* TLS 1.3 specific functions for key agreement.
|
|
*/
|
|
/*
|
|
* 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_KEY_AGREE
|
|
/* # define DEBUG_TLS_1_3_KEY_AGREE */
|
|
# endif
|
|
|
|
# ifdef USE_TLS_1_3
|
|
|
|
# ifdef USE_DH
|
|
# include "tls13DhGroups.h"
|
|
|
|
int32_t tls13LoadDhParams(ssl_t *ssl,
|
|
uint16_t namedGroup,
|
|
psDhParams_t *params)
|
|
{
|
|
int32_t rc;
|
|
const unsigned char *bin;
|
|
psSize_t binLen;
|
|
|
|
switch (namedGroup)
|
|
{
|
|
case namedgroup_ffdhe2048:
|
|
bin = ffdhe2048_params;
|
|
binLen = sizeof(ffdhe2048_params);
|
|
break;
|
|
case namedgroup_ffdhe3072:
|
|
bin = ffdhe3072_params;
|
|
binLen = sizeof(ffdhe3072_params);
|
|
break;
|
|
case namedgroup_ffdhe4096:
|
|
bin = ffdhe4096_params;
|
|
binLen = sizeof(ffdhe4096_params);
|
|
break;
|
|
default:
|
|
psTracePrintTls13NamedGroup(0,
|
|
"Unsupported DHE params",
|
|
namedGroup, PS_TRUE);
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
|
|
rc = psPkcs3ParseDhParamBin(ssl->hsPool,
|
|
bin,
|
|
binLen,
|
|
params);
|
|
if (rc < 0)
|
|
{
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return rc;
|
|
}
|
|
|
|
psTracePrintTls13NamedGroup(0,
|
|
"Loaded DHE params",
|
|
namedGroup, PS_TRUE);
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
# endif /* USE_DH */
|
|
|
|
# ifndef USE_ONLY_PSK_CIPHER_SUITE
|
|
int32_t tls13ImportPublicValue(ssl_t *ssl,
|
|
const unsigned char *keyExchangeData,
|
|
psSize_t keyExchangeDataLen,
|
|
uint16_t namedGroup)
|
|
{
|
|
int32_t rc;
|
|
|
|
if (psIsEcdheGroup(namedGroup))
|
|
{
|
|
if (namedGroup == namedgroup_x25519)
|
|
{
|
|
# ifdef USE_X25519
|
|
if (keyExchangeDataLen != PS_DH_X25519_PUBLIC_KEY_BYTES)
|
|
{
|
|
ssl->err = SSL_ALERT_ILLEGAL_PARAMETER;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
if (ssl->sec.x25519KeyPub != NULL)
|
|
{
|
|
psFree(ssl->sec.x25519KeyPub, ssl->sec.eccDhKeyPool);
|
|
}
|
|
ssl->sec.x25519KeyPub = psMalloc(ssl->sec.eccDhKeyPool,
|
|
PS_DH_X25519_PUBLIC_KEY_BYTES);
|
|
Memcpy(ssl->sec.x25519KeyPub,
|
|
keyExchangeData,
|
|
PS_DH_X25519_PUBLIC_KEY_BYTES);
|
|
return PS_SUCCESS;
|
|
# else
|
|
goto out_internal_error;
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
# ifdef USE_ECC
|
|
const psEccCurve_t *curve;
|
|
rc = getEccParamById(namedGroup, &curve);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
if (ssl->sec.eccKeyPub != NULL)
|
|
{
|
|
psEccClearKey(ssl->sec.eccKeyPub);
|
|
}
|
|
|
|
rc = psEccNewKey(ssl->hsPool, &ssl->sec.eccKeyPub, curve);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Unable to create new EC key\n");
|
|
goto out_internal_error;
|
|
}
|
|
|
|
rc = psEccX963ImportKey(
|
|
ssl->hsPool,
|
|
keyExchangeData,
|
|
keyExchangeDataLen,
|
|
ssl->sec.eccKeyPub,
|
|
curve);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Could not import peer ECDHE public value\n");
|
|
goto out_handshake_failure;
|
|
}
|
|
# ifdef DEBUG_TLS_1_3_KEY_AGREE
|
|
psTraceIntInfo("Imported ECDHE pub val of length %d\n",
|
|
keyExchangeDataLen);
|
|
# endif
|
|
# else
|
|
goto out_internal_error;
|
|
# endif /* USE_ECC */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# ifndef USE_DH
|
|
psTraceInfo("Need USE_DH to be able to import DHE public values\n");
|
|
goto out_internal_error;
|
|
# else
|
|
ssl->sec.dhKeyPub = psMalloc(ssl->hsPool,
|
|
sizeof(psDhKey_t));
|
|
if (ssl->sec.dhKeyPub == NULL)
|
|
{
|
|
return PS_MEM_FAIL;
|
|
}
|
|
rc = psDhImportPubKey(ssl->hsPool,
|
|
keyExchangeData,
|
|
keyExchangeDataLen,
|
|
ssl->sec.dhKeyPub);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Could not import peer DHE public value\n");
|
|
goto out_handshake_failure;
|
|
}
|
|
# ifdef DEBUG_TLS_1_3_KEY_AGREE
|
|
psTraceIntInfo("Imported DHE pub val of length %d\n",
|
|
keyExchangeDataLen);
|
|
# endif
|
|
# endif /* USE_DH */
|
|
}
|
|
|
|
return MATRIXSSL_SUCCESS;
|
|
|
|
out_handshake_failure:
|
|
ssl->err = SSL_ALERT_HANDSHAKE_FAILURE;
|
|
return MATRIXSSL_ERROR;
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
int32_t tls13ExportPublicValue(ssl_t *ssl,
|
|
uint16_t namedGroup,
|
|
psPubKey_t *key,
|
|
unsigned char **out,
|
|
psSize_t *outLen)
|
|
{
|
|
int32_t rc;
|
|
psSize_t pubValLen;
|
|
unsigned char *pubVal;
|
|
|
|
if (psIsEcdheGroup(namedGroup))
|
|
{
|
|
if (namedGroup == namedgroup_x25519)
|
|
{
|
|
# ifdef USE_X25519
|
|
pubVal = psMalloc(ssl->hsPool,
|
|
PS_DH_X25519_PUBLIC_KEY_BYTES);
|
|
if (pubVal == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
Memcpy(pubVal,
|
|
key->key.x25519.pub,
|
|
PS_DH_X25519_PUBLIC_KEY_BYTES);
|
|
pubValLen = PS_DH_X25519_PUBLIC_KEY_BYTES;
|
|
# else
|
|
goto out_internal_error;
|
|
# endif /* USE_X25519 */
|
|
}
|
|
else
|
|
{
|
|
# ifdef USE_ECC
|
|
pubValLen = key->key.ecc.curve->size*2 + 1;
|
|
pubVal = psMalloc(ssl->hsPool, pubValLen);
|
|
if (pubVal == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
rc = psEccX963ExportKey(ssl->hsPool,
|
|
&key->key.ecc,
|
|
pubVal,
|
|
&pubValLen);
|
|
if (rc < 0)
|
|
{
|
|
psFree(pubVal, ssl->hsPool);
|
|
goto out_internal_error;
|
|
}
|
|
# ifdef DEBUG_TLS_1_3_KEY_AGREE
|
|
psTraceIntInfo("Exported ECDHE pub val of length %d\n",
|
|
pubValLen);
|
|
# endif
|
|
# else
|
|
goto out_internal_error;
|
|
# endif /* USE_ECC */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
# ifndef USE_DH
|
|
psTraceInfo("Need USE_DH to export DHE pub values\n");
|
|
goto out_internal_error;
|
|
# else
|
|
pubValLen = key->key.dh.size;
|
|
pubVal = psMalloc(ssl->hsPool, pubValLen);
|
|
if (pubVal == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
rc = psDhExportPubKey(ssl->hsPool,
|
|
&key->key.dh,
|
|
pubVal,
|
|
&pubValLen);
|
|
if (rc < 0)
|
|
{
|
|
psFree(pubVal, ssl->hsPool);
|
|
goto out_internal_error;
|
|
}
|
|
# endif /* USE_DH */
|
|
}
|
|
*out = pubVal;
|
|
*outLen = pubValLen;
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
|
|
# ifdef USE_ECC
|
|
/** Generate an ECDHE private key given the curve NamedGroup id. */
|
|
int32_t tls13GenerateEcdheKey(ssl_t *ssl,
|
|
psEccKey_t *key,
|
|
uint16_t namedGroup)
|
|
{
|
|
int32_t rc;
|
|
void *pkiData = ssl->userPtr;
|
|
const psEccCurve_t *curve;
|
|
|
|
psTraceInfo("Generating new ECDHE private key\n");
|
|
|
|
rc = getEccParamById(namedGroup,
|
|
&curve);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = psEccInitKey(ssl->hsPool, key, curve);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = matrixSslGenEphemeralEcKey(ssl->keys,
|
|
key,
|
|
curve,
|
|
pkiData);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
psTraceStrInfo("Generated new ECDHE key on curve: %s\n",
|
|
key->curve->name);
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
# endif /* USE_ECC */
|
|
|
|
static
|
|
int32_t tls13GenerateKeyForGroup(ssl_t *ssl, uint16_t namedGroup)
|
|
{
|
|
psSize_t i;
|
|
int32_t rc;
|
|
|
|
psAssert(psIsGroupSupported(namedGroup));
|
|
|
|
# ifdef DEBUG_TLS_1_3_KEY_AGREE
|
|
psTracePrintTls13NamedGroup(0,
|
|
"Generating key for group",
|
|
namedGroup,
|
|
PS_TRUE);
|
|
# endif
|
|
|
|
/* Find the correct spot. */
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
if (ssl->tls13SupportedGroups[i] == namedGroup)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if (i == TLS_1_3_MAX_GROUPS)
|
|
{
|
|
psTraceIntInfo("Unsupported group: %d\n", (int)namedGroup);
|
|
goto out_internal_error;
|
|
}
|
|
|
|
/* We might be in the middle of a resumed flight creation,
|
|
where we have to encode the same message again after
|
|
buffer reallocation. Do not re-generate in that case. */
|
|
if (ssl->sec.tls13KeyAgreeKeys[i] != NULL)
|
|
{
|
|
# ifdef DEBUG_TLS_1_3_KEY_AGREE
|
|
psTraceInfo("Already generated.\n");
|
|
# endif
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
/* Generate the ephemeral key pair. */
|
|
if (psIsEcdheGroup(namedGroup))
|
|
{
|
|
# if defined(USE_ECC) || defined(USE_X25519)
|
|
psPubKey_t *key;
|
|
uint8_t keyType;
|
|
|
|
if (namedGroup == namedgroup_x25519)
|
|
{
|
|
keyType = PS_X25519;
|
|
}
|
|
else
|
|
{
|
|
keyType = PS_ECC;
|
|
}
|
|
|
|
rc = psNewPubKey(ssl->hsPool,
|
|
keyType,
|
|
&ssl->sec.tls13KeyAgreeKeys[i]);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
key = ssl->sec.tls13KeyAgreeKeys[i];
|
|
|
|
# ifdef USE_X25519
|
|
if (namedGroup == namedgroup_x25519)
|
|
{
|
|
psRes_t res;
|
|
|
|
res = psDhX25519GenKey(key->key.x25519.priv,
|
|
key->key.x25519.pub);
|
|
if (res < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
return PS_SUCCESS;
|
|
}
|
|
# endif /* USE_X25519 */
|
|
|
|
rc = tls13GenerateEcdheKey(ssl,
|
|
&key->key.ecc,
|
|
namedGroup);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
# else
|
|
goto out_internal_error;
|
|
# endif
|
|
}
|
|
else
|
|
{
|
|
# ifndef USE_DH
|
|
psTraceErrr("Need USE_DH for ffdhe* group support\n");
|
|
goto out_internal_error;
|
|
# else
|
|
rc = psNewPubKey(ssl->hsPool,
|
|
PS_DH,
|
|
&ssl->sec.tls13KeyAgreeKeys[i]);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
/* Ignore whatever DH params the user may have loaded for TLS 1.2. */
|
|
if (ssl->keys->dhParams.size != 0)
|
|
{
|
|
psPkcs3ClearDhParams(&ssl->keys->dhParams);
|
|
}
|
|
|
|
rc = tls13LoadDhParams(ssl,
|
|
namedGroup,
|
|
&ssl->keys->dhParams);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
|
|
rc = psDhGenKeyParams(ssl->hsPool,
|
|
&ssl->keys->dhParams,
|
|
&ssl->sec.tls13KeyAgreeKeys[i]->key.dh,
|
|
NULL);
|
|
if (rc < 0)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
# endif /* !USE_DH */
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_internal_error:
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
#endif /* USE_ONLY_PSK_CIPHER_SUITE */
|
|
|
|
/** Return the element with the lowest sum of indexes from the
|
|
intersection of two priority-ordered arrays a and b, such that
|
|
the element does not belong to the forbidden element list f.
|
|
Return error when the intersection is empty or all elements
|
|
in the intersection belong to f. If the intersection has two
|
|
elements with the same index sum, return the latter element.
|
|
|
|
Precondition: The input arrays must be arranged in priority
|
|
order such that the highest-priority item is at index 0.
|
|
*/
|
|
int32_t tls13IntersectionPrioritySelect(const uint32_t *a,
|
|
psSize_t aLen,
|
|
const uint32_t *b,
|
|
psSize_t bLen,
|
|
const uint32_t *f,
|
|
psSize_t fLen,
|
|
uint32_t *selectedElement)
|
|
{
|
|
psSize_t sum, minSum;
|
|
uint32_t best;
|
|
psSize_t i, k, l;
|
|
psBool_t foundCommon = PS_FALSE;
|
|
psBool_t forbidden;
|
|
|
|
if (aLen == 0 || bLen == 0)
|
|
{
|
|
/* Empty intersection. */
|
|
return PS_ARG_FAIL;
|
|
}
|
|
|
|
best = a[0];
|
|
minSum = aLen + bLen - 2;
|
|
|
|
for (i = 0; i < aLen; i++)
|
|
{
|
|
for (k = 0; k < bLen; k++)
|
|
{
|
|
if (a[i] == b[k])
|
|
{
|
|
forbidden = PS_FALSE;
|
|
if (f != NULL)
|
|
{
|
|
for (l = 0; l < fLen; l++)
|
|
{
|
|
if (a[i] == f[l])
|
|
{
|
|
forbidden = PS_TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!forbidden)
|
|
{
|
|
sum = i + k;
|
|
if (sum <= minSum)
|
|
{
|
|
minSum = sum;
|
|
best = a[i];
|
|
foundCommon = PS_TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (foundCommon)
|
|
{
|
|
if (selectedElement != NULL)
|
|
{
|
|
*selectedElement = best;
|
|
}
|
|
return PS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Empty intersection. */
|
|
return PS_ARG_FAIL;
|
|
}
|
|
}
|
|
|
|
/* An uint16_t wrapper for tls13IntersectionPrioritySelect.*/
|
|
int32_t tls13IntersectionPrioritySelectU16(const uint16_t *a,
|
|
psSize_t aLen,
|
|
const uint16_t *b,
|
|
psSize_t bLen,
|
|
const uint16_t *f,
|
|
psSize_t fLen,
|
|
uint16_t *selectedElement)
|
|
{
|
|
uint32_t selectedElement32 = *selectedElement;
|
|
uint32_t *a32 = NULL;
|
|
uint32_t *b32 = NULL;
|
|
uint32_t *f32 = NULL;
|
|
int32_t rc = PS_ARG_FAIL;
|
|
psSize_t i;
|
|
|
|
a32 = psMalloc(ssl->hsPool, aLen * sizeof(uint32_t));
|
|
if (a32 == NULL)
|
|
{
|
|
psTraceInfo("Out of mem in tls13NegotiateGroup\n");
|
|
goto out;
|
|
}
|
|
b32 = psMalloc(ssl->hsPool, bLen * sizeof(uint32_t));
|
|
if (b32 == NULL)
|
|
{
|
|
psTraceInfo("Out of mem in tls13NegotiateGroup\n");
|
|
goto out;
|
|
}
|
|
f32 = psMalloc(ssl->hsPool, bLen * sizeof(uint32_t));
|
|
if (f32 == NULL)
|
|
{
|
|
psTraceInfo("Out of mem in tls13NegotiateGroup\n");
|
|
goto out;
|
|
}
|
|
for (i = 0; i < aLen; i++)
|
|
{
|
|
a32[i] = a[i];
|
|
}
|
|
for (i = 0; i < bLen; i++)
|
|
{
|
|
b32[i] = b[i];
|
|
}
|
|
for (i = 0; i < fLen; i++)
|
|
{
|
|
f32[i] = f[i];
|
|
}
|
|
|
|
rc = tls13IntersectionPrioritySelect(a32,
|
|
aLen,
|
|
b32,
|
|
bLen,
|
|
f32,
|
|
fLen,
|
|
&selectedElement32);
|
|
|
|
*selectedElement = selectedElement32;
|
|
|
|
out:
|
|
psFree(a32, ssl->hsPool);
|
|
psFree(b32, ssl->hsPool);
|
|
psFree(f32, ssl->hsPool);
|
|
|
|
return rc;
|
|
}
|
|
|
|
/** Given our and the peer's list of supported groups, negotiate
|
|
the group to use, taking into account our and the peer's
|
|
priorities. */
|
|
uint16_t tls13NegotiateGroup(ssl_t *ssl,
|
|
uint16_t *peerList,
|
|
psSize_t peerListLen)
|
|
{
|
|
uint16_t negotiatedGroup;
|
|
int32_t rc;
|
|
|
|
# ifdef USE_SM2
|
|
if (ssl->tls13SelectedSMSuite == PS_TRUE)
|
|
{
|
|
return namedgroup_curveSM2;
|
|
}
|
|
# endif
|
|
|
|
psAssert(ssl->tls13SupportedGroups[0] != 0);
|
|
|
|
/* Default. If anything goes wrong, use this. */
|
|
negotiatedGroup = ssl->tls13SupportedGroups[0];
|
|
|
|
rc = tls13IntersectionPrioritySelectU16(ssl->tls13SupportedGroups,
|
|
ssl->tls13SupportedGroupsLen,
|
|
peerList,
|
|
peerListLen,
|
|
NULL,
|
|
0,
|
|
&negotiatedGroup);
|
|
if (rc == PS_ARG_FAIL)
|
|
{
|
|
psTraceInfo("tls13IntersectionPrioritySelect failed\n");
|
|
}
|
|
|
|
return negotiatedGroup;
|
|
}
|
|
|
|
int32_t tls13ServerChooseGroup(ssl_t *ssl,
|
|
uint16_t *chosenGroup)
|
|
{
|
|
uint16_t group;
|
|
|
|
group = tls13NegotiateGroup(ssl,
|
|
ssl->tls13PeerKeyShareGroups,
|
|
ssl->tls13PeerKeyShareGroupsLen);
|
|
|
|
*chosenGroup = group;
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
int32_t tls13ServerChooseHelloRetryRequestGroup(ssl_t *ssl,
|
|
uint16_t *chosenGroup)
|
|
{
|
|
uint16_t group;
|
|
|
|
group = tls13NegotiateGroup(ssl,
|
|
ssl->tls13PeerSupportedGroups,
|
|
ssl->tls13PeerSupportedGroupsLen);
|
|
|
|
psTraceInfo("Added key_share to HelloRetryRequest:\n");
|
|
psTracePrintTls13NamedGroup(0, NULL, group, PS_TRUE);
|
|
|
|
*chosenGroup = group;
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
# ifndef USE_ONLY_PSK_CIPHER_SUITE
|
|
int32_t tls13GenerateEphemeralKeys(ssl_t *ssl)
|
|
{
|
|
psSize_t i;
|
|
psSize_t numKeys;
|
|
uint16_t group;
|
|
int32_t rc;
|
|
|
|
if (MATRIX_IS_SERVER(ssl))
|
|
{
|
|
group = ssl->tls13NegotiatedGroup;
|
|
rc = tls13GenerateKeyForGroup(ssl, group);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
return PS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
numKeys = ssl->tls13NumClientHelloKeyShares;
|
|
}
|
|
|
|
/*
|
|
If we are the client, we shall use our supported groups list
|
|
and generate shares for the TOP-numKeys groups in that list.
|
|
*/
|
|
|
|
if (ssl->sec.tls13KsState.generateEcdheKeyDone == 0)
|
|
{
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
/* We shall generate numKeys keys. */
|
|
if (i < numKeys)
|
|
{
|
|
group = ssl->tls13SupportedGroups[i];
|
|
rc = tls13GenerateKeyForGroup(ssl, group);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ssl->sec.tls13KeyAgreeKeys[i] = NULL;
|
|
}
|
|
}
|
|
ssl->sec.tls13KsState.generateEcdheKeyDone = 1;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
# endif
|
|
|
|
|
|
# ifdef USE_ECC
|
|
static inline
|
|
int32_t tls13GenSharedSecretNist(ssl_t *ssl,
|
|
psPubKey_t *privKey,
|
|
unsigned char **secretOut,
|
|
psSize_t *secretOutLen)
|
|
{
|
|
unsigned char *secret = NULL;
|
|
psSize_t secretLen;
|
|
int32_t rc;
|
|
|
|
psAssert(privKey->type == PS_ECC);
|
|
psAssert(ssl->sec.eccKeyPub != NULL);
|
|
|
|
if (privKey->key.ecc.curve != ssl->sec.eccKeyPub->curve)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
secretLen = privKey->key.ecc.curve->size;
|
|
|
|
secret = psMalloc(ssl->eccDhKeyPool, secretLen);
|
|
if (secret == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
/* Generate ECDHE shared secret. */
|
|
rc = psEccGenSharedSecret(ssl->sec.eccDhKeyPool,
|
|
&privKey->key.ecc,
|
|
ssl->sec.eccKeyPub,
|
|
secret,
|
|
&secretLen,
|
|
NULL);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Failed to generate ECDHE shared secret\n");
|
|
goto out_internal_error;
|
|
}
|
|
|
|
*secretOut = secret;
|
|
*secretOutLen = secretLen;
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_internal_error:
|
|
if (secret != NULL)
|
|
{
|
|
psFree(secret, ssl->hsPool);
|
|
}
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
# endif /* USE_ECC */
|
|
# ifdef USE_X25519
|
|
static inline
|
|
int32_t tls13GenSharedSecretX25519(ssl_t *ssl,
|
|
psPubKey_t *privKey,
|
|
unsigned char **secretOut,
|
|
psSize_t *secretOutLen)
|
|
{
|
|
unsigned char *secret = NULL;
|
|
psSize_t secretLen;
|
|
psRes_t res;
|
|
|
|
psAssert(privKey->type == PS_X25519);
|
|
psAssert(ssl->sec.x25519KeyPub != NULL);
|
|
|
|
secretLen = PS_DH_X25519_PUBLIC_KEY_BYTES;
|
|
secret = psMalloc(ssl->eccDhKeyPool, secretLen);
|
|
if (secret == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
res = psDhX25519GenSharedSecret(ssl->sec.x25519KeyPub,
|
|
privKey->key.x25519.priv,
|
|
secret);
|
|
if (res != PS_SUCCESS)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
*secretOut = secret;
|
|
*secretOutLen = secretLen;
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_internal_error:
|
|
if (secret != NULL)
|
|
{
|
|
psFree(secret, ssl->hsPool);
|
|
}
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
# endif /* USE_X25519 */
|
|
|
|
# ifdef USE_DH
|
|
static inline
|
|
int32_t tls13GenSharedSecretDh(ssl_t *ssl,
|
|
psPubKey_t *privKey,
|
|
unsigned char **secretOut,
|
|
psSize_t *secretOutLen)
|
|
{
|
|
unsigned char *secret = NULL;
|
|
psSize_t secretLen;
|
|
psSize_t padLen;
|
|
int32_t rc;
|
|
|
|
psAssert(privKey->type == PS_DH);
|
|
psAssert(ssl->sec.dhKeyPub != NULL);
|
|
|
|
/* psDhGenSharedSecret wants the params as byte arrays.*/
|
|
rc = psDhExportParameters(ssl->hsPool,
|
|
&ssl->keys->dhParams,
|
|
&ssl->sec.dhP,
|
|
&ssl->sec.dhPLen,
|
|
&ssl->sec.dhG,
|
|
&ssl->sec.dhGLen);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("psDhExportParameters failed\n");
|
|
goto out_internal_error;
|
|
}
|
|
|
|
secret = psMalloc(ssl->hsPool, privKey->key.dh.size);
|
|
if (secret == NULL)
|
|
{
|
|
goto out_internal_error;
|
|
}
|
|
|
|
secretLen = privKey->key.dh.size;
|
|
|
|
rc = psDhGenSharedSecret(ssl->hsPool,
|
|
&privKey->key.dh,
|
|
ssl->sec.dhKeyPub,
|
|
ssl->sec.dhP,
|
|
ssl->sec.dhPLen,
|
|
secret,
|
|
&secretLen,
|
|
NULL);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Failed to generate DHE shared secret\n");
|
|
/* The psDhGenSharedSecret return value is not specific enough
|
|
to know what went wrong. If the 2 <= x < p-1 check failed,
|
|
we should probably send illegal_parameter or insufficient
|
|
security. For now, just map all failures to internal_error
|
|
alerts. */
|
|
goto out_internal_error;
|
|
}
|
|
|
|
psAssert(secretLen <= privKey->key.dh.size);
|
|
psAssert(secretLen >= 1);
|
|
|
|
/*
|
|
psDhGenSharedSecret removes leading zero octets from the secret.
|
|
However, TLS 1.3 requires that the secret must be of the same
|
|
size as the prime. Reinsert leading zeros here, if needed.
|
|
*/
|
|
padLen = privKey->key.dh.size - secretLen;
|
|
if (padLen > 0)
|
|
{
|
|
Memmove(secret + padLen,
|
|
secret,
|
|
secretLen);
|
|
Memset(secret, 0, padLen);
|
|
psTraceIntInfo("Readded %u leading zeros\n", padLen);
|
|
secretLen = privKey->key.dh.size;
|
|
}
|
|
|
|
*secretOut = secret;
|
|
*secretOutLen = secretLen;
|
|
|
|
return PS_SUCCESS;
|
|
|
|
out_internal_error:
|
|
if (secret != NULL)
|
|
{
|
|
psFree(secret, ssl->hsPool);
|
|
}
|
|
ssl->err = SSL_ALERT_INTERNAL_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
# endif /* USE_DH */
|
|
|
|
/** Generate shared secret.
|
|
|
|
Allocates memory for the secret. Caller must free.
|
|
|
|
Preconditions:
|
|
- Private key (ssl->sec.eccKeyPriv) must exist.
|
|
- Peer public value (ssl->sec.eccKeyPub) must exist.
|
|
*/
|
|
int32_t tls13GenSharedSecret(ssl_t *ssl,
|
|
unsigned char **out,
|
|
psSize_t *outLen)
|
|
{
|
|
psSize_t secretLen = 0;
|
|
unsigned char *secret = NULL;
|
|
psPubKey_t *privKey;
|
|
int32_t rc;
|
|
|
|
privKey = tls13GetGroupKey(ssl, ssl->tls13NegotiatedGroup);
|
|
psAssert(privKey != NULL);
|
|
|
|
switch (privKey->type)
|
|
{
|
|
# ifdef USE_ECC
|
|
case PS_ECC:
|
|
rc = tls13GenSharedSecretNist(ssl, privKey, &secret, &secretLen);
|
|
break;
|
|
#endif
|
|
# ifdef USE_X25519
|
|
case PS_X25519:
|
|
rc = tls13GenSharedSecretX25519(ssl, privKey, &secret, &secretLen);
|
|
break;
|
|
# endif
|
|
# ifdef USE_DH
|
|
case PS_DH:
|
|
rc = tls13GenSharedSecretDh(ssl, privKey, &secret, &secretLen);
|
|
break;
|
|
# endif
|
|
default:
|
|
rc = PS_UNSUPPORTED_FAIL;
|
|
break;
|
|
}
|
|
|
|
if (rc == PS_SUCCESS)
|
|
{
|
|
# ifdef DEBUG_TLS_1_3_KEY_AGREE
|
|
psTraceBytes("(EC)DHE shared secret", secret, secretLen);
|
|
# endif
|
|
|
|
*out = secret;
|
|
*outLen = secretLen;
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
/** Return the key corresponding to a NamedGroup.
|
|
Return NULL if we do not support the group.
|
|
*/
|
|
psPubKey_t *tls13GetGroupKey(ssl_t *ssl,
|
|
uint16_t namedGroup)
|
|
{
|
|
psSize_t i;
|
|
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
if (ssl->tls13SupportedGroups[i] == namedGroup &&
|
|
ssl->sec.tls13KeyAgreeKeys[i] != NULL)
|
|
{
|
|
return ssl->sec.tls13KeyAgreeKeys[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
int32_t tls13AddPeerSupportedGroup(ssl_t *ssl,
|
|
uint16_t namedGroup)
|
|
{
|
|
psSize_t i;
|
|
|
|
/* Find free spot. */
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
if (ssl->tls13PeerSupportedGroups[i] == 0)
|
|
{
|
|
ssl->tls13PeerSupportedGroups[i] = namedGroup;
|
|
ssl->tls13PeerSupportedGroupsLen++;
|
|
return PS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return PS_FAILURE;
|
|
}
|
|
|
|
void tls13ClearPeerSupportedGroupList(ssl_t *ssl)
|
|
{
|
|
psSize_t i;
|
|
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
ssl->tls13PeerSupportedGroups[i] = 0;
|
|
}
|
|
|
|
ssl->tls13PeerSupportedGroupsLen = 0;
|
|
}
|
|
|
|
int32_t tls13AddPeerKeyShareGroup(ssl_t *ssl,
|
|
uint16_t namedGroup)
|
|
{
|
|
psSize_t i;
|
|
|
|
/* Find free spot. */
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
if (ssl->tls13PeerKeyShareGroups[i] == 0)
|
|
{
|
|
ssl->tls13PeerKeyShareGroups[i] = namedGroup;
|
|
ssl->tls13PeerKeyShareGroupsLen++;
|
|
return PS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
return PS_FAILURE;
|
|
}
|
|
|
|
psBool_t tls13WeSupportGroup(ssl_t *ssl,
|
|
uint16_t namedGroup)
|
|
{
|
|
psSize_t i;
|
|
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
if (ssl->tls13SupportedGroups[i] == namedGroup)
|
|
{
|
|
#ifdef USE_SM2
|
|
if (ssl->tls13SelectedSMSuite == PS_TRUE &&
|
|
namedGroup != namedgroup_curveSM2)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
#endif
|
|
return PS_TRUE;
|
|
}
|
|
}
|
|
|
|
return PS_FALSE;
|
|
}
|
|
|
|
psBool_t tls13PeerSupportsGroup(ssl_t *ssl,
|
|
uint16_t namedGroup)
|
|
{
|
|
psSize_t i;
|
|
|
|
/* Find it. */
|
|
for (i = 0; i < TLS_1_3_MAX_GROUPS; i++)
|
|
{
|
|
if (ssl->tls13PeerSupportedGroups[i] == namedGroup)
|
|
{
|
|
return PS_TRUE;
|
|
}
|
|
}
|
|
|
|
return PS_FALSE;
|
|
}
|
|
|
|
# endif /* USE_TLS_1_3 */
|