Bug Summary

File:s/lib/pkcs12/p12e.c
Warning:line 1829, column 9
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name p12e.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/pkcs12 -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/var/lib/jenkins/workspace/nss-scan-build/nss/lib/pkcs12 -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/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-05-18-082241-28900-1 -x c p12e.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#include "p12t.h"
6#include "p12.h"
7#include "plarena.h"
8#include "secitem.h"
9#include "secoid.h"
10#include "seccomon.h"
11#include "secport.h"
12#include "cert.h"
13#include "secpkcs5.h"
14#include "secpkcs7.h"
15#include "secasn1.h"
16#include "secerr.h"
17#include "sechash.h"
18#include "pk11func.h"
19#include "p12plcy.h"
20#include "p12local.h"
21#include "prcpucfg.h"
22
23extern const int NSS_PBE_DEFAULT_ITERATION_COUNT; /* defined in p7create.c */
24
25/*
26** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
27** contexts. It can be difficult to keep straight. Here's a picture:
28**
29** "outer" ASN.1 encoder. The output goes to the library caller's CB.
30** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
31** "middle" ASN1 encoder. Encodes the encrypted aSafes.
32** Feeds the "middle" P7 encoder above.
33** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
34** Feeds the "middle" ASN.1 encoder above.
35** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
36** Feeds the "inner" P7 enocder above.
37**
38** Buffering has been added at each point where the output of an ASN.1
39** encoder feeds the input of a PKCS7 encoder.
40*/
41
42/*********************************
43 * Output buffer object, used to buffer output from ASN.1 encoder
44 * before passing data on down to the next PKCS7 encoder.
45 *********************************/
46
47#define PK12_OUTPUT_BUFFER_SIZE8192 8192
48
49struct sec_pkcs12OutputBufferStr {
50 SEC_PKCS7EncoderContext *p7eCx;
51 PK11Context *hmacCx;
52 unsigned int numBytes;
53 unsigned int bufBytes;
54 char buf[PK12_OUTPUT_BUFFER_SIZE8192];
55};
56typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer;
57
58/*********************************
59 * Structures used in exporting the PKCS 12 blob
60 *********************************/
61
62/* A SafeInfo is used for each ContentInfo which makes up the
63 * sequence of safes in the AuthenticatedSafe portion of the
64 * PFX structure.
65 */
66struct SEC_PKCS12SafeInfoStr {
67 PLArenaPool *arena;
68
69 /* information for setting up password encryption */
70 SECItem pwitem;
71 SECOidTag algorithm;
72 PK11SymKey *encryptionKey;
73
74 /* how many items have been stored in this safe,
75 * we will skip any safe which does not contain any
76 * items
77 */
78 unsigned int itemCount;
79
80 /* the content info for the safe */
81 SEC_PKCS7ContentInfo *cinfo;
82
83 sec_PKCS12SafeContents *safe;
84};
85
86/* An opaque structure which contains information needed for exporting
87 * certificates and keys through PKCS 12.
88 */
89struct SEC_PKCS12ExportContextStr {
90 PLArenaPool *arena;
91 PK11SlotInfo *slot;
92 void *wincx;
93
94 /* integrity information */
95 PRBool integrityEnabled;
96 PRBool pwdIntegrity;
97 union {
98 struct sec_PKCS12PasswordModeInfo pwdInfo;
99 struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
100 } integrityInfo;
101
102 /* helper functions */
103 /* retrieve the password call back */
104 SECKEYGetPasswordKey pwfn;
105 void *pwfnarg;
106
107 /* safe contents bags */
108 SEC_PKCS12SafeInfo **safeInfos;
109 unsigned int safeInfoCount;
110
111 /* the sequence of safes */
112 sec_PKCS12AuthenticatedSafe authSafe;
113
114 /* information needing deletion */
115 CERTCertificate **certList;
116};
117
118/* structures for passing information to encoder callbacks when processing
119 * data through the ASN1 engine.
120 */
121struct sec_pkcs12_encoder_output {
122 SEC_PKCS12EncoderOutputCallback outputfn;
123 void *outputarg;
124};
125
126struct sec_pkcs12_hmac_and_output_info {
127 void *arg;
128 struct sec_pkcs12_encoder_output output;
129};
130
131/* An encoder context which is used for the actual encoding
132 * portion of PKCS 12.
133 */
134typedef struct sec_PKCS12EncoderContextStr {
135 PLArenaPool *arena;
136 SEC_PKCS12ExportContext *p12exp;
137
138 /* encoder information - this is set up based on whether
139 * password based or public key pased privacy is being used
140 */
141 SEC_ASN1EncoderContext *outerA1ecx;
142 union {
143 struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
144 struct sec_pkcs12_encoder_output encOutput;
145 } output;
146
147 /* structures for encoding of PFX and MAC */
148 sec_PKCS12PFXItem pfx;
149 sec_PKCS12MacData mac;
150
151 /* authenticated safe encoding tracking information */
152 SEC_PKCS7ContentInfo *aSafeCinfo;
153 SEC_PKCS7EncoderContext *middleP7ecx;
154 SEC_ASN1EncoderContext *middleA1ecx;
155 unsigned int currentSafe;
156
157 /* hmac context */
158 PK11Context *hmacCx;
159
160 /* output buffers */
161 sec_pkcs12OutputBuffer middleBuf;
162 sec_pkcs12OutputBuffer innerBuf;
163
164} sec_PKCS12EncoderContext;
165
166/*********************************
167 * Export setup routines
168 *********************************/
169
170/* SEC_PKCS12CreateExportContext
171 * Creates an export context and sets the unicode and password retrieval
172 * callbacks. This is the first call which must be made when exporting
173 * a PKCS 12 blob.
174 *
175 * pwfn, pwfnarg - password retrieval callback and argument. these are
176 * required for password-authentication mode.
177 */
178SEC_PKCS12ExportContext *
179SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,
180 PK11SlotInfo *slot, void *wincx)
181{
182 PLArenaPool *arena = NULL((void*)0);
183 SEC_PKCS12ExportContext *p12ctxt = NULL((void*)0);
184
185 /* allocate the arena and create the context */
186 arena = PORT_NewArenaPORT_NewArena_Util(4096);
187 if (!arena) {
188 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
189 return NULL((void*)0);
190 }
191
192 p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena,
193 sizeof(SEC_PKCS12ExportContext));
194 if (!p12ctxt) {
195 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
196 goto loser;
197 }
198
199 /* password callback for key retrieval */
200 p12ctxt->pwfn = pwfn;
201 p12ctxt->pwfnarg = pwfnarg;
202
203 p12ctxt->integrityEnabled = PR_FALSE0;
204 p12ctxt->arena = arena;
205 p12ctxt->wincx = wincx;
206 p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
207
208 return p12ctxt;
209
210loser:
211 if (arena) {
212 PORT_FreeArenaPORT_FreeArena_Util(arena, PR_TRUE1);
213 }
214
215 return NULL((void*)0);
216}
217
218/*
219 * Adding integrity mode
220 */
221
222/* SEC_PKCS12AddPasswordIntegrity
223 * Add password integrity to the exported data. If an integrity method
224 * has already been set, then return an error.
225 *
226 * p12ctxt - the export context
227 * pwitem - the password for integrity mode
228 * integAlg - the integrity algorithm to use for authentication.
229 */
230SECStatus
231SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
232 SECItem *pwitem, SECOidTag integAlg)
233{
234 if (!p12ctxt || p12ctxt->integrityEnabled) {
235 return SECFailure;
236 }
237
238 /* set up integrity information */
239 p12ctxt->pwdIntegrity = PR_TRUE1;
240 p12ctxt->integrityInfo.pwdInfo.password =
241 (SECItem *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena, sizeof(SECItem));
242 if (!p12ctxt->integrityInfo.pwdInfo.password) {
243 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
244 return SECFailure;
245 }
246 if (SECITEM_CopyItemSECITEM_CopyItem_Util(p12ctxt->arena,
247 p12ctxt->integrityInfo.pwdInfo.password, pwitem) != SECSuccess) {
248 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
249 return SECFailure;
250 }
251 p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
252 p12ctxt->integrityEnabled = PR_TRUE1;
253
254 return SECSuccess;
255}
256
257/* SEC_PKCS12AddPublicKeyIntegrity
258 * Add public key integrity to the exported data. If an integrity method
259 * has already been set, then return an error. The certificate must be
260 * allowed to be used as a signing cert.
261 *
262 * p12ctxt - the export context
263 * cert - signer certificate
264 * certDb - the certificate database
265 * algorithm - signing algorithm
266 * keySize - size of the signing key (?)
267 */
268SECStatus
269SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
270 CERTCertificate *cert, CERTCertDBHandle *certDb,
271 SECOidTag algorithm, int keySize)
272{
273 if (!p12ctxt) {
274 return SECFailure;
275 }
276
277 p12ctxt->integrityInfo.pubkeyInfo.cert = cert;
278 p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;
279 p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;
280 p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;
281 p12ctxt->integrityEnabled = PR_TRUE1;
282
283 return SECSuccess;
284}
285
286/*
287 * Adding safes - encrypted (password/public key) or unencrypted
288 * Each of the safe creation routines return an opaque pointer which
289 * are later passed into the routines for exporting certificates and
290 * keys.
291 */
292
293/* append the newly created safeInfo to list of safeInfos in the export
294 * context.
295 */
296static SECStatus
297sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
298{
299 void *mark = NULL((void*)0), *dummy1 = NULL((void*)0), *dummy2 = NULL((void*)0);
300
301 if (!p12ctxt || !info) {
302 return SECFailure;
303 }
304
305 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
306
307 /* if no safeInfos have been set, create the list, otherwise expand it. */
308 if (!p12ctxt->safeInfoCount) {
309 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
310 2 * sizeof(SEC_PKCS12SafeInfo *));
311 dummy1 = p12ctxt->safeInfos;
312 p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
313 2 * sizeof(SECItem *));
314 dummy2 = p12ctxt->authSafe.encodedSafes;
315 } else {
316 dummy1 = PORT_ArenaGrowPORT_ArenaGrow_Util(p12ctxt->arena, p12ctxt->safeInfos,
317 (p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),
318 (p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
319 p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
320 dummy2 = PORT_ArenaGrowPORT_ArenaGrow_Util(p12ctxt->arena, p12ctxt->authSafe.encodedSafes,
321 (p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
322 (p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
323 p12ctxt->authSafe.encodedSafes = (SECItem **)dummy2;
324 }
325 if (!dummy1 || !dummy2) {
326 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
327 goto loser;
328 }
329
330 /* append the new safeInfo and null terminate the list */
331 p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;
332 p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL((void*)0);
333 p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =
334 (SECItem *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena, sizeof(SECItem));
335 if (!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {
336 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
337 goto loser;
338 }
339 p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL((void*)0);
340
341 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
342 return SECSuccess;
343
344loser:
345 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
346 return SECFailure;
347}
348
349/* SEC_PKCS12CreatePasswordPrivSafe
350 * Create a password privacy safe to store exported information in.
351 *
352 * p12ctxt - export context
353 * pwitem - password for encryption
354 * privAlg - pbe algorithm through which encryption is done.
355 */
356SEC_PKCS12SafeInfo *
357SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
358 SECItem *pwitem, SECOidTag privAlg)
359{
360 SEC_PKCS12SafeInfo *safeInfo = NULL((void*)0);
361 void *mark = NULL((void*)0);
362 PK11SlotInfo *slot = NULL((void*)0);
363 SECAlgorithmID *algId;
364 SECItem uniPwitem = { siBuffer, NULL((void*)0), 0 };
365
366 if (!p12ctxt) {
367 return NULL((void*)0);
368 }
369
370 /* allocate the safe info */
371 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
372 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
373 sizeof(SEC_PKCS12SafeInfo));
374 if (!safeInfo) {
375 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
376 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
377 return NULL((void*)0);
378 }
379
380 safeInfo->itemCount = 0;
381
382 /* create the encrypted safe */
383 if (!SEC_PKCS5IsAlgorithmPBEAlgTag(privAlg)) {
384 SECOidTag prfAlg = SEC_OID_UNKNOWN;
385 /* if we have password integrity set, use that to set the integrity
386 * hash algorithm to set our password PRF. If we haven't set it, just
387 * let the low level code pick it */
388 if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) {
389 prfAlg = HASH_GetHMACOidTagByHashOidTag(
390 p12ctxt->integrityInfo.pwdInfo.algorithm);
391 }
392 safeInfo->cinfo = SEC_PKCS7CreateEncryptedDataWithPBEV2(SEC_OID_PKCS5_PBES2,
393 privAlg,
394 prfAlg,
395 0,
396 p12ctxt->pwfn,
397 p12ctxt->pwfnarg);
398 } else {
399 safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
400 p12ctxt->pwfnarg);
401 }
402 if (!safeInfo->cinfo) {
403 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
404 goto loser;
405 }
406 safeInfo->arena = p12ctxt->arena;
407
408 if (!sec_pkcs12_encode_password(NULL((void*)0), &uniPwitem, privAlg, pwitem)) {
409 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
410 goto loser;
411 }
412 if (SECITEM_CopyItemSECITEM_CopyItem_Util(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
413 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
414 goto loser;
415 }
416
417 /* generate the encryption key */
418 slot = PK11_ReferenceSlot(p12ctxt->slot);
419 if (!slot) {
420 slot = PK11_GetInternalKeySlot();
421 if (!slot) {
422 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
423 goto loser;
424 }
425 }
426
427 algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
428 safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
429 PR_FALSE0, p12ctxt->wincx);
430 if (!safeInfo->encryptionKey) {
431 goto loser;
432 }
433
434 safeInfo->arena = p12ctxt->arena;
435 safeInfo->safe = NULL((void*)0);
436 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
437 goto loser;
438 }
439
440 if (uniPwitem.data) {
441 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&uniPwitem, PR_FALSE0);
442 }
443 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
444
445 if (slot) {
446 PK11_FreeSlot(slot);
447 }
448 return safeInfo;
449
450loser:
451 if (slot) {
452 PK11_FreeSlot(slot);
453 }
454 if (safeInfo->cinfo) {
455 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
456 }
457
458 if (uniPwitem.data) {
459 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&uniPwitem, PR_FALSE0);
460 }
461
462 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
463 return NULL((void*)0);
464}
465
466/* SEC_PKCS12CreateUnencryptedSafe
467 * Creates an unencrypted safe within the export context.
468 *
469 * p12ctxt - the export context
470 */
471SEC_PKCS12SafeInfo *
472SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
473{
474 SEC_PKCS12SafeInfo *safeInfo = NULL((void*)0);
475 void *mark = NULL((void*)0);
476
477 if (!p12ctxt) {
478 return NULL((void*)0);
479 }
480
481 /* create the safe info */
482 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
483 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
484 sizeof(SEC_PKCS12SafeInfo));
485 if (!safeInfo) {
486 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
487 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
488 return NULL((void*)0);
489 }
490
491 safeInfo->itemCount = 0;
492
493 /* create the safe content */
494 safeInfo->cinfo = SEC_PKCS7CreateData();
495 if (!safeInfo->cinfo) {
496 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
497 goto loser;
498 }
499
500 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
501 goto loser;
502 }
503
504 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
505 return safeInfo;
506
507loser:
508 if (safeInfo->cinfo) {
509 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
510 }
511
512 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
513 return NULL((void*)0);
514}
515
516/* SEC_PKCS12CreatePubKeyEncryptedSafe
517 * Creates a safe which is protected by public key encryption.
518 *
519 * p12ctxt - the export context
520 * certDb - the certificate database
521 * signer - the signer's certificate
522 * recipients - the list of recipient certificates.
523 * algorithm - the encryption algorithm to use
524 * keysize - the algorithms key size (?)
525 */
526SEC_PKCS12SafeInfo *
527SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,
528 CERTCertDBHandle *certDb,
529 CERTCertificate *signer,
530 CERTCertificate **recipients,
531 SECOidTag algorithm, int keysize)
532{
533 SEC_PKCS12SafeInfo *safeInfo = NULL((void*)0);
534 void *mark = NULL((void*)0);
535
536 if (!p12ctxt || !signer || !recipients || !(*recipients)) {
537 return NULL((void*)0);
538 }
539
540 /* allocate the safeInfo */
541 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
542 safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
543 sizeof(SEC_PKCS12SafeInfo));
544 if (!safeInfo) {
545 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
546 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
547 return NULL((void*)0);
548 }
549
550 safeInfo->itemCount = 0;
551 safeInfo->arena = p12ctxt->arena;
552
553 /* create the enveloped content info using certUsageEmailSigner currently.
554 * XXX We need to eventually use something other than certUsageEmailSigner
555 */
556 safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,
557 certDb, algorithm, keysize,
558 p12ctxt->pwfn, p12ctxt->pwfnarg);
559 if (!safeInfo->cinfo) {
560 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
561 goto loser;
562 }
563
564 /* add recipients */
565 if (recipients) {
566 unsigned int i = 0;
567 while (recipients[i] != NULL((void*)0)) {
568 SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
569 certUsageEmailRecipient, certDb);
570 if (rv != SECSuccess) {
571 goto loser;
572 }
573 i++;
574 }
575 }
576
577 if (sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
578 goto loser;
579 }
580
581 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
582 return safeInfo;
583
584loser:
585 if (safeInfo->cinfo) {
586 SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
587 safeInfo->cinfo = NULL((void*)0);
588 }
589
590 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
591 return NULL((void*)0);
592}
593
594/*********************************
595 * Routines to handle the exporting of the keys and certificates
596 *********************************/
597
598/* creates a safe contents which safeBags will be appended to */
599sec_PKCS12SafeContents *
600sec_PKCS12CreateSafeContents(PLArenaPool *arena)
601{
602 sec_PKCS12SafeContents *safeContents;
603
604 if (arena == NULL((void*)0)) {
605 return NULL((void*)0);
606 }
607
608 /* create the safe contents */
609 safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena,
610 sizeof(sec_PKCS12SafeContents));
611 if (!safeContents) {
612 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
613 goto loser;
614 }
615
616 /* set up the internal contents info */
617 safeContents->safeBags = NULL((void*)0);
618 safeContents->arena = arena;
619 safeContents->bagCount = 0;
620
621 return safeContents;
622
623loser:
624 return NULL((void*)0);
625}
626
627/* appends a safe bag to a safeContents using the specified arena.
628 */
629SECStatus
630sec_pkcs12_append_bag_to_safe_contents(PLArenaPool *arena,
631 sec_PKCS12SafeContents *safeContents,
632 sec_PKCS12SafeBag *safeBag)
633{
634 void *mark = NULL((void*)0), *dummy = NULL((void*)0);
635
636 if (!arena || !safeBag || !safeContents) {
637 return SECFailure;
638 }
639
640 mark = PORT_ArenaMarkPORT_ArenaMark_Util(arena);
641 if (!mark) {
642 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
643 return SECFailure;
644 }
645
646 /* allocate space for the list, or reallocate to increase space */
647 if (!safeContents->safeBags) {
648 safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena,
649 (2 * sizeof(sec_PKCS12SafeBag *)));
650 dummy = safeContents->safeBags;
651 safeContents->bagCount = 0;
652 } else {
653 dummy = PORT_ArenaGrowPORT_ArenaGrow_Util(arena, safeContents->safeBags,
654 (safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *),
655 (safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *));
656 safeContents->safeBags = (sec_PKCS12SafeBag **)dummy;
657 }
658
659 if (!dummy) {
660 PORT_ArenaReleasePORT_ArenaRelease_Util(arena, mark);
661 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
662 return SECFailure;
663 }
664
665 /* append the bag at the end and null terminate the list */
666 safeContents->safeBags[safeContents->bagCount++] = safeBag;
667 safeContents->safeBags[safeContents->bagCount] = NULL((void*)0);
668
669 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(arena, mark);
670
671 return SECSuccess;
672}
673
674/* appends a safeBag to a specific safeInfo.
675 */
676SECStatus
677sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt,
678 SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag)
679{
680 sec_PKCS12SafeContents *dest;
681 SECStatus rv = SECFailure;
682
683 if (!p12ctxt || !safeBag || !safeInfo) {
684 return SECFailure;
685 }
686
687 if (!safeInfo->safe) {
688 safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
689 if (!safeInfo->safe) {
690 return SECFailure;
691 }
692 }
693
694 dest = safeInfo->safe;
695 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
696 if (rv == SECSuccess) {
697 safeInfo->itemCount++;
698 }
699
700 return rv;
701}
702
703/* Creates a safeBag of the specified type, and if bagData is specified,
704 * the contents are set. The contents could be set later by the calling
705 * routine.
706 */
707sec_PKCS12SafeBag *
708sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
709 void *bagData)
710{
711 sec_PKCS12SafeBag *safeBag;
712 void *mark = NULL((void*)0);
713 SECStatus rv = SECSuccess;
714 SECOidData *oidData = NULL((void*)0);
715
716 if (!p12ctxt) {
717 return NULL((void*)0);
718 }
719
720 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
721 if (!mark) {
722 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
723 return NULL((void*)0);
724 }
725
726 safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
727 sizeof(sec_PKCS12SafeBag));
728 if (!safeBag) {
729 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
730 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
731 return NULL((void*)0);
732 }
733
734 /* set the bags content based upon bag type */
735 switch (bagType) {
736 case SEC_OID_PKCS12_V1_KEY_BAG_ID:
737 safeBag->safeBagContent.pkcs8KeyBag =
738 (SECKEYPrivateKeyInfo *)bagData;
739 break;
740 case SEC_OID_PKCS12_V1_CERT_BAG_ID:
741 safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
742 break;
743 case SEC_OID_PKCS12_V1_CRL_BAG_ID:
744 safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
745 break;
746 case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
747 safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
748 break;
749 case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
750 safeBag->safeBagContent.pkcs8ShroudedKeyBag =
751 (SECKEYEncryptedPrivateKeyInfo *)bagData;
752 break;
753 case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
754 safeBag->safeBagContent.safeContents =
755 (sec_PKCS12SafeContents *)bagData;
756 break;
757 default:
758 goto loser;
759 }
760
761 oidData = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(bagType);
762 if (oidData) {
763 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
764 if (rv != SECSuccess) {
765 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
766 goto loser;
767 }
768 } else {
769 goto loser;
770 }
771
772 safeBag->arena = p12ctxt->arena;
773 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
774
775 return safeBag;
776
777loser:
778 if (mark) {
779 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
780 }
781
782 return NULL((void*)0);
783}
784
785/* Creates a new certificate bag and returns a pointer to it. If an error
786 * occurs NULL is returned.
787 */
788sec_PKCS12CertBag *
789sec_PKCS12NewCertBag(PLArenaPool *arena, SECOidTag certType)
790{
791 sec_PKCS12CertBag *certBag = NULL((void*)0);
792 SECOidData *bagType = NULL((void*)0);
793 SECStatus rv;
794 void *mark = NULL((void*)0);
795
796 if (!arena) {
797 return NULL((void*)0);
798 }
799
800 mark = PORT_ArenaMarkPORT_ArenaMark_Util(arena);
801 certBag = (sec_PKCS12CertBag *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena,
802 sizeof(sec_PKCS12CertBag));
803 if (!certBag) {
804 PORT_ArenaReleasePORT_ArenaRelease_Util(arena, mark);
805 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
806 return NULL((void*)0);
807 }
808
809 bagType = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(certType);
810 if (!bagType) {
811 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
812 goto loser;
813 }
814
815 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &certBag->bagID, &bagType->oid);
816 if (rv != SECSuccess) {
817 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
818 goto loser;
819 }
820
821 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(arena, mark);
822 return certBag;
823
824loser:
825 PORT_ArenaReleasePORT_ArenaRelease_Util(arena, mark);
826 return NULL((void*)0);
827}
828
829/* Creates a new CRL bag and returns a pointer to it. If an error
830 * occurs NULL is returned.
831 */
832sec_PKCS12CRLBag *
833sec_PKCS12NewCRLBag(PLArenaPool *arena, SECOidTag crlType)
834{
835 sec_PKCS12CRLBag *crlBag = NULL((void*)0);
836 SECOidData *bagType = NULL((void*)0);
837 SECStatus rv;
838 void *mark = NULL((void*)0);
839
840 if (!arena) {
841 return NULL((void*)0);
842 }
843
844 mark = PORT_ArenaMarkPORT_ArenaMark_Util(arena);
845 crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena,
846 sizeof(sec_PKCS12CRLBag));
847 if (!crlBag) {
848 PORT_ArenaReleasePORT_ArenaRelease_Util(arena, mark);
849 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
850 return NULL((void*)0);
851 }
852
853 bagType = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(crlType);
854 if (!bagType) {
855 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
856 goto loser;
857 }
858
859 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(arena, &crlBag->bagID, &bagType->oid);
860 if (rv != SECSuccess) {
861 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
862 goto loser;
863 }
864
865 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(arena, mark);
866 return crlBag;
867
868loser:
869 PORT_ArenaReleasePORT_ArenaRelease_Util(arena, mark);
870 return NULL((void*)0);
871}
872
873/* sec_PKCS12AddAttributeToBag
874 * adds an attribute to a safeBag. currently, the only attributes supported
875 * are those which are specified within PKCS 12.
876 *
877 * p12ctxt - the export context
878 * safeBag - the safeBag to which attributes are appended
879 * attrType - the attribute type
880 * attrData - the attribute data
881 */
882SECStatus
883sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
884 sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
885 SECItem *attrData)
886{
887 sec_PKCS12Attribute *attribute;
888 void *mark = NULL((void*)0), *dummy = NULL((void*)0);
889 SECOidData *oiddata = NULL((void*)0);
890 SECItem unicodeName = { siBuffer, NULL((void*)0), 0 };
891 void *src = NULL((void*)0);
892 unsigned int nItems = 0;
893 SECStatus rv;
894
895 PORT_Assert(p12ctxt->arena == safeBag->arena)((p12ctxt->arena == safeBag->arena)?((void)0):PR_Assert
("p12ctxt->arena == safeBag->arena","p12e.c",895))
;
896 if (!safeBag || !p12ctxt || p12ctxt->arena != safeBag->arena) {
897 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS);
898 return SECFailure;
899 }
900
901 mark = PORT_ArenaMarkPORT_ArenaMark_Util(safeBag->arena);
902
903 /* allocate the attribute */
904 attribute = (sec_PKCS12Attribute *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(safeBag->arena,
905 sizeof(sec_PKCS12Attribute));
906 if (!attribute) {
907 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
908 goto loser;
909 }
910
911 /* set up the attribute */
912 oiddata = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(attrType);
913 if (!oiddata) {
914 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
915 goto loser;
916 }
917 if (SECITEM_CopyItemSECITEM_CopyItem_Util(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
918 SECSuccess) {
919 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
920 goto loser;
921 }
922
923 nItems = 1;
924 switch (attrType) {
925 case SEC_OID_PKCS9_LOCAL_KEY_ID: {
926 src = attrData;
927 break;
928 }
929 case SEC_OID_PKCS9_FRIENDLY_NAME: {
930 if (!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena,
931 &unicodeName, attrData, PR_FALSE0,
932 PR_FALSE0, PR_TRUE1)) {
933 goto loser;
934 }
935 src = &unicodeName;
936 break;
937 }
938 default:
939 goto loser;
940 }
941
942 /* append the attribute to the attribute value list */
943 attribute->attrValue = (SECItem **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
944 ((nItems + 1) * sizeof(SECItem *)));
945 if (!attribute->attrValue) {
946 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
947 goto loser;
948 }
949
950 /* XXX this will need to be changed if attributes requiring more than
951 * one element are ever used.
952 */
953 attribute->attrValue[0] = (SECItem *)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
954 sizeof(SECItem));
955 if (!attribute->attrValue[0]) {
956 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
957 goto loser;
958 }
959 attribute->attrValue[1] = NULL((void*)0);
960
961 rv = SECITEM_CopyItemSECITEM_CopyItem_Util(p12ctxt->arena, attribute->attrValue[0],
962 (SECItem *)src);
963 if (rv != SECSuccess) {
964 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
965 goto loser;
966 }
967
968 /* append the attribute to the safeBag attributes */
969 if (safeBag->nAttribs) {
970 dummy = PORT_ArenaGrowPORT_ArenaGrow_Util(p12ctxt->arena, safeBag->attribs,
971 ((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)),
972 ((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)));
973 safeBag->attribs = (sec_PKCS12Attribute **)dummy;
974 } else {
975 safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
976 2 * sizeof(sec_PKCS12Attribute *));
977 dummy = safeBag->attribs;
978 }
979 if (!dummy) {
980 goto loser;
981 }
982
983 safeBag->attribs[safeBag->nAttribs] = attribute;
984 safeBag->attribs[++safeBag->nAttribs] = NULL((void*)0);
985
986 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
987 return SECSuccess;
988
989loser:
990 if (mark) {
991 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
992 }
993
994 return SECFailure;
995}
996
997/* SEC_PKCS12AddCert
998 * Adds a certificate to the data being exported.
999 *
1000 * p12ctxt - the export context
1001 * safe - the safeInfo to which the certificate is placed
1002 * nestedDest - if the cert is to be placed within a nested safeContents then,
1003 * this value is to be specified with the destination
1004 * cert - the cert to export
1005 * certDb - the certificate database handle
1006 * keyId - a unique identifier to associate a certificate/key pair
1007 * includeCertChain - PR_TRUE if the certificate chain is to be included.
1008 */
1009SECStatus
1010SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1011 void *nestedDest, CERTCertificate *cert,
1012 CERTCertDBHandle *certDb, SECItem *keyId,
1013 PRBool includeCertChain)
1014{
1015 sec_PKCS12CertBag *certBag;
1016 sec_PKCS12SafeBag *safeBag;
1017 void *mark;
1018 SECStatus rv;
1019 SECItem nick = { siBuffer, NULL((void*)0), 0 };
1020
1021 if (!p12ctxt || !cert) {
1022 return SECFailure;
1023 }
1024 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
1025
1026 /* allocate the cert bag */
1027 certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
1028 SEC_OID_PKCS9_X509_CERT);
1029 if (!certBag) {
1030 goto loser;
1031 }
1032
1033 if (SECITEM_CopyItemSECITEM_CopyItem_Util(p12ctxt->arena, &certBag->value.x509Cert,
1034 &cert->derCert) != SECSuccess) {
1035 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1036 goto loser;
1037 }
1038
1039 /* if the cert chain is to be included, we should only be exporting
1040 * the cert from our internal database.
1041 */
1042 if (includeCertChain) {
1043 CERTCertificateList *certList = CERT_CertChainFromCert(cert,
1044 certUsageSSLClient,
1045 PR_TRUE1);
1046 unsigned int count = 0;
1047 if (!certList) {
1048 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1049 goto loser;
1050 }
1051
1052 /* add cert chain */
1053 for (count = 0; count < (unsigned int)certList->len; count++) {
1054 if (SECITEM_CompareItemSECITEM_CompareItem_Util(&certList->certs[count], &cert->derCert) != SECEqual) {
1055 CERTCertificate *tempCert;
1056
1057 /* decode the certificate */
1058 /* XXX
1059 * This was rather silly. The chain is constructed above
1060 * by finding all of the CERTCertificate's in the database.
1061 * Then the chain is put into a CERTCertificateList, which only
1062 * contains the DER. Finally, the DER was decoded, and the
1063 * decoded cert was sent recursively back to this function.
1064 * Beyond being inefficent, this causes data loss (specifically,
1065 * the nickname). Instead, for 3.4, we'll do a lookup by the
1066 * DER, which should return the cached entry.
1067 */
1068 tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1069 &certList->certs[count]);
1070 if (!tempCert) {
1071 CERT_DestroyCertificateList(certList);
1072 goto loser;
1073 }
1074
1075 /* add the certificate */
1076 if (SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert,
1077 certDb, NULL((void*)0), PR_FALSE0) != SECSuccess) {
1078 CERT_DestroyCertificate(tempCert);
1079 CERT_DestroyCertificateList(certList);
1080 goto loser;
1081 }
1082 CERT_DestroyCertificate(tempCert);
1083 }
1084 }
1085 CERT_DestroyCertificateList(certList);
1086 }
1087
1088 /* if the certificate has a nickname, we will set the friendly name
1089 * to that.
1090 */
1091 if (cert->nickname) {
1092 if (cert->slot && !PK11_IsInternal(cert->slot)) {
1093 /*
1094 * The cert is coming off of an external token,
1095 * let's strip the token name from the nickname
1096 * and only add what comes after the colon as the
1097 * nickname. -javi
1098 */
1099 char *delimit;
1100
1101 delimit = PORT_Strchrstrchr(cert->nickname, ':');
1102 if (delimit == NULL((void*)0)) {
1103 nick.data = (unsigned char *)cert->nickname;
1104 nick.len = PORT_Strlen(cert->nickname)strlen(cert->nickname);
1105 } else {
1106 delimit++;
1107 nick.data = (unsigned char *)PORT_ArenaStrdupPORT_ArenaStrdup_Util(p12ctxt->arena,
1108 delimit);
1109 nick.len = PORT_Strlen(delimit)strlen(delimit);
1110 }
1111 } else {
1112 nick.data = (unsigned char *)cert->nickname;
1113 nick.len = PORT_Strlen(cert->nickname)strlen(cert->nickname);
1114 }
1115 }
1116
1117 safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID,
1118 certBag);
1119 if (!safeBag) {
1120 goto loser;
1121 }
1122
1123 /* add the friendly name and keyId attributes, if necessary */
1124 if (nick.data) {
1125 if (sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
1126 SEC_OID_PKCS9_FRIENDLY_NAME, &nick) != SECSuccess) {
1127 goto loser;
1128 }
1129 }
1130
1131 if (keyId) {
1132 if (sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1133 keyId) != SECSuccess) {
1134 goto loser;
1135 }
1136 }
1137
1138 /* append the cert safeBag */
1139 if (nestedDest) {
1140 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1141 (sec_PKCS12SafeContents *)nestedDest,
1142 safeBag);
1143 } else {
1144 rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
1145 }
1146
1147 if (rv != SECSuccess) {
1148 goto loser;
1149 }
1150
1151 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
1152 return SECSuccess;
1153
1154loser:
1155 if (mark) {
1156 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1157 }
1158
1159 return SECFailure;
1160}
1161
1162/* SEC_PKCS12AddKeyForCert
1163 * Extracts the key associated with a particular certificate and exports
1164 * it.
1165 *
1166 * p12ctxt - the export context
1167 * safe - the safeInfo to place the key in
1168 * nestedDest - the nested safeContents to place a key
1169 * cert - the certificate which the key belongs to
1170 * shroudKey - encrypt the private key for export. This value should
1171 * always be true. lower level code will not allow the export
1172 * of unencrypted private keys.
1173 * algorithm - the algorithm with which to encrypt the private key
1174 * pwitem - the password to encrypt the private key with
1175 * keyId - the keyID attribute
1176 * nickName - the nickname attribute
1177 */
1178SECStatus
1179SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1180 void *nestedDest, CERTCertificate *cert,
1181 PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
1182 SECItem *keyId, SECItem *nickName)
1183{
1184 void *mark;
1185 void *keyItem;
1186 SECOidTag keyType;
1187 SECStatus rv = SECFailure;
1188 SECItem nickname = { siBuffer, NULL((void*)0), 0 }, uniPwitem = { siBuffer, NULL((void*)0), 0 };
1189 sec_PKCS12SafeBag *returnBag;
1190
1191 if (!p12ctxt || !cert || !safe) {
1192 return SECFailure;
1193 }
1194
1195 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
1196
1197 /* retrieve the key based upon the type that it is and
1198 * specify the type of safeBag to store the key in
1199 */
1200 if (!shroudKey) {
1201
1202 /* extract the key unencrypted. this will most likely go away */
1203 SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
1204 p12ctxt->wincx);
1205 if (!pki) {
1206 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1207 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1208 return SECFailure;
1209 }
1210 keyItem = PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
1211 if (!keyItem) {
1212 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1213 goto loser;
1214 }
1215 rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena,
1216 (SECKEYPrivateKeyInfo *)keyItem, pki);
1217 keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID;
1218 SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE1);
1219 } else {
1220
1221 /* extract the key encrypted */
1222 SECKEYEncryptedPrivateKeyInfo *epki = NULL((void*)0);
1223 PK11SlotInfo *slot = NULL((void*)0);
1224 SECOidTag prfAlg = SEC_OID_UNKNOWN;
1225
1226 if (!sec_pkcs12_encode_password(p12ctxt->arena, &uniPwitem, algorithm,
1227 pwitem)) {
1228 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1229 goto loser;
1230 }
1231
1232 /* if we have password integrity set, use that to set the integrity
1233 * hash algorithm to set our password PRF. If we haven't set it, just
1234 * let the low level code pick it */
1235 if (p12ctxt->integrityEnabled && p12ctxt->pwdIntegrity) {
1236 prfAlg = HASH_GetHMACOidTagByHashOidTag(
1237 p12ctxt->integrityInfo.pwdInfo.algorithm);
1238 }
1239
1240 /* we want to make sure to take the key out of the key slot */
1241 if (PK11_IsInternal(p12ctxt->slot)) {
1242 slot = PK11_GetInternalKeySlot();
1243 } else {
1244 slot = PK11_ReferenceSlot(p12ctxt->slot);
1245 }
1246
1247 /* passing algorithm as the pbe will force the PBE code to
1248 * automatically handle the selection between using the algorithm
1249 * as a the pbe algorithm, or using the algorithm as a cipher
1250 * and building a pkcs5 pbe */
1251 epki = PK11_ExportEncryptedPrivateKeyInfoV2(slot, algorithm,
1252 SEC_OID_UNKNOWN, prfAlg,
1253 &uniPwitem, cert,
1254 NSS_PBE_DEFAULT_ITERATION_COUNT,
1255 p12ctxt->wincx);
1256 PK11_FreeSlot(slot);
1257 if (!epki) {
1258 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1259 goto loser;
1260 }
1261
1262 keyItem = PORT_ArenaZAllocPORT_ArenaZAlloc_Util(p12ctxt->arena,
1263 sizeof(SECKEYEncryptedPrivateKeyInfo));
1264 if (!keyItem) {
1265 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1266 goto loser;
1267 }
1268 rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1269 (SECKEYEncryptedPrivateKeyInfo *)keyItem,
1270 epki);
1271 keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1272 SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE1);
1273 }
1274
1275 if (rv != SECSuccess) {
1276 goto loser;
1277 }
1278
1279 /* if no nickname specified, let's see if the certificate has a
1280 * nickname.
1281 */
1282 if (!nickName) {
1283 if (cert->nickname) {
1284 nickname.data = (unsigned char *)cert->nickname;
1285 nickname.len = PORT_Strlen(cert->nickname)strlen(cert->nickname);
1286 nickName = &nickname;
1287 }
1288 }
1289
1290 /* create the safe bag and set any attributes */
1291 returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1292 if (!returnBag) {
1293 rv = SECFailure;
1294 goto loser;
1295 }
1296
1297 if (nickName) {
1298 if (sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1299 SEC_OID_PKCS9_FRIENDLY_NAME, nickName) != SECSuccess) {
1300 goto loser;
1301 }
1302 }
1303
1304 if (keyId) {
1305 if (sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1306 keyId) != SECSuccess) {
1307 goto loser;
1308 }
1309 }
1310
1311 if (nestedDest) {
1312 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1313 (sec_PKCS12SafeContents *)nestedDest,
1314 returnBag);
1315 } else {
1316 rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1317 }
1318
1319loser:
1320
1321 if (rv != SECSuccess) {
1322 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1323 } else {
1324 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
1325 }
1326
1327 return rv;
1328}
1329
1330/* SEC_PKCS12AddCertOrChainAndKey
1331 * Add a certificate and key pair to be exported.
1332 *
1333 * p12ctxt - the export context
1334 * certSafe - the safeInfo where the cert is stored
1335 * certNestedDest - the nested safeContents to store the cert
1336 * keySafe - the safeInfo where the key is stored
1337 * keyNestedDest - the nested safeContents to store the key
1338 * shroudKey - extract the private key encrypted?
1339 * pwitem - the password with which the key is encrypted
1340 * algorithm - the algorithm with which the key is encrypted
1341 * includeCertChain - also add certs from chain to bag.
1342 */
1343SECStatus
1344SEC_PKCS12AddCertOrChainAndKey(SEC_PKCS12ExportContext *p12ctxt,
1345 void *certSafe, void *certNestedDest,
1346 CERTCertificate *cert, CERTCertDBHandle *certDb,
1347 void *keySafe, void *keyNestedDest,
1348 PRBool shroudKey, SECItem *pwitem,
1349 SECOidTag algorithm, PRBool includeCertChain)
1350{
1351 SECStatus rv = SECFailure;
1352 SGNDigestInfo *digest = NULL((void*)0);
1353 void *mark = NULL((void*)0);
1354
1355 if (!p12ctxt || !certSafe || !keySafe || !cert) {
1356 return SECFailure;
1357 }
1358
1359 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
1360
1361 /* generate the thumbprint of the cert to use as a keyId */
1362 digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1363 if (!digest) {
1364 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1365 return SECFailure;
1366 }
1367
1368 /* add the certificate */
1369 rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo *)certSafe,
1370 (SEC_PKCS12SafeInfo *)certNestedDest, cert, certDb,
1371 &digest->digest, includeCertChain);
1372 if (rv != SECSuccess) {
1373 goto loser;
1374 }
1375
1376 /* add the key */
1377 rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo *)keySafe,
1378 keyNestedDest, cert,
1379 shroudKey, algorithm, pwitem,
1380 &digest->digest, NULL((void*)0));
1381 if (rv != SECSuccess) {
1382 goto loser;
1383 }
1384
1385 SGN_DestroyDigestInfoSGN_DestroyDigestInfo_Util(digest);
1386
1387 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
1388 return SECSuccess;
1389
1390loser:
1391 SGN_DestroyDigestInfoSGN_DestroyDigestInfo_Util(digest);
1392 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1393
1394 return SECFailure;
1395}
1396
1397/* like SEC_PKCS12AddCertOrChainAndKey, but always adds cert chain */
1398SECStatus
1399SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt,
1400 void *certSafe, void *certNestedDest,
1401 CERTCertificate *cert, CERTCertDBHandle *certDb,
1402 void *keySafe, void *keyNestedDest,
1403 PRBool shroudKey, SECItem *pwItem, SECOidTag algorithm)
1404{
1405 return SEC_PKCS12AddCertOrChainAndKey(p12ctxt, certSafe, certNestedDest,
1406 cert, certDb, keySafe, keyNestedDest, shroudKey, pwItem,
1407 algorithm, PR_TRUE1);
1408}
1409
1410/* SEC_PKCS12CreateNestedSafeContents
1411 * Allows nesting of safe contents to be implemented. No limit imposed on
1412 * depth.
1413 *
1414 * p12ctxt - the export context
1415 * baseSafe - the base safeInfo
1416 * nestedDest - a parent safeContents (?)
1417 */
1418void *
1419SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
1420 void *baseSafe, void *nestedDest)
1421{
1422 sec_PKCS12SafeContents *newSafe;
1423 sec_PKCS12SafeBag *safeContentsBag;
1424 void *mark;
1425 SECStatus rv;
1426
1427 if (!p12ctxt || !baseSafe) {
1428 return NULL((void*)0);
1429 }
1430
1431 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12ctxt->arena);
1432
1433 newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
1434 if (!newSafe) {
1435 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1436 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1437 return NULL((void*)0);
1438 }
1439
1440 /* create the safeContents safeBag */
1441 safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
1442 SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
1443 newSafe);
1444 if (!safeContentsBag) {
1445 goto loser;
1446 }
1447
1448 /* append the safeContents to the appropriate area */
1449 if (nestedDest) {
1450 rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1451 (sec_PKCS12SafeContents *)nestedDest,
1452 safeContentsBag);
1453 } else {
1454 rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo *)baseSafe,
1455 safeContentsBag);
1456 }
1457 if (rv != SECSuccess) {
1458 goto loser;
1459 }
1460
1461 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12ctxt->arena, mark);
1462 return newSafe;
1463
1464loser:
1465 PORT_ArenaReleasePORT_ArenaRelease_Util(p12ctxt->arena, mark);
1466 return NULL((void*)0);
1467}
1468
1469/*********************************
1470 * Encoding routines
1471 *********************************/
1472
1473/* Clean up the resources allocated by a sec_PKCS12EncoderContext. */
1474static void
1475sec_pkcs12_encoder_destroy_context(sec_PKCS12EncoderContext *p12enc)
1476{
1477 if (p12enc) {
1478 if (p12enc->outerA1ecx) {
1479 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(p12enc->outerA1ecx);
1480 p12enc->outerA1ecx = NULL((void*)0);
1481 }
1482 if (p12enc->aSafeCinfo) {
1483 SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
1484 p12enc->aSafeCinfo = NULL((void*)0);
1485 }
1486 if (p12enc->middleP7ecx) {
1487 SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12enc->p12exp->pwfn,
1488 p12enc->p12exp->pwfnarg);
1489 p12enc->middleP7ecx = NULL((void*)0);
1490 }
1491 if (p12enc->middleA1ecx) {
1492 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(p12enc->middleA1ecx);
1493 p12enc->middleA1ecx = NULL((void*)0);
1494 }
1495 if (p12enc->hmacCx) {
1496 PK11_DestroyContext(p12enc->hmacCx, PR_TRUE1);
1497 p12enc->hmacCx = NULL((void*)0);
1498 }
1499 }
1500}
1501
1502/* set up the encoder context based on information in the export context
1503 * and return the newly allocated enocoder context. A return of NULL
1504 * indicates an error occurred.
1505 */
1506static sec_PKCS12EncoderContext *
1507sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
1508{
1509 sec_PKCS12EncoderContext *p12enc = NULL((void*)0);
1510 unsigned int i, nonEmptyCnt;
1511 SECStatus rv;
1512 SECItem ignore = { 0 };
1513 void *mark;
1514 SECItem *salt = NULL((void*)0);
1515 SECItem *params = NULL((void*)0);
1516
1517 if (!p12exp || !p12exp->safeInfos) {
1518 return NULL((void*)0);
1519 }
1520
1521 /* check for any empty safes and skip them */
1522 i = nonEmptyCnt = 0;
1523 while (p12exp->safeInfos[i]) {
1524 if (p12exp->safeInfos[i]->itemCount) {
1525 nonEmptyCnt++;
1526 }
1527 i++;
1528 }
1529 if (nonEmptyCnt == 0) {
1530 return NULL((void*)0);
1531 }
1532 p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL((void*)0);
1533
1534 /* allocate the encoder context */
1535 mark = PORT_ArenaMarkPORT_ArenaMark_Util(p12exp->arena);
1536 p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext)(sec_PKCS12EncoderContext *)PORT_ArenaZAlloc_Util(p12exp->
arena, sizeof(sec_PKCS12EncoderContext))
;
1537 if (!p12enc) {
1538 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1539 return NULL((void*)0);
1540 }
1541
1542 p12enc->arena = p12exp->arena;
1543 p12enc->p12exp = p12exp;
1544
1545 /* set up the PFX version and information */
1546 PORT_Memsetmemset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem));
1547 if (!SEC_ASN1EncodeIntegerSEC_ASN1EncodeInteger_Util(p12exp->arena, &(p12enc->pfx.version),
1548 SEC_PKCS12_VERSION3)) {
1549 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1550 goto loser;
1551 }
1552
1553 /* set up the authenticated safe content info based on the
1554 * type of integrity being used. this should be changed to
1555 * enforce integrity mode, but will not be implemented until
1556 * it is confirmed that integrity must be in place
1557 */
1558 if (p12exp->integrityEnabled && !p12exp->pwdIntegrity) {
1559 /* create public key integrity mode */
1560 p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData(
1561 p12exp->integrityInfo.pubkeyInfo.cert,
1562 certUsageEmailSigner,
1563 p12exp->integrityInfo.pubkeyInfo.certDb,
1564 p12exp->integrityInfo.pubkeyInfo.algorithm,
1565 NULL((void*)0),
1566 p12exp->pwfn,
1567 p12exp->pwfnarg);
1568 if (!p12enc->aSafeCinfo) {
1569 goto loser;
1570 }
1571 if (SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo, NULL((void*)0)) != SECSuccess) {
1572 goto loser;
1573 }
1574 PORT_CheckSuccess(SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo))(((SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo)) == SECSuccess
)?((void)0):PR_Assert("(SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo)) == SECSuccess"
,"p12e.c",1574))
;
1575 } else {
1576 p12enc->aSafeCinfo = SEC_PKCS7CreateData();
1577
1578 /* init password pased integrity mode */
1579 if (p12exp->integrityEnabled) {
1580 SECItem pwd = { siBuffer, NULL((void*)0), 0 };
1581 PK11SymKey *symKey;
1582 CK_MECHANISM_TYPE integrityMechType;
1583 CK_MECHANISM_TYPE hmacMechType;
1584 salt = sec_pkcs12_generate_salt();
1585
1586 /* zero out macData and set values */
1587 PORT_Memsetmemset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
1588
1589 if (!salt) {
1590 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1591 goto loser;
1592 }
1593 if (SECITEM_CopyItemSECITEM_CopyItem_Util(p12exp->arena, &(p12enc->mac.macSalt), salt) != SECSuccess) {
1594 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1595 goto loser;
1596 }
1597 if (!SEC_ASN1EncodeIntegerSEC_ASN1EncodeInteger_Util(p12exp->arena, &(p12enc->mac.iter),
1598 NSS_PBE_DEFAULT_ITERATION_COUNT)) {
1599 goto loser;
1600 }
1601
1602 /* generate HMAC key */
1603 if (!sec_pkcs12_convert_item_to_unicode(NULL((void*)0), &pwd,
1604 p12exp->integrityInfo.pwdInfo.password, PR_TRUE1,
1605 PR_TRUE1, PR_TRUE1)) {
1606 goto loser;
1607 }
1608 /*
1609 * This code only works with PKCS #12 Mac using PKCS #5 v1
1610 * PBA keygens. PKCS #5 v2 support will require a change to
1611 * the PKCS #12 spec.
1612 */
1613 params = PK11_CreatePBEParams(salt, &pwd,
1614 NSS_PBE_DEFAULT_ITERATION_COUNT);
1615 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(salt, PR_TRUE1);
1616 salt = NULL((void*)0);
1617 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&pwd, PR_FALSE0);
1618
1619 /* get the PBA Mechanism to generate the key */
1620 integrityMechType = sec_pkcs12_algtag_to_keygen_mech(
1621 p12exp->integrityInfo.pwdInfo.algorithm);
1622 if (integrityMechType == CKM_INVALID_MECHANISM0xffffffffUL) {
1623 goto loser;
1624 }
1625
1626 /* generate the key */
1627 symKey = PK11_KeyGen(NULL((void*)0), integrityMechType, params, 20, NULL((void*)0));
1628 PK11_DestroyPBEParams(params);
1629 if (!symKey) {
1630 goto loser;
1631 }
1632
1633 /* initialize HMAC */
1634 /* Get the HMAC mechanism from the hash OID */
1635 hmacMechType = sec_pkcs12_algtag_to_mech(
1636 p12exp->integrityInfo.pwdInfo.algorithm);
1637
1638 p12enc->hmacCx = PK11_CreateContextBySymKey(hmacMechType,
1639 CKA_SIGN0x00000108UL, symKey, &ignore);
1640
1641 PK11_FreeSymKey(symKey);
1642 if (!p12enc->hmacCx) {
1643 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1644 goto loser;
1645 }
1646 rv = PK11_DigestBegin(p12enc->hmacCx);
1647 if (rv != SECSuccess)
1648 goto loser;
1649 }
1650 }
1651
1652 if (!p12enc->aSafeCinfo) {
1653 goto loser;
1654 }
1655
1656 PORT_ArenaUnmarkPORT_ArenaUnmark_Util(p12exp->arena, mark);
1657
1658 return p12enc;
1659
1660loser:
1661 sec_pkcs12_encoder_destroy_context(p12enc);
1662 if (p12exp->arena != NULL((void*)0))
1663 PORT_ArenaReleasePORT_ArenaRelease_Util(p12exp->arena, mark);
1664 if (salt) {
1665 SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(salt, PR_TRUE1);
1666 }
1667 if (params) {
1668 PK11_DestroyPBEParams(params);
1669 }
1670
1671 return NULL((void*)0);
1672}
1673
1674/* The outermost ASN.1 encoder calls this function for output.
1675** This function calls back to the library caller's output routine,
1676** which typically writes to a PKCS12 file.
1677 */
1678static void
1679sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len,
1680 int depth, SEC_ASN1EncodingPart data_kind)
1681{
1682 struct sec_pkcs12_encoder_output *output;
1683
1684 output = (struct sec_pkcs12_encoder_output *)arg;
1685 (*output->outputfn)(output->outputarg, buf, len);
1686}
1687
1688/* The "middle" and "inner" ASN.1 encoders call this function to output.
1689** This function does HMACing, if appropriate, and then buffers the data.
1690** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1691 */
1692static void
1693sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
1694 unsigned long len,
1695 int depth,
1696 SEC_ASN1EncodingPart data_kind)
1697{
1698 sec_pkcs12OutputBuffer *bufcx = (sec_pkcs12OutputBuffer *)arg;
1699
1700 if (!buf || !len)
1701 return;
1702
1703 if (bufcx->hmacCx) {
1704 PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
1705 }
1706
1707 /* buffer */
1708 if (bufcx->numBytes > 0) {
1709 int toCopy;
1710 if (len + bufcx->numBytes <= bufcx->bufBytes) {
1711 memcpy(bufcx->buf + bufcx->numBytes, buf, len);
1712 bufcx->numBytes += len;
1713 if (bufcx->numBytes < bufcx->bufBytes)
1714 return;
1715 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1716 bufcx->numBytes = 0;
1717 return;
1718 }
1719 toCopy = bufcx->bufBytes - bufcx->numBytes;
1720 memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy);
1721 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1722 bufcx->numBytes = 0;
1723 len -= toCopy;
1724 buf += toCopy;
1725 }
1726 /* buffer is presently empty */
1727 if (len >= bufcx->bufBytes) {
1728 /* Just pass it through */
1729 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
1730 } else {
1731 /* copy it all into the buffer, and return */
1732 memcpy(bufcx->buf, buf, len);
1733 bufcx->numBytes = len;
1734 }
1735}
1736
1737void
1738sec_FlushPkcs12OutputBuffer(sec_pkcs12OutputBuffer *bufcx)
1739{
1740 if (bufcx->numBytes > 0) {
1741 SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
1742 bufcx->numBytes = 0;
1743 }
1744}
1745
1746/* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1747** This function is used by both the inner and middle PCS7 encoders.
1748*/
1749static void
1750sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
1751{
1752 SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext *)arg;
1753
1754 if (!buf || !len)
1755 return;
1756
1757 SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(cx, buf, len);
1758}
1759
1760/* this function encodes content infos which are part of the
1761 * sequence of content infos labeled AuthenticatedSafes
1762 */
1763static SECStatus
1764sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
1765{
1766 SEC_PKCS7EncoderContext *innerP7ecx;
1767 SEC_PKCS7ContentInfo *cinfo;
1768 PK11SymKey *bulkKey = NULL((void*)0);
1769 SEC_ASN1EncoderContext *innerA1ecx = NULL((void*)0);
1770 SECStatus rv = SECSuccess;
1771
1772 if (p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
1773 SEC_PKCS12SafeInfo *safeInfo;
1774 SECOidTag cinfoType;
1775
1776 safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
1777
1778 /* skip empty safes */
1779 if (safeInfo->itemCount == 0) {
1780 return SECSuccess;
1781 }
1782
1783 cinfo = safeInfo->cinfo;
1784 cinfoType = SEC_PKCS7ContentType(cinfo);
1785
1786 /* determine the safe type and set the appropriate argument */
1787 switch (cinfoType) {
1788 case SEC_OID_PKCS7_DATA:
1789 case SEC_OID_PKCS7_ENVELOPED_DATA:
1790 break;
1791 case SEC_OID_PKCS7_ENCRYPTED_DATA:
1792 bulkKey = safeInfo->encryptionKey;
1793 PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL((void*)0));
1794 break;
1795 default:
1796 return SECFailure;
1797 }
1798
1799 /* start the PKCS7 encoder */
1800 innerP7ecx = SEC_PKCS7EncoderStart(cinfo,
1801 sec_P12P7OutputCB_CallA1Update,
1802 p12ecx->middleA1ecx, bulkKey);
1803 if (!innerP7ecx) {
1804 goto loser;
1805 }
1806
1807 /* encode safe contents */
1808 p12ecx->innerBuf.p7eCx = innerP7ecx;
1809 p12ecx->innerBuf.hmacCx = NULL((void*)0);
1810 p12ecx->innerBuf.numBytes = 0;
1811 p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf;
1812
1813 innerA1ecx = SEC_ASN1EncoderStartSEC_ASN1EncoderStart_Util(safeInfo->safe,
1814 sec_PKCS12SafeContentsTemplate,
1815 sec_P12A1OutputCB_HmacP7Update,
1816 &p12ecx->innerBuf);
1817 if (!innerA1ecx) {
1818 goto loser;
1819 }
1820 rv = SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(innerA1ecx, NULL((void*)0), 0);
1821 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(innerA1ecx);
1822 sec_FlushPkcs12OutputBuffer(&p12ecx->innerBuf);
1823 innerA1ecx = NULL((void*)0);
1824 if (rv != SECSuccess) {
1825 goto loser;
1826 }
1827
1828 /* finish up safe content info */
1829 rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
Value stored to 'rv' is never read
1830 p12ecx->p12exp->pwfnarg);
1831 }
1832 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1833 return SECSuccess;
1834
1835loser:
1836 if (innerP7ecx) {
1837 SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1838 p12ecx->p12exp->pwfnarg);
1839 }
1840
1841 if (innerA1ecx) {
1842 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(innerA1ecx);
1843 }
1844 memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1845 return SECFailure;
1846}
1847
1848/* finish the HMAC and encode the macData so that it can be
1849 * encoded.
1850 */
1851static SECStatus
1852sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
1853{
1854 unsigned char hmacData[HASH_LENGTH_MAX64];
1855 unsigned int hmacLen;
1856 SECStatus rv;
1857 SGNDigestInfo *di = NULL((void*)0);
1858 void *dummy;
1859
1860 if (!p12ecx) {
1861 return SECFailure;
1862 }
1863
1864 /* make sure we are using password integrity mode */
1865 if (!p12ecx->p12exp->integrityEnabled) {
1866 return SECSuccess;
1867 }
1868
1869 if (!p12ecx->p12exp->pwdIntegrity) {
1870 return SECSuccess;
1871 }
1872
1873 /* finish the hmac */
1874
1875 rv = PK11_DigestFinal(p12ecx->hmacCx, hmacData, &hmacLen, HASH_LENGTH_MAX64);
1876
1877 if (rv != SECSuccess) {
1878 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1879 goto loser;
1880 }
1881
1882 /* create the digest info */
1883 di = SGN_CreateDigestInfoSGN_CreateDigestInfo_Util(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
1884 hmacData, hmacLen);
1885 if (!di) {
1886 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1887 rv = SECFailure;
1888 goto loser;
1889 }
1890
1891 rv = SGN_CopyDigestInfoSGN_CopyDigestInfo_Util(p12ecx->arena, &p12ecx->mac.safeMac, di);
1892 if (rv != SECSuccess) {
1893 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1894 goto loser;
1895 }
1896
1897 /* encode the mac data */
1898 dummy = SEC_ASN1EncodeItemSEC_ASN1EncodeItem_Util(p12ecx->arena, &p12ecx->pfx.encodedMacData,
1899 &p12ecx->mac, sec_PKCS12MacDataTemplate);
1900 if (!dummy) {
1901 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1902 rv = SECFailure;
1903 }
1904
1905loser:
1906 if (di) {
1907 SGN_DestroyDigestInfoSGN_DestroyDigestInfo_Util(di);
1908 }
1909 PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE1);
1910 p12ecx->hmacCx = NULL((void*)0);
1911 PORT_Memsetmemset(hmacData, 0, hmacLen);
1912
1913 return rv;
1914}
1915
1916/* pfx notify function for ASN1 encoder.
1917 * We want to stop encoding once we reach the authenticated safe.
1918 * At that point, the encoder will be updated via streaming
1919 * as the authenticated safe is encoded.
1920 */
1921static void
1922sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth)
1923{
1924 sec_PKCS12EncoderContext *p12ecx;
1925
1926 if (!before) {
1927 return;
1928 }
1929
1930 /* look for authenticated safe */
1931 p12ecx = (sec_PKCS12EncoderContext *)arg;
1932 if (dest != &p12ecx->pfx.encodedAuthSafe) {
1933 return;
1934 }
1935
1936 SEC_ASN1EncoderSetTakeFromBufSEC_ASN1EncoderSetTakeFromBuf_Util(p12ecx->outerA1ecx);
1937 SEC_ASN1EncoderSetStreamingSEC_ASN1EncoderSetStreaming_Util(p12ecx->outerA1ecx);
1938 SEC_ASN1EncoderClearNotifyProcSEC_ASN1EncoderClearNotifyProc_Util(p12ecx->outerA1ecx);
1939}
1940
1941/* SEC_PKCS12Encode
1942 * Encodes the PFX item and returns it to the output function, via
1943 * callback. the output function must be capable of multiple updates.
1944 *
1945 * p12exp - the export context
1946 * output - the output function callback, will be called more than once,
1947 * must be able to accept streaming data.
1948 * outputarg - argument for the output callback.
1949 */
1950SECStatus
1951SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp,
1952 SEC_PKCS12EncoderOutputCallback output, void *outputarg)
1953{
1954 sec_PKCS12EncoderContext *p12enc;
1955 struct sec_pkcs12_encoder_output outInfo;
1956 SECStatus rv;
1957
1958 if (!p12exp || !output) {
1959 return SECFailure;
1960 }
1961
1962 /* get the encoder context */
1963 p12enc = sec_pkcs12_encoder_start_context(p12exp);
1964 if (!p12enc) {
1965 return SECFailure;
1966 }
1967
1968 outInfo.outputfn = output;
1969 outInfo.outputarg = outputarg;
1970
1971 /* set up PFX encoder, the "outer" encoder. Set it for streaming */
1972 p12enc->outerA1ecx = SEC_ASN1EncoderStartSEC_ASN1EncoderStart_Util(&p12enc->pfx,
1973 sec_PKCS12PFXItemTemplate,
1974 sec_P12A1OutputCB_Outer,
1975 &outInfo);
1976 if (!p12enc->outerA1ecx) {
1977 PORT_SetErrorPORT_SetError_Util(SEC_ERROR_NO_MEMORY);
1978 rv = SECFailure;
1979 goto loser;
1980 }
1981 SEC_ASN1EncoderSetStreamingSEC_ASN1EncoderSetStreaming_Util(p12enc->outerA1ecx);
1982 SEC_ASN1EncoderSetNotifyProcSEC_ASN1EncoderSetNotifyProc_Util(p12enc->outerA1ecx,
1983 sec_pkcs12_encoder_pfx_notify, p12enc);
1984 rv = SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(p12enc->outerA1ecx, NULL((void*)0), 0);
1985 if (rv != SECSuccess) {
1986 rv = SECFailure;
1987 goto loser;
1988 }
1989
1990 /* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
1991 p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo,
1992 sec_P12P7OutputCB_CallA1Update,
1993 p12enc->outerA1ecx, NULL((void*)0));
1994 if (!p12enc->middleP7ecx) {
1995 rv = SECFailure;
1996 goto loser;
1997 }
1998
1999 /* encode asafe */
2000 p12enc->middleBuf.p7eCx = p12enc->middleP7ecx;
2001 p12enc->middleBuf.hmacCx = NULL((void*)0);
2002 p12enc->middleBuf.numBytes = 0;
2003 p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf;
2004
2005 /* Setup the "inner ASN.1 encoder for Authenticated Safes. */
2006 if (p12enc->p12exp->integrityEnabled &&
2007 p12enc->p12exp->pwdIntegrity) {
2008 p12enc->middleBuf.hmacCx = p12enc->hmacCx;
2009 }
2010 p12enc->middleA1ecx = SEC_ASN1EncoderStartSEC_ASN1EncoderStart_Util(&p12enc->p12exp->authSafe,
2011 sec_PKCS12AuthenticatedSafeTemplate,
2012 sec_P12A1OutputCB_HmacP7Update,
2013 &p12enc->middleBuf);
2014 if (!p12enc->middleA1ecx) {
2015 rv = SECFailure;
2016 goto loser;
2017 }
2018 SEC_ASN1EncoderSetStreamingSEC_ASN1EncoderSetStreaming_Util(p12enc->middleA1ecx);
2019 SEC_ASN1EncoderSetTakeFromBufSEC_ASN1EncoderSetTakeFromBuf_Util(p12enc->middleA1ecx);
2020
2021 /* encode each of the safes */
2022 while (p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {
2023 sec_pkcs12_encoder_asafe_process(p12enc);
2024 p12enc->currentSafe++;
2025 }
2026 SEC_ASN1EncoderClearTakeFromBufSEC_ASN1EncoderClearTakeFromBuf_Util(p12enc->middleA1ecx);
2027 SEC_ASN1EncoderClearStreamingSEC_ASN1EncoderClearStreaming_Util(p12enc->middleA1ecx);
2028 SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(p12enc->middleA1ecx, NULL((void*)0), 0);
2029 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(p12enc->middleA1ecx);
2030 p12enc->middleA1ecx = NULL((void*)0);
2031
2032 sec_FlushPkcs12OutputBuffer(&p12enc->middleBuf);
2033
2034 /* finish the encoding of the authenticated safes */
2035 rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn,
2036 p12exp->pwfnarg);
2037 p12enc->middleP7ecx = NULL((void*)0);
2038 if (rv != SECSuccess) {
2039 goto loser;
2040 }
2041
2042 SEC_ASN1EncoderClearTakeFromBufSEC_ASN1EncoderClearTakeFromBuf_Util(p12enc->outerA1ecx);
2043 SEC_ASN1EncoderClearStreamingSEC_ASN1EncoderClearStreaming_Util(p12enc->outerA1ecx);
2044
2045 /* update the mac, if necessary */
2046 rv = sec_Pkcs12FinishMac(p12enc);
2047 if (rv != SECSuccess) {
2048 goto loser;
2049 }
2050
2051 /* finish encoding the pfx */
2052 rv = SEC_ASN1EncoderUpdateSEC_ASN1EncoderUpdate_Util(p12enc->outerA1ecx, NULL((void*)0), 0);
2053
2054 SEC_ASN1EncoderFinishSEC_ASN1EncoderFinish_Util(p12enc->outerA1ecx);
2055 p12enc->outerA1ecx = NULL((void*)0);
2056
2057loser:
2058 sec_pkcs12_encoder_destroy_context(p12enc);
2059 return rv;
2060}
2061
2062void
2063SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
2064{
2065 int i = 0;
2066
2067 if (!p12ecx) {
2068 return;
2069 }
2070
2071 if (p12ecx->safeInfos) {
2072 i = 0;
2073 while (p12ecx->safeInfos[i] != NULL((void*)0)) {
2074 if (p12ecx->safeInfos[i]->encryptionKey) {
2075 PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey);
2076 }
2077 if (p12ecx->safeInfos[i]->cinfo) {
2078 SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);
2079 }
2080 i++;
2081 }
2082 }
2083
2084 PK11_FreeSlot(p12ecx->slot);
2085
2086 PORT_FreeArenaPORT_FreeArena_Util(p12ecx->arena, PR_TRUE1);
2087}