/* 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; #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); } 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"); 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(), 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