| /* 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) { |
| NSS_NoDB_Init(NULL); |
| } 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); |
| } |