Coverage Report

Created: 2018-09-25 14:53

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