/** * @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 */