From 3ab5ccd04ffe837862caa412d9d951f93fc2dc2e Mon Sep 17 00:00:00 2001 From: Masashi Honma Date: Tue, 26 Apr 2022 06:19:56 +0900 Subject: [PATCH] Add support for EVP_PKEY_sign/verify functionality (#5056) * Fix wolfSSL_RSA_public_decrypt() return value to match Openssl * Add support for EVP_PKEY_verify_init() and EVP_PKEY_verify() * wpa_supplicant SAE public key functionality requires this function. * Add DSA support for EVP_PKEY_sign/verify() * Add ECDSA support for EVP_PKEY_sign/verify() * Add tests for EVP_PKEY_sign_verify() * Fix "siglen = keySz" at error cases * Fix wolfSSL_DSA_do_sign() usage 1. Check wolfSSL_BN_num_bytes() return value 2. Check siglen size 3. Double the siglen * Check return code of wolfSSL_i2d_ECDSA_SIG() in wolfSSL_EVP_DigestSignFinal() * Add size calculations to `wolfSSL_EVP_PKEY_sign` * Add size checks to wolfSSL_EVP_PKEY_sign before writing out signature * Use wc_ecc_sig_size() to calculate ECC signature size Signed-off-by: Masashi Honma Co-authored-by: Juliusz Sosinowicz --- src/ssl.c | 18 ++-- tests/api.c | 190 ++++++++++++++++++++++++--------- wolfcrypt/src/evp.c | 239 +++++++++++++++++++++++++++++++++++++----- wolfssl/openssl/evp.h | 6 ++ 4 files changed, 372 insertions(+), 81 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index cbd456d83..465fa16d5 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -28632,6 +28632,8 @@ int wolfSSL_RSA_sign_ex(int type, const unsigned char* m, unsigned int mLen, unsigned char* sigRet, unsigned int* sigLen, WOLFSSL_RSA* rsa, int flag) { + if (sigLen != NULL) + *sigLen = RSA_MAX_SIZE / CHAR_BIT; /* No size checking in this API */ return wolfSSL_RSA_sign_generic_padding(type, m, mLen, sigRet, sigLen, rsa, flag, RSA_PKCS1_PADDING); } @@ -28710,6 +28712,10 @@ int wolfSSL_RSA_sign_generic_padding(int type, const unsigned char* m, if (outLen == 0) { WOLFSSL_MSG("Bad RSA size"); } + else if (outLen > *sigLen) { + WOLFSSL_MSG("Output buffer too small"); + return WOLFSSL_FAILURE; + } else if (wc_InitRng(tmpRNG) == 0) { rng = tmpRNG; initTmpRng = 1; @@ -28842,7 +28848,7 @@ int wolfSSL_RSA_verify_ex(int type, const unsigned char* m, int ret = WOLFSSL_FAILURE; unsigned char *sigRet = NULL; unsigned char *sigDec = NULL; - unsigned int len = 0; + unsigned int len = sigLen; int verLen; #if (!defined(HAVE_FIPS) || (defined(FIPS_VERSION_GE) && \ FIPS_VERSION_GE(5,1))) && !defined(HAVE_SELFTEST) @@ -43113,7 +43119,7 @@ int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from, if (rsa == NULL || rsa->internal == NULL || from == NULL) { WOLFSSL_MSG("Bad function arguments"); - return WOLFSSL_FAILURE; + return WOLFSSL_FATAL_ERROR; } #if !defined(HAVE_SELFTEST) && (!defined(HAVE_FIPS) || \ @@ -43133,7 +43139,7 @@ int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from, break; default: WOLFSSL_MSG("RSA_public_decrypt unsupported padding"); - return WOLFSSL_FAILURE; + return WOLFSSL_FATAL_ERROR; } #endif @@ -43142,7 +43148,7 @@ int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from, if (SetRsaInternal(rsa) != WOLFSSL_SUCCESS) { WOLFSSL_MSG("SetRsaInternal failed"); - return WOLFSSL_FAILURE; + return WOLFSSL_FATAL_ERROR; } } @@ -43159,14 +43165,14 @@ int wolfSSL_RSA_public_decrypt(int flen, const unsigned char* from, } else { WOLFSSL_MSG("RSA_public_decrypt pad type not supported in FIPS"); - ret = WOLFSSL_FAILURE; + ret = WOLFSSL_FATAL_ERROR; } #endif WOLFSSL_LEAVE("RSA_public_decrypt", ret); if (ret <= 0) { - ret = WOLFSSL_FAILURE; + ret = WOLFSSL_FATAL_ERROR; } return ret; } diff --git a/tests/api.c b/tests/api.c index 41b2008aa..ac192e5cb 100644 --- a/tests/api.c +++ b/tests/api.c @@ -47011,73 +47011,163 @@ static void test_wolfSSL_EVP_PKEY_encrypt(void) printf(resultFmt, passed); #endif } -static void test_wolfSSL_EVP_PKEY_sign(void) +static void test_wolfSSL_EVP_PKEY_sign_verify(void) { -#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ - !defined(HAVE_FAST_RSA) && !defined(HAVE_SELFTEST) -#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) - WOLFSSL_RSA* rsa = NULL; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + WOLFSSL_DSA* dsa = NULL; +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ WOLFSSL_EVP_PKEY* pkey = NULL; WOLFSSL_EVP_PKEY_CTX* ctx = NULL; + WOLFSSL_EVP_PKEY_CTX* ctx_verify = NULL; const char* in = "What is easy to do is easy not to do."; size_t inlen = XSTRLEN(in); byte hash[SHA256_DIGEST_LENGTH] = {0}; SHA256_CTX c; byte* sig = NULL; byte* sigVerify = NULL; - size_t siglen = 0; - size_t rsaKeySz = 2048/8; /* Bytes */ - - printf(testingFmt, "wolfSSL_EVP_PKEY_sign()"); - sig = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); - AssertNotNull(sig); - XMEMSET(sig, 0, rsaKeySz); - AssertNotNull(sigVerify = (byte*)XMALLOC(rsaKeySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); - XMEMSET(sigVerify, 0, rsaKeySz); - - /* Generate hash */ - SHA256_Init(&c); - SHA256_Update(&c, in, inlen); - SHA256_Final(hash, &c); -#ifdef WOLFSSL_SMALL_STACK_CACHE - /* workaround for small stack cache case */ - wc_Sha256Free((wc_Sha256*)&c); + size_t siglen; + size_t siglenOnlyLen; + size_t keySz = 2048/8; /* Bytes */ + int encs[3] = {0}; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_FAST_RSA) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + encs[0] = EVP_PKEY_RSA; +#endif +#endif +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + encs[1] = EVP_PKEY_DSA; +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + encs[2] = EVP_PKEY_EC; +#endif #endif - AssertNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); - AssertNotNull(pkey = wolfSSL_EVP_PKEY_new()); - AssertIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); - AssertNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL)); - AssertIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); - AssertIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), + printf(testingFmt, "wolfSSL_EVP_PKEY_sign_verify()"); + AssertNotNull(sig = + (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); + AssertNotNull(sigVerify = + (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER)); + + for (int i = 0; i < 3; i++) { + if (encs[i] == 0) + continue; + + siglen = keySz; + XMEMSET(sig, 0, keySz); + XMEMSET(sigVerify, 0, keySz); + + /* Generate hash */ + SHA256_Init(&c); + SHA256_Update(&c, in, inlen); + SHA256_Final(hash, &c); +#ifdef WOLFSSL_SMALL_STACK_CACHE + /* workaround for small stack cache case */ + wc_Sha256Free((wc_Sha256*)&c); +#endif + + /* Generate key */ + AssertNotNull(pkey = EVP_PKEY_new()); + switch (encs[i]) { + case EVP_PKEY_RSA: +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_FAST_RSA) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + { + WOLFSSL_RSA* rsa = NULL; + AssertNotNull(rsa = RSA_generate_key(2048, 3, NULL, NULL)); + AssertIntEQ(EVP_PKEY_assign_RSA(pkey, rsa), WOLFSSL_SUCCESS); + } +#endif +#endif + break; + case EVP_PKEY_DSA: +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + AssertNotNull(dsa = DSA_new()); + AssertIntEQ(DSA_generate_parameters_ex(dsa, 2048, + NULL, 0, NULL, NULL, NULL), 1); + AssertIntEQ(DSA_generate_key(dsa), 1); + AssertIntEQ(EVP_PKEY_set1_DSA(pkey, dsa), WOLFSSL_SUCCESS); +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ + break; + case EVP_PKEY_EC: +#if defined(OPENSSL_EXTRA) && defined(HAVE_ECC) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + { + WOLFSSL_EC_KEY* ecKey = NULL; + AssertNotNull(ecKey = EC_KEY_new()); + AssertIntEQ(EC_KEY_generate_key(ecKey), 1); + AssertIntEQ( + EVP_PKEY_assign_EC_KEY(pkey, ecKey), WOLFSSL_SUCCESS); + } +#endif +#endif + break; + } + AssertNotNull(ctx = EVP_PKEY_CTX_new(pkey, NULL)); + AssertIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_FAST_RSA) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + if (encs[i] == EVP_PKEY_RSA) + AssertIntEQ(EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING), + WOLFSSL_SUCCESS); +#endif +#endif + + /* Check returning only length */ + AssertIntEQ(EVP_PKEY_sign(ctx, NULL, &siglenOnlyLen, hash, + SHA256_DIGEST_LENGTH), WOLFSSL_SUCCESS); + AssertIntGT(siglenOnlyLen, 0); + /* Sign data */ + AssertIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, hash, + SHA256_DIGEST_LENGTH), WOLFSSL_SUCCESS); + AssertIntGE(siglenOnlyLen, siglen); + + /* Verify signature */ + AssertNotNull(ctx_verify = EVP_PKEY_CTX_new(pkey, NULL)); + AssertIntEQ(EVP_PKEY_verify_init(ctx_verify), WOLFSSL_SUCCESS); +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && defined(WOLFSSL_KEY_GEN) && \ + !defined(HAVE_FAST_RSA) && !defined(HAVE_SELFTEST) +#if !defined(HAVE_FIPS) || (defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION>2)) + if (encs[i] == EVP_PKEY_RSA) + AssertIntEQ( + EVP_PKEY_CTX_set_rsa_padding(ctx_verify, RSA_PKCS1_PADDING), WOLFSSL_SUCCESS); +#endif +#endif + AssertIntEQ(EVP_PKEY_verify( + ctx_verify, sig, siglen, hash, SHA256_DIGEST_LENGTH), + WOLFSSL_SUCCESS); + XMEMSET(hash, 0, SHA256_DIGEST_LENGTH); + AssertIntEQ(EVP_PKEY_verify( + ctx_verify, sig, siglen, hash, SHA256_DIGEST_LENGTH), + WOLFSSL_FAILURE); + EVP_PKEY_CTX_free(ctx_verify); - /* Sign data */ - AssertIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, hash, SHA256_DIGEST_LENGTH), - WOLFSSL_SUCCESS); - /* Verify signature. - EVP_PKEY_verify() doesn't exist yet, so use RSA_public_decrypt(). */ - AssertIntEQ(RSA_public_decrypt((int)siglen, sig, sigVerify, - rsa, RSA_PKCS1_PADDING), SHA256_DIGEST_LENGTH); + /* error cases */ + siglen = keySz; /* Reset because sig size may vary slightly */ + AssertIntNE(EVP_PKEY_sign_init(NULL), WOLFSSL_SUCCESS); + AssertIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); + AssertIntNE(EVP_PKEY_sign(NULL, sig, &siglen, (byte*)in, inlen), + WOLFSSL_SUCCESS); + AssertIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, (byte*)in, inlen), + WOLFSSL_SUCCESS); - AssertIntEQ(XMEMCMP(hash, sigVerify, SHA256_DIGEST_LENGTH), 0); - /* error cases */ + EVP_PKEY_free(pkey); +#if !defined (NO_DSA) && !defined(HAVE_SELFTEST) && defined(WOLFSSL_KEY_GEN) + DSA_free(dsa); + dsa = NULL; +#endif /* !NO_DSA && !HAVE_SELFTEST && WOLFSSL_KEY_GEN */ + EVP_PKEY_CTX_free(ctx); + } - AssertIntNE(EVP_PKEY_sign_init(NULL), WOLFSSL_SUCCESS); - ctx->pkey->type = EVP_PKEY_RSA; - AssertIntEQ(EVP_PKEY_sign_init(ctx), WOLFSSL_SUCCESS); - AssertIntNE(EVP_PKEY_sign(NULL, sig, &siglen, (byte*)in, inlen), - WOLFSSL_SUCCESS); - AssertIntEQ(EVP_PKEY_sign(ctx, sig, &siglen, (byte*)in, inlen), - WOLFSSL_SUCCESS); - - EVP_PKEY_free(pkey); - EVP_PKEY_CTX_free(ctx); XFREE(sig, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); XFREE(sigVerify, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); -#endif /* !HAVE_FIPS || HAVE_FIPS_VERSION > 2 */ printf(resultFmt, passed); -#endif +#endif /* OPENSSL_EXTRA || OPENSSL_EXTRA_X509_SMALL */ } static void test_EVP_PKEY_rsa(void) @@ -53919,7 +54009,7 @@ void ApiTest(void) /* OpenSSL EVP_PKEY API tests */ test_EVP_PKEY_rsa(); test_wolfSSL_EVP_PKEY_encrypt(); - test_wolfSSL_EVP_PKEY_sign(); + test_wolfSSL_EVP_PKEY_sign_verify(); test_EVP_PKEY_ec(); test_EVP_PKEY_cmp(); /* OpenSSL error API tests */ diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 11311c701..be59d86c4 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1859,13 +1859,27 @@ int wolfSSL_EVP_PKEY_sign_init(WOLFSSL_EVP_PKEY_CTX *ctx) return ret; switch (ctx->pkey->type) { +#if !defined(NO_RSA) && !defined(HAVE_USER_RSA) case EVP_PKEY_RSA: ctx->op = EVP_PKEY_OP_SIGN; ret = WOLFSSL_SUCCESS; break; +#endif /* NO_RSA */ + +#ifndef NO_DSA + case EVP_PKEY_DSA: + ctx->op = EVP_PKEY_OP_SIGN; + ret = WOLFSSL_SUCCESS; + break; +#endif /* NO_DSA */ + +#ifdef HAVE_ECC case EVP_PKEY_EC: - WOLFSSL_MSG("not implemented"); - FALL_THROUGH; + ctx->op = EVP_PKEY_OP_SIGN; + ret = WOLFSSL_SUCCESS; + break; +#endif /* HAVE_ECC */ + default: ret = -2; } @@ -1882,41 +1896,208 @@ int wolfSSL_EVP_PKEY_sign_init(WOLFSSL_EVP_PKEY_CTX *ctx) int wolfSSL_EVP_PKEY_sign(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen) { - int len = 0; - WOLFSSL_MSG("wolfSSL_EVP_PKEY_sign"); - if (!ctx || ctx->op != EVP_PKEY_OP_SIGN || !ctx->pkey) + if (!ctx || ctx->op != EVP_PKEY_OP_SIGN || !ctx->pkey || !siglen) return WOLFSSL_FAILURE; (void)sig; (void)siglen; (void)tbs; (void)tbslen; - (void)len; switch (ctx->pkey->type) { #if !defined(NO_RSA) && !defined(HAVE_USER_RSA) - case EVP_PKEY_RSA: - len = wolfSSL_RSA_private_encrypt((int)tbslen, tbs, sig, - ctx->pkey->rsa, ctx->padding); - if (len < 0) - break; - else { - *siglen = len; + case EVP_PKEY_RSA: { + int len; + unsigned int usiglen = (unsigned int)*siglen; + if (!sig) { + if (!ctx->pkey->rsa) + return WOLFSSL_FAILURE; + len = wc_RsaEncryptSize((RsaKey*)ctx->pkey->rsa->internal); + if (len < 0) + return WOLFSSL_FAILURE; + *siglen = (size_t)len; return WOLFSSL_SUCCESS; } + /* wolfSSL_RSA_sign_generic_padding performs a check that the output + * sig buffer is large enough */ + if (wolfSSL_RSA_sign_generic_padding(WC_HASH_TYPE_NONE, tbs, + (unsigned int)tbslen, sig, &usiglen, ctx->pkey->rsa, 1, ctx->padding) + != WOLFSSL_SUCCESS) + return WOLFSSL_FAILURE; + *siglen = (size_t)usiglen; + return WOLFSSL_SUCCESS; + } #endif /* NO_RSA */ - case EVP_PKEY_EC: - WOLFSSL_MSG("not implemented"); - FALL_THROUGH; +#ifndef NO_DSA + case EVP_PKEY_DSA: { + int bytes; + int ret; + if (!ctx->pkey->dsa) + return WOLFSSL_FAILURE; + bytes = wolfSSL_BN_num_bytes(ctx->pkey->dsa->q); + if (bytes == WOLFSSL_FAILURE) + return WOLFSSL_FAILURE; + bytes *= 2; + if (!sig) { + *siglen = bytes; + return WOLFSSL_SUCCESS; + } + if ((int)*siglen < bytes) + return WOLFSSL_FAILURE; + ret = wolfSSL_DSA_do_sign(tbs, sig, ctx->pkey->dsa); + /* wolfSSL_DSA_do_sign() can return WOLFSSL_FATAL_ERROR */ + if (ret != WOLFSSL_SUCCESS) + return ret; + if (bytes == WOLFSSL_FAILURE) + return WOLFSSL_FAILURE; + *siglen = bytes; + return WOLFSSL_SUCCESS; + } +#endif /* NO_DSA */ + +#ifdef HAVE_ECC + case EVP_PKEY_EC: { + int ret; + WOLFSSL_ECDSA_SIG *ecdsaSig; + if (!sig) { + WOLFSSL_EC_KEY *key = ctx->pkey->ecc; + ecc_key* eckey; + if (!key) + return WOLFSSL_FAILURE; + /* set internal key if not done */ + if (key->inSet == 0 && SetECKeyInternal(key) != WOLFSSL_SUCCESS) + return WOLFSSL_FAILURE; + eckey = (ecc_key*)ctx->pkey->ecc->internal; + if (!eckey) + return WOLFSSL_FAILURE; + ret = wc_ecc_sig_size(eckey); + if (ret == 0) + return WOLFSSL_FAILURE; + *siglen = ret; + return WOLFSSL_SUCCESS; + } + ecdsaSig = wolfSSL_ECDSA_do_sign(tbs, (int)tbslen, ctx->pkey->ecc); + if (ecdsaSig == NULL) + return WOLFSSL_FAILURE; + ret = wolfSSL_i2d_ECDSA_SIG(ecdsaSig, NULL); + if (ret == 0 || ret > (int)*siglen) { + wolfSSL_ECDSA_SIG_free(ecdsaSig); + return WOLFSSL_FAILURE; + } + ret = wolfSSL_i2d_ECDSA_SIG(ecdsaSig, &sig); + wolfSSL_ECDSA_SIG_free(ecdsaSig); + if (ret == 0) + return WOLFSSL_FAILURE; + *siglen = ret; + return WOLFSSL_SUCCESS; + } +#endif /* HAVE_ECC */ + default: break; } return WOLFSSL_FAILURE; } +/****************************************************************************** +* wolfSSL_EVP_PKEY_verify_init - initializes a public key algorithm context for +* a verification operation. +* +* RETURNS: +* returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure. In particular +* a return value of -2 indicates the operation is not supported by the public +* key algorithm. +*/ + +int wolfSSL_EVP_PKEY_verify_init(WOLFSSL_EVP_PKEY_CTX *ctx) +{ + WOLFSSL_MSG("wolfSSL_EVP_PKEY_verify_init"); + + if (!ctx || !ctx->pkey) + return WOLFSSL_FAILURE; + + switch (ctx->pkey->type) { +#if !defined(NO_RSA) && !defined(HAVE_USER_RSA) + case EVP_PKEY_RSA: + ctx->op = EVP_PKEY_OP_VERIFY; + return WOLFSSL_SUCCESS; +#endif /* NO_RSA */ + +#ifndef NO_DSA + case EVP_PKEY_DSA: + ctx->op = EVP_PKEY_OP_VERIFY; + return WOLFSSL_SUCCESS; +#endif /* NO_DSA */ + +#ifdef HAVE_ECC + case EVP_PKEY_EC: + ctx->op = EVP_PKEY_OP_VERIFY; + return WOLFSSL_SUCCESS; +#endif /* HAVE_ECC */ + + default: + return -2; + } +} + +/****************************************************************************** +* wolfSSL_EVP_PKEY_verify - verifies a signature using ctx +* +* RETURNS: +* returns WOLFSSL_SUCCESS on success, WOLFSSL_FAILURE on failure. In particular +* a return value of -2 indicates the operation is not supported by the public +* key algorithm. +*/ + +int wolfSSL_EVP_PKEY_verify(WOLFSSL_EVP_PKEY_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, + size_t tbslen) +{ + WOLFSSL_MSG("wolfSSL_EVP_PKEY_verify"); + + if (!ctx || ctx->op != EVP_PKEY_OP_VERIFY || !ctx->pkey) + return WOLFSSL_FAILURE; + + switch (ctx->pkey->type) { +#if !defined(NO_RSA) && !defined(HAVE_USER_RSA) + case EVP_PKEY_RSA: + return wolfSSL_RSA_verify_ex(WC_HASH_TYPE_NONE, tbs, + (unsigned int)tbslen, sig, (unsigned int)siglen, ctx->pkey->rsa, + ctx->padding); +#endif /* NO_RSA */ + +#ifndef NO_DSA + case EVP_PKEY_DSA: { + int dsacheck = 0; + if (wolfSSL_DSA_do_verify(tbs, (unsigned char *)sig, ctx->pkey->dsa, + &dsacheck) != WOLFSSL_SUCCESS || dsacheck != 1) + return WOLFSSL_FAILURE; + return WOLFSSL_SUCCESS; + } +#endif /* NO_DSA */ + +#ifdef HAVE_ECC + case EVP_PKEY_EC: { + int ret; + WOLFSSL_ECDSA_SIG *ecdsaSig = wolfSSL_d2i_ECDSA_SIG( + NULL, (const unsigned char **)&sig, (long)siglen); + if (ecdsaSig == NULL) + return WOLFSSL_FAILURE; + ret = wolfSSL_ECDSA_do_verify(tbs, (int)tbslen, ecdsaSig, + ctx->pkey->ecc); + wolfSSL_ECDSA_SIG_free(ecdsaSig); + return ret; + } +#endif /* HAVE_ECC */ + + default: + return -2; + } +} + /* Get the size in bits for WOLFSSL_EVP_PKEY key * * pkey WOLFSSL_EVP_PKEY structure to get key size of @@ -2711,14 +2892,18 @@ int wolfSSL_EVP_SignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sigret, } #endif /* NO_RSA */ #ifndef NO_DSA - case EVP_PKEY_DSA: - if (wolfSSL_DSA_do_sign(md, sigret, pkey->dsa) == WOLFSSL_SUCCESS) { - *siglen = wolfSSL_BN_num_bytes(pkey->dsa->q); - return WOLFSSL_SUCCESS; - } - else { + case EVP_PKEY_DSA: { + int bytes; + ret = wolfSSL_DSA_do_sign(md, sigret, pkey->dsa); + /* wolfSSL_DSA_do_sign() can return WOLFSSL_FATAL_ERROR */ + if (ret != WOLFSSL_SUCCESS) + return ret; + bytes = wolfSSL_BN_num_bytes(pkey->dsa->q); + if (bytes == WOLFSSL_FAILURE || (int)*siglen < bytes * 2) return WOLFSSL_FAILURE; - } + *siglen = bytes * 2; + return WOLFSSL_SUCCESS; + } #endif case EVP_PKEY_EC: WOLFSSL_MSG("not implemented"); @@ -3170,7 +3355,7 @@ int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig, switch (ctx->pctx->pkey->type) { #if !defined(NO_RSA) && !defined(HAVE_USER_RSA) case EVP_PKEY_RSA: { - unsigned int sigSz; + unsigned int sigSz = (unsigned int)*siglen; int nid; const WOLFSSL_EVP_MD *md = wolfSSL_EVP_MD_CTX_md(ctx); if (md == NULL) @@ -3188,13 +3373,17 @@ int wolfSSL_EVP_DigestSignFinal(WOLFSSL_EVP_MD_CTX *ctx, unsigned char *sig, #ifdef HAVE_ECC case EVP_PKEY_EC: { + int len; WOLFSSL_ECDSA_SIG *ecdsaSig; ecdsaSig = wolfSSL_ECDSA_do_sign(digest, hashLen, ctx->pctx->pkey->ecc); if (ecdsaSig == NULL) break; - *siglen = wolfSSL_i2d_ECDSA_SIG(ecdsaSig, &sig); + len = wolfSSL_i2d_ECDSA_SIG(ecdsaSig, &sig); wolfSSL_ECDSA_SIG_free(ecdsaSig); + if (len == 0) + break; + *siglen = len; ret = WOLFSSL_SUCCESS; break; } diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 18e04097f..523b31576 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -376,6 +376,7 @@ enum { #define NID_dsa EVP_PKEY_DSA #define EVP_PKEY_OP_SIGN (1 << 3) +#define EVP_PKEY_OP_VERIFY (1 << 5) #define EVP_PKEY_OP_ENCRYPT (1 << 6) #define EVP_PKEY_OP_DECRYPT (1 << 7) #define EVP_PKEY_OP_DERIVE (1 << 8) @@ -593,6 +594,9 @@ WOLFSSL_API const unsigned char* wolfSSL_EVP_PKEY_get0_hmac(const WOLFSSL_EVP_PK WOLFSSL_API int wolfSSL_EVP_PKEY_sign_init(WOLFSSL_EVP_PKEY_CTX *ctx); WOLFSSL_API int wolfSSL_EVP_PKEY_sign(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen); +WOLFSSL_API int wolfSSL_EVP_PKEY_verify_init(WOLFSSL_EVP_PKEY_CTX *ctx); +WOLFSSL_API int wolfSSL_EVP_PKEY_verify(WOLFSSL_EVP_PKEY_CTX *ctx, const unsigned char *sig, + size_t siglen, const unsigned char *tbs, size_t tbslen); WOLFSSL_API int wolfSSL_EVP_PKEY_paramgen_init(WOLFSSL_EVP_PKEY_CTX *ctx); WOLFSSL_API int wolfSSL_EVP_PKEY_CTX_set_ec_paramgen_curve_nid(WOLFSSL_EVP_PKEY_CTX *ctx, int nid); @@ -948,6 +952,8 @@ WOLFSSL_API int wolfSSL_EVP_SignInit_ex(WOLFSSL_EVP_MD_CTX* ctx, #define EVP_MD_CTX_copy_ex wolfSSL_EVP_MD_CTX_copy_ex #define EVP_PKEY_sign_init wolfSSL_EVP_PKEY_sign_init #define EVP_PKEY_sign wolfSSL_EVP_PKEY_sign +#define EVP_PKEY_verify_init wolfSSL_EVP_PKEY_verify_init +#define EVP_PKEY_verify wolfSSL_EVP_PKEY_verify #define EVP_PKEY_paramgen_init wolfSSL_EVP_PKEY_paramgen_init #define EVP_PKEY_CTX_set_ec_param_enc wolfSSL_EVP_PKEY_CTX_set_ec_param_enc #define EVP_PKEY_CTX_set_ec_paramgen_curve_nid wolfSSL_EVP_PKEY_CTX_set_ec_paramgen_curve_nid