Files
mars-matrixssl/matrixssl/tlsSigVer.c
Janne Johansson 5a72845b65 MatrixSSL 4.0.1
2018-11-15 10:12:51 +02:00

1342 lines
36 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 INSIDE Secure Corporation
* 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 INSIDE at
* http://www.insidesecure.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_ONLY_PSK_CIPHER_SUITE
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->md5sha1);
psMd5Sha1Init(&digestCtx->md5sha1);
psMd5Sha1Update(&digestCtx->md5sha1, ssl->sec.clientRandom,
SSL_HS_RANDOM_SIZE);
psMd5Sha1Update(&digestCtx->md5sha1, ssl->sec.serverRandom,
SSL_HS_RANDOM_SIZE);
psMd5Sha1Update(&digestCtx->md5sha1, tbsStart,
(uint32) (tbsStop - tbsStart));
psMd5Sha1Final(&digestCtx->md5sha1, hsMsgHash);
break;
# endif /* USE_MD5SHA1 */
# ifdef USE_SHA1
case SHA1_HASH_SIZE:
psSha1PreInit(&digestCtx->sha1);
psSha1Init(&digestCtx->sha1);
psSha1Update(&digestCtx->sha1, ssl->sec.clientRandom,
SSL_HS_RANDOM_SIZE);
psSha1Update(&digestCtx->sha1, ssl->sec.serverRandom,
SSL_HS_RANDOM_SIZE);
psSha1Update(&digestCtx->sha1, tbsStart,
(uint32) (tbsStop - tbsStart));
psSha1Final(&digestCtx->sha1, hsMsgHash);
break;
# endif /* USE_SHA1 */
# ifdef USE_TLS_1_2
case SHA256_HASH_SIZE:
psSha256PreInit(&digestCtx->sha256);
psSha256Init(&digestCtx->sha256);
psSha256Update(&digestCtx->sha256, ssl->sec.clientRandom,
SSL_HS_RANDOM_SIZE);
psSha256Update(&digestCtx->sha256, ssl->sec.serverRandom,
SSL_HS_RANDOM_SIZE);
psSha256Update(&digestCtx->sha256, tbsStart,
(uint32) (tbsStop - tbsStart));
psSha256Final(&digestCtx->sha256, hsMsgHash);
break;
# ifdef USE_SHA384
case SHA384_HASH_SIZE:
psSha384PreInit(&digestCtx->sha384);
psSha384Init(&digestCtx->sha384);
psSha384Update(&digestCtx->sha384, ssl->sec.clientRandom,
SSL_HS_RANDOM_SIZE);
psSha384Update(&digestCtx->sha384, ssl->sec.serverRandom,
SSL_HS_RANDOM_SIZE);
psSha384Update(&digestCtx->sha384, tbsStart,
(uint32) (tbsStop - tbsStart));
psSha384Final(&digestCtx->sha384, hsMsgHash);
break;
# endif /* USE_SHA384 */
# ifdef USE_SHA512
case SHA512_HASH_SIZE:
psSha512PreInit(&digestCtx->sha512);
psSha512Init(&digestCtx->sha512);
psSha512Update(&digestCtx->sha512, ssl->sec.clientRandom,
SSL_HS_RANDOM_SIZE);
psSha512Update(&digestCtx->sha512, ssl->sec.serverRandom,
SSL_HS_RANDOM_SIZE);
psSha512Update(&digestCtx->sha512, tbsStart,
(uint32) (tbsStop - tbsStart));
psSha512Final(&digestCtx->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;
}
static inline
int32_t chooseSkeSigAlgTls12(ssl_t *ssl, sslIdentity_t *id)
{
int32_t sigAlg;
sigAlg = chooseSigAlg(id->cert, &id->privKey, ssl->hashSigAlg);
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)
{
sslIdentity_t *chosen = ssl->chosenIdentity;
unsigned char *orig = c;
psDigestContext_t digestCtx;
unsigned char *hsMsgHash, *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;
/* Reserve space for the hash of signed_params. */
hsMsgHash = psMalloc(ssl->hsPool, SHA512_HASH_SIZE);
if (hsMsgHash == NULL)
{
return PS_MEM_FAIL;
}
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)
{
psFree(hsMsgHash, ssl->hsPool);
return rc;
}
*c++ = sigAlgId[0];
*c++ = sigAlgId[1];
}
# endif
/* Compute the hash. */
rc = computeSkeHash(ssl,
&digestCtx,
hashSize,
tbsStart,
tbsStop,
hsMsgHash);
if (rc < 0)
{
psFree(hsMsgHash, ssl->hsPool);
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;
return (c - orig);
}
# endif /* USE_DTLS */
pkaAfter = getPkaAfter(ssl);
if (pkaAfter == NULL)
{
psTraceInfo("getPkaAfter error\n");
psFree(hsMsgHash, ssl->hsPool);
return PS_PLATFORM_FAIL;
}
pkaAfter->inbuf = hsMsgHash;
pkaAfter->outbuf = c;
pkaAfter->data = pkiData;
pkaAfter->inlen = hashSize;
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 = pka->outbuf;
psSize_t sigLen;
psSignOpts_t opts = {0};
/* New temp location for ECDSA sig which can be one len byte different
than what we originally calculated (pka->user is holding) */
unsigned char *tmpEcdsa = NULL;
/* Prepare for the call to psSign. */
switch (pka->type)
{
# ifdef USE_RSA_CIPHER_SUITE
case PKA_AFTER_RSA_SIG_GEN_ELEMENT:
sigAlg = OID_RSA_PKCS15_SIG_ALG;
sigLen = privKey->keysize;
break;
case PKA_AFTER_RSA_SIG_GEN:
sigAlg = OID_RSA_TLS_SIG_ALG;
sigLen = privKey->keysize;
break;
# endif /* USE_RSA_CIPHER_SUITE */
# ifdef USE_ECC_CIPHER_SUITE
case PKA_AFTER_ECDSA_SIG_GEN:
sigAlg = OID_ECDSA_TLS_SIG_ALG;
/* pka->user is the predicted ECDSA signature size. We predicted
that one of the INTEGERs has a leading 0x00 octet, but there
may actually be 0 to 2 extra octets. So allocate 1 larger
than predicted. */
tmpEcdsa = psMalloc(ssl->hsPool, pka->user + 1);
if (tmpEcdsa == NULL)
{
return PS_MEM_FAIL;
}
# ifdef USE_DTLS
ssl->ecdsaSizeChange = 0;
# endif
sigBuf = tmpEcdsa;
/* We did not write the signature vector length octets earlier,
because we cannot completely predict the signature legnth.
Let psSign do this. */
opts.flags |= PS_SIGN_OPTS_ECDSA_INCLUDE_SIZE;
break;
# endif /* USE_ECC_CIPHER_SUITE */
default:
psTraceErrr("Unsupported type of PKA operation\n");
return PS_UNSUPPORTED_FAIL;
}
opts.userData = pka->data;
opts.flags |= PS_SIGN_OPTS_USE_PREALLOCATED_OUTBUF;
/* Compute the signature. */
rc = psSignHash(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;
psFree(tmpEcdsa, ssl->hsPool);
return rc;
}
else if (rc < 0)
{
psFree(tmpEcdsa, ssl->hsPool);
psTraceErrr("SKE signature generation failed\n");
psTraceIntInfo("Signature return code: %d\n", rc);
return MATRIXSSL_ERROR;
}
/* Signature is ready, either in tmpEcdsa 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,
tmpEcdsa,
out,
SSL_HS_SERVER_KEY_EXCHANGE);
if (rc < 0)
{
clearPkaAfter(ssl);
psFree(tmpEcdsa, ssl->hsPool);
return MATRIXSSL_ERROR;
}
}
else
{
Memcpy(pka->outbuf, tmpEcdsa, pka->user);
}
psFree(tmpEcdsa, ssl->hsPool);
}
# 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)
{
psTraceInfo("Memory allocation error ckeMsg\n");
return PS_MEM_FAIL;
}
Memcpy(ssl->ckeMsg, pka->outbuf, ssl->ckeSize);
}
# endif /* USE_DTLS */
clearPkaAfter(ssl);
return rc;
}
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:
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;
}
}
psSize_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_ecdsa_secp256r1_sha256:
return SHA256_HASH_SIZE;
case sigalg_rsa_pkcs1_sha384:
case sigalg_ecdsa_secp384r1_sha384:
return SHA384_HASH_SIZE;
case sigalg_rsa_pkcs1_sha512:
case sigalg_ecdsa_secp521r1_sha512:
return SHA512_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_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;
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;;
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 (tlsIsSupportedRsaSigAlg(sigAlgTls))
{
useRsa = PS_TRUE;
}
/* Note: this a TLS sig alg ID. */
hashLen = tlsSigAlgToHashLen(sigAlgTls);
if (hashLen <= 0)
{
goto out_decode_error;
}
}
# 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;
}
/* Now 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;
}
/* Now verify the signature. */
if (NGTD_VER(ssl, v_tls_with_pkcs15_auth))
{
opts->msgIsDigestInfo = PS_TRUE;
}
if (sigAlgTls == 0)
{
matrixSigAlg = useRsa ? OID_RSA_TLS_SIG_ALG : OID_SHA1_ECDSA_SIG;
}
else
{
matrixSigAlg = tlsSigAlgToMatrix(sigAlgTls);
}
rc = psVerifySig(ssl->hsPool,
hashBuf,
hashLen,
c,
sigLen,
pubKey,
matrixSigAlg,
&verifyResult,
opts);
if (rc < 0 || verifyResult != PS_TRUE)
{
psTraceErrr("Can't verify serverKeyExchange sig\n");
goto out_decrypt_error;
}
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
{
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
{
/* 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,
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
/*
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)
{
/* 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 5746 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->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
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 */