PRStatus PR_CALLBACK nsNSSComponent::IdentityInfoInit() { for (size_t iEV=0; iEV < (sizeof(myTrustedEVInfos)/sizeof(nsMyTrustedEVInfo)); ++iEV) { nsMyTrustedEVInfo &entry = myTrustedEVInfos[iEV]; if (!entry.oid_name) // invalid or placeholder list entry continue; SECStatus rv; CERTIssuerAndSN ias; rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(entry.issuer_base64)); NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary."); rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(entry.serial_base64)); NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary."); entry.cert = CERT_FindCertByIssuerAndSN(nsnull, &ias); NS_ASSERTION(entry.cert, "Could not find EV root in NSS storage"); if (!entry.cert) continue; nsNSSCertificate c(entry.cert); nsAutoString fingerprint; c.GetSha1Fingerprint(fingerprint); NS_ConvertASCIItoUTF16 sha1(entry.ev_root_sha1_fingerprint); if (sha1 != fingerprint) { NS_ASSERTION(sha1 == fingerprint, "found EV root with unexpected SHA1 mismatch"); CERT_DestroyCertificate(entry.cert); entry.cert = nsnull; continue; } SECItem ev_oid_item; ev_oid_item.data = nsnull; ev_oid_item.len = 0; SECStatus srv = SEC_StringToOID(nsnull, &ev_oid_item, entry.dotted_oid, 0); if (srv != SECSuccess) continue; entry.oid_tag = register_oid(&ev_oid_item, entry.oid_name); SECITEM_FreeItem(&ev_oid_item, PR_FALSE); } #ifdef PSM_ENABLE_TEST_EV_ROOTS if (!testEVInfosLoaded) { testEVInfosLoaded = PR_TRUE; testEVInfos = new testEVArray; if (testEVInfos) { loadTestEVInfos(); } } #endif return PR_SUCCESS; }
static nsresult GetCertFingerprintByDottedOidString(CERTCertificate* nsscert, const nsCString &dottedOid, nsCString &fp) { SECItem oid; oid.data = nsnull; oid.len = 0; SECStatus srv = SEC_StringToOID(nsnull, &oid, dottedOid.get(), dottedOid.Length()); if (srv != SECSuccess) return NS_ERROR_FAILURE; SECOidTag oid_tag = SECOID_FindOIDTag(&oid); SECITEM_FreeItem(&oid, PR_FALSE); if (oid_tag == SEC_OID_UNKNOWN) return NS_ERROR_FAILURE; return GetCertFingerprintByOidTag(nsscert, oid_tag, fp); }
static void loadTestEVInfos() { if (!testEVInfos) return; testEVInfos->Clear(); char *env_val = getenv("ENABLE_TEST_EV_ROOTS_FILE"); if (!env_val) return; int enabled_val = atoi(env_val); if (!enabled_val) return; nsCOMPtr<nsIFile> aFile; NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(aFile)); if (!aFile) return; aFile->AppendNative(NS_LITERAL_CSTRING(kTestEVRootsFileName)); nsresult rv; nsCOMPtr<nsIInputStream> fileInputStream; rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInputStream), aFile); if (NS_FAILED(rv)) return; nsCOMPtr<nsILineInputStream> lineInputStream = do_QueryInterface(fileInputStream, &rv); if (NS_FAILED(rv)) return; nsCAutoString buffer; PRBool isMore = PR_TRUE; /* file format * * file format must be strictly followed * strings in file must be UTF-8 * each record consists of multiple lines * each line consists of a descriptor, a single space, and the data * the descriptors are: * 1_fingerprint (in format XX:XX:XX:...) * 2_readable_oid (treated as a comment) * the input file must strictly follow this order * the input file may contain 0, 1 or many records * completely empty lines are ignored * lines that start with the # char are ignored */ int line_counter = 0; PRBool found_error = PR_FALSE; enum { pos_fingerprint, pos_readable_oid, pos_issuer, pos_serial } reader_position = pos_fingerprint; nsCString fingerprint, readable_oid, issuer, serial; while (isMore && NS_SUCCEEDED(lineInputStream->ReadLine(buffer, &isMore))) { ++line_counter; if (buffer.IsEmpty() || buffer.First() == '#') { continue; } PRInt32 seperatorIndex = buffer.FindChar(' ', 0); if (seperatorIndex == 0) { found_error = PR_TRUE; break; } const nsASingleFragmentCString &descriptor = Substring(buffer, 0, seperatorIndex); const nsASingleFragmentCString &data = Substring(buffer, seperatorIndex + 1, buffer.Length() - seperatorIndex + 1); if (reader_position == pos_fingerprint && descriptor.EqualsLiteral(("1_fingerprint"))) { fingerprint = data; reader_position = pos_readable_oid; continue; } else if (reader_position == pos_readable_oid && descriptor.EqualsLiteral(("2_readable_oid"))) { readable_oid = data; reader_position = pos_issuer; continue; } else if (reader_position == pos_issuer && descriptor.EqualsLiteral(("3_issuer"))) { issuer = data; reader_position = pos_serial; continue; } else if (reader_position == pos_serial && descriptor.EqualsLiteral(("4_serial"))) { serial = data; reader_position = pos_fingerprint; } else { found_error = PR_TRUE; break; } nsMyTrustedEVInfoClass *temp_ev = new nsMyTrustedEVInfoClass; if (!temp_ev) return; temp_ev->ev_root_sha1_fingerprint = strdup(fingerprint.get()); temp_ev->oid_name = strdup(readable_oid.get()); temp_ev->dotted_oid = strdup(readable_oid.get()); temp_ev->issuer_base64 = strdup(issuer.get()); temp_ev->serial_base64 = strdup(serial.get()); SECStatus rv; CERTIssuerAndSN ias; rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(temp_ev->issuer_base64)); NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary."); rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(temp_ev->serial_base64)); NS_ASSERTION(rv==SECSuccess, "error converting ascii to binary."); temp_ev->cert = CERT_FindCertByIssuerAndSN(nsnull, &ias); NS_ASSERTION(temp_ev->cert, "Could not find EV root in NSS storage"); if (!temp_ev->cert) return; nsNSSCertificate c(temp_ev->cert); nsAutoString fingerprint; c.GetSha1Fingerprint(fingerprint); NS_ConvertASCIItoUTF16 sha1(temp_ev->ev_root_sha1_fingerprint); if (sha1 != fingerprint) { NS_ASSERTION(sha1 == fingerprint, "found EV root with unexpected SHA1 mismatch"); CERT_DestroyCertificate(temp_ev->cert); temp_ev->cert = nsnull; return; } SECItem ev_oid_item; ev_oid_item.data = nsnull; ev_oid_item.len = 0; SECStatus srv = SEC_StringToOID(nsnull, &ev_oid_item, readable_oid.get(), readable_oid.Length()); if (srv != SECSuccess) { delete temp_ev; found_error = PR_TRUE; break; } temp_ev->oid_tag = register_oid(&ev_oid_item, temp_ev->oid_name); SECITEM_FreeItem(&ev_oid_item, PR_FALSE); testEVInfos->AppendElement(temp_ev); } if (found_error) { fprintf(stderr, "invalid line %d in test_ev_roots file\n", line_counter); } }
int main(int argc, char *argv[], char *envp[]) { char * certDir = NULL; char * progName = NULL; char * oidStr = NULL; CERTCertificate * cert; CERTCertificate * firstCert = NULL; CERTCertificate * issuerCert = NULL; CERTCertDBHandle * defaultDB = NULL; PRBool isAscii = PR_FALSE; PRBool trusted = PR_FALSE; SECStatus secStatus; SECCertificateUsage certUsage = certificateUsageSSLServer; PLOptState * optstate; PRTime time = 0; PLOptStatus status; int usePkix = 0; int rv = 1; int usage; CERTVerifyLog log; CERTCertList *builtChain = NULL; PRBool certFetching = PR_FALSE; int revDataIndex = 0; PRBool ocsp_fetchingFailureIsAFailure = PR_TRUE; PRBool useDefaultRevFlags = PR_TRUE; int vfyCounts = 1; PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); progName = PL_strdup(argv[0]); optstate = PL_CreateOptState(argc, argv, "ab:c:d:efg:h:i:m:o:prs:tu:vw:W:"); while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { switch(optstate->option) { case 0 : /* positional parameter */ goto breakout; case 'a' : isAscii = PR_TRUE; break; case 'b' : secStatus = DER_AsciiToTime(&time, optstate->value); if (secStatus != SECSuccess) Usage(progName); break; case 'd' : certDir = PL_strdup(optstate->value); break; case 'e' : ocsp_fetchingFailureIsAFailure = PR_FALSE; break; case 'f' : certFetching = PR_TRUE; break; case 'g' : if (revMethodsData[revDataIndex].testTypeStr || revMethodsData[revDataIndex].methodTypeStr) { revDataIndex += 1; if (revDataIndex == REV_METHOD_INDEX_MAX) { fprintf(stderr, "Invalid revocation configuration" "specified.\n"); secStatus = SECFailure; break; } } useDefaultRevFlags = PR_FALSE; revMethodsData[revDataIndex]. testTypeStr = PL_strdup(optstate->value); break; case 'h' : revMethodsData[revDataIndex]. testFlagsStr = PL_strdup(optstate->value);break; case 'i' : vfyCounts = PORT_Atoi(optstate->value); break; break; case 'm' : if (revMethodsData[revDataIndex].methodTypeStr) { revDataIndex += 1; if (revDataIndex == REV_METHOD_INDEX_MAX) { fprintf(stderr, "Invalid revocation configuration" "specified.\n"); secStatus = SECFailure; break; } } useDefaultRevFlags = PR_FALSE; revMethodsData[revDataIndex]. methodTypeStr = PL_strdup(optstate->value); break; case 'o' : oidStr = PL_strdup(optstate->value); break; case 'p' : usePkix += 1; break; case 'r' : isAscii = PR_FALSE; break; case 's' : revMethodsData[revDataIndex]. methodFlagsStr = PL_strdup(optstate->value); break; case 't' : trusted = PR_TRUE; break; case 'u' : usage = PORT_Atoi(optstate->value); if (usage < 0 || usage > 62) Usage(progName); certUsage = ((SECCertificateUsage)1) << usage; if (certUsage > certificateUsageHighest) Usage(progName); break; case 'w': pwdata.source = PW_PLAINTEXT; pwdata.data = PORT_Strdup(optstate->value); break; case 'W': pwdata.source = PW_FROMFILE; pwdata.data = PORT_Strdup(optstate->value); break; case 'v' : verbose++; break; default : Usage(progName); break; } } breakout: if (status != PL_OPT_OK) Usage(progName); if (usePkix < 2) { if (oidStr) { fprintf(stderr, "Policy oid(-o) can be used only with" " CERT_PKIXVerifyChain(-pp) function.\n"); Usage(progName); } if (trusted) { fprintf(stderr, "Cert trust flag can be used only with" " CERT_PKIXVerifyChain(-pp) function.\n"); Usage(progName); } } if (!useDefaultRevFlags && parseRevMethodsAndFlags()) { fprintf(stderr, "Invalid revocation configuration specified.\n"); goto punt; } /* Set our password function callback. */ PK11_SetPasswordFunc(SECU_GetModulePassword); /* Initialize the NSS libraries. */ if (certDir) { secStatus = NSS_Init(certDir); } else { secStatus = NSS_NoDB_Init(NULL); /* load the builtins */ SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); } if (secStatus != SECSuccess) { exitErr("NSS_Init"); } SECU_RegisterDynamicOids(); if (isOCSPEnabled()) { CERT_EnableOCSPChecking(CERT_GetDefaultCertDB()); CERT_DisableOCSPDefaultResponder(CERT_GetDefaultCertDB()); if (!ocsp_fetchingFailureIsAFailure) { CERT_SetOCSPFailureMode(ocspMode_FailureIsNotAVerificationFailure); } } while (status == PL_OPT_OK) { switch(optstate->option) { default : Usage(progName); break; case 'a' : isAscii = PR_TRUE; break; case 'r' : isAscii = PR_FALSE; break; case 't' : trusted = PR_TRUE; break; case 0 : /* positional parameter */ if (usePkix < 2 && trusted) { fprintf(stderr, "Cert trust flag can be used only with" " CERT_PKIXVerifyChain(-pp) function.\n"); Usage(progName); } cert = getCert(optstate->value, isAscii, progName); if (!cert) goto punt; rememberCert(cert, trusted); if (!firstCert) firstCert = cert; trusted = PR_FALSE; } status = PL_GetNextOpt(optstate); } PL_DestroyOptState(optstate); if (status == PL_OPT_BAD || !firstCert) Usage(progName); /* Initialize log structure */ log.arena = PORT_NewArena(512); log.head = log.tail = NULL; log.count = 0; do { if (usePkix < 2) { /* NOW, verify the cert chain. */ if (usePkix) { /* Use old API with libpkix validation lib */ CERT_SetUsePKIXForValidation(PR_TRUE); } if (!time) time = PR_Now(); defaultDB = CERT_GetDefaultCertDB(); secStatus = CERT_VerifyCertificate(defaultDB, firstCert, PR_TRUE /* check sig */, certUsage, time, &pwdata, /* wincx */ &log, /* error log */ NULL);/* returned usages */ } else do { static CERTValOutParam cvout[4]; static CERTValInParam cvin[6]; SECOidTag oidTag; int inParamIndex = 0; static PRUint64 revFlagsLeaf[2]; static PRUint64 revFlagsChain[2]; static CERTRevocationFlags rev; if (oidStr) { PRArenaPool *arena; SECOidData od; memset(&od, 0, sizeof od); od.offset = SEC_OID_UNKNOWN; od.desc = "User Defined Policy OID"; od.mechanism = CKM_INVALID_MECHANISM; od.supportedExtension = INVALID_CERT_EXTENSION; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if ( !arena ) { fprintf(stderr, "out of memory"); goto punt; } secStatus = SEC_StringToOID(arena, &od.oid, oidStr, 0); if (secStatus != SECSuccess) { PORT_FreeArena(arena, PR_FALSE); fprintf(stderr, "Can not encode oid: %s(%s)\n", oidStr, SECU_Strerror(PORT_GetError())); break; } oidTag = SECOID_AddEntry(&od); PORT_FreeArena(arena, PR_FALSE); if (oidTag == SEC_OID_UNKNOWN) { fprintf(stderr, "Can not add new oid to the dynamic " "table: %s\n", oidStr); secStatus = SECFailure; break; } cvin[inParamIndex].type = cert_pi_policyOID; cvin[inParamIndex].value.arraySize = 1; cvin[inParamIndex].value.array.oids = &oidTag; inParamIndex++; } if (trustedCertList) { cvin[inParamIndex].type = cert_pi_trustAnchors; cvin[inParamIndex].value.pointer.chain = trustedCertList; inParamIndex++; } cvin[inParamIndex].type = cert_pi_useAIACertFetch; cvin[inParamIndex].value.scalar.b = certFetching; inParamIndex++; rev.leafTests.cert_rev_flags_per_method = revFlagsLeaf; rev.chainTests.cert_rev_flags_per_method = revFlagsChain; secStatus = configureRevocationParams(&rev); if (secStatus) { fprintf(stderr, "Can not config revocation parameters "); break; } cvin[inParamIndex].type = cert_pi_revocationFlags; cvin[inParamIndex].value.pointer.revocation = &rev; inParamIndex++; if (time) { cvin[inParamIndex].type = cert_pi_date; cvin[inParamIndex].value.scalar.time = time; inParamIndex++; } cvin[inParamIndex].type = cert_pi_end; cvout[0].type = cert_po_trustAnchor; cvout[0].value.pointer.cert = NULL; cvout[1].type = cert_po_certList; cvout[1].value.pointer.chain = NULL; /* setting pointer to CERTVerifyLog. Initialized structure * will be used CERT_PKIXVerifyCert */ cvout[2].type = cert_po_errorLog; cvout[2].value.pointer.log = &log; cvout[3].type = cert_po_end; secStatus = CERT_PKIXVerifyCert(firstCert, certUsage, cvin, cvout, &pwdata); if (secStatus != SECSuccess) { break; } issuerCert = cvout[0].value.pointer.cert; builtChain = cvout[1].value.pointer.chain; } while (0); /* Display validation results */ if (secStatus != SECSuccess || log.count > 0) { CERTVerifyLogNode *node = NULL; PRIntn err = PR_GetError(); fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err)); SECU_displayVerifyLog(stderr, &log, verbose); /* Have cert refs in the log only in case of failure. * Destroy them. */ for (node = log.head; node; node = node->next) { if (node->cert) CERT_DestroyCertificate(node->cert); } rv = 1; } else { fprintf(stderr, "Chain is good!\n"); if (issuerCert) { if (verbose > 1) { rv = SEC_PrintCertificateAndTrust(issuerCert, "Root Certificate", NULL); if (rv != SECSuccess) { SECU_PrintError(progName, "problem printing certificate"); } } else if (verbose > 0) { SECU_PrintName(stdout, &issuerCert->subject, "Root " "Certificate Subject:", 0); } CERT_DestroyCertificate(issuerCert); } if (builtChain) { CERTCertListNode *node; int count = 0; char buff[256]; if (verbose) { for(node = CERT_LIST_HEAD(builtChain); !CERT_LIST_END(node, builtChain); node = CERT_LIST_NEXT(node), count++ ) { sprintf(buff, "Certificate %d Subject", count + 1); SECU_PrintName(stdout, &node->cert->subject, buff, 0); } } CERT_DestroyCertList(builtChain); } rv = 0; } } while (--vfyCounts > 0); /* Need to destroy CERTVerifyLog arena at the end */ PORT_FreeArena(log.arena, PR_FALSE); punt: forgetCerts(); if (NSS_Shutdown() != SECSuccess) { SECU_PrintError(progName, "NSS_Shutdown"); rv = 1; } PORT_Free(progName); PORT_Free(certDir); PORT_Free(oidStr); freeRevocationMethodData(); if (pwdata.data) { PORT_Free(pwdata.data); } PR_Cleanup(); return rv; }
/* Parses one AVA, starting at *pbp. Stops at endptr. * Advances *pbp past parsed AVA and trailing separator (if present). * On any error, returns NULL and *pbp is undefined. * On success, returns CERTAVA allocated from arena, and (*pbp)[-1] was * the last character parsed. *pbp is either equal to endptr or * points to first character after separator. */ static CERTAVA * ParseRFC1485AVA(PRArenaPool *arena, char **pbp, char *endptr) { CERTAVA *a; const NameToKind *n2k; char *bp; int vt = -1; int valLen; SECOidTag kind = SEC_OID_UNKNOWN; SECStatus rv = SECFailure; SECItem derOid = { 0, NULL, 0 }; SECItem derVal = { 0, NULL, 0}; char sep = 0; char tagBuf[32]; char valBuf[384]; PORT_Assert(arena); if (SECSuccess != scanTag(pbp, endptr, tagBuf, sizeof tagBuf) || !(valLen = scanVal(pbp, endptr, valBuf, sizeof valBuf))) { goto loser; } bp = *pbp; if (bp < endptr) { sep = *bp++; /* skip over separator */ } *pbp = bp; /* if we haven't finished, insist that we've stopped on a separator */ if (sep && sep != ',' && sep != ';' && sep != '+') { goto loser; } /* is this a dotted decimal OID attribute type ? */ if (!PL_strncasecmp("oid.", tagBuf, 4)) { rv = SEC_StringToOID(arena, &derOid, tagBuf, strlen(tagBuf)); } else { for (n2k = name2kinds; n2k->name; n2k++) { SECOidData *oidrec; if (PORT_Strcasecmp(n2k->name, tagBuf) == 0) { kind = n2k->kind; vt = n2k->valueType; oidrec = SECOID_FindOIDByTag(kind); if (oidrec == NULL) goto loser; derOid = oidrec->oid; break; } } } if (kind == SEC_OID_UNKNOWN && rv != SECSuccess) goto loser; /* Is this a hex encoding of a DER attribute value ? */ if ('#' == valBuf[0]) { /* convert attribute value from hex to binary */ rv = hexToBin(arena, &derVal, valBuf + 1, valLen - 1); if (rv) goto loser; a = CERT_CreateAVAFromRaw(arena, &derOid, &derVal); } else { if (kind == SEC_OID_UNKNOWN) goto loser; if (kind == SEC_OID_AVA_COUNTRY_NAME && valLen != 2) goto loser; if (vt == SEC_ASN1_PRINTABLE_STRING && !IsPrintable((unsigned char*) valBuf, valLen)) goto loser; if (vt == SEC_ASN1_DS) { /* RFC 4630: choose PrintableString or UTF8String */ if (IsPrintable((unsigned char*) valBuf, valLen)) vt = SEC_ASN1_PRINTABLE_STRING; else vt = SEC_ASN1_UTF8_STRING; } derVal.data = (unsigned char*) valBuf; derVal.len = valLen; a = CERT_CreateAVAFromSECItem(arena, kind, vt, &derVal); } return a; loser: /* matched no kind -- invalid tag */ PORT_SetError(SEC_ERROR_INVALID_AVA); return 0; }
static PRStatus IdentityInfoInit() { for (size_t iEV = 0; iEV < PR_ARRAY_SIZE(myTrustedEVInfos); ++iEV) { nsMyTrustedEVInfo& entry = myTrustedEVInfos[iEV]; SECStatus rv; CERTIssuerAndSN ias; rv = ATOB_ConvertAsciiToItem(&ias.derIssuer, const_cast<char*>(entry.issuer_base64)); PR_ASSERT(rv == SECSuccess); if (rv != SECSuccess) { return PR_FAILURE; } rv = ATOB_ConvertAsciiToItem(&ias.serialNumber, const_cast<char*>(entry.serial_base64)); PR_ASSERT(rv == SECSuccess); if (rv != SECSuccess) { SECITEM_FreeItem(&ias.derIssuer, false); return PR_FAILURE; } ias.serialNumber.type = siUnsignedInteger; entry.cert = CERT_FindCertByIssuerAndSN(nullptr, &ias); SECITEM_FreeItem(&ias.derIssuer, false); SECITEM_FreeItem(&ias.serialNumber, false); // If an entry is missing in the NSS root database, it may be because the // root database is out of sync with what we expect (e.g. a different // version of system NSS is installed). We will just silently avoid // treating that root cert as EV. if (!entry.cert) { #ifdef DEBUG // The debug CA info is at position 0, and is NOT on the NSS root db if (iEV == 0) { continue; } #endif PR_NOT_REACHED("Could not find EV root in NSS storage"); continue; } unsigned char certFingerprint[20]; rv = PK11_HashBuf(SEC_OID_SHA1, certFingerprint, entry.cert->derCert.data, entry.cert->derCert.len); PR_ASSERT(rv == SECSuccess); if (rv == SECSuccess) { bool same = !memcmp(certFingerprint, entry.ev_root_sha1_fingerprint, 20); PR_ASSERT(same); if (same) { SECItem ev_oid_item; ev_oid_item.data = nullptr; ev_oid_item.len = 0; rv = SEC_StringToOID(nullptr, &ev_oid_item, entry.dotted_oid, 0); PR_ASSERT(rv == SECSuccess); if (rv == SECSuccess) { entry.oid_tag = register_oid(&ev_oid_item, entry.oid_name); if (entry.oid_tag == SEC_OID_UNKNOWN) { rv = SECFailure; } SECITEM_FreeItem(&ev_oid_item, false); } } else { PR_SetError(SEC_ERROR_BAD_DATA, 0); rv = SECFailure; } } if (rv != SECSuccess) { CERT_DestroyCertificate(entry.cert); entry.cert = nullptr; entry.oid_tag = SEC_OID_UNKNOWN; return PR_FAILURE; } } return PR_SUCCESS; }