~ubuntu-branches/ubuntu/trusty/xulrunner/trusty

« back to all changes in this revision

Viewing changes to security/nss-fips/cmd/signtool/certgen.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-25 13:04:18 UTC
  • mfrom: (1.1.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825130418-ck1i2ms384tzb9m0
Tags: 1.8.1.16+nobinonly-0ubuntu1
* New upstream release (taken from upstream CVS), LP: #254618.
* Fix MFSA 2008-35, MFSA 2008-34, MFSA 2008-33, MFSA 2008-32, MFSA 2008-31,
  MFSA 2008-30, MFSA 2008-29, MFSA 2008-28, MFSA 2008-27, MFSA 2008-25,
  MFSA 2008-24, MFSA 2008-23, MFSA 2008-22, MFSA 2008-21, MFSA 2008-26 also
  known as CVE-2008-2933, CVE-2008-2785, CVE-2008-2811, CVE-2008-2810,
  CVE-2008-2809, CVE-2008-2808, CVE-2008-2807, CVE-2008-2806, CVE-2008-2805,
  CVE-2008-2803, CVE-2008-2802, CVE-2008-2801, CVE-2008-2800, CVE-2008-2798.
* Drop 89_bz419350_attachment_306066 patch, merged upstream.
* Bump Standards-Version to 3.8.0.

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 "signtool.h"
 
38
 
 
39
#include "secoid.h"
 
40
#include "cryptohi.h"
 
41
#include "certdb.h"
 
42
 
 
43
static char     *GetSubjectFromUser(unsigned long serial);
 
44
static CERTCertificate*GenerateSelfSignedObjectSigningCert(char *nickname,
 
45
        CERTCertDBHandle *db, char *subject, unsigned long serial, int keysize,
 
46
        char *token);
 
47
static SECStatus ChangeTrustAttributes(CERTCertDBHandle *db,
 
48
        CERTCertificate *cert, char *trusts);
 
49
static SECStatus set_cert_type(CERTCertificate *cert, unsigned int type);
 
50
static SECItem *sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk);
 
51
static CERTCertificate*install_cert(CERTCertDBHandle *db, SECItem *derCert,
 
52
            char *nickname);
 
53
static SECStatus GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk,
 
54
        SECKEYPrivateKey **privk, int keysize);
 
55
static CERTCertificateRequest*make_cert_request(char *subject,
 
56
        SECKEYPublicKey *pubk);
 
57
static CERTCertificate *make_cert(CERTCertificateRequest *req,
 
58
        unsigned long serial, CERTName *ca_subject);
 
59
static void     output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db);
 
60
 
 
61
 
 
62
/***********************************************************************
 
63
 *
 
64
 * G e n e r a t e C e r t
 
65
 *
 
66
 * Runs the whole process of creating a new cert, getting info from the
 
67
 * user, etc.
 
68
 */
 
69
int
 
70
GenerateCert(char *nickname, int keysize, char *token)
 
71
{
 
72
    CERTCertDBHandle * db;
 
73
    CERTCertificate * cert;
 
74
    char        *subject;
 
75
    unsigned long       serial;
 
76
    char        stdinbuf[160];
 
77
 
 
78
    /* Print warning about having the browser open */
 
79
    PR_fprintf(PR_STDOUT /*always go to console*/,
 
80
        "\nWARNING: Performing this operation while the browser is running could cause"
 
81
        "\ncorruption of your security databases. If the browser is currently running,"
 
82
        "\nyou should exit the browser before continuing this operation. Enter "
 
83
        "\n\"y\" to continue, or anything else to abort: ");
 
84
    pr_fgets(stdinbuf, 160, PR_STDIN);
 
85
    PR_fprintf(PR_STDOUT, "\n");
 
86
    if (tolower(stdinbuf[0]) != 'y') {
 
87
        PR_fprintf(errorFD, "Operation aborted at user's request.\n");
 
88
        errorCount++;
 
89
        return - 1;
 
90
    }
 
91
 
 
92
    db = CERT_GetDefaultCertDB();
 
93
    if (!db) {
 
94
        FatalError("Unable to open certificate database");
 
95
    }
 
96
 
 
97
    if (PK11_FindCertFromNickname(nickname, NULL)) {
 
98
        PR_fprintf(errorFD,
 
99
            "ERROR: Certificate with nickname \"%s\" already exists in database. You\n"
 
100
            "must choose a different nickname.\n", nickname);
 
101
        errorCount++;
 
102
        exit(ERRX);
 
103
    }
 
104
 
 
105
    LL_L2UI(serial, PR_Now());
 
106
 
 
107
    subject = GetSubjectFromUser(serial);
 
108
 
 
109
    cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject,
 
110
                        serial, keysize, token);
 
111
 
 
112
    if (cert) {
 
113
        output_ca_cert(cert, db);
 
114
        CERT_DestroyCertificate(cert);
 
115
    }
 
116
 
 
117
    PORT_Free(subject);
 
118
    return 0;
 
119
}
 
120
 
 
121
 
 
122
#undef VERBOSE_PROMPTS
 
123
 
 
124
/*********************************************************************8
 
125
 * G e t S u b j e c t F r o m U s e r
 
126
 *
 
127
 * Construct the subject information line for a certificate by querying
 
128
 * the user on stdin.
 
129
 */
 
130
static char     *
 
131
GetSubjectFromUser(unsigned long serial)
 
132
{
 
133
    char        buf[STDIN_BUF_SIZE];
 
134
    char        common_name_buf[STDIN_BUF_SIZE];
 
135
    char        *common_name, *state, *orgunit, *country, *org, *locality;
 
136
    char        *email, *uid;
 
137
    char        *subject;
 
138
    char        *cp;
 
139
    int subjectlen = 0;
 
140
 
 
141
    common_name = state = orgunit = country = org = locality = email =
 
142
        uid = subject = NULL;
 
143
 
 
144
    /* Get subject information */
 
145
    PR_fprintf(PR_STDOUT,
 
146
        "\nEnter certificate information.  All fields are optional. Acceptable\n"
 
147
        "characters are numbers, letters, spaces, and apostrophes.\n");
 
148
 
 
149
#ifdef VERBOSE_PROMPTS
 
150
    PR_fprintf(PR_STDOUT, "\nCOMMON NAME\n"
 
151
        "Enter the full name you want to give your certificate. (Example: Test-Only\n"
 
152
        "Object Signing Certificate)\n"
 
153
        "-->");
 
154
#else
 
155
    PR_fprintf(PR_STDOUT, "certificate common name: ");
 
156
#endif
 
157
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
158
    cp = chop(buf);
 
159
    if (*cp == '\0') {
 
160
        sprintf(common_name_buf, "%s (%lu)", DEFAULT_COMMON_NAME,
 
161
             serial);
 
162
        cp = common_name_buf;
 
163
    }
 
164
    common_name = PORT_ZAlloc(strlen(cp) + 6);
 
165
    if (!common_name) {
 
166
        out_of_memory();
 
167
    }
 
168
    sprintf(common_name, "CN=%s, ", cp);
 
169
    subjectlen += strlen(common_name);
 
170
 
 
171
#ifdef VERBOSE_PROMPTS
 
172
    PR_fprintf(PR_STDOUT, "\nORGANIZATION NAME\n"
 
173
        "Enter the name of your organization. For example, this could be the name\n"
 
174
        "of your company.\n"
 
175
        "-->");
 
176
#else
 
177
    PR_fprintf(PR_STDOUT, "organization: ");
 
178
#endif
 
179
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
180
    cp = chop(buf);
 
181
    if (*cp != '\0') {
 
182
        org = PORT_ZAlloc(strlen(cp) + 5);
 
183
        if (!org) {
 
184
            out_of_memory();
 
185
        }
 
186
        sprintf(org, "O=%s, ", cp);
 
187
        subjectlen += strlen(org);
 
188
    }
 
189
 
 
190
#ifdef VERBOSE_PROMPTS
 
191
    PR_fprintf(PR_STDOUT, "\nORGANIZATION UNIT\n"
 
192
        "Enter the name of your organization unit.  For example, this could be the\n"
 
193
        "name of your department.\n"
 
194
        "-->");
 
195
#else
 
196
    PR_fprintf(PR_STDOUT, "organization unit: ");
 
197
#endif
 
198
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
199
    cp = chop(buf);
 
200
    if (*cp != '\0') {
 
201
        orgunit = PORT_ZAlloc(strlen(cp) + 6);
 
202
        if (!orgunit) {
 
203
            out_of_memory();
 
204
        }
 
205
        sprintf(orgunit, "OU=%s, ", cp);
 
206
        subjectlen += strlen(orgunit);
 
207
    }
 
208
 
 
209
#ifdef VERBOSE_PROMPTS
 
210
    PR_fprintf(PR_STDOUT, "\nSTATE\n"
 
211
        "Enter the name of your state or province.\n"
 
212
        "-->");
 
213
#else
 
214
    PR_fprintf(PR_STDOUT, "state or province: ");
 
215
#endif
 
216
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
217
    cp = chop(buf);
 
218
    if (*cp != '\0') {
 
219
        state = PORT_ZAlloc(strlen(cp) + 6);
 
220
        if (!state) {
 
221
            out_of_memory();
 
222
        }
 
223
        sprintf(state, "ST=%s, ", cp);
 
224
        subjectlen += strlen(state);
 
225
    }
 
226
 
 
227
#ifdef VERBOSE_PROMPTS
 
228
    PR_fprintf(PR_STDOUT, "\nCOUNTRY\n"
 
229
        "Enter the 2-character abbreviation for the name of your country.\n"
 
230
        "-->");
 
231
#else
 
232
    PR_fprintf(PR_STDOUT, "country (must be exactly 2 characters): ");
 
233
#endif
 
234
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
235
    cp = chop(cp);
 
236
    if (strlen(cp) != 2) {
 
237
        *cp = '\0';     /* country code must be 2 chars */
 
238
    }
 
239
    if (*cp != '\0') {
 
240
        country = PORT_ZAlloc(strlen(cp) + 5);
 
241
        if (!country) {
 
242
            out_of_memory();
 
243
        }
 
244
        sprintf(country, "C=%s, ", cp);
 
245
        subjectlen += strlen(country);
 
246
    }
 
247
 
 
248
#ifdef VERBOSE_PROMPTS
 
249
    PR_fprintf(PR_STDOUT, "\nUSERNAME\n"
 
250
        "Enter your system username or UID\n"
 
251
        "-->");
 
252
#else
 
253
    PR_fprintf(PR_STDOUT, "username: ");
 
254
#endif
 
255
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
256
    cp = chop(buf);
 
257
    if (*cp != '\0') {
 
258
        uid = PORT_ZAlloc(strlen(cp) + 7);
 
259
        if (!uid) {
 
260
            out_of_memory();
 
261
        }
 
262
        sprintf(uid, "UID=%s, ", cp);
 
263
        subjectlen += strlen(uid);
 
264
    }
 
265
 
 
266
#ifdef VERBOSE_PROMPTS
 
267
    PR_fprintf(PR_STDOUT, "\nEMAIL ADDRESS\n"
 
268
        "Enter your email address.\n"
 
269
        "-->");
 
270
#else
 
271
    PR_fprintf(PR_STDOUT, "email address: ");
 
272
#endif
 
273
    fgets(buf, STDIN_BUF_SIZE, stdin);
 
274
    cp = chop(buf);
 
275
    if (*cp != '\0') {
 
276
        email = PORT_ZAlloc(strlen(cp) + 5);
 
277
        if (!email) {
 
278
            out_of_memory();
 
279
        }
 
280
        sprintf(email, "E=%s,", cp);
 
281
        subjectlen += strlen(email);
 
282
    }
 
283
 
 
284
    subjectlen++;
 
285
 
 
286
    subject = PORT_ZAlloc(subjectlen);
 
287
    if (!subject) {
 
288
        out_of_memory();
 
289
    }
 
290
 
 
291
    sprintf(subject, "%s%s%s%s%s%s%s",
 
292
        common_name ? common_name : "",
 
293
        org ? org : "",
 
294
        orgunit ? orgunit : "",
 
295
        state ? state : "",
 
296
        country ? country : "",
 
297
        uid ? uid : "",
 
298
        email ? email : ""
 
299
        );
 
300
    if ( (strlen(subject) > 1) && (subject[strlen(subject)-1] == ' ') ) {
 
301
        subject[strlen(subject)-2] = '\0';
 
302
    }
 
303
 
 
304
    PORT_Free(common_name);
 
305
    PORT_Free(org);
 
306
    PORT_Free(orgunit);
 
307
    PORT_Free(state);
 
308
    PORT_Free(country);
 
309
    PORT_Free(uid);
 
310
    PORT_Free(email);
 
311
 
 
312
    return subject;
 
313
}
 
314
 
 
315
 
 
316
/**************************************************************************
 
317
 *
 
318
 * G e n e r a t e S e l f S i g n e d O b j e c t S i g n i n g C e r t
 
319
 *                                                                                                                                *phew*^
 
320
 *
 
321
 */
 
322
static CERTCertificate*
 
323
GenerateSelfSignedObjectSigningCert(char *nickname, CERTCertDBHandle *db,
 
324
        char *subject, unsigned long serial, int keysize, char *token)
 
325
{
 
326
    CERTCertificate * cert, *temp_cert;
 
327
    SECItem * derCert;
 
328
    CERTCertificateRequest * req;
 
329
 
 
330
    PK11SlotInfo * slot = NULL;
 
331
    SECKEYPrivateKey * privk = NULL;
 
332
    SECKEYPublicKey * pubk = NULL;
 
333
 
 
334
    if ( token ) {
 
335
        slot = PK11_FindSlotByName(token);
 
336
    } else {
 
337
        slot = PK11_GetInternalKeySlot();
 
338
    }
 
339
 
 
340
    if (slot == NULL) {
 
341
        PR_fprintf(errorFD, "Can't find PKCS11 slot %s\n",
 
342
            token ? token : "");
 
343
        errorCount++;
 
344
        exit (ERRX);
 
345
    }
 
346
 
 
347
    if ( GenerateKeyPair(slot, &pubk, &privk, keysize) != SECSuccess) {
 
348
        FatalError("Error generating keypair.");
 
349
    }
 
350
    req = make_cert_request (subject, pubk);
 
351
    temp_cert = make_cert (req, serial, &req->subject);
 
352
    if (set_cert_type(temp_cert,
 
353
        NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA)
 
354
         != SECSuccess) {
 
355
        FatalError("Unable to set cert type");
 
356
    }
 
357
 
 
358
    derCert = sign_cert (temp_cert, privk);
 
359
    cert = install_cert(db, derCert, nickname);
 
360
    if (ChangeTrustAttributes(db, cert, ",,uC") != SECSuccess) {
 
361
        FatalError("Unable to change trust on generated certificate");
 
362
    }
 
363
 
 
364
    /* !!! Free memory ? !!! */
 
365
    PK11_FreeSlot(slot);
 
366
    SECKEY_DestroyPrivateKey(privk);
 
367
    SECKEY_DestroyPublicKey(pubk);
 
368
 
 
369
    return cert;
 
370
}
 
371
 
 
372
 
 
373
/**************************************************************************
 
374
 *
 
375
 * C h a n g e T r u s t A t t r i b u t e s
 
376
 */
 
377
static SECStatus
 
378
ChangeTrustAttributes(CERTCertDBHandle *db, CERTCertificate *cert, char *trusts)
 
379
{
 
380
 
 
381
    CERTCertTrust        * trust;
 
382
 
 
383
    if (!db || !cert || !trusts) {
 
384
        PR_fprintf(errorFD, "ChangeTrustAttributes got incomplete arguments.\n");
 
385
        errorCount++;
 
386
        return SECFailure;
 
387
    }
 
388
 
 
389
    trust = (CERTCertTrust * ) PORT_ZAlloc(sizeof(CERTCertTrust));
 
390
    if (!trust) {
 
391
        PR_fprintf(errorFD, "ChangeTrustAttributes unable to allocate "
 
392
            "CERTCertTrust\n");
 
393
        errorCount++;
 
394
        return SECFailure;
 
395
    }
 
396
 
 
397
    if ( CERT_DecodeTrustString(trust, trusts) ) {
 
398
        return SECFailure;
 
399
    }
 
400
 
 
401
    if ( CERT_ChangeCertTrust(db, cert, trust) ) {
 
402
        PR_fprintf(errorFD, "unable to modify trust attributes for cert %s\n",
 
403
                         cert->nickname ? cert->nickname : "");
 
404
        errorCount++;
 
405
        return SECFailure;
 
406
    }
 
407
 
 
408
    return SECSuccess;
 
409
}
 
410
 
 
411
 
 
412
/*************************************************************************
 
413
 *
 
414
 * s e t _ c e r t _ t y p e
 
415
 */
 
416
static SECStatus
 
417
set_cert_type(CERTCertificate *cert, unsigned int type)
 
418
{
 
419
    void        *context;
 
420
    SECStatus status = SECSuccess;
 
421
    SECItem certType;
 
422
    char        ctype;
 
423
 
 
424
    context = CERT_StartCertExtensions(cert);
 
425
 
 
426
    certType.type = siBuffer;
 
427
    certType.data = (unsigned char * ) &ctype;
 
428
    certType.len = 1;
 
429
    ctype = (unsigned char)type;
 
430
    if (CERT_EncodeAndAddBitStrExtension(context, SEC_OID_NS_CERT_EXT_CERT_TYPE,
 
431
                 &certType, PR_TRUE /*critical*/) != SECSuccess) {
 
432
        status = SECFailure;
 
433
    }
 
434
 
 
435
    if (CERT_FinishExtensions(context) != SECSuccess) {
 
436
        status = SECFailure;
 
437
    }
 
438
 
 
439
    return status;
 
440
}
 
441
 
 
442
 
 
443
/********************************************************************
 
444
 *
 
445
 * s i g n _ c e r t
 
446
 */
 
447
static SECItem *
 
448
sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk)
 
449
{
 
450
    SECStatus rv;
 
451
 
 
452
    SECItem der2;
 
453
    SECItem * result2;
 
454
 
 
455
    void        *dummy;
 
456
    SECOidTag alg = SEC_OID_UNKNOWN;
 
457
 
 
458
    switch (privk->keyType) {
 
459
    case rsaKey:
 
460
        alg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION;
 
461
        break;
 
462
 
 
463
    case dsaKey:
 
464
        alg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST;
 
465
        break;
 
466
    default:
 
467
        FatalError("Unknown key type");
 
468
    }
 
469
    PORT_Assert(alg != SEC_OID_UNKNOWN);
 
470
 
 
471
    rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0);
 
472
 
 
473
    if (rv != SECSuccess) {
 
474
        PR_fprintf(errorFD, "%s: unable to set signature alg id\n",
 
475
             PROGRAM_NAME);
 
476
        errorCount++;
 
477
        exit (ERRX);
 
478
    }
 
479
 
 
480
    der2.len = 0;
 
481
    der2.data = NULL;
 
482
 
 
483
    dummy = SEC_ASN1EncodeItem
 
484
        (cert->arena, &der2, cert, CERT_CertificateTemplate);
 
485
 
 
486
    if (rv != SECSuccess) {
 
487
        PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME);
 
488
        errorCount++;
 
489
        exit (ERRX);
 
490
    }
 
491
 
 
492
    result2 = (SECItem * ) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem));
 
493
    if (result2 == NULL)
 
494
        out_of_memory();
 
495
 
 
496
    rv = SEC_DerSignData 
 
497
        (cert->arena, result2, der2.data, der2.len, privk, alg);
 
498
 
 
499
    if (rv != SECSuccess) {
 
500
        PR_fprintf(errorFD, "can't sign encoded certificate data\n");
 
501
        errorCount++;
 
502
        exit (ERRX);
 
503
    } else if (verbosity >= 0) {
 
504
        PR_fprintf(outputFD, "certificate has been signed\n");
 
505
    }
 
506
 
 
507
    cert->derCert = *result2;
 
508
 
 
509
    return result2;
 
510
}
 
511
 
 
512
 
 
513
/*********************************************************************
 
514
 *
 
515
 * i n s t a l l _ c e r t
 
516
 *
 
517
 * Installs the cert in the permanent database.
 
518
 */
 
519
static CERTCertificate*
 
520
install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname)
 
521
{
 
522
    CERTCertificate * newcert;
 
523
    PK11SlotInfo * newSlot;
 
524
 
 
525
    newcert = CERT_DecodeDERCertificate(derCert, PR_TRUE, NULL);
 
526
 
 
527
    if (newcert == NULL) {
 
528
        PR_fprintf(errorFD, "%s: can't create new certificate\n",
 
529
             PROGRAM_NAME);
 
530
        errorCount++;
 
531
        exit (ERRX);
 
532
    }
 
533
 
 
534
    newSlot = PK11_ImportCertForKey(newcert, nickname, NULL /*wincx*/);
 
535
    if ( newSlot == NULL ) {
 
536
        PR_fprintf(errorFD, "Unable to install certificate\n");
 
537
        errorCount++;
 
538
        exit(ERRX);
 
539
    }
 
540
    PK11_FreeSlot(newSlot);
 
541
 
 
542
    if (verbosity >= 0) {
 
543
        PR_fprintf(outputFD, "certificate \"%s\" added to database\n",
 
544
             nickname);
 
545
    }
 
546
 
 
547
    return newcert;
 
548
}
 
549
 
 
550
 
 
551
/******************************************************************
 
552
 *
 
553
 * G e n e r a t e K e y P a i r
 
554
 */
 
555
static SECStatus
 
556
GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk,
 
557
SECKEYPrivateKey **privk, int keysize)
 
558
{
 
559
 
 
560
    PK11RSAGenParams rsaParams;
 
561
 
 
562
    if ( keysize == -1 ) {
 
563
        rsaParams.keySizeInBits = DEFAULT_RSA_KEY_SIZE;
 
564
    } else {
 
565
        rsaParams.keySizeInBits = keysize;
 
566
    }
 
567
    rsaParams.pe = 0x10001;
 
568
 
 
569
    if (PK11_Authenticate( slot, PR_FALSE /*loadCerts*/, NULL /*wincx*/)
 
570
         != SECSuccess) {
 
571
        SECU_PrintError(progName, "failure authenticating to key database.\n");
 
572
        exit(ERRX);
 
573
    }
 
574
 
 
575
    *privk = PK11_GenerateKeyPair (slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams,
 
576
         
 
577
        pubk, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, NULL /*wincx*/ );
 
578
 
 
579
    if (*privk != NULL && *pubk != NULL) {
 
580
        if (verbosity >= 0) {
 
581
            PR_fprintf(outputFD, "generated public/private key pair\n");
 
582
        }
 
583
    } else {
 
584
        SECU_PrintError(progName, "failure generating key pair\n");
 
585
        exit (ERRX);
 
586
    }
 
587
 
 
588
    return SECSuccess;
 
589
}
 
590
 
 
591
 
 
592
 
 
593
/******************************************************************
 
594
 *
 
595
 * m a k e _ c e r t _ r e q u e s t
 
596
 */
 
597
static CERTCertificateRequest*
 
598
make_cert_request(char *subject, SECKEYPublicKey *pubk)
 
599
{
 
600
    CERTName * subj;
 
601
    CERTSubjectPublicKeyInfo * spki;
 
602
 
 
603
    CERTCertificateRequest * req;
 
604
 
 
605
    /* Create info about public key */
 
606
    spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
 
607
    if (!spki) {
 
608
        SECU_PrintError(progName, "unable to create subject public key");
 
609
        exit (ERRX);
 
610
    }
 
611
 
 
612
    subj = CERT_AsciiToName (subject);
 
613
    if (subj == NULL) {
 
614
        FatalError("Invalid data in certificate description");
 
615
    }
 
616
 
 
617
    /* Generate certificate request */
 
618
    req = CERT_CreateCertificateRequest(subj, spki, 0);
 
619
    if (!req) {
 
620
        SECU_PrintError(progName, "unable to make certificate request");
 
621
        exit (ERRX);
 
622
    }
 
623
 
 
624
    if (verbosity >= 0) {
 
625
        PR_fprintf(outputFD, "certificate request generated\n");
 
626
    }
 
627
 
 
628
    return req;
 
629
}
 
630
 
 
631
 
 
632
/******************************************************************
 
633
 *
 
634
 * m a k e _ c e r t
 
635
 */
 
636
static CERTCertificate *
 
637
make_cert(CERTCertificateRequest *req, unsigned long serial,
 
638
CERTName *ca_subject)
 
639
{
 
640
    CERTCertificate * cert;
 
641
 
 
642
    CERTValidity * validity = NULL;
 
643
 
 
644
    PRTime now, after;
 
645
    PRExplodedTime printableTime;
 
646
 
 
647
    now = PR_Now();
 
648
    PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
 
649
 
 
650
    printableTime.tm_month += 3;
 
651
    after = PR_ImplodeTime (&printableTime);
 
652
 
 
653
    validity = CERT_CreateValidity (now, after);
 
654
 
 
655
    if (validity == NULL) {
 
656
        PR_fprintf(errorFD, "%s: error creating certificate validity\n",
 
657
             PROGRAM_NAME);
 
658
        errorCount++;
 
659
        exit (ERRX);
 
660
    }
 
661
 
 
662
    cert = CERT_CreateCertificate
 
663
        (serial, ca_subject, validity, req);
 
664
 
 
665
    if (cert == NULL) {
 
666
        /* should probably be more precise here */
 
667
        PR_fprintf(errorFD, "%s: error while generating certificate\n",
 
668
             PROGRAM_NAME);
 
669
        errorCount++;
 
670
        exit (ERRX);
 
671
    }
 
672
 
 
673
    return cert;
 
674
}
 
675
 
 
676
 
 
677
/*************************************************************************
 
678
 *
 
679
 * o u t p u t _ c a _ c e r t
 
680
 */
 
681
static void     
 
682
output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db)
 
683
{
 
684
    FILE * out;
 
685
 
 
686
    SECItem * encodedCertChain;
 
687
    SEC_PKCS7ContentInfo * certChain;
 
688
    char        *filename;
 
689
 
 
690
    /* the raw */
 
691
 
 
692
    filename = PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME) + 8);
 
693
    if (!filename) 
 
694
        out_of_memory();
 
695
 
 
696
    sprintf(filename, "%s.raw", DEFAULT_X509_BASENAME);
 
697
    if ((out = fopen (filename, "wb")) == NULL) {
 
698
        PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME,
 
699
             filename);
 
700
        errorCount++;
 
701
        exit(ERRX);
 
702
    }
 
703
 
 
704
    certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, db);
 
705
    encodedCertChain 
 
706
         = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, NULL);
 
707
    SEC_PKCS7DestroyContentInfo (certChain);
 
708
 
 
709
    if (encodedCertChain) {
 
710
        fprintf(out, "Content-type: application/x-x509-ca-cert\n\n");
 
711
        fwrite (encodedCertChain->data, 1, encodedCertChain->len,
 
712
             out);
 
713
        SECITEM_FreeItem(encodedCertChain, PR_TRUE);
 
714
    } else {
 
715
        PR_fprintf(errorFD, "%s: Can't DER encode this certificate\n",
 
716
             PROGRAM_NAME);
 
717
        errorCount++;
 
718
        exit(ERRX);
 
719
    }
 
720
 
 
721
    fclose (out);
 
722
 
 
723
    /* and the cooked */
 
724
 
 
725
    sprintf(filename, "%s.cacert", DEFAULT_X509_BASENAME);
 
726
    if ((out = fopen (filename, "wb")) == NULL) {
 
727
        PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME,
 
728
             filename);
 
729
        errorCount++;
 
730
        return;
 
731
    }
 
732
 
 
733
    fprintf (out, "%s\n%s\n%s\n", 
 
734
        NS_CERT_HEADER,
 
735
        BTOA_DataToAscii (cert->derCert.data, cert->derCert.len), 
 
736
        NS_CERT_TRAILER);
 
737
 
 
738
    fclose (out);
 
739
 
 
740
    if (verbosity >= 0) {
 
741
        PR_fprintf(outputFD, "Exported certificate to %s.raw and %s.cacert.\n",
 
742
                                DEFAULT_X509_BASENAME, DEFAULT_X509_BASENAME);
 
743
    }
 
744
}
 
745
 
 
746