1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 1994-2000
19
* the Initial Developer. All Rights Reserved.
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
35
* ***** END LICENSE BLOCK ***** */
55
** This PKCS12 file encoder uses numerous nested ASN.1 and PKCS7 encoder
56
** contexts. It can be difficult to keep straight. Here's a picture:
58
** "outer" ASN.1 encoder. The output goes to the library caller's CB.
59
** "middle" PKCS7 encoder. Feeds the "outer" ASN.1 encoder.
60
** "middle" ASN1 encoder. Encodes the encrypted aSafes.
61
** Feeds the "middle" P7 encoder above.
62
** "inner" PKCS7 encoder. Encrypts the "authenticated Safes" (aSafes)
63
** Feeds the "middle" ASN.1 encoder above.
64
** "inner" ASN.1 encoder. Encodes the unencrypted aSafes.
65
** Feeds the "inner" P7 enocder above.
67
** Buffering has been added at each point where the output of an ASN.1
68
** encoder feeds the input of a PKCS7 encoder.
71
/*********************************
72
* Output buffer object, used to buffer output from ASN.1 encoder
73
* before passing data on down to the next PKCS7 encoder.
74
*********************************/
76
#define PK12_OUTPUT_BUFFER_SIZE 8192
78
struct sec_pkcs12OutputBufferStr {
79
SEC_PKCS7EncoderContext * p7eCx;
81
unsigned int numBytes;
82
unsigned int bufBytes;
83
char buf[PK12_OUTPUT_BUFFER_SIZE];
85
typedef struct sec_pkcs12OutputBufferStr sec_pkcs12OutputBuffer;
87
/*********************************
88
* Structures used in exporting the PKCS 12 blob
89
*********************************/
91
/* A SafeInfo is used for each ContentInfo which makes up the
92
* sequence of safes in the AuthenticatedSafe portion of the
95
struct SEC_PKCS12SafeInfoStr {
98
/* information for setting up password encryption */
101
PK11SymKey *encryptionKey;
103
/* how many items have been stored in this safe,
104
* we will skip any safe which does not contain any
107
unsigned int itemCount;
109
/* the content info for the safe */
110
SEC_PKCS7ContentInfo *cinfo;
112
sec_PKCS12SafeContents *safe;
115
/* An opaque structure which contains information needed for exporting
116
* certificates and keys through PKCS 12.
118
struct SEC_PKCS12ExportContextStr {
123
/* integrity information */
124
PRBool integrityEnabled;
127
struct sec_PKCS12PasswordModeInfo pwdInfo;
128
struct sec_PKCS12PublicKeyModeInfo pubkeyInfo;
131
/* helper functions */
132
/* retrieve the password call back */
133
SECKEYGetPasswordKey pwfn;
136
/* safe contents bags */
137
SEC_PKCS12SafeInfo **safeInfos;
138
unsigned int safeInfoCount;
140
/* the sequence of safes */
141
sec_PKCS12AuthenticatedSafe authSafe;
143
/* information needing deletion */
144
CERTCertificate **certList;
147
/* structures for passing information to encoder callbacks when processing
148
* data through the ASN1 engine.
150
struct sec_pkcs12_encoder_output {
151
SEC_PKCS12EncoderOutputCallback outputfn;
155
struct sec_pkcs12_hmac_and_output_info {
157
struct sec_pkcs12_encoder_output output;
160
/* An encoder context which is used for the actual encoding
161
* portion of PKCS 12.
163
typedef struct sec_PKCS12EncoderContextStr {
165
SEC_PKCS12ExportContext *p12exp;
166
PK11SymKey *encryptionKey;
168
/* encoder information - this is set up based on whether
169
* password based or public key pased privacy is being used
171
SEC_ASN1EncoderContext *outerA1ecx;
173
struct sec_pkcs12_hmac_and_output_info hmacAndOutputInfo;
174
struct sec_pkcs12_encoder_output encOutput;
177
/* structures for encoding of PFX and MAC */
178
sec_PKCS12PFXItem pfx;
179
sec_PKCS12MacData mac;
181
/* authenticated safe encoding tracking information */
182
SEC_PKCS7ContentInfo *aSafeCinfo;
183
SEC_PKCS7EncoderContext *middleP7ecx;
184
SEC_ASN1EncoderContext *middleA1ecx;
185
unsigned int currentSafe;
191
sec_pkcs12OutputBuffer middleBuf;
192
sec_pkcs12OutputBuffer innerBuf;
194
} sec_PKCS12EncoderContext;
197
/*********************************
198
* Export setup routines
199
*********************************/
201
/* SEC_PKCS12CreateExportContext
202
* Creates an export context and sets the unicode and password retrieval
203
* callbacks. This is the first call which must be made when exporting
206
* pwfn, pwfnarg - password retrieval callback and argument. these are
207
* required for password-authentication mode.
209
SEC_PKCS12ExportContext *
210
SEC_PKCS12CreateExportContext(SECKEYGetPasswordKey pwfn, void *pwfnarg,
211
PK11SlotInfo *slot, void *wincx)
213
PRArenaPool *arena = NULL;
214
SEC_PKCS12ExportContext *p12ctxt = NULL;
216
/* allocate the arena and create the context */
217
arena = PORT_NewArena(4096);
219
PORT_SetError(SEC_ERROR_NO_MEMORY);
223
p12ctxt = (SEC_PKCS12ExportContext *)PORT_ArenaZAlloc(arena,
224
sizeof(SEC_PKCS12ExportContext));
226
PORT_SetError(SEC_ERROR_NO_MEMORY);
230
/* password callback for key retrieval */
231
p12ctxt->pwfn = pwfn;
232
p12ctxt->pwfnarg = pwfnarg;
234
p12ctxt->integrityEnabled = PR_FALSE;
235
p12ctxt->arena = arena;
236
p12ctxt->wincx = wincx;
237
p12ctxt->slot = (slot) ? PK11_ReferenceSlot(slot) : PK11_GetInternalSlot();
243
PORT_FreeArena(arena, PR_TRUE);
250
* Adding integrity mode
253
/* SEC_PKCS12AddPasswordIntegrity
254
* Add password integrity to the exported data. If an integrity method
255
* has already been set, then return an error.
257
* p12ctxt - the export context
258
* pwitem - the password for integrity mode
259
* integAlg - the integrity algorithm to use for authentication.
262
SEC_PKCS12AddPasswordIntegrity(SEC_PKCS12ExportContext *p12ctxt,
263
SECItem *pwitem, SECOidTag integAlg)
265
if(!p12ctxt || p12ctxt->integrityEnabled) {
269
/* set up integrity information */
270
p12ctxt->pwdIntegrity = PR_TRUE;
271
p12ctxt->integrityInfo.pwdInfo.password =
272
(SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
273
if(!p12ctxt->integrityInfo.pwdInfo.password) {
274
PORT_SetError(SEC_ERROR_NO_MEMORY);
277
if(SECITEM_CopyItem(p12ctxt->arena,
278
p12ctxt->integrityInfo.pwdInfo.password, pwitem)
280
PORT_SetError(SEC_ERROR_NO_MEMORY);
283
p12ctxt->integrityInfo.pwdInfo.algorithm = integAlg;
284
p12ctxt->integrityEnabled = PR_TRUE;
289
/* SEC_PKCS12AddPublicKeyIntegrity
290
* Add public key integrity to the exported data. If an integrity method
291
* has already been set, then return an error. The certificate must be
292
* allowed to be used as a signing cert.
294
* p12ctxt - the export context
295
* cert - signer certificate
296
* certDb - the certificate database
297
* algorithm - signing algorithm
298
* keySize - size of the signing key (?)
301
SEC_PKCS12AddPublicKeyIntegrity(SEC_PKCS12ExportContext *p12ctxt,
302
CERTCertificate *cert, CERTCertDBHandle *certDb,
303
SECOidTag algorithm, int keySize)
309
p12ctxt->integrityInfo.pubkeyInfo.cert = cert;
310
p12ctxt->integrityInfo.pubkeyInfo.certDb = certDb;
311
p12ctxt->integrityInfo.pubkeyInfo.algorithm = algorithm;
312
p12ctxt->integrityInfo.pubkeyInfo.keySize = keySize;
313
p12ctxt->integrityEnabled = PR_TRUE;
320
* Adding safes - encrypted (password/public key) or unencrypted
321
* Each of the safe creation routines return an opaque pointer which
322
* are later passed into the routines for exporting certificates and
326
/* append the newly created safeInfo to list of safeInfos in the export
330
sec_pkcs12_append_safe_info(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *info)
332
void *mark = NULL, *dummy1 = NULL, *dummy2 = NULL;
334
if(!p12ctxt || !info) {
338
mark = PORT_ArenaMark(p12ctxt->arena);
340
/* if no safeInfos have been set, create the list, otherwise expand it. */
341
if(!p12ctxt->safeInfoCount) {
342
p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)PORT_ArenaZAlloc(p12ctxt->arena,
343
2 * sizeof(SEC_PKCS12SafeInfo *));
344
dummy1 = p12ctxt->safeInfos;
345
p12ctxt->authSafe.encodedSafes = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
346
2 * sizeof(SECItem *));
347
dummy2 = p12ctxt->authSafe.encodedSafes;
349
dummy1 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->safeInfos,
350
(p12ctxt->safeInfoCount + 1) * sizeof(SEC_PKCS12SafeInfo *),
351
(p12ctxt->safeInfoCount + 2) * sizeof(SEC_PKCS12SafeInfo *));
352
p12ctxt->safeInfos = (SEC_PKCS12SafeInfo **)dummy1;
353
dummy2 = PORT_ArenaGrow(p12ctxt->arena, p12ctxt->authSafe.encodedSafes,
354
(p12ctxt->authSafe.safeCount + 1) * sizeof(SECItem *),
355
(p12ctxt->authSafe.safeCount + 2) * sizeof(SECItem *));
356
p12ctxt->authSafe.encodedSafes = (SECItem**)dummy2;
358
if(!dummy1 || !dummy2) {
359
PORT_SetError(SEC_ERROR_NO_MEMORY);
363
/* append the new safeInfo and null terminate the list */
364
p12ctxt->safeInfos[p12ctxt->safeInfoCount] = info;
365
p12ctxt->safeInfos[++p12ctxt->safeInfoCount] = NULL;
366
p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount] =
367
(SECItem*)PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECItem));
368
if(!p12ctxt->authSafe.encodedSafes[p12ctxt->authSafe.safeCount]) {
369
PORT_SetError(SEC_ERROR_NO_MEMORY);
372
p12ctxt->authSafe.encodedSafes[++p12ctxt->authSafe.safeCount] = NULL;
374
PORT_ArenaUnmark(p12ctxt->arena, mark);
378
PORT_ArenaRelease(p12ctxt->arena, mark);
382
/* SEC_PKCS12CreatePasswordPrivSafe
383
* Create a password privacy safe to store exported information in.
385
* p12ctxt - export context
386
* pwitem - password for encryption
387
* privAlg - pbe algorithm through which encryption is done.
390
SEC_PKCS12CreatePasswordPrivSafe(SEC_PKCS12ExportContext *p12ctxt,
391
SECItem *pwitem, SECOidTag privAlg)
393
SEC_PKCS12SafeInfo *safeInfo = NULL;
395
PK11SlotInfo *slot = NULL;
396
SECAlgorithmID *algId;
397
SECItem uniPwitem = {siBuffer, NULL, 0};
403
/* allocate the safe info */
404
mark = PORT_ArenaMark(p12ctxt->arena);
405
safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
406
sizeof(SEC_PKCS12SafeInfo));
408
PORT_SetError(SEC_ERROR_NO_MEMORY);
409
PORT_ArenaRelease(p12ctxt->arena, mark);
413
safeInfo->itemCount = 0;
415
/* create the encrypted safe */
416
safeInfo->cinfo = SEC_PKCS7CreateEncryptedData(privAlg, 0, p12ctxt->pwfn,
418
if(!safeInfo->cinfo) {
419
PORT_SetError(SEC_ERROR_NO_MEMORY);
422
safeInfo->arena = p12ctxt->arena;
424
/* convert the password to unicode */
425
if(!sec_pkcs12_convert_item_to_unicode(NULL, &uniPwitem, pwitem,
426
PR_TRUE, PR_TRUE, PR_TRUE)) {
427
PORT_SetError(SEC_ERROR_NO_MEMORY);
430
if(SECITEM_CopyItem(p12ctxt->arena, &safeInfo->pwitem, &uniPwitem) != SECSuccess) {
431
PORT_SetError(SEC_ERROR_NO_MEMORY);
435
/* generate the encryption key */
436
slot = PK11_ReferenceSlot(p12ctxt->slot);
438
slot = PK11_GetInternalKeySlot();
440
PORT_SetError(SEC_ERROR_NO_MEMORY);
445
algId = SEC_PKCS7GetEncryptionAlgorithm(safeInfo->cinfo);
446
safeInfo->encryptionKey = PK11_PBEKeyGen(slot, algId, &uniPwitem,
447
PR_FALSE, p12ctxt->wincx);
448
if(!safeInfo->encryptionKey) {
452
safeInfo->arena = p12ctxt->arena;
453
safeInfo->safe = NULL;
454
if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
459
SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
461
PORT_ArenaUnmark(p12ctxt->arena, mark);
472
if(safeInfo->cinfo) {
473
SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
477
SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
480
PORT_ArenaRelease(p12ctxt->arena, mark);
484
/* SEC_PKCS12CreateUnencryptedSafe
485
* Creates an unencrypted safe within the export context.
487
* p12ctxt - the export context
490
SEC_PKCS12CreateUnencryptedSafe(SEC_PKCS12ExportContext *p12ctxt)
492
SEC_PKCS12SafeInfo *safeInfo = NULL;
499
/* create the safe info */
500
mark = PORT_ArenaMark(p12ctxt->arena);
501
safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
502
sizeof(SEC_PKCS12SafeInfo));
504
PORT_ArenaRelease(p12ctxt->arena, mark);
505
PORT_SetError(SEC_ERROR_NO_MEMORY);
509
safeInfo->itemCount = 0;
511
/* create the safe content */
512
safeInfo->cinfo = SEC_PKCS7CreateData();
513
if(!safeInfo->cinfo) {
514
PORT_SetError(SEC_ERROR_NO_MEMORY);
518
if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
522
PORT_ArenaUnmark(p12ctxt->arena, mark);
526
if(safeInfo->cinfo) {
527
SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
530
PORT_ArenaRelease(p12ctxt->arena, mark);
534
/* SEC_PKCS12CreatePubKeyEncryptedSafe
535
* Creates a safe which is protected by public key encryption.
537
* p12ctxt - the export context
538
* certDb - the certificate database
539
* signer - the signer's certificate
540
* recipients - the list of recipient certificates.
541
* algorithm - the encryption algorithm to use
542
* keysize - the algorithms key size (?)
545
SEC_PKCS12CreatePubKeyEncryptedSafe(SEC_PKCS12ExportContext *p12ctxt,
546
CERTCertDBHandle *certDb,
547
CERTCertificate *signer,
548
CERTCertificate **recipients,
549
SECOidTag algorithm, int keysize)
551
SEC_PKCS12SafeInfo *safeInfo = NULL;
554
if(!p12ctxt || !signer || !recipients || !(*recipients)) {
558
/* allocate the safeInfo */
559
mark = PORT_ArenaMark(p12ctxt->arena);
560
safeInfo = (SEC_PKCS12SafeInfo *)PORT_ArenaZAlloc(p12ctxt->arena,
561
sizeof(SEC_PKCS12SafeInfo));
563
PORT_ArenaRelease(p12ctxt->arena, mark);
564
PORT_SetError(SEC_ERROR_NO_MEMORY);
568
safeInfo->itemCount = 0;
569
safeInfo->arena = p12ctxt->arena;
571
/* create the enveloped content info using certUsageEmailSigner currently.
572
* XXX We need to eventually use something other than certUsageEmailSigner
574
safeInfo->cinfo = SEC_PKCS7CreateEnvelopedData(signer, certUsageEmailSigner,
575
certDb, algorithm, keysize,
576
p12ctxt->pwfn, p12ctxt->pwfnarg);
577
if(!safeInfo->cinfo) {
578
PORT_SetError(SEC_ERROR_NO_MEMORY);
585
while(recipients[i] != NULL) {
586
SECStatus rv = SEC_PKCS7AddRecipient(safeInfo->cinfo, recipients[i],
587
certUsageEmailRecipient, certDb);
588
if(rv != SECSuccess) {
595
if(sec_pkcs12_append_safe_info(p12ctxt, safeInfo) != SECSuccess) {
599
PORT_ArenaUnmark(p12ctxt->arena, mark);
603
if(safeInfo->cinfo) {
604
SEC_PKCS7DestroyContentInfo(safeInfo->cinfo);
605
safeInfo->cinfo = NULL;
608
PORT_ArenaRelease(p12ctxt->arena, mark);
612
/*********************************
613
* Routines to handle the exporting of the keys and certificates
614
*********************************/
616
/* creates a safe contents which safeBags will be appended to */
617
sec_PKCS12SafeContents *
618
sec_PKCS12CreateSafeContents(PRArenaPool *arena)
620
sec_PKCS12SafeContents *safeContents;
626
/* create the safe contents */
627
safeContents = (sec_PKCS12SafeContents *)PORT_ArenaZAlloc(arena,
628
sizeof(sec_PKCS12SafeContents));
630
PORT_SetError(SEC_ERROR_NO_MEMORY);
634
/* set up the internal contents info */
635
safeContents->safeBags = NULL;
636
safeContents->arena = arena;
637
safeContents->bagCount = 0;
645
/* appends a safe bag to a safeContents using the specified arena.
648
sec_pkcs12_append_bag_to_safe_contents(PRArenaPool *arena,
649
sec_PKCS12SafeContents *safeContents,
650
sec_PKCS12SafeBag *safeBag)
652
void *mark = NULL, *dummy = NULL;
654
if(!arena || !safeBag || !safeContents) {
658
mark = PORT_ArenaMark(arena);
660
PORT_SetError(SEC_ERROR_NO_MEMORY);
664
/* allocate space for the list, or reallocate to increase space */
665
if(!safeContents->safeBags) {
666
safeContents->safeBags = (sec_PKCS12SafeBag **)PORT_ArenaZAlloc(arena,
667
(2 * sizeof(sec_PKCS12SafeBag *)));
668
dummy = safeContents->safeBags;
669
safeContents->bagCount = 0;
671
dummy = PORT_ArenaGrow(arena, safeContents->safeBags,
672
(safeContents->bagCount + 1) * sizeof(sec_PKCS12SafeBag *),
673
(safeContents->bagCount + 2) * sizeof(sec_PKCS12SafeBag *));
674
safeContents->safeBags = (sec_PKCS12SafeBag **)dummy;
678
PORT_ArenaRelease(arena, mark);
679
PORT_SetError(SEC_ERROR_NO_MEMORY);
683
/* append the bag at the end and null terminate the list */
684
safeContents->safeBags[safeContents->bagCount++] = safeBag;
685
safeContents->safeBags[safeContents->bagCount] = NULL;
687
PORT_ArenaUnmark(arena, mark);
692
/* appends a safeBag to a specific safeInfo.
695
sec_pkcs12_append_bag(SEC_PKCS12ExportContext *p12ctxt,
696
SEC_PKCS12SafeInfo *safeInfo, sec_PKCS12SafeBag *safeBag)
698
sec_PKCS12SafeContents *dest;
699
SECStatus rv = SECFailure;
701
if(!p12ctxt || !safeBag || !safeInfo) {
705
if(!safeInfo->safe) {
706
safeInfo->safe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
707
if(!safeInfo->safe) {
712
dest = safeInfo->safe;
713
rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena, dest, safeBag);
714
if(rv == SECSuccess) {
715
safeInfo->itemCount++;
721
/* Creates a safeBag of the specified type, and if bagData is specified,
722
* the contents are set. The contents could be set later by the calling
726
sec_PKCS12CreateSafeBag(SEC_PKCS12ExportContext *p12ctxt, SECOidTag bagType,
729
sec_PKCS12SafeBag *safeBag;
730
PRBool setName = PR_TRUE;
732
SECStatus rv = SECSuccess;
733
SECOidData *oidData = NULL;
739
mark = PORT_ArenaMark(p12ctxt->arena);
741
PORT_SetError(SEC_ERROR_NO_MEMORY);
745
safeBag = (sec_PKCS12SafeBag *)PORT_ArenaZAlloc(p12ctxt->arena,
746
sizeof(sec_PKCS12SafeBag));
748
PORT_ArenaRelease(p12ctxt->arena, mark);
749
PORT_SetError(SEC_ERROR_NO_MEMORY);
753
/* set the bags content based upon bag type */
755
case SEC_OID_PKCS12_V1_KEY_BAG_ID:
756
safeBag->safeBagContent.pkcs8KeyBag =
757
(SECKEYPrivateKeyInfo *)bagData;
759
case SEC_OID_PKCS12_V1_CERT_BAG_ID:
760
safeBag->safeBagContent.certBag = (sec_PKCS12CertBag *)bagData;
762
case SEC_OID_PKCS12_V1_CRL_BAG_ID:
763
safeBag->safeBagContent.crlBag = (sec_PKCS12CRLBag *)bagData;
765
case SEC_OID_PKCS12_V1_SECRET_BAG_ID:
766
safeBag->safeBagContent.secretBag = (sec_PKCS12SecretBag *)bagData;
768
case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
769
safeBag->safeBagContent.pkcs8ShroudedKeyBag =
770
(SECKEYEncryptedPrivateKeyInfo *)bagData;
772
case SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID:
773
safeBag->safeBagContent.safeContents =
774
(sec_PKCS12SafeContents *)bagData;
781
oidData = SECOID_FindOIDByTag(bagType);
783
rv = SECITEM_CopyItem(p12ctxt->arena, &safeBag->safeBagType, &oidData->oid);
784
if(rv != SECSuccess) {
785
PORT_SetError(SEC_ERROR_NO_MEMORY);
792
safeBag->arena = p12ctxt->arena;
793
PORT_ArenaUnmark(p12ctxt->arena, mark);
799
PORT_ArenaRelease(p12ctxt->arena, mark);
805
/* Creates a new certificate bag and returns a pointer to it. If an error
806
* occurs NULL is returned.
809
sec_PKCS12NewCertBag(PRArenaPool *arena, SECOidTag certType)
811
sec_PKCS12CertBag *certBag = NULL;
812
SECOidData *bagType = NULL;
820
mark = PORT_ArenaMark(arena);
821
certBag = (sec_PKCS12CertBag *)PORT_ArenaZAlloc(arena,
822
sizeof(sec_PKCS12CertBag));
824
PORT_ArenaRelease(arena, mark);
825
PORT_SetError(SEC_ERROR_NO_MEMORY);
829
bagType = SECOID_FindOIDByTag(certType);
831
PORT_SetError(SEC_ERROR_NO_MEMORY);
835
rv = SECITEM_CopyItem(arena, &certBag->bagID, &bagType->oid);
836
if(rv != SECSuccess) {
837
PORT_SetError(SEC_ERROR_NO_MEMORY);
841
PORT_ArenaUnmark(arena, mark);
845
PORT_ArenaRelease(arena, mark);
849
/* Creates a new CRL bag and returns a pointer to it. If an error
850
* occurs NULL is returned.
853
sec_PKCS12NewCRLBag(PRArenaPool *arena, SECOidTag crlType)
855
sec_PKCS12CRLBag *crlBag = NULL;
856
SECOidData *bagType = NULL;
864
mark = PORT_ArenaMark(arena);
865
crlBag = (sec_PKCS12CRLBag *)PORT_ArenaZAlloc(arena,
866
sizeof(sec_PKCS12CRLBag));
868
PORT_ArenaRelease(arena, mark);
869
PORT_SetError(SEC_ERROR_NO_MEMORY);
873
bagType = SECOID_FindOIDByTag(crlType);
875
PORT_SetError(SEC_ERROR_NO_MEMORY);
879
rv = SECITEM_CopyItem(arena, &crlBag->bagID, &bagType->oid);
880
if(rv != SECSuccess) {
881
PORT_SetError(SEC_ERROR_NO_MEMORY);
885
PORT_ArenaUnmark(arena, mark);
889
PORT_ArenaRelease(arena, mark);
893
/* sec_PKCS12AddAttributeToBag
894
* adds an attribute to a safeBag. currently, the only attributes supported
895
* are those which are specified within PKCS 12.
897
* p12ctxt - the export context
898
* safeBag - the safeBag to which attributes are appended
899
* attrType - the attribute type
900
* attrData - the attribute data
903
sec_PKCS12AddAttributeToBag(SEC_PKCS12ExportContext *p12ctxt,
904
sec_PKCS12SafeBag *safeBag, SECOidTag attrType,
907
sec_PKCS12Attribute *attribute;
908
void *mark = NULL, *dummy = NULL;
909
SECOidData *oiddata = NULL;
910
SECItem unicodeName = { siBuffer, NULL, 0};
912
unsigned int nItems = 0;
915
if(!safeBag || !p12ctxt) {
919
mark = PORT_ArenaMark(safeBag->arena);
921
/* allocate the attribute */
922
attribute = (sec_PKCS12Attribute *)PORT_ArenaZAlloc(safeBag->arena,
923
sizeof(sec_PKCS12Attribute));
925
PORT_SetError(SEC_ERROR_NO_MEMORY);
929
/* set up the attribute */
930
oiddata = SECOID_FindOIDByTag(attrType);
932
PORT_SetError(SEC_ERROR_NO_MEMORY);
935
if(SECITEM_CopyItem(p12ctxt->arena, &attribute->attrType, &oiddata->oid) !=
937
PORT_SetError(SEC_ERROR_NO_MEMORY);
943
case SEC_OID_PKCS9_LOCAL_KEY_ID:
948
case SEC_OID_PKCS9_FRIENDLY_NAME:
950
if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena,
951
&unicodeName, attrData, PR_FALSE,
952
PR_FALSE, PR_TRUE)) {
962
/* append the attribute to the attribute value list */
963
attribute->attrValue = (SECItem **)PORT_ArenaZAlloc(p12ctxt->arena,
964
((nItems + 1) * sizeof(SECItem *)));
965
if(!attribute->attrValue) {
966
PORT_SetError(SEC_ERROR_NO_MEMORY);
970
/* XXX this will need to be changed if attributes requiring more than
971
* one element are ever used.
973
attribute->attrValue[0] = (SECItem *)PORT_ArenaZAlloc(p12ctxt->arena,
975
if(!attribute->attrValue[0]) {
976
PORT_SetError(SEC_ERROR_NO_MEMORY);
979
attribute->attrValue[1] = NULL;
981
rv = SECITEM_CopyItem(p12ctxt->arena, attribute->attrValue[0],
983
if(rv != SECSuccess) {
984
PORT_SetError(SEC_ERROR_NO_MEMORY);
988
/* append the attribute to the safeBag attributes */
989
if(safeBag->nAttribs) {
990
dummy = PORT_ArenaGrow(p12ctxt->arena, safeBag->attribs,
991
((safeBag->nAttribs + 1) * sizeof(sec_PKCS12Attribute *)),
992
((safeBag->nAttribs + 2) * sizeof(sec_PKCS12Attribute *)));
993
safeBag->attribs = (sec_PKCS12Attribute **)dummy;
995
safeBag->attribs = (sec_PKCS12Attribute **)PORT_ArenaZAlloc(p12ctxt->arena,
996
2 * sizeof(sec_PKCS12Attribute *));
997
dummy = safeBag->attribs;
1003
safeBag->attribs[safeBag->nAttribs] = attribute;
1004
safeBag->attribs[++safeBag->nAttribs] = NULL;
1006
PORT_ArenaUnmark(p12ctxt->arena, mark);
1011
PORT_ArenaRelease(p12ctxt->arena, mark);
1017
/* SEC_PKCS12AddCert
1018
* Adds a certificate to the data being exported.
1020
* p12ctxt - the export context
1021
* safe - the safeInfo to which the certificate is placed
1022
* nestedDest - if the cert is to be placed within a nested safeContents then,
1023
* this value is to be specified with the destination
1024
* cert - the cert to export
1025
* certDb - the certificate database handle
1026
* keyId - a unique identifier to associate a certificate/key pair
1027
* includeCertChain - PR_TRUE if the certificate chain is to be included.
1030
SEC_PKCS12AddCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1031
void *nestedDest, CERTCertificate *cert,
1032
CERTCertDBHandle *certDb, SECItem *keyId,
1033
PRBool includeCertChain)
1035
sec_PKCS12CertBag *certBag;
1036
sec_PKCS12SafeBag *safeBag;
1039
SECItem nick = {siBuffer, NULL,0};
1041
if(!p12ctxt || !cert) {
1044
mark = PORT_ArenaMark(p12ctxt->arena);
1046
/* allocate the cert bag */
1047
certBag = sec_PKCS12NewCertBag(p12ctxt->arena,
1048
SEC_OID_PKCS9_X509_CERT);
1053
if(SECITEM_CopyItem(p12ctxt->arena, &certBag->value.x509Cert,
1054
&cert->derCert) != SECSuccess) {
1055
PORT_SetError(SEC_ERROR_NO_MEMORY);
1059
/* if the cert chain is to be included, we should only be exporting
1060
* the cert from our internal database.
1062
if(includeCertChain) {
1063
CERTCertificateList *certList = CERT_CertChainFromCert(cert,
1066
unsigned int count = 0;
1068
PORT_SetError(SEC_ERROR_NO_MEMORY);
1072
/* add cert chain */
1073
for(count = 0; count < (unsigned int)certList->len; count++) {
1074
if(SECITEM_CompareItem(&certList->certs[count], &cert->derCert)
1076
CERTCertificate *tempCert;
1078
/* decode the certificate */
1080
* This was rather silly. The chain is constructed above
1081
* by finding all of the CERTCertificate's in the database.
1082
* Then the chain is put into a CERTCertificateList, which only
1083
* contains the DER. Finally, the DER was decoded, and the
1084
* decoded cert was sent recursively back to this function.
1085
* Beyond being inefficent, this causes data loss (specifically,
1086
* the nickname). Instead, for 3.4, we'll do a lookup by the
1087
* DER, which should return the cached entry.
1089
tempCert = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(),
1090
&certList->certs[count]);
1092
CERT_DestroyCertificateList(certList);
1096
/* add the certificate */
1097
if(SEC_PKCS12AddCert(p12ctxt, safe, nestedDest, tempCert,
1098
certDb, NULL, PR_FALSE) != SECSuccess) {
1099
CERT_DestroyCertificate(tempCert);
1100
CERT_DestroyCertificateList(certList);
1103
CERT_DestroyCertificate(tempCert);
1106
CERT_DestroyCertificateList(certList);
1109
/* if the certificate has a nickname, we will set the friendly name
1112
if(cert->nickname) {
1113
if (cert->slot && !PK11_IsInternal(cert->slot)) {
1115
* The cert is coming off of an external token,
1116
* let's strip the token name from the nickname
1117
* and only add what comes after the colon as the
1122
delimit = PORT_Strchr(cert->nickname,':');
1123
if (delimit == NULL) {
1124
nick.data = (unsigned char *)cert->nickname;
1125
nick.len = PORT_Strlen(cert->nickname);
1128
nick.data = (unsigned char *)PORT_ArenaStrdup(p12ctxt->arena,
1130
nick.len = PORT_Strlen(delimit);
1133
nick.data = (unsigned char *)cert->nickname;
1134
nick.len = PORT_Strlen(cert->nickname);
1138
safeBag = sec_PKCS12CreateSafeBag(p12ctxt, SEC_OID_PKCS12_V1_CERT_BAG_ID,
1144
/* add the friendly name and keyId attributes, if necessary */
1146
if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag,
1147
SEC_OID_PKCS9_FRIENDLY_NAME, &nick)
1154
if(sec_PKCS12AddAttributeToBag(p12ctxt, safeBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1155
keyId) != SECSuccess) {
1160
/* append the cert safeBag */
1162
rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1163
(sec_PKCS12SafeContents*)nestedDest,
1166
rv = sec_pkcs12_append_bag(p12ctxt, safe, safeBag);
1169
if(rv != SECSuccess) {
1173
PORT_ArenaUnmark(p12ctxt->arena, mark);
1178
PORT_ArenaRelease(p12ctxt->arena, mark);
1184
/* SEC_PKCS12AddEncryptedKey
1185
* Extracts the key associated with a particular certificate and exports
1188
* p12ctxt - the export context
1189
* safe - the safeInfo to place the key in
1190
* nestedDest - the nested safeContents to place a key
1191
* cert - the certificate which the key belongs to
1192
* shroudKey - encrypt the private key for export. This value should
1193
* always be true. lower level code will not allow the export
1194
* of unencrypted private keys.
1195
* algorithm - the algorithm with which to encrypt the private key
1196
* pwitem - the password to encrypted the private key with
1197
* keyId - the keyID attribute
1198
* nickName - the nickname attribute
1201
SEC_PKCS12AddEncryptedKey(SEC_PKCS12ExportContext *p12ctxt,
1202
SECKEYEncryptedPrivateKeyInfo *epki, SEC_PKCS12SafeInfo *safe,
1203
void *nestedDest, SECItem *keyId, SECItem *nickName)
1208
SECStatus rv = SECFailure;
1209
sec_PKCS12SafeBag *returnBag;
1211
if(!p12ctxt || !safe || !epki) {
1215
mark = PORT_ArenaMark(p12ctxt->arena);
1217
keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1218
sizeof(SECKEYEncryptedPrivateKeyInfo));
1220
PORT_SetError(SEC_ERROR_NO_MEMORY);
1224
rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1225
(SECKEYEncryptedPrivateKeyInfo *)keyItem,
1227
keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1229
if(rv != SECSuccess) {
1233
/* create the safe bag and set any attributes */
1234
returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1241
if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1242
SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1249
if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1250
SEC_OID_PKCS9_LOCAL_KEY_ID,
1251
keyId) != SECSuccess) {
1257
rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1258
(sec_PKCS12SafeContents*)nestedDest,
1261
rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1266
if (rv != SECSuccess) {
1267
PORT_ArenaRelease(p12ctxt->arena, mark);
1269
PORT_ArenaUnmark(p12ctxt->arena, mark);
1275
/* SEC_PKCS12AddKeyForCert
1276
* Extracts the key associated with a particular certificate and exports
1279
* p12ctxt - the export context
1280
* safe - the safeInfo to place the key in
1281
* nestedDest - the nested safeContents to place a key
1282
* cert - the certificate which the key belongs to
1283
* shroudKey - encrypt the private key for export. This value should
1284
* always be true. lower level code will not allow the export
1285
* of unencrypted private keys.
1286
* algorithm - the algorithm with which to encrypt the private key
1287
* pwitem - the password to encrypt the private key with
1288
* keyId - the keyID attribute
1289
* nickName - the nickname attribute
1292
SEC_PKCS12AddKeyForCert(SEC_PKCS12ExportContext *p12ctxt, SEC_PKCS12SafeInfo *safe,
1293
void *nestedDest, CERTCertificate *cert,
1294
PRBool shroudKey, SECOidTag algorithm, SECItem *pwitem,
1295
SECItem *keyId, SECItem *nickName)
1300
SECStatus rv = SECFailure;
1301
SECItem nickname = {siBuffer,NULL,0}, uniPwitem = {siBuffer, NULL, 0};
1302
sec_PKCS12SafeBag *returnBag;
1304
if(!p12ctxt || !cert || !safe) {
1308
mark = PORT_ArenaMark(p12ctxt->arena);
1310
/* retrieve the key based upon the type that it is and
1311
* specify the type of safeBag to store the key in
1315
/* extract the key unencrypted. this will most likely go away */
1316
SECKEYPrivateKeyInfo *pki = PK11_ExportPrivateKeyInfo(cert,
1319
PORT_ArenaRelease(p12ctxt->arena, mark);
1320
PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1323
keyItem = PORT_ArenaZAlloc(p12ctxt->arena, sizeof(SECKEYPrivateKeyInfo));
1325
PORT_SetError(SEC_ERROR_NO_MEMORY);
1328
rv = SECKEY_CopyPrivateKeyInfo(p12ctxt->arena,
1329
(SECKEYPrivateKeyInfo *)keyItem, pki);
1330
keyType = SEC_OID_PKCS12_V1_KEY_BAG_ID;
1331
SECKEY_DestroyPrivateKeyInfo(pki, PR_TRUE);
1334
/* extract the key encrypted */
1335
SECKEYEncryptedPrivateKeyInfo *epki = NULL;
1336
PK11SlotInfo *slot = NULL;
1338
if(!sec_pkcs12_convert_item_to_unicode(p12ctxt->arena, &uniPwitem,
1339
pwitem, PR_TRUE, PR_TRUE, PR_TRUE)) {
1340
PORT_SetError(SEC_ERROR_NO_MEMORY);
1344
/* we want to make sure to take the key out of the key slot */
1345
if(PK11_IsInternal(p12ctxt->slot)) {
1346
slot = PK11_GetInternalKeySlot();
1348
slot = PK11_ReferenceSlot(p12ctxt->slot);
1351
epki = PK11_ExportEncryptedPrivateKeyInfo(slot, algorithm,
1352
&uniPwitem, cert, 1,
1354
PK11_FreeSlot(slot);
1356
keyItem = PORT_ArenaZAlloc(p12ctxt->arena,
1357
sizeof(SECKEYEncryptedPrivateKeyInfo));
1359
PORT_SetError(SEC_ERROR_NO_MEMORY);
1363
PORT_SetError(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY);
1366
rv = SECKEY_CopyEncryptedPrivateKeyInfo(p12ctxt->arena,
1367
(SECKEYEncryptedPrivateKeyInfo *)keyItem,
1369
keyType = SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID;
1370
SECKEY_DestroyEncryptedPrivateKeyInfo(epki, PR_TRUE);
1373
if(rv != SECSuccess) {
1377
/* if no nickname specified, let's see if the certificate has a
1381
if(cert->nickname) {
1382
nickname.data = (unsigned char *)cert->nickname;
1383
nickname.len = PORT_Strlen(cert->nickname);
1384
nickName = &nickname;
1388
/* create the safe bag and set any attributes */
1389
returnBag = sec_PKCS12CreateSafeBag(p12ctxt, keyType, keyItem);
1396
if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag,
1397
SEC_OID_PKCS9_FRIENDLY_NAME, nickName)
1404
if(sec_PKCS12AddAttributeToBag(p12ctxt, returnBag, SEC_OID_PKCS9_LOCAL_KEY_ID,
1405
keyId) != SECSuccess) {
1411
rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1412
(sec_PKCS12SafeContents*)nestedDest,
1415
rv = sec_pkcs12_append_bag(p12ctxt, safe, returnBag);
1420
if (rv != SECSuccess) {
1421
PORT_ArenaRelease(p12ctxt->arena, mark);
1423
PORT_ArenaUnmark(p12ctxt->arena, mark);
1429
/* SEC_PKCS12AddCertAndEncryptedKey
1430
* Add a certificate and key pair to be exported.
1432
* p12ctxt - the export context
1433
* certSafe - the safeInfo where the cert is stored
1434
* certNestedDest - the nested safeContents to store the cert
1435
* keySafe - the safeInfo where the key is stored
1436
* keyNestedDest - the nested safeContents to store the key
1437
* shroudKey - extract the private key encrypted?
1438
* pwitem - the password with which the key is encrypted
1439
* algorithm - the algorithm with which the key is encrypted
1442
SEC_PKCS12AddDERCertAndEncryptedKey(SEC_PKCS12ExportContext *p12ctxt,
1443
void *certSafe, void *certNestedDest,
1444
SECItem *derCert, void *keySafe,
1445
void *keyNestedDest, SECKEYEncryptedPrivateKeyInfo *epki,
1448
SECStatus rv = SECFailure;
1449
SGNDigestInfo *digest = NULL;
1451
CERTCertificate *cert;
1452
SECItem nick = {siBuffer, NULL,0}, *nickPtr = NULL;
1454
if(!p12ctxt || !certSafe || !keySafe || !derCert) {
1458
mark = PORT_ArenaMark(p12ctxt->arena);
1460
cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
1461
derCert, NULL, PR_FALSE, PR_FALSE);
1463
PORT_ArenaRelease(p12ctxt->arena, mark);
1464
PORT_SetError(SEC_ERROR_NO_MEMORY);
1467
cert->nickname = nickname;
1469
/* generate the thumbprint of the cert to use as a keyId */
1470
digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1472
CERT_DestroyCertificate(cert);
1476
/* add the certificate */
1477
rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe,
1478
certNestedDest, cert, NULL,
1479
&digest->digest, PR_FALSE);
1480
if(rv != SECSuccess) {
1485
nick.data = (unsigned char *)nickname;
1486
nick.len = PORT_Strlen(nickname);
1493
rv = SEC_PKCS12AddEncryptedKey(p12ctxt, epki, (SEC_PKCS12SafeInfo*)keySafe,
1494
keyNestedDest, &digest->digest, nickPtr );
1495
if(rv != SECSuccess) {
1499
SGN_DestroyDigestInfo(digest);
1501
PORT_ArenaUnmark(p12ctxt->arena, mark);
1505
SGN_DestroyDigestInfo(digest);
1506
CERT_DestroyCertificate(cert);
1507
PORT_ArenaRelease(p12ctxt->arena, mark);
1512
/* SEC_PKCS12AddCertAndKey
1513
* Add a certificate and key pair to be exported.
1515
* p12ctxt - the export context
1516
* certSafe - the safeInfo where the cert is stored
1517
* certNestedDest - the nested safeContents to store the cert
1518
* keySafe - the safeInfo where the key is stored
1519
* keyNestedDest - the nested safeContents to store the key
1520
* shroudKey - extract the private key encrypted?
1521
* pwitem - the password with which the key is encrypted
1522
* algorithm - the algorithm with which the key is encrypted
1525
SEC_PKCS12AddCertAndKey(SEC_PKCS12ExportContext *p12ctxt,
1526
void *certSafe, void *certNestedDest,
1527
CERTCertificate *cert, CERTCertDBHandle *certDb,
1528
void *keySafe, void *keyNestedDest,
1529
PRBool shroudKey, SECItem *pwitem, SECOidTag algorithm)
1531
SECStatus rv = SECFailure;
1532
SGNDigestInfo *digest = NULL;
1535
if(!p12ctxt || !certSafe || !keySafe || !cert) {
1539
mark = PORT_ArenaMark(p12ctxt->arena);
1541
/* generate the thumbprint of the cert to use as a keyId */
1542
digest = sec_pkcs12_compute_thumbprint(&cert->derCert);
1544
PORT_ArenaRelease(p12ctxt->arena, mark);
1548
/* add the certificate */
1549
rv = SEC_PKCS12AddCert(p12ctxt, (SEC_PKCS12SafeInfo*)certSafe,
1550
(SEC_PKCS12SafeInfo*)certNestedDest, cert, certDb,
1551
&digest->digest, PR_TRUE);
1552
if(rv != SECSuccess) {
1557
rv = SEC_PKCS12AddKeyForCert(p12ctxt, (SEC_PKCS12SafeInfo*)keySafe,
1558
keyNestedDest, cert,
1559
shroudKey, algorithm, pwitem,
1560
&digest->digest, NULL );
1561
if(rv != SECSuccess) {
1565
SGN_DestroyDigestInfo(digest);
1567
PORT_ArenaUnmark(p12ctxt->arena, mark);
1571
SGN_DestroyDigestInfo(digest);
1572
PORT_ArenaRelease(p12ctxt->arena, mark);
1577
/* SEC_PKCS12CreateNestedSafeContents
1578
* Allows nesting of safe contents to be implemented. No limit imposed on
1581
* p12ctxt - the export context
1582
* baseSafe - the base safeInfo
1583
* nestedDest - a parent safeContents (?)
1586
SEC_PKCS12CreateNestedSafeContents(SEC_PKCS12ExportContext *p12ctxt,
1587
void *baseSafe, void *nestedDest)
1589
sec_PKCS12SafeContents *newSafe;
1590
sec_PKCS12SafeBag *safeContentsBag;
1594
if(!p12ctxt || !baseSafe) {
1598
mark = PORT_ArenaMark(p12ctxt->arena);
1600
newSafe = sec_PKCS12CreateSafeContents(p12ctxt->arena);
1602
PORT_ArenaRelease(p12ctxt->arena, mark);
1603
PORT_SetError(SEC_ERROR_NO_MEMORY);
1607
/* create the safeContents safeBag */
1608
safeContentsBag = sec_PKCS12CreateSafeBag(p12ctxt,
1609
SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
1611
if(!safeContentsBag) {
1615
/* append the safeContents to the appropriate area */
1617
rv = sec_pkcs12_append_bag_to_safe_contents(p12ctxt->arena,
1618
(sec_PKCS12SafeContents*)nestedDest,
1621
rv = sec_pkcs12_append_bag(p12ctxt, (SEC_PKCS12SafeInfo*)baseSafe,
1624
if(rv != SECSuccess) {
1628
PORT_ArenaUnmark(p12ctxt->arena, mark);
1632
PORT_ArenaRelease(p12ctxt->arena, mark);
1636
/*********************************
1638
*********************************/
1640
/* set up the encoder context based on information in the export context
1641
* and return the newly allocated enocoder context. A return of NULL
1642
* indicates an error occurred.
1644
sec_PKCS12EncoderContext *
1645
sec_pkcs12_encoder_start_context(SEC_PKCS12ExportContext *p12exp)
1647
sec_PKCS12EncoderContext *p12enc = NULL;
1648
unsigned int i, nonEmptyCnt;
1650
SECItem ignore = {0};
1653
if(!p12exp || !p12exp->safeInfos) {
1657
/* check for any empty safes and skip them */
1658
i = nonEmptyCnt = 0;
1659
while(p12exp->safeInfos[i]) {
1660
if(p12exp->safeInfos[i]->itemCount) {
1665
if(nonEmptyCnt == 0) {
1668
p12exp->authSafe.encodedSafes[nonEmptyCnt] = NULL;
1670
/* allocate the encoder context */
1671
mark = PORT_ArenaMark(p12exp->arena);
1672
p12enc = PORT_ArenaZNew(p12exp->arena, sec_PKCS12EncoderContext);
1674
PORT_SetError(SEC_ERROR_NO_MEMORY);
1678
p12enc->arena = p12exp->arena;
1679
p12enc->p12exp = p12exp;
1681
/* set up the PFX version and information */
1682
PORT_Memset(&p12enc->pfx, 0, sizeof(sec_PKCS12PFXItem));
1683
if(!SEC_ASN1EncodeInteger(p12exp->arena, &(p12enc->pfx.version),
1684
SEC_PKCS12_VERSION) ) {
1685
PORT_SetError(SEC_ERROR_NO_MEMORY);
1689
/* set up the authenticated safe content info based on the
1690
* type of integrity being used. this should be changed to
1691
* enforce integrity mode, but will not be implemented until
1692
* it is confirmed that integrity must be in place
1694
if(p12exp->integrityEnabled && !p12exp->pwdIntegrity) {
1697
/* create public key integrity mode */
1698
p12enc->aSafeCinfo = SEC_PKCS7CreateSignedData(
1699
p12exp->integrityInfo.pubkeyInfo.cert,
1700
certUsageEmailSigner,
1701
p12exp->integrityInfo.pubkeyInfo.certDb,
1702
p12exp->integrityInfo.pubkeyInfo.algorithm,
1706
if(!p12enc->aSafeCinfo) {
1709
if(SEC_PKCS7IncludeCertChain(p12enc->aSafeCinfo,NULL) != SECSuccess) {
1712
rv = SEC_PKCS7AddSigningTime(p12enc->aSafeCinfo);
1713
PORT_Assert(rv == SECSuccess);
1715
p12enc->aSafeCinfo = SEC_PKCS7CreateData();
1717
/* init password pased integrity mode */
1718
if(p12exp->integrityEnabled) {
1719
SECItem pwd = {siBuffer,NULL, 0};
1720
SECItem *salt = sec_pkcs12_generate_salt();
1723
CK_MECHANISM_TYPE integrityMech;
1724
CK_MECHANISM_TYPE hmacMech;
1726
/* zero out macData and set values */
1727
PORT_Memset(&p12enc->mac, 0, sizeof(sec_PKCS12MacData));
1730
PORT_SetError(SEC_ERROR_NO_MEMORY);
1733
if(SECITEM_CopyItem(p12exp->arena, &(p12enc->mac.macSalt), salt)
1735
PORT_SetError(SEC_ERROR_NO_MEMORY);
1739
/* generate HMAC key */
1740
if(!sec_pkcs12_convert_item_to_unicode(NULL, &pwd,
1741
p12exp->integrityInfo.pwdInfo.password, PR_TRUE,
1742
PR_TRUE, PR_TRUE)) {
1746
params = PK11_CreatePBEParams(salt, &pwd, 1);
1747
SECITEM_ZfreeItem(salt, PR_TRUE);
1748
SECITEM_ZfreeItem(&pwd, PR_FALSE);
1750
switch (p12exp->integrityInfo.pwdInfo.algorithm) {
1752
integrityMech = CKM_NETSCAPE_PBE_SHA1_HMAC_KEY_GEN; break;
1754
integrityMech = CKM_NETSCAPE_PBE_MD5_HMAC_KEY_GEN; break;
1756
integrityMech = CKM_NETSCAPE_PBE_MD2_HMAC_KEY_GEN; break;
1761
symKey = PK11_KeyGen(NULL, integrityMech, params, 20, NULL);
1762
PK11_DestroyPBEParams(params);
1767
/* initialize hmac */
1768
/* XXX NBB, why is this mech different than the one above? */
1769
hmacMech = sec_pkcs12_algtag_to_mech(
1770
p12exp->integrityInfo.pwdInfo.algorithm);
1772
p12enc->hmacCx = PK11_CreateContextBySymKey( hmacMech, CKA_SIGN,
1775
PK11_FreeSymKey(symKey);
1776
if(!p12enc->hmacCx) {
1777
PORT_SetError(SEC_ERROR_NO_MEMORY);
1780
rv = PK11_DigestBegin(p12enc->hmacCx);
1781
if (rv != SECSuccess)
1786
if(!p12enc->aSafeCinfo) {
1790
PORT_ArenaUnmark(p12exp->arena, mark);
1796
if(p12enc->aSafeCinfo) {
1797
SEC_PKCS7DestroyContentInfo(p12enc->aSafeCinfo);
1799
if(p12enc->hmacCx) {
1800
PK11_DestroyContext(p12enc->hmacCx, PR_TRUE);
1803
if (p12exp->arena != NULL)
1804
PORT_ArenaRelease(p12exp->arena, mark);
1809
/* The outermost ASN.1 encoder calls this function for output.
1810
** This function calls back to the library caller's output routine,
1811
** which typically writes to a PKCS12 file.
1814
sec_P12A1OutputCB_Outer(void *arg, const char *buf, unsigned long len,
1815
int depth, SEC_ASN1EncodingPart data_kind)
1817
struct sec_pkcs12_encoder_output *output;
1819
output = (struct sec_pkcs12_encoder_output*)arg;
1820
(* output->outputfn)(output->outputarg, buf, len);
1823
/* The "middle" and "inner" ASN.1 encoders call this function to output.
1824
** This function does HMACing, if appropriate, and then buffers the data.
1825
** The buffered data is eventually passed down to the underlying PKCS7 encoder.
1828
sec_P12A1OutputCB_HmacP7Update(void *arg, const char *buf,
1831
SEC_ASN1EncodingPart data_kind)
1833
sec_pkcs12OutputBuffer * bufcx = (sec_pkcs12OutputBuffer *)arg;
1838
if (bufcx->hmacCx) {
1839
PK11_DigestOp(bufcx->hmacCx, (unsigned char *)buf, len);
1843
if (bufcx->numBytes > 0) {
1845
if (len + bufcx->numBytes <= bufcx->bufBytes) {
1846
memcpy(bufcx->buf + bufcx->numBytes, buf, len);
1847
bufcx->numBytes += len;
1848
if (bufcx->numBytes < bufcx->bufBytes)
1850
SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1851
bufcx->numBytes = 0;
1854
toCopy = bufcx->bufBytes - bufcx->numBytes;
1855
memcpy(bufcx->buf + bufcx->numBytes, buf, toCopy);
1856
SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->bufBytes);
1857
bufcx->numBytes = 0;
1861
/* buffer is presently empty */
1862
if (len >= bufcx->bufBytes) {
1863
/* Just pass it through */
1864
SEC_PKCS7EncoderUpdate(bufcx->p7eCx, buf, len);
1866
/* copy it all into the buffer, and return */
1867
memcpy(bufcx->buf, buf, len);
1868
bufcx->numBytes = len;
1873
sec_FlushPkcs12OutputBuffer( sec_pkcs12OutputBuffer * bufcx)
1875
if (bufcx->numBytes > 0) {
1876
SEC_PKCS7EncoderUpdate(bufcx->p7eCx, bufcx->buf, bufcx->numBytes);
1877
bufcx->numBytes = 0;
1881
/* Feeds the output of a PKCS7 encoder into the next outward ASN.1 encoder.
1882
** This function is used by both the inner and middle PCS7 encoders.
1885
sec_P12P7OutputCB_CallA1Update(void *arg, const char *buf, unsigned long len)
1887
SEC_ASN1EncoderContext *cx = (SEC_ASN1EncoderContext*)arg;
1892
SEC_ASN1EncoderUpdate(cx, buf, len);
1896
/* this function encodes content infos which are part of the
1897
* sequence of content infos labeled AuthenticatedSafes
1900
sec_pkcs12_encoder_asafe_process(sec_PKCS12EncoderContext *p12ecx)
1902
SEC_PKCS7EncoderContext *innerP7ecx;
1903
SEC_PKCS7ContentInfo *cinfo;
1904
PK11SymKey *bulkKey = NULL;
1905
SEC_ASN1EncoderContext *innerA1ecx = NULL;
1906
SECStatus rv = SECSuccess;
1908
if(p12ecx->currentSafe < p12ecx->p12exp->authSafe.safeCount) {
1909
SEC_PKCS12SafeInfo *safeInfo;
1910
SECOidTag cinfoType;
1912
safeInfo = p12ecx->p12exp->safeInfos[p12ecx->currentSafe];
1914
/* skip empty safes */
1915
if(safeInfo->itemCount == 0) {
1919
cinfo = safeInfo->cinfo;
1920
cinfoType = SEC_PKCS7ContentType(cinfo);
1922
/* determine the safe type and set the appropriate argument */
1924
case SEC_OID_PKCS7_DATA:
1925
case SEC_OID_PKCS7_ENVELOPED_DATA:
1927
case SEC_OID_PKCS7_ENCRYPTED_DATA:
1928
bulkKey = safeInfo->encryptionKey;
1929
PK11_SetSymKeyUserData(bulkKey, &safeInfo->pwitem, NULL);
1936
/* start the PKCS7 encoder */
1937
innerP7ecx = SEC_PKCS7EncoderStart(cinfo,
1938
sec_P12P7OutputCB_CallA1Update,
1939
p12ecx->middleA1ecx, bulkKey);
1944
/* encode safe contents */
1945
p12ecx->innerBuf.p7eCx = innerP7ecx;
1946
p12ecx->innerBuf.hmacCx = NULL;
1947
p12ecx->innerBuf.numBytes = 0;
1948
p12ecx->innerBuf.bufBytes = sizeof p12ecx->innerBuf.buf;
1950
innerA1ecx = SEC_ASN1EncoderStart(safeInfo->safe,
1951
sec_PKCS12SafeContentsTemplate,
1952
sec_P12A1OutputCB_HmacP7Update,
1957
rv = SEC_ASN1EncoderUpdate(innerA1ecx, NULL, 0);
1958
SEC_ASN1EncoderFinish(innerA1ecx);
1959
sec_FlushPkcs12OutputBuffer( &p12ecx->innerBuf);
1961
if(rv != SECSuccess) {
1966
/* finish up safe content info */
1967
rv = SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1968
p12ecx->p12exp->pwfnarg);
1970
memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1975
SEC_PKCS7EncoderFinish(innerP7ecx, p12ecx->p12exp->pwfn,
1976
p12ecx->p12exp->pwfnarg);
1980
SEC_ASN1EncoderFinish(innerA1ecx);
1982
memset(&p12ecx->innerBuf, 0, sizeof p12ecx->innerBuf);
1986
/* finish the HMAC and encode the macData so that it can be
1990
sec_Pkcs12FinishMac(sec_PKCS12EncoderContext *p12ecx)
1992
SECItem hmac = { siBuffer, NULL, 0 };
1994
SGNDigestInfo *di = NULL;
2001
/* make sure we are using password integrity mode */
2002
if(!p12ecx->p12exp->integrityEnabled) {
2006
if(!p12ecx->p12exp->pwdIntegrity) {
2010
/* finish the hmac */
2011
hmac.data = (unsigned char *)PORT_ZAlloc(SHA1_LENGTH);
2013
PORT_SetError(SEC_ERROR_NO_MEMORY);
2017
rv = PK11_DigestFinal(p12ecx->hmacCx, hmac.data, &hmac.len, SHA1_LENGTH);
2019
if(rv != SECSuccess) {
2020
PORT_SetError(SEC_ERROR_NO_MEMORY);
2024
/* create the digest info */
2025
di = SGN_CreateDigestInfo(p12ecx->p12exp->integrityInfo.pwdInfo.algorithm,
2026
hmac.data, hmac.len);
2028
PORT_SetError(SEC_ERROR_NO_MEMORY);
2033
rv = SGN_CopyDigestInfo(p12ecx->arena, &p12ecx->mac.safeMac, di);
2034
if(rv != SECSuccess) {
2035
PORT_SetError(SEC_ERROR_NO_MEMORY);
2039
/* encode the mac data */
2040
dummy = SEC_ASN1EncodeItem(p12ecx->arena, &p12ecx->pfx.encodedMacData,
2041
&p12ecx->mac, sec_PKCS12MacDataTemplate);
2043
PORT_SetError(SEC_ERROR_NO_MEMORY);
2049
SGN_DestroyDigestInfo(di);
2052
SECITEM_ZfreeItem(&hmac, PR_FALSE);
2054
PK11_DestroyContext(p12ecx->hmacCx, PR_TRUE);
2055
p12ecx->hmacCx = NULL;
2060
/* pfx notify function for ASN1 encoder.
2061
* We want to stop encoding once we reach the authenticated safe.
2062
* At that point, the encoder will be updated via streaming
2063
* as the authenticated safe is encoded.
2066
sec_pkcs12_encoder_pfx_notify(void *arg, PRBool before, void *dest, int real_depth)
2068
sec_PKCS12EncoderContext *p12ecx;
2074
/* look for authenticated safe */
2075
p12ecx = (sec_PKCS12EncoderContext*)arg;
2076
if(dest != &p12ecx->pfx.encodedAuthSafe) {
2080
SEC_ASN1EncoderSetTakeFromBuf(p12ecx->outerA1ecx);
2081
SEC_ASN1EncoderSetStreaming(p12ecx->outerA1ecx);
2082
SEC_ASN1EncoderClearNotifyProc(p12ecx->outerA1ecx);
2086
* Encodes the PFX item and returns it to the output function, via
2087
* callback. the output function must be capable of multiple updates.
2089
* p12exp - the export context
2090
* output - the output function callback, will be called more than once,
2091
* must be able to accept streaming data.
2092
* outputarg - argument for the output callback.
2095
SEC_PKCS12Encode(SEC_PKCS12ExportContext *p12exp,
2096
SEC_PKCS12EncoderOutputCallback output, void *outputarg)
2098
sec_PKCS12EncoderContext *p12enc;
2099
struct sec_pkcs12_encoder_output outInfo;
2102
if(!p12exp || !output) {
2106
/* get the encoder context */
2107
p12enc = sec_pkcs12_encoder_start_context(p12exp);
2112
outInfo.outputfn = output;
2113
outInfo.outputarg = outputarg;
2115
/* set up PFX encoder, the "outer" encoder. Set it for streaming */
2116
p12enc->outerA1ecx = SEC_ASN1EncoderStart(&p12enc->pfx,
2117
sec_PKCS12PFXItemTemplate,
2118
sec_P12A1OutputCB_Outer,
2120
if(!p12enc->outerA1ecx) {
2121
PORT_SetError(SEC_ERROR_NO_MEMORY);
2125
SEC_ASN1EncoderSetStreaming(p12enc->outerA1ecx);
2126
SEC_ASN1EncoderSetNotifyProc(p12enc->outerA1ecx,
2127
sec_pkcs12_encoder_pfx_notify, p12enc);
2128
rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2129
if(rv != SECSuccess) {
2134
/* set up asafe cinfo - the output of the encoder feeds the PFX encoder */
2135
p12enc->middleP7ecx = SEC_PKCS7EncoderStart(p12enc->aSafeCinfo,
2136
sec_P12P7OutputCB_CallA1Update,
2137
p12enc->outerA1ecx, NULL);
2138
if(!p12enc->middleP7ecx) {
2144
p12enc->middleBuf.p7eCx = p12enc->middleP7ecx;
2145
p12enc->middleBuf.hmacCx = NULL;
2146
p12enc->middleBuf.numBytes = 0;
2147
p12enc->middleBuf.bufBytes = sizeof p12enc->middleBuf.buf;
2149
/* Setup the "inner ASN.1 encoder for Authenticated Safes. */
2150
if(p12enc->p12exp->integrityEnabled &&
2151
p12enc->p12exp->pwdIntegrity) {
2152
p12enc->middleBuf.hmacCx = p12enc->hmacCx;
2154
p12enc->middleA1ecx = SEC_ASN1EncoderStart(&p12enc->p12exp->authSafe,
2155
sec_PKCS12AuthenticatedSafeTemplate,
2156
sec_P12A1OutputCB_HmacP7Update,
2157
&p12enc->middleBuf);
2158
if(!p12enc->middleA1ecx) {
2162
SEC_ASN1EncoderSetStreaming(p12enc->middleA1ecx);
2163
SEC_ASN1EncoderSetTakeFromBuf(p12enc->middleA1ecx);
2165
/* encode each of the safes */
2166
while(p12enc->currentSafe != p12enc->p12exp->safeInfoCount) {
2167
sec_pkcs12_encoder_asafe_process(p12enc);
2168
p12enc->currentSafe++;
2170
SEC_ASN1EncoderClearTakeFromBuf(p12enc->middleA1ecx);
2171
SEC_ASN1EncoderClearStreaming(p12enc->middleA1ecx);
2172
SEC_ASN1EncoderUpdate(p12enc->middleA1ecx, NULL, 0);
2173
SEC_ASN1EncoderFinish(p12enc->middleA1ecx);
2175
sec_FlushPkcs12OutputBuffer( &p12enc->middleBuf);
2177
/* finish the encoding of the authenticated safes */
2178
rv = SEC_PKCS7EncoderFinish(p12enc->middleP7ecx, p12exp->pwfn,
2180
if(rv != SECSuccess) {
2184
SEC_ASN1EncoderClearTakeFromBuf(p12enc->outerA1ecx);
2185
SEC_ASN1EncoderClearStreaming(p12enc->outerA1ecx);
2187
/* update the mac, if necessary */
2188
rv = sec_Pkcs12FinishMac(p12enc);
2189
if(rv != SECSuccess) {
2193
/* finish encoding the pfx */
2194
rv = SEC_ASN1EncoderUpdate(p12enc->outerA1ecx, NULL, 0);
2196
SEC_ASN1EncoderFinish(p12enc->outerA1ecx);
2203
SEC_PKCS12DestroyExportContext(SEC_PKCS12ExportContext *p12ecx)
2211
if(p12ecx->safeInfos) {
2213
while(p12ecx->safeInfos[i] != NULL) {
2214
if(p12ecx->safeInfos[i]->encryptionKey) {
2215
PK11_FreeSymKey(p12ecx->safeInfos[i]->encryptionKey);
2217
if(p12ecx->safeInfos[i]->cinfo) {
2218
SEC_PKCS7DestroyContentInfo(p12ecx->safeInfos[i]->cinfo);
2224
PK11_FreeSlot(p12ecx->slot);
2226
PORT_FreeArena(p12ecx->arena, PR_TRUE);
2230
/*********************************
2231
* All-in-one routines for exporting certificates
2232
*********************************/
2233
struct inPlaceEncodeInfo {
2239
sec_pkcs12_in_place_encoder_output(void *arg, const char *buf, unsigned long len)
2241
struct inPlaceEncodeInfo *outInfo = (struct inPlaceEncodeInfo*)arg;
2243
if(!outInfo || !len || outInfo->error) {
2247
if(!outInfo->outItem.data) {
2248
outInfo->outItem.data = (unsigned char*)PORT_ZAlloc(len);
2249
outInfo->outItem.len = 0;
2251
if(!PORT_Realloc(&(outInfo->outItem.data), (outInfo->outItem.len + len))) {
2252
SECITEM_ZfreeItem(&(outInfo->outItem), PR_FALSE);
2253
outInfo->outItem.data = NULL;
2254
PORT_SetError(SEC_ERROR_NO_MEMORY);
2255
outInfo->error = PR_TRUE;
2260
PORT_Memcpy(&(outInfo->outItem.data[outInfo->outItem.len]), buf, len);
2261
outInfo->outItem.len += len;
2267
* SEC_PKCS12ExportCertifcateAndKeyUsingPassword
2268
* Exports a certificate/key pair using password-based encryption and
2271
* pwfn, pwfnarg - password function and argument for the key database
2272
* cert - the certificate to export
2273
* certDb - certificate database
2274
* pwitem - the password to use
2275
* shroudKey - encrypt the key externally,
2276
* keyShroudAlg - encryption algorithm for key
2277
* encryptionAlg - the algorithm with which data is encrypted
2278
* integrityAlg - the algorithm for integrity
2281
SEC_PKCS12ExportCertificateAndKeyUsingPassword(
2282
SECKEYGetPasswordKey pwfn, void *pwfnarg,
2283
CERTCertificate *cert, PK11SlotInfo *slot,
2284
CERTCertDBHandle *certDb, SECItem *pwitem,
2285
PRBool shroudKey, SECOidTag shroudAlg,
2286
PRBool encryptCert, SECOidTag certEncAlg,
2287
SECOidTag integrityAlg, void *wincx)
2289
struct inPlaceEncodeInfo outInfo;
2290
SEC_PKCS12ExportContext *p12ecx = NULL;
2291
SEC_PKCS12SafeInfo *keySafe, *certSafe;
2292
SECItem *returnItem = NULL;
2294
if(!cert || !pwitem || !slot) {
2298
outInfo.error = PR_FALSE;
2299
outInfo.outItem.data = NULL;
2300
outInfo.outItem.len = 0;
2302
p12ecx = SEC_PKCS12CreateExportContext(pwfn, pwfnarg, slot, wincx);
2307
/* set up cert safe */
2309
certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certEncAlg);
2311
certSafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
2317
/* set up key safe */
2319
keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
2327
/* add integrity mode */
2328
if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, integrityAlg)
2333
/* add cert and key pair */
2334
if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, certDb,
2335
keySafe, NULL, shroudKey, pwitem, shroudAlg)
2340
/* encode the puppy */
2341
if(SEC_PKCS12Encode(p12ecx, sec_pkcs12_in_place_encoder_output, &outInfo)
2349
SEC_PKCS12DestroyExportContext(p12ecx);
2351
returnItem = SECITEM_DupItem(&outInfo.outItem);
2352
SECITEM_ZfreeItem(&outInfo.outItem, PR_FALSE);
2357
if(outInfo.outItem.data) {
2358
SECITEM_ZfreeItem(&(outInfo.outItem), PR_TRUE);
2362
SEC_PKCS12DestroyExportContext(p12ecx);