File: | s/lib/smime/cmsrecinfo.c |
Warning: | line 634, column 13 Value stored to 'encalgtag' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | |
5 | /* |
6 | * CMS recipientInfo methods. |
7 | */ |
8 | |
9 | #include "cmslocal.h" |
10 | |
11 | #include "cert.h" |
12 | #include "keyhi.h" |
13 | #include "secasn1.h" |
14 | #include "secitem.h" |
15 | #include "secoid.h" |
16 | #include "pk11func.h" |
17 | #include "secerr.h" |
18 | |
19 | PRBool |
20 | nss_cmsrecipientinfo_usessubjectkeyid(NSSCMSRecipientInfo *ri) |
21 | { |
22 | if (ri->recipientInfoType == NSSCMSRecipientInfoID_KeyTrans) { |
23 | NSSCMSRecipientIdentifier *rid; |
24 | rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; |
25 | if (rid->identifierType == NSSCMSRecipientID_SubjectKeyID) { |
26 | return PR_TRUE1; |
27 | } |
28 | } |
29 | return PR_FALSE0; |
30 | } |
31 | |
32 | /* |
33 | * NOTE: fakeContent marks CMSMessage structure which is only used as a carrier |
34 | * of pwfn_arg and arena pools. In an ideal world, NSSCMSMessage would not have |
35 | * been exported, and we would have added an ordinary enum to handle this |
36 | * check. Unfortunatly wo don't have that luxury so we are overloading the |
37 | * contentTypeTag field. NO code should every try to interpret this content tag |
38 | * as a real OID tag, or use any fields other than pwfn_arg or poolp of this |
39 | * CMSMessage for that matter */ |
40 | static const SECOidData fakeContent; |
41 | NSSCMSRecipientInfo * |
42 | nss_cmsrecipientinfo_create(NSSCMSMessage *cmsg, |
43 | NSSCMSRecipientIDSelector type, |
44 | CERTCertificate *cert, |
45 | SECKEYPublicKey *pubKey, |
46 | SECItem *subjKeyID, |
47 | void *pwfn_arg, |
48 | SECItem *DERinput) |
49 | { |
50 | NSSCMSRecipientInfo *ri; |
51 | void *mark; |
52 | SECOidTag certalgtag; |
53 | SECStatus rv = SECSuccess; |
54 | NSSCMSRecipientEncryptedKey *rek; |
55 | NSSCMSOriginatorIdentifierOrKey *oiok; |
56 | unsigned long version; |
57 | SECItem *dummy; |
58 | PLArenaPool *poolp; |
59 | CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL((void*)0); |
60 | NSSCMSRecipientIdentifier *rid; |
61 | extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; |
62 | |
63 | if (!cmsg) { |
64 | /* a CMSMessage wasn't supplied, create a fake one to hold the pwfunc |
65 | * and a private arena pool */ |
66 | cmsg = NSS_CMSMessage_Create(NULL((void*)0)); |
67 | cmsg->pwfn_arg = pwfn_arg; |
68 | /* mark it as a special cms message */ |
69 | cmsg->contentInfo.contentTypeTag = (SECOidData *)&fakeContent; |
70 | } |
71 | |
72 | poolp = cmsg->poolp; |
73 | |
74 | mark = PORT_ArenaMarkPORT_ArenaMark_Util(poolp); |
75 | |
76 | ri = (NSSCMSRecipientInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(poolp, sizeof(NSSCMSRecipientInfo)); |
77 | if (ri == NULL((void*)0)) |
78 | goto loser; |
79 | |
80 | ri->cmsg = cmsg; |
81 | |
82 | if (DERinput) { |
83 | /* decode everything from DER */ |
84 | SECItem newinput; |
85 | rv = SECITEM_CopyItemSECITEM_CopyItem_Util(poolp, &newinput, DERinput); |
86 | if (SECSuccess != rv) |
87 | goto loser; |
88 | rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); |
89 | if (SECSuccess != rv) |
90 | goto loser; |
91 | } |
92 | |
93 | switch (type) { |
94 | case NSSCMSRecipientID_IssuerSN: { |
95 | ri->cert = CERT_DupCertificate(cert); |
96 | if (NULL((void*)0) == ri->cert) |
97 | goto loser; |
98 | spki = &(cert->subjectPublicKeyInfo); |
99 | break; |
100 | } |
101 | |
102 | case NSSCMSRecipientID_SubjectKeyID: { |
103 | PORT_Assert(pubKey)((pubKey)?((void)0):PR_Assert("pubKey","cmsrecinfo.c",103)); |
104 | spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); |
105 | break; |
106 | } |
107 | |
108 | case NSSCMSRecipientID_BrandNew: |
109 | goto done; |
110 | break; |
111 | |
112 | default: |
113 | /* unkown type */ |
114 | goto loser; |
115 | break; |
116 | } |
117 | |
118 | certalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(spki->algorithm)); |
119 | |
120 | rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; |
121 | |
122 | // This switch must match the switch in NSS_CMSRecipient_IsSupported. |
123 | switch (certalgtag) { |
124 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
125 | ri->recipientInfoType = NSSCMSRecipientInfoID_KeyTrans; |
126 | rid->identifierType = type; |
127 | if (type == NSSCMSRecipientID_IssuerSN) { |
128 | rid->id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert); |
129 | if (rid->id.issuerAndSN == NULL((void*)0)) { |
130 | break; |
131 | } |
132 | } else if (type == NSSCMSRecipientID_SubjectKeyID) { |
133 | NSSCMSKeyTransRecipientInfoEx *riExtra; |
134 | |
135 | rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem)(SECItem *)PORT_ArenaAlloc_Util(poolp, sizeof(SECItem)); |
136 | if (rid->id.subjectKeyID == NULL((void*)0)) { |
137 | rv = SECFailure; |
138 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY); |
139 | break; |
140 | } |
141 | rv = SECITEM_CopyItemSECITEM_CopyItem_Util(poolp, rid->id.subjectKeyID, subjKeyID); |
142 | if (rv != SECSuccess || rid->id.subjectKeyID->data == NULL((void*)0)) { |
143 | rv = SECFailure; |
144 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY); |
145 | break; |
146 | } |
147 | riExtra = &ri->ri.keyTransRecipientInfoEx; |
148 | riExtra->version = 0; |
149 | riExtra->pubKey = SECKEY_CopyPublicKey(pubKey); |
150 | if (riExtra->pubKey == NULL((void*)0)) { |
151 | rv = SECFailure; |
152 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY); |
153 | break; |
154 | } |
155 | } else { |
156 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS); |
157 | rv = SECFailure; |
158 | } |
159 | break; |
160 | case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ |
161 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
162 | PORT_Assert(type == NSSCMSRecipientID_IssuerSN)((type == NSSCMSRecipientID_IssuerSN)?((void)0):PR_Assert("type == NSSCMSRecipientID_IssuerSN" ,"cmsrecinfo.c",162)); |
163 | if (type != NSSCMSRecipientID_IssuerSN) { |
164 | rv = SECFailure; |
165 | break; |
166 | } |
167 | /* a key agreement op */ |
168 | ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; |
169 | |
170 | /* we do not support the case where multiple recipients |
171 | * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys |
172 | * in this case, we would need to walk all the recipientInfos, take the |
173 | * ones that do KeyAgreement algorithms and join them, algorithm by algorithm |
174 | * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ |
175 | |
176 | /* only epheremal-static Diffie-Hellman is supported for now |
177 | * this is the only form of key agreement that provides potential anonymity |
178 | * of the sender, plus we do not have to include certs in the message */ |
179 | |
180 | /* force single recipientEncryptedKey for now */ |
181 | if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL((void*)0)) { |
182 | rv = SECFailure; |
183 | break; |
184 | } |
185 | |
186 | /* hardcoded IssuerSN choice for now */ |
187 | rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; |
188 | if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL((void*)0)) { |
189 | rv = SECFailure; |
190 | break; |
191 | } |
192 | |
193 | oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); |
194 | |
195 | /* see RFC2630 12.3.1.1 */ |
196 | oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; |
197 | |
198 | rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, |
199 | (void *)rek); |
200 | |
201 | break; |
202 | default: |
203 | /* other algorithms not supported yet */ |
204 | /* NOTE that we do not support any KEK algorithm */ |
205 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM); |
206 | rv = SECFailure; |
207 | break; |
208 | } |
209 | |
210 | if (rv == SECFailure) |
211 | goto loser; |
212 | |
213 | /* set version */ |
214 | switch (ri->recipientInfoType) { |
215 | case NSSCMSRecipientInfoID_KeyTrans: |
216 | if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) |
217 | version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN0; |
218 | else |
219 | version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY2; |
220 | dummy = SEC_ASN1EncodeIntegerSEC_ASN1EncodeInteger_Util(poolp, &(ri->ri.keyTransRecipientInfo.version), version); |
221 | if (dummy == NULL((void*)0)) |
222 | goto loser; |
223 | break; |
224 | case NSSCMSRecipientInfoID_KeyAgree: |
225 | dummy = SEC_ASN1EncodeIntegerSEC_ASN1EncodeInteger_Util(poolp, &(ri->ri.keyAgreeRecipientInfo.version), |
226 | NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION3); |
227 | if (dummy == NULL((void*)0)) |
228 | goto loser; |
229 | break; |
230 | case NSSCMSRecipientInfoID_KEK: |
231 | /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ |
232 | dummy = SEC_ASN1EncodeIntegerSEC_ASN1EncodeInteger_Util(poolp, &(ri->ri.kekRecipientInfo.version), |
233 | NSS_CMS_KEK_RECIPIENT_INFO_VERSION4); |
234 | if (dummy == NULL((void*)0)) |
235 | goto loser; |
236 | break; |
237 | } |
238 | |
239 | done: |
240 | PORT_ArenaUnmarkPORT_ArenaUnmark_Util(poolp, mark); |
241 | if (freeSpki) |
242 | SECKEY_DestroySubjectPublicKeyInfo(freeSpki); |
243 | return ri; |
244 | |
245 | loser: |
246 | if (ri && ri->cert) { |
247 | CERT_DestroyCertificate(ri->cert); |
248 | } |
249 | if (freeSpki) { |
250 | SECKEY_DestroySubjectPublicKeyInfo(freeSpki); |
251 | } |
252 | PORT_ArenaReleasePORT_ArenaRelease_Util(poolp, mark); |
253 | if (cmsg->contentInfo.contentTypeTag == &fakeContent) { |
254 | NSS_CMSMessage_Destroy(cmsg); |
255 | } |
256 | return NULL((void*)0); |
257 | } |
258 | |
259 | /* |
260 | * NSS_CMSRecipient_IsSupported - checks for a support certificate |
261 | * |
262 | * Use this function to confirm that the given certificate will be |
263 | * accepted by NSS_CMSRecipientInfo_Create, which means that the |
264 | * certificate can be used with a supported encryption algorithm. |
265 | */ |
266 | PRBool |
267 | NSS_CMSRecipient_IsSupported(CERTCertificate *cert) |
268 | { |
269 | CERTSubjectPublicKeyInfo *spki = &(cert->subjectPublicKeyInfo); |
270 | SECOidTag certalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(spki->algorithm)); |
271 | |
272 | switch (certalgtag) { |
273 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
274 | case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ |
275 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
276 | return PR_TRUE1; |
277 | default: |
278 | return PR_FALSE0; |
279 | } |
280 | } |
281 | |
282 | /* |
283 | * NSS_CMSRecipientInfo_Create - create a recipientinfo |
284 | * |
285 | * we currently do not create KeyAgreement recipientinfos with multiple |
286 | * recipientEncryptedKeys the certificate is supposed to have been |
287 | * verified by the caller |
288 | */ |
289 | NSSCMSRecipientInfo * |
290 | NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert) |
291 | { |
292 | return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, |
293 | NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
294 | } |
295 | |
296 | NSSCMSRecipientInfo * |
297 | NSS_CMSRecipientInfo_CreateNew(void *pwfn_arg) |
298 | { |
299 | return nss_cmsrecipientinfo_create(NULL((void*)0), NSSCMSRecipientID_BrandNew, NULL((void*)0), |
300 | NULL((void*)0), NULL((void*)0), pwfn_arg, NULL((void*)0)); |
301 | } |
302 | |
303 | NSSCMSRecipientInfo * |
304 | NSS_CMSRecipientInfo_CreateFromDER(SECItem *input, void *pwfn_arg) |
305 | { |
306 | return nss_cmsrecipientinfo_create(NULL((void*)0), NSSCMSRecipientID_BrandNew, NULL((void*)0), |
307 | NULL((void*)0), NULL((void*)0), pwfn_arg, input); |
308 | } |
309 | |
310 | NSSCMSRecipientInfo * |
311 | NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, |
312 | SECItem *subjKeyID, |
313 | SECKEYPublicKey *pubKey) |
314 | { |
315 | return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, |
316 | NULL((void*)0), pubKey, subjKeyID, NULL((void*)0), NULL((void*)0)); |
317 | } |
318 | |
319 | NSSCMSRecipientInfo * |
320 | NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg, |
321 | CERTCertificate *cert) |
322 | { |
323 | SECKEYPublicKey *pubKey = NULL((void*)0); |
324 | SECItem subjKeyID = { siBuffer, NULL((void*)0), 0 }; |
325 | NSSCMSRecipientInfo *retVal = NULL((void*)0); |
326 | |
327 | if (!cmsg || !cert) { |
328 | return NULL((void*)0); |
329 | } |
330 | pubKey = CERT_ExtractPublicKey(cert); |
331 | if (!pubKey) { |
332 | goto done; |
333 | } |
334 | if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess || |
335 | subjKeyID.data == NULL((void*)0)) { |
336 | goto done; |
337 | } |
338 | retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey); |
339 | done: |
340 | if (pubKey) |
341 | SECKEY_DestroyPublicKey(pubKey); |
342 | |
343 | if (subjKeyID.data) |
344 | SECITEM_FreeItemSECITEM_FreeItem_Util(&subjKeyID, PR_FALSE0); |
345 | |
346 | return retVal; |
347 | } |
348 | |
349 | void |
350 | NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) |
351 | { |
352 | if (!ri) { |
353 | return; |
354 | } |
355 | /* version was allocated on the pool, so no need to destroy it */ |
356 | /* issuerAndSN was allocated on the pool, so no need to destroy it */ |
357 | if (ri->cert != NULL((void*)0)) |
358 | CERT_DestroyCertificate(ri->cert); |
359 | |
360 | if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { |
361 | NSSCMSKeyTransRecipientInfoEx *extra; |
362 | extra = &ri->ri.keyTransRecipientInfoEx; |
363 | if (extra->pubKey) |
364 | SECKEY_DestroyPublicKey(extra->pubKey); |
365 | } |
366 | if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { |
367 | NSS_CMSMessage_Destroy(ri->cmsg); |
368 | } |
369 | |
370 | /* we're done. */ |
371 | } |
372 | |
373 | int |
374 | NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri) |
375 | { |
376 | unsigned long version; |
377 | SECItem *versionitem = NULL((void*)0); |
378 | |
379 | switch (ri->recipientInfoType) { |
380 | case NSSCMSRecipientInfoID_KeyTrans: |
381 | /* ignore subIndex */ |
382 | versionitem = &(ri->ri.keyTransRecipientInfo.version); |
383 | break; |
384 | case NSSCMSRecipientInfoID_KEK: |
385 | /* ignore subIndex */ |
386 | versionitem = &(ri->ri.kekRecipientInfo.version); |
387 | break; |
388 | case NSSCMSRecipientInfoID_KeyAgree: |
389 | versionitem = &(ri->ri.keyAgreeRecipientInfo.version); |
390 | break; |
391 | } |
392 | |
393 | PORT_Assert(versionitem)((versionitem)?((void)0):PR_Assert("versionitem","cmsrecinfo.c" ,393)); |
394 | if (versionitem == NULL((void*)0)) |
395 | return 0; |
396 | |
397 | /* always take apart the SECItem */ |
398 | if (SEC_ASN1DecodeIntegerSEC_ASN1DecodeInteger_Util(versionitem, &version) != SECSuccess) |
399 | return 0; |
400 | else |
401 | return (int)version; |
402 | } |
403 | |
404 | SECItem * |
405 | NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex) |
406 | { |
407 | SECItem *enckey = NULL((void*)0); |
408 | |
409 | switch (ri->recipientInfoType) { |
410 | case NSSCMSRecipientInfoID_KeyTrans: |
411 | /* ignore subIndex */ |
412 | enckey = &(ri->ri.keyTransRecipientInfo.encKey); |
413 | break; |
414 | case NSSCMSRecipientInfoID_KEK: |
415 | /* ignore subIndex */ |
416 | enckey = &(ri->ri.kekRecipientInfo.encKey); |
417 | break; |
418 | case NSSCMSRecipientInfoID_KeyAgree: |
419 | enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); |
420 | break; |
421 | } |
422 | return enckey; |
423 | } |
424 | |
425 | SECOidTag |
426 | NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri) |
427 | { |
428 | SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */ |
429 | |
430 | switch (ri->recipientInfoType) { |
431 | case NSSCMSRecipientInfoID_KeyTrans: |
432 | encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); |
433 | break; |
434 | case NSSCMSRecipientInfoID_KeyAgree: |
435 | encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); |
436 | break; |
437 | case NSSCMSRecipientInfoID_KEK: |
438 | encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->ri.kekRecipientInfo.keyEncAlg)); |
439 | break; |
440 | } |
441 | return encalgtag; |
442 | } |
443 | |
444 | SECStatus |
445 | NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, |
446 | SECOidTag bulkalgtag) |
447 | { |
448 | CERTCertificate *cert; |
449 | SECOidTag certalgtag; |
450 | SECStatus rv = SECSuccess; |
451 | NSSCMSRecipientEncryptedKey *rek; |
452 | NSSCMSOriginatorIdentifierOrKey *oiok; |
453 | CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL((void*)0); |
454 | PLArenaPool *poolp; |
455 | NSSCMSKeyTransRecipientInfoEx *extra = NULL((void*)0); |
456 | PRBool usesSubjKeyID; |
457 | void *wincx = NULL((void*)0); |
458 | |
459 | poolp = ri->cmsg->poolp; |
460 | cert = ri->cert; |
461 | usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); |
462 | if (cert) { |
463 | spki = &cert->subjectPublicKeyInfo; |
464 | } else if (usesSubjKeyID) { |
465 | extra = &ri->ri.keyTransRecipientInfoEx; |
466 | /* sanity check */ |
467 | PORT_Assert(extra->pubKey)((extra->pubKey)?((void)0):PR_Assert("extra->pubKey","cmsrecinfo.c" ,467)); |
468 | if (!extra->pubKey) { |
469 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS); |
470 | return SECFailure; |
471 | } |
472 | spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey); |
473 | } else { |
474 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS); |
475 | return SECFailure; |
476 | } |
477 | |
478 | /* XXX set ri->recipientInfoType to the proper value here */ |
479 | /* or should we look if it's been set already ? */ |
480 | |
481 | certalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&spki->algorithm); |
482 | switch (certalgtag) { |
483 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
484 | /* wrap the symkey */ |
485 | if (cert) { |
486 | rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, |
487 | &ri->ri.keyTransRecipientInfo.encKey); |
488 | if (rv != SECSuccess) |
489 | break; |
490 | } else if (usesSubjKeyID) { |
491 | PORT_Assert(extra != NULL)((extra != ((void*)0))?((void)0):PR_Assert("extra != NULL","cmsrecinfo.c" ,491)); |
492 | rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey, |
493 | bulkkey, &ri->ri.keyTransRecipientInfo.encKey); |
494 | if (rv != SECSuccess) |
495 | break; |
496 | } |
497 | |
498 | rv = SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL((void*)0)); |
499 | break; |
500 | case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ |
501 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
502 | rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; |
503 | if (rek == NULL((void*)0)) { |
504 | rv = SECFailure; |
505 | break; |
506 | } |
507 | |
508 | oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); |
509 | PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey)((oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey )?((void)0):PR_Assert("oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey" ,"cmsrecinfo.c",509)); |
510 | |
511 | /* see RFC2630 12.3.1.1 */ |
512 | if (SECOID_SetAlgorithmIDSECOID_SetAlgorithmID_Util(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, |
513 | certalgtag, NULL((void*)0)) != SECSuccess) { |
514 | rv = SECFailure; |
515 | break; |
516 | } |
517 | |
518 | /* this will generate a key pair, compute the shared secret, */ |
519 | /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ |
520 | /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ |
521 | switch (certalgtag) { |
522 | case SEC_OID_X942_DIFFIE_HELMAN_KEY: |
523 | rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey, |
524 | &rek->encKey, |
525 | &ri->ri.keyAgreeRecipientInfo.ukm, |
526 | &ri->ri.keyAgreeRecipientInfo.keyEncAlg, |
527 | &oiok->id.originatorPublicKey.publicKey); |
528 | break; |
529 | |
530 | case SEC_OID_ANSIX962_EC_PUBLIC_KEY: |
531 | if (ri->cmsg) { |
532 | wincx = ri->cmsg->pwfn_arg; |
533 | } else { |
534 | wincx = PK11_GetWindow(bulkkey); |
535 | } |
536 | rv = NSS_CMSUtil_EncryptSymKey_ESECDH(poolp, cert, bulkkey, |
537 | &rek->encKey, |
538 | PR_TRUE1, |
539 | &ri->ri.keyAgreeRecipientInfo.ukm, |
540 | &ri->ri.keyAgreeRecipientInfo.keyEncAlg, |
541 | &oiok->id.originatorPublicKey.publicKey, |
542 | wincx); |
543 | break; |
544 | |
545 | default: |
546 | /* Not reached. Added to silence enum warnings. */ |
547 | PORT_Assert(0)((0)?((void)0):PR_Assert("0","cmsrecinfo.c",547)); |
548 | break; |
549 | } |
550 | break; |
551 | default: |
552 | /* other algorithms not supported yet */ |
553 | /* NOTE that we do not support any KEK algorithm */ |
554 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM); |
555 | rv = SECFailure; |
556 | } |
557 | if (freeSpki) |
558 | SECKEY_DestroySubjectPublicKeyInfo(freeSpki); |
559 | |
560 | return rv; |
561 | } |
562 | |
563 | PK11SymKey * |
564 | NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, |
565 | CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag) |
566 | { |
567 | PK11SymKey *bulkkey = NULL((void*)0); |
568 | SECOidTag encalgtag; |
569 | SECItem *enckey, *ukm; |
570 | NSSCMSOriginatorIdentifierOrKey *oiok; |
571 | int error; |
572 | void *wincx = NULL((void*)0); |
573 | |
574 | ri->cert = CERT_DupCertificate(cert); |
575 | /* mark the recipientInfo so we can find it later */ |
576 | |
577 | switch (ri->recipientInfoType) { |
578 | case NSSCMSRecipientInfoID_KeyTrans: |
579 | encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); |
580 | enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */ |
581 | switch (encalgtag) { |
582 | case SEC_OID_PKCS1_RSA_ENCRYPTION: |
583 | /* RSA encryption algorithm: */ |
584 | /* get the symmetric (bulk) key by unwrapping it using our private key */ |
585 | bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag); |
586 | break; |
587 | default: |
588 | error = SEC_ERROR_UNSUPPORTED_KEYALG; |
589 | goto loser; |
590 | } |
591 | break; |
592 | case NSSCMSRecipientInfoID_KeyAgree: |
593 | encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); |
594 | enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); |
595 | oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); |
596 | ukm = &(ri->ri.keyAgreeRecipientInfo.ukm); |
597 | switch (encalgtag) { |
598 | case SEC_OID_DHSINGLEPASS_STDDH_SHA1KDF_SCHEME: |
599 | case SEC_OID_DHSINGLEPASS_STDDH_SHA224KDF_SCHEME: |
600 | case SEC_OID_DHSINGLEPASS_STDDH_SHA256KDF_SCHEME: |
601 | case SEC_OID_DHSINGLEPASS_STDDH_SHA384KDF_SCHEME: |
602 | case SEC_OID_DHSINGLEPASS_STDDH_SHA512KDF_SCHEME: |
603 | case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA1KDF_SCHEME: |
604 | case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA224KDF_SCHEME: |
605 | case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA256KDF_SCHEME: |
606 | case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA384KDF_SCHEME: |
607 | case SEC_OID_DHSINGLEPASS_COFACTORDH_SHA512KDF_SCHEME: |
608 | if (ri->cmsg) { |
609 | wincx = ri->cmsg->pwfn_arg; |
610 | } |
611 | bulkkey = NSS_CMSUtil_DecryptSymKey_ECDH(privkey, enckey, |
612 | &(ri->ri.keyAgreeRecipientInfo.keyEncAlg), |
613 | bulkalgtag, ukm, oiok, wincx); |
614 | break; |
615 | |
616 | case SEC_OID_X942_DIFFIE_HELMAN_KEY: |
617 | /* Diffie-Helman key exchange */ |
618 | /* XXX not yet implemented */ |
619 | /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */ |
620 | /* we support ephemeral-static DH only, so if the recipientinfo */ |
621 | /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */ |
622 | /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */ |
623 | /* content encryption key using a Unwrap op */ |
624 | /* the derive operation has to generate the key using the algorithm in RFC2631 */ |
625 | error = SEC_ERROR_UNSUPPORTED_KEYALG; |
626 | goto loser; |
627 | break; |
628 | default: |
629 | error = SEC_ERROR_UNSUPPORTED_KEYALG; |
630 | goto loser; |
631 | } |
632 | break; |
633 | case NSSCMSRecipientInfoID_KEK: |
634 | encalgtag = SECOID_GetAlgorithmTagSECOID_GetAlgorithmTag_Util(&(ri->ri.kekRecipientInfo.keyEncAlg)); |
Value stored to 'encalgtag' is never read | |
635 | enckey = &(ri->ri.kekRecipientInfo.encKey); |
636 | /* not supported yet */ |
637 | error = SEC_ERROR_UNSUPPORTED_KEYALG; |
638 | goto loser; |
639 | break; |
640 | } |
641 | /* XXXX continue here */ |
642 | return bulkkey; |
643 | |
644 | loser: |
645 | PORT_SetErrorPORT_SetError_Util(error); |
646 | return NULL((void*)0); |
647 | } |
648 | |
649 | SECStatus |
650 | NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, |
651 | CERTCertificate **retcert, |
652 | SECKEYPrivateKey **retkey) |
653 | { |
654 | CERTCertificate *cert = NULL((void*)0); |
655 | NSSCMSRecipient **recipients = NULL((void*)0); |
656 | NSSCMSRecipientInfo *recipientInfos[2]; |
657 | SECStatus rv = SECSuccess; |
658 | SECKEYPrivateKey *key = NULL((void*)0); |
659 | |
660 | if (!ri) |
661 | return SECFailure; |
662 | |
663 | if (!retcert && !retkey) { |
664 | /* nothing requested, nothing found, success */ |
665 | return SECSuccess; |
666 | } |
667 | |
668 | if (retcert) { |
669 | *retcert = NULL((void*)0); |
670 | } |
671 | if (retkey) { |
672 | *retkey = NULL((void*)0); |
673 | } |
674 | |
675 | if (ri->cert) { |
676 | cert = CERT_DupCertificate(ri->cert); |
677 | if (!cert) { |
678 | rv = SECFailure; |
679 | } |
680 | } |
681 | if (SECSuccess == rv && !cert) { |
682 | /* we don't have the cert, we have to look for it */ |
683 | /* first build an NSS_CMSRecipient */ |
684 | recipientInfos[0] = ri; |
685 | recipientInfos[1] = NULL((void*)0); |
686 | |
687 | recipients = nss_cms_recipient_list_create(recipientInfos); |
688 | if (recipients) { |
689 | /* now look for the cert and key */ |
690 | if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients, |
691 | ri->cmsg->pwfn_arg)) { |
692 | cert = CERT_DupCertificate(recipients[0]->cert); |
693 | key = SECKEY_CopyPrivateKey(recipients[0]->privkey); |
694 | } else { |
695 | rv = SECFailure; |
696 | } |
697 | |
698 | nss_cms_recipient_list_destroy(recipients); |
699 | } else { |
700 | rv = SECFailure; |
701 | } |
702 | } else if (SECSuccess == rv && cert && retkey) { |
703 | /* we have the cert, we just need the key now */ |
704 | key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg); |
705 | } |
706 | if (retcert) { |
707 | *retcert = cert; |
708 | } else { |
709 | if (cert) { |
710 | CERT_DestroyCertificate(cert); |
711 | } |
712 | } |
713 | if (retkey) { |
714 | *retkey = key; |
715 | } else { |
716 | if (key) { |
717 | SECKEY_DestroyPrivateKey(key); |
718 | } |
719 | } |
720 | |
721 | return rv; |
722 | } |
723 | |
724 | SECStatus |
725 | NSS_CMSRecipientInfo_Encode(PLArenaPool *poolp, |
726 | const NSSCMSRecipientInfo *src, |
727 | SECItem *returned) |
728 | { |
729 | extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; |
730 | SECStatus rv = SECFailure; |
731 | if (!src || !returned) { |
732 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS); |
733 | } else if (SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(poolp, returned, src, |
734 | NSSCMSRecipientInfoTemplate)) { |
735 | rv = SECSuccess; |
736 | } |
737 | return rv; |
738 | } |