diff options
Diffstat (limited to '')
-rw-r--r-- | security/nss/cmd/crlutil/crlutil.c | 1144 |
1 files changed, 1144 insertions, 0 deletions
diff --git a/security/nss/cmd/crlutil/crlutil.c b/security/nss/cmd/crlutil/crlutil.c new file mode 100644 index 0000000000..89ac46c737 --- /dev/null +++ b/security/nss/cmd/crlutil/crlutil.c @@ -0,0 +1,1144 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* +** certutil.c +** +** utility for managing certificates and the cert database +** +*/ +/* test only */ + +#include "nspr.h" +#include "plgetopt.h" +#include "secutil.h" +#include "cert.h" +#include "certi.h" +#include "certdb.h" +#include "nss.h" +#include "pk11func.h" +#include "crlgen.h" + +#define SEC_CERT_DB_EXISTS 0 +#define SEC_CREATE_CERT_DB 1 + +static char *progName; + +static CERTSignedCrl * +FindCRL(CERTCertDBHandle *certHandle, char *name, int type) +{ + CERTSignedCrl *crl = NULL; + CERTCertificate *cert = NULL; + SECItem derName; + + derName.data = NULL; + derName.len = 0; + + cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name); + if (!cert) { + CERTName *certName = NULL; + PLArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + + certName = CERT_AsciiToName(name); + if (certName) { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena) { + SECItem *nameItem = + SEC_ASN1EncodeItem(arena, NULL, (void *)certName, + SEC_ASN1_GET(CERT_NameTemplate)); + if (nameItem) { + rv = SECITEM_CopyItem(NULL, &derName, nameItem); + } + PORT_FreeArena(arena, PR_FALSE); + } + CERT_DestroyName(certName); + } + + if (rv != SECSuccess) { + SECU_PrintError(progName, "SECITEM_CopyItem failed, out of memory"); + return ((CERTSignedCrl *)NULL); + } + + if (!derName.len || !derName.data) { + SECU_PrintError(progName, "could not find certificate named '%s'", name); + return ((CERTSignedCrl *)NULL); + } + } else { + SECStatus rv = SECITEM_CopyItem(NULL, &derName, &cert->derSubject); + CERT_DestroyCertificate(cert); + if (rv != SECSuccess) { + return ((CERTSignedCrl *)NULL); + } + } + + crl = SEC_FindCrlByName(certHandle, &derName, type); + if (crl == NULL) + SECU_PrintError(progName, "could not find %s's CRL", name); + if (derName.data) { + SECITEM_FreeItem(&derName, PR_FALSE); + } + return (crl); +} + +static SECStatus +DisplayCRL(CERTCertDBHandle *certHandle, char *nickName, int crlType) +{ + CERTSignedCrl *crl = NULL; + + crl = FindCRL(certHandle, nickName, crlType); + + if (crl) { + SECU_PrintCRLInfo(stdout, &crl->crl, "CRL Info:\n", 0); + SEC_DestroyCrl(crl); + return SECSuccess; + } + return SECFailure; +} + +static void +ListCRLNames(CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls) +{ + CERTCrlHeadNode *crlList = NULL; + CERTCrlNode *crlNode = NULL; + CERTName *name = NULL; + PLArenaPool *arena = NULL; + SECStatus rv; + + do { + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (arena == NULL) { + fprintf(stderr, "%s: fail to allocate memory\n", progName); + break; + } + + name = PORT_ArenaZAlloc(arena, sizeof(*name)); + if (name == NULL) { + fprintf(stderr, "%s: fail to allocate memory\n", progName); + break; + } + name->arena = arena; + + rv = SEC_LookupCrls(certHandle, &crlList, crlType); + if (rv != SECSuccess) { + fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName, + SECU_Strerror(PORT_GetError())); + break; + } + + /* just in case */ + if (!crlList) + break; + + crlNode = crlList->first; + + fprintf(stdout, "\n"); + fprintf(stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type"); + while (crlNode) { + char *asciiname = NULL; + CERTCertificate *cert = NULL; + if (crlNode->crl && crlNode->crl->crl.derName.data != NULL) { + cert = CERT_FindCertByName(certHandle, + &crlNode->crl->crl.derName); + if (!cert) { + SECU_PrintError(progName, "could not find signing " + "certificate in database"); + } + } + if (cert) { + char *certName = NULL; + if (cert->nickname && PORT_Strlen(cert->nickname) > 0) { + certName = cert->nickname; + } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) { + certName = cert->emailAddr; + } + if (certName) { + asciiname = PORT_Strdup(certName); + } + CERT_DestroyCertificate(cert); + } + + if (!asciiname) { + name = &crlNode->crl->crl.name; + if (!name) { + SECU_PrintError(progName, "fail to get the CRL " + "issuer name"); + continue; + } + asciiname = CERT_NameToAscii(name); + } + fprintf(stdout, "%-40s %-5s\n", asciiname, "CRL"); + if (asciiname) { + PORT_Free(asciiname); + } + if (PR_TRUE == deletecrls) { + CERTSignedCrl *acrl = NULL; + SECItem *issuer = &crlNode->crl->crl.derName; + acrl = SEC_FindCrlByName(certHandle, issuer, crlType); + if (acrl) { + SEC_DeletePermCRL(acrl); + SEC_DestroyCrl(acrl); + } + } + crlNode = crlNode->next; + } + + } while (0); + if (crlList) + PORT_FreeArena(crlList->arena, PR_FALSE); + PORT_FreeArena(arena, PR_FALSE); +} + +static SECStatus +ListCRL(CERTCertDBHandle *certHandle, char *nickName, int crlType) +{ + if (nickName == NULL) { + ListCRLNames(certHandle, crlType, PR_FALSE); + return SECSuccess; + } + + return DisplayCRL(certHandle, nickName, crlType); +} + +static SECStatus +DeleteCRL(CERTCertDBHandle *certHandle, char *name, int type) +{ + CERTSignedCrl *crl = NULL; + SECStatus rv = SECFailure; + + crl = FindCRL(certHandle, name, type); + if (!crl) { + SECU_PrintError(progName, "could not find the issuer %s's CRL", name); + return SECFailure; + } + rv = SEC_DeletePermCRL(crl); + SEC_DestroyCrl(crl); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to delete the issuer %s's CRL " + "from the perm database (reason: %s)", + name, SECU_Strerror(PORT_GetError())); + return SECFailure; + } + return (rv); +} + +SECStatus +ImportCRL(CERTCertDBHandle *certHandle, char *url, int type, + PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions, + secuPWData *pwdata) +{ + CERTSignedCrl *crl = NULL; + SECItem crlDER; + PK11SlotInfo *slot = NULL; + int rv; + + crlDER.data = NULL; + + /* Read in the entire file specified with the -f argument */ + rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read input file"); + return (SECFailure); + } + + decodeOptions |= CRL_DECODE_DONT_COPY_DER; + + slot = PK11_GetInternalKeySlot(); + + if (PK11_NeedLogin(slot)) { + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + if (rv != SECSuccess) + goto loser; + } + + crl = PK11_ImportCRL(slot, &crlDER, url, type, + NULL, importOptions, NULL, decodeOptions); + + if (!crl) { + const char *errString; + + rv = SECFailure; + errString = SECU_Strerror(PORT_GetError()); + if (errString && PORT_Strlen(errString) == 0) + SECU_PrintError(progName, + "CRL is not imported (error: input CRL is not up to date.)"); + else + SECU_PrintError(progName, "unable to import CRL"); + } else { + SEC_DestroyCrl(crl); + } +loser: + if (slot) { + PK11_FreeSlot(slot); + } + SECITEM_FreeItem(&crlDER, PR_FALSE); + return (rv); +} + +SECStatus +DumpCRL(PRFileDesc *inFile) +{ + int rv; + PLArenaPool *arena = NULL; + CERTSignedCrl *newCrl = NULL; + + SECItem crlDER; + crlDER.data = NULL; + + /* Read in the entire file specified with the -f argument */ + rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read input file"); + return (SECFailure); + } + + rv = SEC_ERROR_NO_MEMORY; + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) + return rv; + + newCrl = CERT_DecodeDERCrlWithFlags(arena, &crlDER, SEC_CRL_TYPE, + CRL_DECODE_DEFAULT_OPTIONS); + if (!newCrl) + return SECFailure; + + SECU_PrintCRLInfo(stdout, &newCrl->crl, "CRL file contents", 0); + + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +static CERTCertificate * +FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl, + char *certNickName) +{ + CERTCertificate *cert = NULL, *certTemp = NULL; + SECStatus rv = SECFailure; + CERTAuthKeyID *authorityKeyID = NULL; + SECItem *subject = NULL; + + PORT_Assert(certHandle != NULL); + if (!certHandle || (!signCrl && !certNickName)) { + SECU_PrintError(progName, "invalid args for function " + "FindSigningCert \n"); + return NULL; + } + + if (signCrl) { +#if 0 + authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl); +#endif + subject = &signCrl->crl.derName; + } else { + certTemp = CERT_FindCertByNickname(certHandle, certNickName); + if (!certTemp) { + SECU_PrintError(progName, "could not find certificate \"%s\" " + "in database", + certNickName); + goto loser; + } + subject = &certTemp->derSubject; + } + + cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now()); + if (!cert) { + SECU_PrintError(progName, "could not find signing certificate " + "in database"); + goto loser; + } else { + rv = SECSuccess; + } + +loser: + if (certTemp) + CERT_DestroyCertificate(certTemp); + if (cert && rv != SECSuccess) + CERT_DestroyCertificate(cert); + return cert; +} + +static CERTSignedCrl * +CreateModifiedCRLCopy(PLArenaPool *arena, CERTCertDBHandle *certHandle, + CERTCertificate **cert, char *certNickName, + PRFileDesc *inFile, PRInt32 decodeOptions, + PRInt32 importOptions, secuPWData *pwdata) +{ + SECItem crlDER = { 0, NULL, 0 }; + CERTSignedCrl *signCrl = NULL; + CERTSignedCrl *modCrl = NULL; + PLArenaPool *modArena = NULL; + SECStatus rv = SECSuccess; + + if (!arena || !certHandle || !certNickName) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + SECU_PrintError(progName, "CreateModifiedCRLCopy: invalid args\n"); + return NULL; + } + + modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (!modArena) { + SECU_PrintError(progName, "fail to allocate memory\n"); + return NULL; + } + + if (inFile != NULL) { + rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read input file"); + goto loser; + } + + decodeOptions |= CRL_DECODE_DONT_COPY_DER; + + modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE, + decodeOptions); + if (!modCrl) { + SECU_PrintError(progName, "fail to decode CRL"); + goto loser; + } + + if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)) { + /* If caCert is a v2 certificate, make sure that it + * can be used for crl signing purpose */ + *cert = FindSigningCert(certHandle, modCrl, NULL); + if (!*cert) { + goto loser; + } + + rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert, + PR_Now(), pwdata); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to verify signed data\n"); + goto loser; + } + } + } else { + modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE); + if (!modCrl) { + SECU_PrintError(progName, "fail to find crl %s in database\n", + certNickName); + goto loser; + } + } + + signCrl = PORT_ArenaZNew(arena, CERTSignedCrl); + if (signCrl == NULL) { + SECU_PrintError(progName, "fail to allocate memory\n"); + goto loser; + } + + rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to dublicate crl for " + "modification."); + goto loser; + } + + /* Make sure the update time is current. It can be modified later + * by "update <time>" command from crl generation script */ + rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now()); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to encode current time\n"); + goto loser; + } + + signCrl->arena = arena; + signCrl->referenceCount = 1; + +loser: + if (crlDER.data) { + SECITEM_FreeItem(&crlDER, PR_FALSE); + } + if (modArena && (!modCrl || modCrl->arena != modArena)) { + PORT_FreeArena(modArena, PR_FALSE); + } + if (modCrl) + SEC_DestroyCrl(modCrl); + if (rv != SECSuccess && signCrl) { + SEC_DestroyCrl(signCrl); + signCrl = NULL; + } + return signCrl; +} + +static CERTSignedCrl * +CreateNewCrl(PLArenaPool *arena, CERTCertDBHandle *certHandle, + CERTCertificate *cert) +{ + CERTSignedCrl *signCrl = NULL; + void *dummy = NULL; + SECStatus rv; + void *mark = NULL; + + /* if the CERTSignedCrl structure changes, this function will need to be + updated as well */ + if (!cert || !arena) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + SECU_PrintError(progName, "invalid args for function " + "CreateNewCrl\n"); + return NULL; + } + + mark = PORT_ArenaMark(arena); + + signCrl = PORT_ArenaZNew(arena, CERTSignedCrl); + if (signCrl == NULL) { + SECU_PrintError(progName, "fail to allocate memory\n"); + return NULL; + } + + dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version, + SEC_CRL_VERSION_2); + /* set crl->version */ + if (!dummy) { + SECU_PrintError(progName, "fail to create crl version data " + "container\n"); + goto loser; + } + + /* copy SECItem name from cert */ + rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to duplicate der name from " + "certificate.\n"); + goto loser; + } + + /* copy CERTName name structure from cert issuer */ + rv = CERT_CopyName(arena, &signCrl->crl.name, &cert->subject); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to duplicate RD name from " + "certificate.\n"); + goto loser; + } + + rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now()); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to encode current time\n"); + goto loser; + } + + /* set fields */ + signCrl->arena = arena; + signCrl->dbhandle = certHandle; + signCrl->crl.arena = arena; + + PORT_ArenaUnmark(arena, mark); + + return signCrl; + +loser: + PORT_ArenaRelease(arena, mark); + return NULL; +} + +static SECStatus +UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile) +{ + CRLGENGeneratorData *crlGenData = NULL; + SECStatus rv; + + if (!signCrl || !inCrlInitFile) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + SECU_PrintError(progName, "invalid args for function " + "CreateNewCrl\n"); + return SECFailure; + } + + crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile); + if (!crlGenData) { + SECU_PrintError(progName, "can not initialize parser structure.\n"); + return SECFailure; + } + + rv = CRLGEN_ExtHandleInit(crlGenData); + if (rv == SECFailure) { + SECU_PrintError(progName, "can not initialize entries handle.\n"); + goto loser; + } + + rv = CRLGEN_StartCrlGen(crlGenData); + if (rv != SECSuccess) { + SECU_PrintError(progName, "crl generation failed"); + goto loser; + } + +loser: + /* CommitExtensionsAndEntries is partially responsible for freeing + * up memory that was used for CRL generation. Should be called regardless + * of previouse call status, but only after initialization of + * crlGenData was done. It will commit all changes that was done before + * an error has occurred. + */ + if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) { + SECU_PrintError(progName, "crl generation failed"); + rv = SECFailure; + } + CRLGEN_FinalizeCrlGeneration(crlGenData); + return rv; +} + +static SECStatus +SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert, + char *outFileName, SECOidTag hashAlgTag, int ascii, + char *slotName, char *url, secuPWData *pwdata) +{ + PK11SlotInfo *slot = NULL; + PRFileDesc *outFile = NULL; + SECStatus rv; + SignAndEncodeFuncExitStat errCode; + + PORT_Assert(signCrl && (!ascii || outFileName)); + if (!signCrl || (ascii && !outFileName)) { + SECU_PrintError(progName, "invalid args for function " + "SignAndStoreCrl\n"); + return SECFailure; + } + + if (!slotName || !PL_strcmp(slotName, "internal")) + slot = PK11_GetInternalKeySlot(); + else + slot = PK11_FindSlotByName(slotName); + if (!slot) { + SECU_PrintError(progName, "can not find requested slot"); + return SECFailure; + } + + if (PK11_NeedLogin(slot)) { + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + if (rv != SECSuccess) + goto loser; + } + + rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode); + if (rv != SECSuccess) { + char *errMsg = NULL; + switch (errCode) { + case noKeyFound: + errMsg = "No private key found of signing cert"; + break; + + case noSignatureMatch: + errMsg = "Key and Algorithm OId are do not match"; + break; + + default: + case failToEncode: + errMsg = "Failed to encode crl structure"; + break; + + case failToSign: + errMsg = "Failed to sign crl structure"; + break; + + case noMem: + errMsg = "Can not allocate memory"; + break; + } + SECU_PrintError(progName, "%s\n", errMsg); + goto loser; + } + + if (outFileName) { + outFile = PR_Open(outFileName, PR_WRONLY | PR_CREATE_FILE, PR_IRUSR | PR_IWUSR); + if (!outFile) { + SECU_PrintError(progName, "unable to open \"%s\" for writing\n", + outFileName); + goto loser; + } + } + + rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url); + if (rv != SECSuccess) { + SECU_PrintError(progName, "fail to save CRL\n"); + } + +loser: + if (outFile) + PR_Close(outFile); + if (slot) + PK11_FreeSlot(slot); + return rv; +} + +static SECStatus +GenerateCRL(CERTCertDBHandle *certHandle, char *certNickName, + PRFileDesc *inCrlInitFile, PRFileDesc *inFile, + char *outFileName, int ascii, char *slotName, + PRInt32 importOptions, char *alg, PRBool quiet, + PRInt32 decodeOptions, char *url, secuPWData *pwdata, + int modifyFlag) +{ + CERTCertificate *cert = NULL; + CERTSignedCrl *signCrl = NULL; + PLArenaPool *arena = NULL; + SECStatus rv; + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + + if (alg) { + hashAlgTag = SECU_StringToSignatureAlgTag(alg); + if (hashAlgTag == SEC_OID_UNKNOWN) { + SECU_PrintError(progName, "%s -Z: %s is not a recognized type.\n", + progName, alg); + return SECFailure; + } + } else { + hashAlgTag = SEC_OID_UNKNOWN; + } + + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if (!arena) { + SECU_PrintError(progName, "fail to allocate memory\n"); + return SECFailure; + } + + if (modifyFlag == PR_TRUE) { + signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName, + inFile, decodeOptions, importOptions, + pwdata); + if (signCrl == NULL) { + rv = SECFailure; + goto loser; + } + } + + if (!cert) { + cert = FindSigningCert(certHandle, signCrl, certNickName); + if (cert == NULL) { + rv = SECFailure; + goto loser; + } + } + + if (!signCrl) { + if (modifyFlag == PR_TRUE) { + if (!outFileName) { + int len = strlen(certNickName) + 5; + outFileName = PORT_ArenaAlloc(arena, len); + PR_snprintf(outFileName, len, "%s.crl", certNickName); + } + SECU_PrintError(progName, "Will try to generate crl. " + "It will be saved in file: %s", + outFileName); + } + signCrl = CreateNewCrl(arena, certHandle, cert); + if (!signCrl) { + rv = SECFailure; + goto loser; + } + } + + rv = UpdateCrl(signCrl, inCrlInitFile); + if (rv != SECSuccess) { + goto loser; + } + + rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii, + slotName, url, pwdata); + if (rv != SECSuccess) { + goto loser; + } + + if (signCrl && !quiet) { + SECU_PrintCRLInfo(stdout, &signCrl->crl, "CRL Info:\n", 0); + } + +loser: + if (arena && (!signCrl || !signCrl->arena)) + PORT_FreeArena(arena, PR_FALSE); + if (signCrl) + SEC_DestroyCrl(signCrl); + if (cert) + CERT_DestroyCertificate(cert); + return (rv); +} + +static void +Usage() +{ + fprintf(stderr, + "Usage: %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n" + " %s -D -n nickname [-d keydir] [-P dbprefix]\n" + " %s -S -i crl\n" + " %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] " + "[-p pwd-file] -w [pwd-string]\n" + " %s -E -t crlType [-d keydir] [-P dbprefix]\n" + " %s -T\n" + " %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] " + "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] " + "[-a] [-B]\n", + progName, progName, progName, progName, progName, progName, progName); + + fprintf(stderr, "%-15s List CRL\n", "-L"); + fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n", + "-n nickname"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + + fprintf(stderr, "%-15s Delete a CRL from the cert database\n", "-D"); + fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n", + "-n nickname"); + fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + + fprintf(stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E"); + fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + + fprintf(stderr, "%-15s Show contents of a CRL file (without database)\n", "-S"); + fprintf(stderr, "%-20s Specify the file which contains the CRL to show\n", + "-i crl"); + + fprintf(stderr, "%-15s Import a CRL to the cert database\n", "-I"); + fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n", + "-i crl"); + fprintf(stderr, "%-20s Specify the url.\n", "-u url"); + fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); +#ifdef DEBUG + fprintf(stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T"); +#endif + fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " "); + fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " "); + fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " "); + fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B"); + fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p"); + fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>"); + fprintf(stderr, "\n%-15s Create CRL\n", "-G"); + fprintf(stderr, "%-15s Modify CRL\n", "-M"); + fprintf(stderr, "%-20s Specify crl initialization file\n", + "-c crl-conf-file"); + fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n", + "-n nickname"); + fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n", + "-i crl"); + fprintf(stderr, "%-20s Specify a CRL output file\n", + "-o crl-output-file"); + fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n", + "-a"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Provide path to a default pwd file\n", + "-f pwd-file"); + fprintf(stderr, "%-20s Provide db password in command line\n", + "-w pwd-string"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + fprintf(stderr, "%-20s Specify the url.\n", "-u url"); + fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B"); + + exit(-1); +} + +int +main(int argc, char **argv) +{ + CERTCertDBHandle *certHandle; + PRFileDesc *inFile; + PRFileDesc *inCrlInitFile = NULL; + int generateCRL; + int modifyCRL; + int listCRL; + int importCRL; + int showFileCRL; + int deleteCRL; + int rv; + char *nickName; + char *url; + char *dbPrefix = PORT_Strdup(""); + char *alg = NULL; + char *outFile = NULL; + char *slotName = NULL; + int ascii = 0; + int crlType; + PLOptState *optstate; + PLOptStatus status; + SECStatus secstatus; + PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS; + PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS; + PRBool quiet = PR_FALSE; + PRBool test = PR_FALSE; + PRBool erase = PR_FALSE; + PRInt32 i = 0; + PRInt32 iterations = 1; + PRBool readonly = PR_FALSE; + + secuPWData pwdata = { PW_NONE, 0 }; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName + 1 : argv[0]; + + rv = 0; + deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = showFileCRL = 0; + inFile = NULL; + nickName = url = NULL; + certHandle = NULL; + crlType = SEC_CRL_TYPE; + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "sqBCDGILMSTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(); + break; + + case 'T': + test = PR_TRUE; + break; + + case 'E': + erase = PR_TRUE; + break; + + case 'B': + importOptions |= CRL_IMPORT_BYPASS_CHECKS; + break; + + case 'G': + generateCRL = 1; + break; + + case 'M': + modifyCRL = 1; + break; + + case 'D': + deleteCRL = 1; + break; + + case 'I': + importCRL = 1; + break; + + case 'S': + showFileCRL = 1; + break; + + case 'C': + case 'L': + listCRL = 1; + break; + + case 'P': + PORT_Free(dbPrefix); + dbPrefix = PORT_Strdup(optstate->value); + break; + + case 'Z': + alg = PORT_Strdup(optstate->value); + break; + + case 'a': + ascii = 1; + break; + + case 'c': + inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inCrlInitFile) { + PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + rv = SECFailure; + goto loser; + } + break; + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'f': + pwdata.source = PW_FROMFILE; + pwdata.data = PORT_Strdup(optstate->value); + break; + + case 'h': + slotName = PORT_Strdup(optstate->value); + break; + + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + rv = SECFailure; + goto loser; + } + break; + + case 'n': + nickName = PORT_Strdup(optstate->value); + break; + + case 'o': + outFile = PORT_Strdup(optstate->value); + break; + + case 'p': + decodeOptions |= CRL_DECODE_SKIP_ENTRIES; + break; + + case 'r': { + const char *str = optstate->value; + if (str && atoi(str) > 0) + iterations = atoi(str); + } break; + + case 't': { + crlType = atoi(optstate->value); + if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) { + PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName); + rv = SECFailure; + goto loser; + } + break; + + case 'q': + quiet = PR_TRUE; + break; + + case 'w': + pwdata.source = PW_PLAINTEXT; + pwdata.data = PORT_Strdup(optstate->value); + break; + + case 'u': + url = PORT_Strdup(optstate->value); + break; + } + } + } + + if (deleteCRL && !nickName) + Usage(); + if (importCRL && !inFile) + Usage(); + if (showFileCRL && !inFile) + Usage(); + if ((generateCRL && !nickName) || + (modifyCRL && !inFile && !nickName)) + Usage(); + if (!(listCRL || deleteCRL || importCRL || showFileCRL || generateCRL || + modifyCRL || test || erase)) + Usage(); + + if (listCRL || showFileCRL) { + readonly = PR_TRUE; + } + + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + PK11_SetPasswordFunc(SECU_GetModulePassword); + + if (showFileCRL) { + rv = NSS_NoDB_Init(NULL); + if (rv != SECSuccess) { + goto loser; + } + } else { + secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix, + "secmod.db", readonly ? NSS_INIT_READONLY : 0); + if (secstatus != SECSuccess) { + SECU_PrintPRandOSError(progName); + rv = SECFailure; + goto loser; + } + } + + SECU_RegisterDynamicOids(); + + certHandle = CERT_GetDefaultCertDB(); + if (certHandle == NULL) { + SECU_PrintError(progName, "unable to open the cert db"); + rv = SECFailure; + goto loser; + } + + CRLGEN_InitCrlGenParserLock(); + + for (i = 0; i < iterations; i++) { + /* Read in the private key info */ + if (deleteCRL) + DeleteCRL(certHandle, nickName, crlType); + else if (listCRL) { + rv = ListCRL(certHandle, nickName, crlType); + } else if (importCRL) { + rv = ImportCRL(certHandle, url, crlType, inFile, importOptions, + decodeOptions, &pwdata); + } else if (showFileCRL) { + rv = DumpCRL(inFile); + } else if (generateCRL || modifyCRL) { + if (!inCrlInitFile) + inCrlInitFile = PR_STDIN; + rv = GenerateCRL(certHandle, nickName, inCrlInitFile, + inFile, outFile, ascii, slotName, + importOptions, alg, quiet, + decodeOptions, url, &pwdata, + modifyCRL); + } else if (erase) { + /* list and delete all CRLs */ + ListCRLNames(certHandle, crlType, PR_TRUE); + } +#ifdef DEBUG + else if (test) { + /* list and delete all CRLs */ + ListCRLNames(certHandle, crlType, PR_TRUE); + /* list CRLs */ + ListCRLNames(certHandle, crlType, PR_FALSE); + /* import CRL as a blob */ + rv = ImportCRL(certHandle, url, crlType, inFile, importOptions, + decodeOptions, &pwdata); + /* list CRLs */ + ListCRLNames(certHandle, crlType, PR_FALSE); + } +#endif + } + + CRLGEN_DestroyCrlGenParserLock(); + +loser: + PL_DestroyOptState(optstate); + + if (inFile) { + PR_Close(inFile); + } + if (alg) { + PORT_Free(alg); + } + if (slotName) { + PORT_Free(slotName); + } + if (nickName) { + PORT_Free(nickName); + } + if (outFile) { + PORT_Free(outFile); + } + if (url) { + PORT_Free(url); + } + if (pwdata.data) { + PORT_Free(pwdata.data); + } + + PORT_Free(dbPrefix); + + if (NSS_Shutdown() != SECSuccess) { + rv = SECFailure; + } + + return (rv != SECSuccess); +} |