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 "%-15s Run a series of certutil commands from a batch file\n", "-B");
01050     FPS "%-20s Specify the batch file\n", "   -i batch-file");
01051     FPS "%-15s Add an Email certificate to the database (create if needed)\n",
01052        "-E");
01053     FPS "%-20s Specify the nickname of the certificate to add\n",
01054        "   -n cert-name");
01055     FPS "%-20s Set the certificate trust attributes:\n",
01056        "   -t trustargs");
01057     FPS "%-25s p \t valid peer\n", "");
01058     FPS "%-25s P \t trusted peer (implies p)\n", "");
01059     FPS "%-25s c \t valid CA\n", "");
01060     FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", "");
01061     FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", "");
01062     FPS "%-25s u \t user cert\n", "");
01063     FPS "%-25s w \t send warning\n", "");
01064     FPS "%-25s g \t make step-up cert\n", "");
01065     FPS "%-20s Specify the password file\n",
01066        "   -f pwfile");
01067     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01068        "   -d certdir");
01069     FPS "%-20s Cert & Key database prefix\n",
01070        "   -P dbprefix");
01071     FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n",
01072        "   -a");
01073     FPS "%-20s Specify the certificate file (default is stdin)\n",
01074        "   -i input");
01075     FPS "\n");
01076 
01077     FPS "%-15s Create a new binary certificate from a BINARY cert request\n",
01078        "-C");
01079     FPS "%-20s The nickname of the issuer cert\n",
01080        "   -c issuer-name");
01081     FPS "%-20s The BINARY certificate request file\n",
01082        "   -i cert-request ");
01083     FPS "%-20s Output binary cert to this file (default is stdout)\n",
01084        "   -o output-cert");
01085     FPS "%-20s Self sign\n",
01086        "   -x");
01087     FPS "%-20s Cert serial number\n",
01088        "   -m serial-number");
01089     FPS "%-20s Time Warp\n",
01090        "   -w warp-months");
01091     FPS "%-20s Months valid (default is 3)\n",
01092         "   -v months-valid");
01093     FPS "%-20s Specify the password file\n",
01094        "   -f pwfile");
01095     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01096        "   -d certdir");
01097     FPS "%-20s Cert & Key database prefix\n",
01098        "   -P dbprefix");
01099     FPS "%-20s Create key usage extension\n",
01100        "   -1 ");
01101     FPS "%-20s Create basic constraint extension\n",
01102        "   -2 ");
01103     FPS "%-20s Create authority key ID extension\n",
01104        "   -3 ");
01105     FPS "%-20s Create crl distribution point extension\n",
01106        "   -4 ");
01107     FPS "%-20s Create netscape cert type extension\n",
01108        "   -5 ");
01109     FPS "%-20s Create extended key usage extension\n",
01110        "   -6 ");
01111     FPS "%-20s Create an email subject alt name extension\n",
01112        "   -7 ");
01113     FPS "%-20s Create an dns subject alt name extension\n",
01114        "   -8 ");
01115     FPS "\n");
01116 
01117     FPS "%-15s Generate a new key pair\n",
01118        "-G");
01119     FPS "%-20s Name of token in which to generate key (default is internal)\n",
01120        "   -h token-name");
01121 #ifdef NSS_ENABLE_ECC
01122     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
01123        "   -k key-type");
01124     FPS "%-20s Key size in bits, (min %d, max %d, default %d) (not for ec)\n",
01125        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01126 #else
01127     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
01128        "   -k key-type");
01129     FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n",
01130        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01131 #endif /* NSS_ENABLE_ECC */
01132     FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n",
01133        "   -y exp");
01134     FPS "%-20s Specify the password file\n",
01135         "   -f password-file");
01136     FPS "%-20s Specify the noise file to be used\n",
01137        "   -z noisefile");
01138     FPS "%-20s read PQG value from pqgfile (dsa only)\n",
01139        "   -q pqgfile");
01140 #ifdef NSS_ENABLE_ECC
01141     FPS "%-20s Elliptic curve name (ec only)\n",
01142        "   -q curve-name");
01143     FPS "%-20s One of sect163k1, nistk163, sect163r1, sect163r2,\n", "");
01144     FPS "%-20s nistb163, sect193r1, sect193r2, sect233k1, nistk233,\n", "");
01145     FPS "%-20s sect233r1, nistb233, sect239k1, sect283k1, nistk283,\n", "");
01146     FPS "%-20s sect283r1, nistb283, sect409k1, nistk409, sect409r1,\n", "");
01147     FPS "%-20s nistb409, sect571k1, nistk571, sect571r1, nistb571,\n", "");
01148     FPS "%-20s secp160k1, secp160r1, secp160r2, secp192k1, secp192r1,\n", "");
01149     FPS "%-20s nistp192, secp224k1, secp224r1, nistp224, secp256k1,\n", "");
01150     FPS "%-20s secp256r1, nistp256, secp384r1, nistp384, secp521r1,\n", "");
01151     FPS "%-20s nistp521, prime192v1, prime192v2, prime192v3, \n", "");
01152     FPS "%-20s prime239v1, prime239v2, prime239v3, c2pnb163v1, \n", "");
01153     FPS "%-20s c2pnb163v2, c2pnb163v3, c2pnb176v1, c2tnb191v1, \n", "");
01154     FPS "%-20s c2tnb191v2, c2tnb191v3, c2onb191v4, c2onb191v5, \n", "");
01155     FPS "%-20s c2pnb208w1, c2tnb239v1, c2tnb239v2, c2tnb239v3, \n", "");
01156     FPS "%-20s c2onb239v4, c2onb239v5, c2pnb272w1, c2pnb304w1, \n", "");
01157     FPS "%-20s c2tnb359w1, c2pnb368w1, c2tnb431r1, secp112r1, \n", "");
01158     FPS "%-20s secp112r2, secp128r1, secp128r2, sect113r1, sect113r2\n", "");
01159     FPS "%-20s sect131r1, sect131r2\n", "");
01160 #endif
01161     FPS "%-20s Key database directory (default is ~/.netscape)\n",
01162        "   -d keydir");
01163     FPS "%-20s Cert & Key database prefix\n",
01164        "   -P dbprefix");
01165     FPS "\n");
01166 
01167     FPS "%-15s Delete a certificate from the database\n",
01168        "-D");
01169     FPS "%-20s The nickname of the cert to delete\n",
01170        "   -n cert-name");
01171     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01172        "   -d certdir");
01173     FPS "%-20s Cert & Key database prefix\n",
01174        "   -P dbprefix");
01175     FPS "\n");
01176 
01177     FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/
01178         "-U");
01179     FPS "%-20s Module database directory (default is '~/.netscape')\n",
01180         "   -d moddir");
01181     FPS "%-20s Cert & Key database prefix\n",
01182        "   -P dbprefix");
01183     FPS "%-20s force the database to open R/W\n",
01184        "   -X");
01185     FPS "\n");
01186 
01187     FPS "%-15s List all keys\n", /*, or print out a single named key\n",*/
01188         "-K");
01189     FPS "%-20s Name of token in which to look for keys (default is internal,"
01190        " use \"all\" to list keys on all tokens)\n",
01191        "   -h token-name ");
01192 #ifdef NSS_ENABLE_ECC
01193     FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"ec\", \"rsa\" (default))\n",
01194        "   -k key-type");
01195 #else
01196     FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"rsa\" (default))\n",
01197        "   -k key-type");
01198 #endif
01199     FPS "%-20s Specify the password file\n",
01200         "   -f password-file");
01201     FPS "%-20s Key database directory (default is ~/.netscape)\n",
01202        "   -d keydir");
01203     FPS "%-20s Cert & Key database prefix\n",
01204        "   -P dbprefix");
01205     FPS "%-20s force the database to open R/W\n",
01206        "   -X");
01207     FPS "\n");
01208 
01209     FPS "%-15s List all certs, or print out a single named cert\n",
01210        "-L");
01211     FPS "%-20s Pretty print named cert (list all if unspecified)\n",
01212        "   -n cert-name");
01213     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01214        "   -d certdir");
01215     FPS "%-20s Cert & Key database prefix\n",
01216        "   -P dbprefix");
01217     FPS "%-20s force the database to open R/W\n",
01218        "   -X");
01219     FPS "%-20s For single cert, print binary DER encoding\n",
01220        "   -r");
01221     FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n",
01222        "   -a");
01223     FPS "\n");
01224 
01225     FPS "%-15s Modify trust attributes of certificate\n",
01226        "-M");
01227     FPS "%-20s The nickname of the cert to modify\n",
01228        "   -n cert-name");
01229     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
01230        "   -t trustargs");
01231     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01232        "   -d certdir");
01233     FPS "%-20s Cert & Key database prefix\n",
01234        "   -P dbprefix");
01235     FPS "\n");
01236 
01237     FPS "%-15s Create a new certificate database\n",
01238        "-N");
01239     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01240        "   -d certdir");
01241     FPS "%-20s Cert & Key database prefix\n",
01242        "   -P dbprefix");
01243     FPS "\n");
01244     FPS "%-15s Reset the Key database or token\n",
01245        "-T");
01246     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01247        "   -d certdir");
01248     FPS "%-20s Cert & Key database prefix\n",
01249        "   -P dbprefix");
01250     FPS "%-20s Token to reset (default is internal)\n",
01251        "   -h token-name");
01252     FPS "\n");
01253 
01254     FPS "\n");
01255     FPS "%-15s Print the chain of a certificate\n",
01256        "-O");
01257     FPS "%-20s The nickname of the cert to modify\n",
01258        "   -n cert-name");
01259     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01260        "   -d certdir");
01261     FPS "%-20s Cert & Key database prefix\n",
01262        "   -P dbprefix");
01263     FPS "%-20s force the database to open R/W\n",
01264        "   -X");
01265     FPS "\n");
01266 
01267     FPS "%-15s Generate a certificate request (stdout)\n",
01268        "-R");
01269     FPS "%-20s Specify the subject name (using RFC1485)\n",
01270        "   -s subject");
01271     FPS "%-20s Output the cert request to this file\n",
01272        "   -o output-req");
01273 #ifdef NSS_ENABLE_ECC
01274     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
01275        "   -k key-type");
01276 #else
01277     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
01278        "   -k key-type");
01279 #endif /* NSS_ENABLE_ECC */
01280     FPS "%-20s Name of token in which to generate key (default is internal)\n",
01281        "   -h token-name");
01282     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
01283        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01284     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
01285        "   -q pqgfile");
01286 #ifdef NSS_ENABLE_ECC
01287     FPS "%-20s Elliptic curve name (ec only)\n",
01288        "   -q curve-name");
01289     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
01290        "");
01291 #endif /* NSS_ENABLE_ECC */
01292     FPS "%-20s Specify the password file\n",
01293        "   -f pwfile");
01294     FPS "%-20s Key database directory (default is ~/.netscape)\n",
01295        "   -d keydir");
01296     FPS "%-20s Cert & Key database prefix\n",
01297        "   -P dbprefix");
01298     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
01299        "   -p phone");
01300     FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n",
01301        "   -a");
01302     FPS "\n");
01303 
01304     FPS "%-15s Validate a certificate\n",
01305        "-V");
01306     FPS "%-20s The nickname of the cert to Validate\n",
01307        "   -n cert-name");
01308     FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n",
01309        "   -b time");
01310     FPS "%-20s Check certificate signature \n",
01311        "   -e ");   
01312     FPS "%-20s Specify certificate usage:\n", "   -u certusage");
01313     FPS "%-25s C \t SSL Client\n", "");
01314     FPS "%-25s V \t SSL Server\n", "");
01315     FPS "%-25s S \t Email signer\n", "");
01316     FPS "%-25s R \t Email Recipient\n", "");   
01317     FPS "%-25s O \t OCSP status responder\n", "");   
01318     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01319        "   -d certdir");
01320     FPS "%-20s Cert & Key database prefix\n",
01321        "   -P dbprefix");
01322     FPS "%-20s force the database to open R/W\n",
01323        "   -X");
01324     FPS "\n");
01325 
01326     FPS "%-15s Make a certificate and add to database\n",
01327         "-S");
01328     FPS "%-20s Specify the nickname of the cert\n",
01329         "   -n key-name");
01330     FPS "%-20s Specify the subject name (using RFC1485)\n",
01331         "   -s subject");
01332     FPS "%-20s The nickname of the issuer cert\n",
01333        "   -c issuer-name");
01334     FPS "%-20s Set the certificate trust attributes (see -A above)\n",
01335        "   -t trustargs");
01336 #ifdef NSS_ENABLE_ECC
01337     FPS "%-20s Type of key pair to generate (\"dsa\", \"ec\", \"rsa\" (default))\n",
01338        "   -k key-type");
01339 #else
01340     FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n",
01341        "   -k key-type");
01342 #endif /* NSS_ENABLE_ECC */
01343     FPS "%-20s Name of token in which to generate key (default is internal)\n",
01344        "   -h token-name");
01345     FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n",
01346        "   -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS);
01347     FPS "%-20s Name of file containing PQG parameters (dsa only)\n",
01348        "   -q pqgfile");
01349 #ifdef NSS_ENABLE_ECC
01350     FPS "%-20s Elliptic curve name (ec only)\n",
01351        "   -q curve-name");
01352     FPS "%-20s See the \"-G\" option for a full list of supported names.\n",
01353        "");
01354 #endif /* NSS_ENABLE_ECC */
01355     FPS "%-20s Self sign\n",
01356        "   -x");
01357     FPS "%-20s Cert serial number\n",
01358        "   -m serial-number");
01359     FPS "%-20s Time Warp\n",
01360        "   -w warp-months");
01361     FPS "%-20s Months valid (default is 3)\n",
01362         "   -v months-valid");
01363     FPS "%-20s Specify the password file\n",
01364        "   -f pwfile");
01365     FPS "%-20s Cert database directory (default is ~/.netscape)\n",
01366        "   -d certdir");
01367     FPS "%-20s Cert & Key database prefix\n",
01368        "   -P dbprefix");
01369     FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n",
01370        "   -p phone");
01371     FPS "%-20s Create key usage extension\n",
01372        "   -1 ");
01373     FPS "%-20s Create basic constraint extension\n",
01374        "   -2 ");
01375     FPS "%-20s Create authority key ID extension\n",
01376        "   -3 ");
01377     FPS "%-20s Create crl distribution point extension\n",
01378        "   -4 ");
01379     FPS "%-20s Create netscape cert type extension\n",
01380        "   -5 ");
01381     FPS "%-20s Create extended key usage extension\n",
01382        "   -6 ");
01383     FPS "%-20s Create an email subject alt name extension\n",
01384        "   -7 ");
01385     FPS "%-20s Create an dns subject alt name extension\n",
01386        "   -8 ");
01387     FPS "\n");
01388 
01389     exit(1);
01390 #undef FPS
01391 }
01392 
01393 
01394 static CERTCertificate *
01395 MakeV1Cert(   CERTCertDBHandle *   handle, 
01396               CERTCertificateRequest *req,
01397               char *               issuerNickName, 
01398               PRBool                      selfsign, 
01399               unsigned int         serialNumber,
01400               int                  warpmonths,
01401                 int                     validityMonths)
01402 {
01403     CERTCertificate *issuerCert = NULL;
01404     CERTValidity *validity;
01405     CERTCertificate *cert = NULL;
01406     PRExplodedTime printableTime;
01407     PRTime now, after;
01408 
01409     if ( !selfsign ) {
01410        issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName);
01411        if (!issuerCert) {
01412            SECU_PrintError(progName, "could not find certificate named \"%s\"",
01413                          issuerNickName);
01414            return NULL;
01415        }
01416     }
01417 
01418     now = PR_Now();
01419     PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
01420     if ( warpmonths ) {
01421        printableTime.tm_month += warpmonths;
01422        now = PR_ImplodeTime (&printableTime);
01423        PR_ExplodeTime (now, PR_GMTParameters, &printableTime);
01424     }
01425     printableTime.tm_month += validityMonths;
01426     after = PR_ImplodeTime (&printableTime);
01427 
01428     /* note that the time is now in micro-second unit */
01429     validity = CERT_CreateValidity (now, after);
01430 
01431     cert = CERT_CreateCertificate(serialNumber, 
01432                               (selfsign ? &req->subject 
01433                                         : &issuerCert->subject), 
01434                                  validity, req);
01435     
01436     CERT_DestroyValidity(validity);
01437     if ( issuerCert ) {
01438        CERT_DestroyCertificate (issuerCert);
01439     }
01440     
01441     return(cert);
01442 }
01443 
01444 static SECStatus 
01445 AddKeyUsage (void *extHandle)
01446 {
01447     SECItem bitStringValue;
01448     unsigned char keyUsage = 0x0;
01449     char buffer[5];
01450     int value;
01451     PRBool yesNoAns;
01452 
01453     while (1) {
01454        fprintf(stdout, "%-25s 0 - Digital Signature\n", "");
01455        fprintf(stdout, "%-25s 1 - Non-repudiation\n", "");
01456        fprintf(stdout, "%-25s 2 - Key encipherment\n", "");
01457        fprintf(stdout, "%-25s 3 - Data encipherment\n", "");   
01458        fprintf(stdout, "%-25s 4 - Key agreement\n", "");
01459        fprintf(stdout, "%-25s 5 - Cert signing key\n", "");   
01460        fprintf(stdout, "%-25s 6 - CRL signing key\n", "");
01461        fprintf(stdout, "%-25s Other to finish\n", "");
01462        if (Gets_s (buffer, sizeof(buffer))) {
01463            value = PORT_Atoi (buffer);
01464            if (value < 0 || value > 6)
01465                break;
01466            if (value == 0) {
01467               /* Checking that zero value of variable 'value'
01468                * corresponds to '0' input made by user */
01469               char *chPtr = strchr(buffer, '0');
01470               if (chPtr == NULL) {
01471                   continue;
01472               }
01473            }
01474            keyUsage |= (0x80 >> value);
01475        }
01476        else {        /* gets() returns NULL on EOF or error */
01477            break;
01478        }
01479     }
01480 
01481     bitStringValue.data = &keyUsage;
01482     bitStringValue.len = 1;
01483     yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
01484 
01485     return (CERT_EncodeAndAddBitStrExtension
01486            (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue,
01487             yesNoAns));
01488 
01489 }
01490 
01491 
01492 static CERTOidSequence *
01493 CreateOidSequence(void)
01494 {
01495   CERTOidSequence *rv = (CERTOidSequence *)NULL;
01496   PRArenaPool *arena = (PRArenaPool *)NULL;
01497 
01498   arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01499   if( (PRArenaPool *)NULL == arena ) {
01500     goto loser;
01501   }
01502 
01503   rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence));
01504   if( (CERTOidSequence *)NULL == rv ) {
01505     goto loser;
01506   }
01507 
01508   rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *));
01509   if( (SECItem **)NULL == rv->oids ) {
01510     goto loser;
01511   }
01512 
01513   rv->arena = arena;
01514   return rv;
01515 
01516  loser:
01517   if( (PRArenaPool *)NULL != arena ) {
01518     PORT_FreeArena(arena, PR_FALSE);
01519   }
01520 
01521   return (CERTOidSequence *)NULL;
01522 }
01523 
01524 static void
01525 DestroyOidSequence(CERTOidSequence *os)
01526 {
01527   if (os->arena) {
01528     PORT_FreeArena(os->arena, PR_FALSE);
01529   }
01530 }
01531 
01532 static SECStatus
01533 AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag)
01534 {
01535   SECItem **oids;
01536   PRUint32 count = 0;
01537   SECOidData *od;
01538 
01539   od = SECOID_FindOIDByTag(oidTag);
01540   if( (SECOidData *)NULL == od ) {
01541     return SECFailure;
01542   }
01543 
01544   for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) {
01545     count++;
01546   }
01547 
01548   /* ArenaZRealloc */
01549 
01550   {
01551     PRUint32 i;
01552 
01553     oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2));
01554     if( (SECItem **)NULL == oids ) {
01555       return SECFailure;
01556     }
01557     
01558     for( i = 0; i < count; i++ ) {
01559       oids[i] = os->oids[i];
01560     }
01561 
01562     /* ArenaZFree(os->oids); */
01563   }
01564 
01565   os->oids = oids;
01566   os->oids[count] = &od->oid;
01567 
01568   return SECSuccess;
01569 }
01570 
01571 SEC_ASN1_MKSUB(SEC_ObjectIDTemplate)
01572 
01573 const SEC_ASN1Template CERT_OidSeqTemplate[] = {
01574     { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN,
01575          offsetof(CERTOidSequence, oids),
01576          SEC_ASN1_SUB(SEC_ObjectIDTemplate) }
01577 };
01578 
01579 
01580 static SECItem *
01581 EncodeOidSequence(CERTOidSequence *os)
01582 {
01583   SECItem *rv;
01584 
01585   rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem));
01586   if( (SECItem *)NULL == rv ) {
01587     goto loser;
01588   }
01589 
01590   if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) {
01591     goto loser;
01592   }
01593 
01594   return rv;
01595 
01596  loser:
01597   return (SECItem *)NULL;
01598 }
01599 
01600 static SECStatus 
01601 AddExtKeyUsage (void *extHandle)
01602 {
01603   char buffer[5];
01604   int value;
01605   CERTOidSequence *os;
01606   SECStatus rv;
01607   SECItem *item;
01608   PRBool yesNoAns;
01609 
01610   os = CreateOidSequence();
01611   if( (CERTOidSequence *)NULL == os ) {
01612     return SECFailure;
01613   }
01614 
01615   while (1) {
01616     fprintf(stdout, "%-25s 0 - Server Auth\n", "");
01617     fprintf(stdout, "%-25s 1 - Client Auth\n", "");
01618     fprintf(stdout, "%-25s 2 - Code Signing\n", "");
01619     fprintf(stdout, "%-25s 3 - Email Protection\n", "");
01620     fprintf(stdout, "%-25s 4 - Timestamp\n", "");
01621     fprintf(stdout, "%-25s 5 - OCSP Responder\n", "");
01622     fprintf(stdout, "%-25s 6 - Step-up\n", "");
01623     fprintf(stdout, "%-25s Other to finish\n", "");
01624 
01625     if (Gets_s(buffer, sizeof(buffer)) == NULL) {
01626         PORT_SetError(SEC_ERROR_INPUT_LEN);
01627         rv = SECFailure;
01628         goto loser;
01629     }
01630     value = PORT_Atoi(buffer);
01631 
01632     if (value == 0) {
01633         /* Checking that zero value of variable 'value'
01634          * corresponds to '0' input made by user */
01635         char *chPtr = strchr(buffer, '0');
01636         if (chPtr == NULL) {
01637             continue;
01638         }
01639     }
01640 
01641     switch( value ) {
01642     case 0:
01643       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH);
01644       break;
01645     case 1:
01646       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH);
01647       break;
01648     case 2:
01649       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN);
01650       break;
01651     case 3:
01652       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT);
01653       break;
01654     case 4:
01655       rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP);
01656       break;
01657     case 5:
01658       rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER);
01659       break;
01660     case 6:
01661       rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED);
01662       break;
01663     default:
01664       goto endloop;
01665     }
01666 
01667     if( SECSuccess != rv ) goto loser;
01668   }
01669 
01670  endloop:;
01671   item = EncodeOidSequence(os);
01672 
01673   yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
01674 
01675   rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item,
01676                          yesNoAns, PR_TRUE);
01677   /*FALLTHROUGH*/
01678  loser:
01679   DestroyOidSequence(os);
01680   return rv;
01681 }
01682 
01683 static SECStatus 
01684 AddNscpCertType (void *extHandle)
01685 {
01686     SECItem bitStringValue;
01687     unsigned char keyUsage = 0x0;
01688     char buffer[5];
01689     int value;
01690     PRBool yesNoAns;
01691 
01692     while (1) {
01693        fprintf(stdout, "%-25s 0 - SSL Client\n", "");
01694        fprintf(stdout, "%-25s 1 - SSL Server\n", "");
01695        fprintf(stdout, "%-25s 2 - S/MIME\n", "");
01696        fprintf(stdout, "%-25s 3 - Object Signing\n", "");   
01697        fprintf(stdout, "%-25s 4 - Reserved for future use\n", "");
01698        fprintf(stdout, "%-25s 5 - SSL CA\n", "");   
01699        fprintf(stdout, "%-25s 6 - S/MIME CA\n", "");
01700        fprintf(stdout, "%-25s 7 - Object Signing CA\n", "");
01701        fprintf(stdout, "%-25s Other to finish\n", "");
01702        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
01703            PORT_SetError(SEC_ERROR_INPUT_LEN);
01704            return SECFailure;
01705        }
01706        value = PORT_Atoi (buffer);
01707        if (value < 0 || value > 7)
01708            break;
01709        if (value == 0) {
01710            /* Checking that zero value of variable 'value'
01711             * corresponds to '0' input made by user */
01712            char *chPtr = strchr(buffer, '0');
01713            if (chPtr == NULL) {
01714               continue;
01715            }
01716        }
01717        keyUsage |= (0x80 >> value);
01718     }
01719 
01720     bitStringValue.data = &keyUsage;
01721     bitStringValue.len = 1;
01722     yesNoAns = GetYesNo("Is this a critical extension [y/N]?");
01723 
01724     return (CERT_EncodeAndAddBitStrExtension
01725            (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue,
01726             yesNoAns));
01727 
01728 }
01729 
01730 static SECStatus 
01731 AddSubjectAltNames(PRArenaPool *arena, CERTGeneralName **existingListp,
01732                     const char *names, CERTGeneralNameType type)
01733 {
01734     CERTGeneralName *nameList = NULL;
01735     CERTGeneralName *current = NULL;
01736     PRCList *prev = NULL;
01737     const char *cp;
01738     char *tbuf;
01739     SECStatus rv = SECSuccess;
01740 
01741        
01742     /*
01743      * walk down the comma separated list of names. NOTE: there is
01744      * no sanity checks to see if the email address look like email addresses.
01745      */
01746     for (cp=names; cp; cp = PORT_Strchr(cp,',')) {
01747        int len;
01748        char *end;
01749 
01750        if (*cp == ',') {
01751           cp++;
01752        }
01753        end = PORT_Strchr(cp,',');
01754        len = end ? end-cp : PORT_Strlen(cp);
01755        if (len <= 0) {
01756           continue;
01757        }
01758        tbuf = PORT_ArenaAlloc(arena,len+1);
01759        PORT_Memcpy(tbuf,cp,len);
01760        tbuf[len] = 0;
01761        current = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName));
01762        if (!current) {
01763            rv = SECFailure;
01764            break;
01765        }
01766        if (prev) {
01767            current->l.prev = prev;
01768            prev->next = &(current->l);
01769        } else {
01770            nameList = current;
01771        }
01772        current->type = type;
01773        current->name.other.data = (unsigned char *)tbuf;
01774        current->name.other.len = PORT_Strlen(tbuf);
01775        prev = &(current->l);
01776     }
01777     /* at this point nameList points to the head of a doubly linked, but not yet 
01778        circular, list and current points to its tail. */
01779     if (rv == SECSuccess && nameList) {
01780         if (*existingListp != NULL) {
01781             PRCList *existingprev;
01782             /* add nameList to the end of the existing list */
01783             existingprev = (*existingListp)->l.prev;
01784             (*existingListp)->l.prev = &(current->l);
01785             nameList->l.prev = existingprev;
01786             existingprev->next = &(nameList->l);
01787             current->l.next = &((*existingListp)->l);
01788         }
01789         else {
01790             /* make nameList circular and set it as the new existingList */
01791             nameList->l.prev = prev;
01792             current->l.next = &(nameList->l);
01793             *existingListp = nameList;
01794         }
01795     }
01796     return rv;
01797 }
01798 
01799 static SECStatus 
01800 AddEmailSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
01801                     const char *emailAddrs)
01802 {
01803     return AddSubjectAltNames(arena, existingListp, emailAddrs, certRFC822Name);
01804 }
01805 
01806 static SECStatus 
01807 AddDNSSubjectAlt(PRArenaPool *arena, CERTGeneralName **existingListp,
01808                     const char *dnsNames)
01809 {
01810     return AddSubjectAltNames(arena, existingListp, dnsNames, certDNSName);
01811 }
01812 
01813 
01814 static SECStatus 
01815 AddBasicConstraint(void *extHandle)
01816 {
01817     CERTBasicConstraints basicConstraint;    
01818     SECItem encodedValue;
01819     SECStatus rv;
01820     char buffer[10];
01821     PRBool yesNoAns;
01822 
01823     encodedValue.data = NULL;
01824     encodedValue.len = 0;
01825     do {
01826        basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT;
01827        basicConstraint.isCA = GetYesNo ("Is this a CA certificate [y/N]?");
01828 
01829        buffer[0] = '\0';
01830        puts ("Enter the path length constraint, enter to skip [<0 for unlimited path]:");
01831        Gets_s (buffer, sizeof(buffer));
01832        if (PORT_Strlen (buffer) > 0)
01833            basicConstraint.pathLenConstraint = PORT_Atoi (buffer);
01834        
01835        rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint, &encodedValue);
01836        if (rv)
01837            return (rv);
01838 
01839        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
01840 
01841        rv = CERT_AddExtension
01842             (extHandle, SEC_OID_X509_BASIC_CONSTRAINTS,
01843              &encodedValue, yesNoAns, PR_TRUE);
01844     } while (0);
01845     PORT_Free (encodedValue.data);
01846     return (rv);
01847 }
01848 
01849 static SECItem *
01850 SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, 
01851          SECOidTag hashAlgTag,
01852          SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg)
01853 {
01854     SECItem der;
01855     SECItem *result = NULL;
01856     SECKEYPrivateKey *caPrivateKey = NULL;    
01857     SECStatus rv;
01858     PRArenaPool *arena;
01859     SECOidTag algID;
01860     void *dummy;
01861 
01862     if( !selfsign ) {
01863       CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg);
01864       if( (CERTCertificate *)NULL == issuer ) {
01865         SECU_PrintError(progName, "unable to find issuer with nickname %s", 
01866                        issuerNickName);
01867         return (SECItem *)NULL;
01868       }
01869 
01870       privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg);
01871       CERT_DestroyCertificate(issuer);
01872       if (caPrivateKey == NULL) {
01873        SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName);
01874        return NULL;
01875       }
01876     }
01877        
01878     arena = cert->arena;
01879 
01880     algID = SEC_GetSignatureAlgorithmOidTag(privKey->keyType, hashAlgTag);
01881     if (algID == SEC_OID_UNKNOWN) {
01882        fprintf(stderr, "Unknown key or hash type for issuer.");
01883        goto done;
01884     }
01885 
01886     rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0);
01887     if (rv != SECSuccess) {
01888        fprintf(stderr, "Could not set signature algorithm id.");
01889        goto done;
01890     }
01891 
01892     /* we only deal with cert v3 here */
01893     *(cert->version.data) = 2;
01894     cert->version.len = 1;
01895 
01896     der.len = 0;
01897     der.data = NULL;
01898     dummy = SEC_ASN1EncodeItem (arena, &der, cert,
01899                             SEC_ASN1_GET(CERT_CertificateTemplate));
01900     if (!dummy) {
01901        fprintf (stderr, "Could not encode certificate.\n");
01902        goto done;
01903     }
01904 
01905     result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem));
01906     if (result == NULL) {
01907        fprintf (stderr, "Could not allocate item for certificate data.\n");
01908        goto done;
01909     }
01910 
01911     rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID);
01912     if (rv != SECSuccess) {
01913        fprintf (stderr, "Could not sign encoded certificate data.\n");
01914        PORT_Free(result);
01915        result = NULL;
01916        goto done;
01917     }
01918     cert->derCert = *result;
01919 done:
01920     if (caPrivateKey) {
01921        SECKEY_DestroyPrivateKey(caPrivateKey);
01922     }
01923     return result;
01924 }
01925 
01926 static SECStatus 
01927 AddAuthKeyID (void *extHandle)
01928 {
01929     CERTAuthKeyID *authKeyID = NULL;    
01930     PRArenaPool *arena = NULL;
01931     SECStatus rv = SECSuccess;
01932     PRBool yesNoAns;
01933 
01934     do {
01935        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01936        if ( !arena ) {
01937            SECU_PrintError(progName, "out of memory");
01938            GEN_BREAK (SECFailure);
01939        }
01940 
01941        if (GetYesNo ("Enter value for the authKeyID extension [y/N]?") == 0)
01942            break;
01943        
01944        authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID));
01945        if (authKeyID == NULL) {
01946            GEN_BREAK (SECFailure);
01947        }
01948 
01949        rv = GetString (arena, "Enter value for the key identifier fields, enter to omit:",
01950                      &authKeyID->keyID);
01951        if (rv != SECSuccess)
01952            break;
01953        authKeyID->authCertIssuer = GetGeneralName (arena);
01954        if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError ())
01955               break;
01956        
01957 
01958        rv = GetString (arena, "Enter value for the authCertSerial field, enter to omit:",
01959                      &authKeyID->authCertSerialNumber);
01960 
01961        yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
01962 
01963        rv = SECU_EncodeAndAddExtensionValue
01964            (arena, extHandle, authKeyID, yesNoAns,
01965             SEC_OID_X509_AUTH_KEY_ID, 
01966             (EXTEN_EXT_VALUE_ENCODER) CERT_EncodeAuthKeyID);
01967        if (rv)
01968            break;
01969        
01970     } while (0);
01971     if (arena)
01972        PORT_FreeArena (arena, PR_FALSE);
01973     return (rv);
01974 }   
01975     
01976 static SECStatus 
01977 AddCrlDistPoint(void *extHandle)
01978 {
01979     PRArenaPool *arena = NULL;
01980     CERTCrlDistributionPoints *crlDistPoints = NULL;
01981     CRLDistributionPoint *current;
01982     SECStatus rv = SECSuccess;
01983     int count = 0, intValue;
01984     char buffer[512];
01985 
01986     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01987     if ( !arena )
01988        return (SECFailure);
01989 
01990     do {
01991        current = NULL;
01992        current = PORT_ArenaZAlloc (arena, sizeof (*current));
01993         if (current == NULL) {
01994            GEN_BREAK (SECFailure);
01995        }   
01996 
01997        /* Get the distributionPointName fields - this field is optional */
01998        puts ("Enter the type of the distribution point name:\n");
01999        puts ("\t1 - Full Name\n\t2 - Relative Name\n\tAny other number to finish\n\t\tChoice: ");
02000        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
02001            PORT_SetError(SEC_ERROR_INPUT_LEN);
02002            GEN_BREAK (SECFailure);
02003        }
02004        intValue = PORT_Atoi (buffer);
02005        switch (intValue) {
02006            case generalName:
02007               current->distPointType = intValue;
02008               current->distPoint.fullName = GetGeneralName (arena);
02009               rv = PORT_GetError();
02010               break;
02011               
02012            case relativeDistinguishedName: {
02013               CERTName *name;
02014 
02015               current->distPointType = intValue;
02016               puts ("Enter the relative name: ");
02017               fflush (stdout);
02018               if (Gets_s (buffer, sizeof(buffer)) == NULL) {
02019                   GEN_BREAK (SECFailure);
02020               }
02021               /* For simplicity, use CERT_AsciiToName to converse from a string
02022                  to NAME, but we only interest in the first RDN */
02023               name = CERT_AsciiToName (buffer);
02024               if (!name) {
02025                   GEN_BREAK (SECFailure);
02026               }
02027               rv = CERT_CopyRDN (arena, &current->distPoint.relativeName, name->rdns[0]);
02028               CERT_DestroyName (name);
02029               break;
02030            }
02031        }
02032        if (rv != SECSuccess)
02033            break;
02034 
02035        /* Get the reason flags */
02036        puts ("\nSelect one of the following for the reason flags\n");
02037        puts ("\t0 - unused\n\t1 - keyCompromise\n\t2 - caCompromise\n\t3 - affiliationChanged\n");
02038        puts ("\t4 - superseded\n\t5 - cessationOfOperation\n\t6 - certificateHold\n");
02039        puts ("\tAny other number to finish\t\tChoice: ");
02040        
02041        if (Gets_s (buffer, sizeof(buffer)) == NULL) {
02042            PORT_SetError(SEC_ERROR_INPUT_LEN);
02043            GEN_BREAK (SECFailure);
02044        }
02045        intValue = PORT_Atoi (buffer);
02046        if (intValue == 0) {
02047            /* Checking that zero value of variable 'value'
02048             * corresponds to '0' input made by user */
02049            char *chPtr = strchr(buffer, '0');
02050            if (chPtr == NULL) {
02051               intValue = -1;
02052            }
02053        }
02054        if (intValue >= 0 && intValue <8) {
02055            current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char));
02056            if (current->reasons.data == NULL) {
02057               GEN_BREAK (SECFailure);
02058            }
02059            *current->reasons.data = (char)(0x80 >> intValue);
02060            current->reasons.len = 1;
02061        }
02062        puts ("Enter value for the CRL Issuer name:\n");
02063         current->crlIssuer = GetGeneralName (arena);
02064        if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure)
02065            break;
02066 
02067        if (crlDistPoints == NULL) {
02068            crlDistPoints = PORT_ArenaZAlloc (arena, sizeof (*crlDistPoints));
02069            if (crlDistPoints == NULL) {
02070               GEN_BREAK (SECFailure);
02071            }
02072        }
02073            
02074        crlDistPoints->distPoints = PORT_ArenaGrow (arena, 
02075             crlDistPoints->distPoints,
02076             sizeof (*crlDistPoints->distPoints) * count,
02077             sizeof (*crlDistPoints->distPoints) *(count + 1));
02078        if (crlDistPoints->distPoints == NULL) {
02079            GEN_BREAK (SECFailure);
02080        }
02081        
02082        crlDistPoints->distPoints[count] = current;
02083        ++count;
02084        if (GetYesNo ("Enter more value for the CRL distribution point extension [y/N]") == 0) {
02085            /* Add null to the end of the crlDistPoints to mark end of data */
02086            crlDistPoints->distPoints = PORT_ArenaGrow(arena, 
02087                crlDistPoints->distPoints,
02088                sizeof (*crlDistPoints->distPoints) * count,
02089                sizeof (*crlDistPoints->distPoints) *(count + 1));
02090            crlDistPoints->distPoints[count] = NULL;         
02091            break;
02092        }
02093        
02094 
02095     } while (1);
02096     
02097     if (rv == SECSuccess) {
02098        PRBool yesNoAns = GetYesNo ("Is this a critical extension [y/N]?");
02099        
02100        rv = SECU_EncodeAndAddExtensionValue(arena, extHandle, crlDistPoints,
02101              yesNoAns, SEC_OID_X509_CRL_DIST_POINTS,
02102              (EXTEN_EXT_VALUE_ENCODER)  CERT_EncodeCRLDistributionPoints);
02103     }
02104     if (arena)
02105        PORT_FreeArena (arena, PR_FALSE);
02106     return (rv);
02107 }
02108 
02109 static SECStatus
02110 AddExtensions(void *extHandle, const char *emailAddrs, const char *dnsNames,
02111        PRBool keyUsage, 
02112        PRBool  extKeyUsage,
02113        PRBool  basicConstraint, 
02114        PRBool  authKeyID,
02115        PRBool  crlDistPoints, 
02116        PRBool  nscpCertType)
02117 {
02118     SECStatus        rv = SECSuccess;
02119     do {
02120        /* Add key usage extension */
02121        if (keyUsage) {
02122            rv = AddKeyUsage(extHandle);
02123            if (rv)
02124               break;
02125        }
02126 
02127        /* Add extended key usage extension */
02128        if (extKeyUsage) {
02129            rv = AddExtKeyUsage(extHandle);
02130            if (rv)
02131               break;
02132        }
02133 
02134        /* Add basic constraint extension */
02135        if (basicConstraint) {
02136            rv = AddBasicConstraint(extHandle);
02137            if (rv)
02138               break;
02139        }
02140 
02141        if (authKeyID) {
02142            rv = AddAuthKeyID (extHandle);
02143            if (rv)
02144               break;
02145        }    
02146 
02147        if (crlDistPoints) {
02148            rv = AddCrlDistPoint (extHandle);
02149            if (rv)
02150               break;
02151        }
02152        
02153        if (nscpCertType) {
02154            rv = AddNscpCertType(extHandle);
02155            if (rv)
02156               break;
02157        }
02158 
02159        if (emailAddrs || dnsNames) {
02160             PRArenaPool *arena;
02161             CERTGeneralName *namelist = NULL;
02162             SECItem item = { 0, NULL, 0 };
02163             
02164             arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02165             if (arena == NULL) {
02166                 rv = SECFailure;
02167                 break;
02168             }
02169 
02170            rv = AddEmailSubjectAlt(arena, &namelist, emailAddrs);
02171 
02172            rv |= AddDNSSubjectAlt(arena, &namelist, dnsNames);
02173 
02174             if (rv == SECSuccess) {
02175                 rv = CERT_EncodeAltNameExtension(arena, namelist, &item);
02176                 if (rv == SECSuccess) {
02177                    rv = CERT_AddExtension(extHandle,
02178                                            SEC_OID_X509_SUBJECT_ALT_NAME,
02179                                            &item, PR_FALSE, PR_TRUE);
02180                 }
02181             }
02182             PORT_FreeArena(arena, PR_FALSE);
02183        }
02184     } while (0);
02185     return rv;
02186 }
02187 
02188 static SECStatus
02189 CreateCert(
02190        CERTCertDBHandle *handle, 
02191        char *  issuerNickName, 
02192        PRFileDesc *inFile,
02193        PRFileDesc *outFile, 
02194        SECKEYPrivateKey *selfsignprivkey,
02195        void   *pwarg,
02196        SECOidTag hashAlgTag,
02197        unsigned int serialNumber, 
02198        int     warpmonths,
02199        int     validityMonths,
02200        const char *emailAddrs,
02201        const char *dnsNames,
02202        PRBool  ascii,
02203        PRBool  selfsign,
02204        PRBool keyUsage, 
02205        PRBool  extKeyUsage,
02206        PRBool  basicConstraint, 
02207        PRBool  authKeyID,
02208        PRBool  crlDistPoints, 
02209        PRBool  nscpCertType)
02210 {
02211     void *    extHandle;
02212     SECItem * certDER;
02213     PRArenaPool *arena                    = NULL;
02214     CERTCertificate *subjectCert   = NULL;
02215     CERTCertificateRequest *certReq       = NULL;
02216     SECStatus        rv                   = SECSuccess;
02217     SECItem   reqDER;
02218     CERTCertExtension **CRexts;
02219 
02220     reqDER.data = NULL;
02221     do {
02222        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
02223        if (!arena) {
02224            GEN_BREAK (SECFailure);
02225        }
02226        
02227        /* Create a certrequest object from the input cert request der */
02228        certReq = GetCertRequest(inFile, ascii);
02229        if (certReq == NULL) {
02230            GEN_BREAK (SECFailure)
02231        }
02232 
02233        subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign,
02234                               serialNumber, warpmonths, validityMonths);
02235        if (subjectCert == NULL) {
02236            GEN_BREAK (SECFailure)
02237        }
02238         
02239         
02240        extHandle = CERT_StartCertExtensions (subjectCert);
02241        if (extHandle == NULL) {
02242            GEN_BREAK (SECFailure)
02243        }
02244         
02245         rv = AddExtensions(extHandle, emailAddrs, dnsNames, keyUsage, extKeyUsage,
02246                           basicConstraint, authKeyID, crlDistPoints, nscpCertType);
02247         if (rv != SECSuccess) {
02248            GEN_BREAK (SECFailure)
02249        }
02250         
02251         if (certReq->attributes != NULL &&
02252            certReq->attributes[0] != NULL &&
02253            certReq->attributes[0]->attrType.data != NULL &&
02254            certReq->attributes[0]->attrType.len   > 0    &&
02255             SECOID_FindOIDTag(&certReq->attributes[0]->attrType)
02256                 == SEC_OID_PKCS9_EXTENSION_REQUEST) {
02257             rv = CERT_GetCertificateRequestExtensions(certReq, &CRexts);
02258             if (rv != SECSuccess)
02259                 break;
02260             rv = CERT_MergeExtensions(extHandle, CRexts);
02261             if (rv != SECSuccess)
02262                 break;
02263         }
02264 
02265        CERT_FinishExtensions(extHandle);
02266 
02267        certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag,
02268                           selfsignprivkey, issuerNickName,pwarg);
02269 
02270        if (certDER) {
02271           if (ascii) {
02272               PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER, 
02273                          BTOA_DataToAscii(certDER->data, certDER->len), 
02274                         NS_CERT_TRAILER);
02275           } else {
02276               PR_Write(outFile, certDER->data, certDER->len);
02277           }
02278        }
02279 
02280     } while (0);
02281     CERT_DestroyCertificateRequest (certReq);
02282     CERT_DestroyCertificate (subjectCert);
02283     PORT_FreeArena (arena, PR_FALSE);
02284     if (rv != SECSuccess) {
02285        PRErrorCode  perr = PR_GetError();
02286         fprintf(stderr, "%s: unable to create cert (%s)\n", progName,
02287                SECU_Strerror(perr));
02288     }
02289     return (rv);
02290 }
02291 
02292 /*  Certutil commands  */
02293 enum {
02294     cmd_AddCert = 0,
02295     cmd_CreateNewCert,
02296     cmd_DeleteCert,
02297     cmd_AddEmailCert,
02298     cmd_DeleteKey,
02299     cmd_GenKeyPair,
02300     cmd_PrintHelp,
02301     cmd_ListKeys,
02302     cmd_ListCerts,
02303     cmd_ModifyCertTrust,
02304     cmd_NewDBs,
02305     cmd_DumpChain,
02306     cmd_CertReq,
02307     cmd_CreateAndAddCert,
02308     cmd_TokenReset,
02309     cmd_ListModules,
02310     cmd_CheckCertValidity,
02311     cmd_ChangePassword,
02312     cmd_Version,
02313     cmd_Batch
02314 };
02315 
02316 /*  Certutil options */
02317 enum {
02318     opt_SSOPass = 0,
02319     opt_AddKeyUsageExt,
02320     opt_AddBasicConstraintExt,
02321     opt_AddAuthorityKeyIDExt,
02322     opt_AddCRLDistPtsExt,
02323     opt_AddNSCertTypeExt,
02324     opt_AddExtKeyUsageExt,
02325     opt_ExtendedEmailAddrs,
02326     opt_ExtendedDNSNames,
02327     opt_ASCIIForIO,
02328     opt_ValidityTime,
02329     opt_IssuerName,
02330     opt_CertDir,
02331     opt_VerifySig,
02332     opt_PasswordFile,
02333     opt_KeySize,
02334     opt_TokenName,
02335     opt_InputFile,
02336     opt_KeyIndex,
02337     opt_KeyType,
02338     opt_DetailedInfo,
02339     opt_SerialNumber,
02340     opt_Nickname,
02341     opt_OutputFile,
02342     opt_PhoneNumber,
02343     opt_DBPrefix,
02344     opt_PQGFile,
02345     opt_BinaryDER,
02346     opt_Subject,
02347     opt_Trust,
02348     opt_Usage,
02349     opt_Validity,
02350     opt_OffsetMonths,
02351     opt_SelfSign,
02352     opt_RW,
02353     opt_Exponent,
02354     opt_NoiseFile,
02355     opt_Hash
02356 };
02357 
02358 static int 
02359 certutil_main(int argc, char **argv, PRBool initialize)
02360 {
02361     CERTCertDBHandle *certHandle;
02362     PK11SlotInfo *slot = NULL;
02363     CERTName *  subject         = 0;
02364     PRFileDesc *inFile          = PR_STDIN;
02365     PRFileDesc *outFile         = NULL;
02366     char *      certfile        = "tempcert";
02367     char *      certreqfile     = "tempcertreq";
02368     char *      slotname        = "internal";
02369     char *      certPrefix      = "";
02370     KeyType     keytype         = rsaKey;
02371     char *      name            = NULL;
02372     SECOidTag   hashAlgTag      = SEC_OID_UNKNOWN;
02373     int               keysize              = DEFAULT_KEY_BITS;
02374     int         publicExponent  = 0x010001;
02375     unsigned int serialNumber   = 0;
02376     int         warpmonths      = 0;
02377     int         validityMonths  = 3;
02378     int         commandsEntered = 0;
02379     char        commandToRun    = '\0';
02380     secuPWData  pwdata          = { PW_NONE, 0 };
02381     PRBool    readOnly      = PR_FALSE;
02382     PRBool      initialized     = PR_FALSE;
02383 
02384     SECKEYPrivateKey *privkey = NULL;
02385     SECKEYPublicKey *pubkey = NULL;
02386 
02387     int i;
02388     SECStatus rv;
02389 
02390     secuCommand certutil;
02391 
02392 secuCommandFlag certutil_commands[] =
02393 {
02394        { /* cmd_AddCert             */  'A', PR_FALSE, 0, PR_FALSE },
02395        { /* cmd_CreateNewCert       */  'C', PR_FALSE, 0, PR_FALSE },
02396        { /* cmd_DeleteCert          */  'D', PR_FALSE, 0, PR_FALSE },
02397        { /* cmd_AddEmailCert        */  'E', PR_FALSE, 0, PR_FALSE },
02398        { /* cmd_DeleteKey           */  'F', PR_FALSE, 0, PR_FALSE },
02399        { /* cmd_GenKeyPair          */  'G', PR_FALSE, 0, PR_FALSE },
02400        { /* cmd_PrintHelp           */  'H', PR_FALSE, 0, PR_FALSE },
02401        { /* cmd_ListKeys            */  'K', PR_FALSE, 0, PR_FALSE },
02402        { /* cmd_ListCerts           */  'L', PR_FALSE, 0, PR_FALSE },
02403        { /* cmd_ModifyCertTrust     */  'M', PR_FALSE, 0, PR_FALSE },
02404        { /* cmd_NewDBs              */  'N', PR_FALSE, 0, PR_FALSE },
02405        { /* cmd_DumpChain           */  'O', PR_FALSE, 0, PR_FALSE },
02406        { /* cmd_CertReq             */  'R', PR_FALSE, 0, PR_FALSE },
02407        { /* cmd_CreateAndAddCert    */  'S', PR_FALSE, 0, PR_FALSE },
02408        { /* cmd_TokenReset          */  'T', PR_FALSE, 0, PR_FALSE },
02409        { /* cmd_ListModules         */  'U', PR_FALSE, 0, PR_FALSE },
02410        { /* cmd_CheckCertValidity   */  'V', PR_FALSE, 0, PR_FALSE },
02411        { /* cmd_ChangePassword      */  'W', PR_FALSE, 0, PR_FALSE },
02412        { /* cmd_Version             */  'Y', PR_FALSE, 0, PR_FALSE },
02413        { /* cmd_Batch               */  'B', PR_FALSE, 0, PR_FALSE }
02414 };
02415 
02416 secuCommandFlag certutil_options[] =
02417 {
02418        { /* opt_SSOPass             */  '0', PR_TRUE,  0, PR_FALSE },
02419        { /* opt_AddKeyUsageExt      */  '1', PR_FALSE, 0, PR_FALSE },
02420        { /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE },
02421        { /* opt_AddAuthorityKeyIDExt*/  '3', PR_FALSE, 0, PR_FALSE },
02422        { /* opt_AddCRLDistPtsExt    */  '4', PR_FALSE, 0, PR_FALSE },
02423        { /* opt_AddNSCertTypeExt    */  '5', PR_FALSE, 0, PR_FALSE },
02424        { /* opt_AddExtKeyUsageExt   */  '6', PR_FALSE, 0, PR_FALSE },
02425        { /* opt_ExtendedEmailAddrs  */  '7', PR_TRUE,  0, PR_FALSE },
02426        { /* opt_ExtendedDNSNames    */  '8', PR_TRUE,  0, PR_FALSE },
02427        { /* opt_ASCIIForIO          */  'a', PR_FALSE, 0, PR_FALSE },
02428        { /* opt_ValidityTime        */  'b', PR_TRUE,  0, PR_FALSE },
02429        { /* opt_IssuerName          */  'c', PR_TRUE,  0, PR_FALSE },
02430        { /* opt_CertDir             */  'd', PR_TRUE,  0, PR_FALSE },
02431        { /* opt_VerifySig           */  'e', PR_FALSE, 0, PR_FALSE },
02432        { /* opt_PasswordFile        */  'f', PR_TRUE,  0, PR_FALSE },
02433        { /* opt_KeySize             */  'g', PR_TRUE,  0, PR_FALSE },
02434        { /* opt_TokenName           */  'h', PR_TRUE,  0, PR_FALSE },
02435        { /* opt_InputFile           */  'i', PR_TRUE,  0, PR_FALSE },
02436        { /* opt_KeyIndex            */  'j', PR_TRUE,  0, PR_FALSE },
02437        { /* opt_KeyType             */  'k', PR_TRUE,  0, PR_FALSE },
02438        { /* opt_DetailedInfo        */  'l', PR_FALSE, 0, PR_FALSE },
02439        { /* opt_SerialNumber        */  'm', PR_TRUE,  0, PR_FALSE },
02440        { /* opt_Nickname            */  'n', PR_TRUE,  0, PR_FALSE },
02441        { /* opt_OutputFile          */  'o', PR_TRUE,  0, PR_FALSE },
02442        { /* opt_PhoneNumber         */  'p', PR_TRUE,  0, PR_FALSE },
02443        { /* opt_DBPrefix            */  'P', PR_TRUE,  0, PR_FALSE },
02444        { /* opt_PQGFile             */  'q', PR_TRUE,  0, PR_FALSE },
02445        { /* opt_BinaryDER           */  'r', PR_FALSE, 0, PR_FALSE },
02446        { /* opt_Subject             */  's', PR_TRUE,  0, PR_FALSE },
02447        { /* opt_Trust               */  't', PR_TRUE,  0, PR_FALSE },
02448        { /* opt_Usage               */  'u', PR_TRUE,  0, PR_FALSE },
02449        { /* opt_Validity            */  'v', PR_TRUE,  0, PR_FALSE },
02450        { /* opt_OffsetMonths        */  'w', PR_TRUE,  0, PR_FALSE },
02451        { /* opt_SelfSign            */  'x', PR_FALSE, 0, PR_FALSE },
02452        { /* opt_RW                  */  'X', PR_FALSE, 0, PR_FALSE },
02453        { /* opt_Exponent            */  'y', PR_TRUE,  0, PR_FALSE },
02454        { /* opt_NoiseFile           */  'z', PR_TRUE,  0, PR_FALSE },
02455        { /* opt_Hash                */  'Z', PR_TRUE,  0, PR_FALSE }
02456 };
02457 
02458 
02459     certutil.numCommands = sizeof(certutil_commands) / sizeof(secuCommandFlag);
02460     certutil.numOptions = sizeof(certutil_options) / sizeof(secuCommandFlag);
02461     certutil.commands = certutil_commands;
02462     certutil.options = certutil_options;
02463 
02464     progName = PORT_Strrchr(argv[0], '/');
02465     progName = progName ? progName+1 : argv[0];
02466 
02467     rv = SECU_ParseCommandLine(argc, argv, progName, &certutil);
02468 
02469     if (rv != SECSuccess)
02470        Usage(progName);
02471 
02472     if (certutil.commands[cmd_PrintHelp].activated)
02473        LongUsage(progName);
02474 
02475     if (certutil.options[opt_PasswordFile].arg) {
02476        pwdata.source = PW_FROMFILE;
02477        pwdata.data = certutil.options[opt_PasswordFile].arg;
02478     }
02479 
02480     if (certutil.options[opt_CertDir].activated)
02481        SECU_ConfigDirectory(certutil.options[opt_CertDir].arg);
02482 
02483     if (certutil.options[opt_KeySize].activated) {
02484        keysize = PORT_Atoi(certutil.options[opt_KeySize].arg);
02485        if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) {
02486            PR_fprintf(PR_STDERR, 
02487                        "%s -g:  Keysize must be between %d and %d.\n",
02488                      progName, MIN_KEY_BITS, MAX_KEY_BITS);
02489            return 255;
02490        }
02491 #ifdef NSS_ENABLE_ECC
02492        if (keytype == ecKey) {
02493            PR_fprintf(PR_STDERR, "%s -g:  Not for ec keys.\n", progName);
02494            return 255;
02495        }
02496 #endif /* NSS_ENABLE_ECC */
02497 
02498     }
02499 
02500     /*  -h specify token name  */
02501     if (certutil.options[opt_TokenName].activated) {
02502        if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0)
02503            slotname = NULL;
02504        else
02505            slotname = PL_strdup(certutil.options[opt_TokenName].arg);
02506     }
02507 
02508     /*  -Z hash type  */
02509     if (certutil.options[opt_Hash].activated) {
02510        char * arg = certutil.options[opt_Hash].arg;
02511         hashAlgTag = SECU_StringToSignatureAlgTag(arg);
02512         if (hashAlgTag == SEC_OID_UNKNOWN) {
02513            PR_fprintf(PR_STDERR, "%s -Z:  %s is not a recognized type.\n",
02514                       progName, arg);
02515            return 255;
02516        }
02517     }
02518 
02519     /*  -k key type  */
02520     if (certutil.options[opt_KeyType].activated) {
02521        char * arg = certutil.options[opt_KeyType].arg;
02522        if (PL_strcmp(arg, "rsa") == 0) {
02523            keytype = rsaKey;
02524        } else if (PL_strcmp(arg, "dsa") == 0) {
02525            keytype = dsaKey;
02526 #ifdef NSS_ENABLE_ECC
02527        } else if (PL_strcmp(arg, "ec") == 0) {
02528            keytype = ecKey;
02529 #endif /* NSS_ENABLE_ECC */
02530        } else if (PL_strcmp(arg, "all") == 0) {
02531            keytype = nullKey;
02532        } else {
02533            PR_fprintf(PR_STDERR, "%s -k:  %s is not a recognized type.\n",
02534                       progName, arg);
02535            return 255;
02536        }
02537     }
02538 
02539     /*  -m serial number */
02540     if (certutil.options[opt_SerialNumber].activated) {
02541        int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg);
02542        if (sn < 0) {
02543            PR_fprintf(PR_STDERR, "%s -m:  %s is not a valid serial number.\n",
02544                       progName, certutil.options[opt_SerialNumber].arg);
02545            return 255;
02546        }
02547        serialNumber = sn;
02548     }
02549 
02550     /*  -P certdb name prefix */
02551     if (certutil.options[opt_DBPrefix].activated) {
02552         if (certutil.options[opt_DBPrefix].arg) {
02553             certPrefix = strdup(certutil.options[opt_DBPrefix].arg);
02554         } else {
02555             Usage(progName);
02556         }
02557     }
02558 
02559     /*  -q PQG file or curve name */
02560     if (certutil.options[opt_PQGFile].activated) {
02561 #ifdef NSS_ENABLE_ECC
02562        if ((keytype != dsaKey) && (keytype != ecKey)) {
02563            PR_fprintf(PR_STDERR, "%s -q: specifies a PQG file for DSA keys" \
02564                      " (-k dsa) or a named curve for EC keys (-k ec)\n)",
02565                       progName);
02566 #else
02567        if (keytype != dsaKey) {
02568            PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)",
02569                       progName);
02570 #endif /* NSS_ENABLE_ECC */
02571            return 255;
02572        }
02573     }
02574 
02575     /*  -s subject name  */
02576     if (certutil.options[opt_Subject].activated) {
02577        subject = CERT_AsciiToName(certutil.options[opt_Subject].arg);
02578        if (!subject) {
02579            PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n",
02580                       progName, certutil.options[opt_Subject].arg);
02581            return 255;
02582        }
02583     }
02584 
02585     /*  -v validity period  */
02586     if (certutil.options[opt_Validity].activated) {
02587        validityMonths = PORT_Atoi(certutil.options[opt_Validity].arg);
02588        if (validityMonths < 0) {
02589            PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n",
02590                       progName, certutil.options[opt_Validity].arg);
02591            return 255;
02592        }
02593     }
02594 
02595     /*  -w warp months  */
02596     if (certutil.options[opt_OffsetMonths].activated)
02597        warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg);
02598 
02599     /*  -y public exponent (for RSA)  */
02600     if (certutil.options[opt_Exponent].activated) {
02601        publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg);
02602        if ((publicExponent != 3) &&
02603            (publicExponent != 17) &&
02604            (publicExponent != 65537)) {
02605            PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.", 
02606                                   progName, publicExponent);
02607            PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n");
02608            return 255;
02609        }
02610     }
02611 
02612     /*  Check number of commands entered.  */
02613     commandsEntered = 0;
02614     for (i=0; i< certutil.numCommands; i++) {
02615        if (certutil.commands[i].activated) {
02616            commandToRun = certutil.commands[i].flag;
02617            commandsEntered++;
02618        }
02619        if (commandsEntered > 1)
02620            break;
02621     }
02622     if (commandsEntered > 1) {
02623        PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName);
02624        PR_fprintf(PR_STDERR, "You entered: ");
02625        for (i=0; i< certutil.numCommands; i++) {
02626            if (certutil.commands[i].activated)
02627               PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag);
02628        }
02629        PR_fprintf(PR_STDERR, "\n");
02630        return 255;
02631     }
02632     if (commandsEntered == 0) {
02633        PR_fprintf(PR_STDERR, "%s: you must enter a command!\n", progName);
02634        Usage(progName);
02635     }
02636 
02637     if (certutil.commands[cmd_ListCerts].activated ||
02638          certutil.commands[cmd_PrintHelp].activated ||
02639          certutil.commands[cmd_ListKeys].activated ||
02640          certutil.commands[cmd_ListModules].activated ||
02641          certutil.commands[cmd_CheckCertValidity].activated ||
02642          certutil.commands[cmd_Version].activated ) {
02643        readOnly = !certutil.options[opt_RW].activated;
02644     }
02645 
02646     /*  -A, -D, -F, -M, -S, -V, and all require -n  */
02647     if ((certutil.commands[cmd_AddCert].activated ||
02648          certutil.commands[cmd_DeleteCert].activated ||
02649          certutil.commands[cmd_DeleteKey].activated ||
02650         certutil.commands[cmd_DumpChain].activated ||
02651          certutil.commands[cmd_ModifyCertTrust].activated ||
02652          certutil.commands[cmd_CreateAndAddCert].activated ||
02653          certutil.commands[cmd_CheckCertValidity].activated) &&
02654         !certutil.options[opt_Nickname].activated) {
02655        PR_fprintf(PR_STDERR, 
02656                  "%s -%c: nickname is required for this command (-n).\n",
02657                   progName, commandToRun);
02658        return 255;
02659     }
02660 
02661     /*  -A, -E, -M, -S require trust  */
02662     if ((certutil.commands[cmd_AddCert].activated ||
02663          certutil.commands[cmd_AddEmailCert].activated ||
02664          certutil.commands[cmd_ModifyCertTrust].activated ||
02665          certutil.commands[cmd_CreateAndAddCert].activated) &&
02666         !certutil.options[opt_Trust].activated) {
02667        PR_fprintf(PR_STDERR, 
02668                  "%s -%c: trust is required for this command (-t).\n",
02669                   progName, commandToRun);
02670        return 255;
02671     }
02672 
02673     /*  if -L is given raw or ascii mode, it must be for only one cert.  */
02674     if (certutil.commands[cmd_ListCerts].activated &&
02675         (certutil.options[opt_ASCIIForIO].activated ||
02676          certutil.options[opt_BinaryDER].activated) &&
02677         !certutil.options[opt_Nickname].activated) {
02678        PR_fprintf(PR_STDERR, 
02679                "%s: nickname is required to dump cert in raw or ascii mode.\n",
02680                   progName);
02681        return 255;
02682     }
02683     
02684     /*  -L can only be in (raw || ascii).  */
02685     if (certutil.commands[cmd_ListCerts].activated &&
02686         certutil.options[opt_ASCIIForIO].activated &&
02687         certutil.options[opt_BinaryDER].activated) {
02688        PR_fprintf(PR_STDERR, 
02689                   "%s: cannot specify both -r and -a when dumping cert.\n",
02690                   progName);
02691        return 255;
02692     }
02693 
02694     /*  For now, deny -C -x combination */
02695     if (certutil.commands[cmd_CreateNewCert].activated &&
02696         certutil.options[opt_SelfSign].activated) {
02697        PR_fprintf(PR_STDERR,
02698                   "%s: self-signing a cert request is not supported.\n",
02699                   progName);
02700        return 255;
02701     }
02702 
02703     /*  If making a cert request, need a subject.  */
02704     if ((certutil.commands[cmd_CertReq].activated ||
02705          certutil.commands[cmd_CreateAndAddCert].activated) &&
02706         !certutil.options[opt_Subject].activated) {
02707        PR_fprintf(PR_STDERR, 
02708                   "%s -%c: subject is required to create a cert request.\n",
02709                   progName, commandToRun);
02710        return 255;
02711     }
02712 
02713     /*  If making a cert, need a serial number.  */
02714     if ((certutil.commands[cmd_CreateNewCert].activated ||
02715          certutil.commands[cmd_CreateAndAddCert].activated) &&
02716          !certutil.options[opt_SerialNumber].activated) {
02717        /*  Make a default serial number from the current time.  */
02718        PRTime now = PR_Now();
02719        LL_USHR(now, now, 19);
02720        LL_L2UI(serialNumber, now);
02721     }
02722 
02723     /*  Validation needs the usage to validate for.  */
02724     if (certutil.commands[cmd_CheckCertValidity].activated &&
02725         !certutil.options[opt_Usage].activated) {
02726        PR_fprintf(PR_STDERR, 
02727                   "%s -V: specify a usage to validate the cert for (-u).\n",
02728                   progName);
02729        return 255;
02730     }
02731     
02732     /*  To make a cert, need either a issuer or to self-sign it.  */
02733     if (certutil.commands[cmd_CreateAndAddCert].activated &&
02734        !(certutil.options[opt_IssuerName].activated ||
02735           certutil.options[opt_SelfSign].activated)) {
02736        PR_fprintf(PR_STDERR,
02737                   "%s -S: must specify issuer (-c) or self-sign (-x).\n",
02738                   progName);
02739        return 255;
02740     }
02741 
02742     /*  Using slotname == NULL for listing keys and certs on all slots, 
02743      *  but only that. */
02744     if (!(certutil.commands[cmd_ListKeys].activated ||
02745          certutil.commands[cmd_DumpChain].activated ||
02746          certutil.commands[cmd_ListCerts].activated) && slotname == NULL) {
02747        PR_fprintf(PR_STDERR,
02748                   "%s -%c: cannot use \"-h all\" for this command.\n",
02749                   progName, commandToRun);
02750        return 255;
02751     }
02752 
02753     /*  Using keytype == nullKey for list all key types, but only that.  */
02754     if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) {
02755        PR_fprintf(PR_STDERR,
02756                   "%s -%c: cannot use \"-k all\" for this command.\n",
02757                   progName, commandToRun);
02758        return 255;
02759     }
02760 
02761     /*  -S  open outFile, temporary file for cert request.  */
02762     if (certutil.commands[cmd_CreateAndAddCert].activated) {
02763        outFile = PR_Open(certreqfile, PR_RDWR | PR_CREATE_FILE, 00660);
02764        if (!outFile) {
02765            PR_fprintf(PR_STDERR, 
02766                      "%s -o: unable to open \"%s\" for writing (%ld, %ld)\n",
02767                      progName, certreqfile,
02768                      PR_GetError(), PR_GetOSError());
02769            return 255;
02770        }
02771     }
02772 
02773     /*  Open the input file.  */
02774     if (certutil.options[opt_InputFile].activated) {
02775        inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0);
02776        if (!inFile) {
02777            PR_fprintf(PR_STDERR,
02778                       "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
02779                       progName, certutil.options[opt_InputFile].arg,
02780                       PR_GetError(), PR_GetOSError());
02781            return 255;
02782        }
02783     }
02784 
02785     /*  Open the output file.  */
02786     if (certutil.options[opt_OutputFile].activated && !outFile) {
02787        outFile = PR_Open(certutil.options[opt_OutputFile].arg, 
02788                           PR_CREATE_FILE | PR_RDWR, 00660);
02789        if (!outFile) {
02790            PR_fprintf(PR_STDERR,
02791                       "%s:  unable to open \"%s\" for writing (%ld, %ld).\n",
02792                       progName, certutil.options[opt_OutputFile].arg,
02793                       PR_GetError(), PR_GetOSError());
02794            return 255;
02795        }
02796     }
02797 
02798     name = SECU_GetOptionArg(&certutil, opt_Nickname);
02799 
02800     PK11_SetPasswordFunc(SECU_GetModulePassword);
02801 
02802     if (PR_TRUE == initialize) {
02803         /*  Initialize NSPR and NSS.  */
02804         PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
02805         rv = NSS_Initialize(SECU_ConfigDirectory(NULL), certPrefix, certPrefix,
02806                             "secmod.db", readOnly ? NSS_INIT_READONLY: 0);
02807         if (rv != SECSuccess) {
02808            SECU_PrintPRandOSError(progName);
02809            rv = SECFailure;
02810            goto shutdown;
02811         }
02812         initialized = PR_TRUE;
02813        SECU_RegisterDynamicOids();
02814     }
02815     certHandle = CERT_GetDefaultCertDB();
02816 
02817     if (certutil.commands[cmd_Version].activated) {
02818        printf("Certificate database content version: command not implemented.\n");
02819     }
02820 
02821     if (PL_strcmp(slotname, "internal") == 0)
02822        slot = PK11_GetInternalKeySlot();
02823     else if (slotname != NULL)
02824        slot = PK11_FindSlotByName(slotname);
02825 
02826     /*  If creating new database, initialize the password.  */
02827     if (certutil.commands[cmd_NewDBs].activated) {
02828        SECU_ChangePW(slot, 0, certutil.options[opt_PasswordFile].arg);
02829     }
02830 
02831     /* The following 8 options are mutually exclusive with all others. */
02832 
02833     /*  List certs (-L)  */
02834     if (certutil.commands[cmd_ListCerts].activated) {
02835        rv = ListCerts(certHandle, name, slot,
02836                       certutil.options[opt_BinaryDER].activated,
02837                       certutil.options[opt_ASCIIForIO].activated, 
02838                        (outFile) ? outFile : PR_STDOUT, &pwdata);
02839        goto shutdown;
02840     }
02841     if (certutil.commands[cmd_DumpChain].activated) {
02842        rv = DumpChain(certHandle, name);
02843        goto shutdown;
02844     }
02845     /*  XXX needs work  */
02846     /*  List keys (-K)  */
02847     if (certutil.commands[cmd_ListKeys].activated) {
02848        rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/,
02849                      &pwdata);
02850        goto shutdown;
02851     }
02852     /*  List modules (-U)  */
02853     if (certutil.commands[cmd_ListModules].activated) {
02854        rv = ListModules();
02855        goto shutdown;
02856     }
02857     /*  Delete cert (-D)  */
02858     if (certutil.commands[cmd_DeleteCert].activated) {
02859        rv = DeleteCert(certHandle, name);
02860        goto shutdown;
02861     }
02862     /*  Delete key (-F)  */
02863     if (certutil.commands[cmd_DeleteKey].activated) {
02864        rv = DeleteKey(name, &pwdata);
02865        goto shutdown;
02866     }
02867     /*  Modify trust attribute for cert (-M)  */
02868     if (certutil.commands[cmd_ModifyCertTrust].activated) {
02869        rv = ChangeTrustAttributes(certHandle, name, 
02870                                   certutil.options[opt_Trust].arg);
02871        goto shutdown;
02872     }
02873     /*  Change key db password (-W) (future - change pw to slot?)  */
02874     if (certutil.commands[cmd_ChangePassword].activated) {
02875        rv = SECU_ChangePW(slot, 0, certutil.options[opt_PasswordFile].arg);
02876        goto shutdown;
02877     }
02878     /*  Reset the a token */
02879     if (certutil.commands[cmd_TokenReset].activated) {
02880        char *sso_pass = "";
02881 
02882        if (certutil.options[opt_SSOPass].activated) {
02883            sso_pass = certutil.options[opt_SSOPass].arg;
02884        }
02885        rv = PK11_ResetToken(slot,sso_pass);
02886 
02887        goto shutdown;
02888     }
02889     /*  Check cert validity against current time (-V)  */
02890     if (certutil.commands[cmd_CheckCertValidity].activated) {
02891        /* XXX temporary hack for fips - must log in to get priv key */
02892        if (certutil.options[opt_VerifySig].activated) {
02893            if (slot && PK11_NeedLogin(slot))
02894               PK11_Authenticate(slot, PR_TRUE, &pwdata);
02895        }
02896        rv = ValidateCert(certHandle, name, 
02897                          certutil.options[opt_ValidityTime].arg,
02898                        certutil.options[opt_Usage].arg,
02899                        certutil.options[opt_VerifySig].activated,
02900                        certutil.options[opt_DetailedInfo].activated,
02901                          &pwdata);
02902        goto shutdown;
02903     }
02904 
02905     /*
02906      *  Key generation
02907      */
02908 
02909     /*  These commands require keygen.  */
02910     if (certutil.commands[cmd_CertReq].activated ||
02911         certutil.commands[cmd_CreateAndAddCert].activated ||
02912        certutil.commands[cmd_GenKeyPair].activated) {
02913        /*  XXX Give it a nickname.  */
02914        privkey = 
02915            CERTUTIL_GeneratePrivateKey(keytype, slot, keysize,
02916                                        publicExponent, 
02917                                        certutil.options[opt_NoiseFile].arg,
02918                                        &pubkey, 
02919                                        certutil.options[opt_PQGFile].arg,
02920                                        &pwdata);
02921        if (privkey == NULL) {
02922            SECU_PrintError(progName, "unable to generate key(s)\n");
02923            rv = SECFailure;
02924            goto shutdown;
02925        }
02926        privkey->wincx = &pwdata;
02927        PORT_Assert(pubkey != NULL);
02928 
02929        /*  If all that was needed was keygen, exit.  */
02930        if (certutil.commands[cmd_GenKeyPair].activated) {
02931            rv = SECSuccess;
02932            goto shutdown;
02933        }
02934     }
02935 
02936     /*
02937      *  Certificate request
02938      */
02939 
02940     /*  Make a cert request (-R).  */
02941     if (certutil.commands[cmd_CertReq].activated) {
02942        rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
02943                     certutil.options[opt_PhoneNumber].arg,
02944                     certutil.options[opt_ASCIIForIO].activated,
02945                    certutil.options[opt_ExtendedEmailAddrs].arg,
02946                    certutil.options[opt_ExtendedDNSNames].arg,
02947                      certutil.options[opt_AddKeyUsageExt].activated,
02948                      certutil.options[opt_AddExtKeyUsageExt].activated,
02949                      certutil.options[opt_AddBasicConstraintExt].activated,
02950                      certutil.options[opt_AddAuthorityKeyIDExt].activated,
02951                      certutil.options[opt_AddCRLDistPtsExt].activated,
02952                      certutil.options[opt_AddNSCertTypeExt].activated,
02953                      outFile ? outFile : PR_STDOUT);
02954        if (rv) 
02955            goto shutdown;
02956        privkey->wincx = &pwdata;
02957     }
02958 
02959     /*
02960      *  Certificate creation
02961      */
02962 
02963     /*  If making and adding a cert, create a cert request file first without
02964      *  any extensions, then load it with the command line extensions
02965      *  and output the cert to another file.
02966      */
02967     if (certutil.commands[cmd_CreateAndAddCert].activated) {
02968        rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject,
02969                     certutil.options[opt_PhoneNumber].arg,
02970                     certutil.options[opt_ASCIIForIO].activated,
02971                    NULL,
02972                    NULL,
02973                      PR_FALSE,
02974                      PR_FALSE,
02975                      PR_FALSE,
02976                      PR_FALSE,
02977                      PR_FALSE,
02978                      PR_FALSE,
02979                      outFile ? outFile : PR_STDOUT);
02980        if (rv) 
02981            goto shutdown;
02982        privkey->wincx = &pwdata;
02983        PR_Close(outFile);
02984        inFile  = PR_Open(certreqfile, PR_RDONLY, 0);
02985        if (!inFile) {
02986            PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
02987                        certreqfile, PR_GetError(), PR_GetOSError());
02988            rv = SECFailure;
02989            goto shutdown;
02990        }
02991        outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE, 00660);
02992        if (!outFile) {
02993            PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
02994                        certfile, PR_GetError(), PR_GetOSError());
02995            rv = SECFailure;
02996            goto shutdown;
02997        }
02998     }
02999 
03000     /*  Create a certificate (-C or -S).  */
03001     if (certutil.commands[cmd_CreateAndAddCert].activated ||
03002          certutil.commands[cmd_CreateNewCert].activated) {
03003        rv = CreateCert(certHandle, 
03004                        certutil.options[opt_IssuerName].arg,
03005                        inFile, outFile, privkey, &pwdata, hashAlgTag,
03006                        serialNumber, warpmonths, validityMonths,
03007                       certutil.options[opt_ExtendedEmailAddrs].arg,
03008                       certutil.options[opt_ExtendedDNSNames].arg,
03009                        certutil.options[opt_ASCIIForIO].activated,
03010                        certutil.options[opt_SelfSign].activated,
03011                        certutil.options[opt_AddKeyUsageExt].activated,
03012                        certutil.options[opt_AddExtKeyUsageExt].activated,
03013                        certutil.options[opt_AddBasicConstraintExt].activated,
03014                        certutil.options[opt_AddAuthorityKeyIDExt].activated,
03015                        certutil.options[opt_AddCRLDistPtsExt].activated,
03016                        certutil.options[opt_AddNSCertTypeExt].activated);
03017        if (rv) 
03018            goto shutdown;
03019     }
03020 
03021     /* 
03022      * Adding a cert to the database (or slot)
03023      */
03024  
03025     if (certutil.commands[cmd_CreateAndAddCert].activated) { 
03026        PORT_Assert(inFile != PR_STDIN);
03027        PR_Close(inFile);
03028        PR_Close(outFile);
03029        inFile = PR_Open(certfile, PR_RDONLY, 0);
03030        if (!inFile) {
03031            PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n",
03032                        certfile, PR_GetError(), PR_GetOSError());
03033            rv = SECFailure;
03034            goto shutdown;
03035        }
03036     }
03037 
03038     /* -A -E or -S    Add the cert to the DB */
03039     if (certutil.commands[cmd_CreateAndAddCert].activated ||
03040          certutil.commands[cmd_AddCert].activated ||
03041         certutil.commands[cmd_AddEmailCert].activated) {
03042        rv = AddCert(slot, certHandle, name, 
03043                     certutil.options[opt_Trust].arg,
03044                     inFile, 
03045                     certutil.options[opt_ASCIIForIO].activated,
03046                     certutil.commands[cmd_AddEmailCert].activated,&pwdata);
03047        if (rv) 
03048            goto shutdown;
03049     }
03050 
03051     if (certutil.commands[cmd_CreateAndAddCert].activated) {
03052        PORT_Assert(inFile != PR_STDIN);
03053        PR_Close(inFile);
03054        PR_Delete(certfile);
03055        PR_Delete(certreqfile);
03056     }
03057 
03058 shutdown:
03059     if (slot) {
03060        PK11_FreeSlot(slot);
03061     }
03062     if (privkey) {
03063        SECKEY_DestroyPrivateKey(privkey);
03064     }
03065     if (pubkey) {
03066        SECKEY_DestroyPublicKey(pubkey);
03067     }
03068 
03069     /* Open the batch command file.
03070      *
03071      * - If -B <command line> option is specified, the contents in the
03072      * command file will be interpreted as subsequent certutil
03073      * commands to be executed in the current certutil process
03074      * context after the current certutil command has been executed.
03075      * - Each line in the command file consists of the command
03076      * line arguments for certutil.
03077      * - The -d <configdir> option will be ignored if specified in the
03078      * command file.
03079      * - Quoting with double quote characters ("...") is supported
03080      * to allow white space in a command line argument.  The
03081      * double quote character cannot be escaped and quoting cannot
03082      * be nested in this version.
03083      * - each line in the batch file is limited to 512 characters
03084     */
03085 
03086     if ((SECSuccess == rv) && certutil.commands[cmd_Batch].activated) {
03087        FILE* batchFile = NULL;
03088         char nextcommand[512];
03089         if (!certutil.options[opt_InputFile].activated ||
03090             !certutil.options[opt_InputFile].arg) {
03091            PR_fprintf(PR_STDERR,
03092                       "%s:  no batch input file specified.\n",
03093                       progName);
03094            return 255;
03095         }
03096         batchFile = fopen(certutil.options[opt_InputFile].arg, "r");
03097         if (!batchFile) {
03098            PR_fprintf(PR_STDERR,
03099                       "%s:  unable to open \"%s\" for reading (%ld, %ld).\n",
03100                       progName, certutil.options[opt_InputFile].arg,
03101                       PR_GetError(), PR_GetOSError());
03102            return 255;
03103         }
03104         /* read and execute command-lines in a loop */
03105         while ( (SECSuccess == rv ) &&
03106                 fgets(nextcommand, sizeof(nextcommand), batchFile)) {
03107             /* we now need to split the command into argc / argv format */
03108             char* commandline = PORT_Strdup(nextcommand);
03109             PRBool invalid = PR_FALSE;
03110             int newargc = 2;
03111             char* space = NULL;
03112             char* nextarg = NULL;
03113             char** newargv = NULL;
03114             char* crlf = PORT_Strrchr(commandline, '\n');
03115             if (crlf) {
03116                 *crlf = '\0';
03117             }
03118 
03119             newargv = PORT_Alloc(sizeof(char*)*(newargc+1));
03120             newargv[0] = progName;
03121             newargv[1] = commandline;
03122             nextarg = commandline;
03123             while ((space = PORT_Strpbrk(nextarg, " \f\n\r\t\v")) ) {
03124                 while (isspace(*space) ) {
03125                     *space = '\0';
03126                     space ++;
03127                 }
03128                 if (*space == '\0') {
03129                     break;
03130                 } else if (*space != '\"') {
03131                     nextarg = space;
03132                 } else {
03133                     char* closingquote = strchr(space+1, '\"');
03134                     if (closingquote) {
03135                         *closingquote = '\0';
03136                         space++;
03137                         nextarg = closingquote+1;
03138                     } else {
03139                         invalid = PR_TRUE;
03140                         nextarg = space;
03141                     }
03142                 }
03143                 newargc++;
03144                 newargv = PORT_Realloc(newargv, sizeof(char*)*(newargc+1));
03145                 newargv[newargc-1] = space;
03146             }
03147             newargv[newargc] = NULL;
03148             
03149             /* invoke next command */
03150             if (PR_TRUE == invalid) {
03151                 PR_fprintf(PR_STDERR, "Missing closing quote in batch command :\n%s\nNot executed.\n",
03152                            nextcommand);
03153                 rv = SECFailure;
03154             } else {
03155                 if (0 != certutil_main(newargc, newargv, PR_FALSE) )
03156                     rv = SECFailure;
03157             }
03158             PORT_Free(newargv);
03159             PORT_Free(commandline);
03160         }
03161         fclose(batchFile);
03162     }
03163 
03164     if ((initialized == PR_TRUE) && NSS_Shutdown() != SECSuccess) {
03165         exit(1);
03166     }
03167 
03168     if (rv == SECSuccess) {
03169        return 0;
03170     } else {
03171        return 255;
03172     }
03173 }
03174 
03175 int
03176 main(int argc, char **argv)
03177 {
03178     return certutil_main(argc, argv, PR_TRUE);
03179 }