File: | s/cmd/pk12util/pk12util.c |
Warning: | line 913, column 5 Value stored to 'cipher' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | #ifdef _CRTDBG_MAP_ALLOC |
6 | #include <stdlib.h> |
7 | #include <crtdbg.h> |
8 | #endif |
9 | |
10 | #include "nspr.h" |
11 | #include "secutil.h" |
12 | #include "pk11func.h" |
13 | #include "pkcs12.h" |
14 | #include "p12plcy.h" |
15 | #include "pk12util.h" |
16 | #include "nss.h" |
17 | #include "secport.h" |
18 | #include "secpkcs5.h" |
19 | #include "sechash.h" |
20 | #include "certdb.h" |
21 | |
22 | #define PKCS12_IN_BUFFER_SIZE200 200 |
23 | |
24 | static char *progName; |
25 | PRBool pk12_debugging = PR_FALSE0; |
26 | PRBool dumpRawFile; |
27 | static PRBool pk12uForceUnicode; |
28 | |
29 | PRIntn pk12uErrno = 0; |
30 | |
31 | static void |
32 | Usage() |
33 | { |
34 | #define FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), |
35 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "Usage: %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname]\n", |
36 | progName); |
37 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n"); |
38 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "\t\t [-v]\n"); |
39 | |
40 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "Usage: %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname]\n", |
41 | progName); |
42 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n"); |
43 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "\t\t [-v]\n"); |
44 | |
45 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n", |
46 | progName); |
47 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "\t\t [-c key_cipher] [-C cert_cipher] [-M mac_alg]\n" |
48 | "\t\t [-m | --key_len keyLen] [--cert_key_len certKeyLen] [-v]\n"); |
49 | FPSPR_fprintf(PR_GetSpecialFD(PR_StandardError), "\t\t [-k slotpwfile | -K slotpw]\n" |
50 | "\t\t [-w p12filepwfile | -W p12filepw]\n"); |
51 | |
52 | exit(PK12UERR_USAGE2); |
53 | } |
54 | |
55 | static PRBool |
56 | p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead) |
57 | { |
58 | if (!p12cxt || !p12cxt->filename) { |
59 | return PR_FALSE0; |
60 | } |
61 | |
62 | if (fileRead) { |
63 | p12cxt->file = PR_Open(p12cxt->filename, |
64 | PR_RDONLY0x01, 0400); |
65 | } else { |
66 | p12cxt->file = PR_Open(p12cxt->filename, |
67 | PR_CREATE_FILE0x08 | PR_RDWR0x04 | PR_TRUNCATE0x20, |
68 | 0600); |
69 | } |
70 | |
71 | if (!p12cxt->file) { |
72 | p12cxt->error = PR_TRUE1; |
73 | return PR_FALSE0; |
74 | } |
75 | |
76 | return PR_TRUE1; |
77 | } |
78 | |
79 | static void |
80 | p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile) |
81 | { |
82 | if (!ppCtx || !(*ppCtx)) { |
83 | return; |
84 | } |
85 | |
86 | if ((*ppCtx)->file != NULL((void*)0)) { |
87 | PR_Close((*ppCtx)->file); |
88 | } |
89 | |
90 | if ((*ppCtx)->filename != NULL((void*)0)) { |
91 | if (removeFile) { |
92 | PR_Delete((*ppCtx)->filename); |
93 | } |
94 | PL_strfree((*ppCtx)->filename); |
95 | (*ppCtx)->filename = NULL((void*)0); |
96 | } |
97 | |
98 | PR_Free(*ppCtx); |
99 | *ppCtx = NULL((void*)0); |
100 | } |
101 | |
102 | static p12uContext * |
103 | p12u_InitContext(PRBool fileImport, char *filename) |
104 | { |
105 | p12uContext *p12cxt; |
106 | |
107 | p12cxt = PORT_ZNew(p12uContext)(p12uContext *)PORT_ZAlloc_Util(sizeof(p12uContext)); |
108 | if (!p12cxt) { |
109 | return NULL((void*)0); |
110 | } |
111 | |
112 | p12cxt->error = PR_FALSE0; |
113 | p12cxt->errorValue = 0; |
114 | p12cxt->filename = PL_strdup(filename); |
115 | |
116 | if (!p12u_OpenFile(p12cxt, fileImport)) { |
117 | p12u_DestroyContext(&p12cxt, PR_FALSE0); |
118 | return NULL((void*)0); |
119 | } |
120 | |
121 | return p12cxt; |
122 | } |
123 | |
124 | SECItem * |
125 | P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx) |
126 | { |
127 | char *nick = NULL((void*)0); |
128 | SECItem *ret_nick = NULL((void*)0); |
129 | CERTCertificate *cert = (CERTCertificate *)wincx; |
130 | |
131 | if (!cancel || !cert) { |
132 | pk12uErrno = PK12UERR_USER_CANCELLED1; |
133 | return NULL((void*)0); |
134 | } |
135 | |
136 | if (!old_nick) |
137 | fprintf(stdoutstdout, "pk12util: no nickname for cert in PKCS12 file.\n"); |
138 | |
139 | #if 0 |
140 | /* XXX not handled yet */ |
141 | *cancel = PR_TRUE1; |
142 | return NULL((void*)0); |
143 | |
144 | #else |
145 | |
146 | nick = CERT_MakeCANickname(cert); |
147 | if (!nick) { |
148 | return NULL((void*)0); |
149 | } |
150 | |
151 | if (old_nick && old_nick->data && old_nick->len && |
152 | PORT_Strlen(nick)strlen(nick) == old_nick->len && |
153 | !PORT_Strncmpstrncmp((char *)old_nick->data, nick, old_nick->len)) { |
154 | PORT_FreePORT_Free_Util(nick); |
155 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_IO); |
156 | return NULL((void*)0); |
157 | } |
158 | |
159 | fprintf(stdoutstdout, "pk12util: using nickname: %s\n", nick); |
160 | ret_nick = PORT_ZNew(SECItem)(SECItem *)PORT_ZAlloc_Util(sizeof(SECItem)); |
161 | if (ret_nick == NULL((void*)0)) { |
162 | PORT_FreePORT_Free_Util(nick); |
163 | return NULL((void*)0); |
164 | } |
165 | |
166 | ret_nick->data = (unsigned char *)nick; |
167 | ret_nick->len = PORT_Strlen(nick)strlen(nick); |
168 | |
169 | return ret_nick; |
170 | #endif |
171 | } |
172 | |
173 | static SECStatus |
174 | p12u_SwapUnicodeBytes(SECItem *uniItem) |
175 | { |
176 | unsigned int i; |
177 | unsigned char a; |
178 | if ((uniItem == NULL((void*)0)) || (uniItem->len % 2)) { |
179 | return SECFailure; |
180 | } |
181 | for (i = 0; i < uniItem->len; i += 2) { |
182 | a = uniItem->data[i]; |
183 | uniItem->data[i] = uniItem->data[i + 1]; |
184 | uniItem->data[i + 1] = a; |
185 | } |
186 | return SECSuccess; |
187 | } |
188 | |
189 | static PRBool |
190 | p12u_ucs2_ascii_conversion_function(PRBool toUnicode, |
191 | unsigned char *inBuf, |
192 | unsigned int inBufLen, |
193 | unsigned char *outBuf, |
194 | unsigned int maxOutBufLen, |
195 | unsigned int *outBufLen, |
196 | PRBool swapBytes) |
197 | { |
198 | SECItem it = { 0 }; |
199 | SECItem *dup = NULL((void*)0); |
200 | PRBool ret; |
201 | |
202 | #ifdef DEBUG_CONVERSION |
203 | if (pk12_debugging) { |
204 | int i; |
205 | printf("Converted from:\n"); |
206 | for (i = 0; i < inBufLen; i++) { |
207 | printf("%2x ", inBuf[i]); |
208 | /*if (i%60 == 0) printf("\n");*/ |
209 | } |
210 | printf("\n"); |
211 | } |
212 | #endif |
213 | it.data = inBuf; |
214 | it.len = inBufLen; |
215 | dup = SECITEM_DupItemSECITEM_DupItem_Util(&it); |
216 | if (!dup) { |
217 | return PR_FALSE0; |
218 | } |
219 | /* If converting Unicode to ASCII, swap bytes before conversion |
220 | * as neccessary. |
221 | */ |
222 | if (!toUnicode && swapBytes) { |
223 | if (p12u_SwapUnicodeBytes(dup) != SECSuccess) { |
224 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(dup, PR_TRUE1); |
225 | return PR_FALSE0; |
226 | } |
227 | } |
228 | /* Perform the conversion. */ |
229 | ret = PORT_UCS2_UTF8ConversionPORT_UCS2_UTF8Conversion_Util(toUnicode, dup->data, dup->len, |
230 | outBuf, maxOutBufLen, outBufLen); |
231 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(dup, PR_TRUE1); |
232 | |
233 | #ifdef DEBUG_CONVERSION |
234 | if (pk12_debugging) { |
235 | int i; |
236 | printf("Converted to:\n"); |
237 | for (i = 0; i < *outBufLen; i++) { |
238 | printf("%2x ", outBuf[i]); |
239 | /*if (i%60 == 0) printf("\n");*/ |
240 | } |
241 | printf("\n"); |
242 | } |
243 | #endif |
244 | return ret; |
245 | } |
246 | |
247 | SECStatus |
248 | P12U_UnicodeConversion(PLArenaPool *arena, SECItem *dest, SECItem *src, |
249 | PRBool toUnicode, PRBool swapBytes) |
250 | { |
251 | unsigned int allocLen; |
252 | if (!dest || !src) { |
253 | return SECFailure; |
254 | } |
255 | allocLen = ((toUnicode) ? (src->len << 2) : src->len); |
256 | if (arena) { |
257 | dest->data = PORT_ArenaZAllocPORT_ArenaZAlloc_Util(arena, allocLen); |
258 | } else { |
259 | dest->data = PORT_ZAllocPORT_ZAlloc_Util(allocLen); |
260 | } |
261 | if (PORT_UCS2_ASCIIConversionPORT_UCS2_ASCIIConversion_Util(toUnicode, src->data, src->len, |
262 | dest->data, allocLen, &dest->len, |
263 | swapBytes) == PR_FALSE0) { |
264 | if (!arena) { |
265 | PORT_FreePORT_Free_Util(dest->data); |
266 | } |
267 | dest->data = NULL((void*)0); |
268 | return SECFailure; |
269 | } |
270 | return SECSuccess; |
271 | } |
272 | |
273 | /* |
274 | * |
275 | */ |
276 | SECItem * |
277 | P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw) |
278 | { |
279 | char *p0 = NULL((void*)0); |
280 | SECItem *pwItem = NULL((void*)0); |
281 | |
282 | if (p12FilePw == NULL((void*)0) || p12FilePw->source == PW_NONE) { |
283 | char *p1 = NULL((void*)0); |
284 | int rc; |
285 | for (;;) { |
286 | p0 = SECU_GetPasswordString(NULL((void*)0), |
287 | "Enter password for PKCS12 file: "); |
288 | if (!confirmPw || p0 == NULL((void*)0)) |
289 | break; |
290 | p1 = SECU_GetPasswordString(NULL((void*)0), "Re-enter password: "); |
291 | if (p1 == NULL((void*)0)) { |
292 | PORT_ZFreePORT_ZFree_Util(p0, PL_strlen(p0)); |
293 | p0 = NULL((void*)0); |
294 | break; |
295 | } |
296 | rc = PL_strcmp(p0, p1); |
297 | PORT_ZFreePORT_ZFree_Util(p1, PL_strlen(p1)); |
298 | if (rc == 0) |
299 | break; |
300 | PORT_ZFreePORT_ZFree_Util(p0, PL_strlen(p0)); |
301 | } |
302 | } else if (p12FilePw->source == PW_FROMFILE) { |
303 | p0 = SECU_FilePasswd(NULL((void*)0), PR_FALSE0, p12FilePw->data); |
304 | } else { /* Plaintext */ |
305 | p0 = PORT_StrdupPORT_Strdup_Util(p12FilePw->data); |
306 | } |
307 | |
308 | if (p0 == NULL((void*)0)) { |
309 | return NULL((void*)0); |
310 | } |
311 | pwItem = SECITEM_AllocItemSECITEM_AllocItem_Util(NULL((void*)0), NULL((void*)0), PL_strlen(p0) + 1); |
312 | memcpy(pwItem->data, p0, pwItem->len); |
313 | |
314 | PORT_ZFreePORT_ZFree_Util(p0, PL_strlen(p0)); |
315 | |
316 | return pwItem; |
317 | } |
318 | |
319 | SECStatus |
320 | P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw) |
321 | { |
322 | SECStatus rv; |
323 | |
324 | /* New databases, initialize keydb password. */ |
325 | if (PK11_NeedUserInit(slot)) { |
326 | rv = SECU_ChangePW(slot, |
327 | (slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0, |
328 | (slotPw->source == PW_FROMFILE) ? slotPw->data : 0); |
329 | if (rv != SECSuccess) { |
330 | SECU_PrintError(progName, "Failed to initialize slot \"%s\"", |
331 | PK11_GetSlotName(slot)); |
332 | return SECFailure; |
333 | } |
334 | } |
335 | |
336 | if (PK11_Authenticate(slot, PR_TRUE1, slotPw) != SECSuccess) { |
337 | SECU_PrintError(progName, |
338 | "Failed to authenticate to PKCS11 slot"); |
339 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_USER_CANCELLED); |
340 | pk12uErrno = PK12UERR_USER_CANCELLED1; |
341 | return SECFailure; |
342 | } |
343 | |
344 | return SECSuccess; |
345 | } |
346 | |
347 | /* This routine takes care of getting the PKCS12 file password, then reading and |
348 | * verifying the file. It returns the decoder context and a filled in password. |
349 | * (The password is needed by P12U_ImportPKCS12Object() to import the private |
350 | * key.) |
351 | */ |
352 | SEC_PKCS12DecoderContext * |
353 | p12U_ReadPKCS12File(SECItem *uniPwp, char *in_file, PK11SlotInfo *slot, |
354 | secuPWData *slotPw, secuPWData *p12FilePw) |
355 | { |
356 | SEC_PKCS12DecoderContext *p12dcx = NULL((void*)0); |
357 | p12uContext *p12cxt = NULL((void*)0); |
358 | SECItem *pwitem = NULL((void*)0); |
359 | SECItem p12file = { 0 }; |
360 | SECStatus rv = SECFailure; |
361 | PRBool swapUnicode = PR_FALSE0; |
362 | PRBool forceUnicode = pk12uForceUnicode; |
363 | PRBool trypw; |
364 | int error; |
365 | |
366 | #ifdef IS_LITTLE_ENDIAN1 |
367 | swapUnicode = PR_TRUE1; |
368 | #endif |
369 | |
370 | p12cxt = p12u_InitContext(PR_TRUE1, in_file); |
371 | if (!p12cxt) { |
372 | SECU_PrintError(progName, "File Open failed: %s", in_file); |
373 | pk12uErrno = PK12UERR_INIT_FILE10; |
374 | return NULL((void*)0); |
375 | } |
376 | |
377 | /* get the password */ |
378 | pwitem = P12U_GetP12FilePassword(PR_FALSE0, p12FilePw); |
379 | if (!pwitem) { |
380 | pk12uErrno = PK12UERR_USER_CANCELLED1; |
381 | goto done; |
382 | } |
383 | |
384 | if (P12U_UnicodeConversion(NULL((void*)0), uniPwp, pwitem, PR_TRUE1, |
385 | swapUnicode) != SECSuccess) { |
386 | SECU_PrintError(progName, "Unicode conversion failed"); |
387 | pk12uErrno = PK12UERR_UNICODECONV11; |
388 | goto done; |
389 | } |
390 | rv = SECU_FileToItem(&p12file, p12cxt->file); |
391 | if (rv != SECSuccess) { |
392 | SECU_PrintError(progName, "Failed to read from import file"); |
393 | goto done; |
394 | } |
395 | |
396 | do { |
397 | trypw = PR_FALSE0; /* normally we do this once */ |
398 | rv = SECFailure; |
399 | /* init the decoder context */ |
400 | p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw, |
401 | NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0), NULL((void*)0)); |
402 | if (!p12dcx) { |
403 | SECU_PrintError(progName, "PKCS12 decoder start failed"); |
404 | pk12uErrno = PK12UERR_PK12DECODESTART14; |
405 | break; |
406 | } |
407 | |
408 | /* decode the item */ |
409 | rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len); |
410 | |
411 | if (rv != SECSuccess) { |
412 | error = PR_GetError(); |
413 | if (error == SEC_ERROR_DECRYPTION_DISALLOWED) { |
414 | PR_SetError(error, 0); |
415 | break; |
416 | } |
417 | SECU_PrintError(progName, "PKCS12 decoding failed"); |
418 | pk12uErrno = PK12UERR_DECODE16; |
419 | } |
420 | |
421 | /* does the blob authenticate properly? */ |
422 | rv = SEC_PKCS12DecoderVerify(p12dcx); |
423 | if (rv != SECSuccess) { |
424 | if (uniPwp->len == 2) { |
425 | /* this is a null PW, try once more with a zero-length PW |
426 | instead of a null string */ |
427 | SEC_PKCS12DecoderFinish(p12dcx); |
428 | uniPwp->len = 0; |
429 | trypw = PR_TRUE1; |
430 | } else if (forceUnicode == pk12uForceUnicode) { |
431 | /* try again with a different password encoding */ |
432 | forceUnicode = !pk12uForceUnicode; |
433 | rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE0x00c, |
434 | forceUnicode); |
435 | if (rv != SECSuccess) { |
436 | SECU_PrintError(progName, "PKCS12 decoding failed to set option"); |
437 | pk12uErrno = PK12UERR_DECODEVERIFY17; |
438 | break; |
439 | } |
440 | SEC_PKCS12DecoderFinish(p12dcx); |
441 | trypw = PR_TRUE1; |
442 | } else { |
443 | SECU_PrintError(progName, "PKCS12 decode not verified"); |
444 | pk12uErrno = PK12UERR_DECODEVERIFY17; |
445 | break; |
446 | } |
447 | } |
448 | } while (trypw == PR_TRUE1); |
449 | |
450 | /* revert the option setting */ |
451 | if (forceUnicode != pk12uForceUnicode) { |
452 | rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE0x00c, pk12uForceUnicode); |
453 | if (rv != SECSuccess) { |
454 | SECU_PrintError(progName, "PKCS12 decoding failed to set option"); |
455 | pk12uErrno = PK12UERR_DECODEVERIFY17; |
456 | } |
457 | } |
458 | /* rv has been set at this point */ |
459 | |
460 | done: |
461 | if (rv != SECSuccess) { |
462 | if (p12dcx != NULL((void*)0)) { |
463 | SEC_PKCS12DecoderFinish(p12dcx); |
464 | p12dcx = NULL((void*)0); |
465 | } |
466 | if (uniPwp->data) { |
467 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(uniPwp, PR_FALSE0); |
468 | uniPwp->data = NULL((void*)0); |
469 | } |
470 | } |
471 | PR_Close(p12cxt->file); |
472 | p12cxt->file = NULL((void*)0); |
473 | /* PK11_FreeSlot(slot); */ |
474 | p12u_DestroyContext(&p12cxt, PR_FALSE0); |
475 | |
476 | if (pwitem) { |
477 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(pwitem, PR_TRUE1); |
478 | } |
479 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&p12file, PR_FALSE0); |
480 | return p12dcx; |
481 | } |
482 | |
483 | /* |
484 | * given a filename for pkcs12 file, imports certs and keys |
485 | * |
486 | * Change: altitude |
487 | * I've changed this function so that it takes the keydb and pkcs12 file |
488 | * passwords from files. The "pwdKeyDB" and "pwdP12File" |
489 | * variables have been added for this purpose. |
490 | */ |
491 | PRIntn |
492 | P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot, |
493 | secuPWData *slotPw, secuPWData *p12FilePw) |
494 | { |
495 | SEC_PKCS12DecoderContext *p12dcx = NULL((void*)0); |
496 | SECItem uniPwitem = { 0 }; |
497 | PRBool forceUnicode = pk12uForceUnicode; |
498 | PRBool trypw; |
499 | SECStatus rv = SECFailure; |
500 | |
501 | rv = P12U_InitSlot(slot, slotPw); |
502 | if (rv != SECSuccess) { |
503 | SECU_PrintError(progName, "Failed to authenticate to \"%s\"", |
504 | PK11_GetSlotName(slot)); |
505 | pk12uErrno = PK12UERR_PK11GETSLOT13; |
506 | return rv; |
507 | } |
508 | |
509 | do { |
510 | trypw = PR_FALSE0; /* normally we do this once */ |
511 | rv = SECFailure; |
512 | p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw); |
513 | |
514 | if (p12dcx == NULL((void*)0)) { |
515 | goto loser; |
516 | } |
517 | |
518 | /* make sure the bags are okey dokey -- nicknames correct, etc. */ |
519 | rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback); |
520 | if (rv != SECSuccess) { |
521 | if (PORT_GetErrorPORT_GetError_Util() == SEC_ERROR_PKCS12_DUPLICATE_DATA) { |
522 | pk12uErrno = PK12UERR_CERTALREADYEXISTS20; |
523 | } else { |
524 | pk12uErrno = PK12UERR_DECODEVALIBAGS18; |
525 | } |
526 | SECU_PrintError(progName, "PKCS12 decode validate bags failed"); |
527 | goto loser; |
528 | } |
529 | |
530 | /* stuff 'em in */ |
531 | if (forceUnicode != pk12uForceUnicode) { |
532 | rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE0x00c, |
533 | forceUnicode); |
534 | if (rv != SECSuccess) { |
535 | SECU_PrintError(progName, "PKCS12 decode set option failed"); |
536 | pk12uErrno = PK12UERR_DECODEIMPTBAGS19; |
537 | goto loser; |
538 | } |
539 | } |
540 | rv = SEC_PKCS12DecoderImportBags(p12dcx); |
541 | if (rv != SECSuccess) { |
542 | if (PR_GetError() == SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY && |
543 | forceUnicode == pk12uForceUnicode) { |
544 | /* try again with a different password encoding */ |
545 | forceUnicode = !pk12uForceUnicode; |
546 | SEC_PKCS12DecoderFinish(p12dcx); |
547 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&uniPwitem, PR_FALSE0); |
548 | trypw = PR_TRUE1; |
549 | } else { |
550 | SECU_PrintError(progName, "PKCS12 decode import bags failed"); |
551 | pk12uErrno = PK12UERR_DECODEIMPTBAGS19; |
552 | goto loser; |
553 | } |
554 | } |
555 | } while (trypw); |
556 | |
557 | /* revert the option setting */ |
558 | if (forceUnicode != pk12uForceUnicode) { |
559 | rv = NSS_OptionSet(__NSS_PKCS12_DECODE_FORCE_UNICODE0x00c, pk12uForceUnicode); |
560 | if (rv != SECSuccess) { |
561 | SECU_PrintError(progName, "PKCS12 decode set option failed"); |
562 | pk12uErrno = PK12UERR_DECODEIMPTBAGS19; |
563 | goto loser; |
564 | } |
565 | } |
566 | |
567 | fprintf(stdoutstdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName); |
568 | rv = SECSuccess; |
569 | |
570 | loser: |
571 | if (p12dcx) { |
572 | SEC_PKCS12DecoderFinish(p12dcx); |
573 | } |
574 | |
575 | if (uniPwitem.data) { |
576 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&uniPwitem, PR_FALSE0); |
577 | } |
578 | |
579 | return rv; |
580 | } |
581 | |
582 | static void |
583 | p12u_DoPKCS12ExportErrors() |
584 | { |
585 | PRErrorCode error_value; |
586 | |
587 | error_value = PORT_GetErrorPORT_GetError_Util(); |
588 | if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) || |
589 | (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) || |
590 | (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) { |
591 | fputs(SECU_Strerror(error_value)PR_ErrorToString((error_value), 0), stderrstderr); |
592 | } else if (error_value == SEC_ERROR_USER_CANCELLED) { |
593 | ; |
594 | } else { |
595 | fputs(SECU_Strerror(SEC_ERROR_EXPORTING_CERTIFICATES)PR_ErrorToString((SEC_ERROR_EXPORTING_CERTIFICATES), 0), stderrstderr); |
596 | } |
597 | } |
598 | |
599 | static void |
600 | p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len) |
601 | { |
602 | p12uContext *p12cxt = arg; |
603 | int writeLen; |
604 | |
605 | if (!p12cxt || (p12cxt->error == PR_TRUE1)) { |
606 | return; |
607 | } |
608 | |
609 | if (p12cxt->file == NULL((void*)0)) { |
610 | p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; |
611 | p12cxt->error = PR_TRUE1; |
612 | return; |
613 | } |
614 | |
615 | writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (PRInt32)len); |
616 | |
617 | if (writeLen != (int)len) { |
618 | PR_Close(p12cxt->file); |
619 | PL_strfree(p12cxt->filename); |
620 | p12cxt->filename = NULL((void*)0); |
621 | p12cxt->file = NULL((void*)0); |
622 | p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; |
623 | p12cxt->error = PR_TRUE1; |
624 | } |
625 | } |
626 | |
627 | void |
628 | P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot, |
629 | SECOidTag cipher, SECOidTag certCipher, SECOidTag hash, |
630 | secuPWData *slotPw, secuPWData *p12FilePw) |
631 | { |
632 | SEC_PKCS12ExportContext *p12ecx = NULL((void*)0); |
633 | SEC_PKCS12SafeInfo *keySafe = NULL((void*)0), *certSafe = NULL((void*)0); |
634 | SECItem *pwitem = NULL((void*)0); |
635 | p12uContext *p12cxt = NULL((void*)0); |
636 | CERTCertList *certlist = NULL((void*)0); |
637 | CERTCertListNode *node = NULL((void*)0); |
638 | PK11SlotInfo *slot = NULL((void*)0); |
639 | |
640 | if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) { |
641 | SECU_PrintError(progName, "Failed to authenticate to \"%s\"", |
642 | PK11_GetSlotName(inSlot)); |
643 | pk12uErrno = PK12UERR_PK11GETSLOT13; |
644 | goto loser; |
645 | } |
646 | certlist = PK11_FindCertsFromNickname(nn, slotPw); |
647 | if (!certlist) { |
648 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_UNKNOWN_CERT); |
649 | SECU_PrintError(progName, "find user certs from nickname failed"); |
650 | pk12uErrno = PK12UERR_FINDCERTBYNN24; |
651 | return; |
652 | } |
653 | |
654 | if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) || |
655 | CERT_LIST_EMPTY(certlist)(((void *)((CERTCertListNode *)(&certlist->list)->next )) == ((void *)&certlist->list))) { |
656 | PR_fprintf(PR_STDERRPR_GetSpecialFD(PR_StandardError), "%s: no user certs from given nickname\n", |
657 | progName); |
658 | pk12uErrno = PK12UERR_FINDCERTBYNN24; |
659 | goto loser; |
660 | } |
661 | |
662 | /* Password to use for PKCS12 file. */ |
663 | pwitem = P12U_GetP12FilePassword(PR_TRUE1, p12FilePw); |
664 | if (!pwitem) { |
665 | goto loser; |
666 | } |
667 | |
668 | /* we are passing UTF8, drop the NULL in the normal password value. |
669 | * UCS2 conversion will add it back if necessary. This only affects |
670 | * password > Blocksize of the Hash function and pkcs5v2 pbe (if password |
671 | * <=Blocksize then the password is zero padded anyway, so an extra NULL |
672 | * at the end has not effect). This is allows us to work with openssl and |
673 | * gnutls. Older versions of NSS already fail to decrypt long passwords |
674 | * in this case, so we aren't breaking anyone with this code */ |
675 | if ((pwitem->len > 0) && (!pwitem->data[pwitem->len - 1])) { |
676 | pwitem->len--; |
677 | } |
678 | |
679 | p12cxt = p12u_InitContext(PR_FALSE0, outfile); |
680 | if (!p12cxt) { |
681 | SECU_PrintError(progName, "Initialization failed: %s", outfile); |
682 | pk12uErrno = PK12UERR_INIT_FILE10; |
683 | goto loser; |
684 | } |
685 | |
686 | if (certlist) { |
687 | CERTCertificate *cert = CERT_LIST_HEAD(certlist)((CERTCertListNode *)(&certlist->list)->next)->cert; |
688 | if (cert) { |
689 | slot = cert->slot; /* use the slot from the first matching |
690 | certificate to create the context . This is for keygen */ |
691 | } |
692 | } |
693 | if (!slot) { |
694 | SECU_PrintError(progName, "cert does not have a slot"); |
695 | pk12uErrno = PK12UERR_FINDCERTBYNN24; |
696 | goto loser; |
697 | } |
698 | p12ecx = SEC_PKCS12CreateExportContext(NULL((void*)0), NULL((void*)0), slot, slotPw); |
699 | if (!p12ecx) { |
700 | SECU_PrintError(progName, "export context creation failed"); |
701 | pk12uErrno = PK12UERR_EXPORTCXCREATE25; |
702 | goto loser; |
703 | } |
704 | |
705 | if (SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, hash) != |
706 | SECSuccess) { |
707 | SECU_PrintError(progName, "PKCS12 add password integrity failed"); |
708 | pk12uErrno = PK12UERR_PK12ADDPWDINTEG26; |
709 | goto loser; |
710 | } |
711 | |
712 | for (node = CERT_LIST_HEAD(certlist)((CERTCertListNode *)(&certlist->list)->next); |
713 | !CERT_LIST_END(node, certlist)(((void *)node) == ((void *)&certlist->list)); |
714 | node = CERT_LIST_NEXT(node)((CERTCertListNode *)node->links.next)) { |
715 | CERTCertificate *cert = node->cert; |
716 | if (!cert->slot) { |
717 | SECU_PrintError(progName, "cert does not have a slot"); |
718 | pk12uErrno = PK12UERR_FINDCERTBYNN24; |
719 | goto loser; |
720 | } |
721 | |
722 | keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); |
723 | if (certCipher == SEC_OID_UNKNOWN) { |
724 | certSafe = keySafe; |
725 | } else { |
726 | certSafe = |
727 | SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, certCipher); |
728 | } |
729 | |
730 | if (!certSafe || !keySafe) { |
731 | SECU_PrintError(progName, "key or cert safe creation failed"); |
732 | pk12uErrno = PK12UERR_CERTKEYSAFE27; |
733 | goto loser; |
734 | } |
735 | |
736 | if (SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL((void*)0), cert, |
737 | CERT_GetDefaultCertDB(), keySafe, NULL((void*)0), |
738 | PR_TRUE1, pwitem, cipher) != SECSuccess) { |
739 | SECU_PrintError(progName, "add cert and key failed"); |
740 | pk12uErrno = PK12UERR_ADDCERTKEY28; |
741 | goto loser; |
742 | } |
743 | } |
744 | |
745 | CERT_DestroyCertList(certlist); |
746 | certlist = NULL((void*)0); |
747 | |
748 | if (SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt) != |
749 | SECSuccess) { |
750 | SECU_PrintError(progName, "PKCS12 encode failed"); |
751 | pk12uErrno = PK12UERR_ENCODE29; |
752 | goto loser; |
753 | } |
754 | |
755 | p12u_DestroyContext(&p12cxt, PR_FALSE0); |
756 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(pwitem, PR_TRUE1); |
757 | fprintf(stdoutstdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName); |
758 | SEC_PKCS12DestroyExportContext(p12ecx); |
759 | |
760 | return; |
761 | |
762 | loser: |
763 | SEC_PKCS12DestroyExportContext(p12ecx); |
764 | |
765 | if (certlist) { |
766 | CERT_DestroyCertList(certlist); |
767 | certlist = NULL((void*)0); |
768 | } |
769 | |
770 | p12u_DestroyContext(&p12cxt, PR_TRUE1); |
771 | if (pwitem) { |
772 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(pwitem, PR_TRUE1); |
773 | } |
774 | p12u_DoPKCS12ExportErrors(); |
775 | return; |
776 | } |
777 | |
778 | PRIntn |
779 | P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot, |
780 | secuPWData *slotPw, secuPWData *p12FilePw) |
781 | { |
782 | SEC_PKCS12DecoderContext *p12dcx = NULL((void*)0); |
783 | SECItem uniPwitem = { 0 }; |
784 | SECStatus rv = SECFailure; |
785 | const SEC_PKCS12DecoderItem *dip; |
786 | |
787 | p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw); |
788 | /* did the blob authenticate properly? */ |
789 | if (p12dcx == NULL((void*)0)) { |
790 | SECU_PrintError(progName, "PKCS12 decode not verified"); |
791 | pk12uErrno = PK12UERR_DECODEVERIFY17; |
792 | goto loser; |
793 | } |
794 | rv = SEC_PKCS12DecoderIterateInit(p12dcx); |
795 | if (rv != SECSuccess) { |
796 | SECU_PrintError(progName, "PKCS12 decode iterate bags failed"); |
797 | pk12uErrno = PK12UERR_DECODEIMPTBAGS19; |
798 | rv = SECFailure; |
799 | } else { |
800 | int fileCounter = 0; |
801 | while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) { |
802 | switch (dip->type) { |
803 | case SEC_OID_PKCS12_V1_CERT_BAG_ID: |
804 | printf("Certificate"); |
805 | if (dumpRawFile) { |
806 | PRFileDesc *fd; |
807 | char fileName[20]; |
808 | snprintf(fileName, sizeof(fileName), "file%04d.der", ++fileCounter); |
809 | fd = PR_Open(fileName, |
810 | PR_CREATE_FILE0x08 | PR_RDWR0x04 | PR_TRUNCATE0x20, |
811 | 0600); |
812 | if (!fd) { |
813 | SECU_PrintError(progName, |
814 | "Cannot create output file"); |
815 | } else { |
816 | PR_Write(fd, dip->der->data, dip->der->len); |
817 | PR_Close(fd); |
818 | } |
819 | } else if (SECU_PrintSignedData(stdoutstdout, dip->der, |
820 | (dip->hasKey) ? "(has private key)" |
821 | : "", |
822 | 0, (SECU_PPFunc)SECU_PrintCertificate) != |
823 | 0) { |
824 | SECU_PrintError(progName, "PKCS12 print cert bag failed"); |
825 | } |
826 | if (dip->friendlyName != NULL((void*)0)) { |
827 | printf(" Friendly Name: %s\n\n", |
828 | dip->friendlyName->data); |
829 | } |
830 | if (dip->shroudAlg) { |
831 | SECU_PrintAlgorithmID(stdoutstdout, dip->shroudAlg, |
832 | "Encryption algorithm", 1); |
833 | } |
834 | break; |
835 | case SEC_OID_PKCS12_V1_KEY_BAG_ID: |
836 | case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID: |
837 | printf("Key"); |
838 | if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID) |
839 | printf("(shrouded)"); |
840 | printf(":\n"); |
841 | if (dip->friendlyName != NULL((void*)0)) { |
842 | printf(" Friendly Name: %s\n\n", |
843 | dip->friendlyName->data); |
844 | } |
845 | if (dip->shroudAlg) { |
846 | SECU_PrintAlgorithmID(stdoutstdout, dip->shroudAlg, |
847 | "Encryption algorithm", 1); |
848 | } |
849 | break; |
850 | default: |
851 | printf("unknown bag type(%d): %s\n\n", dip->type, |
852 | SECOID_FindOIDTagDescriptionSECOID_FindOIDTagDescription_Util(dip->type)); |
853 | break; |
854 | } |
855 | } |
856 | rv = SECSuccess; |
857 | } |
858 | |
859 | loser: |
860 | |
861 | if (p12dcx) { |
862 | SEC_PKCS12DecoderFinish(p12dcx); |
863 | } |
864 | |
865 | if (uniPwitem.data) { |
866 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&uniPwitem, PR_FALSE0); |
867 | } |
868 | |
869 | return rv; |
870 | } |
871 | |
872 | SECOidTag |
873 | PKCS12U_FindTagFromString(char *cipherString) |
874 | { |
875 | SECOidTag tag; |
876 | SECOidData *oid; |
877 | |
878 | /* future enhancement: accept dotted oid spec? */ |
879 | |
880 | for (tag = 1; (oid = SECOID_FindOIDByTagSECOID_FindOIDByTag_Util(tag)) != NULL((void*)0); tag++) { |
881 | /* only interested in oids that we actually understand */ |
882 | if (oid->mechanism == CKM_INVALID_MECHANISM0xffffffffUL) { |
883 | continue; |
884 | } |
885 | if (PORT_StrcasecmpPL_strcasecmp(oid->desc, cipherString) != 0) { |
886 | continue; |
887 | } |
888 | return tag; |
889 | } |
890 | return SEC_OID_UNKNOWN; |
891 | } |
892 | |
893 | /* |
894 | * use the oid table description to map a user input string to a particular |
895 | * oid. |
896 | */ |
897 | SECOidTag |
898 | PKCS12U_MapCipherFromString(char *cipherString, int keyLen) |
899 | { |
900 | SECOidTag tag; |
901 | SECOidTag cipher; |
902 | |
903 | /* future enhancement: provide 'friendlier' typed in names for |
904 | * pbe mechanisms. |
905 | */ |
906 | |
907 | /* look for the oid tag by Description */ |
908 | tag = PKCS12U_FindTagFromString(cipherString); |
909 | if (tag == SEC_OID_UNKNOWN) { |
910 | return tag; |
911 | } |
912 | |
913 | cipher = SEC_OID_UNKNOWN; |
Value stored to 'cipher' is never read | |
914 | /* we found a match... get the PBE version of this |
915 | * cipher... */ |
916 | if (!SEC_PKCS5IsAlgorithmPBEAlgTag(tag)) { |
917 | cipher = SEC_PKCS5GetPBEAlgorithm(tag, keyLen); |
918 | /* no eqivalent PKCS5/PKCS12 cipher, use the raw |
919 | * encryption tag we got and pass it directly in, |
920 | * pkcs12 will use the pkcsv5 mechanism */ |
921 | if (cipher == SEC_OID_PKCS5_PBES2) { |
922 | cipher = tag; |
923 | } else if (cipher == SEC_OID_PKCS5_PBMAC1) { |
924 | /* make sure we have not macing ciphers here */ |
925 | cipher = SEC_OID_UNKNOWN; |
926 | } |
927 | } else { |
928 | cipher = tag; |
929 | } |
930 | return cipher; |
931 | } |
932 | |
933 | SECOidTag |
934 | PKCS12U_MapHashFromString(char *hashString) |
935 | { |
936 | SECOidTag hashAlg; |
937 | |
938 | /* look for the oid tag by Description */ |
939 | hashAlg = PKCS12U_FindTagFromString(hashString); |
940 | if (hashAlg == SEC_OID_UNKNOWN) { |
941 | return hashAlg; |
942 | } |
943 | /* make sure it's a hashing oid */ |
944 | if (HASH_GetHashTypeByOidTag(hashAlg) == HASH_AlgNULL) { |
945 | return SEC_OID_UNKNOWN; |
946 | } |
947 | return hashAlg; |
948 | } |
949 | |
950 | static void |
951 | p12u_EnableAllCiphers() |
952 | { |
953 | SEC_PKCS12EnableCipher(PKCS12_RC4_40(0x00020000L | 0011), 1); |
954 | SEC_PKCS12EnableCipher(PKCS12_RC4_128(0x00020000L | 0012), 1); |
955 | SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40(0x00020000L | 0001), 1); |
956 | SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128(0x00020000L | 0002), 1); |
957 | SEC_PKCS12EnableCipher(PKCS12_DES_56(0x00020000L | 0021), 1); |
958 | SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168(0x00020000L | 0022), 1); |
959 | SEC_PKCS12EnableCipher(PKCS12_AES_CBC_128(0x00020000L | 0031), 1); |
960 | SEC_PKCS12EnableCipher(PKCS12_AES_CBC_192(0x00020000L | 0032), 1); |
961 | SEC_PKCS12EnableCipher(PKCS12_AES_CBC_256(0x00020000L | 0033), 1); |
962 | SEC_PKCS12SetPreferredCipher(PKCS12_AES_CBC_256(0x00020000L | 0033), 1); |
963 | } |
964 | |
965 | static PRUintn |
966 | P12U_Init(char *dir, char *dbprefix, PRBool listonly) |
967 | { |
968 | SECStatus rv; |
969 | PK11_SetPasswordFunc(SECU_GetModulePassword); |
970 | |
971 | PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); |
972 | if (listonly && NSS_NoDB_Init("") == SECSuccess) { |
973 | rv = SECSuccess; |
974 | } else { |
975 | rv = NSS_Initialize(dir, dbprefix, dbprefix, "secmod.db", 0); |
976 | } |
977 | if (rv != SECSuccess) { |
978 | SECU_PrintPRandOSError(progName); |
979 | exit(-1); |
980 | } |
981 | |
982 | /* setup unicode callback functions */ |
983 | PORT_SetUCS2_ASCIIConversionFunctionPORT_SetUCS2_ASCIIConversionFunction_Util(p12u_ucs2_ascii_conversion_function); |
984 | /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */ |
985 | |
986 | p12u_EnableAllCiphers(); |
987 | |
988 | return 0; |
989 | } |
990 | |
991 | enum { |
992 | opt_CertDir = 0, |
993 | opt_TokenName, |
994 | opt_Import, |
995 | opt_SlotPWFile, |
996 | opt_SlotPW, |
997 | opt_List, |
998 | opt_Nickname, |
999 | opt_Export, |
1000 | opt_Raw, |
1001 | opt_P12FilePWFile, |
1002 | opt_P12FilePW, |
1003 | opt_DBPrefix, |
1004 | opt_Debug, |
1005 | opt_Cipher, |
1006 | opt_CertCipher, |
1007 | opt_KeyLength, |
1008 | opt_CertKeyLength, |
1009 | opt_Mac |
1010 | }; |
1011 | |
1012 | static secuCommandFlag pk12util_options[] = { |
1013 | { /* opt_CertDir */ 'd', PR_TRUE1, 0, PR_FALSE0 }, |
1014 | { /* opt_TokenName */ 'h', PR_TRUE1, 0, PR_FALSE0 }, |
1015 | { /* opt_Import */ 'i', PR_TRUE1, 0, PR_FALSE0 }, |
1016 | { /* opt_SlotPWFile */ 'k', PR_TRUE1, 0, PR_FALSE0 }, |
1017 | { /* opt_SlotPW */ 'K', PR_TRUE1, 0, PR_FALSE0 }, |
1018 | { /* opt_List */ 'l', PR_TRUE1, 0, PR_FALSE0 }, |
1019 | { /* opt_Nickname */ 'n', PR_TRUE1, 0, PR_FALSE0 }, |
1020 | { /* opt_Export */ 'o', PR_TRUE1, 0, PR_FALSE0 }, |
1021 | { /* opt_Raw */ 'r', PR_FALSE0, 0, PR_FALSE0 }, |
1022 | { /* opt_P12FilePWFile */ 'w', PR_TRUE1, 0, PR_FALSE0 }, |
1023 | { /* opt_P12FilePW */ 'W', PR_TRUE1, 0, PR_FALSE0 }, |
1024 | { /* opt_DBPrefix */ 'P', PR_TRUE1, 0, PR_FALSE0 }, |
1025 | { /* opt_Debug */ 'v', PR_FALSE0, 0, PR_FALSE0 }, |
1026 | { /* opt_Cipher */ 'c', PR_TRUE1, 0, PR_FALSE0 }, |
1027 | { /* opt_CertCipher */ 'C', PR_TRUE1, 0, PR_FALSE0 }, |
1028 | { /* opt_KeyLength */ 'm', PR_TRUE1, 0, PR_FALSE0, "key_len" }, |
1029 | { /* opt_CertKeyLength */ 0, PR_TRUE1, 0, PR_FALSE0, "cert_key_len" }, |
1030 | { /* opt_Mac */ 'M', PR_TRUE1, 0, PR_FALSE0, PR_FALSE0 } |
1031 | }; |
1032 | |
1033 | int |
1034 | main(int argc, char **argv) |
1035 | { |
1036 | secuPWData slotPw = { PW_NONE, NULL((void*)0) }; |
1037 | secuPWData p12FilePw = { PW_NONE, NULL((void*)0) }; |
1038 | PK11SlotInfo *slot; |
1039 | char *slotname = NULL((void*)0); |
1040 | char *import_file = NULL((void*)0); |
1041 | char *export_file = NULL((void*)0); |
1042 | char *dbprefix = ""; |
1043 | SECStatus rv; |
1044 | SECOidTag cipher = SEC_OID_AES_256_CBC; |
1045 | SECOidTag hash = SEC_OID_SHA256; |
1046 | SECOidTag certCipher = SEC_OID_AES_128_CBC; |
1047 | int keyLen = 0; |
1048 | int certKeyLen = 0; |
1049 | secuCommand pk12util; |
1050 | PRInt32 forceUnicode; |
1051 | |
1052 | #ifdef _CRTDBG_MAP_ALLOC |
1053 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); |
1054 | #endif |
1055 | |
1056 | pk12util.numCommands = 0; |
1057 | pk12util.commands = 0; |
1058 | pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag); |
1059 | pk12util.options = pk12util_options; |
1060 | |
1061 | progName = strrchr(argv[0], '/'); |
1062 | progName = progName ? progName + 1 : argv[0]; |
1063 | |
1064 | rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util); |
1065 | |
1066 | if (rv != SECSuccess) |
1067 | Usage(); |
1068 | |
1069 | pk12_debugging = pk12util.options[opt_Debug].activated; |
1070 | |
1071 | if ((pk12util.options[opt_Import].activated + |
1072 | pk12util.options[opt_Export].activated + |
1073 | pk12util.options[opt_List].activated) != 1) { |
1074 | Usage(); |
1075 | } |
1076 | |
1077 | if (pk12util.options[opt_Export].activated && |
1078 | !pk12util.options[opt_Nickname].activated) { |
1079 | Usage(); |
1080 | } |
1081 | |
1082 | rv = NSS_OptionGet(__NSS_PKCS12_DECODE_FORCE_UNICODE0x00c, &forceUnicode); |
1083 | if (rv != SECSuccess) { |
1084 | SECU_PrintError(progName, |
1085 | "Failed to get NSS_PKCS12_DECODE_FORCE_UNICODE option"); |
1086 | Usage(); |
1087 | } |
1088 | pk12uForceUnicode = forceUnicode; |
1089 | |
1090 | slotname = SECU_GetOptionArg(&pk12util, opt_TokenName); |
1091 | |
1092 | import_file = (pk12util.options[opt_List].activated) ? SECU_GetOptionArg(&pk12util, opt_List) |
1093 | : SECU_GetOptionArg(&pk12util, opt_Import); |
1094 | export_file = SECU_GetOptionArg(&pk12util, opt_Export); |
1095 | |
1096 | if (pk12util.options[opt_P12FilePWFile].activated) { |
1097 | p12FilePw.source = PW_FROMFILE; |
1098 | p12FilePw.data = PORT_StrdupPORT_Strdup_Util(pk12util.options[opt_P12FilePWFile].arg); |
1099 | } |
1100 | |
1101 | if (pk12util.options[opt_P12FilePW].activated) { |
1102 | p12FilePw.source = PW_PLAINTEXT; |
1103 | p12FilePw.data = PORT_StrdupPORT_Strdup_Util(pk12util.options[opt_P12FilePW].arg); |
1104 | } |
1105 | |
1106 | if (pk12util.options[opt_SlotPWFile].activated) { |
1107 | slotPw.source = PW_FROMFILE; |
1108 | slotPw.data = PORT_StrdupPORT_Strdup_Util(pk12util.options[opt_SlotPWFile].arg); |
1109 | } |
1110 | |
1111 | if (pk12util.options[opt_SlotPW].activated) { |
1112 | slotPw.source = PW_PLAINTEXT; |
1113 | slotPw.data = PORT_StrdupPORT_Strdup_Util(pk12util.options[opt_SlotPW].arg); |
1114 | } |
1115 | |
1116 | if (pk12util.options[opt_CertDir].activated) { |
1117 | SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg); |
1118 | } |
1119 | if (pk12util.options[opt_DBPrefix].activated) { |
1120 | dbprefix = pk12util.options[opt_DBPrefix].arg; |
1121 | } |
1122 | if (pk12util.options[opt_Raw].activated) { |
1123 | dumpRawFile = PR_TRUE1; |
1124 | } |
1125 | if (pk12util.options[opt_KeyLength].activated) { |
1126 | keyLen = atoi(pk12util.options[opt_KeyLength].arg); |
1127 | } |
1128 | if (pk12util.options[opt_CertKeyLength].activated) { |
1129 | certKeyLen = atoi(pk12util.options[opt_CertKeyLength].arg); |
1130 | } |
1131 | |
1132 | P12U_Init(SECU_ConfigDirectory(NULL((void*)0)), dbprefix, |
1133 | pk12util.options[opt_List].activated); |
1134 | |
1135 | if (!slotname || PL_strcmp(slotname, "internal") == 0) |
1136 | slot = PK11_GetInternalKeySlot(); |
1137 | else |
1138 | slot = PK11_FindSlotByName(slotname); |
1139 | |
1140 | if (!slot) { |
1141 | SECU_PrintError(progName, "Invalid slot \"%s\"", slotname); |
1142 | pk12uErrno = PK12UERR_PK11GETSLOT13; |
1143 | goto done; |
1144 | } |
1145 | |
1146 | if (pk12util.options[opt_Cipher].activated) { |
1147 | char *cipherString = pk12util.options[opt_Cipher].arg; |
1148 | |
1149 | cipher = PKCS12U_MapCipherFromString(cipherString, keyLen); |
1150 | /* We only want encryption PBE's. make sure we don't have |
1151 | * any MAC pbes */ |
1152 | if (cipher == SEC_OID_UNKNOWN) { |
1153 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM); |
1154 | SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString); |
1155 | pk12uErrno = PK12UERR_INVALIDALGORITHM30; |
1156 | goto done; |
1157 | } |
1158 | } |
1159 | |
1160 | if (pk12util.options[opt_CertCipher].activated) { |
1161 | char *cipherString = pk12util.options[opt_CertCipher].arg; |
1162 | |
1163 | if (PORT_StrcasecmpPL_strcasecmp(cipherString, "none") == 0) { |
1164 | certCipher = SEC_OID_UNKNOWN; |
1165 | } else { |
1166 | certCipher = PKCS12U_MapCipherFromString(cipherString, certKeyLen); |
1167 | /* If the user requested a cipher and we didn't find it, then |
1168 | * don't just silently not encrypt. */ |
1169 | if (certCipher == SEC_OID_UNKNOWN) { |
1170 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM); |
1171 | SECU_PrintError(progName, "Algorithm: \"%s\"", cipherString); |
1172 | pk12uErrno = PK12UERR_INVALIDALGORITHM30; |
1173 | goto done; |
1174 | } |
1175 | } |
1176 | } |
1177 | if (pk12util.options[opt_Mac].activated) { |
1178 | char *hashString = pk12util.options[opt_Mac].arg; |
1179 | |
1180 | hash = PKCS12U_MapHashFromString(hashString); |
1181 | /* We don't support creating Mac-less pkcs 12 files */ |
1182 | if (hash == SEC_OID_UNKNOWN) { |
1183 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ALGORITHM); |
1184 | SECU_PrintError(progName, "Algorithm: \"%s\"", hashString); |
1185 | pk12uErrno = PK12UERR_INVALIDALGORITHM30; |
1186 | goto done; |
1187 | } |
1188 | } |
1189 | |
1190 | if (pk12util.options[opt_Import].activated) { |
1191 | P12U_ImportPKCS12Object(import_file, slot, &slotPw, &p12FilePw); |
1192 | |
1193 | } else if (pk12util.options[opt_Export].activated) { |
1194 | P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg, |
1195 | export_file, slot, cipher, certCipher, |
1196 | hash, &slotPw, &p12FilePw); |
1197 | |
1198 | } else if (pk12util.options[opt_List].activated) { |
1199 | P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw); |
1200 | |
1201 | } else { |
1202 | Usage(); |
1203 | pk12uErrno = PK12UERR_USAGE2; |
1204 | } |
1205 | |
1206 | done: |
1207 | if (import_file != NULL((void*)0)) |
1208 | PORT_ZFreePORT_ZFree_Util(import_file, PL_strlen(import_file)); |
1209 | if (export_file != NULL((void*)0)) |
1210 | PORT_ZFreePORT_ZFree_Util(export_file, PL_strlen(export_file)); |
1211 | if (slotPw.data != NULL((void*)0)) |
1212 | PORT_ZFreePORT_ZFree_Util(slotPw.data, PL_strlen(slotPw.data)); |
1213 | if (p12FilePw.data != NULL((void*)0)) |
1214 | PORT_ZFreePORT_ZFree_Util(p12FilePw.data, PL_strlen(p12FilePw.data)); |
1215 | if (slot) |
1216 | PK11_FreeSlot(slot); |
1217 | if (NSS_Shutdown() != SECSuccess) { |
1218 | pk12uErrno = 1; |
1219 | } |
1220 | PL_ArenaFinish(); |
1221 | PR_Cleanup(); |
1222 | return pk12uErrno; |
1223 | } |