1606 lines
43 KiB
C
1606 lines
43 KiB
C
/**
|
|
* @file tlsSigVer.c
|
|
* @version $Format:%h%d$
|
|
*
|
|
* Functions for signature generation and verification for TLS 1.2
|
|
* and below.
|
|
*/
|
|
/*
|
|
* Copyright (c) 2013-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 USE_TLS_1_3_ONLY
|
|
|
|
# ifndef USE_ONLY_PSK_CIPHER_SUITE
|
|
|
|
# ifdef USE_ROT_CRYPTO
|
|
# include "../crypto-rot/rotCommon.h"
|
|
# endif
|
|
|
|
# ifndef DEBUG_TLS_SIG_VER
|
|
/*# define DEBUG_TLS_SIG_VER*/
|
|
# endif
|
|
|
|
uint32_t getDefaultSkeHashSize(ssl_t *ssl)
|
|
{
|
|
uint32_t hashSize;
|
|
|
|
hashSize = MD5SHA1_HASH_SIZE; /* Default for (D)TLS <1.2. */
|
|
# ifdef USE_ECC_CIPHER_SUITE
|
|
if (ssl->flags & SSL_FLAGS_DHE_WITH_DSA)
|
|
{
|
|
/* RFC 4492: SHA-1 is the default. */
|
|
hashSize = SHA1_HASH_SIZE;
|
|
}
|
|
# endif /* USE_ECC_CIPHER_SUITE */
|
|
|
|
return hashSize;
|
|
}
|
|
|
|
int32_t computeSkeHash(ssl_t *ssl,
|
|
psDigestContext_t *digestCtx,
|
|
uint32_t hashSize,
|
|
const unsigned char *tbsStart, /* Start of ServerParams. */
|
|
const unsigned char *tbsStop,
|
|
unsigned char *hsMsgHash)
|
|
{
|
|
/*
|
|
In both TLS 1.2 and below, the SKE signature is computed
|
|
over the hash of:
|
|
ClientHello.random || ServerHello.random || ServerParams
|
|
|
|
Unfortunately, we cannot use psComputeHashForSig, since
|
|
it only supports single part operation - we would have to
|
|
concatenate the above data into a single buffer, something
|
|
which we are not willing to do here.
|
|
*/
|
|
switch (hashSize)
|
|
{
|
|
# ifdef USE_MD5SHA1
|
|
case MD5SHA1_HASH_SIZE:
|
|
psMd5Sha1PreInit(&digestCtx->u.md5sha1);
|
|
psMd5Sha1Init(&digestCtx->u.md5sha1);
|
|
psMd5Sha1Update(&digestCtx->u.md5sha1, ssl->sec.clientRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psMd5Sha1Update(&digestCtx->u.md5sha1, ssl->sec.serverRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psMd5Sha1Update(&digestCtx->u.md5sha1, tbsStart,
|
|
(uint32) (tbsStop - tbsStart));
|
|
psMd5Sha1Final(&digestCtx->u.md5sha1, hsMsgHash);
|
|
break;
|
|
# endif /* USE_MD5SHA1 */
|
|
# ifdef USE_SHA1
|
|
case SHA1_HASH_SIZE:
|
|
psSha1PreInit(&digestCtx->u.sha1);
|
|
psSha1Init(&digestCtx->u.sha1);
|
|
psSha1Update(&digestCtx->u.sha1, ssl->sec.clientRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha1Update(&digestCtx->u.sha1, ssl->sec.serverRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha1Update(&digestCtx->u.sha1, tbsStart,
|
|
(uint32) (tbsStop - tbsStart));
|
|
psSha1Final(&digestCtx->u.sha1, hsMsgHash);
|
|
break;
|
|
# endif /* USE_SHA1 */
|
|
# ifdef USE_TLS_1_2
|
|
case SHA256_HASH_SIZE:
|
|
psSha256PreInit(&digestCtx->u.sha256);
|
|
psSha256Init(&digestCtx->u.sha256);
|
|
psSha256Update(&digestCtx->u.sha256, ssl->sec.clientRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha256Update(&digestCtx->u.sha256, ssl->sec.serverRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha256Update(&digestCtx->u.sha256, tbsStart,
|
|
(uint32) (tbsStop - tbsStart));
|
|
psSha256Final(&digestCtx->u.sha256, hsMsgHash);
|
|
break;
|
|
# ifdef USE_SHA384
|
|
case SHA384_HASH_SIZE:
|
|
psSha384PreInit(&digestCtx->u.sha384);
|
|
psSha384Init(&digestCtx->u.sha384);
|
|
psSha384Update(&digestCtx->u.sha384, ssl->sec.clientRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha384Update(&digestCtx->u.sha384, ssl->sec.serverRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha384Update(&digestCtx->u.sha384, tbsStart,
|
|
(uint32) (tbsStop - tbsStart));
|
|
psSha384Final(&digestCtx->u.sha384, hsMsgHash);
|
|
break;
|
|
# endif /* USE_SHA384 */
|
|
# ifdef USE_SHA512
|
|
case SHA512_HASH_SIZE:
|
|
psSha512PreInit(&digestCtx->u.sha512);
|
|
psSha512Init(&digestCtx->u.sha512);
|
|
psSha512Update(&digestCtx->u.sha512, ssl->sec.clientRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha512Update(&digestCtx->u.sha512, ssl->sec.serverRandom,
|
|
SSL_HS_RANDOM_SIZE);
|
|
psSha512Update(&digestCtx->u.sha512, tbsStart,
|
|
(uint32) (tbsStop - tbsStart));
|
|
psSha512Final(&digestCtx->u.sha512, hsMsgHash);
|
|
break;
|
|
# endif /* USE_SHA512 */
|
|
# endif /* USE_TLS_1_2 */
|
|
default:
|
|
psTraceErrr("Unsupported hash algorithm in SKE\n");
|
|
psTraceIntInfo("Unsupported hash size: %u\n", hashSize);
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
psRes_t computeSkeTbs(ssl_t *ssl,
|
|
const unsigned char *tbsStart,
|
|
const unsigned char *tbsStop,
|
|
unsigned char **out,
|
|
psSizeL_t *outLen)
|
|
{
|
|
unsigned char *tbs;
|
|
psSize_t tbsLen;
|
|
|
|
/*
|
|
TBS length is 2x32 bytes for client_random || server_random
|
|
plus the size of signed_params.
|
|
*/
|
|
tbsLen = 64 + (tbsStop - tbsStart);
|
|
tbs = psMalloc(ssl->hsPool, tbsLen);
|
|
if (tbs == NULL)
|
|
{
|
|
return PS_MEM_FAIL;
|
|
}
|
|
|
|
Memcpy(tbs, ssl->sec.clientRandom, 32);
|
|
Memcpy(tbs + 32, ssl->sec.serverRandom, 32);
|
|
Memcpy(tbs + 64, tbsStart, tbsStop - tbsStart);
|
|
|
|
# ifdef DEBUG_TLS_SIG_VER
|
|
psTraceBytes("computeSkeTbs", tbs, tbsLen);
|
|
# endif
|
|
|
|
*out = tbs;
|
|
*outLen = tbsLen;
|
|
|
|
return PS_SUCCESS;
|
|
}
|
|
|
|
# ifdef USE_IDENTITY_CERTIFICATES
|
|
static inline
|
|
int32_t chooseSkeSigAlgTls12(ssl_t *ssl, sslIdentity_t *id)
|
|
{
|
|
int32_t sigAlg;
|
|
uint16_t sigAlgMask;
|
|
|
|
if (MATRIX_IS_CLIENT(ssl))
|
|
{
|
|
/* The client will always receive the servers sigalg
|
|
list in CertificateRequest. */
|
|
sigAlgMask = ssl->peerSigAlg;
|
|
}
|
|
else
|
|
{
|
|
if (ssl->peerSigAlg != 0)
|
|
{
|
|
/* Got signature_algorithms in ClientHello. */
|
|
sigAlgMask = ssl->peerSigAlg;
|
|
}
|
|
else
|
|
{
|
|
/* No signature_algorithms received, use the "shared"
|
|
list, which in this case is equal to our list. */
|
|
sigAlgMask = ssl->hashSigAlg;
|
|
}
|
|
}
|
|
|
|
sigAlg = chooseSigAlg(id->cert, &id->privKey, sigAlgMask);
|
|
if (sigAlg == PS_UNSUPPORTED_FAIL)
|
|
{
|
|
psTraceInfo("Unavailable sigAlgorithm for SKE write\n");
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
return sigAlg;
|
|
}
|
|
|
|
static inline
|
|
int32_t chooseSkeSigAlgTls11(ssl_t *ssl, sslIdentity_t *id)
|
|
{
|
|
if (id->privKey.type == PS_RSA)
|
|
{
|
|
return 0; /* MD5SHA1-RSA does not have an OID, so use 0. */
|
|
}
|
|
else
|
|
{
|
|
/* ECDSA uses SHA-1 by default. */
|
|
return OID_SHA1_ECDSA_SIG;
|
|
}
|
|
}
|
|
|
|
int32_t chooseSkeSigAlg(ssl_t *ssl, sslIdentity_t *id)
|
|
{
|
|
# ifdef USE_TLS_1_2
|
|
if (NGTD_VER(ssl, v_tls_with_signature_algorithms))
|
|
{
|
|
return chooseSkeSigAlgTls12(ssl, id);
|
|
}
|
|
# endif
|
|
|
|
return chooseSkeSigAlgTls11(ssl, id);
|
|
}
|
|
|
|
/** Prepare for a postponed SKE signing operation.
|
|
|
|
@precond The function is only called when the SKE message needs
|
|
a signature, i.e. only when using non-PSK (EC)DHE ciphersuites.
|
|
*/
|
|
psRes_t tlsPrepareSkeSignature(ssl_t *ssl,
|
|
int32_t skeSigAlg,
|
|
unsigned char *tbsStart,
|
|
unsigned char *c,
|
|
psBool_t needPreHash)
|
|
{
|
|
sslIdentity_t *chosen = ssl->chosenIdentity;
|
|
unsigned char *orig = c;
|
|
psDigestContext_t digestCtx;
|
|
unsigned char *hsMsgHash = NULL;
|
|
unsigned char *tbs = NULL;
|
|
psSizeL_t tbsLen = 0;
|
|
unsigned char *tbsStop;
|
|
int32_t rc;
|
|
void *pkiData = ssl->userPtr;
|
|
pkaAfter_t *pkaAfter;
|
|
psSize_t hashSize;
|
|
unsigned char sigAlgId[2];
|
|
uint16_t pkaType = 0;
|
|
|
|
/*
|
|
ServerDHParams params;
|
|
digitally-signed struct {
|
|
opaque client_random[32];
|
|
opaque server_random[32];
|
|
ServerDHParams params;
|
|
} signed_params;
|
|
|
|
How we shall encode the signature (a digitally-signed struct):
|
|
TLS 1.2 and below:
|
|
struct {
|
|
SignatureAndHashAlgorithm algorithm;
|
|
opaque signature<0..2^16-1>;
|
|
} DigitallySigned;
|
|
TLS 1.1 and below:
|
|
opaque vector <0..2^16-1>
|
|
*/
|
|
|
|
/* [tbsStart, tbsStop] == signed_params. */
|
|
tbsStop = c;
|
|
|
|
hashSize = getDefaultSkeHashSize(ssl);
|
|
|
|
# ifdef USE_TLS_1_2
|
|
if (NGTD_VER(ssl, v_tls_with_signature_algorithms))
|
|
{
|
|
rc = getSignatureAndHashAlgorithmEncoding(skeSigAlg,
|
|
&sigAlgId[0],
|
|
&sigAlgId[1],
|
|
&hashSize);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
*c++ = sigAlgId[0];
|
|
*c++ = sigAlgId[1];
|
|
}
|
|
# endif
|
|
|
|
# if defined(USE_SM2) && defined(USE_SM3)
|
|
if (skeSigAlg == OID_SM3_SM2_SIG)
|
|
{
|
|
needPreHash = PS_FALSE;
|
|
}
|
|
# endif
|
|
|
|
if (needPreHash)
|
|
{
|
|
/* Reserve space for the hash of signed_params. */
|
|
hsMsgHash = psMalloc(ssl->hsPool, SHA512_HASH_SIZE);
|
|
if (hsMsgHash == NULL)
|
|
{
|
|
return PS_MEM_FAIL;
|
|
}
|
|
/* Compute the hash. */
|
|
rc = computeSkeHash(ssl,
|
|
&digestCtx,
|
|
hashSize,
|
|
tbsStart,
|
|
tbsStop,
|
|
hsMsgHash);
|
|
if (rc < 0)
|
|
{
|
|
psFree(hsMsgHash, ssl->hsPool);
|
|
return rc;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* No pre-hash, but need to provide the TBS as a contiguous
|
|
buffer for later hashing and signing. */
|
|
rc = computeSkeTbs(ssl,
|
|
tbsStart,
|
|
tbsStop,
|
|
&tbs,
|
|
&tbsLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/* Compute the signature lengths and write the signature length
|
|
octets. */
|
|
|
|
#ifdef USE_RSA_CIPHER_SUITE
|
|
if (ssl->flags & SSL_FLAGS_DHE_WITH_RSA)
|
|
{
|
|
/* Signature size == RSA private key modulus size. */
|
|
*c = (chosen->privKey.keysize & 0xFF00) >> 8; c++;
|
|
*c = chosen->privKey.keysize & 0xFF; c++;
|
|
|
|
pkaType = PKA_AFTER_RSA_SIG_GEN;
|
|
# ifdef USE_TLS_1_2
|
|
if (NGTD_VER(ssl, v_tls_with_pkcs15_auth))
|
|
{
|
|
/* The protocol uses PKCS #1.5 signatures. */
|
|
pkaType = PKA_AFTER_RSA_SIG_GEN_ELEMENT;
|
|
}
|
|
# endif /* USE_TLS_1_2 */
|
|
}
|
|
#endif /* USE_RSA_CIPHER_SUITE */
|
|
|
|
# ifdef USE_ECC_CIPHER_SUITE
|
|
if (ssl->flags & SSL_FLAGS_DHE_WITH_DSA)
|
|
{
|
|
/*
|
|
For ECDSA, the signature length octets are written later by
|
|
psEccDsaSign in nowDoSkePka. Not being consistent is bad. But,
|
|
because of the "negative ECDSA" case, we do not completely
|
|
know the signature length in advance.
|
|
*/
|
|
pkaType = PKA_AFTER_ECDSA_SIG_GEN;
|
|
}
|
|
# endif /* USE_ECC_CIPHER_SUITE */
|
|
|
|
# ifdef USE_DTLS
|
|
if (ACTV_VER(ssl, v_dtls_any) && (ssl->retransmit == 1))
|
|
{
|
|
/* It is not optimal to have run through the above digest updates
|
|
again on a retransmit just to free the hash here but the
|
|
saved message is ONLY the signature portion done in nowDoSke
|
|
so the few hashSigAlg bytes and keysize done above during the
|
|
hash are important to rewrite */
|
|
psFree(hsMsgHash, ssl->hsPool);
|
|
Memcpy(c, ssl->ckeMsg, ssl->ckeSize);
|
|
c += ssl->ckeSize;
|
|
if (tbs != NULL)
|
|
{
|
|
psFree(tbs, ssl->hsPool);
|
|
}
|
|
return (c - orig);
|
|
}
|
|
# endif /* USE_DTLS */
|
|
|
|
pkaAfter = getPkaAfter(ssl);
|
|
if (pkaAfter == NULL)
|
|
{
|
|
psTraceErrr("getPkaAfter error\n");
|
|
psFree(hsMsgHash, ssl->hsPool);
|
|
if (tbs != NULL)
|
|
{
|
|
psFree(tbs, ssl->hsPool);
|
|
}
|
|
return PS_PLATFORM_FAIL;
|
|
}
|
|
if (needPreHash)
|
|
{
|
|
pkaAfter->inbuf = hsMsgHash;
|
|
pkaAfter->inlen = hashSize;
|
|
}
|
|
else
|
|
{
|
|
pkaAfter->inbuf = tbs;
|
|
pkaAfter->inlen = tbsLen;
|
|
}
|
|
pkaAfter->outbuf = c;
|
|
pkaAfter->data = pkiData;
|
|
pkaAfter->type = pkaType;
|
|
|
|
/* Advance write pointer by the predicted size of the signature. */
|
|
|
|
# ifdef USE_RSA_CIPHER_SUITE
|
|
if (ssl->flags & SSL_FLAGS_DHE_WITH_RSA)
|
|
{
|
|
c += chosen->privKey.keysize;
|
|
}
|
|
# endif
|
|
|
|
# ifdef USE_ECC_CIPHER_SUITE
|
|
if (ssl->flags & SSL_FLAGS_DHE_WITH_DSA)
|
|
{
|
|
rc = chosen->privKey.keysize + 8;
|
|
/* NEGATIVE ECDSA - Adding spot for ONE 0x0 byte in ECDSA so we'll
|
|
be right 50% of the time... 521 curve doesn't need */
|
|
if (chosen->privKey.keysize != 132)
|
|
{
|
|
rc += 1;
|
|
}
|
|
/* Above we added in the 8 bytes of overhead (2 sigLen, 1 SEQ,
|
|
1 len (possibly 2!), 1 INT, 1 rLen, 1 INT, 1 sLen) and now
|
|
subtract the first 3 bytes to see if the 1 len needs to be 2 */
|
|
if (rc - 3 >= 128)
|
|
{
|
|
rc++;
|
|
}
|
|
pkaAfter->user = rc; /* outlen for later */
|
|
c += rc;
|
|
}
|
|
# endif
|
|
|
|
/* Return the predicted size of the digitally-signed struct. */
|
|
return (c - orig);
|
|
}
|
|
|
|
|
|
static
|
|
psPool_t *getTmpPkiPool(ssl_t *ssl, pkaAfter_t *pka)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
psRes_t tlsMakeSkeSignature(ssl_t *ssl,
|
|
pkaAfter_t *pka,
|
|
psBuf_t *out)
|
|
{
|
|
int32_t rc;
|
|
psPool_t *pkiPool = getTmpPkiPool(ssl, pka);
|
|
int32_t sigAlg = OID_RSA_TLS_SIG_ALG;
|
|
sslIdentity_t *chosen = ssl->chosenIdentity;
|
|
psPubKey_t *privKey = &chosen->privKey;
|
|
unsigned char *sigBuf;
|
|
psSize_t sigLen;
|
|
psSignOpts_t opts = {0};
|
|
|
|
/*
|
|
Prepare for the call to psSign.
|
|
RSA signatures are be generated straight into pka->outbuf.
|
|
ECDSA signatures use an intermediate temporary buffer.
|
|
|
|
For RSA, the TLS signature vector length octets have been written
|
|
in tlsPrepareSkeSignature. With ECDSA, we cannot completely predict
|
|
the signature size in advance, so we ask psSign to prepend the
|
|
TLS vector length (INCLUDE_SIZE option) to the signature.
|
|
*/
|
|
switch (pka->type)
|
|
{
|
|
# ifdef USE_RSA_CIPHER_SUITE
|
|
case PKA_AFTER_RSA_SIG_GEN_ELEMENT:
|
|
sigAlg = OID_RSA_PKCS15_SIG_ALG;
|
|
sigLen = privKey->keysize;
|
|
sigBuf = pka->outbuf;
|
|
opts.flags |= PS_SIGN_OPTS_USE_PREALLOCATED_OUTBUF;
|
|
break;
|
|
case PKA_AFTER_RSA_SIG_GEN:
|
|
sigAlg = OID_RSA_TLS_SIG_ALG;
|
|
sigLen = privKey->keysize;
|
|
sigBuf = pka->outbuf;
|
|
opts.flags |= PS_SIGN_OPTS_USE_PREALLOCATED_OUTBUF;
|
|
break;
|
|
# endif /* USE_RSA_CIPHER_SUITE */
|
|
# ifdef USE_ECC_CIPHER_SUITE
|
|
case PKA_AFTER_ECDSA_SIG_GEN:
|
|
sigAlg = OID_ECDSA_TLS_SIG_ALG;
|
|
# ifdef USE_DTLS
|
|
ssl->ecdsaSizeChange = 0;
|
|
# endif
|
|
opts.flags |= PS_SIGN_OPTS_ECDSA_INCLUDE_SIZE;
|
|
# if defined(USE_SM2) && defined(USE_SM3)
|
|
if (privKey->key.ecc.curve->curveId == IANA_CURVESM2)
|
|
{
|
|
opts.flags |= PS_SIGN_OPTS_SM2_SIGN;
|
|
}
|
|
# endif
|
|
break;
|
|
# endif /* USE_ECC_CIPHER_SUITE */
|
|
default:
|
|
psTraceErrr("Unsupported type of PKA operation\n");
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
opts.userData = pka->data;
|
|
|
|
/* Compute the signature. */
|
|
rc = psSign(pkiPool,
|
|
privKey,
|
|
sigAlg,
|
|
pka->inbuf,
|
|
pka->inlen,
|
|
&sigBuf,
|
|
&sigLen,
|
|
&opts);
|
|
if (rc == PS_PENDING)
|
|
{
|
|
/* Async operation launched, but not complete. */
|
|
/*
|
|
If the result is going directly inline to the output
|
|
buffer we unflag 'type' so this function isn't called
|
|
again on the way back around. Also, we can safely
|
|
free inbuf because it has been copied out.
|
|
*/
|
|
psFree(pka->inbuf, ssl->hsPool);
|
|
pka->inbuf = NULL;
|
|
pka->type = 0;
|
|
if (sigBuf != pka->outbuf)
|
|
{
|
|
psFree(sigBuf, ssl->pkiPool);
|
|
}
|
|
return rc;
|
|
}
|
|
else if (rc < 0)
|
|
{
|
|
if (sigBuf != pka->outbuf)
|
|
{
|
|
psFree(sigBuf, ssl->hsPool);
|
|
}
|
|
psTraceErrr("SKE signature generation failed\n");
|
|
psTraceIntInfo("Signature return code: %d\n", rc);
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
/* Signature is ready, either in sigBuf or in pka->outbuf. */
|
|
|
|
/* If the signature size is different than predicted, we need to
|
|
tweak the previously encoded flight to account for this.
|
|
This is a huge mess, but cannot be avoided with the current
|
|
approach, where the entire flight is encoded before public
|
|
key operations are used to fill the signature spots. */
|
|
# ifdef USE_ECC_CIPHER_SUITE
|
|
if (pka->type == PKA_AFTER_ECDSA_SIG_GEN)
|
|
{
|
|
if (sigLen != pka->user)
|
|
{
|
|
/* Confirmed ECDSA is not default size */
|
|
psTraceInfo("Need accountForEcdsaSizeChange\n");
|
|
rc = accountForEcdsaSizeChange(ssl,
|
|
pka,
|
|
sigLen,
|
|
sigBuf,
|
|
out,
|
|
SSL_HS_SERVER_KEY_EXCHANGE);
|
|
if (rc < 0)
|
|
{
|
|
clearPkaAfter(ssl);
|
|
psFree(sigBuf, ssl->hsPool);
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Memcpy(pka->outbuf, sigBuf, pka->user);
|
|
}
|
|
psFree(sigBuf, pkiPool);
|
|
}
|
|
# endif /* USE_ECC_CIPHER_SUITE */
|
|
|
|
/* Store the signature in case of a message retransmit in DTLS. */
|
|
# ifdef USE_DTLS
|
|
if ((ssl->flags & SSL_FLAGS_DTLS) && (ssl->retransmit == 0))
|
|
{
|
|
/* Using existing ckeMsg and ckeSize that clients are using but
|
|
this should be totally fine on the server side because it is
|
|
freed at FINISHED parse */
|
|
ssl->ckeSize = sigLen;
|
|
ssl->ckeMsg = psMalloc(ssl->hsPool, ssl->ckeSize);
|
|
if (ssl->ckeMsg == NULL)
|
|
{
|
|
psTraceErrr("Memory allocation error ckeMsg\n");
|
|
return PS_MEM_FAIL;
|
|
}
|
|
Memcpy(ssl->ckeMsg, pka->outbuf, ssl->ckeSize);
|
|
}
|
|
# endif /* USE_DTLS */
|
|
|
|
clearPkaAfter(ssl);
|
|
|
|
return rc;
|
|
}
|
|
#endif /* USE_IDENTITY_CERTIFICATES */
|
|
|
|
psBool_t tlsIsSupportedRsaSigAlg(int32_t alg)
|
|
{
|
|
switch (alg)
|
|
{
|
|
case OID_RSA_TLS_SIG_ALG:
|
|
case sigalg_rsa_pkcs1_sha1:
|
|
case sigalg_rsa_pkcs1_sha256:
|
|
case sigalg_rsa_pkcs1_sha384:
|
|
case sigalg_rsa_pkcs1_sha512:
|
|
# ifdef USE_PKCS1_PSS
|
|
case sigalg_rsa_pss_rsae_sha256:
|
|
case sigalg_rsa_pss_rsae_sha384:
|
|
case sigalg_rsa_pss_rsae_sha512:
|
|
case sigalg_rsa_pss_pss_sha256:
|
|
case sigalg_rsa_pss_pss_sha384:
|
|
case sigalg_rsa_pss_pss_sha512:
|
|
# endif
|
|
return PS_TRUE;
|
|
default:
|
|
return PS_FALSE;
|
|
}
|
|
|
|
return PS_FALSE;
|
|
}
|
|
|
|
psBool_t tlsIsSupportedEcdsaSigAlg(int32_t alg)
|
|
{
|
|
switch (alg)
|
|
{
|
|
case OID_ECDSA_TLS_SIG_ALG:
|
|
case sigalg_ecdsa_sha1:
|
|
case sigalg_ecdsa_secp256r1_sha256:
|
|
case sigalg_ecdsa_secp384r1_sha384:
|
|
case sigalg_ecdsa_secp521r1_sha512:
|
|
return PS_TRUE;
|
|
default:
|
|
return PS_FALSE;
|
|
}
|
|
}
|
|
|
|
psResSize_t tlsSigAlgToHashLen(uint16_t alg)
|
|
{
|
|
/* Note: We are in TLS 1.2 context here. The sigalg_* names below
|
|
are from TLS 1.3, but they are compatible with the TLS 1.2
|
|
ones. Only difference is that the TLS 1.2 ECDSA sig algs
|
|
do not specify the curve. So sigalg_ecdsa_secp256r1_sha256
|
|
just means ECDSA-SHA256 here, for example. */
|
|
switch (alg)
|
|
{
|
|
case sigalg_rsa_pkcs1_sha1:
|
|
case sigalg_ecdsa_sha1:
|
|
return SHA1_HASH_SIZE;
|
|
case sigalg_rsa_pkcs1_sha256:
|
|
case sigalg_rsa_pss_rsae_sha256:
|
|
case sigalg_rsa_pss_pss_sha256:
|
|
case sigalg_ecdsa_secp256r1_sha256:
|
|
return SHA256_HASH_SIZE;
|
|
case sigalg_rsa_pkcs1_sha384:
|
|
case sigalg_rsa_pss_rsae_sha384:
|
|
case sigalg_rsa_pss_pss_sha384:
|
|
case sigalg_ecdsa_secp384r1_sha384:
|
|
return SHA384_HASH_SIZE;
|
|
case sigalg_rsa_pkcs1_sha512:
|
|
case sigalg_rsa_pss_rsae_sha512:
|
|
case sigalg_rsa_pss_pss_sha512:
|
|
case sigalg_ecdsa_secp521r1_sha512:
|
|
return SHA512_HASH_SIZE;
|
|
case sigalg_sm2sig_sm3:
|
|
return SM3_HASH_SIZE;
|
|
default:
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
}
|
|
|
|
int32_t tlsSigAlgToMatrix(uint16_t alg)
|
|
{
|
|
switch (alg)
|
|
{
|
|
case sigalg_rsa_pkcs1_sha1:
|
|
return OID_SHA1_RSA_SIG;
|
|
case sigalg_rsa_pkcs1_sha256:
|
|
return OID_SHA256_RSA_SIG;
|
|
case sigalg_rsa_pkcs1_sha384:
|
|
return OID_SHA384_RSA_SIG;
|
|
case sigalg_rsa_pkcs1_sha512:
|
|
return OID_SHA512_RSA_SIG;
|
|
case sigalg_rsa_pss_rsae_sha256:
|
|
case sigalg_rsa_pss_rsae_sha384:
|
|
case sigalg_rsa_pss_rsae_sha512:
|
|
case sigalg_rsa_pss_pss_sha256:
|
|
case sigalg_rsa_pss_pss_sha384:
|
|
case sigalg_rsa_pss_pss_sha512:
|
|
return OID_RSASSA_PSS;
|
|
case sigalg_ecdsa_sha1:
|
|
return OID_SHA1_ECDSA_SIG;
|
|
case sigalg_ecdsa_secp256r1_sha256:
|
|
return OID_SHA256_ECDSA_SIG;
|
|
case sigalg_ecdsa_secp384r1_sha384:
|
|
return OID_SHA384_ECDSA_SIG;
|
|
case sigalg_ecdsa_secp521r1_sha512:
|
|
return OID_SHA512_ECDSA_SIG;
|
|
case sigalg_sm2sig_sm3:
|
|
case 0x0707: /*in tls1.2 case*/
|
|
return OID_SM3_SM2_SIG;
|
|
default:
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
}
|
|
|
|
int32_t tlsVerify(ssl_t *ssl,
|
|
const unsigned char *tbs,
|
|
psSizeL_t tbsLen,
|
|
const unsigned char *c,
|
|
const unsigned char *end,
|
|
psPubKey_t *pubKey,
|
|
psVerifyOptions_t *opts)
|
|
{
|
|
int32_t rc;
|
|
uint16_t sigAlgTls = 0;
|
|
int32_t matrixSigAlg;
|
|
psSize_t sigLen;
|
|
psDigestContext_t digestCtx;
|
|
psResSize_t hashLen = 0;
|
|
unsigned char hashBuf[SHA512_HASH_SIZE];
|
|
psVerifyOptions_t defaultOpts = {0};
|
|
psBool_t verifyResult;
|
|
const unsigned char *orig_c = c;
|
|
psBool_t useRsa = PS_FALSE;
|
|
unsigned char *refTbs;
|
|
psSizeL_t refTbsLen;
|
|
|
|
if (opts == NULL)
|
|
{
|
|
opts = &defaultOpts;
|
|
}
|
|
if (ssl->flags & SSL_FLAGS_DHE_WITH_RSA)
|
|
{
|
|
useRsa = PS_TRUE; /* Default for TLS 1.1 and below. */
|
|
}
|
|
|
|
/*
|
|
(D)TLS 1.2:
|
|
struct {
|
|
SignatureAndHashAlgorithm algorithm;
|
|
opaque signature<0..2^16-1>;
|
|
} DigitallySigned;
|
|
|
|
TLS 1.1 and below:
|
|
opaque vector <0..2^16-1>
|
|
*/
|
|
|
|
# ifdef USE_TLS_1_2
|
|
if (NGTD_VER(ssl, v_tls_with_signature_algorithms))
|
|
{
|
|
if (end - c < 2)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
sigAlgTls = *c << 8; c++;
|
|
sigAlgTls += *c; c++;
|
|
# if defined(USE_SM2) && defined(USE_SM3)
|
|
if (sigAlgTls == 0x0707)
|
|
{
|
|
sigAlgTls = sigalg_sm2sig_sm3;
|
|
opts->noPreHash = PS_TRUE;
|
|
}
|
|
# endif
|
|
|
|
if (tlsIsSupportedRsaSigAlg(sigAlgTls))
|
|
{
|
|
useRsa = PS_TRUE;
|
|
}
|
|
/* Note: this a TLS sig alg ID. */
|
|
hashLen = tlsSigAlgToHashLen(sigAlgTls);
|
|
if (hashLen <= 0)
|
|
{
|
|
goto out_decode_error;
|
|
}
|
|
psTracePrintTls13SigAlg(INDENT_HS_MSG,
|
|
"signature algorithm",
|
|
sigAlgTls,
|
|
PS_FALSE,
|
|
PS_TRUE);
|
|
|
|
# ifdef USE_PKCS1_PSS
|
|
switch (sigAlgTls)
|
|
{
|
|
case sigalg_rsa_pss_rsae_sha256:
|
|
case sigalg_rsa_pss_pss_sha256:
|
|
opts->useRsaPss = PS_TRUE;
|
|
opts->rsaPssHashAlg = PKCS1_SHA256_ID;
|
|
opts->rsaPssSaltLen = SHA256_HASH_SIZE;
|
|
break;
|
|
case sigalg_rsa_pss_rsae_sha384:
|
|
case sigalg_rsa_pss_pss_sha384:
|
|
opts->useRsaPss = PS_TRUE;
|
|
opts->rsaPssHashAlg = PKCS1_SHA384_ID;
|
|
opts->rsaPssSaltLen = SHA384_HASH_SIZE;
|
|
break;
|
|
case sigalg_rsa_pss_rsae_sha512:
|
|
case sigalg_rsa_pss_pss_sha512:
|
|
opts->useRsaPss = PS_TRUE;
|
|
opts->rsaPssHashAlg = PKCS1_SHA512_ID;
|
|
opts->rsaPssSaltLen = SHA512_HASH_SIZE;
|
|
break;
|
|
}
|
|
# ifdef USE_CL_RSA
|
|
if (opts->useRsaPss)
|
|
{
|
|
/* The crypto-cl API for RSA-PSS verification does not support
|
|
pre-hashing. */
|
|
opts->noPreHash = PS_TRUE;
|
|
}
|
|
# endif /* USE_CL_RSA */
|
|
# endif /* USE_PKCS1_PSS */
|
|
}
|
|
# endif /* USE_TLS_1_2 */
|
|
|
|
/* Sig alg must match the ciphersuite auth alg. */
|
|
if (!useRsa && (ssl->flags & SSL_FLAGS_DHE_WITH_RSA))
|
|
{
|
|
psTraceErrr("Peer used RSA signature for non-RSA suite\n");
|
|
goto out_decode_error;
|
|
}
|
|
if (useRsa && (ssl->flags & SSL_FLAGS_DHE_WITH_DSA))
|
|
{
|
|
psTraceErrr("Peer used ECDSA signature for non-ECDSA suite\n");
|
|
goto out_decode_error;
|
|
}
|
|
|
|
|
|
# ifdef USE_SEC_CONFIG
|
|
/* Ask the security callback whether the verify operation
|
|
with this sig alg and key is allowed. */
|
|
{
|
|
psSecOperation_t secOp;
|
|
psSizeL_t secOpBits;
|
|
|
|
if (useRsa)
|
|
{
|
|
secOp = secop_rsa_verify;
|
|
secOpBits = pubKey->keysize * 8;
|
|
}
|
|
else
|
|
{
|
|
secOp = secop_ecdsa_verify;
|
|
secOpBits = pubKey->key.ecc.curve->size * 8;
|
|
}
|
|
|
|
rc = matrixSslCallSecurityCallback(ssl, secOp, secOpBits, NULL);
|
|
if (rc < 0)
|
|
{
|
|
psTraceErrr("Operation forbidden by security callback\n");
|
|
ssl->err = SSL_ALERT_INSUFFICIENT_SECURITY;
|
|
return rc;
|
|
}
|
|
}
|
|
# endif /* USE_SEC_CONFIG */
|
|
|
|
/* Parse signature vector length. */
|
|
if (end - c < 2)
|
|
{
|
|
psTraceErrr("Could not decode TLS signature\n");
|
|
goto out_decode_error;
|
|
}
|
|
sigLen = *c << 8; c++;
|
|
sigLen |= *c; c++;
|
|
|
|
/* Sanity check. */
|
|
if (sigLen > (end - c))
|
|
{
|
|
psTraceErrr("Sig len sanity check failed\n");
|
|
goto out_decode_error;
|
|
}
|
|
|
|
if (opts == NULL || opts->noPreHash == PS_FALSE)
|
|
{
|
|
/* Compute the reference hash. */
|
|
if (hashLen == 0)
|
|
{
|
|
hashLen = getDefaultSkeHashSize(ssl);
|
|
}
|
|
rc = computeSkeHash(ssl,
|
|
&digestCtx,
|
|
hashLen,
|
|
tbs,
|
|
tbs + tbsLen,
|
|
hashBuf);
|
|
if (rc < 0)
|
|
{
|
|
goto out_illegal_parameter;
|
|
}
|
|
refTbs = hashBuf;
|
|
refTbsLen = hashLen;
|
|
}
|
|
else
|
|
{
|
|
/* No pre-hashing before signature verification.
|
|
Construct the reference tbs as a contiguous block. */
|
|
rc = computeSkeTbs(ssl,
|
|
tbs,
|
|
tbs + tbsLen,
|
|
&refTbs,
|
|
&refTbsLen);
|
|
if (rc < 0)
|
|
{
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/* Now verify the signature. */
|
|
|
|
if (NGTD_VER(ssl, v_tls_with_pkcs15_auth))
|
|
{
|
|
opts->msgIsDigestInfo = PS_TRUE;
|
|
}
|
|
# if defined(USE_SM2) && defined(USE_SM3)
|
|
if (sigAlgTls == sigalg_sm2sig_sm3)
|
|
{
|
|
opts->msgIsDigestInfo = PS_FALSE;
|
|
}
|
|
# endif
|
|
if (sigAlgTls == 0)
|
|
{
|
|
matrixSigAlg = useRsa ? OID_RSA_TLS_SIG_ALG : OID_SHA1_ECDSA_SIG;
|
|
}
|
|
else
|
|
{
|
|
matrixSigAlg = tlsSigAlgToMatrix(sigAlgTls);
|
|
}
|
|
|
|
if (!NGTD_VER(ssl, v_tls_with_signature_algorithms))
|
|
{
|
|
psTracePrintMatrixSigAlg(INDENT_HS_MSG,
|
|
"signature algorithm",
|
|
matrixSigAlg,
|
|
PS_TRUE);
|
|
}
|
|
|
|
rc = psVerifySig(ssl->hsPool,
|
|
refTbs,
|
|
refTbsLen,
|
|
c,
|
|
sigLen,
|
|
pubKey,
|
|
matrixSigAlg,
|
|
&verifyResult,
|
|
opts);
|
|
if (rc < 0 || verifyResult != PS_TRUE)
|
|
{
|
|
psTraceErrr("Can't verify serverKeyExchange sig\n");
|
|
if (refTbs != hashBuf)
|
|
{
|
|
psFree(refTbs, ssl->hsPool);
|
|
}
|
|
goto out_decrypt_error;
|
|
}
|
|
|
|
if (refTbs != hashBuf)
|
|
{
|
|
psFree(refTbs, ssl->hsPool);
|
|
}
|
|
|
|
c += sigLen;
|
|
|
|
psAssert(c > orig_c);
|
|
psAssert(c <= end);
|
|
|
|
return (c - orig_c);
|
|
|
|
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_decrypt_error:
|
|
ssl->err = SSL_ALERT_DECRYPT_ERROR;
|
|
return MATRIXSSL_ERROR;
|
|
}
|
|
|
|
#if defined(USE_SERVER_SIDE_SSL) || defined(USE_CLIENT_AUTH)
|
|
|
|
/**
|
|
Return PS_TRUE if sigAlg is in peerSigAlgs, PS_FALSE otherwise.
|
|
|
|
peerSigAlgs should be the a set of masks we created after
|
|
parsing the peer's supported_signature_algorithms list
|
|
in ClientHello or CertificateRequest.
|
|
*/
|
|
psBool_t peerSupportsSigAlg(int32_t sigAlg,
|
|
uint16_t peerSigAlgs
|
|
/* , psSize_t peerSigAlgsLen) */
|
|
)
|
|
{
|
|
uint16_t yes;
|
|
|
|
if (sigAlg == OID_MD5_RSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_MD5_RSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA1_RSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA1_RSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA256_RSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA256_RSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA384_RSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA384_RSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA512_RSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA512_RSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA1_ECDSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA1_ECDSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA256_ECDSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA256_ECDSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA384_ECDSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA384_ECDSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SHA512_ECDSA_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SHA512_ECDSA_MASK) != 0);
|
|
}
|
|
else if (sigAlg == OID_SM3_SM2_SIG)
|
|
{
|
|
yes = ((peerSigAlgs & HASH_SIG_SM3_SM2_MASK) != 0);
|
|
}
|
|
else
|
|
{
|
|
return PS_FALSE; /* Unknown/unsupported sig alg. */
|
|
}
|
|
|
|
if (yes)
|
|
{
|
|
return PS_TRUE;
|
|
}
|
|
else
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Return PS_TRUE when we support sigAlg for signature generation,
|
|
PS_FALSE otherwise.
|
|
|
|
Compile-time switches as well as FIPS or non-FIPS mode is taken
|
|
into account.
|
|
|
|
@param[in] sigAlg The signature algorithm whose support is to
|
|
be checked.
|
|
@param[in] pubKeyAlgorithm The public key algorithm of our
|
|
private/public key pair (OID_RSA_KEY_ALG or OID_ECDSA_KEY_ALG.)
|
|
*/
|
|
psBool_t weSupportSigAlg(int32_t sigAlg,
|
|
int32_t pubKeyAlgorithm)
|
|
{
|
|
uint16_t we_support = 0;
|
|
uint16_t is_non_fips = 0; /* 1 if not allowed in FIPS mode for
|
|
signature generation. */
|
|
|
|
PS_VARIABLE_SET_BUT_UNUSED(is_non_fips);
|
|
|
|
#ifndef USE_RSA
|
|
if (pubKeyAlgorithm == OID_RSA_KEY_ALG)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
#endif
|
|
#ifndef USE_ECC
|
|
if (pubKeyAlgorithm == OID_ECDSA_KEY_ALG)
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
#endif
|
|
|
|
if (pubKeyAlgorithm == OID_RSA_KEY_ALG)
|
|
{
|
|
if (sigAlg == OID_MD2_RSA_SIG || sigAlg == OID_MD5_RSA_SIG)
|
|
{
|
|
/* No support for generating RSA-MD2 or RSA-MD5 signatures. */
|
|
is_non_fips = 1;
|
|
we_support = 0;
|
|
}
|
|
else if (sigAlg == OID_SHA1_RSA_SIG)
|
|
{
|
|
is_non_fips = 1;
|
|
#ifdef USE_SHA1
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SHA256_RSA_SIG)
|
|
{
|
|
#ifdef USE_SHA256
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SHA384_RSA_SIG)
|
|
{
|
|
#ifdef USE_SHA384
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SHA512_RSA_SIG)
|
|
{
|
|
#ifdef USE_SHA512
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* Our key does not support this algorithm. */
|
|
return PS_FALSE;
|
|
}
|
|
}
|
|
else if (pubKeyAlgorithm == OID_ECDSA_KEY_ALG)
|
|
{
|
|
if (sigAlg == OID_SHA1_ECDSA_SIG)
|
|
{
|
|
#ifdef USE_SHA1
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SHA256_ECDSA_SIG)
|
|
{
|
|
#ifdef USE_SHA256
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SHA384_ECDSA_SIG)
|
|
{
|
|
#ifdef USE_SHA384
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SHA512_ECDSA_SIG)
|
|
{
|
|
#ifdef USE_SHA512
|
|
we_support = 1;
|
|
#endif
|
|
}
|
|
else if (sigAlg == OID_SM3_SM2_SIG)
|
|
{
|
|
#if defined(USE_SM2) && defined(USE_SM3)
|
|
we_support = 1;
|
|
is_non_fips =1;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
/* Our key does not support this algorithm. */
|
|
return PS_FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return PS_FALSE; /* Unsupported public key alg, e.g. DSA. */
|
|
}
|
|
|
|
/* The basic capability is there. Now do some further checks
|
|
if needed. */
|
|
|
|
if (we_support)
|
|
{
|
|
return PS_TRUE;
|
|
}
|
|
else
|
|
{
|
|
return PS_FALSE;
|
|
}
|
|
}
|
|
|
|
/** Return PS_TRUE when:
|
|
- We support sigAlg for signature generation.
|
|
- sigAlg is in peerSigAlgs.
|
|
|
|
@param[in] sigAlg The signature algorithm whose support to check.
|
|
@param[in] pubKeyAlgorithm The public key algorithm of our key.
|
|
@param[in] peerSigAlgs The masks of the sigAlgs supported by the
|
|
peer. This should be the one parsed from the peer's
|
|
supported_signature_algorithms list in CertificateVerify or
|
|
CertificateRequest. In this case, sigAlg \in peerSigAlgs
|
|
means that the peer supports sigAlg for signature verification.
|
|
*/
|
|
psBool_t canUseSigAlg(int32_t sigAlg,
|
|
int32_t pubKeyAlgorithm,
|
|
uint16_t peerSigAlgs)
|
|
{
|
|
return (weSupportSigAlg(sigAlg, pubKeyAlgorithm) &&
|
|
peerSupportsSigAlg(sigAlg, peerSigAlgs));
|
|
}
|
|
|
|
/**
|
|
Upgrade to a more secure signature algorithm. If the algorithm
|
|
is already the strongest possible for the key type (i.e.
|
|
RSA-SHA-512 or ECDSA-SHA-512) change to the most popular
|
|
one (i.e. RSA-SHA-256 or ECDSA-SHA-256).
|
|
*/
|
|
int32_t upgradeSigAlg(int32_t sigAlg, int32_t pubKeyAlgorithm)
|
|
{
|
|
/*
|
|
RSA:
|
|
MD2 -> SHA256
|
|
MD5 -> SHA256
|
|
SHA1 -> SHA256
|
|
SHA256 -> SHA384
|
|
SHA384 -> SHA512
|
|
SHA512 -> SHA256
|
|
*/
|
|
if (pubKeyAlgorithm == OID_RSA_KEY_ALG)
|
|
{
|
|
if (sigAlg == OID_MD2_RSA_SIG ||
|
|
sigAlg == OID_MD5_RSA_SIG ||
|
|
sigAlg == OID_SHA1_RSA_SIG)
|
|
{
|
|
return OID_SHA256_RSA_SIG;
|
|
}
|
|
else if (sigAlg == OID_SHA256_RSA_SIG)
|
|
{
|
|
return OID_SHA384_RSA_SIG;
|
|
}
|
|
else if (sigAlg == OID_SHA384_RSA_SIG)
|
|
{
|
|
return OID_SHA512_RSA_SIG;
|
|
}
|
|
else if (sigAlg == OID_SHA512_RSA_SIG)
|
|
{
|
|
return OID_SHA256_RSA_SIG;
|
|
}
|
|
else
|
|
{
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
}
|
|
/*
|
|
ECDSA:
|
|
SHA1 -> SHA256
|
|
SHA256 -> SHA384
|
|
SHA384 -> SHA512
|
|
SHA512 -> SHA256
|
|
*/
|
|
else if (pubKeyAlgorithm == OID_ECDSA_KEY_ALG)
|
|
{
|
|
if (sigAlg == OID_SHA1_ECDSA_SIG)
|
|
{
|
|
return OID_SHA256_ECDSA_SIG;
|
|
}
|
|
else if (sigAlg == OID_SHA256_ECDSA_SIG)
|
|
{
|
|
return OID_SHA384_ECDSA_SIG;
|
|
}
|
|
else if (sigAlg == OID_SHA384_ECDSA_SIG)
|
|
{
|
|
return OID_SHA512_ECDSA_SIG;
|
|
}
|
|
else if (sigAlg == OID_SHA512_ECDSA_SIG)
|
|
{
|
|
return OID_SHA256_ECDSA_SIG;
|
|
}
|
|
else
|
|
{
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
}
|
|
|
|
static
|
|
int32_t sigAlgRsaToEcdsa(int32_t sigAlg)
|
|
{
|
|
if (sigAlg == OID_SHA1_RSA_SIG)
|
|
{
|
|
return OID_SHA1_ECDSA_SIG;
|
|
}
|
|
if (sigAlg == OID_SHA256_RSA_SIG)
|
|
{
|
|
return OID_SHA256_ECDSA_SIG;
|
|
}
|
|
if (sigAlg == OID_SHA384_RSA_SIG)
|
|
{
|
|
return OID_SHA384_ECDSA_SIG;
|
|
}
|
|
if (sigAlg == OID_SHA512_RSA_SIG)
|
|
{
|
|
return OID_SHA512_ECDSA_SIG;
|
|
}
|
|
else
|
|
{
|
|
return OID_SHA256_ECDSA_SIG;
|
|
}
|
|
}
|
|
|
|
static
|
|
int32_t ecdsaToRsa(int32_t sigAlg)
|
|
{
|
|
if (sigAlg == OID_SHA1_ECDSA_SIG)
|
|
{
|
|
return OID_SHA1_RSA_SIG;
|
|
}
|
|
if (sigAlg == OID_SHA256_ECDSA_SIG)
|
|
{
|
|
return OID_SHA256_RSA_SIG;
|
|
}
|
|
if (sigAlg == OID_SHA384_ECDSA_SIG)
|
|
{
|
|
return OID_SHA384_RSA_SIG;
|
|
}
|
|
if (sigAlg == OID_SHA512_ECDSA_SIG)
|
|
{
|
|
return OID_SHA512_RSA_SIG;
|
|
}
|
|
else
|
|
{
|
|
return OID_SHA256_RSA_SIG;
|
|
}
|
|
}
|
|
|
|
/**
|
|
Determine signature algorithm to use in the CertificateVerify or
|
|
ServerKeyExchange handshake messages in TLS 1.2.
|
|
|
|
TODO: add support for RSASSA-PSS.
|
|
|
|
This function should only be called when using TLS 1.2.
|
|
|
|
@param[in] certSigAlg The signature algorithm with which our
|
|
certificate was signed.
|
|
@param[in] keySize The size of our private key in bytes. For RSA,
|
|
this is modulus; for ECDSA, this is the curve size.
|
|
@param[in] pubKeyAlgorithm The public key algorithm to use for
|
|
authentication. This should the same algorithm our public/private key
|
|
pair is meant for. Must be either OID_RSA_KEY_ALG or
|
|
OID_ECDSA_KEY_ALG.
|
|
@param[in] peerSigAlg The list of signature algorithm masks
|
|
the peer supports (e.g. HASH_SIG_SHA*_RSA_MASK). This should
|
|
be the list created during parsing of the ClientHello or
|
|
CertificateRequest message.
|
|
@return The signature algorithm to use.
|
|
*/
|
|
int32_t chooseSigAlgInt(int32_t certSigAlg,
|
|
psPubKey_t *privKey,
|
|
psSize_t keySize,
|
|
int32_t keyAlgorithm,
|
|
uint16_t peerSigAlgs)
|
|
{
|
|
int32 a = certSigAlg;
|
|
psResSize_t hashLen;
|
|
|
|
#ifndef USE_RSA
|
|
if (keyAlgorithm == OID_RSA_KEY_ALG)
|
|
{
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
#endif
|
|
#ifndef USE_ECC
|
|
if (keyAlgorithm == OID_ECDSA_KEY_ALG)
|
|
{
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef USE_ROT_ECC
|
|
if (keyAlgorithm == OID_ECDSA_KEY_ALG)
|
|
{
|
|
psTraceIntInfo("keySize is %hu\n", keySize);
|
|
psTraceIntInfo("curve ID is %hu\n", privKey->key.ecc.curve->curveId);
|
|
return psRotCurveToSigAlg(privKey->key.ecc.curve->curveId);
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
We are going to use certSigAlg as the basis of our choice.
|
|
This is because the SSL layer must ensure anyway that the peer
|
|
supports this algorithm.
|
|
*/
|
|
if (keyAlgorithm == OID_RSA_KEY_ALG)
|
|
{
|
|
if (certSigAlg == OID_SHA1_ECDSA_SIG ||
|
|
certSigAlg == OID_SHA256_ECDSA_SIG ||
|
|
certSigAlg == OID_SHA384_ECDSA_SIG ||
|
|
certSigAlg == OID_SHA512_ECDSA_SIG)
|
|
{
|
|
/* Pubkey is RSA, but cert is signed with ECDSA.
|
|
Convert certSigAlg to corresponding RSA alg. */
|
|
a = ecdsaToRsa(certSigAlg);
|
|
}
|
|
}
|
|
else if (keyAlgorithm == OID_ECDSA_KEY_ALG)
|
|
{
|
|
if (certSigAlg != OID_SHA1_ECDSA_SIG &&
|
|
certSigAlg != OID_SHA256_ECDSA_SIG &&
|
|
certSigAlg != OID_SHA384_ECDSA_SIG &&
|
|
certSigAlg != OID_SHA512_ECDSA_SIG &&
|
|
certSigAlg != OID_SM3_SM2_SIG)
|
|
{
|
|
/* Pubkey is ECDSA, but cert is signed with RSA.
|
|
Convert to corresponding ECDSA alg. */
|
|
a = sigAlgRsaToEcdsa(certSigAlg);
|
|
}
|
|
}
|
|
|
|
hashLen = psSigAlgToHashLen(a);
|
|
if (hashLen < 0)
|
|
{ /* unknown sigAlg; error on hashLen */
|
|
return hashLen;
|
|
}
|
|
|
|
/*
|
|
For RSA signatures, RFC 5246 allows to pick any hash algorithm,
|
|
as long as it is supported by the peer, i.e. included in the
|
|
peer's signature_algorithms list.
|
|
|
|
We use this opportunity to switch from the insecure MD5 and
|
|
SHA-1 to SHA-256, if possible. We don't want to contribute
|
|
to the longevity of obsolete hash algorithms.
|
|
*/
|
|
if (psIsInsecureSigAlg(a, keyAlgorithm, keySize, hashLen)
|
|
|| !canUseSigAlg(a, keyAlgorithm, peerSigAlgs))
|
|
{
|
|
/* Try to upgrade: This won't select inscure ones. */
|
|
a = upgradeSigAlg(a, keyAlgorithm);
|
|
if (!canUseSigAlg(a, keyAlgorithm, peerSigAlgs))
|
|
{
|
|
/* Stil not supported. Try the next alternative. */
|
|
a = upgradeSigAlg(a, keyAlgorithm);
|
|
if (!canUseSigAlg(a, keyAlgorithm, peerSigAlgs))
|
|
{
|
|
/* Unable to upgrade insecure alg. Have to use the
|
|
server cert sig alg. */
|
|
a = certSigAlg;
|
|
psTraceIntInfo("Fallback to certificate sigAlg: %d\n", a);
|
|
}
|
|
}
|
|
}
|
|
psTraceIntInfo("Chose sigAlg %d\n", a);
|
|
return a;
|
|
}
|
|
|
|
int32_t chooseSigAlg(psX509Cert_t *cert,
|
|
psPubKey_t *privKey,
|
|
uint16_t peerSigAlgs)
|
|
{
|
|
int32 pubKeyAlg;
|
|
|
|
# ifdef USE_CERT_PARSE
|
|
pubKeyAlg = cert->pubKeyAlgorithm;
|
|
# else
|
|
if (privKey->type == PS_RSA)
|
|
{
|
|
pubKeyAlg = OID_RSA_KEY_ALG;
|
|
}
|
|
else if (privKey->type == PS_ECC)
|
|
{
|
|
pubKeyAlg = OID_ECDSA_KEY_ALG;
|
|
}
|
|
else
|
|
{
|
|
return PS_UNSUPPORTED_FAIL;
|
|
}
|
|
# endif /* USE_CERT_PARSE */
|
|
|
|
return chooseSigAlgInt(cert->sigAlgorithm,
|
|
privKey,
|
|
privKey->keysize,
|
|
pubKeyAlg,
|
|
peerSigAlgs);
|
|
}
|
|
|
|
|
|
/* Return the TLS 1.2 SignatureAndHashAlgorithm encoding for the
|
|
given algorithm OID. */
|
|
int32_t getSignatureAndHashAlgorithmEncoding(uint16_t sigAlgOid,
|
|
unsigned char *octet1,
|
|
unsigned char *octet2,
|
|
uint16_t *hashSize)
|
|
{
|
|
unsigned char b1, b2;
|
|
uint16_t hLen = 0;
|
|
|
|
switch (sigAlgOid)
|
|
{
|
|
#ifdef USE_SHA1
|
|
case OID_SHA1_ECDSA_SIG:
|
|
b1 = 0x2; /* SHA-1 */
|
|
b2 = 0x3; /* ECDSA */
|
|
hLen = SHA1_HASH_SIZE;
|
|
break;
|
|
case OID_SHA1_RSA_SIG:
|
|
b1 = 0x2; /* SHA-1 */
|
|
b2 = 0x1; /* RSA */
|
|
hLen = SHA1_HASH_SIZE;
|
|
break;
|
|
#endif
|
|
#ifdef USE_SHA256
|
|
case OID_SHA256_ECDSA_SIG:
|
|
b1 = 0x4; /* SHA-256 */
|
|
b2 = 0x3; /* ECDSA */
|
|
hLen = SHA256_HASH_SIZE;
|
|
break;
|
|
case OID_SHA256_RSA_SIG:
|
|
b1 = 0x4; /* SHA-256 */
|
|
b2 = 0x1; /* RSA */
|
|
hLen = SHA256_HASH_SIZE;
|
|
break;
|
|
#endif
|
|
#ifdef USE_SHA384
|
|
case OID_SHA384_ECDSA_SIG:
|
|
b1 = 0x5; /* SHA-384 */
|
|
b2 = 0x3; /* ECDSA */
|
|
hLen = SHA384_HASH_SIZE;
|
|
break;
|
|
case OID_SHA384_RSA_SIG:
|
|
b1 = 0x5; /* SHA-384 */
|
|
b2 = 0x1; /* RSA */
|
|
hLen = SHA384_HASH_SIZE;
|
|
break;
|
|
#endif
|
|
#ifdef USE_SHA512
|
|
case OID_SHA512_ECDSA_SIG:
|
|
b1 = 0x6; /* SHA-512 */
|
|
b2 = 0x3; /* ECDSA */
|
|
hLen = SHA512_HASH_SIZE;
|
|
break;
|
|
case OID_SHA512_RSA_SIG:
|
|
b1 = 0x6; /* SHA-512 */
|
|
b2 = 0x1; /* RSA */
|
|
hLen = SHA512_HASH_SIZE;
|
|
break;
|
|
#endif
|
|
#if defined(USE_SM2) && defined(USE_SM3)
|
|
case OID_SM3_SM2_SIG:
|
|
b1 = 0x7;
|
|
b2 = 0x7;
|
|
hLen = SM3_HASH_SIZE;
|
|
break;
|
|
#endif
|
|
default:
|
|
return PS_UNSUPPORTED_FAIL; /* algorithm not supported */
|
|
}
|
|
if (octet1 && octet2 && hashSize)
|
|
{
|
|
*octet1 = b1;
|
|
*octet2 = b2;
|
|
*hashSize = hLen;
|
|
return PS_SUCCESS;
|
|
}
|
|
return PS_ARG_FAIL;
|
|
}
|
|
|
|
#endif /* ! USE_ONLY_PSK_CIPHER_SUITE */
|
|
#endif /* USE_SERVER_SIDE_SSL || USE_CLIENT_AUTH */
|
|
|
|
#endif /* USE_TLS_1_3_ONLY */
|