Back to index

lightning-sunbird  0.9+nobinonly
certutil.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** certutil.c
00040 **
00041 ** utility for managing certificates and the cert database
00042 **
00043 */
00044 #include <stdio.h>
00045 #include <string.h>
00046 #include <stdlib.h>
00047 
00048 #if defined(WIN32)
00049 #include "fcntl.h"
00050 #include "io.h"
00051 #endif
00052 
00053 #include "secutil.h"
00054 
00055 #if defined(XP_UNIX)
00056 #include <unistd.h>
00057 #endif
00058 
00059 #include "nspr.h"
00060 #include "prtypes.h"
00061 #include "prtime.h"
00062 #include "prlong.h"
00063 
00064 #include "pk11func.h"
00065 #include "secasn1.h"
00066 #include "cert.h"
00067 #include "cryptohi.h"
00068 #include "secoid.h"
00069 #include "certdb.h"
00070 #include "nss.h"
00071 
00072 #define MIN_KEY_BITS        512
00073 /* MAX_KEY_BITS should agree with MAX_RSA_MODULUS in freebl */
00074 #define MAX_KEY_BITS        8192
00075 #define DEFAULT_KEY_BITS    1024
00076 
00077 #define GEN_BREAK(e) rv=e; break;
00078 
00079 
00080 extern SECKEYPrivateKey *CERTUTIL_GeneratePrivateKey(KeyType keytype,
00081                                                PK11SlotInfo *slot, 
00082                                                      int rsasize,
00083                                                int publicExponent,
00084                                                char *noise,
00085                                                SECKEYPublicKey **pubkeyp,
00086                                                char *pqgFile,
00087                                                      secuPWData *pwdata);
00088 
00089 static char *progName;
00090 
00091 static char *
00092 Gets_s(char *buff, size_t size) {
00093     char *str;
00094     
00095     if (buff == NULL || size < 1) {
00096         PORT_Assert(0);
00097         return NULL;
00098     }
00099     if ((str = fgets(buff, size, stdin)) != NULL) {
00100         int len = PORT_Strlen(str);
00101         /*
00102          * fgets() automatically converts native text file
00103          * line endings to '\n'.  As defensive programming
00104          * (just in case fgets has a bug or we put stdin in
00105          * binary mode by mistake), we handle three native 
00106          * text file line endings here:
00107          *   '\n'      Unix (including Linux and Mac OS X)
00108          *   '\r''\n'  DOS/Windows & OS/2
00109          *   '\r'      Mac OS Classic
00110          * len can not be less then 1, since in case with
00111          * empty string it has at least '\n' in the buffer
00112          */
00113         if (buff[len - 1] == '\n' || buff[len - 1] == '\r') {
00114             buff[len - 1] = '\0';
00115             if (len > 1 && buff[len - 2] == '\r')
00116                 buff[len - 2] = '\0';
00117         }
00118     } else {
00119         buff[0] = '\0';
00120     }
00121     return str;
00122 }
00123 
00124 static CERTGeneralName *
00125 GetGeneralName (PRArenaPool *arena)
00126 {
00127     CERTGeneralName *namesList = NULL;
00128     CERTGeneralName *current;
00129     CERTGeneralName *tail = NULL;
00130     SECStatus rv = SECSuccess;
00131     int intValue;
00132     char buffer[512];
00133     void *mark;
00134 
00135     PORT_Assert (arena);
00136     mark = PORT_ArenaMark (arena);
00137     do {
00138        puts ("\nSelect one of the following general name type: \n");
00139        puts ("\t1 - instance of other name\n\t2 - rfc822Name\n\t3 - dnsName\n");
00140        puts ("\t4 - x400Address\n\t5 - directoryName\n\t6 - ediPartyName\n");
00141        puts ("\t7 - uniformResourceidentifier\n\t8 - ipAddress\n\t9 - registerID\n");
00142        puts ("\tAny other number to finish\n\t\tChoice:");
00143        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
00144            PORT_SetError(SEC_ERROR_INPUT_LEN);
00145            GEN_BREAK (SECFailure);
00146        }
00147        intValue = PORT_Atoi (buffer);
00148         /*
00149          * Should use ZAlloc instead of Alloc to avoid problem with garbage
00150          * initialized pointers in CERT_CopyName
00151          */
00152        if (intValue >= certOtherName && intValue <= certRegisterID) {
00153            if (namesList == NULL) {
00154               namesList = current = tail = PORT_ArenaZNew(arena, CERTGeneralName);
00155            } else {
00156               current = PORT_ArenaZNew(arena, CERTGeneralName);
00157            }
00158            if (current == NULL) {
00159               GEN_BREAK (SECFailure);
00160            }  
00161        } else {
00162            break;
00163        }
00164        current->type = intValue;
00165        puts ("\nEnter data:");
00166        fflush (stdout);
00167        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
00168            PORT_SetError(SEC_ERROR_INPUT_LEN);
00169            GEN_BREAK (SECFailure);
00170        }
00171        switch (current->type) {
00172            case certURI:
00173            case certDNSName:
00174            case certRFC822Name:
00175               current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer));
00176               if (current->name.other.data == NULL) {
00177                   GEN_BREAK (SECFailure);
00178               }
00179               PORT_Memcpy
00180                 (current->name.other.data, buffer, current->name.other.len = strlen(buffer));
00181               break;
00182 
00183            case certEDIPartyName:
00184            case certIPAddress:
00185            case certOtherName:
00186            case certRegisterID:
00187            case certX400Address: {
00188 
00189               current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2);
00190               if (current->name.other.data == NULL) {
00191                   GEN_BREAK (SECFailure);
00192               }
00193 
00194               PORT_Memcpy (current->name.other.data + 2, buffer, strlen (buffer));
00195               /* This may not be accurate for all cases.  For now, use this tag type */
00196               current->name.other.data[0] = (char)(((current->type - 1) & 0x1f)| 0x80);
00197               current->name.other.data[1] = (char)strlen (buffer);
00198               current->name.other.len = strlen (buffer) + 2;
00199               break;
00200            }
00201 
00202            case certDirectoryName: {
00203               CERTName *directoryName = NULL;
00204 
00205               directoryName = CERT_AsciiToName (buffer);
00206               if (!directoryName) {
00207                   fprintf(stderr, "certutil: improperly formatted name: \"%s\"\n", buffer);
00208                   break;
00209               }
00210                          
00211               rv = CERT_CopyName (arena, &current->name.directoryName, directoryName);
00212               CERT_DestroyName (directoryName);
00213               
00214               break;
00215            }
00216        }
00217        if (rv != SECSuccess)
00218            break;
00219        current->l.next = &(namesList->l);
00220        current->l.prev = &(tail->l);
00221        tail->l.next = &(current->l);
00222        tail = current;
00223 
00224     }while (1);
00225 
00226     if (rv != SECSuccess) {
00227        PORT_ArenaRelease (arena, mark);
00228        namesList = NULL;
00229     }
00230     return (namesList);
00231 }
00232 
00233 static SECStatus 
00234 GetString(PRArenaPool *arena, char *prompt, SECItem *value)
00235 {
00236     char buffer[251];
00237     char *buffPrt;
00238 
00239     buffer[0] = '\0';
00240     value->data = NULL;
00241     value->len = 0;
00242     
00243     puts (prompt);
00244     buffPrt = Gets_s (buffer, sizeof(buffer));
00245     /* returned NULL here treated the same way as empty string */
00246     if (buffPrt && strlen (buffer) > 0) {
00247        value->data = PORT_ArenaAlloc (arena, strlen (buffer));
00248        if (value->data == NULL) {
00249            PORT_SetError (SEC_ERROR_NO_MEMORY);
00250            return (SECFailure);
00251        }
00252        PORT_Memcpy (value->data, buffer, value->len = strlen(buffer));
00253     }
00254     return (SECSuccess);
00255 }
00256 
00257 static CERTCertificateRequest *
00258 GetCertRequest(PRFileDesc *inFile, PRBool ascii)
00259 {
00260     CERTCertificateRequest *certReq = NULL;
00261     CERTSignedData signedData;
00262     PRArenaPool *arena = NULL;
00263     SECItem reqDER;
00264     SECStatus rv;
00265 
00266     reqDER.data = NULL;
00267     do {
00268        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00269        if (arena == NULL) {
00270            GEN_BREAK (SECFailure);
00271        }
00272        
00273        rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii);
00274        if (rv) 
00275            break;
00276         certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc
00277                 (arena, sizeof(CERTCertificateRequest));
00278         if (!certReq) 
00279            break;
00280        certReq->arena = arena;
00281 
00282        /* Since cert request is a signed data, must decode to get the inner
00283           data
00284         */
00285        PORT_Memset(&signedData, 0, sizeof(signedData));
00286        rv = SEC_ASN1DecodeItem(arena, &signedData, 
00287               SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER);
00288        if (rv)
00289            break;
00290        
00291         rv = SEC_ASN1DecodeItem(arena, certReq, 
00292               SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data);
00293    } while (0);
00294 
00295    if (!rv) {
00296        rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData, 
00297               &certReq->subjectPublicKeyInfo, NULL /* wincx */);
00298    }
00299 
00300    if (rv) {
00301        PRErrorCode  perr = PR_GetError();
00302        fprintf(stderr, "%s: unable to decode DER cert request (%s)\n", progName,
00303                SECU_Strerror(perr));
00304    }
00305    return (certReq);
00306 }
00307 
00308 static PRBool 
00309 GetYesNo(char *prompt) 
00310 {
00311     char buf[3];
00312     char *buffPrt;
00313 
00314     buf[0] = 'n';
00315     puts(prompt);
00316     buffPrt = Gets_s(buf, sizeof(buf));
00317     return (buffPrt && (buf[0] == 'y' || buf[0] == 'Y')) ? PR_TRUE : PR_FALSE;
00318 }
00319 
00320 static SECStatus
00321 AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts, 
00322         PRFileDesc *inFile, PRBool ascii, PRBool emailcert, void *pwdata)
00323 {
00324     CERTCertTrust *trust = NULL;
00325     CERTCertificate *cert = NULL;
00326     SECItem certDER;
00327     SECStatus rv;
00328 
00329     certDER.data = NULL;
00330     do {
00331        /* Read in the entire file specified with the -i argument */
00332        rv = SECU_ReadDERFromFile(&certDER, inFile, ascii);
00333        if (rv != SECSuccess) {
00334            SECU_PrintError(progName, "unable to read input file");
00335            break;
00336        }
00337 
00338        /* Read in an ASCII cert and return a CERTCertificate */
00339        cert = CERT_DecodeCertFromPackage((char *)certDER.data, certDER.len);
00340        if (!cert) {
00341            SECU_PrintError(progName, "could not obtain certificate from file"); 
00342            GEN_BREAK(SECFailure);
00343        }
00344 
00345        /* Create a cert trust to pass to SEC_AddPermCertificate */
00346        trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
00347        if (!trust) {
00348            SECU_PrintError(progName, "unable to allocate cert trust");
00349            GEN_BREAK(SECFailure);
00350        }
00351 
00352        rv = CERT_DecodeTrustString(trust, trusts);
00353        if (rv) {
00354            SECU_PrintError(progName, "unable to decode trust string");
00355            GEN_BREAK(SECFailure);
00356        }
00357 
00358        if (!PK11_IsFriendly(slot)) {
00359            rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
00360            if (rv != SECSuccess) {
00361               SECU_PrintError(progName, "could not authenticate to token or database");
00362               GEN_BREAK(SECFailure);
00363            }
00364        }
00365 
00366        rv =  PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE);
00367        if (rv != SECSuccess) {
00368            SECU_PrintError(progName, "could not add certificate to token or database");
00369            GEN_BREAK(SECFailure);
00370        }
00371 
00372        rv = CERT_ChangeCertTrust(handle, cert, trust);
00373        if (rv != SECSuccess) {
00374            SECU_PrintError(progName, "could not change trust on certificate");
00375            GEN_BREAK(SECFailure);
00376        }
00377 
00378        if ( emailcert ) {
00379            CERT_SaveSMimeProfile(cert, NULL, pwdata);
00380        }
00381 
00382     } while (0);
00383 
00384     CERT_DestroyCertificate (cert);
00385     PORT_Free(trust);
00386     PORT_Free(certDER.data);
00387 
00388     return rv;
00389 }
00390 
00391 static SECStatus
00392 AddExtensions(void *, const char *, const char *, PRBool, PRBool, PRBool, PRBool,
00393               PRBool, PRBool);
00394 
00395 static SECStatus
00396 CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType,
00397         SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, 
00398        const char *emailAddrs, const char *dnsNames,
00399         PRBool       keyUsage, 
00400        PRBool  extKeyUsage,
00401        PRBool  basicConstraint, 
00402        PRBool  authKeyID,
00403        PRBool  crlDistPoints, 
00404        PRBool  nscpCertType,
00405         PRFileDesc *outFile)
00406 {
00407     CERTSubjectPublicKeyInfo *spki;
00408     CERTCertificateRequest *cr;
00409     SECItem *encoding;
00410     SECOidTag signAlgTag;
00411     SECItem result;
00412     SECStatus rv;
00413     PRArenaPool *arena;
00414     PRInt32 numBytes;
00415     void *extHandle;
00416 
00417     /* Create info about public key */
00418     spki = SECKEY_CreateSubjectPublicKeyInfo(pubk);
00419     if (!spki) {
00420        SECU_PrintError(progName, "unable to create subject public key");
00421        return SECFailure;
00422     }
00423     
00424     /* Generate certificate request */
00425     cr = CERT_CreateCertificateRequest(subject, spki, NULL);
00426     if (!cr) {
00427        SECU_PrintError(progName, "unable to make certificate request");
00428        return SECFailure;
00429     }
00430 
00431     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00432     if ( !arena ) {
00433        SECU_PrintError(progName, "out of memory");
00434        return SECFailure;
00435     }
00436     
00437     extHandle = CERT_StartCertificateRequestAttributes(cr);
00438     if (extHandle == NULL) {
00439         PORT_FreeArena (arena, PR_FALSE);
00440        return SECFailure;
00441     }
00442     if (AddExtensions(extHandle, emailAddrs, dnsNames, keyUsage, extKeyUsage,
00443                       basicConstraint, authKeyID, crlDistPoints, nscpCertType)
00444                   != SECSuccess) {
00445         PORT_FreeArena (arena, PR_FALSE);
00446         return SECFailure;
00447     }
00448     CERT_FinishExtensions(extHandle);
00449     CERT_FinishCertificateRequestAttributes(cr);
00450 
00451     /* Der encode the request */
00452     encoding = SEC_ASN1EncodeItem(arena, NULL, cr,
00453                 SEC_ASN1_GET(CERT_CertificateRequestTemplate));
00454     if (encoding == NULL) {
00455        SECU_PrintError(progName, "der encoding of request failed");
00456        return SECFailure;
00457     }
00458 
00459     /* Sign the request */
00460     signAlgTag = SEC_GetSignatureAlgorithmOidTag(keyType, hashAlgTag);
00461     if (signAlgTag == SEC_OID_UNKNOWN) {
00462        SECU_PrintError(progName, "unknown Key or Hash type");
00463        return SECFailure;
00464     }
00465     rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, 
00466                       privk, signAlgTag);
00467     if (rv) {
00468        SECU_PrintError(progName, "signing of data failed");
00469        return SECFailure;
00470     }
00471 
00472     /* Encode request in specified format */
00473     if (ascii) {
00474        char *obuf;
00475        char *name, *email, *org, *state, *country;
00476        SECItem *it;
00477        int total;
00478 
00479        it = &result;
00480 
00481        obuf = BTOA_ConvertItemToAscii(it);
00482        total = PL_strlen(obuf);
00483 
00484        name = CERT_GetCommonName(subject);
00485        if (!name) {
00486            fprintf(stderr, "You must specify a common name\n");
00487            return SECFailure;
00488        }
00489 
00490        if (!phone)
00491            phone = strdup("(not specified)");
00492 
00493        email = CERT_GetCertEmailAddress(subject);
00494        if (!email)
00495            email = strdup("(not specified)");
00496 
00497        org = CERT_GetOrgName(subject);
00498        if (!org)
00499            org = strdup("(not specified)");
00500 
00501        state = CERT_GetStateName(subject);
00502        if (!state)
00503            state = strdup("(not specified)");
00504 
00505        country = CERT_GetCountryName(subject);
00506        if (!country)
00507            country = strdup("(not specified)");
00508 
00509        PR_fprintf(outFile, 
00510                   "\nCertificate request generated by Netscape certutil\n");
00511        PR_fprintf(outFile, "Phone: %s\n\n", phone);
00512        PR_fprintf(outFile, "Common Name: %s\n", name);
00513        PR_fprintf(outFile, "Email: %s\n", email);
00514        PR_fprintf(outFile, "Organization: %s\n", org);
00515        PR_fprintf(outFile, "State: %s\n", state);
00516        PR_fprintf(outFile, "Country: %s\n\n", country);
00517 
00518        PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER);
00519        numBytes = PR_Write(outFile, obuf, total);
00520        if (numBytes != total) {
00521            SECU_PrintSystemError(progName, "write error");
00522            return SECFailure;
00523        }
00524        PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER);
00525     } else {
00526        numBytes = PR_Write(outFile, result.data, result.len);
00527        if (numBytes != (int)result.len) {
00528            SECU_PrintSystemError(progName, "write error");
00529            return SECFailure;
00530        }
00531     }
00532     return SECSuccess;
00533 }
00534 
00535 static SECStatus 
00536 ChangeTrustAttributes(CERTCertDBHandle *handle, char *name, char *trusts)
00537 {
00538     SECStatus rv;
00539     CERTCertificate *cert;
00540     CERTCertTrust *trust;
00541     
00542     cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
00543     if (!cert) {
00544        SECU_PrintError(progName, "could not find certificate named \"%s\"",
00545                      name);
00546        return SECFailure;
00547     }
00548 
00549     trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust));
00550     if (!trust) {
00551        SECU_PrintError(progName, "unable to allocate cert trust");
00552        return SECFailure;
00553     }
00554 
00555     /* This function only decodes these characters: pPwcTCu, */
00556     rv = CERT_DecodeTrustString(trust, trusts);
00557     if (rv) {
00558        SECU_PrintError(progName, "unable to decode trust string");
00559        return SECFailure;
00560     }
00561 
00562     rv = CERT_ChangeCertTrust(handle, cert, trust);
00563     if (rv) {
00564        SECU_PrintError(progName, "unable to modify trust attributes");
00565        return SECFailure;
00566     }
00567     CERT_DestroyCertificate(cert);
00568 
00569     return SECSuccess;
00570 }
00571 
00572 static SECStatus
00573 printCertCB(CERTCertificate *cert, void *arg)
00574 {
00575     SECStatus rv;
00576     SECItem data;
00577     CERTCertTrust *trust = (CERTCertTrust *)arg;
00578     
00579     data.data = cert->derCert.data;
00580     data.len = cert->derCert.len;
00581 
00582     rv = SECU_PrintSignedData(stdout, &data, "Certificate", 0,
00583                            SECU_PrintCertificate);
00584     if (rv) {
00585        SECU_PrintError(progName, "problem printing certificate");
00586        return(SECFailure);
00587     }
00588     if (trust) {
00589        SECU_PrintTrustFlags(stdout, trust,
00590                             "Certificate Trust Flags", 1);
00591     } else if (cert->trust) {
00592        SECU_PrintTrustFlags(stdout, cert->trust,
00593                             "Certificate Trust Flags", 1);
00594     }
00595 
00596     printf("\n");
00597 
00598     return(SECSuccess);
00599 }
00600 
00601 static SECStatus
00602 DumpChain(CERTCertDBHandle *handle, char *name)
00603 {
00604     CERTCertificate *the_cert;
00605     CERTCertificateList *chain;
00606     int i, j;
00607     the_cert = PK11_FindCertFromNickname(name, NULL);
00608     if (!the_cert) {
00609        SECU_PrintError(progName, "Could not find: %s\n", name);
00610        return SECFailure;
00611     }
00612     chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE);
00613     CERT_DestroyCertificate(the_cert);
00614     if (!chain) {
00615        SECU_PrintError(progName, "Could not obtain chain for: %s\n", name);
00616        return SECFailure;
00617     }
00618     for (i=chain->len-1; i>=0; i--) {
00619        CERTCertificate *c;
00620        c = CERT_FindCertByDERCert(handle, &chain->certs[i]);
00621        for (j=i; j<chain->len-1; j++) printf("  ");
00622        printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName);
00623        CERT_DestroyCertificate(c);
00624     }
00625     CERT_DestroyCertificateList(chain);
00626     return SECSuccess;
00627 }
00628 
00629 static SECStatus
00630 listCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot,
00631           PRBool raw, PRBool ascii, PRFileDesc *outfile, void *pwarg)
00632 {
00633     SECItem data;
00634     PRInt32 numBytes;
00635     SECStatus rv = SECFailure;
00636     CERTCertList *certs;
00637     CERTCertListNode *node;
00638 
00639     /* List certs on a non-internal slot. */
00640     if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot))
00641            PK11_Authenticate(slot, PR_TRUE, pwarg);
00642     if (name) {
00643        CERTCertificate *the_cert;
00644        the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
00645        if (!the_cert) {
00646            the_cert = PK11_FindCertFromNickname(name, NULL);
00647            if (!the_cert) {
00648               SECU_PrintError(progName, "Could not find: %s\n", name);
00649               return SECFailure;
00650            }
00651        }
00652        certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject,
00653               PR_Now(), PR_FALSE);
00654        CERT_DestroyCertificate(the_cert);
00655 
00656        for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
00657                                           node = CERT_LIST_NEXT(node)) {
00658            the_cert = node->cert;
00659            /* now get the subjectList that matches this cert */
00660            data.data = the_cert->derCert.data;
00661            data.len = the_cert->derCert.len;
00662            if (ascii) {
00663               PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER, 
00664                       BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER);
00665               rv = SECSuccess;
00666            } else if (raw) {
00667               numBytes = PR_Write(outfile, data.data, data.len);
00668               if (numBytes != (PRInt32) data.len) {
00669                  SECU_PrintSystemError(progName, "error writing raw cert");
00670                   rv = SECFailure;
00671               }
00672               rv = SECSuccess;
00673            } else {
00674               rv = printCertCB(the_cert, the_cert->trust);
00675            }
00676            if (rv != SECSuccess) {
00677               break;
00678            }
00679        }
00680     } else {
00681 
00682        certs = PK11_ListCertsInSlot(slot);
00683        if (certs) {
00684            for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs);
00685                                           node = CERT_LIST_NEXT(node)) {
00686               SECU_PrintCertNickname(node,stdout);
00687            }
00688            rv = SECSuccess;
00689        }
00690     }
00691     if (certs) {
00692         CERT_DestroyCertList(certs);
00693     }
00694     if (rv) {
00695        SECU_PrintError(progName, "problem printing certificate nicknames");
00696        return SECFailure;
00697     }
00698 
00699     return SECSuccess;      /* not rv ?? */
00700 }
00701 
00702 static SECStatus
00703 ListCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot,
00704           PRBool raw, PRBool ascii, PRFileDesc *outfile, secuPWData *pwdata)
00705 {
00706     SECStatus rv;
00707 
00708     if (slot == NULL) {
00709        CERTCertList *list;
00710        CERTCertListNode *node;
00711 
00712        list = PK11_ListCerts(PK11CertListAll, pwdata);
00713        for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
00714             node = CERT_LIST_NEXT(node)) 
00715        {
00716            SECU_PrintCertNickname(node, stdout);
00717        }
00718        CERT_DestroyCertList(list);
00719        return SECSuccess;
00720     } else {
00721        rv = listCerts(handle,name,slot,raw,ascii,outfile,pwdata);
00722     }
00723     return rv;
00724 }
00725 
00726 static SECStatus 
00727 DeleteCert(CERTCertDBHandle *handle, char *name)
00728 {
00729     SECStatus rv;
00730     CERTCertificate *cert;
00731 
00732     cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
00733     if (!cert) {
00734        SECU_PrintError(progName, "could not find certificate named \"%s\"",
00735                      name);
00736        return SECFailure;
00737     }
00738 
00739     rv = SEC_DeletePermCertificate(cert);
00740     CERT_DestroyCertificate(cert);
00741     if (rv) {
00742        SECU_PrintError(progName, "unable to delete certificate");
00743        return SECFailure;
00744     }
00745 
00746     return SECSuccess;
00747 }
00748 
00749 static SECStatus
00750 ValidateCert(CERTCertDBHandle *handle, char *name, char *date,
00751             char *certUsage, PRBool checkSig, PRBool logit, secuPWData *pwdata)
00752 {
00753     SECStatus rv;
00754     CERTCertificate *cert = NULL;
00755     int64 timeBoundary;
00756     SECCertificateUsage usage;
00757     CERTVerifyLog reallog;
00758     CERTVerifyLog *log = NULL;
00759 
00760     if (!certUsage) {
00761            PORT_SetError (SEC_ERROR_INVALID_ARGS);
00762            return (SECFailure);
00763     }
00764     
00765     switch (*certUsage) {
00766        case 'O':
00767            usage = certificateUsageStatusResponder;
00768            break;
00769        case 'C':
00770            usage = certificateUsageSSLClient;
00771            break;
00772        case 'V':
00773            usage = certificateUsageSSLServer;
00774            break;
00775        case 'S':
00776            usage = certificateUsageEmailSigner;
00777            break;
00778        case 'R':
00779            usage = certificateUsageEmailRecipient;
00780            break;
00781        default:
00782            PORT_SetError (SEC_ERROR_INVALID_ARGS);
00783            return (SECFailure);
00784     }
00785     do {
00786        cert = CERT_FindCertByNicknameOrEmailAddr(handle, name);
00787        if (!cert) {
00788            SECU_PrintError(progName, "could not find certificate named \"%s\"",
00789                          name);
00790            GEN_BREAK (SECFailure)
00791        }
00792 
00793        if (date != NULL) {
00794            rv = DER_AsciiToTime(&timeBoundary, date);
00795            if (rv) {
00796               SECU_PrintError(progName, "invalid input date");
00797               GEN_BREAK (SECFailure)
00798            }
00799        } else {
00800            timeBoundary = PR_Now();
00801        }
00802 
00803        if ( logit ) {
00804            log = &reallog;
00805            
00806            log->count = 0;
00807            log->head = NULL;
00808            log->tail = NULL;
00809            log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00810            if ( log->arena == NULL ) {
00811               SECU_PrintError(progName, "out of memory");
00812               GEN_BREAK (SECFailure)
00813            }
00814        }
00815  
00816        rv = CERT_VerifyCertificate(handle, cert, checkSig, usage,
00817                           timeBoundary, pwdata, log, &usage);
00818        if ( log ) {
00819            if ( log->head == NULL ) {
00820               fprintf(stdout, "%s: certificate is valid\n", progName);
00821               GEN_BREAK (SECSuccess)
00822            } else {
00823               char *name;
00824               CERTVerifyLogNode *node;
00825               
00826               node = log->head;
00827               while ( node ) {
00828                   if ( node->cert->nickname != NULL ) {
00829                      name = node->cert->nickname;
00830                   } else {
00831                      name = node->cert->subjectName;
00832                   }
00833                   fprintf(stderr, "%s : %s\n", name, 
00834                      SECU_Strerror(node->error));
00835                   CERT_DestroyCertificate(node->cert);
00836                   node = node->next;
00837               }
00838            }
00839        } else {
00840            if (rv != SECSuccess) {
00841               PRErrorCode perr = PORT_GetError();
00842               fprintf(stdout, "%s: certificate is invalid: %s\n",
00843                      progName, SECU_Strerror(perr));
00844               GEN_BREAK (SECFailure)
00845            }
00846            fprintf(stdout, "%s: certificate is valid\n", progName);
00847            GEN_BREAK (SECSuccess)
00848        }
00849     } while (0);
00850 
00851     if (cert) {
00852         CERT_DestroyCertificate(cert);
00853     }
00854 
00855     return (rv);
00856 }
00857 
00858 
00859 static SECStatus
00860 printKeyCB(SECKEYPublicKey *key, SECItem *data, void *arg)
00861 {
00862     if (key->keyType == rsaKey) {
00863        fprintf(stdout, "RSA Public-Key:\n");
00864        SECU_PrintInteger(stdout, &key->u.rsa.modulus, "modulus", 1);
00865     } else {
00866        fprintf(stdout, "DSA Public-Key:\n");
00867        SECU_PrintInteger(stdout, &key->u.dsa.publicValue, "publicValue", 1);
00868     }
00869     return SECSuccess;
00870 }
00871 
00872 /* callback for listing certs through pkcs11 */
00873 static SECStatus
00874 secu_PrintKey(FILE *out, int count, SECKEYPrivateKey *key)
00875 {
00876     char *name;
00877 
00878     name = PK11_GetPrivateKeyNickname(key);
00879     if (name == NULL) {
00880        /* should look up associated cert */
00881        name = PORT_Strdup("< orphaned >");
00882     }
00883     fprintf(out, "<%d> %s\n", count, name);
00884     PORT_Free(name);
00885 
00886     return SECSuccess;
00887 }
00888 
00889 static SECStatus
00890 listKeys(PK11SlotInfo *slot, KeyType keyType, void *pwarg)
00891 {
00892     SECKEYPrivateKeyList *list;
00893     SECKEYPrivateKeyListNode *node;
00894     int count;
00895 
00896     if (PK11_NeedLogin(slot))
00897            PK11_Authenticate(slot, PR_TRUE, pwarg);
00898 
00899     list = PK11_ListPrivateKeysInSlot(slot);
00900     if (list == NULL) {
00901        SECU_PrintError(progName, "problem listing keys");
00902        return SECFailure;
00903     }
00904     for (count=0, node=PRIVKEY_LIST_HEAD(list) ; !PRIVKEY_LIST_END(node,list);
00905                        node= PRIVKEY_LIST_NEXT(node),count++) {
00906        secu_PrintKey(stdout, count, node->key);
00907     }
00908     SECKEY_DestroyPrivateKeyList(list);
00909 
00910     if (count == 0) {
00911        fprintf(stderr, "%s: no keys found\n", progName);
00912        return SECFailure;
00913     }
00914     return SECSuccess;
00915 }
00916 
00917 static SECStatus
00918 ListKeys(PK11SlotInfo *slot, char *keyname, int index, 
00919          KeyType keyType, PRBool dopriv, secuPWData *pwdata)
00920 {
00921     SECStatus rv = SECSuccess;
00922 
00923     if (slot == NULL) {
00924        PK11SlotList *list;
00925        PK11SlotListElement *le;
00926 
00927        list= PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,pwdata);
00928        if (list) for (le = list->head; le; le = le->next) {
00929            rv = listKeys(le->slot,keyType,pwdata);
00930        }
00931     } else {
00932        rv = listKeys(slot,keyType,pwdata);
00933     }
00934     return rv;
00935 }
00936 
00937 static SECStatus
00938 DeleteKey(char *nickname, secuPWData *pwdata)
00939 {
00940     SECStatus rv;
00941     CERTCertificate *cert;
00942     PK11SlotInfo *slot;
00943 
00944     slot = PK11_GetInternalKeySlot();
00945     if (PK11_NeedLogin(slot))
00946        PK11_Authenticate(slot, PR_TRUE, pwdata);
00947     cert = PK11_FindCertFromNickname(nickname, pwdata);
00948     if (!cert) {
00949        PK11_FreeSlot(slot);
00950        return SECFailure;
00951     }
00952     rv = PK11_DeleteTokenCertAndKey(cert, pwdata);
00953     if (rv != SECSuccess) {
00954        SECU_PrintError("problem deleting private key \"%s\"\n", nickname);
00955     }
00956     CERT_DestroyCertificate(cert);
00957     PK11_FreeSlot(slot);
00958     return rv;
00959 }
00960 
00961 
00962 /*
00963  *  L i s t M o d u l e s
00964  *
00965  *  Print a list of the PKCS11 modules that are
00966  *  available. This is useful for smartcard people to
00967  *  make sure they have the drivers loaded.
00968  *
00969  */
00970 static SECStatus
00971 ListModules(void)
00972 {
00973     PK11SlotList *list;
00974     PK11SlotListElement *le;
00975 
00976     /* get them all! */
00977     list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL);
00978     if (list == NULL) return SECFailure;
00979 
00980     /* look at each slot*/
00981     for (le = list->head ; le; le = le->next) {
00982       printf ("\n");
00983       printf ("    slot: %s\n", PK11_GetSlotName(le->slot));
00984       printf ("   token: %s\n", PK11_GetTokenName(le->slot));
00985     }
00986     PK11_FreeSlotList(list);
00987 
00988     return SECSuccess;
00989 }
00990 
00991 static void 
00992 Usage(char *progName)
00993 {
00994 #define FPS fprintf(stderr, 
00995     FPS "Type %s -H for more detailed descriptions\n", progName);
00996     FPS "Usage:  %s -N [-d certdir] [-P dbprefix] [-f pwfile]\n", progName);
00997     FPS "Usage:  %s -T [-d certdir] [-P dbprefix] [-h token-name] [-f pwfile]\n", progName);
00998     FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", 
00999        progName);
01000     FPS "\t%s -B -i batch-file\n", progName);
01001     FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n"
01002        "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
01003         "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-1] [-2] [-3] [-4] [-5]\n"
01004        "\t\t [-6] [-7 emailAddrs] [-8 dns-names]\n",
01005        progName);
01006     FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName);
01007     FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", 
01008        progName);
01009     FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n" 
01010        "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
01011     FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n"
01012        "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
01013 #ifdef NSS_ENABLE_ECC
01014     FPS "\t%s -G [-h token-name] -k ec -q curve [-f pwfile]\n"
01015        "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName);
01016     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|ec|rsa|all]\n", 
01017        progName);
01018 #else
01019     FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|rsa|all]\n", 
01020        progName);
01021 #endif /* NSS_ENABLE_ECC */
01022     FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n");
01023     FPS "\t%s -L [-n cert-name] [-X] [-d certdir] [-P dbprefix] [-r] [-a]\n", progName);
01024     FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n",
01025        progName);
01026     FPS "\t%s -O -n cert-name [-X] [-d certdir] [-P dbprefix]\n", progName);
01027     FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n"
01028        "\t\t [-y emailAddrs] [-k key-type] [-h token-name] [-f pwfile] [-g key-size]\n",
01029        progName);
01030     FPS "\t%s -V -n cert-name -u usage [-b time] [-e] \n"
01031        "\t\t[-X] [-d certdir] [-P dbprefix]\n",
01032        progName);
01033     FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x]  -t trustargs\n"
01034        "\t\t [-k key-type] [-q key-params] [-h token-name] [-g key-size]\n"
01035         "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n"
01036        "\t\t [-f pwfile] [-d certdir] [-P dbprefix]\n"
01037         "\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n"
01038         "\t\t [-8 dns-names]\n",
01039        progName);
01040     FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName);
01041     exit(1);
01042 }
01043 
01044 static void LongUsage(char *progName)
01045 {
01046 
01047     FPS "%-15s Add a certificate to the database        (create if needed)\n",
01048        "-A");
01049     FPS "%-20s\n", "   All options under -E apply");
01050     FPS "%-15s Run a series of certutil commands from a batch file\n", "-B");
01051     FPS "%-20s Specify the batch file\n", "   -i batch-file");
01052     FPS "%-15s Add an Email certificate to the database (create if needed)\n",
01053        "-E");
01054     FPS "%-20s Specify the nickname of the certificate to add\n",
01055        "   -n cert-name");
01056     FPS "%-20s Set the certificate trust attributes:\n",
01057        "   -t trustargs");
01058     FPS "%-25s p \t valid peer\n", "");
01059     FPS "%-25s P \t trusted peer (implies p)\n", "");
01060     FPS "%-25s c \t valid CA\n", "");
01061     FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
01062     FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
01063     FPS "%-25s u \t user cert\n", "");
01064     FPS "%-25s w \t send warning\n", "");
01065     FPS "%-25s g \t make step-up cert\n", "");
01066     FPS "%-20s Specify the password file\n",
01067        "   -f pwfile");
01068     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01069        "   -d certdir");
01070     FPS "%-20s Cert & Key database prefix\n",
01071        "   -P dbprefix");
01072     FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
01073        "   -a");
01074     FPS "%-20s Specify the certificate file (default is stdin)\n",
01075        "   -i input");
01076     FPS "\n");
01077 
01078     FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
01079        "-C");
01080     FPS "%-20s The nickname of the issuer cert\n",
01081        "   -c issuer-name");
01082     FPS "%-20s The BINARY certificate request file\n",
01083        "   -i cert-request ");
01084     FPS "%-20s Output binary cert to this file (default is stdout)\n",
01085        "   -o output-cert");
01086     FPS "%-20s Self sign\n",
01087        "   -x");
01088     FPS "%-20s Cert serial number\n",
01089        "   -m serial-number");
01090     FPS "%-20s Time Warp\n",
01091        "   -w warp-months");
01092     FPS "%-20s Months valid (default is 3)\n",
01093         "   -v months-valid");
01094     FPS "%-20s Specify the password file\n",
01095        "   -f pwfile");
01096     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01097        "   -d certdir");
01098     FPS "%-20s Cert & Key database prefix\n",
01099        "   -P dbprefix");
01100     FPS "%-20s Create key usage extension\n",
01101        "   -1 ");
01102     FPS "%-20s Create basic constraint extension\n",
01103        "   -2 ");
01104     FPS "%-20s Create authority key ID extension\n",
01105        "   -3 ");
01106     FPS "%-20s Create crl distribution point extension\n",
01107        "   -4 ");
01108     FPS "%-20s Create netscape cert type extension\n",
01109        "   -5 ");
01110     FPS "%-20s Create extended key usage extension\n",
01111        "   -6 ");
01112     FPS "%-20s Create an email subject alt name extension\n",
01113        "   -7 ");
01114     FPS "%-20s Create an dns subject alt name extension\n",
01115        "   -8 ");
01116     FPS "\n");
01117 
01118     FPS "%-15s Generate a new key pair\n",
01119        "-G");
01120     FPS "%-20s Name of token in which to generate key (default is internal)\n",
01121        "   -h token-name");
01122 #ifdef NSS_ENABLE_ECC
01123     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
01124        "   -k key-type");
01125     FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
01126        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01127 #else
01128     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
01129        "   -k key-type");
01130     FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n",
01131        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01132 #endif /* NSS_ENABLE_ECC */
01133     FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
01134        "   -y exp");
01135     FPS "%-20s Specify the password file\n",
01136         "   -f password-file");
01137     FPS "%-20s Specify the noise file to be used\n",
01138        "   -z noisefile");
01139     FPS "%-20s read PQG value from pqgfile (dsa only)\n",
01140        "   -q pqgfile");
01141 #ifdef NSS_ENABLE_ECC
01142     FPS "%-20s Elliptic curve name (ec only)\n",
01143        "   -q curve-name");
01144     FPS "%-20s One of nistp256, nistp384, nistp521\n", "");
01145 #ifdef NSS_ECC_MORE_THAN_SUITE_B
01146     FPS "%-20s sect163k1, nistk163, sect163r1, sect163r2,\n", "");
01147     FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
01148     FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
01149     FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
01150     FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
01151     FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
01152     FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
01153     FPS "%-20s secp256r1, secp384r1, secp521r1,\n", "");
01154     FPS "%-20s prime192v1, prime192v2, prime192v3, \n", "");
01155     FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
01156     FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
01157     FPS "%-20s c2tnb191v2, c2tnb191v3,  \n", "");
01158     FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
01159     FPS "%-20s c2pnb272w1, c2pnb304w1, \n", "");
01160     FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
01161     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
01162     FPS "%-20s sect131r1, sect131r2\n", "");
01163 #endif /* NSS_ECC_MORE_THAN_SUITE_B */
01164 #endif
01165     FPS "%-20s Key database directory (default is ~/.netscape)\n",
01166        "   -d keydir");
01167     FPS "%-20s Cert & Key database prefix\n",
01168        "   -P dbprefix");
01169     FPS "\n");
01170 
01171     FPS "%-15s Delete a certificate from the database\n",
01172        "-D");
01173     FPS "%-20s The nickname of the cert to delete\n",
01174        "   -n cert-name");
01175     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01176        "   -d certdir");
01177     FPS "%-20s Cert & Key database prefix\n",
01178        "   -P dbprefix");
01179     FPS "\n");
01180 
01181     FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
01182         "-U");
01183     FPS "%-20s Module database directory (default is '~/.netscape')\n",
01184         "   -d moddir");
01185     FPS "%-20s Cert & Key database prefix\n",
01186        "   -P dbprefix");
01187     FPS "%-20s force the database to open R/W\n",
01188        "   -X");
01189     FPS "\n");
01190 
01191     FPS "%-15s List all keys\n", /*, or print out a single named key\n",*/
01192         "-K");
01193     FPS "%-20s Name of token in which to look for keys (default is internal,"
01194        " use \"all\" to list keys on all tokens)\n",
01195        "   -h token-name ");
01196 #ifdef NSS_ENABLE_ECC
01197     FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"ec\", \"rsa\" (default))\n",
01198        "   -k key-type");
01199 #else
01200     FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"rsa\" (default))\n",
01201        "   -k key-type");
01202 #endif
01203     FPS "%-20s Specify the password file\n",
01204         "   -f password-file");
01205     FPS "%-20s Key database directory (default is ~/.netscape)\n",
01206        "   -d keydir");
01207     FPS "%-20s Cert & Key database prefix\n",
01208        "   -P dbprefix");
01209     FPS "%-20s force the database to open R/W\n",
01210        "   -X");
01211     FPS "\n");
01212 
01213     FPS "%-15s List all certs, or print out a single named cert\n",
01214        "-L");
01215     FPS "%-20s Pretty print named cert (list all if unspecified)\n",
01216        "   -n cert-name");
01217     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01218        "   -d certdir");
01219     FPS "%-20s Cert & Key database prefix\n",
01220        "   -P dbprefix");
01221     FPS "%-20s force the database to open R/W\n",
01222        "   -X");
01223     FPS "%-20s For single cert, print binary DER encoding\n",
01224        "   -r");
01225     FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
01226        "   -a");
01227     FPS "\n");
01228 
01229     FPS "%-15s Modify trust attributes of certificate\n",
01230        "-M");
01231     FPS "%-20s The nickname of the cert to modify\n",
01232        "   -n cert-name");
01233     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
01234        "   -t trustargs");
01235     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01236        "   -d certdir");
01237     FPS "%-20s Cert & Key database prefix\n",
01238        "   -P dbprefix");
01239     FPS "\n");
01240 
01241     FPS "%-15s Create a new certificate database\n",
01242        "-N");
01243     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01244        "   -d certdir");
01245     FPS "%-20s Cert & Key database prefix\n",
01246        "   -P dbprefix");
01247     FPS "\n");
01248     FPS "%-15s Reset the Key database or token\n",
01249        "-T");
01250     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01251        "   -d certdir");
01252     FPS "%-20s Cert & Key database prefix\n",
01253        "   -P dbprefix");
01254     FPS "%-20s Token to reset (default is internal)\n",
01255        "   -h token-name");
01256     FPS "\n");
01257 
01258     FPS "\n");
01259     FPS "%-15s Print the chain of a certificate\n",
01260        "-O");
01261     FPS "%-20s The nickname of the cert to modify\n",
01262        "   -n cert-name");
01263     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01264        "   -d certdir");
01265     FPS "%-20s Cert & Key database prefix\n",
01266        "   -P dbprefix");
01267     FPS "%-20s force the database to open R/W\n",
01268        "   -X");
01269     FPS "\n");
01270 
01271     FPS "%-15s Generate a certificate request (stdout)\n",
01272        "-R");
01273     FPS "%-20s Specify the subject name (using RFC1485)\n",
01274        "   -s subject");
01275     FPS "%-20s Output the cert request to this file\n",
01276        "   -o output-req");
01277 #ifdef NSS_ENABLE_ECC
01278     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
01279        "   -k key-type");
01280 #else
01281     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
01282        "   -k key-type");
01283 #endif /* NSS_ENABLE_ECC */
01284     FPS "%-20s Name of token in which to generate key (default is internal)\n",
01285        "   -h token-name");
01286     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
01287        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01288     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
01289        "   -q pqgfile");
01290 #ifdef NSS_ENABLE_ECC
01291     FPS "%-20s Elliptic curve name (ec only)\n",
01292        "   -q curve-name");
01293     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
01294        "");
01295 #endif /* NSS_ENABLE_ECC */
01296     FPS "%-20s Specify the password file\n",
01297        "   -f pwfile");
01298     FPS "%-20s Key database directory (default is ~/.netscape)\n",
01299        "   -d keydir");
01300     FPS "%-20s Cert & Key database prefix\n",
01301        "   -P dbprefix");
01302     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
01303        "   -p phone");
01304     FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
01305        "   -a");
01306     FPS "%-20s \n",
01307        "   See -S for available extension options");
01308     FPS "\n");
01309 
01310     FPS "%-15s Validate a certificate\n",
01311        "-V");
01312     FPS "%-20s The nickname of the cert to Validate\n",
01313        "   -n cert-name");
01314     FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
01315        "   -b time");
01316     FPS "%-20s Check certificate signature \n",
01317        "   -e ");   
01318     FPS "%-20s Specify certificate usage:\n", "   -u certusage");
01319     FPS "%-25s C \t SSL Client\n", "");
01320     FPS "%-25s V \t SSL Server\n", "");
01321     FPS "%-25s S \t Email signer\n", "");
01322     FPS "%-25s R \t Email Recipient\n", "");   
01323     FPS "%-25s O \t OCSP status responder\n", "");   
01324     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01325        "   -d certdir");
01326     FPS "%-20s Cert & Key database prefix\n",
01327        "   -P dbprefix");
01328     FPS "%-20s force the database to open R/W\n",
01329        "   -X");
01330     FPS "\n");
01331 
01332     FPS "%-15s Make a certificate and add to database\n",
01333         "-S");
01334     FPS "%-20s Specify the nickname of the cert\n",
01335         "   -n key-name");
01336     FPS "%-20s Specify the subject name (using RFC1485)\n",
01337         "   -s subject");
01338     FPS "%-20s The nickname of the issuer cert\n",
01339        "   -c issuer-name");
01340     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
01341        "   -t trustargs");
01342 #ifdef NSS_ENABLE_ECC
01343     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
01344        "   -k key-type");
01345 #else
01346     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
01347        "   -k key-type");
01348 #endif /* NSS_ENABLE_ECC */
01349     FPS "%-20s Name of token in which to generate key (default is internal)\n",
01350        "   -h token-name");
01351     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
01352        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01353     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
01354        "   -q pqgfile");
01355 #ifdef NSS_ENABLE_ECC
01356     FPS "%-20s Elliptic curve name (ec only)\n",
01357        "   -q curve-name");
01358     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
01359        "");
01360 #endif /* NSS_ENABLE_ECC */
01361     FPS "%-20s Self sign\n",
01362        "   -x");
01363     FPS "%-20s Cert serial number\n",
01364        "   -m serial-number");
01365     FPS "%-20s Time Warp\n",
01366        "   -w warp-months");
01367     FPS "%-20s Months valid (default is 3)\n",
01368         "   -v months-valid");
01369     FPS "%-20s Specify the password file\n",
01370        "   -f pwfile");
01371     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01372        "   -d certdir");
01373     FPS "%-20s Cert & Key database prefix\n",
01374        "   -P dbprefix");
01375     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
01376        "   -p phone");
01377     FPS "%-20s Create key usage extension\n",
01378        "   -1 ");
01379     FPS "%-20s Create basic constraint extension\n",
01380        "   -2 ");
01381     FPS "%-20s Create authority key ID extension\n",
01382        "   -3 ");
01383     FPS "%-20s Create crl distribution point extension\n",
01384        "   -4 ");
01385     FPS "%-20s Create netscape cert type extension\n",
01386        "   -5 ");
01387     FPS "%-20s Create extended key usage extension\n",
01388        "   -6 ");
01389     FPS "%-20s Create an email subject alt name extension\n",
01390        "   -7 ");
01391     FPS "%-20s Create an dns subject alt name extension\n",
01392        "   -8 ");
01393     FPS "\n");
01394 
01395     exit(1);
01396 #undef FPS
01397 }
01398 
01399 
01400 static CERTCertificate *
01401 MakeV1Cert(   CERTCertDBHandle *   handle, 
01402               CERTCertificateRequest *req,
01403               char *               issuerNickName, 
01404               PRBool                      selfsign, 
01405               unsigned int         serialNumber,
01406               int                  warpmonths,
01407                 int                     validityMonths)
01408 {
01409     CERTCertificate *issuerCert = NULL;
01410     CERTValidity *validity;
01411     CERTCertificate *cert = NULL;
01412     PRExplodedTime printableTime;
01413     PRTime now, after;
01414 
01415     if ( !selfsign ) {
01416        issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
01417        if (!issuerCert) {
01418            SECU_PrintError(progName, "could not find certificate named \"%s\"",
01419                          issuerNickName);
01420            return NULL;
01421        }
01422     }
01423 
01424     now = PR_Now();
01425     PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
01426     if ( warpmonths ) {
01427        printableTime.tm_month += warpmonths;
01428        now = PR_ImplodeTime (&printableTime);
01429        PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
01430     }
01431     printableTime.tm_month += validityMonths;
01432     after = PR_ImplodeTime (&printableTime);
01433 
01434     /* note that the time is now in micro-second unit */
01435     validity = CERT_CreateValidity (now, after);
01436     if (validity) {
01437         cert = CERT_CreateCertificate(serialNumber, 
01438                               (selfsign ? &req->subject 
01439                                         : &issuerCert->subject), 
01440                                  validity, req);
01441     
01442         CERT_DestroyValidity(validity);
01443     }
01444     if ( issuerCert ) {
01445        CERT_DestroyCertificate (issuerCert);
01446     }
01447     
01448     return(cert);
01449 }
01450 
01451 static SECStatus 
01452 AddKeyUsage (void *extHandle)
01453 {
01454     SECItem bitStringValue;
01455     unsigned char keyUsage = 0x0;
01456     char buffer[5];
01457     int value;
01458     PRBool yesNoAns;
01459 
01460     while (1) {
01461        fprintf(stdout, "%-25s 0 - Digital Signature\n", "");
01462        fprintf(stdout, "%-25s 1 - Non-repudiation\n", "");
01463        fprintf(stdout, "%-25s 2 - Key encipherment\n", "");
01464        fprintf(stdout, "%-25s 3 - Data encipherment\n", "");   
01465        fprintf(stdout, "%-25s 4 - Key agreement\n", "");
01466        fprintf(stdout, "%-25s 5 - Cert signing key\n", "");   
01467        fprintf(stdout, "%-25s 6 - CRL signing key\n", "");
01468        fprintf(stdout, "%-25s Other to finish\n", "");
01469        if (Gets_s (buffer, sizeof(buffer))) {
01470            value = PORT_Atoi (buffer);
01471            if (value < 0 || value > 6)
01472                break;
01473            if (value == 0) {
01474               /* Checking that zero value of variable 'value'
01475                * corresponds to '0' input made by user */
01476               char *chPtr = strchr(buffer, '0');
01477               if (chPtr == NULL) {
01478                   continue;
01479               }
01480            }
01481            keyUsage |= (0x80 >> value);
01482        }
01483        else {        /* gets() returns NULL on EOF or error */
01484            break;
01485        }
01486     }
01487 
01488     bitStringValue.data = &keyUsage;
01489     bitStringValue.len = 1;
01490     yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
01491 
01492     return (CERT_EncodeAndAddBitStrExtension
01493            (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
01494             yesNoAns));
01495 
01496 }
01497 
01498 
01499 static CERTOidSequence *
01500 CreateOidSequence(void)
01501 {
01502   CERTOidSequence *rv = (CERTOidSequence *)NULL;
01503   PRArenaPool *arena = (PRArenaPool *)NULL;
01504 
01505   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01506   if( (PRArenaPool *)NULL == arena ) {
01507     goto loser;
01508   }
01509 
01510   rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
01511   if( (CERTOidSequence *)NULL == rv ) {
01512     goto loser;
01513   }
01514 
01515   rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
01516   if( (SECItem **)NULL == rv->oids ) {
01517     goto loser;
01518   }
01519 
01520   rv->arena = arena;
01521   return rv;
01522 
01523  loser:
01524   if( (PRArenaPool *)NULL != arena ) {
01525     PORT_FreeArena(arena, PR_FALSE);
01526   }
01527 
01528   return (CERTOidSequence *)NULL;
01529 }
01530 
01531 static void
01532 DestroyOidSequence(CERTOidSequence *os)
01533 {
01534   if (os->arena) {
01535     PORT_FreeArena(os->arena, PR_FALSE);
01536   }
01537 }
01538 
01539 static SECStatus
01540 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
01541 {
01542   SECItem **oids;
01543   PRUint32 count = 0;
01544   SECOidData *od;
01545 
01546   od = SECOID_FindOIDByTag(oidTag);
01547   if( (SECOidData *)NULL == od ) {
01548     return SECFailure;
01549   }
01550 
01551   for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
01552     count++;
01553   }
01554 
01555   /* ArenaZRealloc */
01556 
01557   {
01558     PRUint32 i;
01559 
01560     oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
01561     if( (SECItem **)NULL == oids ) {
01562       return SECFailure;
01563     }
01564     
01565     for( i = 0; i < count; i++ ) {
01566       oids[i] = os->oids[i];
01567     }
01568 
01569     /* ArenaZFree(os->oids); */
01570   }
01571 
01572   os->oids = oids;
01573   os->oids[count] = &od->oid;
01574 
01575   return SECSuccess;
01576 }
01577 
01578 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
01579 
01580 const SEC_ASN1Template CERT_OidSeqTemplate[] = {
01581     { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN,
01582          offsetof(CERTOidSequence, oids),
01583          SEC_ASN1_SUB(SEC_ObjectIDTemplate) }
01584 };
01585 
01586 
01587 static SECItem *
01588 EncodeOidSequence(CERTOidSequence *os)
01589 {
01590   SECItem *rv;
01591 
01592   rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
01593   if( (SECItem *)NULL == rv ) {
01594     goto loser;
01595   }
01596 
01597   if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
01598     goto loser;
01599   }
01600 
01601   return rv;
01602 
01603  loser:
01604   return (SECItem *)NULL;
01605 }
01606 
01607 static SECStatus 
01608 AddExtKeyUsage (void *extHandle)
01609 {
01610   char buffer[5];
01611   int value;
01612   CERTOidSequence *os;
01613   SECStatus rv;
01614   SECItem *item;
01615   PRBool yesNoAns;
01616 
01617   os = CreateOidSequence();
01618   if( (CERTOidSequence *)NULL == os ) {
01619     return SECFailure;
01620   }
01621 
01622   while (1) {
01623     fprintf(stdout, "%-25s 0 - Server Auth\n", "");
01624     fprintf(stdout, "%-25s 1 - Client Auth\n", "");
01625     fprintf(stdout, "%-25s 2 - Code Signing\n", "");
01626     fprintf(stdout, "%-25s 3 - Email Protection\n", "");
01627     fprintf(stdout, "%-25s 4 - Timestamp\n", "");
01628     fprintf(stdout, "%-25s 5 - OCSP Responder\n", "");
01629     fprintf(stdout, "%-25s 6 - Step-up\n", "");
01630     fprintf(stdout, "%-25s Other to finish\n", "");
01631 
01632     if (Gets_s(buffer, sizeof(buffer)) == NULL) {
01633         PORT_SetError(SEC_ERROR_INPUT_LEN);
01634         rv = SECFailure;
01635         goto loser;
01636     }
01637     value = PORT_Atoi(buffer);
01638 
01639     if (value == 0) {
01640         /* Checking that zero value of variable 'value'
01641          * corresponds to '0' input made by user */
01642         char *chPtr = strchr(buffer, '0');
01643         if (chPtr == NULL) {
01644             continue;
01645         }
01646     }
01647 
01648     switch( value ) {
01649     case 0:
01650       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH);
01651       break;
01652     case 1:
01653       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH);
01654       break;
01655     case 2:
01656       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN);
01657       break;
01658     case 3:
01659       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT);
01660       break;
01661     case 4:
01662       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP);
01663       break;
01664     case 5:
01665       rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
01666       break;
01667     case 6:
01668       rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
01669       break;
01670     default:
01671       goto endloop;
01672     }
01673 
01674     if( SECSuccess != rv ) goto loser;
01675   }
01676 
01677  endloop:;
01678   item = EncodeOidSequence(os);
01679 
01680   yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
01681 
01682   rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item,
01683                          yesNoAns, PR_TRUE);
01684   /*FALLTHROUGH*/
01685  loser:
01686   DestroyOidSequence(os);
01687   return rv;
01688 }
01689 
01690 static SECStatus 
01691 AddNscpCertType (void *extHandle)
01692 {
01693     SECItem bitStringValue;
01694     unsigned char keyUsage = 0x0;
01695     char buffer[5];
01696     int value;
01697     PRBool yesNoAns;
01698 
01699     while (1) {
01700        fprintf(stdout, "%-25s 0 - SSL Client\n", "");
01701        fprintf(stdout, "%-25s 1 - SSL Server\n", "");
01702        fprintf(stdout, "%-25s 2 - S/MIME\n", "");
01703        fprintf(stdout, "%-25s 3 - Object Signing\n", "");   
01704        fprintf(stdout, "%-25s 4 - Reserved for future use\n", "");
01705        fprintf(stdout, "%-25s 5 - SSL CA\n", "");   
01706        fprintf(stdout, "%-25s 6 - S/MIME CA\n", "");
01707        fprintf(stdout, "%-25s 7 - Object Signing CA\n", "");
01708        fprintf(stdout, "%-25s Other to finish\n", "");
01709        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
01710            PORT_SetError(SEC_ERROR_INPUT_LEN);
01711            return SECFailure;
01712        }
01713        value = PORT_Atoi (buffer);
01714        if (value < 0 || value > 7)
01715            break;
01716        if (value == 0) {
01717            /* Checking that zero value of variable 'value'
01718             * corresponds to '0' input made by user */
01719            char *chPtr = strchr(buffer, '0');
01720            if (chPtr == NULL) {
01721               continue;
01722            }
01723        }
01724        keyUsage |= (0x80 >> value);
01725     }
01726 
01727     bitStringValue.data = &keyUsage;
01728     bitStringValue.len = 1;
01729     yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
01730 
01731     return (CERT_EncodeAndAddBitStrExtension
01732            (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue,
01733             yesNoAns));
01734 
01735 }
01736 
01737 static SECStatus 
01738 AddSubjectAltNames(PRArenaPool *arena, CERTGeneralName **existingListp,
01739                     const char *names, CERTGeneralNameType type)
01740 {
01741     CERTGeneralName *nameList = NULL;
01742     CERTGeneralName *current = NULL;
01743     PRCList *prev = NULL;
01744     const char *cp;
01745     char *tbuf;
01746     SECStatus rv = SECSuccess;
01747 
01748        
01749     /*
01750      * walk down the comma separated list of names. NOTE: there is
01751      * no sanity checks to see if the email address look like email addresses.
01752      */
01753     for (cp=names; cp; cp = PORT_Strchr(cp,',')) {
01754        int len;
01755        char *end;
01756 
01757        if (*cp == ',') {
01758           cp++;
01759        }
01760        end = PORT_Strchr(cp,',');
01761        len = end ? end-cp : PORT_Strlen(cp);
01762        if (len <= 0) {
01763           continue;
01764        }
01765        tbuf = PORT_ArenaAlloc(arena,len+1);
01766        PORT_Memcpy(tbuf,cp,len);
01767        tbuf[len] = 0;
01768        current = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
01769        if (!current) {
01770            rv = SECFailure;
01771            break;
01772        }
01773        if (prev) {
01774            current->l.prev = prev;
01775            prev->next = &(current->l);
01776        } else {
01777            nameList = current;
01778        }
01779        current->type = type;
01780        current->name.other.data = (unsigned char *)tbuf;
01781        current->name.other.len = PORT_Strlen(tbuf);
01782        prev = &(current->l);
01783     }
01784     /* at this point nameList points to the head of a doubly linked, but not yet 
01785        circular, list and current points to its tail. */
01786     if (rv == SECSuccess && nameList) {
01787         if (*existingListp != NULL) {
01788             PRCList *existingprev;
01789             /* add nameList to the end of the existing list */
01790             existingprev = (*existingListp)->l.prev;
01791             (*existingListp)->l.prev = &(current->l);
01792             nameList->l.prev = existingprev;
01793             existingprev->next = &(nameList->l);
01794             current->l.next = &((*existingListp)->l);
01795         }
01796         else {
01797             /* make nameList circular and set it as the new existingList */
01798             nameList->l.prev = prev;
01799             current->l.next = &(nameList->l);
01800             *existingListp = nameList;
01801         }
01802     }
01803     return rv;
01804 }
01805 
01806 static SECStatus 
01807 AddEmailSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
01808                     const char *emailAddrs)
01809 {
01810     return AddSubjectAltNames(arena, existingListp, emailAddrs, certRFC822Name);
01811 }
01812 
01813 static SECStatus 
01814 AddDNSSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
01815                     const char *dnsNames)
01816 {
01817     return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName);
01818 }
01819 
01820 
01821 static SECStatus 
01822 AddBasicConstraint(void *extHandle)
01823 {
01824     CERTBasicConstraints basicConstraint;    
01825     SECItem encodedValue;
01826     SECStatus rv;
01827     char buffer[10];
01828     PRBool yesNoAns;
01829 
01830     encodedValue.data = NULL;
01831     encodedValue.len = 0;
01832     do {
01833        basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
01834        basicConstraint.isCA = GetYesNo ("Is this a CA certificate [y/N]?");
01835 
01836        buffer[0] = '\0';
01837        puts ("Enter the path length constraint, enter to skip [<0 for unlimited path]:");
01838        Gets_s (buffer, sizeof(buffer));
01839        if (PORT_Strlen (buffer) > 0)
01840            basicConstraint.pathLenConstraint = PORT_Atoi (buffer);
01841        
01842        rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint, &encodedValue);
01843        if (rv)
01844            return (rv);
01845 
01846        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
01847 
01848        rv = CERT_AddExtension
01849             (extHandle, SEC_OID_X509_BASIC_CONSTRAINTS,
01850              &encodedValue, yesNoAns, PR_TRUE);
01851     } while (0);
01852     PORT_Free (encodedValue.data);
01853     return (rv);
01854 }
01855 
01856 static SECItem *
01857 SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, 
01858          SECOidTag hashAlgTag,
01859          SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg)
01860 {
01861     SECItem der;
01862     SECItem *result = NULL;
01863     SECKEYPrivateKey *caPrivateKey = NULL;    
01864     SECStatus rv;
01865     PRArenaPool *arena;
01866     SECOidTag algID;
01867     void *dummy;
01868 
01869     if( !selfsign ) {
01870       CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
01871       if( (CERTCertificate *)NULL == issuer ) {
01872         SECU_PrintError(progName, "unable to find issuer with nickname %s", 
01873                        issuerNickName);
01874         return (SECItem *)NULL;
01875       }
01876 
01877       privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
01878       CERT_DestroyCertificate(issuer);
01879       if (caPrivateKey == NULL) {
01880        SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
01881        return NULL;
01882       }
01883     }
01884        
01885     arena = cert->arena;
01886 
01887     algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
01888     if (algID == SEC_OID_UNKNOWN) {
01889        fprintf(stderr, "Unknown key or hash type for issuer.");
01890        goto done;
01891     }
01892 
01893     rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
01894     if (rv != SECSuccess) {
01895        fprintf(stderr, "Could not set signature algorithm id.");
01896        goto done;
01897     }
01898 
01899     /* we only deal with cert v3 here */
01900     *(cert->version.data) = 2;
01901     cert->version.len = 1;
01902 
01903     der.len = 0;
01904     der.data = NULL;
01905     dummy = SEC_ASN1EncodeItem (arena, &der, cert,
01906                             SEC_ASN1_GET(CERT_CertificateTemplate));
01907     if (!dummy) {
01908        fprintf (stderr, "Could not encode certificate.\n");
01909        goto done;
01910     }
01911 
01912     result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem));
01913     if (result == NULL) {
01914        fprintf (stderr, "Could not allocate item for certificate data.\n");
01915        goto done;
01916     }
01917 
01918     rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID);
01919     if (rv != SECSuccess) {
01920        fprintf (stderr, "Could not sign encoded certificate data.\n");
01921        PORT_Free(result);
01922        result = NULL;
01923        goto done;
01924     }
01925     cert->derCert = *result;
01926 done:
01927     if (caPrivateKey) {
01928        SECKEY_DestroyPrivateKey(caPrivateKey);
01929     }
01930     return result;
01931 }
01932 
01933 static SECStatus 
01934 AddAuthKeyID (void *extHandle)
01935 {
01936     CERTAuthKeyID *authKeyID = NULL;    
01937     PRArenaPool *arena = NULL;
01938     SECStatus rv = SECSuccess;
01939     PRBool yesNoAns;
01940 
01941     do {
01942        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01943        if ( !arena ) {
01944            SECU_PrintError(progName, "out of memory");
01945            GEN_BREAK (SECFailure);
01946        }
01947 
01948        if (GetYesNo ("Enter value for the authKeyID extension [y/N]?") == 0)
01949            break;
01950        
01951        authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID));
01952        if (authKeyID == NULL) {
01953            GEN_BREAK (SECFailure);
01954        }
01955 
01956        rv = GetString (arena, "Enter value for the key identifier fields, enter to omit:",
01957                      &authKeyID->keyID);
01958        if (rv != SECSuccess)
01959            break;
01960        authKeyID->authCertIssuer = GetGeneralName (arena);
01961        if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError ())
01962               break;
01963        
01964 
01965        rv = GetString (arena, "Enter value for the authCertSerial field, enter to omit:",
01966                      &authKeyID->authCertSerialNumber);
01967 
01968        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
01969 
01970        rv = SECU_EncodeAndAddExtensionValue
01971            (arena, extHandle, authKeyID, yesNoAns,
01972             SEC_OID_X509_AUTH_KEY_ID, 
01973             (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID);
01974        if (rv)
01975            break;
01976        
01977     } while (0);
01978     if (arena)
01979        PORT_FreeArena (arena, PR_FALSE);
01980     return (rv);
01981 }   
01982     
01983 static SECStatus 
01984 AddCrlDistPoint(void *extHandle)
01985 {
01986     PRArenaPool *arena = NULL;
01987     CERTCrlDistributionPoints *crlDistPoints = NULL;
01988     CRLDistributionPoint *current;
01989     SECStatus rv = SECSuccess;
01990     int count = 0, intValue;
01991     char buffer[512];
01992 
01993     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01994     if ( !arena )
01995        return (SECFailure);
01996 
01997     do {
01998        current = NULL;
01999        current = PORT_ArenaZAlloc (arena, sizeof (*current));
02000         if (current == NULL) {
02001            GEN_BREAK (SECFailure);
02002        }   
02003 
02004        /* Get the distributionPointName fields - this field is optional */
02005        puts ("Enter the type of the distribution point name:\n");
02006        puts ("\t1 - Full Name\n\t2 - Relative Name\n\tAny other number to finish\n\t\tChoice: ");
02007        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
02008            PORT_SetError(SEC_ERROR_INPUT_LEN);
02009            GEN_BREAK (SECFailure);
02010        }
02011        intValue = PORT_Atoi (buffer);
02012        switch (intValue) {
02013            case generalName:
02014               current->distPointType = intValue;
02015               current->distPoint.fullName = GetGeneralName (arena);
02016               rv = PORT_GetError();
02017               break;
02018               
02019            case relativeDistinguishedName: {
02020               CERTName *name;
02021 
02022               current->distPointType = intValue;
02023               puts ("Enter the relative name: ");
02024               fflush (stdout);
02025               if (Gets_s (buffer, sizeof(buffer)) == NULL) {
02026                   GEN_BREAK (SECFailure);
02027               }
02028               /* For simplicity, use CERT_AsciiToName to converse from a string
02029                  to NAME, but we only interest in the first RDN */
02030               name = CERT_AsciiToName (buffer);
02031               if (!name) {
02032                   GEN_BREAK (SECFailure);
02033               }
02034               rv = CERT_CopyRDN (arena, &current->distPoint.relativeName, name->rdns[0]);
02035               CERT_DestroyName (name);
02036               break;
02037            }
02038        }
02039        if (rv != SECSuccess)
02040            break;
02041 
02042        /* Get the reason flags */
02043        puts ("\nSelect one of the following for the reason flags\n");
02044        puts ("\t0 - unused\n\t1 - keyCompromise\n\t2 - caCompromise\n\t3 - affiliationChanged\n");
02045        puts ("\t4 - superseded\n\t5 - cessationOfOperation\n\t6 - certificateHold\n");
02046        puts ("\tAny other number to finish\t\tChoice: ");
02047        
02048        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
02049            PORT_SetError(SEC_ERROR_INPUT_LEN);
02050            GEN_BREAK (SECFailure);
02051        }
02052        intValue = PORT_Atoi (buffer);
02053        if (intValue == 0) {
02054            /* Checking that zero value of variable 'value'
02055             * corresponds to '0' input made by user */
02056            char *chPtr = strchr(buffer, '0');
02057            if (chPtr == NULL) {
02058               intValue = -1;
02059            }
02060        }
02061        if (intValue >= 0 && intValue <8) {
02062            current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char));
02063            if (current->reasons.data == NULL) {
02064               GEN_BREAK (SECFailure);
02065            }
02066            *current->reasons.data = (char)(0x80 >> intValue);
02067            current->reasons.len = 1;
02068        }
02069        puts ("Enter value for the CRL Issuer name:\n");
02070         current->crlIssuer = GetGeneralName (arena);
02071        if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure)
02072            break;
02073 
02074        if (crlDistPoints == NULL) {
02075            crlDistPoints = PORT_ArenaZAlloc (arena, sizeof (*crlDistPoints));
02076            if (crlDistPoints == NULL) {
02077               GEN_BREAK (SECFailure);
02078            }
02079        }
02080            
02081        crlDistPoints->distPoints = PORT_ArenaGrow (arena, 
02082             crlDistPoints->distPoints,
02083             sizeof (*crlDistPoints->distPoints) * count,
02084             sizeof (*crlDistPoints->distPoints) *(count + 1));
02085        if (crlDistPoints->distPoints == NULL) {
02086            GEN_BREAK (SECFailure);
02087        }
02088        
02089        crlDistPoints->distPoints[count] = current;
02090        ++count;
02091        if (GetYesNo ("Enter more value for the CRL distribution point extension [y/N]") == 0) {
02092            /* Add null to the end of the crlDistPoints to mark end of data */
02093            crlDistPoints->distPoints = PORT_ArenaGrow(arena, 
02094                crlDistPoints->distPoints,
02095                sizeof (*crlDistPoints->distPoints) * count,
02096                sizeof (*crlDistPoints->distPoints) *(count + 1));
02097            crlDistPoints->distPoints[count] = NULL;         
02098            break;
02099        }
02100        
02101 
02102     } while (1);
02103     
02104     if (rv == SECSuccess) {
02105        PRBool yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
02106        
02107        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, crlDistPoints,
02108              yesNoAns, SEC_OID_X509_CRL_DIST_POINTS,
02109              (EXTEN_EXT_VALUE_ENCODER)  CERT_EncodeCRLDistributionPoints);
02110     }
02111     if (arena)
02112        PORT_FreeArena (arena, PR_FALSE);
02113     return (rv);
02114 }
02115 
02116 static SECStatus
02117 AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
02118        PRBool keyUsage, 
02119        PRBool  extKeyUsage,
02120        PRBool  basicConstraint, 
02121        PRBool  authKeyID,
02122        PRBool  crlDistPoints, 
02123        PRBool  nscpCertType)
02124 {
02125     SECStatus        rv = SECSuccess;
02126     do {
02127        /* Add key usage extension */
02128        if (keyUsage) {
02129            rv = AddKeyUsage(extHandle);
02130            if (rv)
02131               break;
02132        }
02133 
02134        /* Add extended key usage extension */
02135        if (extKeyUsage) {
02136            rv = AddExtKeyUsage(extHandle);
02137            if (rv)
02138               break;
02139        }
02140 
02141        /* Add basic constraint extension */
02142        if (basicConstraint) {
02143            rv = AddBasicConstraint(extHandle);
02144            if (rv)
02145               break;
02146        }
02147 
02148        if (authKeyID) {
02149            rv = AddAuthKeyID (extHandle);
02150            if (rv)
02151               break;
02152        }    
02153 
02154        if (crlDistPoints) {
02155            rv = AddCrlDistPoint (extHandle);
02156            if (rv)
02157               break;
02158        }
02159        
02160        if (nscpCertType) {
02161            rv = AddNscpCertType(extHandle);
02162            if (rv)
02163               break;
02164        }
02165 
02166        if (emailAddrs || dnsNames) {
02167             PRArenaPool *arena;
02168             CERTGeneralName *namelist = NULL;
02169             SECItem item = { 0, NULL, 0 };
02170             
02171             arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02172             if (arena == NULL) {
02173                 rv = SECFailure;
02174                 break;
02175             }
02176 
02177            rv = AddEmailSubjectAlt(arena, &namelist, emailAddrs);
02178 
02179            rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
02180 
02181             if (rv == SECSuccess) {
02182                 rv = CERT_EncodeAltNameExtension(arena, namelist, &item);
02183                 if (rv == SECSuccess) {
02184                    rv = CERT_AddExtension(extHandle,
02185                                            SEC_OID_X509_SUBJECT_ALT_NAME,
02186                                            &item, PR_FALSE, PR_TRUE);
02187                 }
02188             }
02189             PORT_FreeArena(arena, PR_FALSE);
02190        }
02191     } while (0);
02192     return rv;
02193 }
02194 
02195 static SECStatus
02196 CreateCert(
02197        CERTCertDBHandle *handle, 
02198        char *  issuerNickName, 
02199        PRFileDesc *inFile,
02200        PRFileDesc *outFile, 
02201        SECKEYPrivateKey *selfsignprivkey,
02202        void   *pwarg,
02203        SECOidTag hashAlgTag,
02204        unsigned int serialNumber, 
02205        int     warpmonths,
02206        int     validityMonths,
02207        const char *emailAddrs,
02208        const char *dnsNames,
02209        PRBool  ascii,
02210        PRBool  selfsign,
02211        PRBool keyUsage, 
02212        PRBool  extKeyUsage,
02213        PRBool  basicConstraint, 
02214        PRBool  authKeyID,
02215        PRBool  crlDistPoints, 
02216        PRBool  nscpCertType)
02217 {
02218     void *    extHandle;
02219     SECItem * certDER;
02220     PRArenaPool *arena                    = NULL;
02221     CERTCertificate *subjectCert   = NULL;
02222     CERTCertificateRequest *certReq       = NULL;
02223     SECStatus        rv                   = SECSuccess;
02224     SECItem   reqDER;
02225     CERTCertExtension **CRexts;
02226 
02227     reqDER.data = NULL;
02228     do {
02229        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02230        if (!arena) {
02231            GEN_BREAK (SECFailure);
02232        }
02233        
02234        /* Create a certrequest object from the input cert request der */
02235        certReq = GetCertRequest(inFile, ascii);
02236        if (certReq == NULL) {
02237            GEN_BREAK (SECFailure)
02238        }
02239 
02240        subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign,
02241                               serialNumber, warpmonths, validityMonths);
02242        if (subjectCert == NULL) {
02243            GEN_BREAK (SECFailure)
02244        }
02245         
02246         
02247        extHandle = CERT_StartCertExtensions (subjectCert);
02248        if (extHandle == NULL) {
02249            GEN_BREAK (SECFailure)
02250        }
02251         
02252         rv = AddExtensions(extHandle, emailAddrs, dnsNames, keyUsage, extKeyUsage,
02253                           basicConstraint, authKeyID, crlDistPoints, nscpCertType);
02254         if (rv != SECSuccess) {
02255            GEN_BREAK (SECFailure)
02256        }
02257         
02258         if (certReq->attributes != NULL &&
02259            certReq->attributes[0] != NULL &&
02260            certReq->attributes[0]->attrType.data != NULL &&
02261            certReq->attributes[0]->attrType.len   > 0    &&
02262             SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
02263                 == SEC_OID_PKCS9_EXTENSION_REQUEST) {
02264             rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
02265             if (rv != SECSuccess)
02266                 break;
02267             rv = CERT_MergeExtensions(extHandle, CRexts);
02268             if (rv != SECSuccess)
02269                 break;
02270         }
02271 
02272        CERT_FinishExtensions(extHandle);
02273 
02274        certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag,
02275                           selfsignprivkey, issuerNickName,pwarg);
02276 
02277        if (certDER) {
02278           if (ascii) {
02279               PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER, 
02280                          BTOA_DataToAscii(certDER->data, certDER->len), 
02281                         NS_CERT_TRAILER);
02282           } else {
02283               PR_Write(outFile, certDER->data, certDER->len);
02284           }
02285        }
02286 
02287     } while (0);
02288     CERT_DestroyCertificateRequest (certReq);
02289     CERT_DestroyCertificate (subjectCert);
02290     PORT_FreeArena (arena, PR_FALSE);
02291     if (rv != SECSuccess) {
02292        PRErrorCode  perr = PR_GetError();
02293         fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
02294                SECU_Strerror(perr));
02295     }
02296     return (rv);
02297 }
02298 
02299 /*  Certutil commands  */
02300 enum {
02301     cmd_AddCert = 0,
02302     cmd_CreateNewCert,
02303     cmd_DeleteCert,
02304     cmd_AddEmailCert,
02305     cmd_DeleteKey,
02306     cmd_GenKeyPair,
02307     cmd_PrintHelp,
02308     cmd_ListKeys,
02309     cmd_ListCerts,
02310     cmd_ModifyCertTrust,
02311     cmd_NewDBs,
02312     cmd_DumpChain,
02313     cmd_CertReq,
02314     cmd_CreateAndAddCert,
02315     cmd_TokenReset,
02316     cmd_ListModules,
02317     cmd_CheckCertValidity,
02318     cmd_ChangePassword,
02319     cmd_Version,
02320     cmd_Batch
02321 };
02322 
02323 /*  Certutil options */
02324 enum {
02325     opt_SSOPass = 0,
02326     opt_AddKeyUsageExt,
02327     opt_AddBasicConstraintExt,
02328     opt_AddAuthorityKeyIDExt,
02329     opt_AddCRLDistPtsExt,
02330     opt_AddNSCertTypeExt,
02331     opt_AddExtKeyUsageExt,
02332     opt_ExtendedEmailAddrs,
02333     opt_ExtendedDNSNames,
02334     opt_ASCIIForIO,
02335     opt_ValidityTime,
02336     opt_IssuerName,
02337     opt_CertDir,
02338     opt_VerifySig,
02339     opt_PasswordFile,
02340     opt_KeySize,
02341     opt_TokenName,
02342     opt_InputFile,
02343     opt_KeyIndex,
02344     opt_KeyType,
02345     opt_DetailedInfo,
02346     opt_SerialNumber,
02347     opt_Nickname,
02348     opt_OutputFile,
02349     opt_PhoneNumber,
02350     opt_DBPrefix,
02351     opt_PQGFile,
02352     opt_BinaryDER,
02353     opt_Subject,
02354     opt_Trust,
02355     opt_Usage,
02356     opt_Validity,
02357     opt_OffsetMonths,
02358     opt_SelfSign,
02359     opt_RW,
02360     opt_Exponent,
02361     opt_NoiseFile,
02362     opt_Hash
02363 };
02364 
02365 static int 
02366 certutil_main(int argc, char **argv, PRBool initialize)
02367 {
02368     CERTCertDBHandle *certHandle;
02369     PK11SlotInfo *slot = NULL;
02370     CERTName *  subject         = 0;
02371     PRFileDesc *inFile          = PR_STDIN;
02372     PRFileDesc *outFile         = NULL;
02373     char *      certfile        = "tempcert";
02374     char *      certreqfile     = "tempcertreq";
02375     char *      slotname        = "internal";
02376     char *      certPrefix      = "";
02377     KeyType     keytype         = rsaKey;
02378     char *      name            = NULL;
02379     SECOidTag   hashAlgTag      = SEC_OID_UNKNOWN;
02380     int               keysize              = DEFAULT_KEY_BITS;
02381     int         publicExponent  = 0x010001;
02382     unsigned int serialNumber   = 0;
02383     int         warpmonths      = 0;
02384     int         validityMonths  = 3;
02385     int         commandsEntered = 0;
02386     char        commandToRun    = '\0';
02387     secuPWData  pwdata          = { PW_NONE, 0 };
02388     PRBool    readOnly      = PR_FALSE;
02389     PRBool      initialized     = PR_FALSE;
02390 
02391     SECKEYPrivateKey *privkey = NULL;
02392     SECKEYPublicKey *pubkey = NULL;
02393 
02394     int i;
02395     SECStatus rv;
02396 
02397     secuCommand certutil;
02398 
02399 secuCommandFlag certutil_commands[] =
02400 {
02401        { /* cmd_AddCert             */  'A', PR_FALSE, 0, PR_FALSE },
02402        { /* cmd_CreateNewCert       */  'C', PR_FALSE, 0, PR_FALSE },
02403        { /* cmd_DeleteCert          */  'D', PR_FALSE, 0, PR_FALSE },
02404        { /* cmd_AddEmailCert        */  'E', PR_FALSE, 0, PR_FALSE },
02405        { /* cmd_DeleteKey           */  'F', PR_FALSE, 0, PR_FALSE },
02406        { /* cmd_GenKeyPair          */  'G', PR_FALSE, 0, PR_FALSE },
02407        { /* cmd_PrintHelp           */  'H', PR_FALSE, 0, PR_FALSE },
02408        { /* cmd_ListKeys            */  'K', PR_FALSE, 0, PR_FALSE },
02409        { /* cmd_ListCerts           */  'L', PR_FALSE, 0, PR_FALSE },
02410        { /* cmd_ModifyCertTrust     */  'M', PR_FALSE, 0, PR_FALSE },
02411        { /* cmd_NewDBs              */  'N', PR_FALSE, 0, PR_FALSE },
02412        { /* cmd_DumpChain           */  'O', PR_FALSE, 0, PR_FALSE },
02413        { /* cmd_CertReq             */  'R', PR_FALSE, 0, PR_FALSE },
02414        { /* cmd_CreateAndAddCert    */  'S', PR_FALSE, 0, PR_FALSE },
02415        { /* cmd_TokenReset          */  'T', PR_FALSE, 0, PR_FALSE },
02416        { /* cmd_ListModules         */  'U', PR_FALSE, 0, PR_FALSE },
02417        { /* cmd_CheckCertValidity   */  'V', PR_FALSE, 0, PR_FALSE },
02418        { /* cmd_ChangePassword      */  'W', PR_FALSE, 0, PR_FALSE },
02419        { /* cmd_Version             */  'Y', PR_FALSE, 0, PR_FALSE },
02420        { /* cmd_Batch               */  'B', PR_FALSE, 0, PR_FALSE }
02421 };
02422 
02423 secuCommandFlag certutil_options[] =
02424 {
02425        { /* opt_SSOPass             */  '0', PR_TRUE,  0, PR_FALSE },
02426        { /* opt_AddKeyUsageExt      */  '1', PR_FALSE, 0, PR_FALSE },
02427        { /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
02428        { /* opt_AddAuthorityKeyIDExt*/  '3', PR_FALSE, 0, PR_FALSE },
02429        { /* opt_AddCRLDistPtsExt    */  '4', PR_FALSE, 0, PR_FALSE },
02430        { /* opt_AddNSCertTypeExt    */  '5', PR_FALSE, 0, PR_FALSE },
02431        { /* opt_AddExtKeyUsageExt   */  '6', PR_FALSE, 0, PR_FALSE },
02432        { /* opt_ExtendedEmailAddrs  */  '7', PR_TRUE,  0, PR_FALSE },
02433        { /* opt_ExtendedDNSNames    */  '8', PR_TRUE,  0, PR_FALSE },
02434        { /* opt_ASCIIForIO          */  'a', PR_FALSE, 0, PR_FALSE },
02435        { /* opt_ValidityTime        */  'b', PR_TRUE,  0, PR_FALSE },
02436        { /* opt_IssuerName          */  'c', PR_TRUE,  0, PR_FALSE },
02437        { /* opt_CertDir             */  'd', PR_TRUE,  0, PR_FALSE },
02438        { /* opt_VerifySig           */  'e', PR_FALSE, 0, PR_FALSE },
02439        { /* opt_PasswordFile        */  'f', PR_TRUE,  0, PR_FALSE },
02440        { /* opt_KeySize             */  'g', PR_TRUE,  0, PR_FALSE },
02441        { /* opt_TokenName           */  'h', PR_TRUE,  0, PR_FALSE },
02442        { /* opt_InputFile           */  'i', PR_TRUE,  0, PR_FALSE },
02443        { /* opt_KeyIndex            */  'j', PR_TRUE,  0, PR_FALSE },
02444        { /* opt_KeyType             */  'k', PR_TRUE,  0, PR_FALSE },
02445        { /* opt_DetailedInfo        */  'l', PR_FALSE, 0, PR_FALSE },
02446        { /* opt_SerialNumber        */  'm', PR_TRUE,  0, PR_FALSE },
02447        { /* opt_Nickname            */  'n', PR_TRUE,  0, PR_FALSE },
02448        { /* opt_OutputFile          */  'o', PR_TRUE,  0, PR_FALSE },
02449        { /* opt_PhoneNumber         */  'p', PR_TRUE,  0, PR_FALSE },
02450        { /* opt_DBPrefix            */  'P', PR_TRUE,  0, PR_FALSE },
02451        { /* opt_PQGFile             */  'q', PR_TRUE,  0, PR_FALSE },
02452        { /* opt_BinaryDER           */  'r', PR_FALSE, 0, PR_FALSE },
02453        { /* opt_Subject             */  's', PR_TRUE,  0, PR_FALSE },
02454        { /* opt_Trust               */  't', PR_TRUE,  0, PR_FALSE },
02455        { /* opt_Usage               */  'u', PR_TRUE,  0, PR_FALSE },
02456        { /* opt_Validity            */  'v', PR_TRUE,  0, PR_FALSE },
02457        { /* opt_OffsetMonths        */  'w', PR_TRUE,  0, PR_FALSE },
02458        { /* opt_SelfSign            */  'x', PR_FALSE, 0, PR_FALSE },
02459        { /* opt_RW                  */  'X', PR_FALSE, 0, PR_FALSE },
02460        { /* opt_Exponent            */  'y', PR_TRUE,  0, PR_FALSE },
02461        { /* opt_NoiseFile           */  'z', PR_TRUE,  0, PR_FALSE },
02462        { /* opt_Hash                */  'Z', PR_TRUE,  0, PR_FALSE }
02463 };
02464 
02465 
02466     certutil.numCommands = sizeof(certutil_commands) / sizeof(secuCommandFlag);
02467     certutil.numOptions = sizeof(certutil_options) / sizeof(secuCommandFlag);
02468     certutil.commands = certutil_commands;
02469     certutil.options = certutil_options;
02470 
02471     progName = PORT_Strrchr(argv[0], '/');
02472     progName = progName ? progName+1 : argv[0];
02473 
02474     rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
02475 
02476     if (rv != SECSuccess)
02477        Usage(progName);
02478 
02479     if (certutil.commands[cmd_PrintHelp].activated)
02480        LongUsage(progName);
02481 
02482     if (certutil.options[opt_PasswordFile].arg) {
02483        pwdata.source = PW_FROMFILE;
02484        pwdata.data = certutil.options[opt_PasswordFile].arg;
02485     }
02486 
02487     if (certutil.options[opt_CertDir].activated)
02488        SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
02489 
02490     if (certutil.options[opt_KeySize].activated) {
02491        keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
02492        if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
02493            PR_fprintf(PR_STDERR, 
02494                        "%s -g:  Keysize must be between %d and %d.\n",
02495                      progName, MIN_KEY_BITS, MAX_KEY_BITS);
02496            return 255;
02497        }
02498 #ifdef NSS_ENABLE_ECC
02499        if (keytype == ecKey) {
02500            PR_fprintf(PR_STDERR, "%s -g:  Not for ec keys.\n", progName);
02501            return 255;
02502        }
02503 #endif /* NSS_ENABLE_ECC */
02504 
02505     }
02506 
02507     /*  -h specify token name  */
02508     if (certutil.options[opt_TokenName].activated) {
02509        if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
02510            slotname = NULL;
02511        else
02512            slotname = PL_strdup(certutil.options[opt_TokenName].arg);
02513     }
02514 
02515     /*  -Z hash type  */
02516     if (certutil.options[opt_Hash].activated) {
02517        char * arg = certutil.options[opt_Hash].arg;
02518         hashAlgTag = SECU_StringToSignatureAlgTag(arg);
02519         if (hashAlgTag == SEC_OID_UNKNOWN) {
02520            PR_fprintf(PR_STDERR, "%s -Z:  %s is not a recognized type.\n",
02521                       progName, arg);
02522            return 255;
02523        }
02524     }
02525 
02526     /*  -k key type  */
02527     if (certutil.options[opt_KeyType].activated) {
02528        char * arg = certutil.options[opt_KeyType].arg;
02529        if (PL_strcmp(arg, "rsa") == 0) {
02530            keytype = rsaKey;
02531        } else if (PL_strcmp(arg, "dsa") == 0) {
02532            keytype = dsaKey;
02533 #ifdef NSS_ENABLE_ECC
02534        } else if (PL_strcmp(arg, "ec") == 0) {
02535            keytype = ecKey;
02536 #endif /* NSS_ENABLE_ECC */
02537        } else if (PL_strcmp(arg, "all") == 0) {
02538            keytype = nullKey;
02539        } else {
02540            PR_fprintf(PR_STDERR, "%s -k:  %s is not a recognized type.\n",
02541                       progName, arg);
02542            return 255;
02543        }
02544     }
02545 
02546     /*  -m serial number */
02547     if (certutil.options[opt_SerialNumber].activated) {
02548        int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
02549        if (sn < 0) {
02550            PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
02551                       progName, certutil.options[opt_SerialNumber].arg);
02552            return 255;
02553        }
02554        serialNumber = sn;
02555     }
02556 
02557     /*  -P certdb name prefix */
02558     if (certutil.options[opt_DBPrefix].activated) {
02559         if (certutil.options[opt_DBPrefix].arg) {
02560             certPrefix = strdup(certutil.options[opt_DBPrefix].arg);
02561         } else {
02562             Usage(progName);
02563         }
02564     }
02565 
02566     /*  -q PQG file or curve name */
02567     if (certutil.options[opt_PQGFile].activated) {
02568 #ifdef NSS_ENABLE_ECC
02569        if ((keytype != dsaKey) && (keytype != ecKey)) {
02570            PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys" \
02571                      " (-k dsa) or a named curve for EC keys (-k ec)\n)",
02572                       progName);
02573 #else
02574        if (keytype != dsaKey) {
02575            PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)",
02576                       progName);
02577 #endif /* NSS_ENABLE_ECC */
02578            return 255;
02579        }
02580     }
02581 
02582     /*  -s subject name  */
02583     if (certutil.options[opt_Subject].activated) {
02584        subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
02585        if (!subject) {
02586            PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
02587                       progName, certutil.options[opt_Subject].arg);
02588            return 255;
02589        }
02590     }
02591 
02592     /*  -v validity period  */
02593     if (certutil.options[opt_Validity].activated) {
02594        validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
02595        if (validityMonths < 0) {
02596            PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
02597                       progName, certutil.options[opt_Validity].arg);
02598            return 255;
02599        }
02600     }
02601 
02602     /*  -w warp months  */
02603     if (certutil.options[opt_OffsetMonths].activated)
02604        warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
02605 
02606     /*  -y public exponent (for RSA)  */
02607     if (certutil.options[opt_Exponent].activated) {
02608        publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
02609        if ((publicExponent != 3) &&
02610            (publicExponent != 17) &&
02611            (publicExponent != 65537)) {
02612            PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.", 
02613                                   progName, publicExponent);
02614            PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
02615            return 255;
02616        }
02617     }
02618 
02619     /*  Check number of commands entered.  */
02620     commandsEntered = 0;
02621     for (i=0; i< certutil.numCommands; i++) {
02622        if (certutil.commands[i].activated) {
02623            commandToRun = certutil.commands[i].flag;
02624            commandsEntered++;
02625        }
02626        if (commandsEntered > 1)
02627            break;
02628     }
02629     if (commandsEntered > 1) {
02630        PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
02631        PR_fprintf(PR_STDERR, "You entered: ");
02632        for (i=0; i< certutil.numCommands; i++) {
02633            if (certutil.commands[i].activated)
02634               PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
02635        }
02636        PR_fprintf(PR_STDERR, "\n");
02637        return 255;
02638     }
02639     if (commandsEntered == 0) {
02640        PR_fprintf(PR_STDERR, "%s: you must enter a command!\n", progName);
02641        Usage(progName);
02642     }
02643 
02644     if (certutil.commands[cmd_ListCerts].activated ||
02645          certutil.commands[cmd_PrintHelp].activated ||
02646          certutil.commands[cmd_ListKeys].activated ||
02647          certutil.commands[cmd_ListModules].activated ||
02648          certutil.commands[cmd_CheckCertValidity].activated ||
02649          certutil.commands[cmd_Version].activated ) {
02650        readOnly = !certutil.options[opt_RW].activated;
02651     }
02652 
02653     /*  -A, -D, -F, -M, -S, -V, and all require -n  */
02654     if ((certutil.commands[cmd_AddCert].activated ||
02655          certutil.commands[cmd_DeleteCert].activated ||
02656          certutil.commands[cmd_DeleteKey].activated ||
02657         certutil.commands[cmd_DumpChain].activated ||
02658          certutil.commands[cmd_ModifyCertTrust].activated ||
02659          certutil.commands[cmd_CreateAndAddCert].activated ||
02660          certutil.commands[cmd_CheckCertValidity].activated) &&
02661         !certutil.options[opt_Nickname].activated) {
02662        PR_fprintf(PR_STDERR, 
02663                  "%s -%c: nickname is required for this command (-n).\n",
02664                   progName, commandToRun);
02665        return 255;
02666     }
02667 
02668     /*  -A, -E, -M, -S require trust  */
02669     if ((certutil.commands[cmd_AddCert].activated ||
02670          certutil.commands[cmd_AddEmailCert].activated ||
02671          certutil.commands[cmd_ModifyCertTrust].activated ||
02672          certutil.commands[cmd_CreateAndAddCert].activated) &&
02673         !certutil.options[opt_Trust].activated) {
02674        PR_fprintf(PR_STDERR, 
02675                  "%s -%c: trust is required for this command (-t).\n",
02676                   progName, commandToRun);
02677        return 255;
02678     }
02679 
02680     /*  if -L is given raw or ascii mode, it must be for only one cert.  */
02681     if (certutil.commands[cmd_ListCerts].activated &&
02682         (certutil.options[opt_ASCIIForIO].activated ||
02683          certutil.options[opt_BinaryDER].activated) &&
02684         !certutil.options[opt_Nickname].activated) {
02685        PR_fprintf(PR_STDERR, 
02686                "%s: nickname is required to dump cert in raw or ascii mode.\n",
02687                   progName);
02688        return 255;
02689     }
02690     
02691     /*  -L can only be in (raw || ascii).  */
02692     if (certutil.commands[cmd_ListCerts].activated &&
02693         certutil.options[opt_ASCIIForIO].activated &&
02694         certutil.options[opt_BinaryDER].activated) {
02695        PR_fprintf(PR_STDERR, 
02696                   "%s: cannot specify both -r and -a when dumping cert.\n",
02697                   progName);
02698        return 255;
02699     }
02700 
02701     /*  For now, deny -C -x combination */
02702     if (certutil.commands[cmd_CreateNewCert].activated &&
02703         certutil.options[opt_SelfSign].activated) {
02704        PR_fprintf(PR_STDERR,
02705                   "%s: self-signing a cert request is not supported.\n",
02706                   progName);
02707        return 255;
02708     }
02709 
02710     /*  If making a cert request, need a subject.  */
02711     if ((certutil.commands[cmd_CertReq].activated ||
02712          certutil.commands[cmd_CreateAndAddCert].activated) &&
02713         !certutil.options[opt_Subject].activated) {
02714        PR_fprintf(PR_STDERR, 
02715                   "%s -%c: subject is required to create a cert request.\n",
02716                   progName, commandToRun);
02717        return 255;
02718     }
02719 
02720     /*  If making a cert, need a serial number.  */
02721     if ((certutil.commands[cmd_CreateNewCert].activated ||
02722          certutil.commands[cmd_CreateAndAddCert].activated) &&
02723          !certutil.options[opt_SerialNumber].activated) {
02724        /*  Make a default serial number from the current time.  */
02725        PRTime now = PR_Now();
02726        LL_USHR(now, now, 19);
02727        LL_L2UI(serialNumber, now);
02728     }
02729 
02730     /*  Validation needs the usage to validate for.  */
02731     if (certutil.commands[cmd_CheckCertValidity].activated &&
02732         !certutil.options[opt_Usage].activated) {
02733        PR_fprintf(PR_STDERR, 
02734                   "%s -V: specify a usage to validate the cert for (-u).\n",
02735                   progName);
02736        return 255;
02737     }
02738     
02739     /*  To make a cert, need either a issuer or to self-sign it.  */
02740     if (certutil.commands[cmd_CreateAndAddCert].activated &&
02741        !(certutil.options[opt_IssuerName].activated ||
02742           certutil.options[opt_SelfSign].activated)) {
02743        PR_fprintf(PR_STDERR,
02744                   "%s -S: must specify issuer (-c) or self-sign (-x).\n",
02745                   progName);
02746        return 255;
02747     }
02748 
02749     /*  Using slotname == NULL for listing keys and certs on all slots, 
02750      *  but only that. */
02751     if (!(certutil.commands[cmd_ListKeys].activated ||
02752          certutil.commands[cmd_DumpChain].activated ||
02753          certutil.commands[cmd_ListCerts].activated) && slotname == NULL) {
02754        PR_fprintf(PR_STDERR,
02755                   "%s -%c: cannot use \"-h all\" for this command.\n",
02756                   progName, commandToRun);
02757        return 255;
02758     }
02759 
02760     /*  Using keytype == nullKey for list all key types, but only that.  */
02761     if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
02762        PR_fprintf(PR_STDERR,
02763                   "%s -%c: cannot use \"-k all\" for this command.\n",
02764                   progName, commandToRun);
02765        return 255;
02766     }
02767 
02768     /*  -S  open outFile, temporary file for cert request.  */
02769     if (certutil.commands[cmd_CreateAndAddCert].activated) {
02770        outFile = PR_Open(certreqfile, PR_RDWR | PR_CREATE_FILE, 00660);
02771        if (!outFile) {
02772            PR_fprintf(PR_STDERR, 
02773                      "%s -o: unable to open \"%s\" for writing (%ld, %ld)\n",
02774                      progName, certreqfile,
02775                      PR_GetError(), PR_GetOSError());
02776            return 255;
02777        }
02778     }
02779 
02780     /*  Open the input file.  */
02781     if (certutil.options[opt_InputFile].activated) {
02782        inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
02783        if (!inFile) {
02784            PR_fprintf(PR_STDERR,
02785                       "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
02786                       progName, certutil.options[opt_InputFile].arg,
02787                       PR_GetError(), PR_GetOSError());
02788            return 255;
02789        }
02790     }
02791 
02792     /*  Open the output file.  */
02793     if (certutil.options[opt_OutputFile].activated && !outFile) {
02794        outFile = PR_Open(certutil.options[opt_OutputFile].arg, 
02795                           PR_CREATE_FILE | PR_RDWR, 00660);
02796        if (!outFile) {
02797            PR_fprintf(PR_STDERR,
02798                       "%s:  unable to open \"%s\" for writing (%ld, %ld).\n",
02799                       progName, certutil.options[opt_OutputFile].arg,
02800                       PR_GetError(), PR_GetOSError());
02801            return 255;
02802        }
02803     }
02804 
02805     name = SECU_GetOptionArg(&certutil, opt_Nickname);
02806 
02807     PK11_SetPasswordFunc(SECU_GetModulePassword);
02808 
02809     if (PR_TRUE == initialize) {
02810         /*  Initialize NSPR and NSS.  */
02811         PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
02812         rv = NSS_Initialize(SECU_ConfigDirectory(NULL), certPrefix, certPrefix,
02813                             "secmod.db", readOnly ? NSS_INIT_READONLY: 0);
02814         if (rv != SECSuccess) {
02815            SECU_PrintPRandOSError(progName);
02816            rv = SECFailure;
02817            goto shutdown;
02818         }
02819         initialized = PR_TRUE;
02820        SECU_RegisterDynamicOids();
02821     }
02822     certHandle = CERT_GetDefaultCertDB();
02823 
02824     if (certutil.commands[cmd_Version].activated) {
02825        printf("Certificate database content version: command not implemented.\n");
02826     }
02827 
02828     if (PL_strcmp(slotname, "internal") == 0)
02829        slot = PK11_GetInternalKeySlot();
02830     else if (slotname != NULL)
02831        slot = PK11_FindSlotByName(slotname);
02832    
02833     if ( !slot && (certutil.commands[cmd_NewDBs].activated ||
02834          certutil.commands[cmd_ModifyCertTrust].activated  || 
02835          certutil.commands[cmd_ChangePassword].activated   ||
02836          certutil.commands[cmd_TokenReset].activated       ||
02837          certutil.commands[cmd_CreateAndAddCert].activated ||
02838          certutil.commands[cmd_AddCert].activated          ||
02839          certutil.commands[cmd_AddEmailCert].activated)) {
02840       
02841          SECU_PrintError(progName, "could not find the slot %s",slotname);
02842          rv = SECFailure;
02843          goto shutdown;
02844     }
02845 
02846 
02847 
02848     /*  If creating new database, initialize the password.  */
02849     if (certutil.commands[cmd_NewDBs].activated) {
02850        SECU_ChangePW(slot, 0, certutil.options[opt_PasswordFile].arg);
02851     }
02852 
02853     /* The following 8 options are mutually exclusive with all others. */
02854 
02855     /*  List certs (-L)  */
02856     if (certutil.commands[cmd_ListCerts].activated) {
02857        rv = ListCerts(certHandle, name, slot,
02858                       certutil.options[opt_BinaryDER].activated,
02859                       certutil.options[opt_ASCIIForIO].activated, 
02860                        (outFile) ? outFile : PR_STDOUT, &pwdata);
02861        goto shutdown;
02862     }
02863     if (certutil.commands[cmd_DumpChain].activated) {
02864        rv = DumpChain(certHandle, name);
02865        goto shutdown;
02866     }
02867     /*  XXX needs work  */
02868     /*  List keys (-K)  */
02869     if (certutil.commands[cmd_ListKeys].activated) {
02870        rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
02871                      &pwdata);
02872        goto shutdown;
02873     }
02874     /*  List modules (-U)  */
02875     if (certutil.commands[cmd_ListModules].activated) {
02876        rv = ListModules();
02877        goto shutdown;
02878     }
02879     /*  Delete cert (-D)  */
02880     if (certutil.commands[cmd_DeleteCert].activated) {
02881        rv = DeleteCert(certHandle, name);
02882        goto shutdown;
02883     }
02884     /*  Delete key (-F)  */
02885     if (certutil.commands[cmd_DeleteKey].activated) {
02886        rv = DeleteKey(name, &pwdata);
02887        goto shutdown;
02888     }
02889     /*  Modify trust attribute for cert (-M)  */
02890     if (certutil.commands[cmd_ModifyCertTrust].activated) {
02891        rv = ChangeTrustAttributes(certHandle, name, 
02892                                   certutil.options[opt_Trust].arg);
02893        goto shutdown;
02894     }
02895     /*  Change key db password (-W) (future - change pw to slot?)  */
02896     if (certutil.commands[cmd_ChangePassword].activated) {
02897        rv = SECU_ChangePW(slot, 0, certutil.options[opt_PasswordFile].arg);
02898        goto shutdown;
02899     }
02900     /*  Reset the a token */
02901     if (certutil.commands[cmd_TokenReset].activated) {
02902        char *sso_pass = "";
02903 
02904        if (certutil.options[opt_SSOPass].activated) {
02905            sso_pass = certutil.options[opt_SSOPass].arg;
02906        }
02907        rv = PK11_ResetToken(slot,sso_pass);
02908 
02909        goto shutdown;
02910     }
02911     /*  Check cert validity against current time (-V)  */
02912     if (certutil.commands[cmd_CheckCertValidity].activated) {
02913        /* XXX temporary hack for fips - must log in to get priv key */
02914        if (certutil.options[opt_VerifySig].activated) {
02915            if (slot && PK11_NeedLogin(slot))
02916               PK11_Authenticate(slot, PR_TRUE, &pwdata);
02917        }
02918        rv = ValidateCert(certHandle, name, 
02919                          certutil.options[opt_ValidityTime].arg,
02920                        certutil.options[opt_Usage].arg,
02921                        certutil.options[opt_VerifySig].activated,
02922                        certutil.options[opt_DetailedInfo].activated,
02923                          &pwdata);
02924        goto shutdown;
02925     }
02926 
02927     /*
02928      *  Key generation
02929      */
02930 
02931     /*  These commands require keygen.  */
02932     if (certutil.commands[cmd_CertReq].activated ||
02933         certutil.commands[cmd_CreateAndAddCert].activated ||
02934        certutil.commands[cmd_GenKeyPair].activated) {
02935        /*  XXX Give it a nickname.  */
02936        privkey = 
02937            CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
02938                                        publicExponent, 
02939                                        certutil.options[opt_NoiseFile].arg,
02940                                        &pubkey, 
02941                                        certutil.options[opt_PQGFile].arg,
02942                                        &pwdata);
02943        if (privkey == NULL) {
02944            SECU_PrintError(progName, "unable to generate key(s)\n");
02945            rv = SECFailure;
02946            goto shutdown;
02947        }
02948        privkey->wincx = &pwdata;
02949        PORT_Assert(pubkey != NULL);
02950 
02951        /*  If all that was needed was keygen, exit.  */
02952        if (certutil.commands[cmd_GenKeyPair].activated) {
02953            rv = SECSuccess;
02954            goto shutdown;
02955        }
02956     }
02957 
02958     /*
02959      *  Certificate request
02960      */
02961 
02962     /*  Make a cert request (-R).  */
02963     if (certutil.commands[cmd_CertReq].activated) {
02964        rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
02965                     certutil.options[opt_PhoneNumber].arg,
02966                     certutil.options[opt_ASCIIForIO].activated,
02967                    certutil.options[opt_ExtendedEmailAddrs].arg,
02968                    certutil.options[opt_ExtendedDNSNames].arg,
02969                      certutil.options[opt_AddKeyUsageExt].activated,
02970                      certutil.options[opt_AddExtKeyUsageExt].activated,
02971                      certutil.options[opt_AddBasicConstraintExt].activated,
02972                      certutil.options[opt_AddAuthorityKeyIDExt].activated,
02973                      certutil.options[opt_AddCRLDistPtsExt].activated,
02974                      certutil.options[opt_AddNSCertTypeExt].activated,
02975                      outFile ? outFile : PR_STDOUT);
02976        if (rv) 
02977            goto shutdown;
02978        privkey->wincx = &pwdata;
02979     }
02980 
02981     /*
02982      *  Certificate creation
02983      */
02984 
02985     /*  If making and adding a cert, create a cert request file first without
02986      *  any extensions, then load it with the command line extensions
02987      *  and output the cert to another file.
02988      */
02989     if (certutil.commands[cmd_CreateAndAddCert].activated) {
02990        rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
02991                     certutil.options[opt_PhoneNumber].arg,
02992                     certutil.options[opt_ASCIIForIO].activated,
02993                    NULL,
02994                    NULL,
02995                      PR_FALSE,
02996                      PR_FALSE,
02997                      PR_FALSE,
02998                      PR_FALSE,
02999                      PR_FALSE,
03000                      PR_FALSE,
03001                      outFile ? outFile : PR_STDOUT);
03002        if (rv) 
03003            goto shutdown;
03004        privkey->wincx = &pwdata;
03005        PR_Close(outFile);
03006        inFile  = PR_Open(certreqfile, PR_RDONLY, 0);
03007        if (!inFile) {
03008            PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
03009                        certreqfile, PR_GetError(), PR_GetOSError());
03010            rv = SECFailure;
03011            goto shutdown;
03012        }
03013        outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE, 00660);
03014        if (!outFile) {
03015            PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
03016                        certfile, PR_GetError(), PR_GetOSError());
03017            rv = SECFailure;
03018            goto shutdown;
03019        }
03020     }
03021 
03022     /*  Create a certificate (-C or -S).  */
03023     if (certutil.commands[cmd_CreateAndAddCert].activated ||
03024          certutil.commands[cmd_CreateNewCert].activated) {
03025        rv = CreateCert(certHandle, 
03026                        certutil.options[opt_IssuerName].arg,
03027                        inFile, outFile, privkey, &pwdata, hashAlgTag,
03028                        serialNumber, warpmonths, validityMonths,
03029                       certutil.options[opt_ExtendedEmailAddrs].arg,
03030                       certutil.options[opt_ExtendedDNSNames].arg,
03031                        certutil.options[opt_ASCIIForIO].activated,
03032                        certutil.options[opt_SelfSign].activated,
03033                        certutil.options[opt_AddKeyUsageExt].activated,
03034                        certutil.options[opt_AddExtKeyUsageExt].activated,
03035                        certutil.options[opt_AddBasicConstraintExt].activated,
03036                        certutil.options[opt_AddAuthorityKeyIDExt].activated,
03037                        certutil.options[opt_AddCRLDistPtsExt].activated,
03038                        certutil.options[opt_AddNSCertTypeExt].activated);
03039        if (rv) 
03040            goto shutdown;
03041     }
03042 
03043     /* 
03044      * Adding a cert to the database (or slot)
03045      */
03046  
03047     if (certutil.commands[cmd_CreateAndAddCert].activated) { 
03048        PORT_Assert(inFile != PR_STDIN);
03049        PR_Close(inFile);
03050        PR_Close(outFile);
03051        inFile = PR_Open(certfile, PR_RDONLY, 0);
03052        if (!inFile) {
03053            PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
03054                        certfile, PR_GetError(), PR_GetOSError());
03055            rv = SECFailure;
03056            goto shutdown;
03057        }
03058     }
03059 
03060     /* -A -E or -S    Add the cert to the DB */
03061     if (certutil.commands[cmd_CreateAndAddCert].activated ||
03062          certutil.commands[cmd_AddCert].activated ||
03063         certutil.commands[cmd_AddEmailCert].activated) {
03064        rv = AddCert(slot, certHandle, name, 
03065                     certutil.options[opt_Trust].arg,
03066                     inFile, 
03067                     certutil.options[opt_ASCIIForIO].activated,
03068                     certutil.commands[cmd_AddEmailCert].activated,&pwdata);
03069        if (rv) 
03070            goto shutdown;
03071     }
03072 
03073     if (certutil.commands[cmd_CreateAndAddCert].activated) {
03074        PORT_Assert(inFile != PR_STDIN);
03075        PR_Close(inFile);
03076        PR_Delete(certfile);
03077        PR_Delete(certreqfile);
03078     }
03079 
03080 shutdown:
03081     if (slot) {
03082        PK11_FreeSlot(slot);
03083     }
03084     if (privkey) {
03085        SECKEY_DestroyPrivateKey(privkey);
03086     }
03087     if (pubkey) {
03088        SECKEY_DestroyPublicKey(pubkey);
03089     }
03090 
03091     /* Open the batch command file.
03092      *
03093      * - If -B <command line> option is specified, the contents in the
03094      * command file will be interpreted as subsequent certutil
03095      * commands to be executed in the current certutil process
03096      * context after the current certutil command has been executed.
03097      * - Each line in the command file consists of the command
03098      * line arguments for certutil.
03099      * - The -d <configdir> option will be ignored if specified in the
03100      * command file.
03101      * - Quoting with double quote characters ("...") is supported
03102      * to allow white space in a command line argument.  The
03103      * double quote character cannot be escaped and quoting cannot
03104      * be nested in this version.
03105      * - each line in the batch file is limited to 512 characters
03106     */
03107 
03108     if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
03109        FILE* batchFile = NULL;
03110         char nextcommand[512];
03111         if (!certutil.options[opt_InputFile].activated ||
03112             !certutil.options[opt_InputFile].arg) {
03113            PR_fprintf(PR_STDERR,
03114                       "%s:  no batch input file specified.\n",
03115                       progName);
03116            return 255;
03117         }
03118         batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
03119         if (!batchFile) {
03120            PR_fprintf(PR_STDERR,
03121                       "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
03122                       progName, certutil.options[opt_InputFile].arg,
03123                       PR_GetError(), PR_GetOSError());
03124            return 255;
03125         }
03126         /* read and execute command-lines in a loop */
03127         while ( (SECSuccess == rv ) &&
03128                 fgets(nextcommand, sizeof(nextcommand), batchFile)) {
03129             /* we now need to split the command into argc / argv format */
03130             char* commandline = PORT_Strdup(nextcommand);
03131             PRBool invalid = PR_FALSE;
03132             int newargc = 2;
03133             char* space = NULL;
03134             char* nextarg = NULL;
03135             char** newargv = NULL;
03136             char* crlf = PORT_Strrchr(commandline, '\n');
03137             if (crlf) {
03138                 *crlf = '\0';
03139             }
03140 
03141             newargv = PORT_Alloc(sizeof(char*)*(newargc+1));
03142             newargv[0] = progName;
03143             newargv[1] = commandline;
03144             nextarg = commandline;
03145             while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v")) ) {
03146                 while (isspace(*space) ) {
03147                     *space = '\0';
03148                     space ++;
03149                 }
03150                 if (*space == '\0') {
03151                     break;
03152                 } else if (*space != '\"') {
03153                     nextarg = space;
03154                 } else {
03155                     char* closingquote = strchr(space+1, '\"');
03156                     if (closingquote) {
03157                         *closingquote = '\0';
03158                         space++;
03159                         nextarg = closingquote+1;
03160                     } else {
03161                         invalid = PR_TRUE;
03162                         nextarg = space;
03163                     }
03164                 }
03165                 newargc++;
03166                 newargv = PORT_Realloc(newargv, sizeof(char*)*(newargc+1));
03167                 newargv[newargc-1] = space;
03168             }
03169             newargv[newargc] = NULL;
03170             
03171             /* invoke next command */
03172             if (PR_TRUE == invalid) {
03173                 PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
03174                            nextcommand);
03175                 rv = SECFailure;
03176             } else {
03177                 if (0 != certutil_main(newargc, newargv, PR_FALSE) )
03178                     rv = SECFailure;
03179             }
03180             PORT_Free(newargv);
03181             PORT_Free(commandline);
03182         }
03183         fclose(batchFile);
03184     }
03185 
03186     if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
03187         exit(1);
03188     }
03189 
03190     if (rv == SECSuccess) {
03191        return 0;
03192     } else {
03193        return 255;
03194     }
03195 }
03196 
03197 int
03198 main(int argc, char **argv)
03199 {
03200     return certutil_main(argc, argv, PR_TRUE);
03201 }