From fc02003f7654bb9e7880d8946f217fae054b3d0b Mon Sep 17 00:00:00 2001 From: David Garske Date: Wed, 25 Apr 2018 13:10:53 -0700 Subject: [PATCH] Added new signature wrapper functions to allow direct use of hash `wc_SignatureVerifyHash` and `wc_SignatureGenerateHash`. These new function abstract existing signature wrapper code, so minimal code size increase. Added test cases for new functions for RSA (with and without DER encoding) and ECC. --- wolfcrypt/src/signature.c | 377 ++++++++++++++++++++-------------- wolfcrypt/test/test.c | 69 ++++++- wolfssl/wolfcrypt/signature.h | 11 + 3 files changed, 298 insertions(+), 159 deletions(-) diff --git a/wolfcrypt/src/signature.c b/wolfcrypt/src/signature.c index e5cd5c365..6d8ef5224 100644 --- a/wolfcrypt/src/signature.c +++ b/wolfcrypt/src/signature.c @@ -63,6 +63,7 @@ static int wc_SignatureDerEncode(enum wc_HashType hash_type, byte** hash_data, ret = wc_EncodeSignature(digest_buf, *hash_data, *hash_len, oid); if (ret > 0) { digest_len = ret; + ret = 0; /* Replace hash with digest (DER encoding + hash) */ XFREE(*hash_data, NULL, DYNAMIC_TYPE_TMP_BUFFER); @@ -93,7 +94,7 @@ int wc_SignatureGetSize(enum wc_SignatureType sig_type, switch(sig_type) { case WC_SIGNATURE_TYPE_ECC: #ifdef HAVE_ECC - /* Santity check that void* key is at least ecc_key in size */ + /* Sanity check that void* key is at least ecc_key in size */ if (key_len >= sizeof(ecc_key)) { sig_len = wc_ecc_sig_size((ecc_key*)key); } @@ -108,7 +109,7 @@ int wc_SignatureGetSize(enum wc_SignatureType sig_type, case WC_SIGNATURE_TYPE_RSA_W_ENC: case WC_SIGNATURE_TYPE_RSA: #ifndef NO_RSA - /* Santity check that void* key is at least RsaKey in size */ + /* Sanity check that void* key is at least RsaKey in size */ if (key_len >= sizeof(RsaKey)) { sig_len = wc_RsaEncryptSize((RsaKey*)key); } @@ -128,6 +129,114 @@ int wc_SignatureGetSize(enum wc_SignatureType sig_type, return sig_len; } +int wc_SignatureVerifyHash( + enum wc_HashType hash_type, enum wc_SignatureType sig_type, + const byte* hash_data, word32 hash_len, + const byte* sig, word32 sig_len, + const void* key, word32 key_len) +{ + int ret; + + /* Check arguments */ + if (hash_data == NULL || hash_len <= 0 || + sig == NULL || sig_len <= 0 || + key == NULL || key_len <= 0) { + return BAD_FUNC_ARG; + } + + /* Validate signature len (1 to max is okay) */ + if ((int)sig_len > wc_SignatureGetSize(sig_type, key, key_len)) { + WOLFSSL_MSG("wc_SignatureVerify: Invalid sig type/len"); + return BAD_FUNC_ARG; + } + + /* Validate hash size */ + ret = wc_HashGetDigestSize(hash_type); + if (ret < 0) { + WOLFSSL_MSG("wc_SignatureVerify: Invalid hash type/len"); + return ret; + } + ret = 0; + + /* Verify signature using hash */ + switch (sig_type) { + case WC_SIGNATURE_TYPE_ECC: + { +#if defined(HAVE_ECC) && defined(HAVE_ECC_VERIFY) + int is_valid_sig = 0; + + /* Perform verification of signature using provided ECC key */ + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &((ecc_key*)key)->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) + ret = wc_ecc_verify_hash(sig, sig_len, hash_data, hash_len, + &is_valid_sig, (ecc_key*)key); + } while (ret == WC_PENDING_E); + if (ret != 0 || is_valid_sig != 1) { + ret = SIG_VERIFY_E; + } +#else + ret = SIG_TYPE_E; +#endif + break; + } + + case WC_SIGNATURE_TYPE_RSA_W_ENC: + case WC_SIGNATURE_TYPE_RSA: + { +#ifndef NO_RSA + word32 plain_len = hash_len; + byte *plain_data; + + /* Make sure the plain text output is at least key size */ + if (plain_len < sig_len) { + plain_len = sig_len; + } + plain_data = (byte*)XMALLOC(plain_len, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (plain_data) { + /* Perform verification of signature using provided RSA key */ + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &((RsaKey*)key)->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) + ret = wc_RsaSSL_Verify(sig, sig_len, plain_data, + plain_len, (RsaKey*)key); + } while (ret == WC_PENDING_E); + if (ret >= 0) { + if ((word32)ret == hash_len && + XMEMCMP(plain_data, hash_data, hash_len) == 0) { + ret = 0; /* Success */ + } + else { + WOLFSSL_MSG("RSA Signature Verify difference!"); + ret = SIG_VERIFY_E; + } + } + XFREE(plain_data, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + else { + ret = MEMORY_E; + } +#else + ret = SIG_TYPE_E; +#endif + break; + } + + case WC_SIGNATURE_TYPE_NONE: + default: + ret = BAD_FUNC_ARG; + break; + } + + return ret; +} + int wc_SignatureVerify( enum wc_HashType hash_type, enum wc_SignatureType sig_type, const byte* data, word32 data_len, @@ -139,7 +248,8 @@ int wc_SignatureVerify( byte *hash_data = NULL; /* Check arguments */ - if (data == NULL || data_len <= 0 || sig == NULL || sig_len <= 0 || + if (data == NULL || data_len <= 0 || + sig == NULL || sig_len <= 0 || key == NULL || key_len <= 0) { return BAD_FUNC_ARG; } @@ -166,95 +276,20 @@ int wc_SignatureVerify( /* Perform hash of data */ ret = wc_Hash(hash_type, data, data_len, hash_data, hash_len); - if(ret == 0) { - /* Verify signature using hash as data */ - switch(sig_type) { - case WC_SIGNATURE_TYPE_ECC: - { -#if defined(HAVE_ECC) && defined(HAVE_ECC_VERIFY) - int is_valid_sig = 0; + if (ret == 0) { + /* Handle RSA with DER encoding */ + if (sig_type == WC_SIGNATURE_TYPE_RSA_W_ENC) { + #if defined(NO_RSA) || defined(NO_ASN) + ret = SIG_TYPE_E; + #else + ret = wc_SignatureDerEncode(hash_type, &hash_data, &hash_len); + #endif + } - /* Perform verification of signature using provided ECC key */ - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &((ecc_key*)key)->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) - ret = wc_ecc_verify_hash(sig, sig_len, hash_data, hash_len, - &is_valid_sig, (ecc_key*)key); - } while (ret == WC_PENDING_E); - if (ret != 0 || is_valid_sig != 1) { - ret = SIG_VERIFY_E; - } -#else - ret = SIG_TYPE_E; -#endif - break; - } - - case WC_SIGNATURE_TYPE_RSA_W_ENC: -#if defined(NO_RSA) || defined(NO_ASN) - ret = SIG_TYPE_E; - break; -#else - ret = wc_SignatureDerEncode(hash_type, &hash_data, &hash_len); - /* Check for error */ - if (ret < 0) { - break; - } - /* Otherwise fall-through and perform normal RSA verify against updated - * DER encoding + hash */ -#endif - FALL_THROUGH; - - case WC_SIGNATURE_TYPE_RSA: - { -#ifndef NO_RSA - word32 plain_len = hash_len; - byte *plain_data; - - /* Make sure the plain text output is at least key size */ - if (plain_len < sig_len) { - plain_len = sig_len; - } - plain_data = (byte*)XMALLOC(plain_len, NULL, DYNAMIC_TYPE_TMP_BUFFER); - if (plain_data) { - /* Perform verification of signature using provided RSA key */ - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &((RsaKey*)key)->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) - ret = wc_RsaSSL_Verify(sig, sig_len, plain_data, - plain_len, (RsaKey*)key); - } while (ret == WC_PENDING_E); - if (ret >= 0) { - if ((word32)ret == hash_len && - XMEMCMP(plain_data, hash_data, hash_len) == 0) { - ret = 0; /* Success */ - } - else { - WOLFSSL_MSG("RSA Signature Verify difference!"); - ret = SIG_VERIFY_E; - } - } - XFREE(plain_data, NULL, DYNAMIC_TYPE_TMP_BUFFER); - } - else { - ret = MEMORY_E; - } -#else - ret = SIG_TYPE_E; -#endif - break; - } - - case WC_SIGNATURE_TYPE_NONE: - default: - ret = BAD_FUNC_ARG; - break; + if (ret == 0) { + /* Verify signature using hash */ + ret = wc_SignatureVerifyHash(hash_type, sig_type, + hash_data, hash_len, sig, sig_len, key, key_len); } } @@ -265,6 +300,89 @@ int wc_SignatureVerify( return ret; } + +int wc_SignatureGenerateHash( + enum wc_HashType hash_type, enum wc_SignatureType sig_type, + const byte* hash_data, word32 hash_len, + byte* sig, word32 *sig_len, + const void* key, word32 key_len, WC_RNG* rng) +{ + int ret; + + /* Suppress possible unused arg if all signature types are disabled */ + (void)rng; + + /* Check arguments */ + if (hash_data == NULL || hash_len <= 0 || + sig == NULL || sig_len == NULL || *sig_len <= 0 || + key == NULL || key_len <= 0) { + return BAD_FUNC_ARG; + } + + /* Validate signature len (needs to be at least max) */ + if ((int)*sig_len < wc_SignatureGetSize(sig_type, key, key_len)) { + WOLFSSL_MSG("wc_SignatureGenerate: Invalid sig type/len"); + return BAD_FUNC_ARG; + } + + /* Validate hash size */ + ret = wc_HashGetDigestSize(hash_type); + if (ret < 0) { + WOLFSSL_MSG("wc_SignatureGenerate: Invalid hash type/len"); + return ret; + } + ret = 0; + + /* Create signature using hash as data */ + switch (sig_type) { + case WC_SIGNATURE_TYPE_ECC: +#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN) + /* Create signature using provided ECC key */ + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &((ecc_key*)key)->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) + ret = wc_ecc_sign_hash(hash_data, hash_len, sig, sig_len, + rng, (ecc_key*)key); + } while (ret == WC_PENDING_E); +#else + ret = SIG_TYPE_E; +#endif + break; + + case WC_SIGNATURE_TYPE_RSA_W_ENC: + case WC_SIGNATURE_TYPE_RSA: +#ifndef NO_RSA + /* Create signature using provided RSA key */ + do { + #ifdef WOLFSSL_ASYNC_CRYPT + ret = wc_AsyncWait(ret, &((RsaKey*)key)->asyncDev, + WC_ASYNC_FLAG_CALL_AGAIN); + #endif + if (ret >= 0) + ret = wc_RsaSSL_Sign(hash_data, hash_len, sig, *sig_len, + (RsaKey*)key, rng); + } while (ret == WC_PENDING_E); + if (ret >= 0) { + *sig_len = ret; + ret = 0; /* Success */ + } +#else + ret = SIG_TYPE_E; +#endif + break; + + case WC_SIGNATURE_TYPE_NONE: + default: + ret = BAD_FUNC_ARG; + break; + } + + return ret; +} + int wc_SignatureGenerate( enum wc_HashType hash_type, enum wc_SignatureType sig_type, const byte* data, word32 data_len, @@ -275,12 +393,10 @@ int wc_SignatureGenerate( word32 hash_len; byte *hash_data = NULL; - /* Suppress possible unused arg if all signature types are disabled */ - (void)rng; - /* Check arguments */ - if (data == NULL || data_len <= 0 || sig == NULL || sig_len == NULL || - *sig_len <= 0 || key == NULL || key_len <= 0) { + if (data == NULL || data_len <= 0 || + sig == NULL || sig_len == NULL || *sig_len <= 0 || + key == NULL || key_len <= 0) { return BAD_FUNC_ARG; } @@ -307,64 +423,19 @@ int wc_SignatureGenerate( /* Perform hash of data */ ret = wc_Hash(hash_type, data, data_len, hash_data, hash_len); if (ret == 0) { - /* Create signature using hash as data */ - switch(sig_type) { - case WC_SIGNATURE_TYPE_ECC: -#if defined(HAVE_ECC) && defined(HAVE_ECC_SIGN) - /* Create signature using provided ECC key */ - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &((ecc_key*)key)->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) - ret = wc_ecc_sign_hash(hash_data, hash_len, sig, sig_len, - rng, (ecc_key*)key); - } while (ret == WC_PENDING_E); -#else - ret = SIG_TYPE_E; -#endif - break; + /* Handle RSA with DER encoding */ + if (sig_type == WC_SIGNATURE_TYPE_RSA_W_ENC) { + #if defined(NO_RSA) || defined(NO_ASN) + ret = SIG_TYPE_E; + #else + ret = wc_SignatureDerEncode(hash_type, &hash_data, &hash_len); + #endif + } - case WC_SIGNATURE_TYPE_RSA_W_ENC: -#if defined(NO_RSA) || defined(NO_ASN) - ret = SIG_TYPE_E; - break; -#else - ret = wc_SignatureDerEncode(hash_type, &hash_data, &hash_len); - /* Check for error */ - if (ret < 0) { - break; - } - /* Otherwise fall-through and perform normal RSA sign against updated - * DER encoding + hash */ -#endif - FALL_THROUGH; - case WC_SIGNATURE_TYPE_RSA: -#ifndef NO_RSA - /* Create signature using provided RSA key */ - do { - #ifdef WOLFSSL_ASYNC_CRYPT - ret = wc_AsyncWait(ret, &((RsaKey*)key)->asyncDev, - WC_ASYNC_FLAG_CALL_AGAIN); - #endif - if (ret >= 0) - ret = wc_RsaSSL_Sign(hash_data, hash_len, sig, *sig_len, - (RsaKey*)key, rng); - } while (ret == WC_PENDING_E); - if (ret >= 0) { - *sig_len = ret; - ret = 0; /* Success */ - } -#else - ret = SIG_TYPE_E; -#endif - break; - - case WC_SIGNATURE_TYPE_NONE: - default: - ret = BAD_FUNC_ARG; - break; + if (ret == 0) { + /* Generate signature using hash */ + ret = wc_SignatureGenerateHash(hash_type, sig_type, + hash_data, hash_len, sig, sig_len, key, key_len, rng); } } diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index ae7dd0716..0918b3ea0 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -8205,7 +8205,23 @@ static int rsa_sig_test(RsaKey* key, word32 keyLen, int modLen, WC_RNG* rng) { int ret; word32 sigSz; - byte in[] = "Everyone gets Friday off."; + const byte in[] = "Everyone gets Friday off."; + const byte hash[] = { + 0xf2, 0x02, 0x95, 0x65, 0xcb, 0xf6, 0x2a, 0x59, + 0x39, 0x2c, 0x05, 0xff, 0x0e, 0x29, 0xaf, 0xfe, + 0x47, 0x33, 0x8c, 0x99, 0x8d, 0x58, 0x64, 0x83, + 0xa6, 0x58, 0x0a, 0x33, 0x0b, 0x84, 0x5f, 0x5f + }; + const byte hashEnc[] = { + 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, + 0x00, 0x04, 0x20, + + 0xf2, 0x02, 0x95, 0x65, 0xcb, 0xf6, 0x2a, 0x59, + 0x39, 0x2c, 0x05, 0xff, 0x0e, 0x29, 0xaf, 0xfe, + 0x47, 0x33, 0x8c, 0x99, 0x8d, 0x58, 0x64, 0x83, + 0xa6, 0x58, 0x0a, 0x33, 0x0b, 0x84, 0x5f, 0x5f + }; word32 inLen = (word32)XSTRLEN((char*)in); byte out[256]; @@ -8316,7 +8332,7 @@ static int rsa_sig_test(RsaKey* key, word32 keyLen, int modLen, WC_RNG* rng) if (ret != 0) return -5358; - sigSz = sizeof(out); + sigSz = (word32)sizeof(out); ret = wc_SignatureGenerate(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_RSA_W_ENC, in, inLen, out, &sigSz, key, keyLen, rng); if (ret != 0) @@ -8333,6 +8349,30 @@ static int rsa_sig_test(RsaKey* key, word32 keyLen, int modLen, WC_RNG* rng) if (ret == 0) return -5361; + + /* check hash functions */ + sigSz = (word32)sizeof(out); + ret = wc_SignatureGenerateHash(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_RSA, + hash, (int)sizeof(hash), out, &sigSz, key, keyLen, rng); + if (ret != 0) + return -5362; + + ret = wc_SignatureVerifyHash(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_RSA, + hash, (int)sizeof(hash), out, (word32)modLen, key, keyLen); + if (ret != 0) + return -5363; + + sigSz = (word32)sizeof(out); + ret = wc_SignatureGenerateHash(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_RSA_W_ENC, + hashEnc, (int)sizeof(hashEnc), out, &sigSz, key, keyLen, rng); + if (ret != 0) + return -5364; + + ret = wc_SignatureVerifyHash(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_RSA_W_ENC, + hashEnc, (int)sizeof(hashEnc), out, (word32)modLen, key, keyLen); + if (ret != 0) + return -5365; + return 0; } #endif /* !NO_SIG_WRAPPER */ @@ -14589,25 +14629,42 @@ static int ecc_sig_test(WC_RNG* rng, ecc_key* key) word32 sigSz; int size; byte out[ECC_MAX_SIG_SIZE]; - byte in[] = "Everyone gets Friday off."; + byte in[] = "Everyone gets Friday off."; + const byte hash[] = { + 0xf2, 0x02, 0x95, 0x65, 0xcb, 0xf6, 0x2a, 0x59, + 0x39, 0x2c, 0x05, 0xff, 0x0e, 0x29, 0xaf, 0xfe, + 0x47, 0x33, 0x8c, 0x99, 0x8d, 0x58, 0x64, 0x83, + 0xa6, 0x58, 0x0a, 0x33, 0x0b, 0x84, 0x5f, 0x5f + }; word32 inLen = (word32)XSTRLEN((char*)in); size = wc_ecc_sig_size(key); ret = wc_SignatureGetSize(WC_SIGNATURE_TYPE_ECC, key, sizeof(*key)); if (ret != size) - return -6628; + return -6740; sigSz = (word32)ret; ret = wc_SignatureGenerate(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_ECC, in, inLen, out, &sigSz, key, sizeof(*key), rng); if (ret != 0) - return -6629; + return -6741; ret = wc_SignatureVerify(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_ECC, in, inLen, out, sigSz, key, sizeof(*key)); if (ret != 0) - return -6630; + return -6742; + + sigSz = (word32)sizeof(out); + ret = wc_SignatureGenerateHash(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_ECC, + hash, (int)sizeof(hash), out, &sigSz, key, sizeof(*key), rng); + if (ret != 0) + return -6743; + + ret = wc_SignatureVerifyHash(WC_HASH_TYPE_SHA256, WC_SIGNATURE_TYPE_ECC, + hash, (int)sizeof(hash), out, sigSz, key, sizeof(*key)); + if (ret != 0) + return -6744; return 0; } diff --git a/wolfssl/wolfcrypt/signature.h b/wolfssl/wolfcrypt/signature.h index 43b93abd7..ef01e6085 100644 --- a/wolfssl/wolfcrypt/signature.h +++ b/wolfssl/wolfcrypt/signature.h @@ -45,12 +45,23 @@ enum wc_SignatureType { WOLFSSL_API int wc_SignatureGetSize(enum wc_SignatureType sig_type, const void* key, word32 key_len); +WOLFSSL_API int wc_SignatureVerifyHash( + enum wc_HashType hash_type, enum wc_SignatureType sig_type, + const byte* hash_data, word32 hash_len, + const byte* sig, word32 sig_len, + const void* key, word32 key_len); + WOLFSSL_API int wc_SignatureVerify( enum wc_HashType hash_type, enum wc_SignatureType sig_type, const byte* data, word32 data_len, const byte* sig, word32 sig_len, const void* key, word32 key_len); +WOLFSSL_API int wc_SignatureGenerateHash( + enum wc_HashType hash_type, enum wc_SignatureType sig_type, + const byte* hash_data, word32 hash_len, + byte* sig, word32 *sig_len, + const void* key, word32 key_len, WC_RNG* rng); WOLFSSL_API int wc_SignatureGenerate( enum wc_HashType hash_type, enum wc_SignatureType sig_type, const byte* data, word32 data_len,