diff -r 000000000000 -r 6474c204b198 security/nss/cmd/crlutil/crlutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/security/nss/cmd/crlutil/crlutil.c Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,1109 @@ +/* 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; + + 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) { + SECITEM_CopyItem(NULL, &derName, nameItem); + } + PORT_FreeArena(arena, PR_FALSE); + } + CERT_DestroyName(certName); + } + + if (!derName.len || !derName.data) { + SECU_PrintError(progName, "could not find certificate named '%s'", name); + return ((CERTSignedCrl *)NULL); + } + } else { + SECITEM_CopyItem(NULL, &derName, &cert->derSubject); + CERT_DestroyCertificate (cert); + } + + 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) { + 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; +#if defined(DEBUG_jp96085) + PRIntervalTime starttime, endtime, elapsed; + PRUint32 mins, secs, msecs; +#endif + + 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; + } + +#if defined(DEBUG_jp96085) + starttime = PR_IntervalNow(); +#endif + crl = PK11_ImportCRL(slot, &crlDER, url, type, + NULL, importOptions, NULL, decodeOptions); +#if defined(DEBUG_jp96085) + endtime = PR_IntervalNow(); + elapsed = endtime - starttime; + mins = PR_IntervalToSeconds(elapsed) / 60; + secs = PR_IntervalToSeconds(elapsed) % 60; + msecs = PR_IntervalToMilliseconds(elapsed) % 1000; + printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs); +#endif + 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); + } + 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) +{ + 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"); + PORT_FreeArena(modArena, PR_FALSE); + 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(), NULL); + 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