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 CreateModifiedCRLCopy(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, "CreateModifiedCRLCopy: 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     /* Make sure the update time is current. It can be modified later
00433      * by "update <time>" command from crl generation script */
00434     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
00435     if (rv != SECSuccess) {
00436         SECU_PrintError(progName, "fail to encode current time\n");
00437         goto loser;
00438     }
00439 
00440     signCrl->arena = arena;
00441 
00442   loser:
00443     SECITEM_FreeItem(&crlDER, PR_FALSE);
00444     if (modCrl)
00445         SEC_DestroyCrl(modCrl);
00446     if (rv != SECSuccess && signCrl) {
00447         SEC_DestroyCrl(signCrl);
00448         signCrl = NULL;
00449     }
00450     return signCrl;
00451 }
00452 
00453 
00454 static CERTSignedCrl*
00455 CreateNewCrl(PRArenaPool *arena, CERTCertDBHandle *certHandle,
00456              CERTCertificate *cert)
00457 { 
00458     CERTSignedCrl *signCrl = NULL;
00459     void *dummy = NULL;
00460     SECStatus rv;
00461     void* mark = NULL;
00462 
00463     /* if the CERTSignedCrl structure changes, this function will need to be
00464        updated as well */
00465     PORT_Assert(cert != NULL);
00466     if (!cert || !arena) {
00467         SECU_PrintError(progName, "invalid args for function "
00468                         "CreateNewCrl\n");
00469         return NULL;
00470     }
00471 
00472     mark = PORT_ArenaMark(arena);
00473         
00474     signCrl = PORT_ArenaZNew(arena, CERTSignedCrl);
00475     if (signCrl == NULL) {
00476         SECU_PrintError(progName, "fail to allocate memory\n");
00477         return NULL;
00478     }
00479 
00480     dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version,
00481                                   SEC_CRL_VERSION_2);
00482     /* set crl->version */
00483     if (!dummy) {
00484         SECU_PrintError(progName, "fail to create crl version data "
00485                         "container\n");
00486         goto loser;
00487     }
00488     
00489     /* copy SECItem name from cert */
00490     rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject);
00491     if (rv != SECSuccess) {
00492         SECU_PrintError(progName, "fail to duplicate der name from "
00493                         "certificate.\n");
00494         goto loser;
00495     }
00496         
00497     /* copy CERTName name structure from cert issuer */
00498     rv = CERT_CopyName (arena, &signCrl->crl.name, &cert->subject);
00499     if (rv != SECSuccess) {
00500         SECU_PrintError(progName, "fail to duplicate RD name from "
00501                         "certificate.\n");
00502         goto loser;
00503     }
00504 
00505     rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now());
00506     if (rv != SECSuccess) {
00507         SECU_PrintError(progName, "fail to encode current time\n");
00508         goto loser;
00509     }
00510 
00511     /* set fields */
00512     signCrl->arena = arena;
00513     signCrl->dbhandle = certHandle;
00514     signCrl->crl.arena = arena;
00515 
00516     return signCrl;
00517 
00518   loser:
00519     PORT_ArenaRelease(arena, mark);
00520     return NULL;
00521 }
00522 
00523 
00524 static SECStatus
00525 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile)
00526 {
00527     CRLGENGeneratorData *crlGenData = NULL;
00528     SECStatus rv;
00529     
00530     PORT_Assert(signCrl != NULL && inCrlInitFile != NULL);
00531     if (!signCrl || !inCrlInitFile) {
00532         SECU_PrintError(progName, "invalid args for function "
00533                         "CreateNewCrl\n");
00534         return SECFailure;
00535     }
00536 
00537     crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile);
00538     if (!crlGenData) {
00539        SECU_PrintError(progName, "can not initialize parser structure.\n");
00540        return SECFailure;
00541     }
00542 
00543     rv = CRLGEN_ExtHandleInit(crlGenData);
00544     if (rv == SECFailure) {
00545        SECU_PrintError(progName, "can not initialize entries handle.\n");
00546        goto loser;
00547     }
00548        
00549     rv = CRLGEN_StartCrlGen(crlGenData);
00550     if (rv != SECSuccess) {
00551        SECU_PrintError(progName, "crl generation failed");
00552        goto loser;
00553     }
00554 
00555   loser:
00556     /* CommitExtensionsAndEntries is partially responsible for freeing
00557      * up memory that was used for CRL generation. Should be called regardless
00558      * of previouse call status, but only after initialization of
00559      * crlGenData was done. It will commit all changes that was done before
00560      * an error has occured.
00561      */
00562     if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) {
00563         SECU_PrintError(progName, "crl generation failed");
00564         rv = SECFailure;
00565     }
00566     CRLGEN_FinalizeCrlGeneration(crlGenData);    
00567     return rv;
00568 }
00569 
00570 static SECStatus
00571 SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert,
00572                 char *outFileName, SECOidTag hashAlgTag, int ascii,
00573                 char *slotName, char *url, secuPWData *pwdata)
00574 {
00575     PK11SlotInfo *slot = NULL;
00576     PRFileDesc   *outFile = NULL;
00577     SECStatus rv;
00578     SignAndEncodeFuncExitStat errCode;
00579 
00580     PORT_Assert(signCrl && (!ascii || outFileName));
00581     if (!signCrl || (ascii && !outFileName)) {
00582         SECU_PrintError(progName, "invalid args for function "
00583                         "SignAndStoreCrl\n");
00584         return SECFailure;
00585     }
00586 
00587     if (!slotName || !PL_strcmp(slotName, "internal"))
00588        slot = PK11_GetInternalKeySlot();
00589     else
00590        slot = PK11_FindSlotByName(slotName);
00591     if (!slot) {
00592        SECU_PrintError(progName, "can not find requested slot");
00593        return SECFailure;
00594     }
00595 
00596     if (PK11_NeedLogin(slot)) {
00597         rv = PK11_Authenticate(slot, PR_TRUE, pwdata);
00598        if (rv != SECSuccess)
00599            goto loser;
00600     }
00601 
00602     rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode);
00603     if (rv != SECSuccess) {
00604         char* errMsg = NULL;
00605         switch (errCode)
00606         {
00607             case noKeyFound:
00608                 errMsg = "No private key found of signing cert";
00609                 break;
00610 
00611             case noSignatureMatch:
00612                 errMsg = "Key and Algorithm OId are do not match";
00613                 break;
00614 
00615             default:
00616             case failToEncode:
00617                 errMsg = "Failed to encode crl structure";
00618                 break;
00619 
00620             case failToSign:
00621                 errMsg = "Failed to sign crl structure";
00622                 break;
00623 
00624             case noMem:
00625                 errMsg = "Can not allocate memory";
00626                 break;
00627         }
00628        SECU_PrintError(progName, "%s\n", errMsg);
00629        goto loser;
00630     }
00631 
00632     if (outFileName) {
00633        outFile = PR_Open(outFileName, PR_WRONLY|PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
00634        if (!outFile) {
00635            SECU_PrintError(progName, "unable to open \"%s\" for writing\n",
00636                          outFileName);
00637            goto loser;
00638        }
00639     }
00640 
00641     rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url);
00642     if (rv != SECSuccess) {
00643         SECU_PrintError(progName, "fail to save CRL\n");
00644     }
00645 
00646   loser:
00647     if (outFile)
00648        PR_Close(outFile);
00649     if (slot)
00650        PK11_FreeSlot(slot);
00651     return rv;
00652 }
00653 
00654 static SECStatus
00655 GenerateCRL (CERTCertDBHandle *certHandle, char *certNickName, 
00656             PRFileDesc *inCrlInitFile,  PRFileDesc *inFile,
00657             char *outFileName, int ascii, char *slotName,
00658             PRInt32 importOptions, char *alg, PRBool quiet,
00659              PRInt32 decodeOptions, char *url, secuPWData *pwdata,
00660              int modifyFlag)
00661 {
00662     CERTCertificate *cert = NULL;
00663     CERTSignedCrl *signCrl = NULL;
00664     PRArenaPool *arena = NULL;
00665     SECStatus rv;
00666     SECOidTag hashAlgTag = SEC_OID_UNKNOWN;
00667 
00668     if (alg) {
00669         hashAlgTag = SECU_StringToSignatureAlgTag(alg);
00670         if (hashAlgTag == SEC_OID_UNKNOWN) {
00671             SECU_PrintError(progName, "%s -Z:  %s is not a recognized type.\n",
00672                             progName, alg);
00673             return SECFailure;
00674         }
00675     } else {
00676         hashAlgTag = SEC_OID_UNKNOWN;
00677     }
00678 
00679     arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
00680     if (!arena) {
00681         SECU_PrintError(progName, "fail to allocate memory\n");
00682         return SECFailure;
00683     }
00684 
00685     if (modifyFlag == PR_TRUE) {
00686         signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName,
00687                                          inFile, decodeOptions, importOptions);
00688         if (signCrl == NULL) {
00689             goto loser;
00690         }
00691     }
00692 
00693     if (!cert) {
00694         cert = FindSigningCert(certHandle, signCrl, certNickName);
00695         if (cert == NULL) {
00696             goto loser;
00697         }
00698     }
00699 
00700     if (!signCrl) {
00701         if (modifyFlag == PR_TRUE) {
00702             if (!outFileName) {
00703                 int len = strlen(certNickName) + 5;
00704                 outFileName = PORT_ArenaAlloc(arena, len);
00705                 PR_snprintf(outFileName, len, "%s.crl", certNickName);
00706             }
00707             SECU_PrintError(progName, "Will try to generate crl. "
00708                             "It will be saved in file: %s",
00709                             outFileName);
00710         }
00711         signCrl = CreateNewCrl(arena, certHandle, cert);
00712         if (!signCrl)
00713             goto loser;
00714     }
00715 
00716     rv = UpdateCrl(signCrl, inCrlInitFile);
00717     if (rv != SECSuccess) {
00718         goto loser;
00719     }
00720 
00721     rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii,
00722                          slotName, url, pwdata);
00723     if (rv != SECSuccess) {
00724         goto loser;
00725     }
00726 
00727     if (signCrl && !quiet) {
00728        SECU_PrintCRLInfo (stdout, &signCrl->crl, "CRL Info:\n", 0);
00729     }
00730 
00731   loser:
00732     if (arena && (!signCrl || !signCrl->arena))
00733         PORT_FreeArena (arena, PR_FALSE);
00734     if (signCrl)
00735        SEC_DestroyCrl (signCrl);
00736     if (cert)
00737        CERT_DestroyCertificate (cert);
00738     return (rv);
00739 }
00740 
00741 static void Usage(char *progName)
00742 {
00743     fprintf(stderr,
00744            "Usage:  %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n"
00745            "        %s -D -n nickname [-d keydir] [-P dbprefix]\n"
00746            "        %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] "
00747             "[-p pwd-file] -w [pwd-string]\n"
00748            "        %s -E -t crlType [-d keydir] [-P dbprefix]\n"
00749            "        %s -T\n"
00750            "        %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] "
00751             "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] "
00752             "[-a] [-B]\n",
00753            progName, progName, progName, progName, progName, progName);
00754 
00755     fprintf (stderr, "%-15s List CRL\n", "-L");
00756     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
00757            "-n nickname");
00758     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00759            "-d keydir");
00760     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00761            "-P dbprefix");
00762    
00763     fprintf (stderr, "%-15s Delete a CRL from the cert database\n", "-D");    
00764     fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n",
00765            "-n nickname");
00766     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
00767     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00768            "-d keydir");
00769     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00770            "-P dbprefix");
00771 
00772     fprintf (stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E");
00773     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
00774     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00775            "-d keydir");
00776     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00777            "-P dbprefix");
00778 
00779     fprintf (stderr, "%-15s Import a CRL to the cert database\n", "-I");    
00780     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
00781            "-i crl");
00782     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
00783     fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType");
00784     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00785            "-d keydir");
00786     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00787            "-P dbprefix");
00788 #ifdef DEBUG
00789     fprintf (stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T");
00790 #endif
00791     fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " ");
00792     fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " ");
00793     fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " ");        
00794     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
00795     fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p");
00796     fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>");
00797     fprintf(stderr, "\n%-15s Create CRL\n", "-G");
00798     fprintf(stderr, "%-15s Modify CRL\n", "-M");
00799     fprintf(stderr, "%-20s Specify crl initialization file\n",
00800            "-c crl-conf-file");
00801     fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n",
00802            "-n nickname");
00803     fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n",
00804            "-i crl");
00805     fprintf(stderr, "%-20s Specify a CRL output file\n",
00806            "-o crl-output-file");
00807     fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n",
00808            "-a");
00809     fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n",
00810            "-d keydir");
00811     fprintf(stderr, "%-20s Provide path to a default pwd file\n",
00812            "-f pwd-file");
00813     fprintf(stderr, "%-20s Provide db password in command line\n",
00814            "-w pwd-string");
00815     fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n",
00816            "-P dbprefix");
00817     fprintf(stderr, "%-20s Specify the url.\n", "-u url");
00818     fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B");
00819 
00820     exit(-1);
00821 }
00822 
00823 int main(int argc, char **argv)
00824 {
00825     SECItem privKeyDER;
00826     CERTCertDBHandle *certHandle;
00827     FILE *certFile;
00828     PRFileDesc *inFile;
00829     PRFileDesc *inCrlInitFile = NULL;
00830     int generateCRL;
00831     int modifyCRL;
00832     int listCRL;
00833     int importCRL;
00834     int deleteCRL;
00835     int rv;
00836     char *nickName;
00837     char *url;
00838     char *dbPrefix = "";
00839     char *alg = NULL;
00840     char *outFile = NULL;
00841     char *slotName = NULL;
00842     int ascii = 0;
00843     int crlType;
00844     PLOptState *optstate;
00845     PLOptStatus status;
00846     SECStatus secstatus;
00847     PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS;
00848     PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS;
00849     PRBool quiet = PR_FALSE;
00850     PRBool test = PR_FALSE;
00851     PRBool erase = PR_FALSE;
00852     PRInt32 i = 0;
00853     PRInt32 iterations = 1;
00854 
00855     secuPWData  pwdata          = { PW_NONE, 0 };
00856 
00857     progName = strrchr(argv[0], '/');
00858     progName = progName ? progName+1 : argv[0];
00859 
00860     rv = 0;
00861     deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = 0;
00862     certFile = NULL;
00863     inFile = NULL;
00864     nickName = url = NULL;
00865     privKeyDER.data = NULL;
00866     certHandle = NULL;
00867     crlType = SEC_CRL_TYPE;
00868     /*
00869      * Parse command line arguments
00870      */
00871     optstate = PL_CreateOptState(argc, argv, "sqBCDGILMTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:");
00872     while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
00873        switch (optstate->option) {
00874          case '?':
00875            Usage(progName);
00876            break;
00877 
00878           case 'T':
00879             test = PR_TRUE;
00880             break;
00881 
00882           case 'E':
00883             erase = PR_TRUE;
00884             break;
00885 
00886          case 'B':
00887             importOptions |= CRL_IMPORT_BYPASS_CHECKS;
00888             break;
00889 
00890          case 'G':
00891            generateCRL = 1;
00892            break;
00893 
00894           case 'M':
00895             modifyCRL = 1;
00896             break;
00897 
00898          case 'D':
00899              deleteCRL = 1;
00900              break;
00901 
00902          case 'I':
00903              importCRL = 1;
00904              break;
00905                   
00906          case 'C':
00907          case 'L':
00908              listCRL = 1;
00909              break;
00910 
00911          case 'P':
00912            dbPrefix = strdup(optstate->value);
00913            break;
00914               
00915          case 'Z':
00916               alg = strdup(optstate->value);
00917               break;
00918               
00919          case 'a':
00920              ascii = 1;
00921              break;
00922 
00923          case 'c':
00924               inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0);
00925               if (!inCrlInitFile) {
00926                   PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
00927                              progName, optstate->value);
00928                   PL_DestroyOptState(optstate);
00929                   return -1;
00930               }
00931               break;
00932            
00933          case 'd':
00934               SECU_ConfigDirectory(optstate->value);
00935               break;
00936 
00937          case 'f':
00938              pwdata.source = PW_FROMFILE;
00939              pwdata.data = strdup(optstate->value);
00940              break;
00941 
00942          case 'h':
00943               slotName = strdup(optstate->value);
00944               break;
00945 
00946          case 'i':
00947            inFile = PR_Open(optstate->value, PR_RDONLY, 0);
00948            if (!inFile) {
00949               PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n",
00950                      progName, optstate->value);
00951               PL_DestroyOptState(optstate);
00952               return -1;
00953            }
00954            break;
00955            
00956          case 'n':
00957            nickName = strdup(optstate->value);
00958            break;
00959 
00960          case 'o':
00961            outFile = strdup(optstate->value);
00962            break;
00963            
00964          case 'p':
00965            decodeOptions |= CRL_DECODE_SKIP_ENTRIES;
00966            break;
00967 
00968          case 'r': {
00969            const char* str = optstate->value;
00970            if (str && atoi(str)>0)
00971               iterations = atoi(str);
00972            }
00973            break;
00974            
00975          case 't': {
00976            char *type;
00977            
00978            type = strdup(optstate->value);
00979            crlType = atoi (type);
00980            if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) {
00981               PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName);
00982               PL_DestroyOptState(optstate);
00983               return -1;
00984            }
00985            break;
00986 
00987          case 'q':
00988             quiet = PR_TRUE;
00989            break;
00990 
00991          case 'w':
00992              pwdata.source = PW_PLAINTEXT;
00993              pwdata.data = strdup(optstate->value);
00994              break;
00995 
00996          case 'u':
00997            url = strdup(optstate->value);
00998            break;
00999 
01000           }
01001        }
01002     }
01003     PL_DestroyOptState(optstate);
01004 
01005     if (deleteCRL && !nickName) Usage (progName);
01006     if (importCRL && !inFile) Usage (progName);
01007     if ((generateCRL && !nickName) ||
01008         (modifyCRL && !inFile && !nickName)) Usage (progName);
01009     if (!(listCRL || deleteCRL || importCRL || generateCRL ||
01010          modifyCRL || test || erase)) Usage (progName);
01011     
01012     PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
01013 
01014     PK11_SetPasswordFunc(SECU_GetModulePassword);
01015 
01016     secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix,
01017                             "secmod.db", 0);
01018     if (secstatus != SECSuccess) {
01019        SECU_PrintPRandOSError(progName);
01020        return -1;
01021     }
01022     SECU_RegisterDynamicOids();
01023 
01024     certHandle = CERT_GetDefaultCertDB();
01025     if (certHandle == NULL) {
01026        SECU_PrintError(progName, "unable to open the cert db");              
01027        /*ignoring return value of NSS_Shutdown() as code returns -1*/
01028        (void) NSS_Shutdown();
01029        return (-1);
01030     }
01031 
01032     CRLGEN_InitCrlGenParserLock();
01033 
01034     for (i=0; i<iterations; i++) {
01035        /* Read in the private key info */
01036        if (deleteCRL) 
01037            DeleteCRL (certHandle, nickName, crlType);
01038        else if (listCRL) {
01039            ListCRL (certHandle, nickName, crlType);
01040        }
01041        else if (importCRL) {
01042            rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
01043                          decodeOptions);
01044        } else if (generateCRL || modifyCRL) {
01045            if (!inCrlInitFile)
01046               inCrlInitFile = PR_STDIN;
01047            rv = GenerateCRL (certHandle, nickName, inCrlInitFile,
01048                            inFile, outFile, ascii,  slotName,
01049                            importOptions, alg, quiet,
01050                            decodeOptions, url, &pwdata,
01051                            modifyCRL);
01052        }
01053        else if (erase) {
01054            /* list and delete all CRLs */
01055            ListCRLNames (certHandle, crlType, PR_TRUE);
01056        }
01057 #ifdef DEBUG
01058        else if (test) {
01059            /* list and delete all CRLs */
01060            ListCRLNames (certHandle, crlType, PR_TRUE);
01061            /* list CRLs */
01062            ListCRLNames (certHandle, crlType, PR_FALSE);
01063            /* import CRL as a blob */
01064            rv = ImportCRL (certHandle, url, crlType, inFile, importOptions,
01065                          decodeOptions);
01066            /* list CRLs */
01067            ListCRLNames (certHandle, crlType, PR_FALSE);
01068        }
01069 #endif    
01070     }
01071 
01072     CRLGEN_DestroyCrlGenParserLock();
01073 
01074     if (NSS_Shutdown() != SECSuccess) {
01075         rv = SECFailure;
01076     }
01077 
01078     return (rv != SECSuccess);
01079 }