|
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 "key.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_TRUE; |
|
27 } |
|
28 } |
|
29 return PR_FALSE; |
|
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; |
|
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); |
|
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_ArenaMark(poolp); |
|
75 |
|
76 ri = (NSSCMSRecipientInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSRecipientInfo)); |
|
77 if (ri == NULL) |
|
78 goto loser; |
|
79 |
|
80 ri->cmsg = cmsg; |
|
81 |
|
82 if (DERinput) { |
|
83 /* decode everything from DER */ |
|
84 SECItem newinput; |
|
85 SECStatus rv = SECITEM_CopyItem(poolp, &newinput, DERinput); |
|
86 if (SECSuccess != rv) |
|
87 goto loser; |
|
88 rv = SEC_QuickDERDecodeItem(poolp, ri, NSSCMSRecipientInfoTemplate, &newinput); |
|
89 if (SECSuccess != rv) |
|
90 goto loser; |
|
91 } |
|
92 |
|
93 switch (type) { |
|
94 case NSSCMSRecipientID_IssuerSN: |
|
95 { |
|
96 ri->cert = CERT_DupCertificate(cert); |
|
97 if (NULL == ri->cert) |
|
98 goto loser; |
|
99 spki = &(cert->subjectPublicKeyInfo); |
|
100 break; |
|
101 } |
|
102 |
|
103 case NSSCMSRecipientID_SubjectKeyID: |
|
104 { |
|
105 PORT_Assert(pubKey); |
|
106 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); |
|
107 break; |
|
108 } |
|
109 |
|
110 case NSSCMSRecipientID_BrandNew: |
|
111 goto done; |
|
112 break; |
|
113 |
|
114 default: |
|
115 /* unkown type */ |
|
116 goto loser; |
|
117 break; |
|
118 } |
|
119 |
|
120 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); |
|
121 |
|
122 rid = &ri->ri.keyTransRecipientInfo.recipientIdentifier; |
|
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) { |
|
130 break; |
|
131 } |
|
132 } else if (type == NSSCMSRecipientID_SubjectKeyID){ |
|
133 NSSCMSKeyTransRecipientInfoEx *riExtra; |
|
134 |
|
135 rid->id.subjectKeyID = PORT_ArenaNew(poolp, SECItem); |
|
136 if (rid->id.subjectKeyID == NULL) { |
|
137 rv = SECFailure; |
|
138 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
139 break; |
|
140 } |
|
141 SECITEM_CopyItem(poolp, rid->id.subjectKeyID, subjKeyID); |
|
142 if (rid->id.subjectKeyID->data == NULL) { |
|
143 rv = SECFailure; |
|
144 PORT_SetError(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) { |
|
151 rv = SECFailure; |
|
152 PORT_SetError(SEC_ERROR_NO_MEMORY); |
|
153 break; |
|
154 } |
|
155 } else { |
|
156 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
157 rv = SECFailure; |
|
158 } |
|
159 break; |
|
160 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ |
|
161 PORT_Assert(type == NSSCMSRecipientID_IssuerSN); |
|
162 if (type != NSSCMSRecipientID_IssuerSN) { |
|
163 rv = SECFailure; |
|
164 break; |
|
165 } |
|
166 /* a key agreement op */ |
|
167 ri->recipientInfoType = NSSCMSRecipientInfoID_KeyAgree; |
|
168 |
|
169 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.id.issuerAndSN == NULL) { |
|
170 rv = SECFailure; |
|
171 break; |
|
172 } |
|
173 /* we do not support the case where multiple recipients |
|
174 * share the same KeyAgreeRecipientInfo and have multiple RecipientEncryptedKeys |
|
175 * in this case, we would need to walk all the recipientInfos, take the |
|
176 * ones that do KeyAgreement algorithms and join them, algorithm by algorithm |
|
177 * Then, we'd generate ONE ukm and OriginatorIdentifierOrKey */ |
|
178 |
|
179 /* only epheremal-static Diffie-Hellman is supported for now |
|
180 * this is the only form of key agreement that provides potential anonymity |
|
181 * of the sender, plus we do not have to include certs in the message */ |
|
182 |
|
183 /* force single recipientEncryptedKey for now */ |
|
184 if ((rek = NSS_CMSRecipientEncryptedKey_Create(poolp)) == NULL) { |
|
185 rv = SECFailure; |
|
186 break; |
|
187 } |
|
188 |
|
189 /* hardcoded IssuerSN choice for now */ |
|
190 rek->recipientIdentifier.identifierType = NSSCMSKeyAgreeRecipientID_IssuerSN; |
|
191 if ((rek->recipientIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL) { |
|
192 rv = SECFailure; |
|
193 break; |
|
194 } |
|
195 |
|
196 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); |
|
197 |
|
198 /* see RFC2630 12.3.1.1 */ |
|
199 oiok->identifierType = NSSCMSOriginatorIDOrKey_OriginatorPublicKey; |
|
200 |
|
201 rv = NSS_CMSArray_Add(poolp, (void ***)&ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys, |
|
202 (void *)rek); |
|
203 |
|
204 break; |
|
205 default: |
|
206 /* other algorithms not supported yet */ |
|
207 /* NOTE that we do not support any KEK algorithm */ |
|
208 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
|
209 rv = SECFailure; |
|
210 break; |
|
211 } |
|
212 |
|
213 if (rv == SECFailure) |
|
214 goto loser; |
|
215 |
|
216 /* set version */ |
|
217 switch (ri->recipientInfoType) { |
|
218 case NSSCMSRecipientInfoID_KeyTrans: |
|
219 if (ri->ri.keyTransRecipientInfo.recipientIdentifier.identifierType == NSSCMSRecipientID_IssuerSN) |
|
220 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_ISSUERSN; |
|
221 else |
|
222 version = NSS_CMS_KEYTRANS_RECIPIENT_INFO_VERSION_SUBJKEY; |
|
223 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyTransRecipientInfo.version), version); |
|
224 if (dummy == NULL) |
|
225 goto loser; |
|
226 break; |
|
227 case NSSCMSRecipientInfoID_KeyAgree: |
|
228 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.keyAgreeRecipientInfo.version), |
|
229 NSS_CMS_KEYAGREE_RECIPIENT_INFO_VERSION); |
|
230 if (dummy == NULL) |
|
231 goto loser; |
|
232 break; |
|
233 case NSSCMSRecipientInfoID_KEK: |
|
234 /* NOTE: this cannot happen as long as we do not support any KEK algorithm */ |
|
235 dummy = SEC_ASN1EncodeInteger(poolp, &(ri->ri.kekRecipientInfo.version), |
|
236 NSS_CMS_KEK_RECIPIENT_INFO_VERSION); |
|
237 if (dummy == NULL) |
|
238 goto loser; |
|
239 break; |
|
240 |
|
241 } |
|
242 |
|
243 done: |
|
244 PORT_ArenaUnmark (poolp, mark); |
|
245 if (freeSpki) |
|
246 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); |
|
247 return ri; |
|
248 |
|
249 loser: |
|
250 if (ri && ri->cert) { |
|
251 CERT_DestroyCertificate(ri->cert); |
|
252 } |
|
253 if (freeSpki) { |
|
254 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); |
|
255 } |
|
256 PORT_ArenaRelease (poolp, mark); |
|
257 if (cmsg->contentInfo.contentTypeTag == &fakeContent) { |
|
258 NSS_CMSMessage_Destroy(cmsg); |
|
259 } |
|
260 return NULL; |
|
261 } |
|
262 |
|
263 /* |
|
264 * NSS_CMSRecipientInfo_Create - create a recipientinfo |
|
265 * |
|
266 * we currently do not create KeyAgreement recipientinfos with multiple |
|
267 * recipientEncryptedKeys the certificate is supposed to have been |
|
268 * verified by the caller |
|
269 */ |
|
270 NSSCMSRecipientInfo * |
|
271 NSS_CMSRecipientInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert) |
|
272 { |
|
273 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_IssuerSN, cert, |
|
274 NULL, NULL, NULL, NULL); |
|
275 } |
|
276 |
|
277 NSSCMSRecipientInfo * |
|
278 NSS_CMSRecipientInfo_CreateNew(void* pwfn_arg) |
|
279 { |
|
280 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, |
|
281 NULL, NULL, pwfn_arg, NULL); |
|
282 } |
|
283 |
|
284 NSSCMSRecipientInfo * |
|
285 NSS_CMSRecipientInfo_CreateFromDER(SECItem* input, void* pwfn_arg) |
|
286 { |
|
287 return nss_cmsrecipientinfo_create(NULL, NSSCMSRecipientID_BrandNew, NULL, |
|
288 NULL, NULL, pwfn_arg, input); |
|
289 } |
|
290 |
|
291 |
|
292 NSSCMSRecipientInfo * |
|
293 NSS_CMSRecipientInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, |
|
294 SECItem *subjKeyID, |
|
295 SECKEYPublicKey *pubKey) |
|
296 { |
|
297 return nss_cmsrecipientinfo_create(cmsg, NSSCMSRecipientID_SubjectKeyID, |
|
298 NULL, pubKey, subjKeyID, NULL, NULL); |
|
299 } |
|
300 |
|
301 NSSCMSRecipientInfo * |
|
302 NSS_CMSRecipientInfo_CreateWithSubjKeyIDFromCert(NSSCMSMessage *cmsg, |
|
303 CERTCertificate *cert) |
|
304 { |
|
305 SECKEYPublicKey *pubKey = NULL; |
|
306 SECItem subjKeyID = {siBuffer, NULL, 0}; |
|
307 NSSCMSRecipientInfo *retVal = NULL; |
|
308 |
|
309 if (!cmsg || !cert) { |
|
310 return NULL; |
|
311 } |
|
312 pubKey = CERT_ExtractPublicKey(cert); |
|
313 if (!pubKey) { |
|
314 goto done; |
|
315 } |
|
316 if (CERT_FindSubjectKeyIDExtension(cert, &subjKeyID) != SECSuccess || |
|
317 subjKeyID.data == NULL) { |
|
318 goto done; |
|
319 } |
|
320 retVal = NSS_CMSRecipientInfo_CreateWithSubjKeyID(cmsg, &subjKeyID, pubKey); |
|
321 done: |
|
322 if (pubKey) |
|
323 SECKEY_DestroyPublicKey(pubKey); |
|
324 |
|
325 if (subjKeyID.data) |
|
326 SECITEM_FreeItem(&subjKeyID, PR_FALSE); |
|
327 |
|
328 return retVal; |
|
329 } |
|
330 |
|
331 void |
|
332 NSS_CMSRecipientInfo_Destroy(NSSCMSRecipientInfo *ri) |
|
333 { |
|
334 if (!ri) { |
|
335 return; |
|
336 } |
|
337 /* version was allocated on the pool, so no need to destroy it */ |
|
338 /* issuerAndSN was allocated on the pool, so no need to destroy it */ |
|
339 if (ri->cert != NULL) |
|
340 CERT_DestroyCertificate(ri->cert); |
|
341 |
|
342 if (nss_cmsrecipientinfo_usessubjectkeyid(ri)) { |
|
343 NSSCMSKeyTransRecipientInfoEx *extra; |
|
344 extra = &ri->ri.keyTransRecipientInfoEx; |
|
345 if (extra->pubKey) |
|
346 SECKEY_DestroyPublicKey(extra->pubKey); |
|
347 } |
|
348 if (ri->cmsg && ri->cmsg->contentInfo.contentTypeTag == &fakeContent) { |
|
349 NSS_CMSMessage_Destroy(ri->cmsg); |
|
350 } |
|
351 |
|
352 /* we're done. */ |
|
353 } |
|
354 |
|
355 int |
|
356 NSS_CMSRecipientInfo_GetVersion(NSSCMSRecipientInfo *ri) |
|
357 { |
|
358 unsigned long version; |
|
359 SECItem *versionitem = NULL; |
|
360 |
|
361 switch (ri->recipientInfoType) { |
|
362 case NSSCMSRecipientInfoID_KeyTrans: |
|
363 /* ignore subIndex */ |
|
364 versionitem = &(ri->ri.keyTransRecipientInfo.version); |
|
365 break; |
|
366 case NSSCMSRecipientInfoID_KEK: |
|
367 /* ignore subIndex */ |
|
368 versionitem = &(ri->ri.kekRecipientInfo.version); |
|
369 break; |
|
370 case NSSCMSRecipientInfoID_KeyAgree: |
|
371 versionitem = &(ri->ri.keyAgreeRecipientInfo.version); |
|
372 break; |
|
373 } |
|
374 |
|
375 PORT_Assert(versionitem); |
|
376 if (versionitem == NULL) |
|
377 return 0; |
|
378 |
|
379 /* always take apart the SECItem */ |
|
380 if (SEC_ASN1DecodeInteger(versionitem, &version) != SECSuccess) |
|
381 return 0; |
|
382 else |
|
383 return (int)version; |
|
384 } |
|
385 |
|
386 SECItem * |
|
387 NSS_CMSRecipientInfo_GetEncryptedKey(NSSCMSRecipientInfo *ri, int subIndex) |
|
388 { |
|
389 SECItem *enckey = NULL; |
|
390 |
|
391 switch (ri->recipientInfoType) { |
|
392 case NSSCMSRecipientInfoID_KeyTrans: |
|
393 /* ignore subIndex */ |
|
394 enckey = &(ri->ri.keyTransRecipientInfo.encKey); |
|
395 break; |
|
396 case NSSCMSRecipientInfoID_KEK: |
|
397 /* ignore subIndex */ |
|
398 enckey = &(ri->ri.kekRecipientInfo.encKey); |
|
399 break; |
|
400 case NSSCMSRecipientInfoID_KeyAgree: |
|
401 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); |
|
402 break; |
|
403 } |
|
404 return enckey; |
|
405 } |
|
406 |
|
407 |
|
408 SECOidTag |
|
409 NSS_CMSRecipientInfo_GetKeyEncryptionAlgorithmTag(NSSCMSRecipientInfo *ri) |
|
410 { |
|
411 SECOidTag encalgtag = SEC_OID_UNKNOWN; /* an invalid encryption alg */ |
|
412 |
|
413 switch (ri->recipientInfoType) { |
|
414 case NSSCMSRecipientInfoID_KeyTrans: |
|
415 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); |
|
416 break; |
|
417 case NSSCMSRecipientInfoID_KeyAgree: |
|
418 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); |
|
419 break; |
|
420 case NSSCMSRecipientInfoID_KEK: |
|
421 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); |
|
422 break; |
|
423 } |
|
424 return encalgtag; |
|
425 } |
|
426 |
|
427 SECStatus |
|
428 NSS_CMSRecipientInfo_WrapBulkKey(NSSCMSRecipientInfo *ri, PK11SymKey *bulkkey, |
|
429 SECOidTag bulkalgtag) |
|
430 { |
|
431 CERTCertificate *cert; |
|
432 SECOidTag certalgtag; |
|
433 SECStatus rv = SECSuccess; |
|
434 NSSCMSRecipientEncryptedKey *rek; |
|
435 NSSCMSOriginatorIdentifierOrKey *oiok; |
|
436 CERTSubjectPublicKeyInfo *spki, *freeSpki = NULL; |
|
437 PLArenaPool *poolp; |
|
438 NSSCMSKeyTransRecipientInfoEx *extra = NULL; |
|
439 PRBool usesSubjKeyID; |
|
440 |
|
441 poolp = ri->cmsg->poolp; |
|
442 cert = ri->cert; |
|
443 usesSubjKeyID = nss_cmsrecipientinfo_usessubjectkeyid(ri); |
|
444 if (cert) { |
|
445 spki = &cert->subjectPublicKeyInfo; |
|
446 certalgtag = SECOID_GetAlgorithmTag(&(spki->algorithm)); |
|
447 } else if (usesSubjKeyID) { |
|
448 extra = &ri->ri.keyTransRecipientInfoEx; |
|
449 /* sanity check */ |
|
450 PORT_Assert(extra->pubKey); |
|
451 if (!extra->pubKey) { |
|
452 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
453 return SECFailure; |
|
454 } |
|
455 spki = freeSpki = SECKEY_CreateSubjectPublicKeyInfo(extra->pubKey); |
|
456 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm); |
|
457 } else { |
|
458 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
459 return SECFailure; |
|
460 } |
|
461 |
|
462 /* XXX set ri->recipientInfoType to the proper value here */ |
|
463 /* or should we look if it's been set already ? */ |
|
464 |
|
465 certalgtag = SECOID_GetAlgorithmTag(&spki->algorithm); |
|
466 switch (certalgtag) { |
|
467 case SEC_OID_PKCS1_RSA_ENCRYPTION: |
|
468 /* wrap the symkey */ |
|
469 if (cert) { |
|
470 rv = NSS_CMSUtil_EncryptSymKey_RSA(poolp, cert, bulkkey, |
|
471 &ri->ri.keyTransRecipientInfo.encKey); |
|
472 if (rv != SECSuccess) |
|
473 break; |
|
474 } else if (usesSubjKeyID) { |
|
475 PORT_Assert(extra != NULL); |
|
476 rv = NSS_CMSUtil_EncryptSymKey_RSAPubKey(poolp, extra->pubKey, |
|
477 bulkkey, &ri->ri.keyTransRecipientInfo.encKey); |
|
478 if (rv != SECSuccess) |
|
479 break; |
|
480 } |
|
481 |
|
482 rv = SECOID_SetAlgorithmID(poolp, &(ri->ri.keyTransRecipientInfo.keyEncAlg), certalgtag, NULL); |
|
483 break; |
|
484 case SEC_OID_X942_DIFFIE_HELMAN_KEY: /* dh-public-number */ |
|
485 rek = ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[0]; |
|
486 if (rek == NULL) { |
|
487 rv = SECFailure; |
|
488 break; |
|
489 } |
|
490 |
|
491 oiok = &(ri->ri.keyAgreeRecipientInfo.originatorIdentifierOrKey); |
|
492 PORT_Assert(oiok->identifierType == NSSCMSOriginatorIDOrKey_OriginatorPublicKey); |
|
493 |
|
494 /* see RFC2630 12.3.1.1 */ |
|
495 if (SECOID_SetAlgorithmID(poolp, &oiok->id.originatorPublicKey.algorithmIdentifier, |
|
496 SEC_OID_X942_DIFFIE_HELMAN_KEY, NULL) != SECSuccess) { |
|
497 rv = SECFailure; |
|
498 break; |
|
499 } |
|
500 |
|
501 /* this will generate a key pair, compute the shared secret, */ |
|
502 /* derive a key and ukm for the keyEncAlg out of it, encrypt the bulk key with */ |
|
503 /* the keyEncAlg, set encKey, keyEncAlg, publicKey etc. */ |
|
504 rv = NSS_CMSUtil_EncryptSymKey_ESDH(poolp, cert, bulkkey, |
|
505 &rek->encKey, |
|
506 &ri->ri.keyAgreeRecipientInfo.ukm, |
|
507 &ri->ri.keyAgreeRecipientInfo.keyEncAlg, |
|
508 &oiok->id.originatorPublicKey.publicKey); |
|
509 |
|
510 break; |
|
511 default: |
|
512 /* other algorithms not supported yet */ |
|
513 /* NOTE that we do not support any KEK algorithm */ |
|
514 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); |
|
515 rv = SECFailure; |
|
516 break; |
|
517 } |
|
518 if (freeSpki) |
|
519 SECKEY_DestroySubjectPublicKeyInfo(freeSpki); |
|
520 |
|
521 return rv; |
|
522 } |
|
523 |
|
524 PK11SymKey * |
|
525 NSS_CMSRecipientInfo_UnwrapBulkKey(NSSCMSRecipientInfo *ri, int subIndex, |
|
526 CERTCertificate *cert, SECKEYPrivateKey *privkey, SECOidTag bulkalgtag) |
|
527 { |
|
528 PK11SymKey *bulkkey = NULL; |
|
529 SECAlgorithmID *encalg; |
|
530 SECOidTag encalgtag; |
|
531 SECItem *enckey; |
|
532 int error; |
|
533 |
|
534 ri->cert = CERT_DupCertificate(cert); |
|
535 /* mark the recipientInfo so we can find it later */ |
|
536 |
|
537 switch (ri->recipientInfoType) { |
|
538 case NSSCMSRecipientInfoID_KeyTrans: |
|
539 encalg = &(ri->ri.keyTransRecipientInfo.keyEncAlg); |
|
540 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyTransRecipientInfo.keyEncAlg)); |
|
541 enckey = &(ri->ri.keyTransRecipientInfo.encKey); /* ignore subIndex */ |
|
542 switch (encalgtag) { |
|
543 case SEC_OID_PKCS1_RSA_ENCRYPTION: |
|
544 /* RSA encryption algorithm: */ |
|
545 /* get the symmetric (bulk) key by unwrapping it using our private key */ |
|
546 bulkkey = NSS_CMSUtil_DecryptSymKey_RSA(privkey, enckey, bulkalgtag); |
|
547 break; |
|
548 default: |
|
549 error = SEC_ERROR_UNSUPPORTED_KEYALG; |
|
550 goto loser; |
|
551 } |
|
552 break; |
|
553 case NSSCMSRecipientInfoID_KeyAgree: |
|
554 encalg = &(ri->ri.keyAgreeRecipientInfo.keyEncAlg); |
|
555 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.keyAgreeRecipientInfo.keyEncAlg)); |
|
556 enckey = &(ri->ri.keyAgreeRecipientInfo.recipientEncryptedKeys[subIndex]->encKey); |
|
557 switch (encalgtag) { |
|
558 case SEC_OID_X942_DIFFIE_HELMAN_KEY: |
|
559 /* Diffie-Helman key exchange */ |
|
560 /* XXX not yet implemented */ |
|
561 /* XXX problem: SEC_OID_X942_DIFFIE_HELMAN_KEY points to a PKCS3 mechanism! */ |
|
562 /* we support ephemeral-static DH only, so if the recipientinfo */ |
|
563 /* has originator stuff in it, we punt (or do we? shouldn't be that hard...) */ |
|
564 /* first, we derive the KEK (a symkey!) using a Derive operation, then we get the */ |
|
565 /* content encryption key using a Unwrap op */ |
|
566 /* the derive operation has to generate the key using the algorithm in RFC2631 */ |
|
567 error = SEC_ERROR_UNSUPPORTED_KEYALG; |
|
568 goto loser; |
|
569 break; |
|
570 default: |
|
571 error = SEC_ERROR_UNSUPPORTED_KEYALG; |
|
572 goto loser; |
|
573 } |
|
574 break; |
|
575 case NSSCMSRecipientInfoID_KEK: |
|
576 encalg = &(ri->ri.kekRecipientInfo.keyEncAlg); |
|
577 encalgtag = SECOID_GetAlgorithmTag(&(ri->ri.kekRecipientInfo.keyEncAlg)); |
|
578 enckey = &(ri->ri.kekRecipientInfo.encKey); |
|
579 /* not supported yet */ |
|
580 error = SEC_ERROR_UNSUPPORTED_KEYALG; |
|
581 goto loser; |
|
582 break; |
|
583 } |
|
584 /* XXXX continue here */ |
|
585 return bulkkey; |
|
586 |
|
587 loser: |
|
588 PORT_SetError(error); |
|
589 return NULL; |
|
590 } |
|
591 |
|
592 SECStatus NSS_CMSRecipientInfo_GetCertAndKey(NSSCMSRecipientInfo *ri, |
|
593 CERTCertificate** retcert, |
|
594 SECKEYPrivateKey** retkey) |
|
595 { |
|
596 CERTCertificate* cert = NULL; |
|
597 NSSCMSRecipient** recipients = NULL; |
|
598 NSSCMSRecipientInfo* recipientInfos[2]; |
|
599 SECStatus rv = SECSuccess; |
|
600 SECKEYPrivateKey* key = NULL; |
|
601 |
|
602 if (!ri) |
|
603 return SECFailure; |
|
604 |
|
605 if (!retcert && !retkey) { |
|
606 /* nothing requested, nothing found, success */ |
|
607 return SECSuccess; |
|
608 } |
|
609 |
|
610 if (retcert) { |
|
611 *retcert = NULL; |
|
612 } |
|
613 if (retkey) { |
|
614 *retkey = NULL; |
|
615 } |
|
616 |
|
617 if (ri->cert) { |
|
618 cert = CERT_DupCertificate(ri->cert); |
|
619 if (!cert) { |
|
620 rv = SECFailure; |
|
621 } |
|
622 } |
|
623 if (SECSuccess == rv && !cert) { |
|
624 /* we don't have the cert, we have to look for it */ |
|
625 /* first build an NSS_CMSRecipient */ |
|
626 recipientInfos[0] = ri; |
|
627 recipientInfos[1] = NULL; |
|
628 |
|
629 recipients = nss_cms_recipient_list_create(recipientInfos); |
|
630 if (recipients) { |
|
631 /* now look for the cert and key */ |
|
632 if (0 == PK11_FindCertAndKeyByRecipientListNew(recipients, |
|
633 ri->cmsg->pwfn_arg)) { |
|
634 cert = CERT_DupCertificate(recipients[0]->cert); |
|
635 key = SECKEY_CopyPrivateKey(recipients[0]->privkey); |
|
636 } else { |
|
637 rv = SECFailure; |
|
638 } |
|
639 |
|
640 nss_cms_recipient_list_destroy(recipients); |
|
641 } |
|
642 else { |
|
643 rv = SECFailure; |
|
644 } |
|
645 } else if (SECSuccess == rv && cert && retkey) { |
|
646 /* we have the cert, we just need the key now */ |
|
647 key = PK11_FindPrivateKeyFromCert(cert->slot, cert, ri->cmsg->pwfn_arg); |
|
648 } |
|
649 if (retcert) { |
|
650 *retcert = cert; |
|
651 } else { |
|
652 if (cert) { |
|
653 CERT_DestroyCertificate(cert); |
|
654 } |
|
655 } |
|
656 if (retkey) { |
|
657 *retkey = key; |
|
658 } else { |
|
659 if (key) { |
|
660 SECKEY_DestroyPrivateKey(key); |
|
661 } |
|
662 } |
|
663 |
|
664 return rv; |
|
665 } |
|
666 |
|
667 SECStatus NSS_CMSRecipientInfo_Encode(PLArenaPool* poolp, |
|
668 const NSSCMSRecipientInfo *src, |
|
669 SECItem* returned) |
|
670 { |
|
671 extern const SEC_ASN1Template NSSCMSRecipientInfoTemplate[]; |
|
672 SECStatus rv = SECFailure; |
|
673 if (!src || !returned) { |
|
674 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
675 } else if (SEC_ASN1EncodeItem(poolp, returned, src, |
|
676 NSSCMSRecipientInfoTemplate)) { |
|
677 rv = SECSuccess; |
|
678 } |
|
679 return rv; |
|
680 } |