SECStatus PathBuildingStep::RecordResult(PRErrorCode newResult, /*out*/ bool& keepGoing) { if (newResult == SEC_ERROR_UNTRUSTED_CERT) { newResult = SEC_ERROR_UNTRUSTED_ISSUER; } if (resultWasSet) { if (result == 0) { PR_NOT_REACHED("RecordResult called after finding a chain"); PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); return SECFailure; } // If every potential issuer has the same problem (e.g. expired) and/or if // there is only one bad potential issuer, then return a more specific // error. Otherwise, punt on trying to decide which error should be // returned by returning the generic SEC_ERROR_UNKNOWN_ISSUER error. if (newResult != 0 && newResult != result) { newResult = SEC_ERROR_UNKNOWN_ISSUER; } } result = newResult; resultWasSet = true; keepGoing = result != 0; return SECSuccess; }
Result PathBuildingStep::RecordResult(Result newResult, /*out*/ bool& keepGoing) { if (newResult == Result::ERROR_UNTRUSTED_CERT) { newResult = Result::ERROR_UNTRUSTED_ISSUER; } if (resultWasSet) { if (result == Success) { PR_NOT_REACHED("RecordResult called after finding a chain"); return Result::FATAL_ERROR_INVALID_STATE; } // If every potential issuer has the same problem (e.g. expired) and/or if // there is only one bad potential issuer, then return a more specific // error. Otherwise, punt on trying to decide which error should be // returned by returning the generic Result::ERROR_UNKNOWN_ISSUER error. if (newResult != Success && newResult != result) { newResult = Result::ERROR_UNKNOWN_ISSUER; } } result = newResult; resultWasSet = true; keepGoing = result != Success; return Success; }
static PRStatus AddModule(const nsID &target, ipcModuleMethods *methods, const char *libPath) { if (ipcModuleCount == IPC_MAX_MODULE_COUNT) { LOG(("too many modules!\n")); return PR_FAILURE; } if (!methods) { PR_NOT_REACHED("null module methods"); return PR_FAILURE; } // // each ipcModuleRegEntry holds a reference to a PRLibrary, and on // shutdown, each PRLibrary reference will be released. this ensures // that the library will not be unloaded until all of the modules in // that library are shutdown. // ipcModules[ipcModuleCount].target = target; ipcModules[ipcModuleCount].methods = methods; ipcModules[ipcModuleCount].lib = PR_LoadLibrary(libPath); ++ipcModuleCount; return PR_SUCCESS; }
PRWord *_MD_HomeGCRegisters(PRThread *t, int isCurrent, int *np) { #if defined(_X86_) CONTEXT context; context.ContextFlags = CONTEXT_INTEGER; if (_PR_IS_NATIVE_THREAD(t)) { context.ContextFlags |= CONTEXT_CONTROL; if (GetThreadContext(t->md.handle, &context)) { t->md.gcContext[0] = context.Eax; t->md.gcContext[1] = context.Ebx; t->md.gcContext[2] = context.Ecx; t->md.gcContext[3] = context.Edx; t->md.gcContext[4] = context.Esi; t->md.gcContext[5] = context.Edi; t->md.gcContext[6] = context.Esp; t->md.gcContext[7] = context.Ebp; *np = PR_NUM_GCREGS; } else { PR_ASSERT(0);/* XXX */ } } else { /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING * * This code is extremely machine dependant and completely * undocumented by MS. Its only known to work experimentally. * Ready for a walk on the wild * side? * * WARNING WARNING WARNING WARNING WARNING WARNING WARNING */ #if !defined WIN95 // Win95 does not have fibers int *fiberData = t->md.fiber_id; /* I found these offsets by disassembling SwitchToFiber(). * Are your palms sweating yet? */ /* ** EAX is on the stack (ESP+0) ** EDX is on the stack (ESP+4) ** ECX is on the stack (ESP+8) */ t->md.gcContext[0] = 0; /* context.Eax */ t->md.gcContext[1] = fiberData[0x2e]; /* context.Ebx */ t->md.gcContext[2] = 0; /* context.Ecx */ t->md.gcContext[3] = 0; /* context.Edx */ t->md.gcContext[4] = fiberData[0x2d]; /* context.Esi */ t->md.gcContext[5] = fiberData[0x2c]; /* context.Edi */ t->md.gcContext[6] = fiberData[0x36]; /* context.Esp */ t->md.gcContext[7] = fiberData[0x32]; /* context.Ebp */ *np = PR_NUM_GCREGS; #endif } return (PRWord *)&t->md.gcContext; #else PR_NOT_REACHED("not implemented"); return NULL; #endif /* defined(_X86_) */ }
PRInt64 _PR_InvalidInt64(void) { PRInt64 rv; LL_I2L(rv, -1); PR_NOT_REACHED("I/O method is invalid"); PR_SetError(PR_INVALID_METHOD_ERROR, 0); return rv; } /* _PR_InvalidInt */
SECStatus VerifySignedData(const CERTSignedData* sd, const CERTCertificate* cert, void* pkcs11PinArg) { if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data || !sd->signature.data || !cert) { PR_NOT_REACHED("invalid args to VerifySignedData"); PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } // See bug 921585. if (sd->data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } // convert sig->len from bit counts to byte count. SECItem sig = sd->signature; DER_ConvertBitString(&sig); // Use SECKEY_ExtractPublicKey instead of CERT_ExtractPublicKey because // CERT_ExtractPublicKey would try to do (EC)DSA parameter inheritance, using // the classic (wrong) NSS path building logic. We intentionally do not // support parameter inheritance. ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo)); if (!pubKey) { return SECFailure; } SECOidTag hashAlg; if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast<int>(sd->data.len), pubKey.get(), &sig, &sd->signatureAlgorithm, &hashAlg, pkcs11PinArg) != SECSuccess) { return SECFailure; } // TODO: Ideally, we would do this check before we call // VFY_VerifyDataWithAlgorithmID. But, VFY_VerifyDataWithAlgorithmID gives us // the hash algorithm so it is more convenient to do things in this order. uint32_t policy; if (NSS_GetAlgorithmPolicy(hashAlg, &policy) != SECSuccess) { return SECFailure; } // XXX: I'm not sure why there isn't NSS_USE_ALG_IN_SSL_SIGNATURE, but there // isn't. Since we don't know the context in which we're being called, be as // strict as we can be given the NSS API that is available. static const uint32_t requiredPolicy = NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE; if ((policy & requiredPolicy) != requiredPolicy) { PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); return SECFailure; } return SECSuccess; }
_MD_CREATE_THREAD( PRThread *thread, void (*start) (void *), PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize) { PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for AIX."); }
PRStatus _MD_CREATE_THREAD(PRThread *thread, void (*start)(void *), PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize) { PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SunOS 4.1.3."); return PR_FAILURE; }
SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf, size_t digestBufLen) { static_assert(TrustDomain::DIGEST_LENGTH == SHA1_LENGTH, "TrustDomain::DIGEST_LENGTH must be 20 (SHA-1 digest length)"); if (digestBufLen != TrustDomain::DIGEST_LENGTH) { PR_NOT_REACHED("invalid hash length"); PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } if (item.len > static_cast<decltype(item.len)>(std::numeric_limits<int32_t>::max())) { PR_NOT_REACHED("large OCSP responses should have already been rejected"); PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } return PK11_HashBuf(SEC_OID_SHA1, digestBuf, item.data, static_cast<int32_t>(item.len)); }
static PRIntervalTime OCSPFetchingTypeToTimeoutTime(NSSCertDBTrustDomain::OCSPFetching ocspFetching) { switch (ocspFetching) { case NSSCertDBTrustDomain::FetchOCSPForDVSoftFail: return PR_SecondsToInterval(2); case NSSCertDBTrustDomain::FetchOCSPForEV: case NSSCertDBTrustDomain::FetchOCSPForDVHardFail: return PR_SecondsToInterval(10); // The rest of these are error cases. Assert in debug builds, but return // the default value corresponding to 2 seconds in release builds. case NSSCertDBTrustDomain::NeverFetchOCSP: case NSSCertDBTrustDomain::LocalOnlyOCSPForEV: PR_NOT_REACHED("we should never see this OCSPFetching type here"); default: PR_NOT_REACHED("we're not handling every OCSPFetching type"); } return PR_SecondsToInterval(2); }
RCNetAddr::RCNetAddr(RCNetAddr::HostValue host, PRUint16 port): RCBase() { PRNetAddrValue how; switch (host) { case RCNetAddr::any: how = PR_IpAddrAny; break; case RCNetAddr::loopback: how = PR_IpAddrLoopback; break; default: PR_NOT_REACHED("This can't happen -- and did!"); } (void)PR_InitializeNetAddr(how, port, &address); } /* RCNetAddr::RCNetAddr */
PRStatus _MD_CREATE_THREAD( PRThread *thread, void (*start) (void *), PRThreadPriority priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize) { PR_NOT_REACHED("_MD_CREATE_THREAD has not yet been implemented on L4."); return PR_FAILURE; }
SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const CERTCertificate* cert, CERTCertificate* issuerCert, PRTime time, const SECItem* encodedResponse, PRTime* thisUpdate, PRTime* validThrough) { PR_ASSERT(cert); PR_ASSERT(issuerCert); // TODO: PR_Assert(pinArg) PR_ASSERT(encodedResponse); if (!cert || !issuerCert || !encodedResponse || !encodedResponse->data) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } der::Input input; if (input.Init(encodedResponse->data, encodedResponse->len) != der::Success) { SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } Context context(trustDomain, *cert, *issuerCert, time, thisUpdate, validThrough); if (der::Nested(input, der::SEQUENCE, bind(OCSPResponse, _1, ref(context))) != der::Success) { SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } if (der::End(input) != der::Success) { SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } switch (context.certStatus) { case CertStatus::Good: return SECSuccess; case CertStatus::Revoked: PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0); return SECFailure; case CertStatus::Unknown: PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); return SECFailure; } PR_NOT_REACHED("unknown CertStatus"); PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); return SECFailure; }
SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID, PRTime time, uint16_t maxOCSPLifetimeInDays, const SECItem& encodedResponse, /*out*/ bool& expired, /*optional out*/ PRTime* thisUpdate, /*optional out*/ PRTime* validThrough) { // Always initialize this to something reasonable. expired = false; Input input; if (input.Init(encodedResponse.data, encodedResponse.len) != Success) { SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } Context context(trustDomain, certID, time, maxOCSPLifetimeInDays, thisUpdate, validThrough); if (der::Nested(input, der::SEQUENCE, bind(OCSPResponse, _1, ref(context))) != Success) { SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } if (der::End(input) != Success) { SetErrorToMalformedResponseOnBadDERError(); return SECFailure; } expired = context.expired; switch (context.certStatus) { case CertStatus::Good: if (expired) { PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0); return SECFailure; } return SECSuccess; case CertStatus::Revoked: PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0); return SECFailure; case CertStatus::Unknown: PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); return SECFailure; } PR_NOT_REACHED("unknown CertStatus"); PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0); return SECFailure; }
Result DigestBuf(Input item, /*out*/ uint8_t* digestBuf, size_t digestBufLen) { static_assert(TrustDomain::DIGEST_LENGTH == SHA1_LENGTH, "TrustDomain::DIGEST_LENGTH must be 20 (SHA-1 digest length)"); if (digestBufLen != TrustDomain::DIGEST_LENGTH) { PR_NOT_REACHED("invalid hash length"); return Result::FATAL_ERROR_INVALID_ARGS; } SECItem itemSECItem = UnsafeMapInputToSECItem(item); if (itemSECItem.len > static_cast<decltype(itemSECItem.len)>( std::numeric_limits<int32_t>::max())) { PR_NOT_REACHED("large items should not be possible here"); return Result::FATAL_ERROR_INVALID_ARGS; } SECStatus srv = PK11_HashBuf(SEC_OID_SHA1, digestBuf, itemSECItem.data, static_cast<int32_t>(itemSECItem.len)); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } return Success; }
_PR_MD_GETTHREADAFFINITYMASK(PRThread *thread, PRUint32 *mask) { /* Can we do this on OS/2? Only on SMP versions? */ PR_NOT_REACHED("Not implemented"); return 0; /* This is what windows does: PRInt32 rv, system_mask; rv = GetProcessAffinityMask(GetCurrentProcess(), mask, &system_mask); return rv?0:-1; */ }
_PR_MD_SETTHREADAFFINITYMASK(PRThread *thread, PRUint32 mask ) { /* Can we do this on OS/2? Only on SMP versions? */ PR_NOT_REACHED("Not implemented"); return 0; /* This is what windows does: int rv; rv = SetThreadAffinityMask(thread->md.handle, mask); return rv?0:-1; */ }
void tmTransactionManager::HandleTransaction(tmTransaction *aTrans) { PRUint32 action = aTrans->GetAction(); PRUint32 ownerID = aTrans->GetOwnerID(); tmQueue *queue = nsnull; // get the right queue -- attaches do it differently if (action == TM_ATTACH) { const char *name = (char*) aTrans->GetMessage(); // is qName for Attaches queue = GetQueue(name); if (!queue) { PRInt32 index = AddQueue(name); if (index >= 0) queue = GetQueue(index); // GetQueue may return nsnull } } else // all other trans should have a valid queue ID already queue = GetQueue(aTrans->GetQueueID()); if (queue) { // All possible actions should have a case, default is not valid // delete trans when done with them, let the queue own the trans // that are posted to them. PRInt32 result = 0; switch (action) { case TM_ATTACH: queue->AttachClient(ownerID); break; case TM_POST: result = queue->PostTransaction(aTrans); if (result >= 0) // post failed, aTrans cached in a tmQueue return; break; case TM_FLUSH: queue->FlushQueue(ownerID); break; case TM_DETACH: if (queue->DetachClient(ownerID) == TM_SUCCESS_DELETE_QUEUE) { // the last client has been removed, remove the queue RemoveQueue(aTrans->GetQueueID()); // this _could_ be out of bounds } break; default: PR_NOT_REACHED("bad action in the transaction"); } } delete aTrans; }
PRStatus _MD_CREATE_THREAD( PRThread *thread, void (*start) (void *), PRUintn priority, PRThreadScope scope, PRThreadState state, PRUint32 stackSize) { PR_NOT_REACHED("_MD_CREATE_THREAD should not be called for SINIX."); #if defined(SNI) && !defined(__GNUC__) /* make compiler happy */ return (PRStatus)NULL; #endif }
const char* MapResultToName(Result result) { switch (result) { #define MAP(mozilla_pkix_result, nss_result) \ case mozilla_pkix_result: return #mozilla_pkix_result; MAP_LIST #undef MAP default: PR_NOT_REACHED("Unknown error code in MapResultToName"); return nullptr; } }
PRErrorCode MapResultToPRErrorCode(Result result) { switch (result) { #define MAP(mozilla_pkix_result, nss_result) \ case mozilla_pkix_result: return nss_result; MAP_LIST #undef MAP default: PR_NOT_REACHED("Unknown error code in MapResultToPRErrorCode"); return SEC_ERROR_LIBRARY_FAILURE; } }
SECStatus BuildCertChain(TrustDomain& trustDomain, const CERTCertificate* nssCert, PRTime time, EndEntityOrCA endEntityOrCA, /*optional*/ KeyUsages requiredKeyUsagesIfPresent, /*optional*/ KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, /*optional*/ const SECItem* stapledOCSPResponse, /*out*/ ScopedCERTCertList& results) { if (!nssCert) { PR_NOT_REACHED("null cert passed to BuildCertChain"); PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } // XXX: Support the legacy use of the subject CN field for indicating the // domain name the certificate is valid for. BackCert::IncludeCN includeCN = endEntityOrCA == EndEntityOrCA::MustBeEndEntity && requiredEKUIfPresent == KeyPurposeId::id_kp_serverAuth ? BackCert::IncludeCN::Yes : BackCert::IncludeCN::No; BackCert cert(nullptr, includeCN); Result rv = cert.Init(nssCert->derCert); if (rv != Success) { return SECFailure; } rv = BuildForward(trustDomain, cert, time, endEntityOrCA, requiredKeyUsagesIfPresent, requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse, 0, results); if (rv != Success) { results = nullptr; return SECFailure; } return SECSuccess; }
static PRInt16 PR_CALLBACK MyPoll( PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags) { PRInt16 my_flags, new_flags; PRFilePrivate *mine = (PRFilePrivate*)fd->secret; if (0 != (PR_POLL_READ & in_flags)) { /* client thinks he's reading */ switch (mine->rcvstate) { case rcv_send_credit: my_flags = (in_flags & ~PR_POLL_READ) | PR_POLL_WRITE; break; case rcv_data: case rcv_get_debit: my_flags = in_flags; default: break; } } else if (0 != (PR_POLL_WRITE & in_flags)) { /* client thinks he's writing */ switch (mine->xmtstate) { case xmt_recv_credit: my_flags = (in_flags & ~PR_POLL_WRITE) | PR_POLL_READ; break; case xmt_send_debit: case xmt_data: my_flags = in_flags; default: break; } } else PR_NOT_REACHED("How'd I get here?"); new_flags = (fd->lower->methods->poll)(fd->lower, my_flags, out_flags); if (verbosity > chatty) PR_fprintf( logFile, "Poll [i: 0x%x, m: 0x%x, o: 0x%x, n: 0x%x]\n", in_flags, my_flags, *out_flags, new_flags); return new_flags; } /* MyPoll */
/* This function is not used right now, but is left as a reference. * If you ever need to get the fiberID from the currently running fiber, * this is it. */ void * GetMyFiberID() { #if defined(_X86_) && !defined(__MINGW32__) void *fiberData; /* A pointer to our tib entry is found at FS:[18] * At offset 10h is the fiberData pointer. The context of the * fiber is stored in there. */ __asm { mov EDX, FS:[18h] mov EAX, DWORD PTR [EDX+10h] mov [fiberData], EAX } return fiberData; #else PR_NOT_REACHED("not implemented"); return NULL; #endif /* defined(_X86_) */ }
/* * Allow the application to pass the set of trust anchors */ SECStatus SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList) { PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); PR_NOT_REACHED("not implemented"); return SECFailure; #if 0 sslSocket * ss = ssl_FindSocket(fd); CERTDistNames *names = NULL; if (!certList) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors", SSL_GETPID(), fd)); return SECFailure; } names = CERT_DistNamesFromCertList(certList); if (names == NULL) { return SECFailure; } ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); if (ss->ssl3.ca_list) { CERT_FreeDistNames(ss->ssl3.ca_list); } ss->ssl3.ca_list = names; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); return SECSuccess; #endif }
static Result MatchEKU(Reader& value, KeyPurposeId requiredEKU, EndEntityOrCA endEntityOrCA, /*in/out*/ bool& found, /*in/out*/ bool& foundOCSPSigning) { // See Section 5.9 of "A Layman's Guide to a Subset of ASN.1, BER, and DER" // for a description of ASN.1 DER encoding of OIDs. // id-pkix OBJECT IDENTIFIER ::= // { iso(1) identified-organization(3) dod(6) internet(1) // security(5) mechanisms(5) pkix(7) } // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } // id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } // id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } static const uint8_t server[] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 1 }; static const uint8_t client[] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 2 }; static const uint8_t code [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 3 }; static const uint8_t email [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 4 }; static const uint8_t ocsp [] = { (40*1)+3, 6, 1, 5, 5, 7, 3, 9 }; // id-Netscape OBJECT IDENTIFIER ::= { 2 16 840 1 113730 } // id-Netscape-policy OBJECT IDENTIFIER ::= { id-Netscape 4 } // id-Netscape-stepUp OBJECT IDENTIFIER ::= { id-Netscape-policy 1 } static const uint8_t serverStepUp[] = { (40*2)+16, 128+6,72, 1, 128+6,128+120,66, 4, 1 }; bool match = false; if (!found) { switch (requiredEKU) { case KeyPurposeId::id_kp_serverAuth: // Treat CA certs with step-up OID as also having SSL server type. // Comodo has issued certificates that require this behavior that don't // expire until June 2020! TODO(bug 982932): Limit this exception to // old certificates. match = value.MatchRest(server) || (endEntityOrCA == EndEntityOrCA::MustBeCA && value.MatchRest(serverStepUp)); break; case KeyPurposeId::id_kp_clientAuth: match = value.MatchRest(client); break; case KeyPurposeId::id_kp_codeSigning: match = value.MatchRest(code); break; case KeyPurposeId::id_kp_emailProtection: match = value.MatchRest(email); break; case KeyPurposeId::id_kp_OCSPSigning: match = value.MatchRest(ocsp); break; case KeyPurposeId::anyExtendedKeyUsage: PR_NOT_REACHED("anyExtendedKeyUsage should start with found==true"); return Result::FATAL_ERROR_LIBRARY_FAILURE; default: PR_NOT_REACHED("unrecognized EKU"); return Result::FATAL_ERROR_LIBRARY_FAILURE; } } if (match) { found = true; if (requiredEKU == KeyPurposeId::id_kp_OCSPSigning) { foundOCSPSigning = true; } } else if (value.MatchRest(ocsp)) { foundOCSPSigning = true; } value.SkipToEnd(); // ignore unmatched OIDs. return Success; }
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; }
/* These functions should not be called for HP-UX */ void _MD_YIELD(void) { PR_NOT_REACHED("_MD_YIELD should not be called for HP-UX."); }
/* These functions should not be called for RISC OS */ void _MD_YIELD(void) { PR_NOT_REACHED("_MD_YIELD should not be called for RISC OS."); }
// Recursively build the path from the given subject certificate to the root. // // Be very careful about changing the order of checks. The order is significant // because it affects which error we return when a certificate or certificate // chain has multiple problems. See the error ranking documentation in // pkix/pkix.h. static Result BuildForward(TrustDomain& trustDomain, const BackCert& subject, PRTime time, KeyUsage requiredKeyUsageIfPresent, KeyPurposeId requiredEKUIfPresent, const CertPolicyId& requiredPolicy, /*optional*/ const Input* stapledOCSPResponse, unsigned int subCACount) { Result rv; TrustLevel trustLevel; // If this is an end-entity and not a trust anchor, we defer reporting // any error found here until after attempting to find a valid chain. // See the explanation of error prioritization in pkix.h. rv = CheckIssuerIndependentProperties(trustDomain, subject, time, requiredKeyUsageIfPresent, requiredEKUIfPresent, requiredPolicy, subCACount, trustLevel); Result deferredEndEntityError = Success; if (rv != Success) { if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity && trustLevel != TrustLevel::TrustAnchor) { deferredEndEntityError = rv; } else { return rv; } } if (trustLevel == TrustLevel::TrustAnchor) { // End of the recursion. NonOwningDERArray chain; for (const BackCert* cert = &subject; cert; cert = cert->childCert) { rv = chain.Append(cert->GetDER()); if (rv != Success) { PR_NOT_REACHED("NonOwningDERArray::SetItem failed."); return rv; } } // This must be done here, after the chain is built but before any // revocation checks have been done. return trustDomain.IsChainValid(chain); } if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) { // Avoid stack overflows and poor performance by limiting cert chain // length. static const unsigned int MAX_SUBCA_COUNT = 6; static_assert(1/*end-entity*/ + MAX_SUBCA_COUNT + 1/*root*/ == NonOwningDERArray::MAX_LENGTH, "MAX_SUBCA_COUNT and NonOwningDERArray::MAX_LENGTH mismatch."); if (subCACount >= MAX_SUBCA_COUNT) { return Result::ERROR_UNKNOWN_ISSUER; } ++subCACount; } else { PR_ASSERT(subCACount == 0); } // Find a trusted issuer. PathBuildingStep pathBuilder(trustDomain, subject, time, requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse, subCACount); // TODO(bug 965136): Add SKI/AKI matching optimizations rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time); if (rv != Success) { return rv; } rv = pathBuilder.CheckResult(); if (rv != Success) { return rv; } // If we found a valid chain but deferred reporting an error with the // end-entity certificate, report it now. if (deferredEndEntityError != Success) { return deferredEndEntityError; } // We've built a valid chain from the subject cert up to a trusted root. return Success; }