~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/cmd/pk12util/pk12util.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ***** BEGIN LICENSE BLOCK *****
 
2
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
3
 *
 
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/
 
8
 *
 
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
 
12
 * License.
 
13
 *
 
14
 * The Original Code is the Netscape security libraries.
 
15
 *
 
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.
 
20
 *
 
21
 * Contributor(s):
 
22
 *
 
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.
 
34
 *
 
35
 * ***** END LICENSE BLOCK ***** */
 
36
 
 
37
#include "nspr.h"
 
38
#include "secutil.h"
 
39
#include "pk11func.h"
 
40
#include "pkcs12.h"
 
41
#include "p12plcy.h"
 
42
#include "pk12util.h"
 
43
#include "nss.h"
 
44
#include "secport.h"
 
45
#include "certdb.h"
 
46
 
 
47
#define PKCS12_IN_BUFFER_SIZE   200
 
48
 
 
49
static char *progName;
 
50
PRBool pk12_debugging = PR_FALSE;
 
51
 
 
52
PRIntn pk12uErrno = 0;
 
53
 
 
54
static void
 
55
Usage(char *progName)
 
56
{
 
57
#define FPS PR_fprintf(PR_STDERR,
 
58
    FPS "Usage:  %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
 
59
                                 progName);
 
60
    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
 
61
    FPS "\t\t [-v]\n");
 
62
    FPS "Usage:  %s -l listfile [-d certdir] [-P dbprefix] [-h tokenname]\n",
 
63
                                 progName);
 
64
    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
 
65
    FPS "Usage:  %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n", progName);
 
66
    FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n");
 
67
    FPS "\t\t [-v]\n");
 
68
    exit(PK12UERR_USAGE);
 
69
}
 
70
 
 
71
static PRBool
 
72
p12u_OpenFile(p12uContext *p12cxt, PRBool fileRead)
 
73
{
 
74
    if(!p12cxt || !p12cxt->filename) {
 
75
        return PR_FALSE;
 
76
    }
 
77
 
 
78
    if(fileRead) {
 
79
        p12cxt->file = PR_Open(p12cxt->filename,
 
80
                                 PR_RDONLY, 0400);
 
81
    } else {
 
82
        p12cxt->file = PR_Open(p12cxt->filename,
 
83
                                 PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE,
 
84
                                 0600);
 
85
    }
 
86
 
 
87
    if(!p12cxt->file) {
 
88
        p12cxt->error = PR_TRUE;
 
89
        return PR_FALSE;
 
90
    }
 
91
 
 
92
    return PR_TRUE;
 
93
}
 
94
 
 
95
static void
 
96
p12u_DestroyContext(p12uContext **ppCtx, PRBool removeFile)
 
97
{
 
98
    if(!ppCtx || !(*ppCtx)) {
 
99
        return;
 
100
    }
 
101
 
 
102
    if((*ppCtx)->file != NULL) {
 
103
        PR_Close((*ppCtx)->file);
 
104
    }
 
105
 
 
106
    if((*ppCtx)->filename != NULL) {
 
107
        if(removeFile) {
 
108
            PR_Delete((*ppCtx)->filename);
 
109
        }
 
110
        PR_Free((*ppCtx)->filename);
 
111
    }
 
112
 
 
113
    PR_Free(*ppCtx);
 
114
    *ppCtx = NULL;
 
115
}
 
116
 
 
117
static p12uContext *
 
118
p12u_InitContext(PRBool fileImport, char *filename)
 
119
{
 
120
    p12uContext *p12cxt;
 
121
    PRBool fileExist;
 
122
 
 
123
    fileExist = fileImport;
 
124
 
 
125
    p12cxt = PORT_ZNew(p12uContext);
 
126
    if(!p12cxt) {
 
127
        return NULL;
 
128
    }
 
129
 
 
130
    p12cxt->error = PR_FALSE;
 
131
    p12cxt->errorValue = 0;
 
132
    p12cxt->filename = strdup(filename);
 
133
 
 
134
    if(!p12u_OpenFile(p12cxt, fileImport)) {
 
135
        p12u_DestroyContext(&p12cxt, PR_FALSE);
 
136
        return NULL;
 
137
    }
 
138
 
 
139
    return p12cxt;
 
140
}
 
141
 
 
142
SECItem *
 
143
P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx)
 
144
{
 
145
    if(cancel == NULL) {
 
146
      pk12uErrno = PK12UERR_USER_CANCELLED;
 
147
      return NULL;
 
148
    }
 
149
 
 
150
    if (!old_nick)
 
151
      fprintf(stdout, "pk12util: no nickname for cert...not handled\n");
 
152
 
 
153
    /* XXX not handled yet  */
 
154
    *cancel = PR_TRUE;
 
155
    return NULL;
 
156
 
 
157
#if 0
 
158
    char *nick = NULL;
 
159
    SECItem *ret_nick = NULL;
 
160
 
 
161
    nick = strdup( DEFAULT_CERT_NICKNAME );
 
162
 
 
163
    if(old_nick && !PORT_Strcmp((char *)old_nick->data, nick)) {
 
164
        PORT_Free(nick);
 
165
        return NULL;
 
166
    }
 
167
 
 
168
    ret_nick = (SECItem *)PORT_ZAlloc(sizeof(SECItem));
 
169
    if(ret_nick == NULL) {
 
170
        PORT_Free(nick);
 
171
        return NULL;
 
172
    }
 
173
 
 
174
    ret_nick->data = (unsigned char *)nick;
 
175
    ret_nick->len = PORT_Strlen(nick);
 
176
 
 
177
    return ret_nick;
 
178
#endif
 
179
}
 
180
 
 
181
static SECStatus
 
182
p12u_SwapUnicodeBytes(SECItem *uniItem)
 
183
{
 
184
    unsigned int i;
 
185
    unsigned char a;
 
186
    if((uniItem == NULL) || (uniItem->len % 2)) {
 
187
        return SECFailure;
 
188
    }
 
189
    for(i = 0; i < uniItem->len; i += 2) {
 
190
        a = uniItem->data[i];
 
191
        uniItem->data[i] = uniItem->data[i+1];
 
192
        uniItem->data[i+1] = a;
 
193
    }
 
194
    return SECSuccess;
 
195
}
 
196
 
 
197
static PRBool
 
198
p12u_ucs2_ascii_conversion_function(PRBool         toUnicode,
 
199
                                    unsigned char *inBuf,
 
200
                                    unsigned int   inBufLen,
 
201
                                    unsigned char *outBuf,
 
202
                                    unsigned int   maxOutBufLen,
 
203
                                    unsigned int  *outBufLen,
 
204
                                    PRBool         swapBytes)
 
205
{
 
206
    SECItem it = { 0 };
 
207
    SECItem *dup = NULL;
 
208
    PRBool ret;
 
209
 
 
210
#ifdef DEBUG_CONVERSION
 
211
    if (pk12_debugging) {
 
212
        int i;
 
213
        printf("Converted from:\n");
 
214
        for (i=0; i<inBufLen; i++) {
 
215
            printf("%2x ", inBuf[i]);
 
216
            /*if (i%60 == 0) printf("\n");*/
 
217
        }
 
218
        printf("\n");
 
219
    }
 
220
#endif
 
221
    it.data = inBuf;
 
222
    it.len = inBufLen;
 
223
    dup = SECITEM_DupItem(&it);
 
224
    /* If converting Unicode to ASCII, swap bytes before conversion
 
225
     * as neccessary.
 
226
     */
 
227
    if (!toUnicode && swapBytes) {
 
228
        if (p12u_SwapUnicodeBytes(dup) != SECSuccess) {
 
229
            SECITEM_ZfreeItem(dup, PR_TRUE);
 
230
            return PR_FALSE;
 
231
        }
 
232
    }
 
233
    /* Perform the conversion. */
 
234
    ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len,
 
235
                                   outBuf, maxOutBufLen, outBufLen);
 
236
    if (dup)
 
237
        SECITEM_ZfreeItem(dup, PR_TRUE);
 
238
 
 
239
#ifdef DEBUG_CONVERSION
 
240
    if (pk12_debugging) {
 
241
        int i;
 
242
        printf("Converted to:\n");
 
243
        for (i=0; i<*outBufLen; i++) {
 
244
            printf("%2x ", outBuf[i]);
 
245
            /*if (i%60 == 0) printf("\n");*/
 
246
        }
 
247
        printf("\n");
 
248
    }
 
249
#endif
 
250
    return ret;
 
251
}
 
252
 
 
253
SECStatus
 
254
P12U_UnicodeConversion(PRArenaPool *arena, SECItem *dest, SECItem *src,
 
255
                       PRBool toUnicode, PRBool swapBytes)
 
256
{
 
257
    unsigned int allocLen;
 
258
    if(!dest || !src) {
 
259
        return SECFailure;
 
260
    }
 
261
    allocLen = ((toUnicode) ? (src->len << 2) : src->len);
 
262
    if(arena) {
 
263
        dest->data = PORT_ArenaZAlloc(arena, allocLen);
 
264
    } else {
 
265
        dest->data = PORT_ZAlloc(allocLen);
 
266
    }
 
267
    if(PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len,
 
268
                                 dest->data, allocLen, &dest->len,
 
269
                                 swapBytes) == PR_FALSE) {
 
270
        if(!arena) {
 
271
            PORT_Free(dest->data);
 
272
        }
 
273
        dest->data = NULL;
 
274
        return SECFailure;
 
275
    }
 
276
    return SECSuccess;
 
277
}
 
278
 
 
279
/*
 
280
 *
 
281
 */
 
282
SECItem *
 
283
P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw)
 
284
{
 
285
    char *p0 = NULL, *p1 = NULL;
 
286
    SECItem *pwItem = NULL;
 
287
 
 
288
    if (p12FilePw == NULL || p12FilePw->source == PW_NONE) {
 
289
        for (;;) {
 
290
            p0 = SECU_GetPasswordString(NULL,
 
291
                                        "Enter password for PKCS12 file: ");
 
292
            if (!confirmPw)
 
293
                break;
 
294
            p1 = SECU_GetPasswordString(NULL, "Re-enter password: ");
 
295
            if (PL_strcmp(p0, p1) == 0)
 
296
                break;
 
297
        }
 
298
    } else if (p12FilePw->source == PW_FROMFILE) {
 
299
        p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data);
 
300
    } else { /* Plaintext */
 
301
        p0 = p12FilePw->data;
 
302
    }
 
303
 
 
304
    if (p0 == NULL) {
 
305
        return NULL;
 
306
    }
 
307
    pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1);
 
308
    memcpy(pwItem->data, p0, pwItem->len);
 
309
 
 
310
    PORT_Memset(p0, 0, PL_strlen(p0));
 
311
    PORT_Free(p0);
 
312
 
 
313
    PORT_Memset(p1, 0, PL_strlen(p1));
 
314
    PORT_Free(p1);
 
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_TRUE, slotPw) != SECSuccess) {
 
337
        SECU_PrintError(progName,
 
338
                         "Failed to authenticate to PKCS11 slot");
 
339
        PORT_SetError(SEC_ERROR_USER_CANCELLED);
 
340
        pk12uErrno = PK12UERR_USER_CANCELLED;
 
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;
 
357
    p12uContext *p12cxt = NULL;
 
358
    SECItem *pwitem = NULL;
 
359
    SECItem p12file = { 0 };
 
360
    SECStatus rv = SECFailure;
 
361
    PRBool swapUnicode = PR_FALSE;
 
362
    PRBool trypw;
 
363
    int error;
 
364
    
 
365
#ifdef IS_LITTLE_ENDIAN
 
366
    swapUnicode = PR_TRUE;
 
367
#endif
 
368
 
 
369
    p12cxt = p12u_InitContext(PR_TRUE, in_file);
 
370
    if(!p12cxt) {
 
371
        SECU_PrintError(progName,"File Open failed: %s", in_file);
 
372
        pk12uErrno = PK12UERR_INIT_FILE;
 
373
        return NULL;
 
374
    }
 
375
 
 
376
    /* get the password */
 
377
    pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw);
 
378
    if (!pwitem) {
 
379
        pk12uErrno = PK12UERR_USER_CANCELLED;
 
380
        goto done;
 
381
    }
 
382
 
 
383
    if(P12U_UnicodeConversion(NULL, uniPwp, pwitem, PR_TRUE,
 
384
                              swapUnicode) != SECSuccess) {
 
385
        SECU_PrintError(progName,"Unicode conversion failed");
 
386
        pk12uErrno = PK12UERR_UNICODECONV;
 
387
        goto done;
 
388
    }
 
389
    rv = SECU_FileToItem(&p12file, p12cxt->file);
 
390
    if (rv != SECSuccess) {
 
391
        SECU_PrintError(progName,"Failed to read from import file");
 
392
        goto done;
 
393
    }
 
394
 
 
395
    do {
 
396
        trypw = PR_FALSE;                  /* normally we do this once */
 
397
        rv = SECFailure;
 
398
        /* init the decoder context */
 
399
        p12dcx = SEC_PKCS12DecoderStart(uniPwp, slot, slotPw,
 
400
                                        NULL, NULL, NULL, NULL, NULL);
 
401
        if(!p12dcx) {
 
402
            SECU_PrintError(progName,"PKCS12 decoder start failed");
 
403
            pk12uErrno = PK12UERR_PK12DECODESTART;
 
404
            break;
 
405
        }
 
406
 
 
407
        /* decode the item */
 
408
        rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len);
 
409
 
 
410
        if(rv != SECSuccess) {
 
411
            error = PR_GetError();
 
412
            if(error == SEC_ERROR_DECRYPTION_DISALLOWED) {
 
413
                PR_SetError(error, 0);
 
414
                break;
 
415
            }
 
416
            SECU_PrintError(progName,"PKCS12 decoding failed");
 
417
            pk12uErrno = PK12UERR_DECODE;
 
418
        }
 
419
 
 
420
        /* does the blob authenticate properly? */
 
421
        rv = SEC_PKCS12DecoderVerify(p12dcx);
 
422
        if (rv != SECSuccess) {
 
423
            if(uniPwp->len == 2) {
 
424
                /* this is a null PW, try once more with a zero-length PW
 
425
                   instead of a null string */
 
426
                SEC_PKCS12DecoderFinish(p12dcx);
 
427
                uniPwp->len = 0;
 
428
                trypw = PR_TRUE;
 
429
            }
 
430
            else {
 
431
                SECU_PrintError(progName,"PKCS12 decode not verified");
 
432
                pk12uErrno = PK12UERR_DECODEVERIFY;
 
433
                break;
 
434
            }
 
435
        }
 
436
    } while (trypw == PR_TRUE);
 
437
    /* rv has been set at this point */
 
438
 
 
439
 
 
440
done:
 
441
    if (rv != SECSuccess) {
 
442
        if (p12dcx != NULL) {
 
443
            SEC_PKCS12DecoderFinish(p12dcx);
 
444
            p12dcx = NULL;
 
445
        }
 
446
        if (uniPwp->data) {
 
447
            SECITEM_ZfreeItem(uniPwp, PR_FALSE);
 
448
            uniPwp->data = NULL;
 
449
        }
 
450
    }
 
451
    PR_Close(p12cxt->file);
 
452
    p12cxt->file = NULL;
 
453
    /* PK11_FreeSlot(slot); */
 
454
    p12u_DestroyContext(&p12cxt, PR_FALSE);
 
455
 
 
456
    if (pwitem) {
 
457
        SECITEM_ZfreeItem(pwitem, PR_TRUE);
 
458
    }
 
459
    return p12dcx;
 
460
}
 
461
 
 
462
/*
 
463
 * given a filename for pkcs12 file, imports certs and keys
 
464
 *
 
465
 * Change: altitude
 
466
 *  I've changed this function so that it takes the keydb and pkcs12 file
 
467
 *  passwords from files.  The "pwdKeyDB" and "pwdP12File"
 
468
 *  variables have been added for this purpose.
 
469
 */
 
470
PRIntn
 
471
P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot,
 
472
                        secuPWData *slotPw, secuPWData *p12FilePw)
 
473
{
 
474
    SEC_PKCS12DecoderContext *p12dcx = NULL;
 
475
    SECItem uniPwitem = { 0 };
 
476
    SECStatus rv = SECFailure;
 
477
    int error;
 
478
 
 
479
    rv = P12U_InitSlot(slot, slotPw);
 
480
    if (rv != SECSuccess) {
 
481
        SECU_PrintError(progName, "Failed to authenticate to \"%s\"",
 
482
                                                 PK11_GetSlotName(slot));
 
483
        pk12uErrno = PK12UERR_PK11GETSLOT;
 
484
        return rv;
 
485
    }
 
486
 
 
487
    rv = SECFailure;
 
488
    p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw, p12FilePw);
 
489
    
 
490
    if(p12dcx == NULL) {
 
491
        goto loser;
 
492
    }
 
493
    
 
494
    /* make sure the bags are okey dokey -- nicknames correct, etc. */
 
495
    rv = SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback);
 
496
    if (rv != SECSuccess) {
 
497
        if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) {
 
498
            pk12uErrno = PK12UERR_CERTALREADYEXISTS;
 
499
        } else {
 
500
            pk12uErrno = PK12UERR_DECODEVALIBAGS;
 
501
        }
 
502
        SECU_PrintError(progName,"PKCS12 decode validate bags failed");
 
503
        goto loser;
 
504
    }
 
505
 
 
506
    /* stuff 'em in */
 
507
    rv = SEC_PKCS12DecoderImportBags(p12dcx);
 
508
    if (rv != SECSuccess) {
 
509
        SECU_PrintError(progName,"PKCS12 decode import bags failed");
 
510
        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
 
511
        goto loser;
 
512
    }
 
513
 
 
514
    fprintf(stdout, "%s: PKCS12 IMPORT SUCCESSFUL\n", progName);
 
515
    rv = SECSuccess;
 
516
 
 
517
loser:
 
518
    if (p12dcx) {
 
519
        SEC_PKCS12DecoderFinish(p12dcx);
 
520
    }
 
521
    
 
522
    if (uniPwitem.data) {
 
523
        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
 
524
    }
 
525
    
 
526
    return rv;
 
527
}
 
528
 
 
529
static void
 
530
p12u_DoPKCS12ExportErrors()
 
531
{
 
532
    int error_value;
 
533
 
 
534
    error_value = PORT_GetError();
 
535
    if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) ||
 
536
        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) ||
 
537
        (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) {
 
538
        fprintf(stderr, SECU_ErrorStringRaw((int16)error_value));
 
539
    } else if(error_value == SEC_ERROR_USER_CANCELLED) {
 
540
        ;
 
541
    } else {
 
542
        fprintf(stderr, SECU_ErrorStringRaw(SEC_ERROR_EXPORTING_CERTIFICATES));
 
543
    }
 
544
}
 
545
 
 
546
static void
 
547
p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len)
 
548
{
 
549
    p12uContext *p12cxt = arg;
 
550
    int writeLen;
 
551
 
 
552
    if(!p12cxt || (p12cxt->error == PR_TRUE)) {
 
553
        return;
 
554
    }
 
555
 
 
556
    if(p12cxt->file == NULL) {
 
557
        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
 
558
        p12cxt->error = PR_TRUE;
 
559
        return;
 
560
    }
 
561
 
 
562
    writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len);
 
563
 
 
564
    if(writeLen != (int)len) {
 
565
        PR_Close(p12cxt->file);
 
566
        PR_Free(p12cxt->filename);
 
567
        p12cxt->filename = NULL;
 
568
        p12cxt->file = NULL;
 
569
        p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE;
 
570
        p12cxt->error = PR_TRUE;
 
571
    }
 
572
}
 
573
 
 
574
 
 
575
void
 
576
P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot,
 
577
                        secuPWData *slotPw, secuPWData *p12FilePw)
 
578
{
 
579
    SEC_PKCS12ExportContext *p12ecx = NULL;
 
580
    SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL;
 
581
    SECItem *pwitem = NULL;
 
582
    p12uContext *p12cxt = NULL;
 
583
    CERTCertList* certlist = NULL;
 
584
    CERTCertListNode* node = NULL;
 
585
    PK11SlotInfo* slot = NULL;
 
586
 
 
587
    if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) {
 
588
        SECU_PrintError(progName,"Failed to authenticate to \"%s\"",
 
589
                          PK11_GetSlotName(inSlot));
 
590
        pk12uErrno = PK12UERR_PK11GETSLOT;
 
591
        goto loser;
 
592
    }
 
593
    certlist = PK11_FindCertsFromNickname(nn, slotPw);
 
594
    if(!certlist) {
 
595
        SECU_PrintError(progName,"find user certs from nickname failed");
 
596
        pk12uErrno = PK12UERR_FINDCERTBYNN;
 
597
        return;
 
598
    }
 
599
 
 
600
    if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) ||
 
601
        CERT_LIST_EMPTY(certlist)) {
 
602
        SECU_PrintError(progName,"no user certs from given nickname");
 
603
        pk12uErrno = PK12UERR_FINDCERTBYNN;
 
604
        goto loser;
 
605
    }
 
606
 
 
607
    /*  Password to use for PKCS12 file.  */
 
608
    pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw);
 
609
    if(!pwitem) {
 
610
        goto loser;
 
611
    }
 
612
 
 
613
    p12cxt = p12u_InitContext(PR_FALSE, outfile); 
 
614
    if(!p12cxt) {
 
615
        SECU_PrintError(progName,"Initialization failed: %s", outfile);
 
616
        pk12uErrno = PK12UERR_INIT_FILE;
 
617
        goto loser;
 
618
    }
 
619
 
 
620
    if (certlist) {
 
621
        CERTCertificate* cert = NULL;
 
622
        node = CERT_LIST_HEAD(certlist);
 
623
        if (node) {
 
624
            cert = node->cert;
 
625
        }
 
626
        if (cert) {
 
627
            slot = cert->slot; /* use the slot from the first matching
 
628
                certificate to create the context . This is for keygen */
 
629
        }
 
630
    }
 
631
    if (!slot) {
 
632
        SECU_PrintError(progName,"cert does not have a slot");
 
633
        pk12uErrno = PK12UERR_FINDCERTBYNN;
 
634
        goto loser;
 
635
    }
 
636
    p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw);
 
637
    if(!p12ecx) {
 
638
        SECU_PrintError(progName,"export context creation failed");
 
639
        pk12uErrno = PK12UERR_EXPORTCXCREATE;
 
640
        goto loser;
 
641
    }
 
642
 
 
643
    if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, SEC_OID_SHA1)
 
644
       != SECSuccess) {
 
645
        SECU_PrintError(progName,"PKCS12 add password integrity failed");
 
646
        pk12uErrno = PK12UERR_PK12ADDPWDINTEG;
 
647
        goto loser;
 
648
    }
 
649
 
 
650
    for (node = CERT_LIST_HEAD(certlist);!CERT_LIST_END(node,certlist);node=CERT_LIST_NEXT(node))
 
651
    {
 
652
        CERTCertificate* cert = node->cert;
 
653
        if (!cert->slot) {
 
654
            SECU_PrintError(progName,"cert does not have a slot");
 
655
            pk12uErrno = PK12UERR_FINDCERTBYNN;
 
656
            goto loser;
 
657
        }
 
658
    
 
659
        keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx);
 
660
        if(/*!SEC_PKCS12IsEncryptionAllowed() || */ PK11_IsFIPS()) {
 
661
            certSafe = keySafe;
 
662
        } else {
 
663
            certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem,
 
664
                SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC);
 
665
        }
 
666
    
 
667
        if(!certSafe || !keySafe) {
 
668
            SECU_PrintError(progName,"key or cert safe creation failed");
 
669
            pk12uErrno = PK12UERR_CERTKEYSAFE;
 
670
            goto loser;
 
671
        }
 
672
    
 
673
        if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert,
 
674
            CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem,
 
675
            SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC)
 
676
            != SECSuccess) {
 
677
                SECU_PrintError(progName,"add cert and key failed");
 
678
                pk12uErrno = PK12UERR_ADDCERTKEY;
 
679
                goto loser;
 
680
        }
 
681
    }
 
682
 
 
683
    CERT_DestroyCertList(certlist);
 
684
    certlist = NULL;
 
685
 
 
686
    if(SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt)
 
687
                        != SECSuccess) {
 
688
        SECU_PrintError(progName,"PKCS12 encode failed");
 
689
        pk12uErrno = PK12UERR_ENCODE;
 
690
        goto loser;
 
691
    }
 
692
 
 
693
    p12u_DestroyContext(&p12cxt, PR_FALSE);
 
694
    SECITEM_ZfreeItem(pwitem, PR_TRUE);
 
695
    fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName);
 
696
    SEC_PKCS12DestroyExportContext(p12ecx);
 
697
 
 
698
    return;
 
699
 
 
700
loser:
 
701
    SEC_PKCS12DestroyExportContext(p12ecx);
 
702
 
 
703
    if (certlist) {
 
704
        CERT_DestroyCertList(certlist);
 
705
        certlist = NULL;
 
706
    }    
 
707
 
 
708
    if (slotPw)
 
709
        PR_Free(slotPw->data);
 
710
 
 
711
    if (p12FilePw)
 
712
        PR_Free(p12FilePw->data);
 
713
 
 
714
    p12u_DestroyContext(&p12cxt, PR_TRUE);
 
715
    if(pwitem) {
 
716
        SECITEM_ZfreeItem(pwitem, PR_TRUE);
 
717
    }
 
718
    p12u_DoPKCS12ExportErrors();
 
719
    return;
 
720
}
 
721
 
 
722
 
 
723
PRIntn
 
724
P12U_ListPKCS12File(char *in_file, PK11SlotInfo *slot,
 
725
                        secuPWData *slotPw, secuPWData *p12FilePw)
 
726
{
 
727
    SEC_PKCS12DecoderContext *p12dcx = NULL;
 
728
    SECItem uniPwitem = { 0 };
 
729
    SECStatus rv = SECFailure;
 
730
    const SEC_PKCS12DecoderItem *dip;
 
731
    int error;
 
732
 
 
733
    p12dcx = p12U_ReadPKCS12File(&uniPwitem, in_file, slot, slotPw,
 
734
                             p12FilePw);
 
735
    /* did the blob authenticate properly? */
 
736
    if(p12dcx == NULL) {
 
737
        SECU_PrintError(progName,"PKCS12 decode not verified");
 
738
        pk12uErrno = PK12UERR_DECODEVERIFY;
 
739
        goto loser;
 
740
    }
 
741
    rv = SEC_PKCS12DecoderIterateInit(p12dcx);
 
742
    if(rv != SECSuccess) {
 
743
        SECU_PrintError(progName,"PKCS12 decode iterate bags failed");
 
744
        pk12uErrno = PK12UERR_DECODEIMPTBAGS;
 
745
        rv = SECFailure;
 
746
    }
 
747
    else {
 
748
        while (SEC_PKCS12DecoderIterateNext(p12dcx, &dip) == SECSuccess) {
 
749
            switch (dip->type) {
 
750
                case SEC_OID_PKCS12_V1_CERT_BAG_ID:
 
751
                    printf("Certificate");
 
752
                    if (SECU_PrintSignedData(stdout, dip->der,
 
753
                            (dip->hasKey) ? "(has private key)" : "",
 
754
                             0, SECU_PrintCertificate) != 0) {
 
755
                        SECU_PrintError(progName,"PKCS12 print cert bag failed");
 
756
                    }
 
757
                    if (dip->friendlyName != NULL) {
 
758
                        printf("    Friendly Name: %s\n\n",
 
759
                                dip->friendlyName->data);
 
760
                    }
 
761
                    break;
 
762
                case SEC_OID_PKCS12_V1_KEY_BAG_ID:
 
763
                case SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID:
 
764
                    printf("Key");
 
765
                    if (dip->type == SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID)
 
766
                        printf("(shrouded)");
 
767
                    printf(":\n");
 
768
                    if (dip->friendlyName != NULL) {
 
769
                        printf("    Friendly Name: %s\n\n",
 
770
                                dip->friendlyName->data);
 
771
                    }
 
772
                    break;
 
773
                default:
 
774
                    printf("unknown bag type(%d): %s\n\n", dip->type,
 
775
                            SECOID_FindOIDTagDescription(dip->type));
 
776
                    break;
 
777
            }
 
778
        }
 
779
        rv = SECSuccess;
 
780
    }
 
781
 
 
782
loser:
 
783
    
 
784
    if (p12dcx) {
 
785
        SEC_PKCS12DecoderFinish(p12dcx);
 
786
    }
 
787
    
 
788
    if (uniPwitem.data) {
 
789
        SECITEM_ZfreeItem(&uniPwitem, PR_FALSE);
 
790
    }
 
791
    
 
792
    return rv;
 
793
}
 
794
 
 
795
static void
 
796
p12u_EnableAllCiphers()
 
797
{
 
798
    SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1);
 
799
    SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1);
 
800
    SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1);
 
801
    SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1);
 
802
    SEC_PKCS12EnableCipher(PKCS12_DES_56, 1);
 
803
    SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1);
 
804
    SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1);
 
805
}
 
806
 
 
807
static PRUintn
 
808
P12U_Init(char *dir, char *dbprefix, PRBool listonly)
 
809
{
 
810
    SECStatus rv;
 
811
    PK11_SetPasswordFunc(SECU_GetModulePassword);
 
812
 
 
813
    PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
 
814
    if (listonly && NSS_NoDB_Init("") == SECSuccess) {
 
815
        rv = SECSuccess;
 
816
    }
 
817
    else {
 
818
        rv = NSS_Initialize(dir,dbprefix,dbprefix,"secmod.db",0);
 
819
    }
 
820
    if (rv != SECSuccess) {
 
821
        SECU_PrintPRandOSError(progName);
 
822
        exit(-1);
 
823
    }
 
824
 
 
825
    /* setup unicode callback functions */
 
826
    PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function);
 
827
    /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */
 
828
 
 
829
    p12u_EnableAllCiphers();
 
830
 
 
831
    return 0;
 
832
}
 
833
 
 
834
enum {
 
835
    opt_CertDir = 0,
 
836
    opt_TokenName,
 
837
    opt_Import,
 
838
    opt_SlotPWFile,
 
839
    opt_SlotPW,
 
840
    opt_List,
 
841
    opt_Nickname,
 
842
    opt_Export,
 
843
    opt_P12FilePWFile,
 
844
    opt_P12FilePW,
 
845
    opt_DBPrefix,
 
846
    opt_Debug
 
847
};
 
848
 
 
849
static secuCommandFlag pk12util_options[] =
 
850
{
 
851
    { /* opt_CertDir           */ 'd', PR_TRUE,  0, PR_FALSE },
 
852
    { /* opt_TokenName         */ 'h', PR_TRUE,  0, PR_FALSE },
 
853
    { /* opt_Import            */ 'i', PR_TRUE,  0, PR_FALSE },
 
854
    { /* opt_SlotPWFile        */ 'k', PR_TRUE,  0, PR_FALSE },
 
855
    { /* opt_SlotPW            */ 'K', PR_TRUE,  0, PR_FALSE },
 
856
    { /* opt_List              */ 'l', PR_TRUE,  0, PR_FALSE },
 
857
    { /* opt_Nickname          */ 'n', PR_TRUE,  0, PR_FALSE },
 
858
    { /* opt_Export            */ 'o', PR_TRUE,  0, PR_FALSE },
 
859
    { /* opt_P12FilePWFile     */ 'w', PR_TRUE,  0, PR_FALSE },
 
860
    { /* opt_P12FilePW         */ 'W', PR_TRUE,  0, PR_FALSE },
 
861
    { /* opt_DBPrefix          */ 'P', PR_TRUE,  0, PR_FALSE },
 
862
    { /* opt_Debug             */ 'v', PR_FALSE, 0, PR_FALSE }
 
863
};
 
864
 
 
865
int
 
866
main(int argc, char **argv)
 
867
{
 
868
    secuPWData slotPw = { PW_NONE, NULL };
 
869
    secuPWData p12FilePw = { PW_NONE, NULL };
 
870
    PK11SlotInfo *slot;
 
871
    char *slotname = NULL;
 
872
    char *import_file = NULL;
 
873
    char *export_file = NULL;
 
874
    char *dbprefix = "";
 
875
    SECStatus rv;
 
876
 
 
877
    secuCommand pk12util;
 
878
    pk12util.numCommands = 0;
 
879
    pk12util.commands = 0;
 
880
    pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag);
 
881
    pk12util.options = pk12util_options;
 
882
 
 
883
    progName = strrchr(argv[0], '/');
 
884
    progName = progName ? progName+1 : argv[0];
 
885
 
 
886
    rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util);
 
887
 
 
888
    if (rv != SECSuccess)
 
889
        Usage(progName);
 
890
 
 
891
    pk12_debugging = pk12util.options[opt_Debug].activated;
 
892
 
 
893
    if ((pk12util.options[opt_Import].activated +
 
894
        pk12util.options[opt_Export].activated +
 
895
        pk12util.options[opt_List].activated) != 1) {
 
896
        Usage(progName);
 
897
    }
 
898
 
 
899
    if (pk12util.options[opt_Export].activated &&
 
900
       !pk12util.options[opt_Nickname].activated) {
 
901
        Usage(progName);
 
902
    }
 
903
 
 
904
    slotname = SECU_GetOptionArg(&pk12util, opt_TokenName);
 
905
 
 
906
    import_file = (pk12util.options[opt_List].activated) ?
 
907
                    SECU_GetOptionArg(&pk12util, opt_List) :
 
908
                    SECU_GetOptionArg(&pk12util, opt_Import);
 
909
    export_file = SECU_GetOptionArg(&pk12util, opt_Export);
 
910
 
 
911
    if (pk12util.options[opt_P12FilePWFile].activated) {
 
912
        p12FilePw.source = PW_FROMFILE;
 
913
        p12FilePw.data = PL_strdup(pk12util.options[opt_P12FilePWFile].arg);
 
914
    }
 
915
 
 
916
    if (pk12util.options[opt_P12FilePW].activated) {
 
917
        p12FilePw.source = PW_PLAINTEXT;
 
918
        p12FilePw.data = PL_strdup(pk12util.options[opt_P12FilePW].arg);
 
919
    }
 
920
 
 
921
    if (pk12util.options[opt_SlotPWFile].activated) {
 
922
        slotPw.source = PW_FROMFILE;
 
923
        slotPw.data = PL_strdup(pk12util.options[opt_SlotPWFile].arg);
 
924
    }
 
925
 
 
926
    if (pk12util.options[opt_SlotPW].activated) {
 
927
        slotPw.source = PW_PLAINTEXT;
 
928
        slotPw.data = PL_strdup(pk12util.options[opt_SlotPW].arg);
 
929
    }
 
930
 
 
931
    if (pk12util.options[opt_CertDir].activated) {
 
932
        SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg);
 
933
    }
 
934
    if (pk12util.options[opt_DBPrefix].activated) {
 
935
        dbprefix = pk12util.options[opt_DBPrefix].arg;
 
936
    }
 
937
    P12U_Init(SECU_ConfigDirectory(NULL), dbprefix,
 
938
                pk12util.options[opt_List].activated);
 
939
 
 
940
    if (!slotname || PL_strcmp(slotname, "internal") == 0)
 
941
        slot = PK11_GetInternalKeySlot();
 
942
    else
 
943
        slot = PK11_FindSlotByName(slotname);
 
944
 
 
945
    if (!slot) {
 
946
        SECU_PrintError(progName,"Invalid slot \"%s\"", slotname);
 
947
        pk12uErrno = PK12UERR_PK11GETSLOT;
 
948
        goto done;
 
949
    }
 
950
 
 
951
    if (pk12util.options[opt_Import].activated) {
 
952
        P12U_ImportPKCS12Object(import_file, slot, &slotPw,
 
953
                                           &p12FilePw);
 
954
 
 
955
    } else if (pk12util.options[opt_Export].activated) {
 
956
        P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg,
 
957
                                export_file, slot, &slotPw, &p12FilePw);
 
958
        
 
959
    } else if (pk12util.options[opt_List].activated) {
 
960
        P12U_ListPKCS12File(import_file, slot, &slotPw, &p12FilePw);
 
961
                                           
 
962
    } else {
 
963
        Usage(progName);
 
964
        pk12uErrno = PK12UERR_USAGE;
 
965
    }
 
966
 
 
967
done:
 
968
    if (slot) PK11_FreeSlot(slot);
 
969
    if (NSS_Shutdown() != SECSuccess) {
 
970
        pk12uErrno = 1;
 
971
    }
 
972
    return pk12uErrno;
 
973
}