]> pd.if.org Git - zpackage/blob - libtomcrypt/src/pk/rsa/rsa_verify_hash.c
commit files needed for zpm-fetchurl
[zpackage] / libtomcrypt / src / pk / rsa / rsa_verify_hash.c
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 #include "tomcrypt.h"
10
11 /**
12   @file rsa_verify_hash.c
13   RSA PKCS #1 v1.5 or v2 PSS signature verification, Tom St Denis and Andreas Lange
14 */
15
16 #ifdef LTC_MRSA
17
18 /**
19   PKCS #1 de-sign then v1.5 or PSS depad
20   @param sig              The signature data
21   @param siglen           The length of the signature data (octets)
22   @param hash             The hash of the message that was signed
23   @param hashlen          The length of the hash of the message that was signed (octets)
24   @param padding          Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
25   @param hash_idx         The index of the desired hash
26   @param saltlen          The length of the salt used during signature
27   @param stat             [out] The result of the signature comparison, 1==valid, 0==invalid
28   @param key              The public RSA key corresponding to the key that performed the signature
29   @return CRYPT_OK on success (even if the signature is invalid)
30 */
31 int rsa_verify_hash_ex(const unsigned char *sig,      unsigned long siglen,
32                        const unsigned char *hash,     unsigned long hashlen,
33                              int            padding,
34                              int            hash_idx, unsigned long saltlen,
35                              int           *stat,     rsa_key      *key)
36 {
37   unsigned long modulus_bitlen, modulus_bytelen, x;
38   int           err;
39   unsigned char *tmpbuf;
40
41   LTC_ARGCHK(hash  != NULL);
42   LTC_ARGCHK(sig   != NULL);
43   LTC_ARGCHK(stat  != NULL);
44   LTC_ARGCHK(key   != NULL);
45
46   /* default to invalid */
47   *stat = 0;
48
49   /* valid padding? */
50
51   if ((padding != LTC_PKCS_1_V1_5) &&
52       (padding != LTC_PKCS_1_PSS) &&
53       (padding != LTC_PKCS_1_V1_5_NA1)) {
54     return CRYPT_PK_INVALID_PADDING;
55   }
56
57   if (padding != LTC_PKCS_1_V1_5_NA1) {
58     /* valid hash ? */
59     if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
60        return err;
61     }
62   }
63
64   /* get modulus len in bits */
65   modulus_bitlen = mp_count_bits( (key->N));
66
67   /* outlen must be at least the size of the modulus */
68   modulus_bytelen = mp_unsigned_bin_size( (key->N));
69   if (modulus_bytelen != siglen) {
70      return CRYPT_INVALID_PACKET;
71   }
72
73   /* allocate temp buffer for decoded sig */
74   tmpbuf = XMALLOC(siglen);
75   if (tmpbuf == NULL) {
76      return CRYPT_MEM;
77   }
78
79   /* RSA decode it  */
80   x = siglen;
81   if ((err = ltc_mp.rsa_me(sig, siglen, tmpbuf, &x, PK_PUBLIC, key)) != CRYPT_OK) {
82      XFREE(tmpbuf);
83      return err;
84   }
85
86   /* make sure the output is the right size */
87   if (x != siglen) {
88      XFREE(tmpbuf);
89      return CRYPT_INVALID_PACKET;
90   }
91
92   if (padding == LTC_PKCS_1_PSS) {
93     /* PSS decode and verify it */
94
95     if(modulus_bitlen%8 == 1){
96       err = pkcs_1_pss_decode(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, modulus_bitlen, stat);
97     }
98     else{
99       err = pkcs_1_pss_decode(hash, hashlen, tmpbuf, x, saltlen, hash_idx, modulus_bitlen, stat);
100     }
101
102   } else {
103     /* PKCS #1 v1.5 decode it */
104     unsigned char *out;
105     unsigned long outlen;
106     int           decoded;
107
108     /* allocate temp buffer for decoded hash */
109     outlen = ((modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0)) - 3;
110     out    = XMALLOC(outlen);
111     if (out == NULL) {
112       err = CRYPT_MEM;
113       goto bail_2;
114     }
115
116     if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
117       XFREE(out);
118       goto bail_2;
119     }
120
121     if (padding == LTC_PKCS_1_V1_5) {
122       unsigned long loid[16], reallen;
123       ltc_asn1_list digestinfo[2], siginfo[2];
124
125       /* not all hashes have OIDs... so sad */
126       if (hash_descriptor[hash_idx].OIDlen == 0) {
127          err = CRYPT_INVALID_ARG;
128          goto bail_2;
129       }
130
131       /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
132       /* construct the SEQUENCE
133         SEQUENCE {
134            SEQUENCE {hashoid OID
135                      blah    NULL
136            }
137            hash    OCTET STRING
138         }
139      */
140       LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, sizeof(loid)/sizeof(loid[0]));
141       LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL,              NULL,                          0);
142       LTC_SET_ASN1(siginfo,    0, LTC_ASN1_SEQUENCE,          digestinfo,                    2);
143       LTC_SET_ASN1(siginfo,    1, LTC_ASN1_OCTET_STRING,      tmpbuf,                        siglen);
144
145       if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
146          /* fallback to Legacy:missing NULL */
147          LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE,          digestinfo,                    1);
148          if ((err = der_decode_sequence(out, outlen, siginfo, 2)) != CRYPT_OK) {
149            XFREE(out);
150            goto bail_2;
151          }
152       }
153
154       if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {
155          XFREE(out);
156          goto bail_2;
157       }
158
159       /* test OID */
160       if ((reallen == outlen) &&
161           (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
162         (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
163           (siginfo[1].size == hashlen) &&
164         (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
165          *stat = 1;
166       }
167     } else {
168       /* only check if the hash is equal */
169       if ((hashlen == outlen) &&
170           (XMEMCMP(out, hash, hashlen) == 0)) {
171         *stat = 1;
172       }
173     }
174
175 #ifdef LTC_CLEAN_STACK
176     zeromem(out, outlen);
177 #endif
178     XFREE(out);
179   }
180
181 bail_2:
182 #ifdef LTC_CLEAN_STACK
183   zeromem(tmpbuf, siglen);
184 #endif
185   XFREE(tmpbuf);
186   return err;
187 }
188
189 #endif /* LTC_MRSA */
190
191 /* ref:         $Format:%D$ */
192 /* git commit:  $Format:%H$ */
193 /* commit time: $Format:%ai$ */