Files
mars-matrixssl/crypto/pubkey/pubkey_verify.c
Janne Johansson 69b5f2c6c3 MatrixSSL 4.5.1
2022-07-29 12:30:12 +03:00

356 lines
9.6 KiB
C

/**
* @file pubkey_verify.c
* @version $Format:%h%d$
*
* Algorithm-independent signature verification API.
*/
/*
* 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 "../cryptoImpl.h"
#if defined(USE_RSA) || defined(USE_ECC)
psRes_t psVerifySig(psPool_t *pool,
const unsigned char *msgIn,
psSizeL_t msgInLen,
const unsigned char *sig,
psSize_t sigLen,
psPubKey_t *key,
int32_t signatureAlgorithm,
psBool_t *verifyResult,
psVerifyOptions_t *opts)
{
# ifdef USE_RSA
unsigned char out[SHA512_HASH_SIZE] = { 0 };
# endif
# if defined(USE_SM2) && defined(USE_SM3)
unsigned char sm3_out[SM3_HASH_SIZE] = { 0 };
psSize_t sm3_out_len = SM3_HASH_SIZE;
# endif
# ifdef USE_ECC
int32 eccRet;
# endif
psRes_t rc = PS_SUCCESS;
if (pool == NULL)
{
}
*verifyResult = PS_FALSE;
switch (key->type)
{
# ifdef USE_RSA
case PS_RSA:
# ifdef USE_PKCS1_PSS
if (opts && opts->useRsaPss)
{
rc = psRsaPssVerify(pool,
msgIn,
msgInLen,
sig,
sigLen,
key,
signatureAlgorithm,
verifyResult,
opts);
if (rc != PS_SUCCESS)
{
psTraceCrypto("Error validating RSA-PSS signature\n");
goto out;
}
}
else
# endif /* USE_PKCS1_PSS */
{
if (opts && opts->msgIsDigestInfo)
{
/* RSA PKCS 1.5 verification of TLS signed elements. */
rc = pubRsaDecryptSignedElementExt(pool,
&key->key.rsa,
(unsigned char *) sig,
sigLen,
out,
msgInLen,
signatureAlgorithm,
NULL);
if (rc < 0)
{
psTraceIntCrypto("pubRsaDecryptSignedElementExt failed: %d\n",
rc);
rc = PS_FAILURE;
goto out;
}
}
else
{
/* Standard RSA PKCS #1.5 verification. */
rc = psRsaDecryptPub(pool,
&key->key.rsa,
(unsigned char *) sig,
sigLen,
out,
msgInLen,
NULL);
if (rc < 0)
{
psTraceIntCrypto("pubRsaDecryptPub failed: %d\n", rc);
rc = PS_FAILURE;
goto out;
}
}
if (memcmpct(msgIn, out, msgInLen) != 0)
{
psTraceCrypto("RSA PKCS #1.5 signature verification failed\n");
rc = PS_VERIFICATION_FAILED;
*verifyResult = PS_FALSE;
goto out;
}
}
break;
# endif /* USE_RSA */
# ifdef USE_ECC
case PS_ECC:
# if defined(USE_SM2) && defined(USE_SM3)
if (signatureAlgorithm == OID_SM3_SM2_SIG &&
!(opts && opts->msgIsDigestInfo))
{
psComputeHashForSm2(msgIn, msgInLen,
&key->key.ecc,
"1234567812345678", 16,
sm3_out, &sm3_out_len);
rc = psEccDsaVerify(pool,
&key->key.ecc,
sm3_out,
sm3_out_len,
sig,
sigLen,
&eccRet,
NULL);
}
else
# endif
{
rc = psEccDsaVerify(pool,
&key->key.ecc,
msgIn,
msgInLen,
sig,
sigLen,
&eccRet,
NULL);
}
if (rc < 0)
{
psTraceIntCrypto("psEccDsaVerify failed: %d\n", rc);
rc = PS_FAILURE;
goto out;
}
if (eccRet != 1)
{
psTraceCrypto("ECDSA signature verification failed\n");
rc = PS_VERIFICATION_FAILED;
*verifyResult = PS_FALSE;
goto out;
}
break;
# ifdef USE_ED25519
case PS_ED25519:
rc = psEd25519Verify(sig,
msgIn,
msgInLen,
key->key.ed25519.pub);
if (rc != PS_SUCCESS)
{
psTraceCrypto("Ed25519 signature verification failed\n");
rc = PS_VERIFICATION_FAILED;
*verifyResult = PS_FALSE;
goto out;
}
break;
# endif /* USE_ED25519 */
# endif /* USE_ECC */
default:
psTraceCrypto("Unsupported pubkey algorithm\n");
rc = PS_UNSUPPORTED_FAIL;
goto out;
}
*verifyResult = PS_TRUE;
out:
return rc;
}
psRes_t psHashDataAndVerifySig(psPool_t *pool,
const unsigned char *dataBegin,
const psSizeL_t dataLen,
const unsigned char *sig,
psSize_t sigLen,
psPubKey_t *key,
int32_t signatureAlgorithm,
psBool_t *verifyResult,
psVerifyOptions_t *opts)
{
unsigned char digest[SHA512_HASH_SIZE] = { 0 };
psSize_t digestLen = sizeof(digest);
psRes_t rc;
*verifyResult = PS_FALSE;
#if defined(USE_SM2) && defined(USE_SM3)
if (signatureAlgorithm == OID_SM3_SM2_SIG)
{
rc = psComputeHashForSm2(
dataBegin,
dataLen,
&key->key.ecc,
"TLSv1.3+GM+Cipher+Suite",
23,
digest,
&digestLen);
opts->msgIsDigestInfo = PS_TRUE;
}
else
#endif
{
rc = psComputeHashForSig(dataBegin, dataLen,
signatureAlgorithm, digest,
&digestLen);
}
if (rc != PS_SUCCESS)
{
return rc;
}
rc = psVerifySig(pool,
digest, digestLen,
sig, sigLen,
key, signatureAlgorithm,
verifyResult,
opts);
return rc;
}
# if defined(USE_RSA) && defined(USE_PKCS1_PSS)
static
int32_t get_pss_hash_sig_alg(psVerifyOptions_t *opts)
{
switch (opts->rsaPssHashAlg)
{
case PKCS1_SHA1_ID:
return OID_SHA1_RSA_SIG;
case PKCS1_SHA256_ID:
return OID_SHA256_RSA_SIG;
case PKCS1_SHA384_ID:
return OID_SHA384_RSA_SIG;
case PKCS1_SHA512_ID:
return OID_SHA512_RSA_SIG;
default:
return PS_UNSUPPORTED_FAIL;
}
}
# endif /* USE_PKCS1_PSS */
psRes_t psVerify(psPool_t *pool,
const unsigned char *dataBegin,
const psSizeL_t dataLen,
const unsigned char *sig,
psSize_t sigLen,
psPubKey_t *key,
int32_t signatureAlgorithm,
psBool_t *verifyResult,
psVerifyOptions_t *opts)
{
psBool_t needPreHash = PS_TRUE;
*verifyResult = PS_FALSE;
# if defined(USE_RSA) && defined(USE_PKCS1_PSS)
if (opts && opts->useRsaPss)
{
# ifdef USE_CL_RSA
/* The crypto-cl API for RSA-PSS verification does not support
pre-hashing. */
needPreHash = PS_FALSE;
# endif
if (needPreHash && signatureAlgorithm == OID_RSASSA_PSS)
{
/* psComputeHashForSig called by psHashDataAndVerifySig below
cannot operate on OID_RSASSA_PSS, since this ID does not
indicate the hash alg. So translate to one of the
OID_*_RSA_SIG IDs. */
signatureAlgorithm = get_pss_hash_sig_alg(opts);
}
}
# endif /* RSA && PKCS1_PSS */
# ifdef USE_ED25519
if (signatureAlgorithm == OID_ED25519_KEY_ALG)
{
/* The Ed25519 algorithm does not use pre-hashing. */
needPreHash = PS_FALSE;
}
# endif /* USE_ED25519 */
if (needPreHash)
{
return psHashDataAndVerifySig(pool,
dataBegin,
dataLen,
sig,
sigLen,
key,
signatureAlgorithm,
verifyResult,
opts);
}
else
{
return psVerifySig(pool,
dataBegin,
dataLen,
sig,
sigLen,
key,
signatureAlgorithm,
verifyResult,
opts);
}
}
/******************************************************************************/
#endif /* USE_RSA || USE_ECC */