Bug Summary

File:s/lib/smime/cmsrecinfo.c
Warning:line 635, column 13
Value stored to 'enckey' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name cmsrecinfo.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/smime -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/smime -resource-dir /usr/lib/llvm-18/lib/clang/18 -D HAVE_STRERROR -D LINUX -D linux -D XP_UNIX -D XP_UNIX -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D DEBUG -U NDEBUG -D _DEFAULT_SOURCE -D _BSD_SOURCE -D _POSIX_SOURCE -D SDB_MEASURE_USE_TEMP_DIR -D _REENTRANT -D NSS_DISABLE_SSE3 -D NSS_NO_INIT_SUPPORT -D USE_UTIL_DIRECTLY -D NO_NSPR_10_SUPPORT -D SSL_DISABLE_DEPRECATED_CIPHER_SUITE_NAMES -I ../../../dist/Linux4.19_x86_64_gcc_glibc_PTH_64_DBG.OBJ/include -I ../../../dist/public/nss -I ../../../dist/private/nss -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-04-23-111009-16947-1 -x c cmsrecinfo.c
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
19PRBool
20nss_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 */
40static const SECOidData fakeContent;
41NSSCMSRecipientInfo *
42nss_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
239done:
240 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(poolp, mark);
241 if (freeSpki)
242 SECKEY_DestroySubjectPublicKeyInfo(freeSpki);
243 return ri;
244
245loser:
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 */
266PRBool
267NSS_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 */
289NSSCMSRecipientInfo *
290NSS_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
296NSSCMSRecipientInfo *
297NSS_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
303NSSCMSRecipientInfo *
304NSS_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
310NSSCMSRecipientInfo *
311NSS_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
319NSSCMSRecipientInfo *
320NSS_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);
339done:
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
349void
350NSS_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
373int
374NSS_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
404SECItem *
405NSS_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
425SECOidTag
426NSS_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
444SECStatus
445NSS_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
563PK11SymKey *
564NSS_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));
635 enckey = &(ri->ri.kekRecipientInfo.encKey);
Value stored to 'enckey' is never read
636 /* not supported yet */
637 error = SEC_ERROR_UNSUPPORTED_KEYALG;
638 goto loser;
639 break;
640 }
641 /* XXXX continue here */
642 return bulkkey;
643
644loser:
645 PORT_SetErrorPORT_SetError_Util(error);
646 return NULL((void*)0);
647}
648
649SECStatus
650NSS_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
724SECStatus
725NSS_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}