michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: ** certutil.c michael@0: ** michael@0: ** utility for managing certificates and the cert database michael@0: ** michael@0: */ michael@0: /* test only */ michael@0: michael@0: #include "nspr.h" michael@0: #include "plgetopt.h" michael@0: #include "secutil.h" michael@0: #include "cert.h" michael@0: #include "certi.h" michael@0: #include "certdb.h" michael@0: #include "nss.h" michael@0: #include "pk11func.h" michael@0: #include "crlgen.h" michael@0: michael@0: #define SEC_CERT_DB_EXISTS 0 michael@0: #define SEC_CREATE_CERT_DB 1 michael@0: michael@0: static char *progName; michael@0: michael@0: static CERTSignedCrl *FindCRL michael@0: (CERTCertDBHandle *certHandle, char *name, int type) michael@0: { michael@0: CERTSignedCrl *crl = NULL; michael@0: CERTCertificate *cert = NULL; michael@0: SECItem derName; michael@0: michael@0: derName.data = NULL; michael@0: derName.len = 0; michael@0: michael@0: cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name); michael@0: if (!cert) { michael@0: CERTName *certName = NULL; michael@0: PLArenaPool *arena = NULL; michael@0: michael@0: certName = CERT_AsciiToName(name); michael@0: if (certName) { michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (arena) { michael@0: SECItem *nameItem = michael@0: SEC_ASN1EncodeItem (arena, NULL, (void *)certName, michael@0: SEC_ASN1_GET(CERT_NameTemplate)); michael@0: if (nameItem) { michael@0: SECITEM_CopyItem(NULL, &derName, nameItem); michael@0: } michael@0: PORT_FreeArena(arena, PR_FALSE); michael@0: } michael@0: CERT_DestroyName(certName); michael@0: } michael@0: michael@0: if (!derName.len || !derName.data) { michael@0: SECU_PrintError(progName, "could not find certificate named '%s'", name); michael@0: return ((CERTSignedCrl *)NULL); michael@0: } michael@0: } else { michael@0: SECITEM_CopyItem(NULL, &derName, &cert->derSubject); michael@0: CERT_DestroyCertificate (cert); michael@0: } michael@0: michael@0: crl = SEC_FindCrlByName(certHandle, &derName, type); michael@0: if (crl ==NULL) michael@0: SECU_PrintError michael@0: (progName, "could not find %s's CRL", name); michael@0: if (derName.data) { michael@0: SECITEM_FreeItem(&derName, PR_FALSE); michael@0: } michael@0: return (crl); michael@0: } michael@0: michael@0: static SECStatus DisplayCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType) michael@0: { michael@0: CERTSignedCrl *crl = NULL; michael@0: michael@0: crl = FindCRL (certHandle, nickName, crlType); michael@0: michael@0: if (crl) { michael@0: SECU_PrintCRLInfo (stdout, &crl->crl, "CRL Info:\n", 0); michael@0: SEC_DestroyCrl (crl); michael@0: return SECSuccess; michael@0: } michael@0: return SECFailure; michael@0: } michael@0: michael@0: static void ListCRLNames (CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls) michael@0: { michael@0: CERTCrlHeadNode *crlList = NULL; michael@0: CERTCrlNode *crlNode = NULL; michael@0: CERTName *name = NULL; michael@0: PLArenaPool *arena = NULL; michael@0: SECStatus rv; michael@0: michael@0: do { michael@0: arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); michael@0: if (arena == NULL) { michael@0: fprintf(stderr, "%s: fail to allocate memory\n", progName); michael@0: break; michael@0: } michael@0: michael@0: name = PORT_ArenaZAlloc (arena, sizeof(*name)); michael@0: if (name == NULL) { michael@0: fprintf(stderr, "%s: fail to allocate memory\n", progName); michael@0: break; michael@0: } michael@0: name->arena = arena; michael@0: michael@0: rv = SEC_LookupCrls (certHandle, &crlList, crlType); michael@0: if (rv != SECSuccess) { michael@0: fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName, michael@0: SECU_Strerror(PORT_GetError())); michael@0: break; michael@0: } michael@0: michael@0: /* just in case */ michael@0: if (!crlList) michael@0: break; michael@0: michael@0: crlNode = crlList->first; michael@0: michael@0: fprintf (stdout, "\n"); michael@0: fprintf (stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type"); michael@0: while (crlNode) { michael@0: char* asciiname = NULL; michael@0: CERTCertificate *cert = NULL; michael@0: if (crlNode->crl && &crlNode->crl->crl.derName) { michael@0: cert = CERT_FindCertByName(certHandle, michael@0: &crlNode->crl->crl.derName); michael@0: if (!cert) { michael@0: SECU_PrintError(progName, "could not find signing " michael@0: "certificate in database"); michael@0: } michael@0: } michael@0: if (cert) { michael@0: char* certName = NULL; michael@0: if (cert->nickname && PORT_Strlen(cert->nickname) > 0) { michael@0: certName = cert->nickname; michael@0: } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) { michael@0: certName = cert->emailAddr; michael@0: } michael@0: if (certName) { michael@0: asciiname = PORT_Strdup(certName); michael@0: } michael@0: CERT_DestroyCertificate(cert); michael@0: } michael@0: michael@0: if (!asciiname) { michael@0: name = &crlNode->crl->crl.name; michael@0: if (!name){ michael@0: SECU_PrintError(progName, "fail to get the CRL " michael@0: "issuer name"); michael@0: continue; michael@0: } michael@0: asciiname = CERT_NameToAscii(name); michael@0: } michael@0: fprintf (stdout, "%-40s %-5s\n", asciiname, "CRL"); michael@0: if (asciiname) { michael@0: PORT_Free(asciiname); michael@0: } michael@0: if ( PR_TRUE == deletecrls) { michael@0: CERTSignedCrl* acrl = NULL; michael@0: SECItem* issuer = &crlNode->crl->crl.derName; michael@0: acrl = SEC_FindCrlByName(certHandle, issuer, crlType); michael@0: if (acrl) michael@0: { michael@0: SEC_DeletePermCRL(acrl); michael@0: SEC_DestroyCrl(acrl); michael@0: } michael@0: } michael@0: crlNode = crlNode->next; michael@0: } michael@0: michael@0: } while (0); michael@0: if (crlList) michael@0: PORT_FreeArena (crlList->arena, PR_FALSE); michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: } michael@0: michael@0: static SECStatus ListCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType) michael@0: { michael@0: if (nickName == NULL) { michael@0: ListCRLNames (certHandle, crlType, PR_FALSE); michael@0: return SECSuccess; michael@0: } michael@0: michael@0: return DisplayCRL (certHandle, nickName, crlType); michael@0: } michael@0: michael@0: michael@0: michael@0: static SECStatus DeleteCRL (CERTCertDBHandle *certHandle, char *name, int type) michael@0: { michael@0: CERTSignedCrl *crl = NULL; michael@0: SECStatus rv = SECFailure; michael@0: michael@0: crl = FindCRL (certHandle, name, type); michael@0: if (!crl) { michael@0: SECU_PrintError michael@0: (progName, "could not find the issuer %s's CRL", name); michael@0: return SECFailure; michael@0: } michael@0: rv = SEC_DeletePermCRL (crl); michael@0: SEC_DestroyCrl(crl); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "fail to delete the issuer %s's CRL " michael@0: "from the perm database (reason: %s)", michael@0: name, SECU_Strerror(PORT_GetError())); michael@0: return SECFailure; michael@0: } michael@0: return (rv); michael@0: } michael@0: michael@0: SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type, michael@0: PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions, michael@0: secuPWData *pwdata) michael@0: { michael@0: CERTSignedCrl *crl = NULL; michael@0: SECItem crlDER; michael@0: PK11SlotInfo* slot = NULL; michael@0: int rv; michael@0: #if defined(DEBUG_jp96085) michael@0: PRIntervalTime starttime, endtime, elapsed; michael@0: PRUint32 mins, secs, msecs; michael@0: #endif michael@0: michael@0: crlDER.data = NULL; michael@0: michael@0: michael@0: /* Read in the entire file specified with the -f argument */ michael@0: rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "unable to read input file"); michael@0: return (SECFailure); michael@0: } michael@0: michael@0: decodeOptions |= CRL_DECODE_DONT_COPY_DER; michael@0: michael@0: slot = PK11_GetInternalKeySlot(); michael@0: michael@0: if (PK11_NeedLogin(slot)) { michael@0: rv = PK11_Authenticate(slot, PR_TRUE, pwdata); michael@0: if (rv != SECSuccess) michael@0: goto loser; michael@0: } michael@0: michael@0: #if defined(DEBUG_jp96085) michael@0: starttime = PR_IntervalNow(); michael@0: #endif michael@0: crl = PK11_ImportCRL(slot, &crlDER, url, type, michael@0: NULL, importOptions, NULL, decodeOptions); michael@0: #if defined(DEBUG_jp96085) michael@0: endtime = PR_IntervalNow(); michael@0: elapsed = endtime - starttime; michael@0: mins = PR_IntervalToSeconds(elapsed) / 60; michael@0: secs = PR_IntervalToSeconds(elapsed) % 60; michael@0: msecs = PR_IntervalToMilliseconds(elapsed) % 1000; michael@0: printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs); michael@0: #endif michael@0: if (!crl) { michael@0: const char *errString; michael@0: michael@0: rv = SECFailure; michael@0: errString = SECU_Strerror(PORT_GetError()); michael@0: if ( errString && PORT_Strlen (errString) == 0) michael@0: SECU_PrintError (progName, michael@0: "CRL is not imported (error: input CRL is not up to date.)"); michael@0: else michael@0: SECU_PrintError (progName, "unable to import CRL"); michael@0: } else { michael@0: SEC_DestroyCrl (crl); michael@0: } michael@0: loser: michael@0: if (slot) { michael@0: PK11_FreeSlot(slot); michael@0: } michael@0: return (rv); michael@0: } michael@0: michael@0: SECStatus DumpCRL(PRFileDesc *inFile) michael@0: { michael@0: int rv; michael@0: PLArenaPool *arena = NULL; michael@0: CERTSignedCrl *newCrl = NULL; michael@0: michael@0: SECItem crlDER; michael@0: crlDER.data = NULL; michael@0: michael@0: /* Read in the entire file specified with the -f argument */ michael@0: rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "unable to read input file"); michael@0: return (SECFailure); michael@0: } michael@0: michael@0: rv = SEC_ERROR_NO_MEMORY; michael@0: arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); michael@0: if (!arena) michael@0: return rv; michael@0: michael@0: newCrl = CERT_DecodeDERCrlWithFlags(arena, &crlDER, SEC_CRL_TYPE, michael@0: CRL_DECODE_DEFAULT_OPTIONS); michael@0: if (!newCrl) michael@0: return SECFailure; michael@0: michael@0: SECU_PrintCRLInfo (stdout, &newCrl->crl, "CRL file contents", 0); michael@0: michael@0: PORT_FreeArena (arena, PR_FALSE); michael@0: return rv; michael@0: } michael@0: michael@0: static CERTCertificate* michael@0: FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl, michael@0: char *certNickName) michael@0: { michael@0: CERTCertificate *cert = NULL, *certTemp = NULL; michael@0: SECStatus rv = SECFailure; michael@0: CERTAuthKeyID* authorityKeyID = NULL; michael@0: SECItem* subject = NULL; michael@0: michael@0: PORT_Assert(certHandle != NULL); michael@0: if (!certHandle || (!signCrl && !certNickName)) { michael@0: SECU_PrintError(progName, "invalid args for function " michael@0: "FindSigningCert \n"); michael@0: return NULL; michael@0: } michael@0: michael@0: if (signCrl) { michael@0: #if 0 michael@0: authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl); michael@0: #endif michael@0: subject = &signCrl->crl.derName; michael@0: } else { michael@0: certTemp = CERT_FindCertByNickname(certHandle, certNickName); michael@0: if (!certTemp) { michael@0: SECU_PrintError(progName, "could not find certificate \"%s\" " michael@0: "in database", certNickName); michael@0: goto loser; michael@0: } michael@0: subject = &certTemp->derSubject; michael@0: } michael@0: michael@0: cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now()); michael@0: if (!cert) { michael@0: SECU_PrintError(progName, "could not find signing certificate " michael@0: "in database"); michael@0: goto loser; michael@0: } else { michael@0: rv = SECSuccess; michael@0: } michael@0: michael@0: loser: michael@0: if (certTemp) michael@0: CERT_DestroyCertificate(certTemp); michael@0: if (cert && rv != SECSuccess) michael@0: CERT_DestroyCertificate(cert); michael@0: return cert; michael@0: } michael@0: michael@0: static CERTSignedCrl* michael@0: CreateModifiedCRLCopy(PLArenaPool *arena, CERTCertDBHandle *certHandle, michael@0: CERTCertificate **cert, char *certNickName, michael@0: PRFileDesc *inFile, PRInt32 decodeOptions, michael@0: PRInt32 importOptions) michael@0: { michael@0: SECItem crlDER = {0, NULL, 0}; michael@0: CERTSignedCrl *signCrl = NULL; michael@0: CERTSignedCrl *modCrl = NULL; michael@0: PLArenaPool *modArena = NULL; michael@0: SECStatus rv = SECSuccess; michael@0: michael@0: if (!arena || !certHandle || !certNickName) { michael@0: PORT_SetError(SEC_ERROR_INVALID_ARGS); michael@0: SECU_PrintError(progName, "CreateModifiedCRLCopy: invalid args\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); michael@0: if (!modArena) { michael@0: SECU_PrintError(progName, "fail to allocate memory\n"); michael@0: return NULL; michael@0: } michael@0: michael@0: if (inFile != NULL) { michael@0: rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "unable to read input file"); michael@0: PORT_FreeArena(modArena, PR_FALSE); michael@0: goto loser; michael@0: } michael@0: michael@0: decodeOptions |= CRL_DECODE_DONT_COPY_DER; michael@0: michael@0: modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE, michael@0: decodeOptions); michael@0: if (!modCrl) { michael@0: SECU_PrintError(progName, "fail to decode CRL"); michael@0: goto loser; michael@0: } michael@0: michael@0: if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){ michael@0: /* If caCert is a v2 certificate, make sure that it michael@0: * can be used for crl signing purpose */ michael@0: *cert = FindSigningCert(certHandle, modCrl, NULL); michael@0: if (!*cert) { michael@0: goto loser; michael@0: } michael@0: michael@0: rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert, michael@0: PR_Now(), NULL); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "fail to verify signed data\n"); michael@0: goto loser; michael@0: } michael@0: } michael@0: } else { michael@0: modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE); michael@0: if (!modCrl) { michael@0: SECU_PrintError(progName, "fail to find crl %s in database\n", michael@0: certNickName); michael@0: goto loser; michael@0: } michael@0: } michael@0: michael@0: signCrl = PORT_ArenaZNew(arena, CERTSignedCrl); michael@0: if (signCrl == NULL) { michael@0: SECU_PrintError(progName, "fail to allocate memory\n"); michael@0: goto loser; michael@0: } michael@0: michael@0: rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl); michael@0: if (rv != SECSuccess) { michael@0: SECU_PrintError(progName, "unable to dublicate crl for " michael@0: "modification."); michael@0: goto loser; michael@0: } michael@0: michael@0: /* Make sure the update time is current. It can be modified later michael@0: * by "update