/
pk12util.c
1168 lines (1027 loc) · 35.6 KB
1
2
3
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
7
8
9
#ifdef _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif
10
11
12
13
14
15
#include "nspr.h"
#include "secutil.h"
#include "pk11func.h"
#include "pkcs12.h"
#include "p12plcy.h"
#include "pk12util.h"
16
#include "nss.h"
17
#include "secport.h"
18
#include "secpkcs5.h"
19
#include "certdb.h"
21
#define PKCS12_IN_BUFFER_SIZE 200
23
static char *progName;
24
PRBool pk12_debugging = PR_FALSE;
25
PRBool dumpRawFile;
26
static PRBool pk12uForceUnicode;
27
28
29
PRIntn pk12uErrno = 0;
30
static void
33
#define FPS PR_fprintf(PR_STDERR,
34
FPS "Usage: %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
35
progName);
36
FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
37
FPS "\t\t [-v]\n");
39
FPS "Usage: %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
40
41
progName);
FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
42
FPS "\t\t [-v]\n");
44
45
46
47
48
FPS "Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n",
progName);
FPS "\t\t [-c key_cipher] [-C cert_cipher]\n"
"\t\t [-m | --key_len keyLen] [--cert_key_len certKeyLen] [-v]\n");
FPS "\t\t [-k slotpwfile | -K slotpw]\n"
49
"\t\t [-w p12filepwfile | -W p12filepw]\n");
51
exit(PK12UERR_USAGE);
52
53
54
}
static PRBool
55
p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
57
58
if (!p12cxt || !p12cxt->filename) {
return PR_FALSE;
61
62
63
if (fileRead) {
p12cxt->file = PR_Open(p12cxt->filename,
PR_RDONLY, 0400);
64
} else {
65
66
67
p12cxt->file = PR_Open(p12cxt->filename,
PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
0600);
70
71
72
if (!p12cxt->file) {
p12cxt->error = PR_TRUE;
return PR_FALSE;
75
return PR_TRUE;
76
77
78
}
static void
79
p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
81
82
if (!ppCtx || !(*ppCtx)) {
return;
85
86
if ((*ppCtx)->file != NULL) {
PR_Close((*ppCtx)->file);
89
90
91
92
93
94
if ((*ppCtx)->filename != NULL) {
if (removeFile) {
PR_Delete((*ppCtx)->filename);
}
PL_strfree((*ppCtx)->filename);
(*ppCtx)->filename = NULL;
97
98
PR_Free(*ppCtx);
*ppCtx = NULL;
99
100
101
}
static p12uContext *
102
p12u_InitContext(PRBool fileImport, char *filename)
104
p12uContext *p12cxt;
106
p12cxt = PORT_ZNew(p12uContext);
107
108
if (!p12cxt) {
return NULL;
111
112
p12cxt->error = PR_FALSE;
p12cxt->errorValue = 0;
113
p12cxt->filename = PL_strdup(filename);
115
116
117
if (!p12u_OpenFile(p12cxt, fileImport)) {
p12u_DestroyContext(&p12cxt, PR_FALSE);
return NULL;
120
return p12cxt;
121
122
123
124
125
}
SECItem *
P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx)
{
126
127
128
char *nick = NULL;
SECItem *ret_nick = NULL;
CERTCertificate *cert = (CERTCertificate *)wincx;
129
130
if (!cancel || !cert) {
131
132
pk12uErrno = PK12UERR_USER_CANCELLED;
return NULL;
135
if (!old_nick)
136
fprintf(stdout, "pk12util: no nickname for cert in PKCS12 file.\n");
139
140
141
/* XXX not handled yet */
*cancel = PR_TRUE;
return NULL;
145
nick = CERT_MakeCANickname(cert);
147
return NULL;
150
151
152
153
154
155
if (old_nick && old_nick->data && old_nick->len &&
PORT_Strlen(nick) == old_nick->len &&
!PORT_Strncmp((char *)old_nick->data, nick, old_nick->len)) {
PORT_Free(nick);
PORT_SetError(SEC_ERROR_IO);
return NULL;
158
159
fprintf(stdout, "pk12util: using nickname: %s\n", nick);
ret_nick = PORT_ZNew(SECItem);
160
161
162
if (ret_nick == NULL) {
PORT_Free(nick);
return NULL;
165
166
ret_nick->data = (unsigned char *)nick;
ret_nick->len = PORT_Strlen(nick);
168
return ret_nick;
169
170
171
172
173
174
#endif
}
static SECStatus
p12u_SwapUnicodeBytes(SECItem *uniItem)
{
175
176
unsigned int i;
unsigned char a;
177
178
if ((uniItem == NULL) || (uniItem->len % 2)) {
return SECFailure;
180
181
182
183
for (i = 0; i < uniItem->len; i += 2) {
a = uniItem->data[i];
uniItem->data[i] = uniItem->data[i + 1];
uniItem->data[i + 1] = a;
184
185
}
return SECSuccess;
188
static PRBool
189
190
191
192
193
194
195
p12u_ucs2_ascii_conversion_function(PRBool toUnicode,
unsigned char *inBuf,
unsigned int inBufLen,
unsigned char *outBuf,
unsigned int maxOutBufLen,
unsigned int *outBufLen,
PRBool swapBytes)
196
197
198
199
{
SECItem it = { 0 };
SECItem *dup = NULL;
PRBool ret;
200
201
#ifdef DEBUG_CONVERSION
202
if (pk12_debugging) {
203
204
205
206
207
208
209
int i;
printf("Converted from:\n");
for (i = 0; i < inBufLen; i++) {
printf("%2x ", inBuf[i]);
/*if (i%60 == 0) printf("\n");*/
}
printf("\n");
212
213
214
it.data = inBuf;
it.len = inBufLen;
dup = SECITEM_DupItem(&it);
215
216
217
if (!dup) {
return PR_FALSE;
}
218
219
220
/* If converting Unicode to ASCII, swap bytes before conversion
* as neccessary.
*/
221
if (!toUnicode && swapBytes) {
222
223
224
225
if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
SECITEM_ZfreeItem(dup, PR_TRUE);
return PR_FALSE;
}
226
227
}
/* Perform the conversion. */
228
229
ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
outBuf, maxOutBufLen, outBufLen);
230
SECITEM_ZfreeItem(dup, PR_TRUE);
231
232
#ifdef DEBUG_CONVERSION
233
if (pk12_debugging) {
234
235
236
237
238
239
240
int i;
printf("Converted to:\n");
for (i = 0; i < *outBufLen; i++) {
printf("%2x ", outBuf[i]);
/*if (i%60 == 0) printf("\n");*/
}
printf("\n");
243
244
return ret;
}
246
SECStatus
247
P12U_UnicodeConversion(PLArenaPool *arena, SECItem *dest, SECItem *src,
248
PRBool toUnicode, PRBool swapBytes)
249
250
{
unsigned int allocLen;
251
252
if (!dest || !src) {
return SECFailure;
253
254
}
allocLen = ((toUnicode) ? (src->len << 2) : src->len);
255
256
if (arena) {
dest->data = PORT_ArenaZAlloc(arena, allocLen);
257
} else {
258
dest->data = PORT_ZAlloc(allocLen);
260
261
262
263
264
265
266
267
if (PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len,
dest->data, allocLen, &dest->len,
swapBytes) == PR_FALSE) {
if (!arena) {
PORT_Free(dest->data);
}
dest->data = NULL;
return SECFailure;
268
269
}
return SECSuccess;
270
271
272
273
274
275
276
277
}
/*
*
*/
SECItem *
P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
{
278
char *p0 = NULL;
279
280
281
SECItem *pwItem = NULL;
if (p12FilePw == NULL || p12FilePw->source == PW_NONE) {
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
char *p1 = NULL;
int rc;
for (;;) {
p0 = SECU_GetPasswordString(NULL,
"Enter password for PKCS12 file: ");
if (!confirmPw || p0 == NULL)
break;
p1 = SECU_GetPasswordString(NULL, "Re-enter password: ");
if (p1 == NULL) {
PORT_ZFree(p0, PL_strlen(p0));
p0 = NULL;
break;
}
rc = PL_strcmp(p0, p1);
PORT_ZFree(p1, PL_strlen(p1));
if (rc == 0)
break;
PORT_ZFree(p0, PL_strlen(p0));
}
301
} else if (p12FilePw->source == PW_FROMFILE) {
302
p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data);
303
} else { /* Plaintext */
304
p0 = PORT_Strdup(p12FilePw->data);
307
308
309
if (p0 == NULL) {
return NULL;
}
310
311
pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1);
memcpy(pwItem->data, p0, pwItem->len);
313
PORT_ZFree(p0, PL_strlen(p0));
315
return pwItem;
316
317
318
319
320
}
SECStatus
P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw)
{
321
SECStatus rv;
323
324
/* New databases, initialize keydb password. */
if (PK11_NeedUserInit(slot)) {
325
326
327
328
329
330
331
332
rv = SECU_ChangePW(slot,
(slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0,
(slotPw->source == PW_FROMFILE) ? slotPw->data : 0);
if (rv != SECSuccess) {
SECU_PrintError(progName, "Failed to initialize slot \"%s\"",
PK11_GetSlotName(slot));
return SECFailure;
}
335
if (PK11_Authenticate(slot, PR_TRUE, slotPw) != SECSuccess) {
336
337
338
339
340
SECU_PrintError(progName,
"Failed to authenticate to PKCS11 slot");
PORT_SetError(SEC_ERROR_USER_CANCELLED);
pk12uErrno = PK12UERR_USER_CANCELLED;
return SECFailure;
341
342
343
}
return SECSuccess;
346
347
348
349
/* This routine takes care of getting the PKCS12 file password, then reading and
* verifying the file. It returns the decoder context and a filled in password.
* (The password is needed by P12U_ImportPKCS12Object() to import the private
* key.)
351
352
353
SEC_PKCS12DecoderContext *
p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot,
secuPWData *slotPw, secuPWData *p12FilePw)
355
SEC_PKCS12DecoderContext *p12dcx = NULL;
356
357
p12uContext *p12cxt = NULL;
SECItem *pwitem = NULL;
358
359
360
SECItem p12file = { 0 };
SECStatus rv = SECFailure;
PRBool swapUnicode = PR_FALSE;
361
PRBool forceUnicode = pk12uForceUnicode;
362
PRBool trypw;
363
int error;
365
#ifdef IS_LITTLE_ENDIAN
366
swapUnicode = PR_TRUE;
367
368
#endif
369
p12cxt = p12u_InitContext(PR_TRUE, in_file);
370
371
372
if (!p12cxt) {
SECU_PrintError(progName, "File Open failed: %s", in_file);
pk12uErrno = PK12UERR_INIT_FILE;
373
return NULL;
374
375
376
377
378
}
/* get the password */
pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
if (!pwitem) {
379
380
pk12uErrno = PK12UERR_USER_CANCELLED;
goto done;
381
382
}
383
384
385
386
387
if (P12U_UnicodeConversion(NULL, uniPwp, pwitem, PR_TRUE,
swapUnicode) != SECSuccess) {
SECU_PrintError(progName, "Unicode conversion failed");
pk12uErrno = PK12UERR_UNICODECONV;
goto done;
389
390
rv = SECU_FileToItem(&p12file, p12cxt->file);
if (rv != SECSuccess) {
391
SECU_PrintError(progName, "Failed to read from import file");
393
394
}
396
trypw = PR_FALSE; /* normally we do this once */
397
398
399
400
rv = SECFailure;
/* init the decoder context */
p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw,
NULL, NULL, NULL, NULL, NULL);
401
402
if (!p12dcx) {
SECU_PrintError(progName, "PKCS12 decoder start failed");
403
404
405
406
407
408
409
pk12uErrno = PK12UERR_PK12DECODESTART;
break;
}
/* decode the item */
rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
410
if (rv != SECSuccess) {
411
error = PR_GetError();
412
if (error == SEC_ERROR_DECRYPTION_DISALLOWED) {
413
414
415
PR_SetError(error, 0);
break;
}
416
SECU_PrintError(progName, "PKCS12 decoding failed");
417
418
419
420
421
422
pk12uErrno = PK12UERR_DECODE;
}
/* does the blob authenticate properly? */
rv = SEC_PKCS12DecoderVerify(p12dcx);
if (rv != SECSuccess) {
423
if (uniPwp->len == 2) {
424
425
426
427
428
/* this is a null PW, try once more with a zero-length PW
instead of a null string */
SEC_PKCS12DecoderFinish(p12dcx);
uniPwp->len = 0;
trypw = PR_TRUE;
429
430
431
432
433
434
435
436
437
438
439
440
} else if (forceUnicode == pk12uForceUnicode) {
/* try again with a different password encoding */
forceUnicode = !pk12uForceUnicode;
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
forceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decoding failed to set option");
pk12uErrno = PK12UERR_DECODEVERIFY;
break;
}
SEC_PKCS12DecoderFinish(p12dcx);
trypw = PR_TRUE;
441
442
} else {
SECU_PrintError(progName, "PKCS12 decode not verified");
443
444
445
446
447
pk12uErrno = PK12UERR_DECODEVERIFY;
break;
}
}
} while (trypw == PR_TRUE);
448
449
450
451
452
453
454
455
456
/* revert the option setting */
if (forceUnicode != pk12uForceUnicode) {
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decoding failed to set option");
pk12uErrno = PK12UERR_DECODEVERIFY;
}
}
457
/* rv has been set at this point */
460
if (rv != SECSuccess) {
461
462
463
464
465
466
467
468
if (p12dcx != NULL) {
SEC_PKCS12DecoderFinish(p12dcx);
p12dcx = NULL;
}
if (uniPwp->data) {
SECITEM_ZfreeItem(uniPwp, PR_FALSE);
uniPwp->data = NULL;
}
470
471
472
473
PR_Close(p12cxt->file);
p12cxt->file = NULL;
/* PK11_FreeSlot(slot); */
p12u_DestroyContext(&p12cxt, PR_FALSE);
475
if (pwitem) {
476
SECITEM_ZfreeItem(pwitem, PR_TRUE);
478
SECITEM_ZfreeItem(&p12file, PR_FALSE);
479
480
return p12dcx;
}
482
483
484
485
486
487
488
489
490
491
/*
* given a filename for pkcs12 file, imports certs and keys
*
* Change: altitude
* I've changed this function so that it takes the keydb and pkcs12 file
* passwords from files. The "pwdKeyDB" and "pwdP12File"
* variables have been added for this purpose.
*/
PRIntn
P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
492
secuPWData *slotPw, secuPWData *p12FilePw)
493
494
495
{
SEC_PKCS12DecoderContext *p12dcx = NULL;
SECItem uniPwitem = { 0 };
496
497
PRBool forceUnicode = pk12uForceUnicode;
PRBool trypw;
498
SECStatus rv = SECFailure;
500
501
rv = P12U_InitSlot(slot, slotPw);
if (rv != SECSuccess) {
502
503
504
505
SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
PK11_GetSlotName(slot));
pk12uErrno = PK12UERR_PK11GETSLOT;
return rv;
506
507
}
508
509
510
511
do {
trypw = PR_FALSE; /* normally we do this once */
rv = SECFailure;
p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
513
514
515
if (p12dcx == NULL) {
goto loser;
}
517
518
519
520
521
522
523
524
525
526
/* make sure the bags are okey dokey -- nicknames correct, etc. */
rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
if (rv != SECSuccess) {
if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
pk12uErrno = PK12UERR_CERTALREADYEXISTS;
} else {
pk12uErrno = PK12UERR_DECODEVALIBAGS;
}
SECU_PrintError(progName, "PKCS12 decode validate bags failed");
goto loser;
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
/* stuff 'em in */
if (forceUnicode != pk12uForceUnicode) {
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE,
forceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decode set option failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
}
}
rv = SEC_PKCS12DecoderImportBags(p12dcx);
if (rv != SECSuccess) {
if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY &&
forceUnicode == pk12uForceUnicode) {
/* try again with a different password encoding */
forceUnicode = !pk12uForceUnicode;
SEC_PKCS12DecoderFinish(p12dcx);
SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
trypw = PR_TRUE;
} else {
SECU_PrintError(progName, "PKCS12 decode import bags failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
}
}
} while (trypw);
/* revert the option setting */
if (forceUnicode != pk12uForceUnicode) {
rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE, pk12uForceUnicode);
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decode set option failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
goto loser;
}
566
fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
567
rv = SECSuccess;
568
569
loser:
570
if (p12dcx) {
571
SEC_PKCS12DecoderFinish(p12dcx);
574
if (uniPwitem.data) {
575
SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
578
return rv;
579
580
581
582
583
}
static void
p12u_DoPKCS12ExportErrors()
{
584
PRErrorCode error_value;
585
586
587
error_value = PORT_GetError();
if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) ||
588
589
590
591
592
(error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) ||
(error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) {
fputs(SECU_Strerror(error_value), stderr);
} else if (error_value == SEC_ERROR_USER_CANCELLED) {
;
593
} else {
594
fputs(SECU_Strerror(SEC_ERROR_EXPORTING_CERTIFICATES), stderr);
596
597
598
599
600
}
static void
p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
{
601
602
p12uContext *p12cxt = arg;
int writeLen;
604
605
if (!p12cxt || (p12cxt->error == PR_TRUE)) {
return;
608
609
610
611
if (p12cxt->file == NULL) {
p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
p12cxt->error = PR_TRUE;
return;
614
writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (PRInt32)len);
616
617
618
619
620
621
622
if (writeLen != (int)len) {
PR_Close(p12cxt->file);
PL_strfree(p12cxt->filename);
p12cxt->filename = NULL;
p12cxt->file = NULL;
p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
p12cxt->error = PR_TRUE;
624
625
626
}
void
627
P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
628
629
SECOidTag cipher, SECOidTag certCipher,
secuPWData *slotPw, secuPWData *p12FilePw)
630
631
632
633
634
{
SEC_PKCS12ExportContext *p12ecx = NULL;
SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
SECItem *pwitem = NULL;
p12uContext *p12cxt = NULL;
635
636
637
CERTCertList *certlist = NULL;
CERTCertListNode *node = NULL;
PK11SlotInfo *slot = NULL;
639
if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) {
640
641
642
643
SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
PK11_GetSlotName(inSlot));
pk12uErrno = PK12UERR_PK11GETSLOT;
goto loser;
645
certlist = PK11_FindCertsFromNickname(nn, slotPw);
646
647
648
649
if (!certlist) {
SECU_PrintError(progName, "find user certs from nickname failed");
pk12uErrno = PK12UERR_FINDCERTBYNN;
return;
650
651
}
652
653
if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) ||
CERT_LIST_EMPTY(certlist)) {
654
655
PR_fprintf(PR_STDERR, "%s: no user certs from given nickname\n",
progName);
656
pk12uErrno = PK12UERR_FINDCERTBYNN;
660
661
/* Password to use for PKCS12 file. */
pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
662
663
if (!pwitem) {
goto loser;
664
665
}
666
667
668
669
670
p12cxt = p12u_InitContext(PR_FALSE, outfile);
if (!p12cxt) {
SECU_PrintError(progName, "Initialization failed: %s", outfile);
pk12uErrno = PK12UERR_INIT_FILE;
goto loser;
671
672
}
673
if (certlist) {
674
CERTCertificate *cert = CERT_LIST_HEAD(certlist)->cert;
675
676
677
678
if (cert) {
slot = cert->slot; /* use the slot from the first matching
certificate to create the context . This is for keygen */
}
680
if (!slot) {
681
SECU_PrintError(progName, "cert does not have a slot");
682
683
pk12uErrno = PK12UERR_FINDCERTBYNN;
goto loser;
685
p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw);
686
687
if (!p12ecx) {
SECU_PrintError(progName, "export context creation failed");
688
689
pk12uErrno = PK12UERR_EXPORTCXCREATE;
goto loser;
690
691
}
692
693
694
if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, SEC_OID_SHA1) !=
SECSuccess) {
SECU_PrintError(progName, "PKCS12 add password integrity failed");
695
696
697
698
pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
goto loser;
}
699
for (node = CERT_LIST_HEAD(certlist);
700
701
702
!CERT_LIST_END(node, certlist);
node = CERT_LIST_NEXT(node)) {
CERTCertificate *cert = node->cert;
703
if (!cert->slot) {
704
SECU_PrintError(progName, "cert does not have a slot");
705
706
707
pk12uErrno = PK12UERR_FINDCERTBYNN;
goto loser;
}
709
keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
710
if (certCipher == SEC_OID_UNKNOWN) {
711
712
certSafe = keySafe;
} else {
713
714
certSafe =
SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certCipher);
716
717
718
if (!certSafe || !keySafe) {
SECU_PrintError(progName, "key or cert safe creation failed");
719
720
721
pk12uErrno = PK12UERR_CERTKEYSAFE;
goto loser;
}
722
723
724
725
726
727
728
if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem, cipher) !=
SECSuccess) {
SECU_PrintError(progName, "add cert and key failed");
pk12uErrno = PK12UERR_ADDCERTKEY;
goto loser;
730
731
}
732
733
734
CERT_DestroyCertList(certlist);
certlist = NULL;
735
736
737
if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt) !=
SECSuccess) {
SECU_PrintError(progName, "PKCS12 encode failed");
738
739
pk12uErrno = PK12UERR_ENCODE;
goto loser;
740
741
}
742
p12u_DestroyContext(&p12cxt, PR_FALSE);
743
744
745
SECITEM_ZfreeItem(pwitem, PR_TRUE);
fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName);
SEC_PKCS12DestroyExportContext(p12ecx);
747
return;
748
749
loser:
750
SEC_PKCS12DestroyExportContext(p12ecx);
752
753
754
if (certlist) {
CERT_DestroyCertList(certlist);
certlist = NULL;
757
p12u_DestroyContext(&p12cxt, PR_TRUE);
758
if (pwitem) {
759
SECITEM_ZfreeItem(pwitem, PR_TRUE);
760
761
762
}
p12u_DoPKCS12ExportErrors();
return;
765
766
PRIntn
P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
767
secuPWData *slotPw, secuPWData *p12FilePw)
768
769
{
SEC_PKCS12DecoderContext *p12dcx = NULL;
770
SECItem uniPwitem = { 0 };
771
772
773
SECStatus rv = SECFailure;
const SEC_PKCS12DecoderItem *dip;
774
p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
775
/* did the blob authenticate properly? */
776
777
778
if (p12dcx == NULL) {
SECU_PrintError(progName, "PKCS12 decode not verified");
pk12uErrno = PK12UERR_DECODEVERIFY;
779
goto loser;
781
rv = SEC_PKCS12DecoderIterateInit(p12dcx);
782
783
784
if (rv != SECSuccess) {
SECU_PrintError(progName, "PKCS12 decode iterate bags failed");
pk12uErrno = PK12UERR_DECODEIMPTBAGS;
785
rv = SECFailure;
787
int fileCounter = 0;
788
789
790
791
while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
switch (dip->type) {
case SEC_OID_PKCS12_V1_CERT_BAG_ID:
printf("Certificate");
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
if (dumpRawFile) {
PRFileDesc *fd;
char fileName[20];
sprintf(fileName, "file%04d.der", ++fileCounter);
fd = PR_Open(fileName,
PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
0600);
if (!fd) {
SECU_PrintError(progName,
"Cannot create output file");
} else {
PR_Write(fd, dip->der->data, dip->der->len);
PR_Close(fd);
}
} else if (SECU_PrintSignedData(stdout, dip->der,
807
(dip->hasKey) ? "(has private key)"
808
809
810
811
: "",
0, (SECU_PPFunc)SECU_PrintCertificate) !=
0) {
SECU_PrintError(progName, "PKCS12 print cert bag failed");
812
813
814
}
if (dip->friendlyName != NULL) {
printf(" Friendly Name: %s\n\n",
815
816
817
818
819
dip->friendlyName->data);
}
if (dip->shroudAlg) {
SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
"Encryption algorithm", 1);
820
821
822
823
824
825
826
827
828
829
}
break;
case SEC_OID_PKCS12_V1_KEY_BAG_ID:
case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
printf("Key");
if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
printf("(shrouded)");
printf(":\n");
if (dip->friendlyName != NULL) {
printf(" Friendly Name: %s\n\n",
830
831
832
833
834
dip->friendlyName->data);
}
if (dip->shroudAlg) {
SECU_PrintAlgorithmID(stdout, dip->shroudAlg,
"Encryption algorithm", 1);
835
836
837
838
}
break;
default:
printf("unknown bag type(%d): %s\n\n", dip->type,
839
SECOID_FindOIDTagDescription(dip->type));
840
841
842
843
844
845
846
break;
}
}
rv = SECSuccess;
}
loser:
848
if (p12dcx) {
849
SEC_PKCS12DecoderFinish(p12dcx);
852
if (uniPwitem.data) {
853
SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
856
857
858
return rv;
}
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
/*
* use the oid table description to map a user input string to a particular
* oid.
*/
SECOidTag
PKCS12U_MapCipherFromString(char *cipherString, int keyLen)
{
SECOidTag tag;
SECOidData *oid;
SECOidTag cipher;
/* future enhancement: accept dotted oid spec? */
/* future enhancement: provide 'friendlier' typed in names for
* pbe mechanisms.
*/
/* look for the oid tag by Description */
cipher = SEC_OID_UNKNOWN;
878
879
880
881
882
883
884
885
886
for (tag = 1; (oid = SECOID_FindOIDByTag(tag)) != NULL; tag++) {
/* only interested in oids that we actually understand */
if (oid->mechanism == CKM_INVALID_MECHANISM) {
continue;
}
if (PORT_Strcasecmp(oid->desc, cipherString) != 0) {
continue;
}
/* we found a match... get the PBE version of this
887
* cipher... */
888
889
890
if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) {
cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen);
/* no eqivalent PKCS5/PKCS12 cipher, use the raw
891
892
* encryption tag we got and pass it directly in,
* pkcs12 will use the pkcsv5 mechanism */
893
894
895
896
897
898
899
900
901
902
if (cipher == SEC_OID_PKCS5_PBES2) {
cipher = tag;
} else if (cipher == SEC_OID_PKCS5_PBMAC1) {
/* make sure we have not macing ciphers here */
cipher = SEC_OID_UNKNOWN;
}
} else {
cipher = tag;
}
break;
903
904
905
906
}
return cipher;
}
907
908
909
910
911
912
913
914
915
static void
p12u_EnableAllCiphers()
{
SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
916
917
918
SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128, 1);
SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192, 1);
SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256, 1);
919
920
921
SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
}
922
static PRUintn
923
P12U_Init(char *dir, char *dbprefix, PRBool listonly)
926
PK11_SetPasswordFunc(SECU_GetModulePassword);
928
PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
929
930
if (listonly && NSS_NoDB_Init("") == SECSuccess) {
rv = SECSuccess;
931
932
} else {
rv = NSS_Initialize(dir, dbprefix, dbprefix, "secmod.db", 0);
934
if (rv != SECSuccess) {
935
SECU_PrintPRandOSError(progName);
936
937
938
exit(-1);
}
939
940
/* setup unicode callback functions */
PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
941
942
943
/* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
p12u_EnableAllCiphers();
944
945
return 0;
946
947
948
}
enum {
949
950
951
952
953
opt_CertDir = 0,
opt_TokenName,
opt_Import,
opt_SlotPWFile,
opt_SlotPW,
955
956
opt_Nickname,
opt_Export,
958
opt_P12FilePWFile,
959
opt_P12FilePW,
960
opt_DBPrefix,
961
962
963
964
965
opt_Debug,
opt_Cipher,
opt_CertCipher,
opt_KeyLength,
opt_CertKeyLength
966
967
968
};
static secuCommandFlag pk12util_options[] =
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
{
{ /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE },
{ /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE },
{ /* opt_Import */ 'i', PR_TRUE, 0, PR_FALSE },
{ /* opt_SlotPWFile */ 'k', PR_TRUE, 0, PR_FALSE },
{ /* opt_SlotPW */ 'K', PR_TRUE, 0, PR_FALSE },
{ /* opt_List */ 'l', PR_TRUE, 0, PR_FALSE },
{ /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE },
{ /* opt_Export */ 'o', PR_TRUE, 0, PR_FALSE },
{ /* opt_Raw */ 'r', PR_FALSE, 0, PR_FALSE },
{ /* opt_P12FilePWFile */ 'w', PR_TRUE, 0, PR_FALSE },
{ /* opt_P12FilePW */ 'W', PR_TRUE, 0, PR_FALSE },
{ /* opt_DBPrefix */ 'P', PR_TRUE, 0, PR_FALSE },
{ /* opt_Debug */ 'v', PR_FALSE, 0, PR_FALSE },
{ /* opt_Cipher */ 'c', PR_TRUE, 0, PR_FALSE },
{ /* opt_CertCipher */ 'C', PR_TRUE, 0, PR_FALSE },
{ /* opt_KeyLength */ 'm', PR_TRUE, 0, PR_FALSE, "key_len" },
{ /* opt_CertKeyLength */ 0, PR_TRUE, 0, PR_FALSE, "cert_key_len" }
};
988
989
990
991
int
main(int argc, char **argv)
{
992
993
994
995
996
997
secuPWData slotPw = { PW_NONE, NULL };
secuPWData p12FilePw = { PW_NONE, NULL };
PK11SlotInfo *slot;
char *slotname = NULL;
char *import_file = NULL;
char *export_file = NULL;
998
char *dbprefix = "";
999
SECStatus rv;
1000
SECOidTag cipher =