Back to index

lightning-sunbird  0.9+nobinonly
crlutil.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  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038 ** certutil.c
00039 **
00040 ** utility for managing certificates and the cert database
00041 **
00042 */
00043 /* test only */
00044 
00045 #include "nspr.h"
00046 #include "plgetopt.h"
00047 #include "secutil.h"
00048 #include "cert.h"
00049 #include "certi.h"
00050 #include "certdb.h"
00051 #include "nss.h"
00052 #include "pk11func.h"
00053 #include "crlgen.h"
00054 
00055 #define SEC_CERT_DB_EXISTS 0
00056 #define SEC_CREATE_CERT_DB 1
00057 
00058 static char *progName;
00059 
00060 static CERTSignedCrl *FindCRL
00061    (CERTCertDBHandle *certHandle, char *name, int type)
00062 {
00063     CERTSignedCrl *crl = NULL;    
00064     CERTCertificate *cert = NULL;
00065     SECItem derName;
00066 
00067     derName.data = NULL;
00068     derName.len = 0;
00069 
00070     cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name);
00071     if (!cert) {
00072         CERTName *certName = NULL;
00073         PRArenaPool *arena = NULL;
00074     
00075         certName = CERT_AsciiToName(name);
00076         if (certName) {
00077             arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00078             if (arena) {
00079                 SECItem *nameItem = 
00080                     SEC_ASN1EncodeItem (arena, NULL, (void *)certName,
00081                                         SEC_ASN1_GET(CERT_NameTemplate));
00082                 if (nameItem) {
00083                     SECITEM_CopyItem(NULL, &derName, nameItem);
00084                 }
00085                 PORT_FreeArena(arena, PR_FALSE);
00086             }
00087             CERT_DestroyName(certName);
00088         }
00089 
00090         if (!derName.len || !derName.data) {
00091             SECU_PrintError(progName, "could not find certificate named '%s'", name);
00092             return ((CERTSignedCrl *)NULL);
00093         }
00094     } else {
00095         SECITEM_CopyItem(NULL, &derName, &cert->derSubject);
00096         CERT_DestroyCertificate (cert);
00097     }
00098  
00099     crl = SEC_FindCrlByName(certHandle, &derName, type);
00100     if (crl ==NULL) 
00101        SECU_PrintError
00102               (progName, "could not find %s's CRL", name);
00103     if (derName.data) {
00104         SECITEM_FreeItem(&derName, PR_FALSE);
00105     }
00106     return (crl);
00107 }
00108 
00109 static void DisplayCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType)
00110 {
00111     CERTSignedCrl *crl = NULL;
00112 
00113     crl = FindCRL (certHandle, nickName, crlType);
00114        
00115     if (crl) {
00116        SECU_PrintCRLInfo (stdout, &crl->crl, "CRL Info:\n", 0);
00117        SEC_DestroyCrl (crl);
00118     }
00119 }
00120 
00121 static void ListCRLNames (CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls)
00122 {
00123     CERTCrlHeadNode *crlList = NULL;
00124     CERTCrlNode *crlNode = NULL;
00125     CERTName *name = NULL;
00126     PRArenaPool *arena = NULL;
00127     SECStatus rv;
00128 
00129     do {
00130        arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
00131        if (arena == NULL) {
00132            fprintf(stderr, "%s: fail to allocate memory\n", progName);
00133            break;
00134        }
00135        
00136        name = PORT_ArenaZAlloc (arena, sizeof(*name));
00137        if (name == NULL) {
00138            fprintf(stderr, "%s: fail to allocate memory\n", progName);
00139            break;
00140        }
00141        name->arena = arena;
00142            
00143        rv = SEC_LookupCrls (certHandle, &crlList, crlType);
00144        if (rv != SECSuccess) {
00145            fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName,
00146            SECU_Strerror(PORT_GetError()));
00147            break;
00148        }
00149        
00150        /* just in case */
00151        if (!crlList)
00152            break;
00153 
00154        crlNode  = crlList->first;
00155 
00156         fprintf (stdout, "\n");
00157        fprintf (stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type");
00158        while (crlNode) {
00159            char* asciiname = NULL;
00160            CERTCertificate *cert = NULL;
00161            if (crlNode->crl && &crlNode->crl->crl.derName) {
00162                cert = CERT_FindCertByName(certHandle, 
00163                                           &crlNode->crl->crl.derName);
00164                if (!cert) {
00165                    SECU_PrintError(progName, "could not find signing "
00166                                 "certificate in database");
00167                }
00168            }
00169            if (cert) {
00170                char* certName = NULL;
00171                  if (cert->nickname && PORT_Strlen(cert->nickname) > 0) {
00172                    certName = cert->nickname;
00173                } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) {
00174                    certName = cert->emailAddr;
00175                }
00176                if (certName) {
00177                    asciiname = PORT_Strdup(certName);
00178                }
00179                CERT_DestroyCertificate(cert);
00180            }
00181                 
00182            if (!asciiname) {
00183                name = &crlNode->crl->crl.name;
00184                if (!name){
00185                    SECU_PrintError(progName, "fail to get the CRL "
00186                                   "issuer name");
00187                    continue;
00188                }
00189                asciiname = CERT_NameToAscii(name);
00190            }
00191            fprintf (stdout, "%-40s %-5s\n", asciiname, "CRL");
00192            if (asciiname) {
00193               PORT_Free(asciiname);
00194            }
00195             if ( PR_TRUE == deletecrls) {
00196                 CERTSignedCrl* acrl = NULL;
00197                 SECItem* issuer = &crlNode->crl->crl.derName;
00198                 acrl = SEC_FindCrlByName(certHandle, issuer, crlType);
00199                 if (acrl)
00200                 {
00201                     SEC_DeletePermCRL(acrl);
00202                     SEC_DestroyCrl(acrl);
00203                 }
00204             }
00205             crlNode = crlNode->next;
00206        } 
00207        
00208     } while (0);
00209     if (crlList)
00210        PORT_FreeArena (crlList->arena, PR_FALSE);
00211     PORT_FreeArena (arena, PR_FALSE);
00212 }
00213 
00214 static void ListCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType)
00215 {
00216     if (nickName == NULL)
00217        ListCRLNames (certHandle, crlType, PR_FALSE);
00218     else
00219        DisplayCRL (certHandle, nickName, crlType);
00220 }
00221 
00222 
00223 
00224 static SECStatus DeleteCRL (CERTCertDBHandle *certHandle, char *name, int type)
00225 {
00226     CERTSignedCrl *crl = NULL;    
00227     SECStatus rv = SECFailure;
00228 
00229     crl = FindCRL (certHandle, name, type);
00230     if (!crl) {
00231        SECU_PrintError
00232               (progName, "could not find the issuer %s's CRL", name);
00233        return SECFailure;
00234     }
00235     rv = SEC_DeletePermCRL (crl);
00236     SEC_DestroyCrl(crl);
00237     if (rv != SECSuccess) {
00238        SECU_PrintError(progName, "fail to delete the issuer %s's CRL "
00239                        "from the perm database (reason: %s)",
00240                        name, SECU_Strerror(PORT_GetError()));
00241        return SECFailure;
00242     }
00243     return (rv);
00244 }
00245 
00246 SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type, 
00247                      PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions)
00248 {
00249     CERTSignedCrl *crl = NULL;
00250     SECItem crlDER;
00251     PK11SlotInfo* slot = NULL;
00252     int rv;
00253 #if defined(DEBUG_jpierre)
00254     PRIntervalTime starttime, endtime, elapsed;
00255     PRUint32 mins, secs, msecs;
00256 #endif
00257 
00258     crlDER.data = NULL;
00259 
00260 
00261     /* Read in the entire file specified with the -f argument */
00262     rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE);
00263     if (rv != SECSuccess) {
00264        SECU_PrintError(progName, "unable to read input file");
00265        return (SECFailure);
00266     }
00267 
00268     decodeOptions |= CRL_DECODE_DONT_COPY_DER;
00269 
00270     slot = PK11_GetInternalKeySlot();
00271  
00272 #if defined(DEBUG_jpierre)
00273     starttime = PR_IntervalNow();
00274 #endif
00275     crl = PK11_ImportCRL(slot, &crlDER, url, type,
00276           NULL, importOptions, NULL, decodeOptions);
00277 #if defined(DEBUG_jpierre)
00278     endtime = PR_IntervalNow();
00279     elapsed = endtime - starttime;
00280     mins = PR_IntervalToSeconds(elapsed) / 60;
00281     secs = PR_IntervalToSeconds(elapsed) % 60;
00282     msecs = PR_IntervalToMilliseconds(elapsed) % 1000;
00283     printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs);
00284 #endif
00285     if (!crl) {
00286        const char *errString;
00287 
00288        rv = SECFailure;
00289        errString = SECU_Strerror(PORT_GetError());
00290        if ( errString && PORT_Strlen (errString) == 0)
00291            SECU_PrintError (progName, 
00292                "CRL is not imported (error: input CRL is not up to date.)");
00293        else    
00294            SECU_PrintError (progName, "unable to import CRL");
00295     } else {
00296        SEC_DestroyCrl (crl);
00297     }
00298     if (slot) {
00299         PK11_FreeSlot(slot);
00300     }
00301     return (rv);
00302 }
00303 
00304 
00305 static CERTCertificate*
00306 FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl,
00307                 char *certNickName)
00308 {                   
00309     CERTCertificate *cert = NULL, *certTemp = NULL;
00310     SECStatus rv = SECFailure;
00311     CERTAuthKeyID* authorityKeyID = NULL;
00312     SECItem* subject = NULL;
00313 
00314     PORT_Assert(certHandle != NULL);
00315     if (!certHandle || (!signCrl && !certNickName)) {
00316         SECU_PrintError(progName, "invalid args for function "
00317                         "FindSigningCert \n");
00318         return NULL;
00319     }
00320 
00321     if (signCrl) {
00322 #if 0
00323         authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl);
00324 #endif
00325         subject = &signCrl->crl.derName;
00326     } else {
00327         certTemp = CERT_FindCertByNickname(certHandle, certNickName);
00328         if (!certTemp) {
00329             SECU_PrintError(progName, "could not find certificate \"%s\" "
00330                             "in database", certNickName);
00331             goto loser;
00332         }
00333         subject = &certTemp->derSubject;
00334     }
00335 
00336     cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now());
00337     if (!cert) {
00338         SECU_PrintError(progName, "could not find signing certificate "
00339                         "in database");
00340         goto loser;
00341     } else {
00342         rv = SECSuccess;
00343     }
00344 
00345   loser:
00346     if (certTemp)
00347         CERT_DestroyCertificate(certTemp);
00348     if (cert && rv != SECSuccess)
00349         CERT_DestroyCertificate(cert);
00350     return cert;
00351 }
00352 
00353 static CERTSignedCrl*
00354 DuplicateModCrl(PRArenaPool *arena, CERTCertDBHandle *certHandle,
00355                 CERTCertificate **cert, char *certNickName,
00356                 PRFileDesc *inFile, PRInt32 decodeOptions,
00357                 PRInt32 importOptions)
00358 {
00359     SECItem crlDER;
00360     CERTSignedCrl *signCrl = NULL;
00361     CERTSignedCrl *modCrl = NULL;
00362     PRArenaPool *modArena = NULL;
00363     SECStatus rv = SECSuccess;
00364 
00365     PORT_Assert(arena != NULL && certHandle != NULL &&
00366                 certNickName != NULL);
00367     if (!arena || !certHandle || !certNickName) {
00368         SECU_PrintError(progName, "DuplicateModCrl: invalid args\n");
00369         return NULL;
00370     }
00371 
00372     modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
00373     if (!modArena) {
00374         SECU_PrintError(progName, "fail to allocate memory\n");
00375         return NULL;
00376     }
00377     
00378     if (inFile != NULL) {
00379         rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE);
00380         if (rv != SECSuccess) {
00381             SECU_PrintError(progName, "unable to read input file");
00382             PORT_FreeArena(modArena, PR_FALSE);
00383             goto loser;
00384         }
00385         
00386         decodeOptions |= CRL_DECODE_DONT_COPY_DER;
00387         
00388         modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE,
00389                                             decodeOptions);
00390         if (!modCrl) {
00391             SECU_PrintError(progName, "fail to decode CRL");
00392             goto loser;
00393         }
00394         
00395         if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){
00396             /* If caCert is a v2 certificate, make sure that it
00397              * can be used for crl signing purpose */
00398             *cert = FindSigningCert(certHandle, modCrl, NULL);
00399             if (!*cert) {
00400                 goto loser;
00401             }
00402 
00403             rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert,
00404                                        PR_Now(), NULL);
00405             if (rv != SECSuccess) {
00406                 SECU_PrintError(progName, "fail to verify signed data\n");
00407                 goto loser;
00408             }
00409         }
00410     } else {
00411         modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE);
00412         if (!modCrl) {
00413             SECU_PrintError(progName, "fail to find crl %s in database\n",
00414                             certNickName);
00415             goto loser;
00416         }
00417     }
00418 
00419     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
00420     if (signCrl == NULL) {
00421         SECU_PrintError(progName, "fail to allocate memory\n");
00422         goto loser;
00423     }
00424 
00425     rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl);
00426     if (rv != SECSuccess) {
00427         SECU_PrintError(progName, "unable to dublicate crl for "
00428                         "modification.");
00429         goto loser;
00430     }  
00431 
00432     signCrl->arena = arena;    
00433 
00434   loser:
00435     SECITEM_FreeItem(&crlDER, PR_FALSE);
00436     if (modCrl)
00437         SEC_DestroyCrl(modCrl);
00438     if (rv != SECSuccess && signCrl) {
00439         SEC_DestroyCrl(signCrl);
00440         signCrl = NULL;
00441     }
00442     return signCrl;
00443 }
00444 
00445 
00446 static CERTSignedCrl*
00447 CreateNewCrl(PRArenaPool *arena, CERTCertDBHandle *certHandle,
00448              CERTCertificate *cert)
00449 { 
00450     CERTSignedCrl *signCrl = NULL;
00451     void *dummy = NULL;
00452     SECStatus rv;
00453     void* mark = NULL;
00454 
00455     /* if the CERTSignedCrl structure changes, this function will need to be
00456        updated as well */
00457     PORT_Assert(cert != NULL);
00458     if (!cert || !arena) {
00459         SECU_PrintError(progName, "invalid args for function "
00460                         "CreateNewCrl\n");
00461         return NULL;
00462     }
00463 
00464     mark = PORT_ArenaMark(arena);
00465         
00466     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
00467     if (signCrl == NULL) {
00468         SECU_PrintError(progName, "fail to allocate memory\n");
00469         return NULL;
00470     }
00471 
00472     dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version,
00473                                   SEC_CRL_VERSION_2);
00474     /* set crl->version */
00475     if (!dummy) {
00476         SECU_PrintError(progName, "fail to create crl version data "
00477                         "container\n");
00478         goto loser;
00479     }
00480     
00481     /* copy SECItem name from cert */
00482     rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject);
00483     if (rv != SECSuccess) {
00484         SECU_PrintError(progName, "fail to duplicate der name from "
00485                         "certificate.\n");
00486         goto loser;
00487     }
00488         
00489     /* copy CERTName name structure from cert issuer */
00490     rv = CERT_CopyName (arena, &signCrl->crl.name, &cert->subject);
00491     if (rv != SECSuccess) {
00492         SECU_PrintError(progName, "fail to duplicate RD name from "
00493                         "certificate.\n");
00494         goto loser;
00495     }
00496 
00497     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
00498     if (rv != SECSuccess) {
00499         SECU_PrintError(progName, "fail to encode current time\n");
00500         goto loser;
00501     }
00502 
00503     /* set fields */
00504     signCrl->arena = arena;
00505     signCrl->dbhandle = certHandle;
00506     signCrl->crl.arena = arena;
00507 
00508     return signCrl;
00509 
00510   loser:
00511     PORT_ArenaRelease(arena, mark);
00512     return NULL;
00513 }
00514 
00515 
00516 static SECStatus
00517 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
00518 {
00519     CRLGENGeneratorData *crlGenData = NULL;
00520     SECStatus rv;
00521     
00522     PORT_Assert(signCrl != NULL && inCrlInitFile != NULL);
00523     if (!signCrl || !inCrlInitFile) {
00524         SECU_PrintError(progName, "invalid args for function "
00525                         "CreateNewCrl\n");
00526         return SECFailure;
00527     }
00528 
00529     crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
00530     if (!crlGenData) {
00531        SECU_PrintError(progName, "can not initialize parser structure.\n");
00532        return SECFailure;
00533     }
00534 
00535     rv = CRLGEN_ExtHandleInit(crlGenData);
00536     if (rv == SECFailure) {
00537        SECU_PrintError(progName, "can not initialize entries handle.\n");
00538        goto loser;
00539     }
00540        
00541     rv = CRLGEN_StartCrlGen(crlGenData);
00542     if (rv != SECSuccess) {
00543        SECU_PrintError(progName, "crl generation failed");
00544        goto loser;
00545     }
00546 
00547   loser:
00548     /* CommitExtensionsAndEntries is partially responsible for freeing
00549      * up memory that was used for CRL generation. Should be called regardless
00550      * of previouse call status, but only after initialization of
00551      * crlGenData was done. It will commit all changes that was done before
00552      * an error has occured.
00553      */
00554     if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) {
00555         SECU_PrintError(progName, "crl generation failed");
00556         rv = SECFailure;
00557     }
00558     CRLGEN_FinalizeCrlGeneration(crlGenData);    
00559     return rv;
00560 }
00561 
00562 static SECStatus
00563 SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert,
00564                 char *outFileName, SECOidTag hashAlgTag, int ascii,
00565                 char *slotName, char *url, secuPWData *pwdata)
00566 {
00567     PK11SlotInfo *slot = NULL;
00568     PRFileDesc   *outFile = NULL;
00569     SECStatus rv;
00570     SignAndEncodeFuncExitStat errCode;
00571 
00572     PORT_Assert(signCrl && (!ascii || outFileName));
00573     if (!signCrl || (ascii && !outFileName)) {
00574         SECU_PrintError(progName, "invalid args for function "
00575                         "SignAndStoreCrl\n");
00576         return SECFailure;
00577     }
00578 
00579     if (!slotName || !PL_strcmp(slotName, "internal"))
00580        slot = PK11_GetInternalKeySlot();
00581     else
00582        slot = PK11_FindSlotByName(slotName);
00583     if (!slot) {
00584        SECU_PrintError(progName, "can not find requested slot");
00585        return SECFailure;
00586     }
00587 
00588     if (PK11_NeedLogin(slot)) {
00589         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
00590        if (rv != SECSuccess)
00591            goto loser;
00592     }
00593 
00594     rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
00595     if (rv != SECSuccess) {
00596         char* errMsg = NULL;
00597         switch (errCode)
00598         {
00599             case noKeyFound:
00600                 errMsg = "No private key found of signing cert";
00601                 break;
00602 
00603             case noSignatureMatch:
00604                 errMsg = "Key and Algorithm OId are do not match";
00605                 break;
00606 
00607             default:
00608             case failToEncode:
00609                 errMsg = "Failed to encode crl structure";
00610                 break;
00611 
00612             case failToSign:
00613                 errMsg = "Failed to sign crl structure";
00614                 break;
00615 
00616             case noMem:
00617                 errMsg = "Can not allocate memory";
00618                 break;
00619         }
00620        SECU_PrintError(progName, "%s\n", errMsg);
00621        goto loser;
00622     }
00623 
00624     if (outFileName) {
00625        outFile = PR_Open(outFileName, PR_WRONLY|PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
00626        if (!outFile) {
00627            SECU_PrintError(progName, "unable to open \"%s\" for writing\n",
00628                          outFileName);
00629            goto loser;
00630        }
00631     }
00632 
00633     rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
00634     if (rv != SECSuccess) {
00635         SECU_PrintError(progName, "fail to save CRL\n");
00636     }
00637 
00638   loser:
00639     if (outFile)
00640        PR_Close(outFile);
00641     if (slot)
00642        PK11_FreeSlot(slot);
00643     return rv;
00644 }
00645 
00646 static SECStatus
00647 GenerateCRL (CERTCertDBHandle *certHandle, char *certNickName, 
00648             PRFileDesc *inCrlInitFile,  PRFileDesc *inFile,
00649             char *outFileName, int ascii, char *slotName,
00650             PRInt32 importOptions, char *alg, PRBool quiet,
00651              PRInt32 decodeOptions, char *url, secuPWData *pwdata,
00652              int modifyFlag)
00653 {
00654     CERTCertificate *cert = NULL;
00655     CERTSignedCrl *signCrl = NULL;
00656     PRArenaPool *arena = NULL;
00657     SECStatus rv;
00658     SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
00659 
00660     if (alg) {
00661         hashAlgTag = SECU_StringToSignatureAlgTag(alg);
00662         if (hashAlgTag == SEC_OID_UNKNOWN) {
00663             SECU_PrintError(progName, "%s -Z:  %s is not a recognized type.\n",
00664                             progName, alg);
00665             return SECFailure;
00666         }
00667     } else {
00668         hashAlgTag = SEC_OID_UNKNOWN;
00669     }
00670 
00671     arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
00672     if (!arena) {
00673         SECU_PrintError(progName, "fail to allocate memory\n");
00674         return SECFailure;
00675     }
00676 
00677     if (modifyFlag == PR_TRUE) {
00678         signCrl = DuplicateModCrl(arena, certHandle, &cert, certNickName,
00679                                          inFile, decodeOptions, importOptions);
00680         if (signCrl == NULL) {
00681             goto loser;
00682         }
00683     }
00684 
00685     if (!cert) {
00686         cert = FindSigningCert(certHandle, signCrl, certNickName);
00687         if (cert == NULL) {
00688             goto loser;
00689         }
00690     }
00691 
00692     if (!signCrl) {
00693         if (modifyFlag == PR_TRUE) {
00694             if (!outFileName) {
00695                 int len = strlen(certNickName) + 5;
00696                 outFileName = PORT_ArenaAlloc(arena, len);
00697                 PR_snprintf(outFileName, len, "%s.crl", certNickName);
00698             }
00699             SECU_PrintError(progName, "Will try to generate crl. "
00700                             "It will be saved in file: %s",
00701                             outFileName);
00702         }
00703         signCrl = CreateNewCrl(arena, certHandle, cert);
00704         if (!signCrl)
00705             goto loser;
00706     }
00707 
00708     rv = UpdateCrl(signCrl, inCrlInitFile);
00709     if (rv != SECSuccess) {
00710         goto loser;
00711     }
00712 
00713     rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
00714                          slotName, url, pwdata);
00715     if (rv != SECSuccess) {
00716         goto loser;
00717     }
00718 
00719     if (signCrl && !quiet) {
00720        SECU_PrintCRLInfo (stdout, &signCrl->crl, "CRL Info:\n", 0);
00721     }
00722 
00723   loser:
00724     if (arena && (!signCrl || !signCrl->arena))
00725         PORT_FreeArena (arena, PR_FALSE);
00726     if (signCrl)
00727        SEC_DestroyCrl (signCrl);
00728     if (cert)
00729        CERT_DestroyCertificate (cert);
00730     return (rv);
00731 }
00732 
00733 static void Usage(char *progName)
00734 {
00735     fprintf(stderr,
00736            "Usage:  %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
00737            "        %s -D -n nickname [-d keydir] [-P dbprefix]\n"
00738            "        %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
00739             "[-p pwd-file] -w [pwd-string]\n"
00740            "        %s -E -t crlType [-d keydir] [-P dbprefix]\n"
00741            "        %s -T\n"
00742            "        %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
00743             "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
00744             "[-a] [-B]\n",
00745            progName, progName, progName, progName, progName, progName);
00746 
00747     fprintf (stderr, "%-15s List CRL\n", "-L");
00748     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
00749            "-n nickname");
00750     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00751            "-d keydir");
00752     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00753            "-P dbprefix");
00754    
00755     fprintf (stderr, "%-15s Delete a CRL from the cert database\n", "-D");    
00756     fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n",
00757            "-n nickname");
00758     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
00759     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00760            "-d keydir");
00761     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00762            "-P dbprefix");
00763 
00764     fprintf (stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E");
00765     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
00766     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00767            "-d keydir");
00768     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00769            "-P dbprefix");
00770 
00771     fprintf (stderr, "%-15s Import a CRL to the cert database\n", "-I");    
00772     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
00773            "-i crl");
00774     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
00775     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
00776     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00777            "-d keydir");
00778     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00779            "-P dbprefix");
00780 #ifdef DEBUG
00781     fprintf (stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T");
00782 #endif
00783     fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " ");
00784     fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " ");
00785     fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " ");        
00786     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
00787     fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
00788     fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
00789     fprintf(stderr, "\n%-15s Create CRL\n", "-G");
00790     fprintf(stderr, "%-15s Modify CRL\n", "-M");
00791     fprintf(stderr, "%-20s Specify crl initialization file\n",
00792            "-c crl-conf-file");
00793     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
00794            "-n nickname");
00795     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
00796            "-i crl");
00797     fprintf(stderr, "%-20s Specify a CRL output file\n",
00798            "-o crl-output-file");
00799     fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
00800            "-a");
00801     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00802            "-d keydir");
00803     fprintf(stderr, "%-20s Provide path to a default pwd file\n",
00804            "-f pwd-file");
00805     fprintf(stderr, "%-20s Provide db password in command line\n",
00806            "-w pwd-string");
00807     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00808            "-P dbprefix");
00809     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
00810     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
00811 
00812     exit(-1);
00813 }
00814 
00815 int main(int argc, char **argv)
00816 {
00817     SECItem privKeyDER;
00818     CERTCertDBHandle *certHandle;
00819     FILE *certFile;
00820     PRFileDesc *inFile;
00821     PRFileDesc *inCrlInitFile = NULL;
00822     int generateCRL;
00823     int modifyCRL;
00824     int listCRL;
00825     int importCRL;
00826     int deleteCRL;
00827     int rv;
00828     char *nickName;
00829     char *url;
00830     char *dbPrefix = "";
00831     char *alg = NULL;
00832     char *outFile = NULL;
00833     char *slotName = NULL;
00834     int ascii = 0;
00835     int crlType;
00836     PLOptState *optstate;
00837     PLOptStatus status;
00838     SECStatus secstatus;
00839     PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
00840     PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
00841     PRBool quiet = PR_FALSE;
00842     PRBool test = PR_FALSE;
00843     PRBool erase = PR_FALSE;
00844     PRInt32 i = 0;
00845     PRInt32 iterations = 1;
00846 
00847     secuPWData  pwdata          = { PW_NONE, 0 };
00848 
00849     progName = strrchr(argv[0], '/');
00850     progName = progName ? progName+1 : argv[0];
00851 
00852     rv = 0;
00853     deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = 0;
00854     certFile = NULL;
00855     inFile = NULL;
00856     nickName = url = NULL;
00857     privKeyDER.data = NULL;
00858     certHandle = NULL;
00859     crlType = SEC_CRL_TYPE;
00860     /*
00861      * Parse command line arguments
00862      */
00863     optstate = PL_CreateOptState(argc, argv, "sqBCDGILMTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
00864     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
00865        switch (optstate->option) {
00866          case '?':
00867            Usage(progName);
00868            break;
00869 
00870           case 'T':
00871             test = PR_TRUE;
00872             break;
00873 
00874           case 'E':
00875             erase = PR_TRUE;
00876             break;
00877 
00878          case 'B':
00879             importOptions |= CRL_IMPORT_BYPASS_CHECKS;
00880             break;
00881 
00882          case 'G':
00883            generateCRL = 1;
00884            break;
00885 
00886           case 'M':
00887             modifyCRL = 1;
00888             break;
00889 
00890          case 'D':
00891              deleteCRL = 1;
00892              break;
00893 
00894          case 'I':
00895              importCRL = 1;
00896              break;
00897                   
00898          case 'C':
00899          case 'L':
00900              listCRL = 1;
00901              break;
00902 
00903          case 'P':
00904            dbPrefix = strdup(optstate->value);
00905            break;
00906               
00907          case 'Z':
00908               alg = strdup(optstate->value);
00909               break;
00910               
00911          case 'a':
00912              ascii = 1;
00913              break;
00914 
00915          case 'c':
00916               inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
00917               if (!inCrlInitFile) {
00918                   PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
00919                              progName, optstate->value);
00920                   PL_DestroyOptState(optstate);
00921                   return -1;
00922               }
00923               break;
00924            
00925          case 'd':
00926               SECU_ConfigDirectory(optstate->value);
00927               break;
00928 
00929          case 'f':
00930              pwdata.source = PW_FROMFILE;
00931              pwdata.data = strdup(optstate->value);
00932              break;
00933 
00934          case 'h':
00935               slotName = strdup(optstate->value);
00936               break;
00937 
00938          case 'i':
00939            inFile = PR_Open(optstate->value, PR_RDONLY, 0);
00940            if (!inFile) {
00941               PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
00942                      progName, optstate->value);
00943               PL_DestroyOptState(optstate);
00944               return -1;
00945            }
00946            break;
00947            
00948          case 'n':
00949            nickName = strdup(optstate->value);
00950            break;
00951 
00952          case 'o':
00953            outFile = strdup(optstate->value);
00954            break;
00955            
00956          case 'p':
00957            decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
00958            break;
00959 
00960          case 'r': {
00961            const char* str = optstate->value;
00962            if (str && atoi(str)>0)
00963               iterations = atoi(str);
00964            }
00965            break;
00966            
00967          case 't': {
00968            char *type;
00969            
00970            type = strdup(optstate->value);
00971            crlType = atoi (type);
00972            if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
00973               PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
00974               PL_DestroyOptState(optstate);
00975               return -1;
00976            }
00977            break;
00978 
00979          case 'q':
00980             quiet = PR_TRUE;
00981            break;
00982 
00983          case 'w':
00984              pwdata.source = PW_PLAINTEXT;
00985              pwdata.data = strdup(optstate->value);
00986              break;
00987 
00988          case 'u':
00989            url = strdup(optstate->value);
00990            break;
00991 
00992           }
00993        }
00994     }
00995     PL_DestroyOptState(optstate);
00996 
00997     if (deleteCRL && !nickName) Usage (progName);
00998     if (importCRL && !inFile) Usage (progName);
00999     if ((generateCRL && !nickName) ||
01000         (modifyCRL && !inFile && !nickName)) Usage (progName);
01001     if (!(listCRL || deleteCRL || importCRL || generateCRL ||
01002          modifyCRL || test || erase)) Usage (progName);
01003     
01004     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
01005 
01006     PK11_SetPasswordFunc(SECU_GetModulePassword);
01007 
01008     secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
01009                             "secmod.db", 0);
01010     if (secstatus != SECSuccess) {
01011        SECU_PrintPRandOSError(progName);
01012        return -1;
01013     }
01014     SECU_RegisterDynamicOids();
01015 
01016     certHandle = CERT_GetDefaultCertDB();
01017     if (certHandle == NULL) {
01018        SECU_PrintError(progName, "unable to open the cert db");              
01019        /*ignoring return value of NSS_Shutdown() as code returns -1*/
01020        (void) NSS_Shutdown();
01021        return (-1);
01022     }
01023 
01024     CRLGEN_InitCrlGenParserLock();
01025 
01026     for (i=0; i<iterations; i++) {
01027        /* Read in the private key info */
01028        if (deleteCRL) 
01029            DeleteCRL (certHandle, nickName, crlType);
01030        else if (listCRL) {
01031            ListCRL (certHandle, nickName, crlType);
01032        }
01033        else if (importCRL) {
01034            rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
01035                          decodeOptions);
01036        } else if (generateCRL || modifyCRL) {
01037            if (!inCrlInitFile)
01038               inCrlInitFile = PR_STDIN;
01039            rv = GenerateCRL (certHandle, nickName, inCrlInitFile,
01040                            inFile, outFile, ascii,  slotName,
01041                            importOptions, alg, quiet,
01042                            decodeOptions, url, &pwdata,
01043                            modifyCRL);
01044        }
01045        else if (erase) {
01046            /* list and delete all CRLs */
01047            ListCRLNames (certHandle, crlType, PR_TRUE);
01048        }
01049 #ifdef DEBUG
01050        else if (test) {
01051            /* list and delete all CRLs */
01052            ListCRLNames (certHandle, crlType, PR_TRUE);
01053            /* list CRLs */
01054            ListCRLNames (certHandle, crlType, PR_FALSE);
01055            /* import CRL as a blob */
01056            rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
01057                          decodeOptions);
01058            /* list CRLs */
01059            ListCRLNames (certHandle, crlType, PR_FALSE);
01060        }
01061 #endif    
01062     }
01063 
01064     CRLGEN_DestroyCrlGenParserLock();
01065 
01066     if (NSS_Shutdown() != SECSuccess) {
01067         rv = SECFailure;
01068     }
01069 
01070     return (rv != SECSuccess);
01071 }