summaryrefslogtreecommitdiff
path: root/src/pk/rsa/rsa_verify_hash.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pk/rsa/rsa_verify_hash.c')
-rw-r--r--src/pk/rsa/rsa_verify_hash.c141
1 files changed, 111 insertions, 30 deletions
diff --git a/src/pk/rsa/rsa_verify_hash.c b/src/pk/rsa/rsa_verify_hash.c
index 690364d..4b61029 100644
--- a/src/pk/rsa/rsa_verify_hash.c
+++ b/src/pk/rsa/rsa_verify_hash.c
@@ -6,75 +6,156 @@
* The library is free for all purposes without any express
* guarantee it works.
*
- * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.org
+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
*/
#include "tomcrypt.h"
/**
@file rsa_verify_hash.c
- RSA PKCS v2 PSS signature verification, Tom St Denis
-*/
+ RSA PKCS #1 v1.5 or v2 PSS signature verification, Tom St Denis and Andreas Lange
+*/
#ifdef MRSA
/**
- (PKCS #1, v2.0) de-sign then PSS depad
+ PKCS #1 de-sign then v1.5 or PSS depad
@param sig The signature data
@param siglen The length of the signature data (octets)
@param hash The hash of the message that was signed
@param hashlen The length of the hash of the message that was signed (octets)
+ @param padding Type of padding (LTC_PKCS_1_PSS or LTC_PKCS_1_V1_5)
@param hash_idx The index of the desired hash
@param saltlen The length of the salt used during signature
@param stat [out] The result of the signature comparison, 1==valid, 0==invalid
@param key The public RSA key corresponding to the key that performed the signature
@return CRYPT_OK on success (even if the signature is invalid)
*/
-int rsa_verify_hash(const unsigned char *sig, unsigned long siglen,
- const unsigned char *hash, unsigned long hashlen,
- int hash_idx, unsigned long saltlen,
- int *stat, rsa_key *key)
+int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen,
+ const unsigned char *hash, unsigned long hashlen,
+ int padding,
+ int hash_idx, unsigned long saltlen,
+ int *stat, rsa_key *key)
{
- unsigned long modulus_bitlen, modulus_bytelen, x;
- int err;
- unsigned char *tmpbuf;
-
+ unsigned long modulus_bitlen, modulus_bytelen, x;
+ int err;
+ unsigned char *tmpbuf;
+
LTC_ARGCHK(hash != NULL);
- LTC_ARGCHK(sig != NULL);
- LTC_ARGCHK(stat != NULL);
- LTC_ARGCHK(key != NULL);
+ LTC_ARGCHK(sig != NULL);
+ LTC_ARGCHK(stat != NULL);
+ LTC_ARGCHK(key != NULL);
/* default to invalid */
*stat = 0;
-
- /* valid hash ? */
- if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
- return err;
+
+ /* valid padding? */
+
+ if ((padding != LTC_PKCS_1_V1_5) &&
+ (padding != LTC_PKCS_1_PSS)) {
+ return CRYPT_PK_INVALID_PADDING;
}
-
+
+ if (padding == LTC_PKCS_1_PSS) {
+ /* valid hash ? */
+ if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+ return err;
+ }
+ }
+
/* get modulus len in bits */
- modulus_bitlen = mp_count_bits(&(key->N));
+ modulus_bitlen = mp_count_bits( (key->N));
/* outlen must be at least the size of the modulus */
- modulus_bytelen = mp_unsigned_bin_size(&(key->N));
+ modulus_bytelen = mp_unsigned_bin_size( (key->N));
if (modulus_bytelen != siglen) {
return CRYPT_INVALID_PACKET;
}
-
+
/* allocate temp buffer for decoded sig */
tmpbuf = XMALLOC(siglen);
if (tmpbuf == NULL) {
return CRYPT_MEM;
}
-
+
/* RSA decode it */
x = siglen;
- if ((err = rsa_exptmod(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
+ if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
XFREE(tmpbuf);
return err;
}
-
- /* PSS decode it */
- err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat);
+
+ /* make sure the output is the right size */
+ if (x != siglen) {
+ XFREE(tmpbuf);
+ return CRYPT_INVALID_PACKET;
+ }
+
+ if (padding == LTC_PKCS_1_PSS) {
+ /* PSS decode and verify it */
+ err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat);
+ } else {
+ /* PKCS #1 v1.5 decode it */
+ unsigned char *out;
+ unsigned long outlen, loid[16];
+ int decoded;
+ ltc_asn1_list digestinfo[2], siginfo[2];
+
+ /* not all hashes have OIDs... so sad */
+ if (hash_descriptor[hash_idx].OIDlen == 0) {
+ err = CRYPT_INVALID_ARG;
+ goto bail_2;
+ }
+
+ /* allocate temp buffer for decoded hash */
+ outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
+ out = XMALLOC(outlen);
+ if (out == NULL) {
+ err = CRYPT_MEM;
+ goto bail_2;
+ }
+
+ if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
+ XFREE(out);
+ goto bail_2;
+ }
+
+ /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
+ /* construct the SEQUENCE
+ SEQUENCE {
+ SEQUENCE {hashoid OID
+ blah NULL
+ }
+ hash OCTET STRING
+ }
+ */
+ LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
+ LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0);
+ LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2);
+ LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen);
+
+ if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
+ XFREE(out);
+ goto bail_2;
+ }
+
+ /* test OID */
+ if ((digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
+ (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
+ (siginfo[1].size == hashlen) &&
+ (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
+ *stat = 1;
+ }
+
+#ifdef LTC_CLEAN_STACK
+ zeromem(out, outlen);
+#endif
+ XFREE(out);
+ }
+
+bail_2:
+#ifdef LTC_CLEAN_STACK
+ zeromem(tmpbuf, siglen);
+#endif
XFREE(tmpbuf);
return err;
}
@@ -82,5 +163,5 @@ int rsa_verify_hash(const unsigned char *sig, unsigned long siglen,
#endif /* MRSA */
/* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_verify_hash.c,v $ */
-/* $Revision: 1.3 $ */
-/* $Date: 2005/05/05 14:35:59 $ */
+/* $Revision: 1.11 $ */
+/* $Date: 2006/12/04 03:09:28 $ */