1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis 2 * 3 * LibTomCrypt is a library that provides various cryptographic 4 * algorithms in a highly modular and flexible manner. 5 * 6 * The library is free for all purposes without any express 7 * guarantee it works. 8 * 9 * Tom St Denis, tomstdenis (at) gmail.com, http://libtomcrypt.com 10 */ 11 #include "tomcrypt.h" 12 13 /** 14 @file rsa_verify_hash.c 15 RSA PKCS #1 v1.5 or v2 PSS signature verification, Tom St Denis and Andreas Lange 16 */ 17 18 #ifdef MRSA 19 20 /** 21 PKCS #1 de-sign then v1.5 or PSS depad 22 @param sig The signature data 23 @param siglen The length of the signature data (octets) 24 @param hash The hash of the message that was signed 25 @param hashlen The length of the hash of the message that was signed (octets) 26 @param padding Type of padding (LTC_PKCS_1_PSS or LTC_PKCS_1_V1_5) 27 @param hash_idx The index of the desired hash 28 @param saltlen The length of the salt used during signature 29 @param stat [out] The result of the signature comparison, 1==valid, 0==invalid 30 @param key The public RSA key corresponding to the key that performed the signature 31 @return CRYPT_OK on success (even if the signature is invalid) 32 */ 33 int rsa_verify_hash_ex(const unsigned char *sig, unsigned long siglen, 34 const unsigned char *hash, unsigned long hashlen, 35 int padding, 36 int hash_idx, unsigned long saltlen, 37 int *stat, rsa_key *key) 38 { 39 unsigned long modulus_bitlen, modulus_bytelen, x; 40 int err; 41 unsigned char *tmpbuf; 42 43 LTC_ARGCHK(hash != NULL); 44 LTC_ARGCHK(sig != NULL); 45 LTC_ARGCHK(stat != NULL); 46 LTC_ARGCHK(key != NULL); 47 48 /* default to invalid */ 49 *stat = 0; 50 51 /* valid padding? */ 52 53 if ((padding != LTC_PKCS_1_V1_5) && 54 (padding != LTC_PKCS_1_PSS)) { 55 return CRYPT_PK_INVALID_PADDING; 56 } 57 58 if (padding == LTC_PKCS_1_PSS) { 59 /* valid hash ? */ 60 if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) { 61 return err; 62 } 63 } 64 65 /* get modulus len in bits */ 66 modulus_bitlen = mp_count_bits( (key->N)); 67 68 /* outlen must be at least the size of the modulus */ 69 modulus_bytelen = mp_unsigned_bin_size( (key->N)); 70 if (modulus_bytelen != siglen) { 71 return CRYPT_INVALID_PACKET; 72 } 73 74 /* allocate temp buffer for decoded sig */ 75 tmpbuf = XMALLOC(siglen); 76 if (tmpbuf == NULL) { 77 return CRYPT_MEM; 78 } 79 80 /* RSA decode it */ 81 x = siglen; 82 if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) { 83 XFREE(tmpbuf); 84 return err; 85 } 86 87 /* make sure the output is the right size */ 88 if (x != siglen) { 89 XFREE(tmpbuf); 90 return CRYPT_INVALID_PACKET; 91 } 92 93 if (padding == LTC_PKCS_1_PSS) { 94 /* PSS decode and verify it */ 95 err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat); 96 } else { 97 /* PKCS #1 v1.5 decode it */ 98 unsigned char *out; 99 unsigned long outlen, loid[16]; 100 int decoded; 101 ltc_asn1_list digestinfo[2], siginfo[2]; 102 103 /* not all hashes have OIDs... so sad */ 104 if (hash_descriptor[hash_idx].OIDlen == 0) { 105 err = CRYPT_INVALID_ARG; 106 goto bail_2; 107 } 108 109 /* allocate temp buffer for decoded hash */ 110 outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3; 111 out = XMALLOC(outlen); 112 if (out == NULL) { 113 err = CRYPT_MEM; 114 goto bail_2; 115 } 116 117 if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) { 118 XFREE(out); 119 goto bail_2; 120 } 121 122 /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */ 123 /* construct the SEQUENCE 124 SEQUENCE { 125 SEQUENCE {hashoid OID 126 blah NULL 127 } 128 hash OCTET STRING 129 } 130 */ 131 LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0])); 132 LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL, NULL, 0); 133 LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE, digestinfo, 2); 134 LTC_SET_ASN1(siginfo, 1, LTC_ASN1_OCTET_STRING, tmpbuf, siglen); 135 136 if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) { 137 XFREE(out); 138 goto bail_2; 139 } 140 141 /* test OID */ 142 if ((digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) && 143 (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) && 144 (siginfo[1].size == hashlen) && 145 (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) { 146 *stat = 1; 147 } 148 149 #ifdef LTC_CLEAN_STACK 150 zeromem(out, outlen); 151 #endif 152 XFREE(out); 153 } 154 155 bail_2: 156 #ifdef LTC_CLEAN_STACK 157 zeromem(tmpbuf, siglen); 158 #endif 159 XFREE(tmpbuf); 160 return err; 161 } 162 163 #endif /* MRSA */ 164 165 /* $Source: /cvs/libtom/libtomcrypt/src/pk/rsa/rsa_verify_hash.c,v $ */ 166 /* $Revision: 1.11 $ */ 167 /* $Date: 2006/12/04 03:09:28 $ */ 168