/src/nss/lib/cryptohi/secsign.c
Line | Count | Source |
1 | | /* |
2 | | * Signature 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 "secder.h" |
12 | | #include "keyhi.h" |
13 | | #include "secoid.h" |
14 | | #include "secdig.h" |
15 | | #include "pk11func.h" |
16 | | #include "secerr.h" |
17 | | #include "keyi.h" |
18 | | #include "nss.h" |
19 | | |
20 | | struct SGNContextStr { |
21 | | SECOidTag signalg; |
22 | | SECOidTag hashalg; |
23 | | CK_MECHANISM_TYPE mech; |
24 | | /* if we are using explicitly hashing, this value will be non-null */ |
25 | | PK11Context *hashcx; |
26 | | /* if we are using the combined mechanism, this value will be non-null */ |
27 | | PK11Context *signcx; |
28 | | SECKEYPrivateKey *key; |
29 | | SECItem mechparams; |
30 | | }; |
31 | | |
32 | | static SGNContext * |
33 | | sgn_NewContext(SECOidTag alg, SECItem *params, SECKEYPrivateKey *key) |
34 | 2.71k | { |
35 | 2.71k | SGNContext *cx; |
36 | 2.71k | SECOidTag hashalg, signalg; |
37 | 2.71k | CK_MECHANISM_TYPE mech; |
38 | 2.71k | SECItem mechparams; |
39 | 2.71k | KeyType keyType; |
40 | 2.71k | PRUint32 policyFlags; |
41 | 2.71k | PRInt32 optFlags; |
42 | 2.71k | SECStatus rv; |
43 | | |
44 | | /* OK, map a PKCS #7 hash and encrypt algorithm into |
45 | | * a standard hashing algorithm. Why did we pass in the whole |
46 | | * PKCS #7 algTag if we were just going to change here you might |
47 | | * ask. Well the answer is for some cards we may have to do the |
48 | | * hashing on card. It may not support CKM_RSA_PKCS sign algorithm, |
49 | | * it may just support CKM_SHA1_RSA_PKCS and/or CKM_MD5_RSA_PKCS. |
50 | | */ |
51 | | /* we have a private key, not a public key, so don't pass it in */ |
52 | 2.71k | rv = sec_DecodeSigAlg(NULL, alg, params, &signalg, &hashalg, &mech, |
53 | 2.71k | &mechparams); |
54 | 2.71k | if (rv != SECSuccess) { |
55 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
56 | 0 | return NULL; |
57 | 0 | } |
58 | 2.71k | keyType = seckey_GetKeyType(signalg); |
59 | | |
60 | | /* verify our key type */ |
61 | 2.71k | if (key->keyType != keyType && |
62 | 1.76k | !((key->keyType == dsaKey) && (keyType == fortezzaKey)) && |
63 | 1.76k | !((key->keyType == rsaKey) && (keyType == rsaPssKey))) { |
64 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
65 | 0 | goto loser; |
66 | 0 | } |
67 | 2.71k | if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { |
68 | 2.71k | if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) { |
69 | 2.71k | rv = SECKEY_EnforceKeySize(key->keyType, |
70 | 2.71k | SECKEY_PrivateKeyStrengthInBits(key), |
71 | 2.71k | SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
72 | 2.71k | if (rv != SECSuccess) { |
73 | 0 | goto loser; |
74 | 0 | } |
75 | 2.71k | } |
76 | 2.71k | } |
77 | | /* check the policy on the hash algorithm */ |
78 | 2.71k | if ((NSS_GetAlgorithmPolicy(hashalg, &policyFlags) == SECFailure) || |
79 | 2.71k | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
80 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
81 | 0 | goto loser; |
82 | 0 | } |
83 | | /* check the policy on the encryption algorithm */ |
84 | 2.71k | if ((NSS_GetAlgorithmPolicy(signalg, &policyFlags) == SECFailure) || |
85 | 2.71k | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
86 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
87 | 0 | goto loser; |
88 | 0 | } |
89 | | |
90 | 2.71k | cx = (SGNContext *)PORT_ZAlloc(sizeof(SGNContext)); |
91 | 2.71k | if (!cx) { |
92 | 0 | goto loser; |
93 | 0 | } |
94 | 2.71k | cx->hashalg = hashalg; |
95 | 2.71k | cx->signalg = signalg; |
96 | 2.71k | cx->mech = mech; |
97 | 2.71k | cx->key = key; |
98 | 2.71k | cx->mechparams = mechparams; |
99 | 2.71k | return cx; |
100 | 0 | loser: |
101 | 0 | SECITEM_FreeItem(&mechparams, PR_FALSE); |
102 | 0 | return NULL; |
103 | 2.71k | } |
104 | | |
105 | | SGNContext * |
106 | | SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) |
107 | 0 | { |
108 | 0 | return sgn_NewContext(alg, NULL, key); |
109 | 0 | } |
110 | | |
111 | | SGNContext * |
112 | | SGN_NewContextWithAlgorithmID(SECAlgorithmID *alg, SECKEYPrivateKey *key) |
113 | 2.71k | { |
114 | 2.71k | SECOidTag tag = SECOID_GetAlgorithmTag(alg); |
115 | 2.71k | return sgn_NewContext(tag, &alg->parameters, key); |
116 | 2.71k | } |
117 | | |
118 | | void |
119 | | SGN_DestroyContext(SGNContext *cx, PRBool freeit) |
120 | 2.71k | { |
121 | 2.71k | if (cx) { |
122 | 2.71k | if (cx->hashcx != NULL) { |
123 | 0 | PK11_DestroyContext(cx->hashcx, PR_TRUE); |
124 | 0 | cx->hashcx = NULL; |
125 | 0 | } |
126 | 2.71k | if (cx->signcx != NULL) { |
127 | 2.71k | PK11_DestroyContext(cx->signcx, PR_TRUE); |
128 | 2.71k | cx->signcx = NULL; |
129 | 2.71k | } |
130 | 2.71k | SECITEM_FreeItem(&cx->mechparams, PR_FALSE); |
131 | 2.71k | if (freeit) { |
132 | 2.71k | PORT_ZFree(cx, sizeof(SGNContext)); |
133 | 2.71k | } |
134 | 2.71k | } |
135 | 2.71k | } |
136 | | |
137 | | static PK11Context * |
138 | | sgn_CreateCombinedContext(SGNContext *cx) |
139 | 2.71k | { |
140 | | /* the particular combination of hash and signature doesn't have a combined |
141 | | * mechanism, fall back to hand hash & sign */ |
142 | 2.71k | if (cx->mech == CKM_INVALID_MECHANISM) { |
143 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
144 | 0 | return NULL; |
145 | 0 | } |
146 | | /* the token the private key resides in doesn't support the combined |
147 | | * mechanism, fall back to hand hash & sign */ |
148 | 2.71k | if (!PK11_DoesMechanismFlag(cx->key->pkcs11Slot, cx->mech, CKF_SIGN)) { |
149 | 0 | PORT_SetError(SEC_ERROR_NO_TOKEN); |
150 | 0 | return NULL; |
151 | 0 | } |
152 | 2.71k | return PK11_CreateContextByPrivKey(cx->mech, CKA_SIGN, cx->key, |
153 | 2.71k | &cx->mechparams); |
154 | 2.71k | } |
155 | | |
156 | | SECStatus |
157 | | SGN_Begin(SGNContext *cx) |
158 | 2.71k | { |
159 | 2.71k | PK11Context *signcx = NULL; |
160 | | |
161 | 2.71k | if (cx->hashcx != NULL) { |
162 | 0 | PK11_DestroyContext(cx->hashcx, PR_TRUE); |
163 | 0 | cx->hashcx = NULL; |
164 | 0 | } |
165 | 2.71k | if (cx->signcx != NULL) { |
166 | 0 | PK11_DestroyContext(cx->signcx, PR_TRUE); |
167 | 0 | cx->signcx = NULL; |
168 | 0 | } |
169 | | /* if we can get a combined context, we'll use that */ |
170 | 2.71k | signcx = sgn_CreateCombinedContext(cx); |
171 | 2.71k | if (signcx != NULL) { |
172 | 2.71k | cx->signcx = signcx; |
173 | 2.71k | return SECSuccess; |
174 | 2.71k | } |
175 | | |
176 | 0 | cx->hashcx = PK11_CreateDigestContext(cx->hashalg); |
177 | 0 | if (cx->hashcx == NULL) |
178 | 0 | return SECFailure; /* error code is already set */ |
179 | | |
180 | 0 | if (PK11_DigestBegin(cx->hashcx) != SECSuccess) { |
181 | 0 | PK11_DestroyContext(cx->hashcx, PR_TRUE); |
182 | 0 | cx->hashcx = NULL; |
183 | 0 | return SECFailure; /* error code is already set */ |
184 | 0 | } |
185 | 0 | return SECSuccess; |
186 | 0 | } |
187 | | |
188 | | SECStatus |
189 | | SGN_Update(SGNContext *cx, const unsigned char *input, unsigned int inputLen) |
190 | 8.13k | { |
191 | 8.13k | if (cx->hashcx == NULL) { |
192 | 8.13k | if (cx->signcx == NULL) { |
193 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
194 | 0 | return SECFailure; |
195 | 0 | } |
196 | 8.13k | return PK11_DigestOp(cx->signcx, input, inputLen); |
197 | 8.13k | } |
198 | 0 | return PK11_DigestOp(cx->hashcx, input, inputLen); |
199 | 8.13k | } |
200 | | |
201 | | /* XXX Old template; want to expunge it eventually. */ |
202 | | static DERTemplate SECAlgorithmIDTemplate[] = { |
203 | | { DER_SEQUENCE, |
204 | | 0, NULL, sizeof(SECAlgorithmID) }, |
205 | | { DER_OBJECT_ID, |
206 | | offsetof(SECAlgorithmID, algorithm) }, |
207 | | { DER_OPTIONAL | DER_ANY, |
208 | | offsetof(SECAlgorithmID, parameters) }, |
209 | | { 0 } |
210 | | }; |
211 | | |
212 | | /* |
213 | | * XXX OLD Template. Once all uses have been switched over to new one, |
214 | | * remove this. |
215 | | */ |
216 | | static DERTemplate SGNDigestInfoTemplate[] = { |
217 | | { DER_SEQUENCE, |
218 | | 0, NULL, sizeof(SGNDigestInfo) }, |
219 | | { DER_INLINE, |
220 | | offsetof(SGNDigestInfo, digestAlgorithm), |
221 | | SECAlgorithmIDTemplate }, |
222 | | { DER_OCTET_STRING, |
223 | | offsetof(SGNDigestInfo, digest) }, |
224 | | { 0 } |
225 | | }; |
226 | | |
227 | | static SECStatus |
228 | | sgn_allocateSignatureItem(SECKEYPrivateKey *privKey, SECItem *sigitem) |
229 | 2.71k | { |
230 | 2.71k | int signatureLen; |
231 | 2.71k | signatureLen = PK11_SignatureLen(privKey); |
232 | 2.71k | if (signatureLen <= 0) { |
233 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
234 | 0 | return SECFailure; |
235 | 0 | } |
236 | 2.71k | sigitem->len = signatureLen; |
237 | 2.71k | sigitem->data = (unsigned char *)PORT_Alloc(signatureLen); |
238 | | |
239 | 2.71k | if (sigitem->data == NULL) { |
240 | 0 | PORT_SetError(SEC_ERROR_NO_MEMORY); |
241 | 0 | return SECFailure; |
242 | 0 | } |
243 | 2.71k | return SECSuccess; |
244 | 2.71k | } |
245 | | |
246 | | /* Sometimes the DER signature format for the signature is different than |
247 | | * The PKCS #11 format for the signature. This code handles the correction |
248 | | * from PKCS #11 to DER */ |
249 | | static SECStatus |
250 | | sgn_PKCS11ToX509Sig(SGNContext *cx, SECItem *sigitem) |
251 | 2.71k | { |
252 | 2.71k | SECStatus rv; |
253 | 2.71k | SECItem result = { siBuffer, NULL, 0 }; |
254 | | |
255 | 2.71k | if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || |
256 | 2.71k | (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { |
257 | | /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ |
258 | 948 | rv = DSAU_EncodeDerSigWithLen(&result, sigitem, sigitem->len); |
259 | | /* we are done with sigItem. In case of failure, we want to free |
260 | | * it anyway */ |
261 | 948 | SECITEM_FreeItem(sigitem, PR_FALSE); |
262 | 948 | if (rv != SECSuccess) { |
263 | 0 | return rv; |
264 | 0 | } |
265 | 948 | *sigitem = result; |
266 | 948 | } |
267 | 2.71k | return SECSuccess; |
268 | 2.71k | } |
269 | | |
270 | | SECStatus |
271 | | SGN_End(SGNContext *cx, SECItem *result) |
272 | 2.71k | { |
273 | 2.71k | unsigned char digest[HASH_LENGTH_MAX]; |
274 | 2.71k | unsigned int part1 = 0; |
275 | 2.71k | unsigned int expectedLen; |
276 | 2.71k | SECStatus rv; |
277 | 2.71k | SECItem digder, sigitem; |
278 | 2.71k | PLArenaPool *arena = 0; |
279 | 2.71k | SECKEYPrivateKey *privKey = cx->key; |
280 | 2.71k | SGNDigestInfo *di = 0; |
281 | | |
282 | 2.71k | result->data = 0; |
283 | 2.71k | digder.data = 0; |
284 | 2.71k | sigitem.data = 0; |
285 | | |
286 | 2.71k | if (cx->hashcx == NULL) { |
287 | 2.71k | if (cx->signcx == NULL) { |
288 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
289 | 0 | return SECFailure; |
290 | 0 | } |
291 | | /* if we are doing the combined hash/sign function, just finalize |
292 | | * the signature */ |
293 | 2.71k | rv = sgn_allocateSignatureItem(privKey, result); |
294 | 2.71k | if (rv != SECSuccess) { |
295 | 0 | return rv; |
296 | 0 | } |
297 | 2.71k | rv = PK11_DigestFinal(cx->signcx, result->data, &result->len, |
298 | 2.71k | result->len); |
299 | 2.71k | if (rv != SECSuccess) { |
300 | 0 | SECITEM_ZfreeItem(result, PR_FALSE); |
301 | 0 | result->data = NULL; |
302 | 0 | return rv; |
303 | 0 | } |
304 | 2.71k | return sgn_PKCS11ToX509Sig(cx, result); |
305 | 2.71k | } |
306 | | /* Finish up digest function */ |
307 | 0 | rv = PK11_DigestFinal(cx->hashcx, digest, &part1, sizeof(digest)); |
308 | 0 | if (rv != SECSuccess) { |
309 | 0 | goto loser; |
310 | 0 | } |
311 | 0 | expectedLen = HASH_ResultLenByOidTag(cx->hashalg); |
312 | 0 | if (expectedLen == 0 || part1 != expectedLen) { |
313 | 0 | PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
314 | 0 | rv = SECFailure; |
315 | 0 | goto loser; |
316 | 0 | } |
317 | | |
318 | 0 | if (privKey->keyType == rsaKey && |
319 | 0 | cx->signalg != SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { |
320 | |
|
321 | 0 | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
322 | 0 | if (!arena) { |
323 | 0 | rv = SECFailure; |
324 | 0 | goto loser; |
325 | 0 | } |
326 | | |
327 | | /* Construct digest info */ |
328 | 0 | di = SGN_CreateDigestInfo(cx->hashalg, digest, part1); |
329 | 0 | if (!di) { |
330 | 0 | rv = SECFailure; |
331 | 0 | goto loser; |
332 | 0 | } |
333 | | |
334 | | /* Der encode the digest as a DigestInfo */ |
335 | 0 | rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, |
336 | 0 | di); |
337 | 0 | if (rv != SECSuccess) { |
338 | 0 | goto loser; |
339 | 0 | } |
340 | 0 | } else { |
341 | 0 | digder.data = digest; |
342 | 0 | digder.len = part1; |
343 | 0 | } |
344 | | |
345 | | /* |
346 | | ** Encrypt signature after constructing appropriate PKCS#1 signature |
347 | | ** block |
348 | | */ |
349 | 0 | rv = sgn_allocateSignatureItem(privKey, &sigitem); |
350 | 0 | if (rv != SECSuccess) { |
351 | 0 | return rv; |
352 | 0 | } |
353 | | |
354 | 0 | if (cx->signalg == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) { |
355 | 0 | rv = PK11_SignWithMechanism(privKey, CKM_RSA_PKCS_PSS, &cx->mechparams, |
356 | 0 | &sigitem, &digder); |
357 | 0 | if (rv != SECSuccess) { |
358 | 0 | goto loser; |
359 | 0 | } |
360 | 0 | } else { |
361 | 0 | rv = PK11_Sign(privKey, &sigitem, &digder); |
362 | 0 | if (rv != SECSuccess) { |
363 | 0 | goto loser; |
364 | 0 | } |
365 | 0 | } |
366 | 0 | rv = sgn_PKCS11ToX509Sig(cx, &sigitem); |
367 | 0 | *result = sigitem; |
368 | 0 | if (rv != SECSuccess) { |
369 | 0 | goto loser; |
370 | 0 | } |
371 | 0 | return SECSuccess; |
372 | | |
373 | 0 | loser: |
374 | 0 | if (rv != SECSuccess) { |
375 | 0 | SECITEM_FreeItem(&sigitem, PR_FALSE); |
376 | 0 | } |
377 | 0 | SGN_DestroyDigestInfo(di); |
378 | 0 | if (arena != NULL) { |
379 | 0 | PORT_FreeArena(arena, PR_FALSE); |
380 | 0 | } |
381 | 0 | return rv; |
382 | 0 | } |
383 | | |
384 | | static SECStatus |
385 | | sgn_SingleShot(SGNContext *cx, const unsigned char *input, |
386 | | unsigned int inputLen, SECItem *result) |
387 | 0 | { |
388 | 0 | SECStatus rv; |
389 | |
|
390 | 0 | result->data = 0; |
391 | | /* if we have the combined mechanism, just do the single shot |
392 | | * version */ |
393 | 0 | if ((cx->mech != CKM_INVALID_MECHANISM) && |
394 | 0 | PK11_DoesMechanismFlag(cx->key->pkcs11Slot, cx->mech, CKF_SIGN)) { |
395 | 0 | SECItem data = { siBuffer, (unsigned char *)input, inputLen }; |
396 | 0 | rv = sgn_allocateSignatureItem(cx->key, result); |
397 | 0 | if (rv != SECSuccess) { |
398 | 0 | return rv; |
399 | 0 | } |
400 | 0 | rv = PK11_SignWithMechanism(cx->key, cx->mech, &cx->mechparams, |
401 | 0 | result, &data); |
402 | 0 | if (rv != SECSuccess) { |
403 | 0 | SECITEM_ZfreeItem(result, PR_FALSE); |
404 | 0 | return rv; |
405 | 0 | } |
406 | 0 | return sgn_PKCS11ToX509Sig(cx, result); |
407 | 0 | } |
408 | | /* fall back to the stream version */ |
409 | 0 | rv = SGN_Begin(cx); |
410 | 0 | if (rv != SECSuccess) |
411 | 0 | return rv; |
412 | | |
413 | 0 | rv = SGN_Update(cx, input, inputLen); |
414 | 0 | if (rv != SECSuccess) |
415 | 0 | return rv; |
416 | | |
417 | 0 | return SGN_End(cx, result); |
418 | 0 | } |
419 | | |
420 | | /************************************************************************/ |
421 | | |
422 | | static SECStatus |
423 | | sec_SignData(SECItem *res, const unsigned char *buf, int len, |
424 | | SECKEYPrivateKey *pk, SECOidTag algid, SECItem *params) |
425 | 0 | { |
426 | 0 | SECStatus rv; |
427 | 0 | SGNContext *sgn; |
428 | |
|
429 | 0 | sgn = sgn_NewContext(algid, params, pk); |
430 | |
|
431 | 0 | if (sgn == NULL) |
432 | 0 | return SECFailure; |
433 | | |
434 | 0 | rv = sgn_SingleShot(sgn, buf, len, res); |
435 | 0 | if (rv != SECSuccess) |
436 | 0 | goto loser; |
437 | | |
438 | 0 | loser: |
439 | 0 | SGN_DestroyContext(sgn, PR_TRUE); |
440 | 0 | return rv; |
441 | 0 | } |
442 | | |
443 | | /* |
444 | | ** Sign a block of data returning in result a bunch of bytes that are the |
445 | | ** signature. Returns zero on success, an error code on failure. |
446 | | */ |
447 | | SECStatus |
448 | | SEC_SignData(SECItem *res, const unsigned char *buf, int len, |
449 | | SECKEYPrivateKey *pk, SECOidTag algid) |
450 | 0 | { |
451 | 0 | return sec_SignData(res, buf, len, pk, algid, NULL); |
452 | 0 | } |
453 | | |
454 | | SECStatus |
455 | | SEC_SignDataWithAlgorithmID(SECItem *res, const unsigned char *buf, int len, |
456 | | SECKEYPrivateKey *pk, SECAlgorithmID *algid) |
457 | 0 | { |
458 | 0 | SECOidTag tag = SECOID_GetAlgorithmTag(algid); |
459 | 0 | return sec_SignData(res, buf, len, pk, tag, &algid->parameters); |
460 | 0 | } |
461 | | |
462 | | /************************************************************************/ |
463 | | |
464 | | DERTemplate CERTSignedDataTemplate[] = { |
465 | | { DER_SEQUENCE, |
466 | | 0, NULL, sizeof(CERTSignedData) }, |
467 | | { DER_ANY, |
468 | | offsetof(CERTSignedData, data) }, |
469 | | { DER_INLINE, |
470 | | offsetof(CERTSignedData, signatureAlgorithm), |
471 | | SECAlgorithmIDTemplate }, |
472 | | { DER_BIT_STRING, |
473 | | offsetof(CERTSignedData, signature) }, |
474 | | { 0 } |
475 | | }; |
476 | | |
477 | | static SECOidTag |
478 | | seckey_CurveOidFromPrivKey(const SECKEYPrivateKey *privKey) |
479 | 0 | { |
480 | 0 | SECItem params; |
481 | 0 | SECStatus rv; |
482 | 0 | SECOidTag tag; |
483 | |
|
484 | 0 | rv = PK11_ReadAttribute(privKey->pkcs11Slot, privKey->pkcs11ID, |
485 | 0 | CKA_EC_PARAMS, NULL, ¶ms); |
486 | 0 | if (rv != SECSuccess) { |
487 | 0 | return SEC_OID_UNKNOWN; |
488 | 0 | } |
489 | 0 | tag = SECKEY_GetECCOid(¶ms); |
490 | 0 | SECITEM_FreeItem(¶ms, PR_FALSE); |
491 | 0 | return tag; |
492 | 0 | } |
493 | | |
494 | | static SECStatus |
495 | | sec_DerSignData(PLArenaPool *arena, SECItem *result, |
496 | | const unsigned char *buf, int len, SECKEYPrivateKey *pk, |
497 | | SECOidTag algID, SECItem *params) |
498 | 0 | { |
499 | 0 | SECItem it; |
500 | 0 | CERTSignedData sd; |
501 | 0 | SECStatus rv; |
502 | |
|
503 | 0 | it.data = 0; |
504 | | |
505 | | /* XXX We should probably have some asserts here to make sure the key type |
506 | | * and algID match |
507 | | */ |
508 | |
|
509 | 0 | if (algID == SEC_OID_UNKNOWN) { |
510 | 0 | switch (pk->keyType) { |
511 | 0 | case rsaKey: |
512 | 0 | algID = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; |
513 | 0 | break; |
514 | 0 | case dsaKey: |
515 | | /* get Signature length (= q_len*2) and work from there */ |
516 | 0 | switch (PK11_SignatureLen(pk)) { |
517 | 0 | case 320: |
518 | 0 | algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; |
519 | 0 | break; |
520 | 0 | case 448: |
521 | 0 | algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; |
522 | 0 | break; |
523 | 0 | case 512: |
524 | 0 | default: |
525 | 0 | algID = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; |
526 | 0 | break; |
527 | 0 | } |
528 | 0 | break; |
529 | 0 | case ecKey: |
530 | 0 | algID = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; |
531 | 0 | break; |
532 | 0 | case edKey: |
533 | 0 | algID = seckey_CurveOidFromPrivKey(pk); |
534 | 0 | break; |
535 | 0 | case mldsaKey: |
536 | 0 | algID = seckey_GetParameterSet(pk); |
537 | 0 | break; |
538 | 0 | default: |
539 | 0 | algID = SEC_OID_UNKNOWN; |
540 | 0 | break; |
541 | 0 | } |
542 | 0 | } |
543 | 0 | if (algID == SEC_OID_UNKNOWN) { |
544 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
545 | 0 | return SECFailure; |
546 | 0 | } |
547 | | |
548 | | /* Sign input buffer */ |
549 | 0 | rv = sec_SignData(&it, buf, len, pk, algID, params); |
550 | 0 | if (rv) |
551 | 0 | goto loser; |
552 | | |
553 | | /* Fill out SignedData object */ |
554 | 0 | PORT_Memset(&sd, 0, sizeof(sd)); |
555 | 0 | sd.data.data = (unsigned char *)buf; |
556 | 0 | sd.data.len = len; |
557 | 0 | sd.signature.data = it.data; |
558 | 0 | sd.signature.len = it.len << 3; /* convert to bit string */ |
559 | 0 | rv = SECOID_SetAlgorithmID(arena, &sd.signatureAlgorithm, algID, params); |
560 | 0 | if (rv) |
561 | 0 | goto loser; |
562 | | |
563 | | /* DER encode the signed data object */ |
564 | 0 | rv = DER_Encode(arena, result, CERTSignedDataTemplate, &sd); |
565 | | /* FALL THROUGH */ |
566 | |
|
567 | 0 | loser: |
568 | 0 | PORT_Free(it.data); |
569 | 0 | return rv; |
570 | 0 | } |
571 | | |
572 | | SECStatus |
573 | | SEC_DerSignData(PLArenaPool *arena, SECItem *result, |
574 | | const unsigned char *buf, int len, SECKEYPrivateKey *pk, |
575 | | SECOidTag algID) |
576 | 0 | { |
577 | 0 | return sec_DerSignData(arena, result, buf, len, pk, algID, NULL); |
578 | 0 | } |
579 | | |
580 | | SECStatus |
581 | | SEC_DerSignDataWithAlgorithmID(PLArenaPool *arena, SECItem *result, |
582 | | const unsigned char *buf, int len, |
583 | | SECKEYPrivateKey *pk, |
584 | | SECAlgorithmID *algID) |
585 | 0 | { |
586 | 0 | SECOidTag tag = SECOID_GetAlgorithmTag(algID); |
587 | 0 | return sec_DerSignData(arena, result, buf, len, pk, tag, &algID->parameters); |
588 | 0 | } |
589 | | |
590 | | SECStatus |
591 | | SGN_Digest(SECKEYPrivateKey *privKey, |
592 | | SECOidTag algtag, SECItem *result, SECItem *digest) |
593 | 25.2k | { |
594 | 25.2k | int modulusLen; |
595 | 25.2k | SECStatus rv; |
596 | 25.2k | SECItem digder; |
597 | 25.2k | PLArenaPool *arena = 0; |
598 | 25.2k | SGNDigestInfo *di = 0; |
599 | 25.2k | SECOidTag enctag; |
600 | 25.2k | PRUint32 policyFlags; |
601 | 25.2k | PRInt32 optFlags; |
602 | | |
603 | 25.2k | result->data = 0; |
604 | | |
605 | 25.2k | if (NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optFlags) != SECFailure) { |
606 | 25.2k | if (optFlags & NSS_KEY_SIZE_POLICY_SIGN_FLAG) { |
607 | 25.2k | rv = SECKEY_EnforceKeySize(privKey->keyType, |
608 | 25.2k | SECKEY_PrivateKeyStrengthInBits(privKey), |
609 | 25.2k | SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
610 | 25.2k | if (rv != SECSuccess) { |
611 | 0 | return SECFailure; |
612 | 0 | } |
613 | 25.2k | } |
614 | 25.2k | } |
615 | | /* check the policy on the hash algorithm */ |
616 | 25.2k | if ((NSS_GetAlgorithmPolicy(algtag, &policyFlags) == SECFailure) || |
617 | 25.2k | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
618 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
619 | 0 | return SECFailure; |
620 | 0 | } |
621 | | |
622 | 25.2k | if ((privKey->keyType == mldsaKey) || (privKey->keyType == edKey)) { |
623 | | /* don't allow digest sign for mldsa. May be possible if mu |
624 | | * is enabled, in that case the hash must be the special mldsa |
625 | | * hash, which we don't have defined yet */ |
626 | 0 | PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); |
627 | 0 | return SECFailure; |
628 | 0 | } |
629 | | /* check the policy on the encryption algorithm */ |
630 | 25.2k | enctag = sec_GetEncAlgFromSigAlg( |
631 | 25.2k | SEC_GetSignatureAlgorithmOidTagByKey(privKey, NULL, algtag)); |
632 | 25.2k | if ((enctag == SEC_OID_UNKNOWN) || |
633 | 25.2k | (NSS_GetAlgorithmPolicy(enctag, &policyFlags) == SECFailure) || |
634 | 25.2k | !(policyFlags & NSS_USE_ALG_IN_ANY_SIGNATURE)) { |
635 | 0 | PORT_SetError(SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED); |
636 | 0 | return SECFailure; |
637 | 0 | } |
638 | | |
639 | 25.2k | if (privKey->keyType == rsaKey) { |
640 | | |
641 | 19.6k | arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
642 | 19.6k | if (!arena) { |
643 | 0 | rv = SECFailure; |
644 | 0 | goto loser; |
645 | 0 | } |
646 | | |
647 | | /* Construct digest info */ |
648 | 19.6k | di = SGN_CreateDigestInfo(algtag, digest->data, digest->len); |
649 | 19.6k | if (!di) { |
650 | 0 | rv = SECFailure; |
651 | 0 | goto loser; |
652 | 0 | } |
653 | | |
654 | | /* Der encode the digest as a DigestInfo */ |
655 | 19.6k | rv = DER_Encode(arena, &digder, SGNDigestInfoTemplate, |
656 | 19.6k | di); |
657 | 19.6k | if (rv != SECSuccess) { |
658 | 0 | goto loser; |
659 | 0 | } |
660 | 19.6k | } else { |
661 | 5.62k | digder.data = digest->data; |
662 | 5.62k | digder.len = digest->len; |
663 | 5.62k | } |
664 | | |
665 | | /* |
666 | | ** Encrypt signature after constructing appropriate PKCS#1 signature |
667 | | ** block |
668 | | */ |
669 | 25.2k | modulusLen = PK11_SignatureLen(privKey); |
670 | 25.2k | if (modulusLen <= 0) { |
671 | 0 | PORT_SetError(SEC_ERROR_INVALID_KEY); |
672 | 0 | rv = SECFailure; |
673 | 0 | goto loser; |
674 | 0 | } |
675 | 25.2k | result->len = modulusLen; |
676 | 25.2k | result->data = (unsigned char *)PORT_Alloc(modulusLen); |
677 | 25.2k | result->type = siBuffer; |
678 | | |
679 | 25.2k | if (result->data == NULL) { |
680 | 0 | rv = SECFailure; |
681 | 0 | goto loser; |
682 | 0 | } |
683 | | |
684 | 25.2k | rv = PK11_Sign(privKey, result, &digder); |
685 | 25.2k | if (rv != SECSuccess) { |
686 | 0 | PORT_Free(result->data); |
687 | 0 | result->data = NULL; |
688 | 0 | } |
689 | | |
690 | 25.2k | loser: |
691 | 25.2k | SGN_DestroyDigestInfo(di); |
692 | 25.2k | if (arena != NULL) { |
693 | 19.6k | PORT_FreeArena(arena, PR_FALSE); |
694 | 19.6k | } |
695 | 25.2k | return rv; |
696 | 25.2k | } |
697 | | |
698 | | SECOidTag |
699 | | SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) |
700 | 25.2k | { |
701 | 25.2k | SECOidTag sigTag = SEC_OID_UNKNOWN; |
702 | | |
703 | 25.2k | switch (keyType) { |
704 | 0 | case rsaPssKey: |
705 | 0 | sigTag = SEC_OID_PKCS1_RSA_PSS_SIGNATURE; |
706 | 0 | break; |
707 | 19.6k | case rsaKey: |
708 | 19.6k | switch (hashAlgTag) { |
709 | 0 | case SEC_OID_MD2: |
710 | 0 | sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; |
711 | 0 | break; |
712 | 0 | case SEC_OID_MD5: |
713 | 0 | sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; |
714 | 0 | break; |
715 | 17.8k | case SEC_OID_SHA1: |
716 | 17.8k | sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; |
717 | 17.8k | break; |
718 | 0 | case SEC_OID_SHA224: |
719 | 0 | sigTag = SEC_OID_PKCS1_SHA224_WITH_RSA_ENCRYPTION; |
720 | 0 | break; |
721 | 0 | case SEC_OID_UNKNOWN: /* default for RSA if not specified */ |
722 | 248 | case SEC_OID_SHA256: |
723 | 248 | sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; |
724 | 248 | break; |
725 | 462 | case SEC_OID_SHA384: |
726 | 462 | sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; |
727 | 462 | break; |
728 | 1.06k | case SEC_OID_SHA512: |
729 | 1.06k | sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; |
730 | 1.06k | break; |
731 | 0 | default: |
732 | 0 | break; |
733 | 19.6k | } |
734 | 19.6k | break; |
735 | 19.6k | case dsaKey: |
736 | 0 | switch (hashAlgTag) { |
737 | 0 | case SEC_OID_SHA1: |
738 | 0 | sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; |
739 | 0 | break; |
740 | 0 | case SEC_OID_SHA224: |
741 | 0 | sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA224_DIGEST; |
742 | 0 | break; |
743 | 0 | case SEC_OID_UNKNOWN: /* default for DSA if not specified */ |
744 | 0 | case SEC_OID_SHA256: |
745 | 0 | sigTag = SEC_OID_NIST_DSA_SIGNATURE_WITH_SHA256_DIGEST; |
746 | 0 | break; |
747 | 0 | default: |
748 | 0 | break; |
749 | 0 | } |
750 | 0 | break; |
751 | 0 | case mldsaKey: |
752 | 0 | switch (hashAlgTag) { |
753 | 0 | case SEC_OID_ML_DSA_44: |
754 | 0 | case SEC_OID_ML_DSA_65: |
755 | 0 | case SEC_OID_ML_DSA_87: |
756 | | /* only accept known mldsa values. For mldsa, the hash must |
757 | | * match the underlying signature algorithm */ |
758 | 0 | sigTag = hashAlgTag; |
759 | 0 | break; |
760 | 0 | default: |
761 | 0 | break; |
762 | 0 | } |
763 | 0 | break; |
764 | 5.62k | case ecKey: |
765 | 5.62k | switch (hashAlgTag) { |
766 | 4.49k | case SEC_OID_SHA1: |
767 | 4.49k | sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; |
768 | 4.49k | break; |
769 | 0 | case SEC_OID_SHA224: |
770 | 0 | sigTag = SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE; |
771 | 0 | break; |
772 | 0 | case SEC_OID_UNKNOWN: /* default for ECDSA if not specified */ |
773 | 304 | case SEC_OID_SHA256: |
774 | 304 | sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; |
775 | 304 | break; |
776 | 33 | case SEC_OID_SHA384: |
777 | 33 | sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; |
778 | 33 | break; |
779 | 789 | case SEC_OID_SHA512: |
780 | 789 | sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; |
781 | 789 | break; |
782 | 0 | default: |
783 | 0 | break; |
784 | 5.62k | } |
785 | 5.62k | break; |
786 | 5.62k | case edKey: |
787 | | /* signature and curve are the same oid, just make sure |
788 | | * it's valid */ |
789 | 0 | switch (hashAlgTag) { |
790 | 0 | case SEC_OID_ED25519_SIGNATURE: |
791 | | /* add curve 448 here if/when we to support it */ |
792 | 0 | sigTag = hashAlgTag; |
793 | 0 | break; |
794 | 0 | default: |
795 | 0 | break; |
796 | 0 | } |
797 | 0 | break; |
798 | 0 | default: |
799 | 0 | break; |
800 | 25.2k | } |
801 | 25.2k | return sigTag; |
802 | 25.2k | } |
803 | | |
804 | | SECOidTag |
805 | | SEC_GetSignatureAlgorithmOidTagByKey(const SECKEYPrivateKey *privKey, const SECKEYPublicKey *pubKey, SECOidTag hashAlgTag) |
806 | 25.2k | { |
807 | 25.2k | KeyType keyType = nullKey; |
808 | | /* make sure we have a key */ |
809 | 25.2k | if ((privKey && pubKey) || (!privKey && !pubKey)) { |
810 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
811 | 0 | return SEC_OID_UNKNOWN; |
812 | 0 | } |
813 | | /* make sure we have only one key */ |
814 | 25.2k | if (privKey) { |
815 | 25.2k | keyType = privKey->keyType; |
816 | 25.2k | switch (keyType) { |
817 | 0 | case mldsaKey: |
818 | | /* for mldsa, the hash has to match the paramset anyway, so |
819 | | * pass in the param set as the hash */ |
820 | 0 | hashAlgTag = seckey_GetParameterSet(privKey); |
821 | 0 | break; |
822 | 0 | case edKey: |
823 | | /* for ed, hash matches the curve, so we return the curve oid */ |
824 | 0 | hashAlgTag = seckey_CurveOidFromPrivKey(privKey); |
825 | 0 | break; |
826 | 25.2k | default: |
827 | | /* everything gets the hash from the caller, or will default */ |
828 | 25.2k | break; |
829 | 25.2k | } |
830 | 25.2k | } else { |
831 | | /* the logic above should guarentee the following assert. */ |
832 | 0 | PORT_Assert(pubKey != NULL); |
833 | 0 | PORT_Assert(privKey == NULL); |
834 | 0 | keyType = pubKey->keyType; |
835 | 0 | switch (keyType) { |
836 | 0 | case mldsaKey: |
837 | | /* for mldsa, the hash has to match the paramset anyway, so |
838 | | * pass in the param set as the hash */ |
839 | 0 | hashAlgTag = pubKey->u.mldsa.paramSet; |
840 | 0 | break; |
841 | 0 | case edKey: |
842 | | /* for ed, hash matches the curve, so we return the curve oid */ |
843 | 0 | hashAlgTag = SECKEY_GetECCOid(&pubKey->u.ec.DEREncodedParams); |
844 | 0 | break; |
845 | 0 | default: |
846 | | /* everything gets the hash from the caller, or will default */ |
847 | 0 | break; |
848 | 0 | } |
849 | 0 | } |
850 | 25.2k | return SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag); |
851 | 25.2k | } |
852 | | |
853 | | SECItem * |
854 | | sec_CreateRSAPSSParameters(PLArenaPool *arena, |
855 | | SECItem *result, |
856 | | SECOidTag hashAlgTag, |
857 | | const SECItem *params, |
858 | | int modBytes) |
859 | 1.76k | { |
860 | 1.76k | SECKEYRSAPSSParams pssParams; |
861 | 1.76k | int hashLength; |
862 | 1.76k | unsigned long saltLength; |
863 | 1.76k | PRBool defaultSHA1 = PR_FALSE; |
864 | 1.76k | SECStatus rv; |
865 | | |
866 | 1.76k | PORT_Memset(&pssParams, 0, sizeof(pssParams)); |
867 | | |
868 | 1.76k | if (params && params->data) { |
869 | | /* The parameters field should either be empty or contain |
870 | | * valid RSA-PSS parameters */ |
871 | 0 | PORT_Assert(!(params->len == 2 && |
872 | 0 | params->data[0] == SEC_ASN1_NULL && |
873 | 0 | params->data[1] == 0)); |
874 | 0 | rv = SEC_QuickDERDecodeItem(arena, &pssParams, |
875 | 0 | SECKEY_RSAPSSParamsTemplate, |
876 | 0 | params); |
877 | 0 | if (rv != SECSuccess) { |
878 | 0 | return NULL; |
879 | 0 | } |
880 | 0 | defaultSHA1 = PR_TRUE; |
881 | 0 | } |
882 | | |
883 | 1.76k | if (pssParams.trailerField.data) { |
884 | 0 | unsigned long trailerField; |
885 | |
|
886 | 0 | rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.trailerField, |
887 | 0 | &trailerField); |
888 | 0 | if (rv != SECSuccess) { |
889 | 0 | return NULL; |
890 | 0 | } |
891 | 0 | if (trailerField != 1) { |
892 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
893 | 0 | return NULL; |
894 | 0 | } |
895 | 0 | } |
896 | | |
897 | | /* Determine the hash algorithm to use, based on hashAlgTag and |
898 | | * pssParams.hashAlg; there are 6 cases. |
899 | | * case: |
900 | | * 1) We have params and params.hashAlg and we have a specified hashAlgTag, |
901 | | * make sure that hashAlgTag specified by the appication matches. |
902 | | * 2) We have params, but no params.hashAlg and we have a specified |
903 | | * hashAlg, make sure the hashAlgTag matches SEC_OID_SHA1. |
904 | | * 3) we did not specify any parameters but we did specified |
905 | | * a hashAlgTag. Use the specified hash algtag. |
906 | | * 4) We have params and params.hashAlg and we did not specify a |
907 | | * hashAlgTag, use the hashAlg from the parameter. |
908 | | * 5) We have params, but no params.hashAlg and we did not specify a |
909 | | * hashAlgTag, use the SEC_OID_SHA1 |
910 | | * 6) We did not specify any parameters, nor did we specify a |
911 | | * hashAlgTag, use the key size to select an appropriate hashAlg. |
912 | | */ |
913 | 1.76k | if (hashAlgTag != SEC_OID_UNKNOWN) { |
914 | 1.76k | SECOidTag tag = SEC_OID_UNKNOWN; |
915 | | |
916 | 1.76k | if (pssParams.hashAlg) { |
917 | 0 | tag = SECOID_GetAlgorithmTag(pssParams.hashAlg); |
918 | 1.76k | } else if (defaultSHA1) { |
919 | 0 | tag = SEC_OID_SHA1; |
920 | 0 | } |
921 | | |
922 | 1.76k | if (tag != SEC_OID_UNKNOWN && tag != hashAlgTag) { |
923 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
924 | 0 | return NULL; |
925 | 0 | } |
926 | 1.76k | } else if (hashAlgTag == SEC_OID_UNKNOWN) { |
927 | 0 | if (pssParams.hashAlg) { |
928 | 0 | hashAlgTag = SECOID_GetAlgorithmTag(pssParams.hashAlg); |
929 | 0 | } else if (defaultSHA1) { |
930 | 0 | hashAlgTag = SEC_OID_SHA1; |
931 | 0 | } else { |
932 | | /* Find a suitable hash algorithm based on the NIST recommendation */ |
933 | 0 | if (modBytes <= 384) { /* 128, in NIST 800-57, Part 1 */ |
934 | 0 | hashAlgTag = SEC_OID_SHA256; |
935 | 0 | } else if (modBytes <= 960) { /* 192, NIST 800-57, Part 1 */ |
936 | 0 | hashAlgTag = SEC_OID_SHA384; |
937 | 0 | } else { |
938 | 0 | hashAlgTag = SEC_OID_SHA512; |
939 | 0 | } |
940 | 0 | } |
941 | 0 | } |
942 | | |
943 | | /* explicitly restrict hashAlg to SHA2 variants */ |
944 | 1.76k | if (hashAlgTag != SEC_OID_SHA1 && hashAlgTag != SEC_OID_SHA224 && |
945 | 1.76k | hashAlgTag != SEC_OID_SHA256 && hashAlgTag != SEC_OID_SHA384 && |
946 | 464 | hashAlgTag != SEC_OID_SHA512) { |
947 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
948 | 0 | return NULL; |
949 | 0 | } |
950 | | |
951 | | /* Now that the hash algorithm is decided, check if it matches the |
952 | | * existing parameters if any */ |
953 | 1.76k | if (pssParams.maskAlg) { |
954 | 0 | SECAlgorithmID maskHashAlg; |
955 | |
|
956 | 0 | if (SECOID_GetAlgorithmTag(pssParams.maskAlg) != SEC_OID_PKCS1_MGF1) { |
957 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
958 | 0 | return NULL; |
959 | 0 | } |
960 | | |
961 | 0 | if (pssParams.maskAlg->parameters.data == NULL) { |
962 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
963 | 0 | return NULL; |
964 | 0 | } |
965 | | |
966 | 0 | PORT_Memset(&maskHashAlg, 0, sizeof(maskHashAlg)); |
967 | 0 | rv = SEC_QuickDERDecodeItem(arena, &maskHashAlg, |
968 | 0 | SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), |
969 | 0 | &pssParams.maskAlg->parameters); |
970 | 0 | if (rv != SECSuccess) { |
971 | 0 | return NULL; |
972 | 0 | } |
973 | | |
974 | | /* Following the recommendation in RFC 4055, assume the hash |
975 | | * algorithm identical to pssParam.hashAlg */ |
976 | 0 | if (SECOID_GetAlgorithmTag(&maskHashAlg) != hashAlgTag) { |
977 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
978 | 0 | return NULL; |
979 | 0 | } |
980 | 1.76k | } else if (defaultSHA1) { |
981 | 0 | if (hashAlgTag != SEC_OID_SHA1) { |
982 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
983 | 0 | return NULL; |
984 | 0 | } |
985 | 0 | } |
986 | | |
987 | 1.76k | hashLength = HASH_ResultLenByOidTag(hashAlgTag); |
988 | | |
989 | 1.76k | if (modBytes < hashLength + 2) { |
990 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
991 | 0 | return NULL; |
992 | 0 | } |
993 | | |
994 | 1.76k | if (pssParams.saltLength.data) { |
995 | 0 | rv = SEC_ASN1DecodeInteger((SECItem *)&pssParams.saltLength, |
996 | 0 | &saltLength); |
997 | 0 | if (rv != SECSuccess) { |
998 | 0 | return NULL; |
999 | 0 | } |
1000 | | |
1001 | | /* The specified salt length is too long */ |
1002 | 0 | if (saltLength > (unsigned long)(modBytes - hashLength - 2)) { |
1003 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1004 | 0 | return NULL; |
1005 | 0 | } |
1006 | 1.76k | } else if (defaultSHA1) { |
1007 | 0 | saltLength = 20; |
1008 | 0 | } |
1009 | | |
1010 | | /* Fill in the parameters */ |
1011 | 1.76k | if (pssParams.hashAlg) { |
1012 | 0 | if (hashAlgTag == SEC_OID_SHA1) { |
1013 | | /* Omit hashAlg if the the algorithm is SHA-1 (default) */ |
1014 | 0 | pssParams.hashAlg = NULL; |
1015 | 0 | } |
1016 | 1.76k | } else { |
1017 | 1.76k | if (hashAlgTag != SEC_OID_SHA1) { |
1018 | 1.76k | pssParams.hashAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); |
1019 | 1.76k | if (!pssParams.hashAlg) { |
1020 | 0 | return NULL; |
1021 | 0 | } |
1022 | 1.76k | rv = SECOID_SetAlgorithmID(arena, pssParams.hashAlg, hashAlgTag, |
1023 | 1.76k | NULL); |
1024 | 1.76k | if (rv != SECSuccess) { |
1025 | 0 | return NULL; |
1026 | 0 | } |
1027 | 1.76k | } |
1028 | 1.76k | } |
1029 | | |
1030 | 1.76k | if (pssParams.maskAlg) { |
1031 | 0 | if (hashAlgTag == SEC_OID_SHA1) { |
1032 | | /* Omit maskAlg if the the algorithm is SHA-1 (default) */ |
1033 | 0 | pssParams.maskAlg = NULL; |
1034 | 0 | } |
1035 | 1.76k | } else { |
1036 | 1.76k | if (hashAlgTag != SEC_OID_SHA1) { |
1037 | 1.76k | SECItem *hashAlgItem; |
1038 | | |
1039 | 1.76k | PORT_Assert(pssParams.hashAlg != NULL); |
1040 | | |
1041 | 1.76k | hashAlgItem = SEC_ASN1EncodeItem(arena, NULL, pssParams.hashAlg, |
1042 | 1.76k | SEC_ASN1_GET(SECOID_AlgorithmIDTemplate)); |
1043 | 1.76k | if (!hashAlgItem) { |
1044 | 0 | return NULL; |
1045 | 0 | } |
1046 | 1.76k | pssParams.maskAlg = PORT_ArenaZAlloc(arena, sizeof(SECAlgorithmID)); |
1047 | 1.76k | if (!pssParams.maskAlg) { |
1048 | 0 | return NULL; |
1049 | 0 | } |
1050 | 1.76k | rv = SECOID_SetAlgorithmID(arena, pssParams.maskAlg, |
1051 | 1.76k | SEC_OID_PKCS1_MGF1, hashAlgItem); |
1052 | 1.76k | if (rv != SECSuccess) { |
1053 | 0 | return NULL; |
1054 | 0 | } |
1055 | 1.76k | } |
1056 | 1.76k | } |
1057 | | |
1058 | 1.76k | if (pssParams.saltLength.data) { |
1059 | 0 | if (saltLength == 20) { |
1060 | | /* Omit the salt length if it is the default */ |
1061 | 0 | pssParams.saltLength.data = NULL; |
1062 | 0 | } |
1063 | 1.76k | } else { |
1064 | | /* Find a suitable length from the hash algorithm and modulus bits */ |
1065 | 1.76k | saltLength = PR_MIN(hashLength, modBytes - hashLength - 2); |
1066 | | |
1067 | 1.76k | if (saltLength != 20 && |
1068 | 1.76k | !SEC_ASN1EncodeInteger(arena, &pssParams.saltLength, saltLength)) { |
1069 | 0 | return NULL; |
1070 | 0 | } |
1071 | 1.76k | } |
1072 | | |
1073 | 1.76k | if (pssParams.trailerField.data) { |
1074 | | /* Omit trailerField if the value is 1 (default) */ |
1075 | 0 | pssParams.trailerField.data = NULL; |
1076 | 0 | } |
1077 | | |
1078 | 1.76k | return SEC_ASN1EncodeItem(arena, result, |
1079 | 1.76k | &pssParams, SECKEY_RSAPSSParamsTemplate); |
1080 | 1.76k | } |
1081 | | |
1082 | | SECItem * |
1083 | | SEC_CreateRSAPSSParameters(PLArenaPool *arena, |
1084 | | SECItem *result, |
1085 | | SECOidTag hashAlgTag, |
1086 | | const SECItem *params, |
1087 | | const SECKEYPrivateKey *privKey, |
1088 | | const SECKEYPublicKey *pubKey) |
1089 | 1.76k | { |
1090 | | /* if no keys are provided arrange for the saltLength to be hashLen */ |
1091 | 1.76k | int modBytes = (HASH_LENGTH_MAX * 2) + 2; |
1092 | | |
1093 | | /* we don't need all these parameters, but we should have at least |
1094 | | * one of these */ |
1095 | 1.76k | if (!privKey && !pubKey && !params && (hashAlgTag == SEC_OID_UNKNOWN)) { |
1096 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1097 | 0 | return NULL; |
1098 | 0 | } |
1099 | | /* only allow one key */ |
1100 | 1.76k | if (privKey && pubKey) { |
1101 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1102 | 0 | return NULL; |
1103 | 0 | } |
1104 | 1.76k | if (privKey) { |
1105 | 1.76k | if (privKey->keyType != rsaKey && privKey->keyType != rsaPssKey) { |
1106 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
1107 | 0 | return NULL; |
1108 | 0 | } |
1109 | | /* cast away the const, even though it's still logically a const |
1110 | | * function */ |
1111 | 1.76k | modBytes = PK11_GetPrivateModulusLen((SECKEYPrivateKey *)privKey); |
1112 | 1.76k | } else if (pubKey) { |
1113 | 0 | if (pubKey->keyType != rsaKey && pubKey->keyType != rsaPssKey) { |
1114 | 0 | PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
1115 | 0 | return NULL; |
1116 | 0 | } |
1117 | 0 | modBytes = pubKey->u.rsa.modulus.len; |
1118 | 0 | } |
1119 | 1.76k | return sec_CreateRSAPSSParameters(arena, result, hashAlgTag, |
1120 | 1.76k | params, modBytes); |
1121 | 1.76k | } |
1122 | | |
1123 | | SECItem * |
1124 | | SEC_CreateSignatureAlgorithmParameters(PLArenaPool *arena, |
1125 | | SECItem *result, |
1126 | | SECOidTag signAlgTag, |
1127 | | SECOidTag hashAlgTag, |
1128 | | const SECItem *params, |
1129 | | const SECKEYPrivateKey *key) |
1130 | 2.71k | { |
1131 | 2.71k | PORT_SetError(0); |
1132 | 2.71k | switch (signAlgTag) { |
1133 | 1.76k | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
1134 | 1.76k | return SEC_CreateRSAPSSParameters(arena, result, |
1135 | 1.76k | hashAlgTag, params, key, NULL); |
1136 | | |
1137 | 948 | default: |
1138 | 948 | if (params == NULL) |
1139 | 948 | return NULL; |
1140 | 0 | if (result == NULL) |
1141 | 0 | result = SECITEM_AllocItem(arena, NULL, 0); |
1142 | 0 | if (result == NULL) { |
1143 | 0 | return NULL; |
1144 | 0 | } |
1145 | 0 | if (SECITEM_CopyItem(arena, result, params) != SECSuccess) |
1146 | 0 | return NULL; |
1147 | 0 | return result; |
1148 | 2.71k | } |
1149 | 2.71k | } |
1150 | | |
1151 | | SECItem * |
1152 | | SEC_CreateVerifyAlgorithmParameters(PLArenaPool *arena, |
1153 | | SECItem *result, |
1154 | | SECOidTag signAlgTag, |
1155 | | SECOidTag hashAlgTag, |
1156 | | const SECItem *params, |
1157 | | const SECKEYPublicKey *key) |
1158 | 0 | { |
1159 | 0 | PORT_SetError(0); |
1160 | 0 | switch (signAlgTag) { |
1161 | 0 | case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: |
1162 | 0 | return SEC_CreateRSAPSSParameters(arena, result, |
1163 | 0 | hashAlgTag, params, NULL, key); |
1164 | | |
1165 | 0 | default: |
1166 | 0 | if (params == NULL) |
1167 | 0 | return NULL; |
1168 | 0 | if (result == NULL) |
1169 | 0 | result = SECITEM_AllocItem(arena, NULL, 0); |
1170 | 0 | if (result == NULL) { |
1171 | 0 | return NULL; |
1172 | 0 | } |
1173 | 0 | if (SECITEM_CopyItem(arena, result, params) != SECSuccess) |
1174 | 0 | return NULL; |
1175 | 0 | return result; |
1176 | 0 | } |
1177 | 0 | } |
1178 | | |
1179 | | SECStatus |
1180 | | SEC_CreateSignatureAlgorithmID(PLArenaPool *arena, |
1181 | | SECAlgorithmID *signAlgID, |
1182 | | SECOidTag signAlgTag, |
1183 | | SECOidTag hashAlgTag, |
1184 | | const SECItem *params, |
1185 | | const SECKEYPrivateKey *privKey, |
1186 | | const SECKEYPublicKey *pubKey) |
1187 | 2.71k | { |
1188 | 2.71k | SECItem *newParams = NULL; |
1189 | | |
1190 | 2.71k | if (signAlgTag == SEC_OID_UNKNOWN) { |
1191 | 0 | signAlgTag = SEC_GetSignatureAlgorithmOidTagByKey(privKey, pubKey, |
1192 | 0 | hashAlgTag); |
1193 | 2.71k | } else { |
1194 | | /* SEC_GetSignatureAlgorithm already checks if privKey and pubKey |
1195 | | * is present and the only case */ |
1196 | 2.71k | if ((privKey && pubKey) || (!privKey && !pubKey)) { |
1197 | 0 | PORT_SetError(SEC_ERROR_INVALID_ARGS); |
1198 | 0 | return SECFailure; |
1199 | 0 | } |
1200 | 2.71k | } |
1201 | | |
1202 | 2.71k | if (signAlgTag == SEC_OID_UNKNOWN) { |
1203 | | /* error already set by SEC_GetSignatureAlgorithmOidTagByKey */ |
1204 | 0 | return SECFailure; |
1205 | 0 | } |
1206 | | |
1207 | 2.71k | if (privKey) { |
1208 | 2.71k | newParams = SEC_CreateSignatureAlgorithmParameters(arena, NULL, |
1209 | 2.71k | signAlgTag, |
1210 | 2.71k | hashAlgTag, |
1211 | 2.71k | params, |
1212 | 2.71k | privKey); |
1213 | 2.71k | } else { |
1214 | | /* must be pubKey */ |
1215 | 0 | newParams = SEC_CreateVerifyAlgorithmParameters(arena, NULL, |
1216 | 0 | signAlgTag, |
1217 | 0 | hashAlgTag, |
1218 | 0 | params, |
1219 | 0 | pubKey); |
1220 | 0 | } |
1221 | | |
1222 | | /* It's legal (and common) for params to be NULL; look at the error |
1223 | | * code to see if there was a failure */ |
1224 | 2.71k | if (!newParams && PORT_GetError() != 0) { |
1225 | 0 | return SECFailure; |
1226 | 0 | } |
1227 | | |
1228 | 2.71k | return SECOID_SetAlgorithmID(arena, signAlgID, signAlgTag, newParams); |
1229 | 2.71k | } |