/src/nss-nspr/nss/lib/cryptohi/secvfy.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Verification stuff. |
3 | | * |
4 | | * This Source Code Form is subject to the terms of the Mozilla Public |
5 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
6 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
7 | | |
8 | | #include <stdio.h> |
9 | | #include "cryptohi.h" |
10 | | #include "sechash.h" |
11 | | #include "keyhi.h" |
12 | | #include "secasn1.h" |
13 | | #include "secoid.h" |
14 | | #include "pk11func.h" |
15 | | #include "pkcs1sig.h" |
16 | | #include "secdig.h" |
17 | | #include "secerr.h" |
18 | | #include "keyi.h" |
19 | | #include "nss.h" |
20 | | #include "prenv.h" |
21 | | |
22 | | /* |
23 | | ** Recover the DigestInfo from an RSA PKCS#1 signature. |
24 | | ** |
25 | | ** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut. |
26 | | ** Otherwise, parse the DigestInfo structure and store the decoded digest |
27 | | ** algorithm into digestAlgOut. |
28 | | ** |
29 | | ** Store the encoded DigestInfo into digestInfo. |
30 | | ** Store the DigestInfo length into digestInfoLen. |
31 | | ** |
32 | | ** This function does *not* verify that the AlgorithmIdentifier in the |
33 | | ** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded |
34 | | ** correctly; verifyPKCS1DigestInfo does that. |
35 | | ** |
36 | | ** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION |
37 | | */ |
38 | | static SECStatus |
39 | | recoverPKCS1DigestInfo(SECOidTag givenDigestAlg, |
40 | | /*out*/ SECOidTag *digestAlgOut, |
41 | | /*out*/ unsigned char **digestInfo, |
42 | | /*out*/ unsigned int *digestInfoLen, |
43 | | SECKEYPublicKey *key, |
44 | | const SECItem *sig, void *wincx) |
45 | 0 | { |
46 | 0 | SGNDigestInfo *di = NULL; |
47 | 0 | SECItem it; |
48 | 0 | PRBool rv = SECSuccess; |
49 | |
|
50 | 0 | PORT_Assert(digestAlgOut); |
51 | 0 | PORT_Assert(digestInfo); |
52 | 0 | PORT_Assert(digestInfoLen); |
53 | 0 | PORT_Assert(key); |
54 | 0 | PORT_Assert(key->keyType == rsaKey); |
55 | 0 | PORT_Assert(sig); |
56 | |
|
57 | 0 | it.data = NULL; |
58 | 0 | it.len = SECKEY_PublicKeyStrength(key); |
59 | 0 | if (it.len != 0) { |
60 | 0 | it.data = (unsigned char *)PORT_Alloc(it.len); |
61 | 0 | } |
62 | 0 | if (it.len == 0 || it.data == NULL) { |
63 | 0 | rv = SECFailure; |
64 | 0 | } |
65 | |
|
66 | 0 | if (rv == SECSuccess) { |
67 | | /* decrypt the block */ |
68 | 0 | rv = PK11_VerifyRecover(key, sig, &it, wincx); |
69 | 0 | } |
70 | |
|
71 | 0 | if (rv == SECSuccess) { |
72 | 0 | if (givenDigestAlg != SEC_OID_UNKNOWN) { |
73 | | /* We don't need to parse the DigestInfo if the caller gave us the |
74 | | * digest algorithm to use. Later verifyPKCS1DigestInfo will verify |
75 | | * that the DigestInfo identifies the given digest algorithm and |
76 | | * that the DigestInfo is encoded absolutely correctly. |
77 | | */ |
78 | 0 | *digestInfoLen = it.len; |
79 | 0 | *digestInfo = (unsigned char *)it.data; |
80 | 0 | *digestAlgOut = givenDigestAlg; |
81 | 0 | return SECSuccess; |
82 | 0 | } |
83 | 0 | } |
84 | | |
85 | 0 | if (rv == SECSuccess) { |
86 | | /* The caller didn't specify a digest algorithm to use, so choose the |
87 | | * digest algorithm by parsing the AlgorithmIdentifier within the |
88 | | * DigestInfo. |
89 | | */ |
90 | 0 | di = SGN_DecodeDigestInfo(&it); |
91 | 0 | if (!di) { |
92 | 0 | rv = SECFailure; |
93 | 0 | } |
94 | 0 | } |
95 | |
|
96 | 0 | if (rv == SECSuccess) { |
97 | 0 | *digestAlgOut = SECOID_GetAlgorithmTag(&di->digestAlgorithm); |
98 | 0 | if (*digestAlgOut == SEC_OID_UNKNOWN) { |
99 | 0 | rv = SECFailure; |
100 | 0 | } |
101 | 0 | } |
102 | |
|
103 | 0 | if (di) { |
104 | 0 | SGN_DestroyDigestInfo(di); |
105 | 0 | } |
106 | |
|
107 | 0 | if (rv == SECSuccess) { |
108 | 0 | *digestInfoLen = it.len; |
109 | 0 | *digestInfo = (unsigned char *)it.data; |
110 | 0 | } else { |
111 | 0 | if (it.data) { |
112 | 0 | PORT_Free(it.data); |
113 | 0 | } |
114 | 0 | *digestInfo = NULL; |
115 | 0 | *digestInfoLen = 0; |
116 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
117 | 0 | } |
118 | |
|
119 | 0 | return rv; |
120 | 0 | } |
121 | | |
122 | | struct VFYContextStr { |
123 | | SECOidTag hashAlg; /* the hash algorithm */ |
124 | | SECKEYPublicKey *key; |
125 | | /* |
126 | | * This buffer holds either the digest or the full signature |
127 | | * depending on the type of the signature (key->keyType). It is |
128 | | * defined as a union to make sure it always has enough space. |
129 | | * |
130 | | * Use the "buffer" union member to reference the buffer. |
131 | | * Note: do not take the size of the "buffer" union member. Take |
132 | | * the size of the union or some other union member instead. |
133 | | */ |
134 | | union { |
135 | | unsigned char buffer[1]; |
136 | | |
137 | | /* the full DSA signature... 40 bytes */ |
138 | | unsigned char dsasig[DSA_MAX_SIGNATURE_LEN]; |
139 | | /* the full ECDSA signature */ |
140 | | unsigned char ecdsasig[2 * MAX_ECKEY_LEN]; |
141 | | /* the full RSA signature, only used in RSA-PSS */ |
142 | | unsigned char rsasig[(RSA_MAX_MODULUS_BITS + 7) / 8]; |
143 | | unsigned char gensig[MAX_SIGNATURE_LEN]; |
144 | | } u; |
145 | | unsigned int signatureLen; |
146 | | unsigned int pkcs1RSADigestInfoLen; |
147 | | /* the encoded DigestInfo from a RSA PKCS#1 signature */ |
148 | | unsigned char *pkcs1RSADigestInfo; |
149 | | void *wincx; |
150 | | void *hashcx; |
151 | | const SECHashObject *hashobj; |
152 | | PK11Context *vfycx; |
153 | | SECOidTag encAlg; /* enc alg */ |
154 | | CK_MECHANISM_TYPE mech; |
155 | | PRBool hasSignature; /* true if the signature was provided in the |
156 | | * VFY_CreateContext call. If false, the |
157 | | * signature must be provided with a |
158 | | * VFY_EndWithSignature call. */ |
159 | | SECItem mechparams; |
160 | | }; |
161 | | |
162 | | static SECStatus |
163 | | verifyPKCS1DigestInfo(const VFYContext *cx, const SECItem *digest) |
164 | 0 | { |
165 | 0 | SECItem pkcs1DigestInfo; |
166 | 0 | pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo; |
167 | 0 | pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen; |
168 | 0 | return _SGN_VerifyPKCS1DigestInfo( |
169 | 0 | cx->hashAlg, digest, &pkcs1DigestInfo, |
170 | 0 | PR_FALSE /*XXX: unsafeAllowMissingParameters*/); |
171 | 0 | } |
172 | | |
173 | | static unsigned int |
174 | | checkedSignatureLen(const SECKEYPublicKey *pubk) |
175 | 0 | { |
176 | 0 | unsigned int sigLen = SECKEY_SignatureLen(pubk); |
177 | 0 | if (sigLen == 0) { |
178 | | /* Error set by SECKEY_SignatureLen */ |
179 | 0 | return sigLen; |
180 | 0 | } |
181 | 0 | unsigned int maxSigLen; |
182 | 0 | switch (pubk->keyType) { |
183 | 0 | case rsaKey: |
184 | 0 | case rsaPssKey: |
185 | 0 | maxSigLen = (RSA_MAX_MODULUS_BITS + 7) / 8; |
186 | 0 | break; |
187 | 0 | case dsaKey: |
188 | 0 | maxSigLen = DSA_MAX_SIGNATURE_LEN; |
189 | 0 | break; |
190 | 0 | case ecKey: |
191 | 0 | maxSigLen = 2 * MAX_ECKEY_LEN; |
192 | 0 | break; |
193 | 0 | default: |
194 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
195 | 0 | return 0; |
196 | 0 | } |
197 | 0 | PORT_Assert(maxSigLen <= MAX_SIGNATURE_LEN); |
198 | 0 | if (sigLen > maxSigLen) { |
199 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
200 | 0 | return 0; |
201 | 0 | } |
202 | 0 | return sigLen; |
203 | 0 | } |
204 | | |
205 | | /* |
206 | | * decode the ECDSA or DSA signature from it's DER wrapping. |
207 | | * The unwrapped/raw signature is placed in the buffer pointed |
208 | | * to by dsig and has enough room for len bytes. |
209 | | */ |
210 | | static SECStatus |
211 | | decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig, |
212 | | unsigned int len) |
213 | 0 | { |
214 | 0 | SECItem *dsasig = NULL; /* also used for ECDSA */ |
215 | | |
216 | | /* Safety: Ensure algId is as expected and that signature size is within maxmimums */ |
217 | 0 | if (algid == SEC_OID_ANSIX9_DSA_SIGNATURE) { |
218 | 0 | if (len > DSA_MAX_SIGNATURE_LEN) { |
219 | 0 | goto loser; |
220 | 0 | } |
221 | 0 | } else if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) { |
222 | 0 | if (len > MAX_ECKEY_LEN * 2) { |
223 | 0 | goto loser; |
224 | 0 | } |
225 | 0 | } else { |
226 | 0 | goto loser; |
227 | 0 | } |
228 | | |
229 | | /* Decode and pad to length */ |
230 | 0 | dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len); |
231 | 0 | if (dsasig == NULL) { |
232 | 0 | goto loser; |
233 | 0 | } |
234 | 0 | if (dsasig->len != len) { |
235 | 0 | SECITEM_FreeItem(dsasig, PR_TRUE); |
236 | 0 | goto loser; |
237 | 0 | } |
238 | | |
239 | 0 | PORT_Memcpy(dsig, dsasig->data, len); |
240 | 0 | SECITEM_FreeItem(dsasig, PR_TRUE); |
241 | |
|
242 | 0 | return SECSuccess; |
243 | | |
244 | 0 | loser: |
245 | 0 | PORT_SetError(SEC_ERROR_BAD_DER); |
246 | 0 | return SECFailure; |
247 | 0 | } |
248 | | |
249 | | const SEC_ASN1Template hashParameterTemplate[] = { |
250 | | { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, |
251 | | { SEC_ASN1_OBJECT_ID, 0 }, |
252 | | { SEC_ASN1_SKIP_REST }, |
253 | | { 0 } |
254 | | }; |
255 | | |
256 | | /* |
257 | | * Get just the encryption algorithm from the signature algorithm |
258 | | */ |
259 | | SECOidTag |
260 | | sec_GetEncAlgFromSigAlg(SECOidTag sigAlg) |
261 | 0 | { |
262 | | /* get the "encryption" algorithm */ |
263 | 0 | switch (sigAlg) { |
264 | 0 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
265 | 0 | case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
266 | 0 | case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
267 | 0 | case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: |
268 | 0 | case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: |
269 | 0 | case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: |
270 | 0 | case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: |
271 | 0 | case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: |
272 | 0 | case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: |
273 | 0 | case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: |
274 | 0 | return SEC_OID_PKCS1_RSA_ENCRYPTION; |
275 | 0 | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
276 | 0 | return SEC_OID_PKCS1_RSA_PSS_SIGNATURE; |
277 | | |
278 | | /* what about normal DSA? */ |
279 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
280 | 0 | case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
281 | 0 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: |
282 | 0 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: |
283 | 0 | return SEC_OID_ANSIX9_DSA_SIGNATURE; |
284 | 0 | case SEC_OID_MISSI_DSS: |
285 | 0 | case SEC_OID_MISSI_KEA_DSS: |
286 | 0 | case SEC_OID_MISSI_KEA_DSS_OLD: |
287 | 0 | case SEC_OID_MISSI_DSS_OLD: |
288 | 0 | return SEC_OID_MISSI_DSS; |
289 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: |
290 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: |
291 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: |
292 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: |
293 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: |
294 | 0 | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: |
295 | 0 | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: |
296 | 0 | return SEC_OID_ANSIX962_EC_PUBLIC_KEY; |
297 | | /* we don't implement MD4 hashes */ |
298 | 0 | case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
299 | 0 | default: |
300 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
301 | 0 | break; |
302 | 0 | } |
303 | 0 | return SEC_OID_UNKNOWN; |
304 | 0 | } |
305 | | static CK_MECHANISM_TYPE |
306 | | sec_RSAPKCS1GetCombinedMech(SECOidTag hashalg) |
307 | 0 | { |
308 | 0 | switch (hashalg) { |
309 | 0 | case SEC_OID_MD5: |
310 | 0 | return CKM_MD5_RSA_PKCS; |
311 | 0 | case SEC_OID_MD2: |
312 | 0 | return CKM_MD2_RSA_PKCS; |
313 | 0 | case SEC_OID_SHA1: |
314 | 0 | return CKM_SHA1_RSA_PKCS; |
315 | 0 | case SEC_OID_SHA224: |
316 | 0 | return CKM_SHA224_RSA_PKCS; |
317 | 0 | case SEC_OID_SHA256: |
318 | 0 | return CKM_SHA256_RSA_PKCS; |
319 | 0 | case SEC_OID_SHA384: |
320 | 0 | return CKM_SHA384_RSA_PKCS; |
321 | 0 | case SEC_OID_SHA512: |
322 | 0 | return CKM_SHA512_RSA_PKCS; |
323 | 0 | default: |
324 | 0 | break; |
325 | 0 | } |
326 | 0 | return CKM_INVALID_MECHANISM; |
327 | 0 | } |
328 | | |
329 | | static CK_MECHANISM_TYPE |
330 | | sec_RSAPSSGetCombinedMech(SECOidTag hashalg) |
331 | 0 | { |
332 | 0 | switch (hashalg) { |
333 | 0 | case SEC_OID_SHA1: |
334 | 0 | return CKM_SHA1_RSA_PKCS_PSS; |
335 | 0 | case SEC_OID_SHA224: |
336 | 0 | return CKM_SHA224_RSA_PKCS_PSS; |
337 | 0 | case SEC_OID_SHA256: |
338 | 0 | return CKM_SHA256_RSA_PKCS_PSS; |
339 | 0 | case SEC_OID_SHA384: |
340 | 0 | return CKM_SHA384_RSA_PKCS_PSS; |
341 | 0 | case SEC_OID_SHA512: |
342 | 0 | return CKM_SHA512_RSA_PKCS_PSS; |
343 | 0 | default: |
344 | 0 | break; |
345 | 0 | } |
346 | 0 | return CKM_INVALID_MECHANISM; |
347 | 0 | } |
348 | | |
349 | | static CK_MECHANISM_TYPE |
350 | | sec_DSAGetCombinedMech(SECOidTag hashalg) |
351 | 0 | { |
352 | 0 | switch (hashalg) { |
353 | 0 | case SEC_OID_SHA1: |
354 | 0 | return CKM_DSA_SHA1; |
355 | 0 | case SEC_OID_SHA224: |
356 | 0 | return CKM_DSA_SHA224; |
357 | 0 | case SEC_OID_SHA256: |
358 | 0 | return CKM_DSA_SHA256; |
359 | 0 | case SEC_OID_SHA384: |
360 | 0 | return CKM_DSA_SHA384; |
361 | 0 | case SEC_OID_SHA512: |
362 | 0 | return CKM_DSA_SHA512; |
363 | 0 | default: |
364 | 0 | break; |
365 | 0 | } |
366 | 0 | return CKM_INVALID_MECHANISM; |
367 | 0 | } |
368 | | static CK_MECHANISM_TYPE |
369 | | sec_ECDSAGetCombinedMech(SECOidTag hashalg) |
370 | 0 | { |
371 | 0 | switch (hashalg) { |
372 | 0 | case SEC_OID_SHA1: |
373 | 0 | return CKM_ECDSA_SHA1; |
374 | 0 | case SEC_OID_SHA224: |
375 | 0 | return CKM_ECDSA_SHA224; |
376 | 0 | case SEC_OID_SHA256: |
377 | 0 | return CKM_ECDSA_SHA256; |
378 | 0 | case SEC_OID_SHA384: |
379 | 0 | return CKM_ECDSA_SHA384; |
380 | 0 | case SEC_OID_SHA512: |
381 | 0 | return CKM_ECDSA_SHA512; |
382 | 0 | default: |
383 | 0 | break; |
384 | 0 | } |
385 | 0 | return CKM_INVALID_MECHANISM; |
386 | 0 | } |
387 | | |
388 | | static CK_MECHANISM_TYPE |
389 | | sec_GetCombinedMech(SECOidTag encalg, SECOidTag hashalg) |
390 | 0 | { |
391 | 0 | switch (encalg) { |
392 | 0 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
393 | 0 | return sec_RSAPKCS1GetCombinedMech(hashalg); |
394 | 0 | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
395 | 0 | return sec_RSAPSSGetCombinedMech(hashalg); |
396 | 0 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
397 | 0 | return sec_ECDSAGetCombinedMech(hashalg); |
398 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE: |
399 | 0 | return sec_DSAGetCombinedMech(hashalg); |
400 | 0 | default: |
401 | 0 | break; |
402 | 0 | } |
403 | 0 | return CKM_INVALID_MECHANISM; |
404 | 0 | } |
405 | | |
406 | | /* |
407 | | * Pulls the hash algorithm, signing algorithm, and key type out of a |
408 | | * composite algorithm. |
409 | | * |
410 | | * key: pointer to the public key. Should be NULL if called for a sign operation. |
411 | | * sigAlg: the composite algorithm to dissect. |
412 | | * hashalg: address of a SECOidTag which will be set with the hash algorithm. |
413 | | * encalg: address of a SECOidTag which will be set with the signing alg. |
414 | | * mechp: address of a PCKS #11 Mechanism which will be set to the |
415 | | * combined hash/encrypt mechanism. If set to CKM_INVALID_MECHANISM, the code |
416 | | * will fall back to external hashing. |
417 | | * mechparams: address of a SECItem will set to the parameters for the combined |
418 | | * hash/encrypt mechanism. |
419 | | * |
420 | | * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the |
421 | | * algorithm was not found or was not a signing algorithm. |
422 | | */ |
423 | | SECStatus |
424 | | sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg, |
425 | | const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg, |
426 | | CK_MECHANISM_TYPE *mechp, SECItem *mechparamsp) |
427 | 0 | { |
428 | 0 | unsigned int len; |
429 | 0 | PLArenaPool *arena; |
430 | 0 | SECStatus rv; |
431 | 0 | SECItem oid; |
432 | 0 | SECOidTag encalg; |
433 | 0 | char *evp; |
434 | |
|
435 | 0 | PR_ASSERT(hashalg != NULL); |
436 | 0 | PR_ASSERT(encalgp != NULL); |
437 | 0 | PR_ASSERT(mechp != NULL); |
438 | | /* Get the expected combined mechanism from the signature OID |
439 | | * We'll override it in the table below if necessary */ |
440 | 0 | *mechp = PK11_AlgtagToMechanism(sigAlg); |
441 | 0 | if (mechparamsp) { |
442 | 0 | mechparamsp->data = NULL; |
443 | 0 | mechparamsp->len = 0; |
444 | 0 | } |
445 | |
|
446 | 0 | switch (sigAlg) { |
447 | | /* We probably shouldn't be generating MD2 signatures either */ |
448 | 0 | case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: |
449 | 0 | *hashalg = SEC_OID_MD2; |
450 | 0 | break; |
451 | 0 | case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: |
452 | 0 | *hashalg = SEC_OID_MD5; |
453 | 0 | break; |
454 | 0 | case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: |
455 | 0 | case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE: |
456 | 0 | case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE: |
457 | 0 | *hashalg = SEC_OID_SHA1; |
458 | 0 | break; |
459 | 0 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
460 | | /* SEC_OID_PKCS1_RSA_ENCRYPTION returns the generic |
461 | | * CKM_RSA_PKCS mechanism, which isn't a combined mechanism. |
462 | | * We don't have a hash, so we need to fall back to the old |
463 | | * code which gets the hashalg by decoding the signature */ |
464 | 0 | *mechp = CKM_INVALID_MECHANISM; |
465 | 0 | *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */ |
466 | 0 | break; |
467 | 0 | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
468 | | /* SEC_OID_PKCS1_RSA_PSS_SIGNATURE returns the generic |
469 | | * CKM_RSA_PSS_PKCS mechanism, which isn't a combined mechanism. |
470 | | * If successful, we'll select the mechanism below, set it to |
471 | | * invalid here incase we aren't successful */ |
472 | 0 | *mechp = CKM_INVALID_MECHANISM; |
473 | 0 | CK_RSA_PKCS_PSS_PARAMS *rsapssmechparams = NULL; |
474 | 0 | CK_RSA_PKCS_PSS_PARAMS space; |
475 | | |
476 | | /* if we don't have a mechanism parameter to put the data in |
477 | | * we don't need to return it, just use a stack buffer */ |
478 | 0 | if (mechparamsp == NULL) { |
479 | 0 | rsapssmechparams = &space; |
480 | 0 | } else { |
481 | 0 | rsapssmechparams = PORT_ZNew(CK_RSA_PKCS_PSS_PARAMS); |
482 | 0 | } |
483 | 0 | if (rsapssmechparams == NULL) { |
484 | 0 | return SECFailure; |
485 | 0 | } |
486 | 0 | if (param && param->data) { |
487 | 0 | PORTCheapArenaPool tmpArena; |
488 | |
|
489 | 0 | PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE); |
490 | 0 | rv = sec_DecodeRSAPSSParamsToMechanism(&tmpArena.arena, param, |
491 | 0 | rsapssmechparams, hashalg); |
492 | 0 | PORT_DestroyCheapArena(&tmpArena); |
493 | | |
494 | | /* only accept hash algorithms */ |
495 | 0 | if (rv != SECSuccess || HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { |
496 | | /* error set by sec_DecodeRSAPSSParams or HASH_GetHashTypeByOidTag */ |
497 | 0 | if (mechparamsp) |
498 | 0 | PORT_Free(rsapssmechparams); |
499 | 0 | return SECFailure; |
500 | 0 | } |
501 | 0 | } else { |
502 | 0 | *hashalg = SEC_OID_SHA1; /* default, SHA-1 */ |
503 | 0 | rsapssmechparams->hashAlg = CKM_SHA_1; |
504 | 0 | rsapssmechparams->mgf = CKG_MGF1_SHA1; |
505 | 0 | rsapssmechparams->sLen = SHA1_LENGTH; |
506 | 0 | } |
507 | 0 | *mechp = sec_RSAPSSGetCombinedMech(*hashalg); |
508 | 0 | if (mechparamsp) { |
509 | 0 | mechparamsp->data = (unsigned char *)rsapssmechparams; |
510 | 0 | mechparamsp->len = sizeof(*rsapssmechparams); |
511 | 0 | } |
512 | 0 | break; |
513 | | |
514 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: |
515 | 0 | case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION: |
516 | 0 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST: |
517 | 0 | *hashalg = SEC_OID_SHA224; |
518 | 0 | break; |
519 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: |
520 | 0 | case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: |
521 | 0 | case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST: |
522 | 0 | *hashalg = SEC_OID_SHA256; |
523 | 0 | break; |
524 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: |
525 | 0 | case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: |
526 | 0 | *hashalg = SEC_OID_SHA384; |
527 | 0 | break; |
528 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: |
529 | 0 | case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: |
530 | 0 | *hashalg = SEC_OID_SHA512; |
531 | 0 | break; |
532 | | |
533 | | /* what about normal DSA? */ |
534 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
535 | 0 | case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: |
536 | 0 | case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: |
537 | 0 | *hashalg = SEC_OID_SHA1; |
538 | 0 | break; |
539 | 0 | case SEC_OID_MISSI_DSS: |
540 | 0 | case SEC_OID_MISSI_KEA_DSS: |
541 | 0 | case SEC_OID_MISSI_KEA_DSS_OLD: |
542 | 0 | case SEC_OID_MISSI_DSS_OLD: |
543 | 0 | *mechp = CKM_DSA_SHA1; |
544 | 0 | *hashalg = SEC_OID_SHA1; |
545 | 0 | break; |
546 | 0 | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: |
547 | | /* This is an EC algorithm. Recommended means the largest |
548 | | * hash algorithm that is not reduced by the keysize of |
549 | | * the EC algorithm. Note that key strength is in bytes and |
550 | | * algorithms are specified in bits. Never use an algorithm |
551 | | * weaker than sha1. */ |
552 | 0 | len = SECKEY_PublicKeyStrength(key); |
553 | 0 | if (len < 28) { /* 28 bytes == 224 bits */ |
554 | 0 | *hashalg = SEC_OID_SHA1; |
555 | 0 | } else if (len < 32) { /* 32 bytes == 256 bits */ |
556 | 0 | *hashalg = SEC_OID_SHA224; |
557 | 0 | } else if (len < 48) { /* 48 bytes == 384 bits */ |
558 | 0 | *hashalg = SEC_OID_SHA256; |
559 | 0 | } else if (len < 64) { /* 48 bytes == 512 bits */ |
560 | 0 | *hashalg = SEC_OID_SHA384; |
561 | 0 | } else { |
562 | | /* use the largest in this case */ |
563 | 0 | *hashalg = SEC_OID_SHA512; |
564 | 0 | } |
565 | 0 | *mechp = sec_ECDSAGetCombinedMech(*hashalg); |
566 | 0 | break; |
567 | 0 | case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: |
568 | 0 | if (param == NULL) { |
569 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
570 | 0 | return SECFailure; |
571 | 0 | } |
572 | 0 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
573 | 0 | if (arena == NULL) { |
574 | 0 | return SECFailure; |
575 | 0 | } |
576 | 0 | rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, param); |
577 | 0 | if (rv == SECSuccess) { |
578 | 0 | *hashalg = SECOID_FindOIDTag(&oid); |
579 | 0 | } |
580 | 0 | PORT_FreeArena(arena, PR_FALSE); |
581 | 0 | if (rv != SECSuccess) { |
582 | 0 | return rv; |
583 | 0 | } |
584 | | /* only accept hash algorithms */ |
585 | 0 | if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) { |
586 | | /* error set by HASH_GetHashTypeByOidTag */ |
587 | 0 | return SECFailure; |
588 | 0 | } |
589 | 0 | *mechp = sec_ECDSAGetCombinedMech(*hashalg); |
590 | 0 | break; |
591 | | /* we don't implement MD4 hashes */ |
592 | 0 | case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: |
593 | 0 | default: |
594 | 0 | *mechp = CKM_INVALID_MECHANISM; |
595 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
596 | 0 | return SECFailure; |
597 | 0 | } |
598 | | |
599 | 0 | encalg = sec_GetEncAlgFromSigAlg(sigAlg); |
600 | 0 | if (encalg == SEC_OID_UNKNOWN) { |
601 | 0 | *mechp = CKM_INVALID_MECHANISM; |
602 | 0 | SECITEM_FreeItem(mechparamsp, PR_FALSE); |
603 | 0 | return SECFailure; |
604 | 0 | } |
605 | 0 | *encalgp = encalg; |
606 | | /* for testing, we want to be able to turn off combo signatures to |
607 | | * 1) make sure the fallback code is working correctly so we know |
608 | | * we can handle cases where the fallback doesn't work. |
609 | | * 2) make sure that the combo code is compatible with the non-combo |
610 | | * versions. |
611 | | * We know if we are signing or verifying based on the value of 'key'. |
612 | | * Since key is a public key, then it's set to NULL for signing */ |
613 | 0 | evp = PR_GetEnvSecure("NSS_COMBO_SIGNATURES"); |
614 | 0 | if (evp) { |
615 | 0 | if (PORT_Strcasecmp(evp, "none") == 0) { |
616 | 0 | *mechp = CKM_INVALID_MECHANISM; |
617 | 0 | } else if (key && (PORT_Strcasecmp(evp, "signonly") == 0)) { |
618 | 0 | *mechp = CKM_INVALID_MECHANISM; |
619 | 0 | } else if (!key && (PORT_Strcasecmp(evp, "vfyonly") == 0)) { |
620 | 0 | *mechp = CKM_INVALID_MECHANISM; |
621 | 0 | } |
622 | | /* anything else we take as use combo, which is the default */ |
623 | 0 | } |
624 | |
|
625 | 0 | return SECSuccess; |
626 | 0 | } |
627 | | |
628 | | SECStatus |
629 | | vfy_ImportPublicKey(VFYContext *cx) |
630 | 0 | { |
631 | 0 | PK11SlotInfo *slot; |
632 | 0 | CK_OBJECT_HANDLE objID; |
633 | |
|
634 | 0 | if (cx->key->pkcs11Slot && |
635 | 0 | PK11_DoesMechanismFlag(cx->key->pkcs11Slot, |
636 | 0 | cx->mech, CKF_VERIFY)) { |
637 | 0 | return SECSuccess; |
638 | 0 | } |
639 | 0 | slot = PK11_GetBestSlotWithAttributes(cx->mech, CKF_VERIFY, 0, cx->wincx); |
640 | 0 | if (slot == NULL) { |
641 | 0 | return SECFailure; /* can't find a slot, fall back to |
642 | | * normal processing */ |
643 | 0 | } |
644 | 0 | objID = PK11_ImportPublicKey(slot, cx->key, PR_FALSE); |
645 | 0 | PK11_FreeSlot(slot); |
646 | 0 | return objID == CK_INVALID_HANDLE ? SECFailure : SECSuccess; |
647 | 0 | } |
648 | | |
649 | | /* Sometimes there are differences between how DER encodes a |
650 | | * signature and how it's encoded in PKCS #11. This function converts the |
651 | | * DER form to the PKCS #11 form. it also verify signature length based |
652 | | * on the key, and verifies that length will fit in our buffer. */ |
653 | | static SECStatus |
654 | | vfy_SetPKCS11SigFromX509Sig(VFYContext *cx, const SECItem *sig) |
655 | 0 | { |
656 | 0 | unsigned int sigLen; |
657 | | |
658 | | /* skip the legacy RSA PKCS #11 case, it's always handled separately */ |
659 | 0 | if ((cx->key->keyType == rsaKey) && (cx->mech == CKM_INVALID_MECHANISM) && |
660 | 0 | (cx->encAlg != SEC_OID_PKCS1_RSA_PSS_SIGNATURE)) { |
661 | 0 | return SECSuccess; |
662 | 0 | } |
663 | | |
664 | 0 | sigLen = checkedSignatureLen(cx->key); |
665 | | /* Check signature length is within limits */ |
666 | 0 | if (sigLen == 0) { |
667 | | /* error set by checkedSignatureLen */ |
668 | 0 | return SECFailure; |
669 | 0 | } |
670 | 0 | if (sigLen > sizeof(cx->u)) { |
671 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
672 | 0 | return SECFailure; |
673 | 0 | } |
674 | | /* save the authenticated length */ |
675 | 0 | cx->signatureLen = sigLen; |
676 | 0 | switch (cx->encAlg) { |
677 | 0 | case SEC_OID_ANSIX9_DSA_SIGNATURE: |
678 | 0 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
679 | | /* decodeECorDSASignature will check sigLen == sig->len after padding */ |
680 | 0 | return decodeECorDSASignature(cx->encAlg, sig, cx->u.buffer, sigLen); |
681 | 0 | default: |
682 | 0 | break; |
683 | 0 | } |
684 | | /* all other cases, no transform needed, just copy the signature */ |
685 | 0 | if (sig->len != sigLen) { |
686 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
687 | 0 | return SECFailure; |
688 | 0 | } |
689 | 0 | PORT_Memcpy(cx->u.buffer, sig->data, sigLen); |
690 | 0 | return SECSuccess; |
691 | 0 | } |
692 | | |
693 | | /* |
694 | | * we can verify signatures that come from 2 different sources: |
695 | | * one in with the signature contains a signature oid, and the other |
696 | | * in which the signature is managed by a Public key (encAlg) oid |
697 | | * and a hash oid. The latter is the more basic, so that's what |
698 | | * our base vfyCreate function takes. |
699 | | * |
700 | | * Modern signature algorithms builds the hashing into the algorithm, and |
701 | | * some tokens (like smart cards), purposefully only export hash & sign |
702 | | * combo mechanisms (which gives stronger guarrentees on key type usage |
703 | | * for RSA operations). If mech is set to a PKCS #11 mechanism, we assume |
704 | | * we can do the combined operations, otherwise we fall back to manually |
705 | | * hashing then signing. |
706 | | * |
707 | | * This function adopts the mechparamsp parameter, so if we fail before |
708 | | * setting up the context, we need to free any space associated with it |
709 | | * before we return. |
710 | | * |
711 | | * There is one noteworthy corner case, if we are using an RSA key, and the |
712 | | * signature block is provided, then the hashAlg can be specified as |
713 | | * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied |
714 | | * in the RSA signature block. |
715 | | */ |
716 | | static VFYContext * |
717 | | vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig, |
718 | | SECOidTag encAlg, SECOidTag hashAlg, CK_MECHANISM_TYPE mech, |
719 | | SECItem *mechparamsp, SECOidTag *hash, PRBool prehash, |
720 | | void *wincx) |
721 | 0 | { |
722 | 0 | VFYContext *cx; |
723 | 0 | SECStatus rv; |
724 | 0 | KeyType type; |
725 | 0 | PRUint32 policyFlags; |
726 | 0 | PRInt32 optFlags; |
727 | | |
728 | | /* make sure the encryption algorithm matches the key type */ |
729 | | /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */ |
730 | 0 | type = seckey_GetKeyType(encAlg); |
731 | 0 | if ((key->keyType != type) && |
732 | 0 | ((key->keyType != rsaKey) || (type != rsaPssKey))) { |
733 | 0 | SECITEM_FreeItem(mechparamsp, PR_FALSE); |
734 | 0 | PORT_SetError(SEC_ERROR_PKCS7_KEYALG_MISMATCH); |
735 | 0 | return NULL; |
736 | 0 | } |
737 | 0 | if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { |
738 | 0 | if (optFlags & NSS_KEY_SIZE_POLICY_VERIFY_FLAG) { |
739 | 0 | rv = SECKEY_EnforceKeySize(key->keyType, |
740 | 0 | SECKEY_PublicKeyStrengthInBits(key), |
741 | 0 | SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
742 | 0 | if (rv != SECSuccess) { |
743 | 0 | SECITEM_FreeItem(mechparamsp, PR_FALSE); |
744 | 0 | return NULL; |
745 | 0 | } |
746 | 0 | } |
747 | 0 | } |
748 | | /* check the policy on the encryption algorithm */ |
749 | 0 | if ((NSS_GetAlgorithmPolicy(encAlg, &policyFlags) == SECFailure) || |
750 | 0 | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
751 | 0 | SECITEM_FreeItem(mechparamsp, PR_FALSE); |
752 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
753 | 0 | return NULL; |
754 | 0 | } |
755 | | |
756 | 0 | cx = (VFYContext *)PORT_ZAlloc(sizeof(VFYContext)); |
757 | 0 | if (cx == NULL) { |
758 | | /* after this point mechparamsp is 'owned' by the context and will be |
759 | | * freed by Destroy context for any other failures here */ |
760 | 0 | SECITEM_FreeItem(mechparamsp, PR_FALSE); |
761 | 0 | goto loser; |
762 | 0 | } |
763 | | |
764 | 0 | cx->wincx = wincx; |
765 | 0 | cx->hasSignature = (sig != NULL); |
766 | 0 | cx->encAlg = encAlg; |
767 | 0 | cx->hashAlg = hashAlg; |
768 | 0 | cx->mech = mech; |
769 | 0 | if (mechparamsp) { |
770 | 0 | cx->mechparams = *mechparamsp; |
771 | 0 | } else { |
772 | | /* probably needs to have a call to set the default |
773 | | * paramseters based on hashAlg and encAlg */ |
774 | 0 | cx->mechparams.data = NULL; |
775 | 0 | cx->mechparams.len = 0; |
776 | 0 | } |
777 | 0 | cx->key = SECKEY_CopyPublicKey(key); |
778 | 0 | cx->pkcs1RSADigestInfo = NULL; |
779 | 0 | if (mech != CKM_INVALID_MECHANISM) { |
780 | 0 | rv = vfy_ImportPublicKey(cx); |
781 | | /* if we can't import the key, then we probably can't |
782 | | * support the requested combined mechanism, fallback |
783 | | * to the non-combined method */ |
784 | 0 | if (rv != SECSuccess) { |
785 | 0 | cx->mech = mech = CKM_INVALID_MECHANISM; |
786 | 0 | } |
787 | 0 | } |
788 | 0 | if (sig) { |
789 | | /* sigh, if we are prehashing, we still need to do verifyRecover |
790 | | * recover for RSA PKCS #1 */ |
791 | 0 | if ((mech == CKM_INVALID_MECHANISM || prehash) && (type == rsaKey)) { |
792 | | /* in traditional rsa PKCS #1, we use verify recover to get |
793 | | * the encoded RSADigestInfo. In all other cases we just |
794 | | * stash the signature encoded in PKCS#11 in our context */ |
795 | 0 | rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg, |
796 | 0 | &cx->pkcs1RSADigestInfo, |
797 | 0 | &cx->pkcs1RSADigestInfoLen, |
798 | 0 | cx->key, |
799 | 0 | sig, wincx); |
800 | 0 | } else { |
801 | | /* at this point hashAlg should be known. Only the RSA case |
802 | | * enters here with hashAlg unknown, and it's found out |
803 | | * above */ |
804 | 0 | PORT_Assert(hashAlg != SEC_OID_UNKNOWN); |
805 | 0 | rv = vfy_SetPKCS11SigFromX509Sig(cx, sig); |
806 | 0 | } |
807 | 0 | if (rv != SECSuccess) { |
808 | 0 | goto loser; |
809 | 0 | } |
810 | 0 | } |
811 | | |
812 | | /* check hash alg again, RSA may have changed it.*/ |
813 | 0 | if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) { |
814 | | /* error set by HASH_GetHashTypeByOidTag */ |
815 | 0 | goto loser; |
816 | 0 | } |
817 | | /* check the policy on the hash algorithm. Do this after |
818 | | * the rsa decode because some uses of this function get hash implicitly |
819 | | * from the RSA signature itself. */ |
820 | 0 | if ((NSS_GetAlgorithmPolicy(cx->hashAlg, &policyFlags) == SECFailure) || |
821 | 0 | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
822 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
823 | 0 | goto loser; |
824 | 0 | } |
825 | | |
826 | 0 | if (hash) { |
827 | 0 | *hash = cx->hashAlg; |
828 | 0 | } |
829 | 0 | return cx; |
830 | | |
831 | 0 | loser: |
832 | 0 | if (cx) { |
833 | 0 | VFY_DestroyContext(cx, PR_TRUE); |
834 | 0 | } |
835 | 0 | return 0; |
836 | 0 | } |
837 | | |
838 | | VFYContext * |
839 | | VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg, |
840 | | void *wincx) |
841 | 0 | { |
842 | 0 | SECOidTag encAlg, hashAlg; |
843 | 0 | CK_MECHANISM_TYPE mech; |
844 | 0 | SECItem mechparams; |
845 | 0 | SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL, &encAlg, &hashAlg, |
846 | 0 | &mech, &mechparams); |
847 | 0 | if (rv != SECSuccess) { |
848 | 0 | return NULL; |
849 | 0 | } |
850 | 0 | return vfy_CreateContext(key, sig, encAlg, hashAlg, mech, |
851 | 0 | &mechparams, NULL, PR_FALSE, wincx); |
852 | 0 | } |
853 | | |
854 | | VFYContext * |
855 | | VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig, |
856 | | SECOidTag encAlg, SECOidTag hashAlg, |
857 | | SECOidTag *hash, void *wincx) |
858 | 0 | { |
859 | 0 | CK_MECHANISM_TYPE mech = sec_GetCombinedMech(encAlg, hashAlg); |
860 | 0 | return vfy_CreateContext(key, sig, encAlg, hashAlg, mech, NULL, |
861 | 0 | hash, PR_FALSE, wincx); |
862 | 0 | } |
863 | | |
864 | | VFYContext * |
865 | | VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig, |
866 | | const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx) |
867 | 0 | { |
868 | 0 | SECOidTag encAlg, hashAlg; |
869 | 0 | CK_MECHANISM_TYPE mech; |
870 | 0 | SECItem mechparams; |
871 | 0 | SECStatus rv = sec_DecodeSigAlg(key, |
872 | 0 | SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), |
873 | 0 | &sigAlgorithm->parameters, &encAlg, &hashAlg, |
874 | 0 | &mech, &mechparams); |
875 | 0 | if (rv != SECSuccess) { |
876 | 0 | return NULL; |
877 | 0 | } |
878 | | |
879 | 0 | return vfy_CreateContext(key, sig, encAlg, hashAlg, mech, &mechparams, |
880 | 0 | hash, PR_FALSE, wincx); |
881 | 0 | } |
882 | | |
883 | | void |
884 | | VFY_DestroyContext(VFYContext *cx, PRBool freeit) |
885 | 0 | { |
886 | 0 | if (cx) { |
887 | 0 | if (cx->hashcx != NULL) { |
888 | 0 | (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); |
889 | 0 | cx->hashcx = NULL; |
890 | 0 | } |
891 | 0 | if (cx->vfycx != NULL) { |
892 | 0 | (void)PK11_DestroyContext(cx->vfycx, PR_TRUE); |
893 | 0 | cx->vfycx = NULL; |
894 | 0 | } |
895 | 0 | if (cx->key) { |
896 | 0 | SECKEY_DestroyPublicKey(cx->key); |
897 | 0 | } |
898 | 0 | if (cx->pkcs1RSADigestInfo) { |
899 | 0 | PORT_Free(cx->pkcs1RSADigestInfo); |
900 | 0 | } |
901 | 0 | SECITEM_FreeItem(&cx->mechparams, PR_FALSE); |
902 | 0 | if (freeit) { |
903 | 0 | PORT_ZFree(cx, sizeof(VFYContext)); |
904 | 0 | } |
905 | 0 | } |
906 | 0 | } |
907 | | |
908 | | SECStatus |
909 | | VFY_Begin(VFYContext *cx) |
910 | 0 | { |
911 | 0 | if (cx->hashcx != NULL) { |
912 | 0 | (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE); |
913 | 0 | cx->hashcx = NULL; |
914 | 0 | } |
915 | 0 | if (cx->vfycx != NULL) { |
916 | 0 | (void)PK11_DestroyContext(cx->vfycx, PR_TRUE); |
917 | 0 | cx->vfycx = NULL; |
918 | 0 | } |
919 | 0 | if (cx->mech != CKM_INVALID_MECHANISM) { |
920 | 0 | cx->vfycx = PK11_CreateContextByPubKey(cx->mech, CKA_VERIFY, cx->key, |
921 | 0 | &cx->mechparams, cx->wincx); |
922 | 0 | if (!cx->vfycx) |
923 | 0 | return SECFailure; |
924 | 0 | return SECSuccess; |
925 | 0 | } |
926 | 0 | cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg); |
927 | 0 | if (!cx->hashobj) |
928 | 0 | return SECFailure; /* error code is set */ |
929 | | |
930 | 0 | cx->hashcx = (*cx->hashobj->create)(); |
931 | 0 | if (cx->hashcx == NULL) |
932 | 0 | return SECFailure; |
933 | | |
934 | 0 | (*cx->hashobj->begin)(cx->hashcx); |
935 | 0 | return SECSuccess; |
936 | 0 | } |
937 | | |
938 | | SECStatus |
939 | | VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen) |
940 | 0 | { |
941 | 0 | if (cx->hashcx == NULL) { |
942 | 0 | if (cx->vfycx == NULL) { |
943 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
944 | 0 | return SECFailure; |
945 | 0 | } |
946 | 0 | return PK11_DigestOp(cx->vfycx, input, inputLen); |
947 | 0 | } |
948 | 0 | (*cx->hashobj->update)(cx->hashcx, input, inputLen); |
949 | 0 | return SECSuccess; |
950 | 0 | } |
951 | | |
952 | | static SECStatus |
953 | | vfy_SingleShot(VFYContext *cx, const unsigned char *buf, int len) |
954 | 0 | { |
955 | 0 | SECStatus rv; |
956 | | /* if we have the combo mechanism, do a direct verify */ |
957 | 0 | if (cx->mech != CKM_INVALID_MECHANISM) { |
958 | 0 | SECItem sig = { siBuffer, cx->u.gensig, cx->signatureLen }; |
959 | 0 | SECItem data = { siBuffer, (unsigned char *)buf, len }; |
960 | 0 | return PK11_VerifyWithMechanism(cx->key, cx->mech, &cx->mechparams, |
961 | 0 | &sig, &data, cx->wincx); |
962 | 0 | } |
963 | 0 | rv = VFY_Begin(cx); |
964 | 0 | if (rv != SECSuccess) { |
965 | 0 | return rv; |
966 | 0 | } |
967 | 0 | rv = VFY_Update(cx, (unsigned char *)buf, len); |
968 | 0 | if (rv != SECSuccess) { |
969 | 0 | return rv; |
970 | 0 | } |
971 | 0 | return VFY_End(cx); |
972 | 0 | } |
973 | | |
974 | | SECStatus |
975 | | VFY_EndWithSignature(VFYContext *cx, SECItem *sig) |
976 | 0 | { |
977 | 0 | unsigned char final[HASH_LENGTH_MAX]; |
978 | 0 | unsigned part; |
979 | 0 | SECStatus rv; |
980 | | |
981 | | /* make sure our signature is set (either previously nor now) */ |
982 | 0 | if (sig) { |
983 | 0 | rv = vfy_SetPKCS11SigFromX509Sig(cx, sig); |
984 | 0 | if (rv != SECSuccess) { |
985 | 0 | return SECFailure; |
986 | 0 | } |
987 | 0 | } else if (cx->hasSignature == PR_FALSE) { |
988 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
989 | 0 | return SECFailure; |
990 | 0 | } |
991 | | |
992 | 0 | if (cx->hashcx == NULL) { |
993 | 0 | unsigned int dummy; |
994 | 0 | if (cx->vfycx == NULL) { |
995 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
996 | 0 | return SECFailure; |
997 | 0 | } |
998 | 0 | return PK11_DigestFinal(cx->vfycx, cx->u.gensig, &dummy, |
999 | 0 | cx->signatureLen); |
1000 | 0 | } |
1001 | 0 | (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final)); |
1002 | 0 | SECItem gensig = { siBuffer, cx->u.gensig, cx->signatureLen }; |
1003 | 0 | SECItem hash = { siBuffer, final, part }; |
1004 | 0 | PORT_Assert(part <= sizeof(final)); |
1005 | | /* handle the algorithm specific final call */ |
1006 | 0 | switch (cx->key->keyType) { |
1007 | 0 | case ecKey: |
1008 | 0 | case dsaKey: |
1009 | 0 | if (PK11_Verify(cx->key, &gensig, &hash, cx->wincx) != SECSuccess) { |
1010 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1011 | 0 | return SECFailure; |
1012 | 0 | } |
1013 | 0 | break; |
1014 | 0 | case rsaKey: |
1015 | 0 | if (cx->encAlg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { |
1016 | 0 | if (PK11_VerifyWithMechanism(cx->key, CKM_RSA_PKCS_PSS, |
1017 | 0 | &cx->mechparams, &gensig, &hash, |
1018 | 0 | cx->wincx) != SECSuccess) { |
1019 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1020 | 0 | return SECFailure; |
1021 | 0 | } |
1022 | 0 | } else { |
1023 | 0 | if (sig) { |
1024 | 0 | SECOidTag hashid; |
1025 | 0 | PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN); |
1026 | 0 | rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid, |
1027 | 0 | &cx->pkcs1RSADigestInfo, |
1028 | 0 | &cx->pkcs1RSADigestInfoLen, |
1029 | 0 | cx->key, |
1030 | 0 | sig, cx->wincx); |
1031 | 0 | if (rv != SECSuccess) { |
1032 | 0 | return SECFailure; |
1033 | 0 | } |
1034 | 0 | PORT_Assert(cx->hashAlg == hashid); |
1035 | 0 | } |
1036 | 0 | return verifyPKCS1DigestInfo(cx, &hash); |
1037 | 0 | } |
1038 | 0 | break; |
1039 | 0 | default: |
1040 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1041 | 0 | return SECFailure; /* shouldn't happen */ |
1042 | 0 | } |
1043 | 0 | return SECSuccess; |
1044 | 0 | } |
1045 | | |
1046 | | SECStatus |
1047 | | VFY_End(VFYContext *cx) |
1048 | 0 | { |
1049 | 0 | return VFY_EndWithSignature(cx, NULL); |
1050 | 0 | } |
1051 | | |
1052 | | /************************************************************************/ |
1053 | | /* |
1054 | | * Verify that a previously-computed digest matches a signature. |
1055 | | */ |
1056 | | static SECStatus |
1057 | | vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key, |
1058 | | const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, |
1059 | | CK_MECHANISM_TYPE mech, SECItem *mechparamsp, void *wincx) |
1060 | 0 | { |
1061 | 0 | SECStatus rv; |
1062 | 0 | VFYContext *cx; |
1063 | 0 | SECItem dsasig; /* also used for ECDSA */ |
1064 | 0 | rv = SECFailure; |
1065 | |
|
1066 | 0 | cx = vfy_CreateContext(key, sig, encAlg, hashAlg, mech, mechparamsp, |
1067 | 0 | NULL, PR_TRUE, wincx); |
1068 | 0 | if (cx != NULL) { |
1069 | 0 | switch (key->keyType) { |
1070 | 0 | case rsaKey: |
1071 | | /* PSS isn't handled here for VerifyDigest. SSL |
1072 | | * calls PK11_Verify directly */ |
1073 | 0 | rv = verifyPKCS1DigestInfo(cx, digest); |
1074 | | /* Error (if any) set by verifyPKCS1DigestInfo */ |
1075 | 0 | break; |
1076 | 0 | case ecKey: |
1077 | 0 | case dsaKey: |
1078 | 0 | dsasig.data = cx->u.buffer; |
1079 | 0 | dsasig.len = checkedSignatureLen(cx->key); |
1080 | 0 | if (dsasig.len == 0) { |
1081 | | /* Error set by checkedSignatureLen */ |
1082 | 0 | rv = SECFailure; |
1083 | 0 | break; |
1084 | 0 | } |
1085 | 0 | if (dsasig.len > sizeof(cx->u)) { |
1086 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1087 | 0 | rv = SECFailure; |
1088 | 0 | break; |
1089 | 0 | } |
1090 | 0 | rv = PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx); |
1091 | 0 | if (rv != SECSuccess) { |
1092 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1093 | 0 | } |
1094 | 0 | break; |
1095 | 0 | default: |
1096 | 0 | break; |
1097 | 0 | } |
1098 | 0 | VFY_DestroyContext(cx, PR_TRUE); |
1099 | 0 | } |
1100 | 0 | return rv; |
1101 | 0 | } |
1102 | | |
1103 | | SECStatus |
1104 | | VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key, |
1105 | | const SECItem *sig, SECOidTag encAlg, |
1106 | | SECOidTag hashAlg, void *wincx) |
1107 | 0 | { |
1108 | 0 | CK_MECHANISM_TYPE mech = sec_GetCombinedMech(encAlg, hashAlg); |
1109 | 0 | return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, mech, |
1110 | 0 | NULL, wincx); |
1111 | 0 | } |
1112 | | |
1113 | | SECStatus |
1114 | | VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, |
1115 | | SECOidTag algid, void *wincx) |
1116 | 0 | { |
1117 | 0 | SECOidTag encAlg, hashAlg; |
1118 | 0 | CK_MECHANISM_TYPE mech; |
1119 | 0 | SECItem mechparams; |
1120 | 0 | SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg, |
1121 | 0 | &mech, &mechparams); |
1122 | 0 | if (rv != SECSuccess) { |
1123 | 0 | return SECFailure; |
1124 | 0 | } |
1125 | 0 | return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, |
1126 | 0 | mech, &mechparams, wincx); |
1127 | 0 | } |
1128 | | |
1129 | | /* |
1130 | | * this function takes an optional hash oid, which the digest function |
1131 | | * will be compared with our target hash value. |
1132 | | */ |
1133 | | SECStatus |
1134 | | VFY_VerifyDigestWithAlgorithmID(const SECItem *digest, |
1135 | | const SECKEYPublicKey *key, const SECItem *sig, |
1136 | | const SECAlgorithmID *sigAlgorithm, |
1137 | | SECOidTag hashCmp, void *wincx) |
1138 | 0 | { |
1139 | 0 | SECOidTag encAlg, hashAlg; |
1140 | 0 | CK_MECHANISM_TYPE mech; |
1141 | 0 | SECItem mechparams; |
1142 | 0 | SECStatus rv = sec_DecodeSigAlg(key, |
1143 | 0 | SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), |
1144 | 0 | &sigAlgorithm->parameters, &encAlg, &hashAlg, |
1145 | 0 | &mech, &mechparams); |
1146 | 0 | if (rv != SECSuccess) { |
1147 | 0 | return rv; |
1148 | 0 | } |
1149 | 0 | if (hashCmp != SEC_OID_UNKNOWN && |
1150 | 0 | hashAlg != SEC_OID_UNKNOWN && |
1151 | 0 | hashCmp != hashAlg) { |
1152 | 0 | if (mechparams.data != NULL) { |
1153 | 0 | PORT_Free(mechparams.data); |
1154 | 0 | } |
1155 | 0 | PORT_SetError(SEC_ERROR_BAD_SIGNATURE); |
1156 | 0 | return SECFailure; |
1157 | 0 | } |
1158 | 0 | return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, |
1159 | 0 | mech, &mechparams, wincx); |
1160 | 0 | } |
1161 | | |
1162 | | static SECStatus |
1163 | | vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, |
1164 | | const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg, |
1165 | | CK_MECHANISM_TYPE mech, SECItem *mechparamsp, |
1166 | | SECOidTag *hash, void *wincx) |
1167 | 0 | { |
1168 | 0 | SECStatus rv; |
1169 | 0 | VFYContext *cx; |
1170 | |
|
1171 | 0 | cx = vfy_CreateContext(key, sig, encAlg, hashAlg, mech, mechparamsp, |
1172 | 0 | hash, PR_FALSE, wincx); |
1173 | 0 | if (cx == NULL) |
1174 | 0 | return SECFailure; |
1175 | | |
1176 | 0 | rv = vfy_SingleShot(cx, buf, len); |
1177 | |
|
1178 | 0 | VFY_DestroyContext(cx, PR_TRUE); |
1179 | 0 | return rv; |
1180 | 0 | } |
1181 | | |
1182 | | SECStatus |
1183 | | VFY_VerifyDataDirect(const unsigned char *buf, int len, |
1184 | | const SECKEYPublicKey *key, const SECItem *sig, |
1185 | | SECOidTag encAlg, SECOidTag hashAlg, |
1186 | | SECOidTag *hash, void *wincx) |
1187 | 0 | { |
1188 | 0 | CK_MECHANISM_TYPE mech = sec_GetCombinedMech(encAlg, hashAlg); |
1189 | 0 | return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, mech, NULL, |
1190 | 0 | hash, wincx); |
1191 | 0 | } |
1192 | | |
1193 | | SECStatus |
1194 | | VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key, |
1195 | | const SECItem *sig, SECOidTag algid, void *wincx) |
1196 | 0 | { |
1197 | 0 | SECOidTag encAlg, hashAlg; |
1198 | 0 | CK_MECHANISM_TYPE mech; |
1199 | 0 | SECItem mechparams; |
1200 | 0 | SECStatus rv = sec_DecodeSigAlg(key, algid, NULL, &encAlg, &hashAlg, |
1201 | 0 | &mech, &mechparams); |
1202 | 0 | if (rv != SECSuccess) { |
1203 | 0 | return rv; |
1204 | 0 | } |
1205 | 0 | return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, |
1206 | 0 | mech, &mechparams, NULL, wincx); |
1207 | 0 | } |
1208 | | |
1209 | | SECStatus |
1210 | | VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, |
1211 | | const SECKEYPublicKey *key, |
1212 | | const SECItem *sig, |
1213 | | const SECAlgorithmID *sigAlgorithm, |
1214 | | SECOidTag *hash, void *wincx) |
1215 | 0 | { |
1216 | 0 | SECOidTag encAlg, hashAlg; |
1217 | 0 | SECOidTag sigAlg = SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm); |
1218 | 0 | CK_MECHANISM_TYPE mech; |
1219 | 0 | SECItem mechparams; |
1220 | 0 | SECStatus rv = sec_DecodeSigAlg(key, sigAlg, |
1221 | 0 | &sigAlgorithm->parameters, &encAlg, &hashAlg, |
1222 | 0 | &mech, &mechparams); |
1223 | 0 | if (rv != SECSuccess) { |
1224 | 0 | return rv; |
1225 | 0 | } |
1226 | 0 | return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, mech, |
1227 | 0 | &mechparams, hash, wincx); |
1228 | 0 | } |