Bug Summary

File:s/lib/cryptohi/secvfy.c
Warning:line 508, column 5
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name secvfy.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/cryptohi -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/cryptohi -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -I ../../../dist/public/nssutil -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-06-034810-12449-1 -x c secvfy.c
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
21/*
22** Recover the DigestInfo from an RSA PKCS#1 signature.
23**
24** If givenDigestAlg != SEC_OID_UNKNOWN, copy givenDigestAlg to digestAlgOut.
25** Otherwise, parse the DigestInfo structure and store the decoded digest
26** algorithm into digestAlgOut.
27**
28** Store the encoded DigestInfo into digestInfo.
29** Store the DigestInfo length into digestInfoLen.
30**
31** This function does *not* verify that the AlgorithmIdentifier in the
32** DigestInfo identifies givenDigestAlg or that the DigestInfo is encoded
33** correctly; verifyPKCS1DigestInfo does that.
34**
35** XXX this is assuming that the signature algorithm has WITH_RSA_ENCRYPTION
36*/
37static SECStatus
38recoverPKCS1DigestInfo(SECOidTag givenDigestAlg,
39 /*out*/ SECOidTag *digestAlgOut,
40 /*out*/ unsigned char **digestInfo,
41 /*out*/ unsigned int *digestInfoLen,
42 SECKEYPublicKey *key,
43 const SECItem *sig, void *wincx)
44{
45 SGNDigestInfo *di = NULL((void*)0);
46 SECItem it;
47 PRBool rv = SECSuccess;
48
49 PORT_Assert(digestAlgOut)((digestAlgOut)?((void)0):PR_Assert("digestAlgOut","secvfy.c"
,49))
;
50 PORT_Assert(digestInfo)((digestInfo)?((void)0):PR_Assert("digestInfo","secvfy.c",50)
)
;
51 PORT_Assert(digestInfoLen)((digestInfoLen)?((void)0):PR_Assert("digestInfoLen","secvfy.c"
,51))
;
52 PORT_Assert(key)((key)?((void)0):PR_Assert("key","secvfy.c",52));
53 PORT_Assert(key->keyType == rsaKey)((key->keyType == rsaKey)?((void)0):PR_Assert("key->keyType == rsaKey"
,"secvfy.c",53))
;
54 PORT_Assert(sig)((sig)?((void)0):PR_Assert("sig","secvfy.c",54));
55
56 it.data = NULL((void*)0);
57 it.len = SECKEY_PublicKeyStrength(key);
58 if (it.len != 0) {
59 it.data = (unsigned char *)PORT_AllocPORT_Alloc_Util(it.len);
60 }
61 if (it.len == 0 || it.data == NULL((void*)0)) {
62 rv = SECFailure;
63 }
64
65 if (rv == SECSuccess) {
66 /* decrypt the block */
67 rv = PK11_VerifyRecover(key, sig, &it, wincx);
68 }
69
70 if (rv == SECSuccess) {
71 if (givenDigestAlg != SEC_OID_UNKNOWN) {
72 /* We don't need to parse the DigestInfo if the caller gave us the
73 * digest algorithm to use. Later verifyPKCS1DigestInfo will verify
74 * that the DigestInfo identifies the given digest algorithm and
75 * that the DigestInfo is encoded absolutely correctly.
76 */
77 *digestInfoLen = it.len;
78 *digestInfo = (unsigned char *)it.data;
79 *digestAlgOut = givenDigestAlg;
80 return SECSuccess;
81 }
82 }
83
84 if (rv == SECSuccess) {
85 /* The caller didn't specify a digest algorithm to use, so choose the
86 * digest algorithm by parsing the AlgorithmIdentifier within the
87 * DigestInfo.
88 */
89 di = SGN_DecodeDigestInfo(&it);
90 if (!di) {
91 rv = SECFailure;
92 }
93 }
94
95 if (rv == SECSuccess) {
96 *digestAlgOut = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&di->digestAlgorithm);
97 if (*digestAlgOut == SEC_OID_UNKNOWN) {
98 rv = SECFailure;
99 }
100 }
101
102 if (di) {
103 SGN_DestroyDigestInfoSGN_DestroyDigestInfo_Util(di);
104 }
105
106 if (rv == SECSuccess) {
107 *digestInfoLen = it.len;
108 *digestInfo = (unsigned char *)it.data;
109 } else {
110 if (it.data) {
111 PORT_FreePORT_Free_Util(it.data);
112 }
113 *digestInfo = NULL((void*)0);
114 *digestInfoLen = 0;
115 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
116 }
117
118 return rv;
119}
120
121struct VFYContextStr {
122 SECOidTag hashAlg; /* the hash algorithm */
123 SECKEYPublicKey *key;
124 /*
125 * This buffer holds either the digest or the full signature
126 * depending on the type of the signature (key->keyType). It is
127 * defined as a union to make sure it always has enough space.
128 *
129 * Use the "buffer" union member to reference the buffer.
130 * Note: do not take the size of the "buffer" union member. Take
131 * the size of the union or some other union member instead.
132 */
133 union {
134 unsigned char buffer[1];
135
136 /* the full DSA signature... 40 bytes */
137 unsigned char dsasig[DSA_MAX_SIGNATURE_LEN(32 * 2)];
138 /* the full ECDSA signature */
139 unsigned char ecdsasig[2 * MAX_ECKEY_LEN72];
140 /* the full RSA signature, only used in RSA-PSS */
141 unsigned char rsasig[(RSA_MAX_MODULUS_BITS16384 + 7) / 8];
142 } u;
143 unsigned int pkcs1RSADigestInfoLen;
144 /* the encoded DigestInfo from a RSA PKCS#1 signature */
145 unsigned char *pkcs1RSADigestInfo;
146 void *wincx;
147 void *hashcx;
148 const SECHashObject *hashobj;
149 SECOidTag encAlg; /* enc alg */
150 PRBool hasSignature; /* true if the signature was provided in the
151 * VFY_CreateContext call. If false, the
152 * signature must be provided with a
153 * VFY_EndWithSignature call. */
154 SECItem *params;
155};
156
157static SECStatus
158verifyPKCS1DigestInfo(const VFYContext *cx, const SECItem *digest)
159{
160 SECItem pkcs1DigestInfo;
161 pkcs1DigestInfo.data = cx->pkcs1RSADigestInfo;
162 pkcs1DigestInfo.len = cx->pkcs1RSADigestInfoLen;
163 return _SGN_VerifyPKCS1DigestInfo(
164 cx->hashAlg, digest, &pkcs1DigestInfo,
165 PR_FALSE0 /*XXX: unsafeAllowMissingParameters*/);
166}
167
168static unsigned int
169checkedSignatureLen(const SECKEYPublicKey *pubk)
170{
171 unsigned int sigLen = SECKEY_SignatureLen(pubk);
172 if (sigLen == 0) {
173 /* Error set by SECKEY_SignatureLen */
174 return sigLen;
175 }
176 unsigned int maxSigLen;
177 switch (pubk->keyType) {
178 case rsaKey:
179 case rsaPssKey:
180 maxSigLen = (RSA_MAX_MODULUS_BITS16384 + 7) / 8;
181 break;
182 case dsaKey:
183 maxSigLen = DSA_MAX_SIGNATURE_LEN(32 * 2);
184 break;
185 case ecKey:
186 maxSigLen = 2 * MAX_ECKEY_LEN72;
187 break;
188 default:
189 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_UNSUPPORTED_KEYALG);
190 return 0;
191 }
192 if (sigLen > maxSigLen) {
193 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_KEY);
194 return 0;
195 }
196 return sigLen;
197}
198
199/*
200 * decode the ECDSA or DSA signature from it's DER wrapping.
201 * The unwrapped/raw signature is placed in the buffer pointed
202 * to by dsig and has enough room for len bytes.
203 */
204static SECStatus
205decodeECorDSASignature(SECOidTag algid, const SECItem *sig, unsigned char *dsig,
206 unsigned int len)
207{
208 SECItem *dsasig = NULL((void*)0); /* also used for ECDSA */
209
210 /* Safety: Ensure algId is as expected and that signature size is within maxmimums */
211 if (algid == SEC_OID_ANSIX9_DSA_SIGNATURE) {
212 if (len > DSA_MAX_SIGNATURE_LEN(32 * 2)) {
213 goto loser;
214 }
215 } else if (algid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
216 if (len > MAX_ECKEY_LEN72 * 2) {
217 goto loser;
218 }
219 } else {
220 goto loser;
221 }
222
223 /* Decode and pad to length */
224 dsasig = DSAU_DecodeDerSigToLen((SECItem *)sig, len);
225 if (dsasig == NULL((void*)0)) {
226 goto loser;
227 }
228 if (dsasig->len != len) {
229 SECITEM_FreeItemSECITEM_FreeItem_Util(dsasig, PR_TRUE1);
230 goto loser;
231 }
232
233 PORT_Memcpymemcpy(dsig, dsasig->data, len);
234 SECITEM_FreeItemSECITEM_FreeItem_Util(dsasig, PR_TRUE1);
235
236 return SECSuccess;
237
238loser:
239 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_DER);
240 return SECFailure;
241}
242
243const SEC_ASN1Template hashParameterTemplate[] = {
244 { SEC_ASN1_SEQUENCE0x10, 0, NULL((void*)0), sizeof(SECItem) },
245 { SEC_ASN1_OBJECT_ID0x06, 0 },
246 { SEC_ASN1_SKIP_REST0x80000 },
247 { 0 }
248};
249
250/*
251 * Get just the encryption algorithm from the signature algorithm
252 */
253SECOidTag
254sec_GetEncAlgFromSigAlg(SECOidTag sigAlg)
255{
256 /* get the "encryption" algorithm */
257 switch (sigAlg) {
258 case SEC_OID_PKCS1_RSA_ENCRYPTION:
259 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
260 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
261 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
262 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
263 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
264 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
265 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
266 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
267 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
268 return SEC_OID_PKCS1_RSA_ENCRYPTION;
269 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
270 return SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
271
272 /* what about normal DSA? */
273 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
274 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
275 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
276 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
277 return SEC_OID_ANSIX9_DSA_SIGNATURE;
278 case SEC_OID_MISSI_DSS:
279 case SEC_OID_MISSI_KEA_DSS:
280 case SEC_OID_MISSI_KEA_DSS_OLD:
281 case SEC_OID_MISSI_DSS_OLD:
282 return SEC_OID_MISSI_DSS;
283 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
284 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
285 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
286 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
287 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
288 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
289 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
290 return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
291 /* we don't implement MD4 hashes */
292 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
293 default:
294 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM);
295 break;
296 }
297 return SEC_OID_UNKNOWN;
298}
299
300/*
301 * Pulls the hash algorithm, signing algorithm, and key type out of a
302 * composite algorithm.
303 *
304 * sigAlg: the composite algorithm to dissect.
305 * hashalg: address of a SECOidTag which will be set with the hash algorithm.
306 * encalg: address of a SECOidTag which will be set with the signing alg.
307 *
308 * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the
309 * algorithm was not found or was not a signing algorithm.
310 */
311SECStatus
312sec_DecodeSigAlg(const SECKEYPublicKey *key, SECOidTag sigAlg,
313 const SECItem *param, SECOidTag *encalgp, SECOidTag *hashalg)
314{
315 unsigned int len;
316 PLArenaPool *arena;
317 SECStatus rv;
318 SECItem oid;
319 SECOidTag encalg;
320
321 PR_ASSERT(hashalg != NULL)((hashalg != ((void*)0))?((void)0):PR_Assert("hashalg != NULL"
,"secvfy.c",321))
;
322 PR_ASSERT(encalgp != NULL)((encalgp != ((void*)0))?((void)0):PR_Assert("encalgp != NULL"
,"secvfy.c",322))
;
323
324 switch (sigAlg) {
325 /* We probably shouldn't be generating MD2 signatures either */
326 case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
327 *hashalg = SEC_OID_MD2;
328 break;
329 case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
330 *hashalg = SEC_OID_MD5;
331 break;
332 case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
333 case SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE:
334 case SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE:
335 *hashalg = SEC_OID_SHA1;
336 break;
337 case SEC_OID_PKCS1_RSA_ENCRYPTION:
338 *hashalg = SEC_OID_UNKNOWN; /* get it from the RSA signature */
339 break;
340 case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
341 if (param && param->data) {
342 PORTCheapArenaPool tmpArena;
343
344 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE(2048));
345 rv = sec_DecodeRSAPSSParams(&tmpArena.arena, param,
346 hashalg, NULL((void*)0), NULL((void*)0));
347 PORT_DestroyCheapArena(&tmpArena);
348
349 /* only accept hash algorithms */
350 if (rv != SECSuccess || HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
351 /* error set by sec_DecodeRSAPSSParams or HASH_GetHashTypeByOidTag */
352 return SECFailure;
353 }
354 } else {
355 *hashalg = SEC_OID_SHA1; /* default, SHA-1 */
356 }
357 break;
358
359 case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE:
360 case SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION:
361 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST:
362 *hashalg = SEC_OID_SHA224;
363 break;
364 case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE:
365 case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
366 case SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST:
367 *hashalg = SEC_OID_SHA256;
368 break;
369 case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE:
370 case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
371 *hashalg = SEC_OID_SHA384;
372 break;
373 case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE:
374 case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
375 *hashalg = SEC_OID_SHA512;
376 break;
377
378 /* what about normal DSA? */
379 case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
380 case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST:
381 case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
382 *hashalg = SEC_OID_SHA1;
383 break;
384 case SEC_OID_MISSI_DSS:
385 case SEC_OID_MISSI_KEA_DSS:
386 case SEC_OID_MISSI_KEA_DSS_OLD:
387 case SEC_OID_MISSI_DSS_OLD:
388 *hashalg = SEC_OID_SHA1;
389 break;
390 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST:
391 /* This is an EC algorithm. Recommended means the largest
392 * hash algorithm that is not reduced by the keysize of
393 * the EC algorithm. Note that key strength is in bytes and
394 * algorithms are specified in bits. Never use an algorithm
395 * weaker than sha1. */
396 len = SECKEY_PublicKeyStrength(key);
397 if (len < 28) { /* 28 bytes == 224 bits */
398 *hashalg = SEC_OID_SHA1;
399 } else if (len < 32) { /* 32 bytes == 256 bits */
400 *hashalg = SEC_OID_SHA224;
401 } else if (len < 48) { /* 48 bytes == 384 bits */
402 *hashalg = SEC_OID_SHA256;
403 } else if (len < 64) { /* 48 bytes == 512 bits */
404 *hashalg = SEC_OID_SHA384;
405 } else {
406 /* use the largest in this case */
407 *hashalg = SEC_OID_SHA512;
408 }
409 break;
410 case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST:
411 if (param == NULL((void*)0)) {
412 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM);
413 return SECFailure;
414 }
415 arena = PORT_NewArenaPORT_NewArena_Util(DER_DEFAULT_CHUNKSIZE(2048));
416 if (arena == NULL((void*)0)) {
417 return SECFailure;
418 }
419 rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, &oid, hashParameterTemplate, param);
420 if (rv == SECSuccess) {
421 *hashalg = SECOID_FindOIDTagSECOID_FindOIDTag_Util(&oid);
422 }
423 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0);
424 if (rv != SECSuccess) {
425 return rv;
426 }
427 /* only accept hash algorithms */
428 if (HASH_GetHashTypeByOidTag(*hashalg) == HASH_AlgNULL) {
429 /* error set by HASH_GetHashTypeByOidTag */
430 return SECFailure;
431 }
432 break;
433 /* we don't implement MD4 hashes */
434 case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
435 default:
436 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM);
437 return SECFailure;
438 }
439
440 encalg = sec_GetEncAlgFromSigAlg(sigAlg);
441 if (encalg == SEC_OID_UNKNOWN) {
442 return SECFailure;
443 }
444 *encalgp = encalg;
445
446 return SECSuccess;
447}
448
449/*
450 * we can verify signatures that come from 2 different sources:
451 * one in with the signature contains a signature oid, and the other
452 * in which the signature is managed by a Public key (encAlg) oid
453 * and a hash oid. The latter is the more basic, so that's what
454 * our base vfyCreate function takes.
455 *
456 * There is one noteworthy corner case, if we are using an RSA key, and the
457 * signature block is provided, then the hashAlg can be specified as
458 * SEC_OID_UNKNOWN. In this case, verify will use the hash oid supplied
459 * in the RSA signature block.
460 */
461static VFYContext *
462vfy_CreateContext(const SECKEYPublicKey *key, const SECItem *sig,
463 SECOidTag encAlg, SECOidTag hashAlg, SECOidTag *hash, void *wincx)
464{
465 VFYContext *cx;
466 SECStatus rv;
467 unsigned int sigLen;
468 KeyType type;
469 PRUint32 policyFlags;
470 PRInt32 optFlags;
471
472 /* make sure the encryption algorithm matches the key type */
473 /* RSA-PSS algorithm can be used with both rsaKey and rsaPssKey */
474 type = seckey_GetKeyType(encAlg);
475 if ((key->keyType != type) &&
476 ((key->keyType != rsaKey) || (type != rsaPssKey))) {
477 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS7_KEYALG_MISMATCH);
478 return NULL((void*)0);
479 }
480 if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS0x00e, &optFlags) != SECFailure) {
481 if (optFlags & NSS_KEY_SIZE_POLICY_VERIFY_FLAG2) {
482 rv = seckey_EnforceKeySize(key->keyType,
483 SECKEY_PublicKeyStrengthInBits(key),
484 SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
485 if (rv != SECSuccess) {
486 return NULL((void*)0);
487 }
488 }
489 }
490 /* check the policy on the encryption algorithm */
491 if ((NSS_GetAlgorithmPolicy(encAlg, &policyFlags) == SECFailure) ||
492 !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE0x00000020)) {
493 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
494 return NULL((void*)0);
495 }
496
497 cx = (VFYContext *)PORT_ZAllocPORT_ZAlloc_Util(sizeof(VFYContext));
498 if (cx == NULL((void*)0)) {
499 goto loser;
500 }
501
502 cx->wincx = wincx;
503 cx->hasSignature = (sig != NULL((void*)0));
504 cx->encAlg = encAlg;
505 cx->hashAlg = hashAlg;
506 cx->key = SECKEY_CopyPublicKey(key);
507 cx->pkcs1RSADigestInfo = NULL((void*)0);
508 rv = SECSuccess;
Value stored to 'rv' is never read
509 if (sig) {
510 rv = SECFailure;
511 if (type == rsaKey) {
512 rv = recoverPKCS1DigestInfo(hashAlg, &cx->hashAlg,
513 &cx->pkcs1RSADigestInfo,
514 &cx->pkcs1RSADigestInfoLen,
515 cx->key,
516 sig, wincx);
517 } else {
518 sigLen = checkedSignatureLen(key);
519 /* Check signature length is within limits */
520 if (sigLen == 0) {
521 /* error set by checkedSignatureLen */
522 rv = SECFailure;
523 goto loser;
524 }
525 if (sigLen > sizeof(cx->u)) {
526 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
527 rv = SECFailure;
528 goto loser;
529 }
530 switch (type) {
531 case rsaPssKey:
532 if (sig->len != sigLen) {
533 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
534 rv = SECFailure;
535 goto loser;
536 }
537 PORT_Memcpymemcpy(cx->u.buffer, sig->data, sigLen);
538 rv = SECSuccess;
539 break;
540 case ecKey:
541 case dsaKey:
542 /* decodeECorDSASignature will check sigLen == sig->len after padding */
543 rv = decodeECorDSASignature(encAlg, sig, cx->u.buffer, sigLen);
544 break;
545 default:
546 /* Unreachable */
547 rv = SECFailure;
548 goto loser;
549 }
550 }
551 if (rv != SECSuccess) {
552 goto loser;
553 }
554 }
555
556 /* check hash alg again, RSA may have changed it.*/
557 if (HASH_GetHashTypeByOidTag(cx->hashAlg) == HASH_AlgNULL) {
558 /* error set by HASH_GetHashTypeByOidTag */
559 goto loser;
560 }
561 /* check the policy on the hash algorithm. Do this after
562 * the rsa decode because some uses of this function get hash implicitly
563 * from the RSA signature itself. */
564 if ((NSS_GetAlgorithmPolicy(cx->hashAlg, &policyFlags) == SECFailure) ||
565 !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE0x00000020)) {
566 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
567 goto loser;
568 }
569
570 if (hash) {
571 *hash = cx->hashAlg;
572 }
573 return cx;
574
575loser:
576 if (cx) {
577 VFY_DestroyContext(cx, PR_TRUE1);
578 }
579 return 0;
580}
581
582VFYContext *
583VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag sigAlg,
584 void *wincx)
585{
586 SECOidTag encAlg, hashAlg;
587 SECStatus rv = sec_DecodeSigAlg(key, sigAlg, NULL((void*)0), &encAlg, &hashAlg);
588 if (rv != SECSuccess) {
589 return NULL((void*)0);
590 }
591 return vfy_CreateContext(key, sig, encAlg, hashAlg, NULL((void*)0), wincx);
592}
593
594VFYContext *
595VFY_CreateContextDirect(const SECKEYPublicKey *key, const SECItem *sig,
596 SECOidTag encAlg, SECOidTag hashAlg,
597 SECOidTag *hash, void *wincx)
598{
599 return vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
600}
601
602VFYContext *
603VFY_CreateContextWithAlgorithmID(const SECKEYPublicKey *key, const SECItem *sig,
604 const SECAlgorithmID *sigAlgorithm, SECOidTag *hash, void *wincx)
605{
606 VFYContext *cx;
607 SECOidTag encAlg, hashAlg;
608 SECStatus rv = sec_DecodeSigAlg(key,
609 SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util((SECAlgorithmID *)sigAlgorithm),
610 &sigAlgorithm->parameters, &encAlg, &hashAlg);
611 if (rv != SECSuccess) {
612 return NULL((void*)0);
613 }
614
615 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
616 if (sigAlgorithm->parameters.data) {
617 cx->params = SECITEM_DupItemSECITEM_DupItem_Util(&sigAlgorithm->parameters);
618 }
619
620 return cx;
621}
622
623void
624VFY_DestroyContext(VFYContext *cx, PRBool freeit)
625{
626 if (cx) {
627 if (cx->hashcx != NULL((void*)0)) {
628 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE1);
629 cx->hashcx = NULL((void*)0);
630 }
631 if (cx->key) {
632 SECKEY_DestroyPublicKey(cx->key);
633 }
634 if (cx->pkcs1RSADigestInfo) {
635 PORT_FreePORT_Free_Util(cx->pkcs1RSADigestInfo);
636 }
637 if (cx->params) {
638 SECITEM_FreeItemSECITEM_FreeItem_Util(cx->params, PR_TRUE1);
639 }
640 if (freeit) {
641 PORT_ZFreePORT_ZFree_Util(cx, sizeof(VFYContext));
642 }
643 }
644}
645
646SECStatus
647VFY_Begin(VFYContext *cx)
648{
649 if (cx->hashcx != NULL((void*)0)) {
650 (*cx->hashobj->destroy)(cx->hashcx, PR_TRUE1);
651 cx->hashcx = NULL((void*)0);
652 }
653
654 cx->hashobj = HASH_GetHashObjectByOidTag(cx->hashAlg);
655 if (!cx->hashobj)
656 return SECFailure; /* error code is set */
657
658 cx->hashcx = (*cx->hashobj->create)();
659 if (cx->hashcx == NULL((void*)0))
660 return SECFailure;
661
662 (*cx->hashobj->begin)(cx->hashcx);
663 return SECSuccess;
664}
665
666SECStatus
667VFY_Update(VFYContext *cx, const unsigned char *input, unsigned inputLen)
668{
669 if (cx->hashcx == NULL((void*)0)) {
670 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
671 return SECFailure;
672 }
673 (*cx->hashobj->update)(cx->hashcx, input, inputLen);
674 return SECSuccess;
675}
676
677SECStatus
678VFY_EndWithSignature(VFYContext *cx, SECItem *sig)
679{
680 unsigned char final[HASH_LENGTH_MAX64];
681 unsigned part;
682 SECItem hash, rsasig, dsasig; /* dsasig is also used for ECDSA */
683 SECStatus rv;
684
685 if ((cx->hasSignature == PR_FALSE0) && (sig == NULL((void*)0))) {
686 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
687 return SECFailure;
688 }
689
690 if (cx->hashcx == NULL((void*)0)) {
691 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
692 return SECFailure;
693 }
694 (*cx->hashobj->end)(cx->hashcx, final, &part, sizeof(final));
695 switch (cx->key->keyType) {
696 case ecKey:
697 case dsaKey:
698 dsasig.len = checkedSignatureLen(cx->key);
699 if (dsasig.len == 0) {
700 return SECFailure;
701 }
702 if (dsasig.len > sizeof(cx->u)) {
703 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
704 return SECFailure;
705 }
706 dsasig.data = cx->u.buffer;
707
708 if (sig) {
709 rv = decodeECorDSASignature(cx->encAlg, sig, dsasig.data,
710 dsasig.len);
711 if (rv != SECSuccess) {
712 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
713 return SECFailure;
714 }
715 }
716 hash.data = final;
717 hash.len = part;
718 if (PK11_Verify(cx->key, &dsasig, &hash, cx->wincx) != SECSuccess) {
719 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
720 return SECFailure;
721 }
722 break;
723 case rsaKey:
724 if (cx->encAlg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
725 CK_RSA_PKCS_PSS_PARAMS mech;
726 SECItem mechItem = { siBuffer, (unsigned char *)&mech, sizeof(mech) };
727 PORTCheapArenaPool tmpArena;
728
729 PORT_InitCheapArena(&tmpArena, DER_DEFAULT_CHUNKSIZE(2048));
730 rv = sec_DecodeRSAPSSParamsToMechanism(&tmpArena.arena,
731 cx->params,
732 &mech);
733 PORT_DestroyCheapArena(&tmpArena);
734 if (rv != SECSuccess) {
735 return SECFailure;
736 }
737
738 rsasig.data = cx->u.buffer;
739 rsasig.len = checkedSignatureLen(cx->key);
740 if (rsasig.len == 0) {
741 /* Error set by checkedSignatureLen */
742 return SECFailure;
743 }
744 if (rsasig.len > sizeof(cx->u)) {
745 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
746 return SECFailure;
747 }
748 if (sig) {
749 if (sig->len != rsasig.len) {
750 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
751 return SECFailure;
752 }
753 PORT_Memcpymemcpy(rsasig.data, sig->data, rsasig.len);
754 }
755 hash.data = final;
756 hash.len = part;
757 if (PK11_VerifyWithMechanism(cx->key, CKM_RSA_PKCS_PSS0x0000000DUL, &mechItem,
758 &rsasig, &hash, cx->wincx) != SECSuccess) {
759 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
760 return SECFailure;
761 }
762 } else {
763 SECItem digest;
764 digest.data = final;
765 digest.len = part;
766 if (sig) {
767 SECOidTag hashid;
768 PORT_Assert(cx->hashAlg != SEC_OID_UNKNOWN)((cx->hashAlg != SEC_OID_UNKNOWN)?((void)0):PR_Assert("cx->hashAlg != SEC_OID_UNKNOWN"
,"secvfy.c",768))
;
769 rv = recoverPKCS1DigestInfo(cx->hashAlg, &hashid,
770 &cx->pkcs1RSADigestInfo,
771 &cx->pkcs1RSADigestInfoLen,
772 cx->key,
773 sig, cx->wincx);
774 if (rv != SECSuccess) {
775 return SECFailure;
776 }
777 PORT_Assert(cx->hashAlg == hashid)((cx->hashAlg == hashid)?((void)0):PR_Assert("cx->hashAlg == hashid"
,"secvfy.c",777))
;
778 }
779 return verifyPKCS1DigestInfo(cx, &digest);
780 }
781 break;
782 default:
783 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
784 return SECFailure; /* shouldn't happen */
785 }
786 return SECSuccess;
787}
788
789SECStatus
790VFY_End(VFYContext *cx)
791{
792 return VFY_EndWithSignature(cx, NULL((void*)0));
793}
794
795/************************************************************************/
796/*
797 * Verify that a previously-computed digest matches a signature.
798 */
799static SECStatus
800vfy_VerifyDigest(const SECItem *digest, const SECKEYPublicKey *key,
801 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
802 void *wincx)
803{
804 SECStatus rv;
805 VFYContext *cx;
806 SECItem dsasig; /* also used for ECDSA */
807 rv = SECFailure;
808
809 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, NULL((void*)0), wincx);
810 if (cx != NULL((void*)0)) {
811 switch (key->keyType) {
812 case rsaKey:
813 rv = verifyPKCS1DigestInfo(cx, digest);
814 /* Error (if any) set by verifyPKCS1DigestInfo */
815 break;
816 case ecKey:
817 case dsaKey:
818 dsasig.data = cx->u.buffer;
819 dsasig.len = checkedSignatureLen(cx->key);
820 if (dsasig.len == 0) {
821 /* Error set by checkedSignatureLen */
822 rv = SECFailure;
823 break;
824 }
825 if (dsasig.len > sizeof(cx->u)) {
826 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
827 rv = SECFailure;
828 break;
829 }
830 rv = PK11_Verify(cx->key, &dsasig, (SECItem *)digest, cx->wincx);
831 if (rv != SECSuccess) {
832 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
833 }
834 break;
835 default:
836 break;
837 }
838 VFY_DestroyContext(cx, PR_TRUE1);
839 }
840 return rv;
841}
842
843SECStatus
844VFY_VerifyDigestDirect(const SECItem *digest, const SECKEYPublicKey *key,
845 const SECItem *sig, SECOidTag encAlg,
846 SECOidTag hashAlg, void *wincx)
847{
848 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
849}
850
851SECStatus
852VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig,
853 SECOidTag algid, void *wincx)
854{
855 SECOidTag encAlg, hashAlg;
856 SECStatus rv = sec_DecodeSigAlg(key, algid, NULL((void*)0), &encAlg, &hashAlg);
857 if (rv != SECSuccess) {
858 return SECFailure;
859 }
860 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
861}
862
863/*
864 * this function takes an optional hash oid, which the digest function
865 * will be compared with our target hash value.
866 */
867SECStatus
868VFY_VerifyDigestWithAlgorithmID(const SECItem *digest,
869 const SECKEYPublicKey *key, const SECItem *sig,
870 const SECAlgorithmID *sigAlgorithm,
871 SECOidTag hashCmp, void *wincx)
872{
873 SECOidTag encAlg, hashAlg;
874 SECStatus rv = sec_DecodeSigAlg(key,
875 SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util((SECAlgorithmID *)sigAlgorithm),
876 &sigAlgorithm->parameters, &encAlg, &hashAlg);
877 if (rv != SECSuccess) {
878 return rv;
879 }
880 if (hashCmp != SEC_OID_UNKNOWN &&
881 hashAlg != SEC_OID_UNKNOWN &&
882 hashCmp != hashAlg) {
883 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_BAD_SIGNATURE);
884 return SECFailure;
885 }
886 return vfy_VerifyDigest(digest, key, sig, encAlg, hashAlg, wincx);
887}
888
889static SECStatus
890vfy_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
891 const SECItem *sig, SECOidTag encAlg, SECOidTag hashAlg,
892 const SECItem *params, SECOidTag *hash, void *wincx)
893{
894 SECStatus rv;
895 VFYContext *cx;
896
897 cx = vfy_CreateContext(key, sig, encAlg, hashAlg, hash, wincx);
898 if (cx == NULL((void*)0))
899 return SECFailure;
900 if (params) {
901 cx->params = SECITEM_DupItemSECITEM_DupItem_Util(params);
902 }
903
904 rv = VFY_Begin(cx);
905 if (rv == SECSuccess) {
906 rv = VFY_Update(cx, (unsigned char *)buf, len);
907 if (rv == SECSuccess)
908 rv = VFY_End(cx);
909 }
910
911 VFY_DestroyContext(cx, PR_TRUE1);
912 return rv;
913}
914
915SECStatus
916VFY_VerifyDataDirect(const unsigned char *buf, int len,
917 const SECKEYPublicKey *key, const SECItem *sig,
918 SECOidTag encAlg, SECOidTag hashAlg,
919 SECOidTag *hash, void *wincx)
920{
921 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL((void*)0), hash, wincx);
922}
923
924SECStatus
925VFY_VerifyData(const unsigned char *buf, int len, const SECKEYPublicKey *key,
926 const SECItem *sig, SECOidTag algid, void *wincx)
927{
928 SECOidTag encAlg, hashAlg;
929 SECStatus rv = sec_DecodeSigAlg(key, algid, NULL((void*)0), &encAlg, &hashAlg);
930 if (rv != SECSuccess) {
931 return rv;
932 }
933 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg, NULL((void*)0), NULL((void*)0), wincx);
934}
935
936SECStatus
937VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len,
938 const SECKEYPublicKey *key,
939 const SECItem *sig,
940 const SECAlgorithmID *sigAlgorithm,
941 SECOidTag *hash, void *wincx)
942{
943 SECOidTag encAlg, hashAlg;
944 SECOidTag sigAlg = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util((SECAlgorithmID *)sigAlgorithm);
945 SECStatus rv = sec_DecodeSigAlg(key, sigAlg,
946 &sigAlgorithm->parameters, &encAlg, &hashAlg);
947 if (rv != SECSuccess) {
948 return rv;
949 }
950 return vfy_VerifyData(buf, len, key, sig, encAlg, hashAlg,
951 &sigAlgorithm->parameters, hash, wincx);
952}