From 065ae0162c2c91b9d9a68c5bfe864e969dc6da0a Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 4 Jun 2024 18:33:30 -0700 Subject: [PATCH] RSA Verify Refactor 1. Duplicated the function wolfSSH_RsaVerify() into wolfSSH_RsaVerify_2() to handle the whole verify process including wrapping the digest with the RSA wrapper. 2. If the signature to verify is short, pad it to the key length with leading zeros. Some implementations of SSH will prune leading zeros from an mpint value as a string for the signature. 3. Swapped one case of needing to verify a signature to use the new function. Note: this is a WIP. Testing the new function, then reusing it where needed. --- src/internal.c | 166 +++++++++++++++++++++++++++++---------------- wolfssh/internal.h | 3 + 2 files changed, 109 insertions(+), 60 deletions(-) diff --git a/src/internal.c b/src/internal.c index ea4028817..d7f4621c3 100644 --- a/src/internal.c +++ b/src/internal.c @@ -5798,10 +5798,6 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, enum wc_HashType hashId, byte* digest, word32 digestSz) { - enum wc_HashType enmhashId = hashId; - byte *checkDigest = NULL; - byte *encDigest = NULL; - int checkDigestSz; const byte* publicKeyType; word32 publicKeyTypeSz = 0; const byte* n; @@ -5814,10 +5810,6 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, int ret = WS_SUCCESS; RsaKey *key_ptr = NULL; -#ifndef WOLFSSH_SMALL_STACK - byte s_checkDigest[MAX_ENCODED_SIG_SZ]; -#endif - WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsa()"); if (ssh == NULL || ssh->ctx == NULL || pk == NULL || digest == NULL || @@ -5827,14 +5819,6 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, } if (ret == WS_SUCCESS) { -#ifdef WOLFSSH_SMALL_STACK - checkDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, ssh->ctx->heap, - DYNTYPE_BUFFER); - if (checkDigest == NULL) - ret = WS_MEMORY_E; -#else - checkDigest = s_checkDigest; -#endif key_ptr = (RsaKey*)WMALLOC(sizeof(RsaKey), ssh->ctx->heap, DYNTYPE_PUBKEY); if (key_ptr == NULL) @@ -5842,7 +5826,6 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, } if (ret == WS_SUCCESS) { - WMEMSET(checkDigest, 0, MAX_ENCODED_SIG_SZ); ret = wc_InitRsaKey(key_ptr, ssh->ctx->heap); if (ret == 0) { ret = WS_SUCCESS; @@ -5903,55 +5886,14 @@ static int DoUserAuthRequestRsa(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, } if (ret == WS_SUCCESS) { - checkDigestSz = wc_RsaSSL_Verify(sig, sigSz, checkDigest, - MAX_ENCODED_SIG_SZ, key_ptr); - if (checkDigestSz <= 0) { - WLOG(WS_LOG_DEBUG, "Could not verify signature"); - ret = WS_CRYPTO_FAILED; - } + ret = wolfSSH_RsaVerify_2(sig, sigSz, digest, digestSz, hashId, + key_ptr, ssh->ctx->heap, "DoUserAuthRequestRsa"); } - if (ret == WS_SUCCESS) { - word32 encDigestSz; - volatile int compare; - volatile int sizeCompare; -#ifdef WOLFSSH_SMALL_STACK - encDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, ssh->ctx->heap, - DYNTYPE_BUFFER); - if (encDigest == NULL) - ret = WS_MEMORY_E; - - if (ret == WS_SUCCESS) -#else - byte s_encDigest[MAX_ENCODED_SIG_SZ]; - encDigest = s_encDigest; -#endif - { - WMEMSET(encDigest, 0, MAX_ENCODED_SIG_SZ); - encDigestSz = wc_EncodeSignature(encDigest, digest, - wc_HashGetDigestSize(enmhashId), - wc_HashGetOID(enmhashId)); - - compare = ConstantCompare(encDigest, checkDigest, - encDigestSz); - sizeCompare = encDigestSz != (word32)checkDigestSz; - - if ((compare == 0) && (sizeCompare == 0)) - ret = WS_SUCCESS; - else - ret = WS_RSA_E; - } - } if (key_ptr != NULL) { wc_FreeRsaKey(key_ptr); WFREE(key_ptr, ssh->ctx->heap, DYNTYPE_PUBKEY); } -#ifdef WOLFSSH_SMALL_STACK - if (checkDigest) - WFREE(checkDigest, ssh->ctx->heap, DYNTYPE_BUFFER); - if (encDigest) - WFREE(encDigest, ssh->ctx->heap, DYNTYPE_BUFFER); -#endif WLOG(WS_LOG_DEBUG, "Leaving DoUserAuthRequestRsa(), ret = %d", ret); return ret; } @@ -9866,6 +9808,110 @@ static INLINE byte SigTypeForId(byte id) #ifndef WOLFSSH_NO_RSA +/* + * wolfSSH_RsaVerify_2 + * sig - signature to verify + * sigSz - signature size + * digest - digest for verification + * digestSz - digest size + * digestId - ID of the digest type + * key - key used to sign and verify signature + * heap - allocation heap + * loc - calling function for logging + * + * Takes the provided digest of type digestId and converts it to an + * encoded digest. Then verifies the signature, comparing the output + * digest and compares it. + */ +int wolfSSH_RsaVerify_2(const byte *sig, word32 sigSz, + const byte* digest, word32 digestSz, byte digestId, + RsaKey* key, void* heap, const char* loc) +{ + byte* checkSig = NULL; + byte* checkDigest = NULL; + byte* encDigest = NULL; + int checkDigestSz; + word32 encDigestSz; + word32 keySz; + volatile int compare; + volatile int sizeCompare; + int ret = WS_SUCCESS; +#ifndef WOLFSSH_SMALL_STACK + byte s_checkDigest[MAX_ENCODED_SIG_SZ]; + byte s_encDigest[MAX_ENCODED_SIG_SZ]; +#endif + + keySz = (word32)wc_RsaEncryptSize(key); + + if (ret == WS_SUCCESS) { + checkSig = (byte*)WMALLOC(keySz, heap, DYNTYPE_TEMP); + if (checkSig == NULL) + ret = WS_MEMORY_E; + } +#ifdef WOLFSSH_SMALL_STACK + if (ret == WS_SUCCESS) { + checkDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, heap, DYNTYPE_BUFFER); + if (checkDigest == NULL) + ret = WS_MEMORY_E; + } + if (ret == WS_SUCCESS) { + encDigest = (byte*)WMALLOC(MAX_ENCODED_SIG_SZ, heap, DYNTYPE_BUFFER); + if (encDigest == NULL) + ret = WS_MEMORY_E; + } +#else + checkDigest = s_checkDigest; + encDigest = s_encDigest; +#endif + + /* Normalize the peer's signature. Some SSH implementations remove + * leading zeros on the signatures they encode. We need to pad the + * front of the signature to the key size. */ + if (ret == WS_SUCCESS) { + word32 offset; + + if (keySz > sigSz) { + offset = keySz - sigSz; + } + else { + sigSz = keySz; + offset = 0; + } + + WMEMSET(checkSig, 0, offset); + WMEMCPY(checkSig + offset, sig, sigSz); + } + + if (ret == WS_SUCCESS) { + WMEMSET(encDigest, 0, MAX_ENCODED_SIG_SZ); + + encDigestSz = wc_EncodeSignature(encDigest, + digest, digestSz, wc_HashGetOID(digestId)); + checkDigestSz = wc_RsaSSL_Verify(checkSig, keySz, + checkDigest, MAX_ENCODED_SIG_SZ, key); + + sizeCompare = checkDigestSz > 0 + && encDigestSz != (word32)checkDigestSz; + compare = ConstantCompare(encDigest, checkDigest, encDigestSz); + + if (checkDigestSz < 0 || sizeCompare || compare) { + WLOG(WS_LOG_DEBUG, "%s: %s", loc, "Bad RSA Verify"); + ret = WS_RSA_E; + } + } + +#ifdef WOLFSSH_SMALL_STACK + if (checkDigest) + WFREE(checkDigest, heap, DYNTYPE_BUFFER); + if (encDigest) + WFREE(encDigest, heap, DYNTYPE_BUFFER); +#endif + if (checkSig) + WFREE(checkSig, heap, DYNTYPE_BUFFER); + return ret; +} + + /* * wolfSSH_RsaVerify * sig - signature to verify diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 6ff2721cf..657aa2a1e 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -1250,6 +1250,9 @@ WOLFSSH_LOCAL int wolfSSH_CleanPath(WOLFSSH* ssh, char* in); WOLFSSH_LOCAL int wolfSSH_RsaVerify(byte *sig, word32 sigSz, const byte* digest, word32 digestSz, RsaKey* key, void* heap, const char* loc); +WOLFSSH_LOCAL int wolfSSH_RsaVerify_2(const byte *sig, word32 sigSz, + const byte* digest, word32 digestSz, byte digestId, + RsaKey* key, void* heap, const char* loc); #endif WOLFSSH_LOCAL void DumpOctetString(const byte*, word32); WOLFSSH_LOCAL int wolfSSH_oct2dec(WOLFSSH* ssh, byte* oct, word32 octSz);