/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * 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/. */
// Implements the client authentication certificate selection callback for NSS. // nsNSSIOLayer.cpp sets the callback by calling SSL_GetClientAuthDataHook and // identifying SSLGetClientAuthDataHook as the function to call when a TLS // server requests a client authentication certificate. // // In the general case, SSLGetClientAuthDataHook (running on the socket thread), // dispatches an event to the main thread to ask the user to select a client // authentication certificate. Meanwhile, it returns SECWouldBlock so that other // network I/O can occur. When the user selects a client certificate (or opts // not to send one), an event is dispatched to the socket thread that gives NSS // the appropriate information to proceed with the TLS connection. // // If networking is being done on the socket process, SSLGetClientAuthDataHook // sends an IPC call to the parent process to ask the user to select a // certificate. Meanwhile, it again returns SECWouldBlock so other network I/O // can occur. When a certificate (or no certificate) has been selected, the // parent process sends an IPC call back to the socket process, which causes an // event to be dispatched to the socket thread to continue to the TLS // connection.
// Possible behaviors for choosing a cert for client auth. enumclass UserCertChoice { // Ask the user to choose a cert.
Ask = 0, // Automatically choose a cert. Auto = 1,
};
// Returns the most appropriate user cert choice based on the value of the // security.default_personal_cert preference.
UserCertChoice nsGetUserCertChoice() {
nsAutoCString value;
nsresult rv =
Preferences::GetCString("security.default_personal_cert", value); if (NS_FAILED(rv)) { return UserCertChoice::Ask;
}
// There are three cases for what the preference could be set to: // 1. "Select Automatically" -> Auto. // 2. "Ask Every Time" -> Ask. // 3. Something else -> Ask. This might be a nickname from a migrated cert, // but we no longer support this case. return value.EqualsLiteral("Select Automatically") ? UserCertChoice::Auto
: UserCertChoice::Ask;
}
staticbool hasExplicitKeyUsageNonRepudiation(CERTCertificate* cert) { // There is no extension, v1 or v2 certificate if (!cert->extensions) returnfalse;
nsTArray<nsTArray<uint8_t>> collectedCANames; if (!caNames) { return collectedCANames;
}
for (int i = 0; i < caNames->nnames; i++) {
nsTArray<uint8_t> caName;
caName.AppendElements(caNames->names[i].data, caNames->names[i].len);
collectedCANames.AppendElement(std::move(caName));
} return collectedCANames;
}
// This TrustDomain only exists to facilitate the mozilla::pkix path building // algorithm. It considers any certificate with an issuer distinguished name in // the set of given CA names to be a trust anchor. It does essentially no // validation or verification (in particular, the signature checking function // always returns "Success"). class ClientAuthCertNonverifyingTrustDomain final : public TrustDomain { public:
ClientAuthCertNonverifyingTrustDomain( const nsTArray<nsTArray<uint8_t>>& caNames, const nsTArray<nsTArray<uint8_t>>& thirdPartyCertificates)
: mCANames(caNames),
mCertStorage(do_GetService(NS_CERT_STORAGE_CID)),
mThirdPartyCertificates(thirdPartyCertificates) {}
mozilla::pkix::Result ClientAuthCertNonverifyingTrustDomain::GetCertTrust(
pkix::EndEntityOrCA endEntityOrCA, const pkix::CertPolicyId& policy,
pkix::Input candidateCertDER, /*out*/ pkix::TrustLevel& trustLevel) { // If the server did not specify any CA names, all client certificates are // acceptable. if (mCANames.Length() == 0) {
trustLevel = pkix::TrustLevel::TrustAnchor; return pkix::Success;
}
BackCert cert(candidateCertDER, endEntityOrCA, nullptr);
mozilla::pkix::Result rv = cert.Init(); if (rv != pkix::Success) { return rv;
} // If this certificate's issuer distinguished name is in the set of acceptable // CA names, we say this is a trust anchor so that the client certificate // issued from this certificate will be presented as an option for the user. // We also check the certificate's subject distinguished name to account for // the case where client certificates that have the id-kp-OCSPSigning EKU // can't be trust anchors according to mozilla::pkix, and thus we may be // looking directly at the issuer.
pkix::Input issuer(cert.GetIssuer());
pkix::Input subject(cert.GetSubject()); for (constauto& caName : mCANames) {
pkix::Input caNameInput;
rv = caNameInput.Init(caName.Elements(), caName.Length()); if (rv != pkix::Success) { continue; // probably too big
} if (InputsAreEqual(issuer, caNameInput) ||
InputsAreEqual(subject, caNameInput)) {
trustLevel = pkix::TrustLevel::TrustAnchor; return pkix::Success;
}
}
trustLevel = pkix::TrustLevel::InheritsTrust; return pkix::Success;
}
// In theory this implementation should only need to consider intermediate // certificates, since in theory it should only need to look at the issuer // distinguished name of each certificate to determine if the client // certificate is considered acceptable to the server. // However, because we need to account for client certificates with the // id-kp-OCSPSigning EKU, and because mozilla::pkix doesn't allow such // certificates to be trust anchors, we need to consider the issuers of such // certificates directly. These issuers could be roots, so we have to consider // roots here.
mozilla::pkix::Result ClientAuthCertNonverifyingTrustDomain::FindIssuer(
pkix::Input encodedIssuerName, IssuerChecker& checker, pkix::Time time) { // First try all relevant certificates known to Gecko, which avoids calling // CERT_CreateSubjectCertList, because that can be expensive.
Vector<pkix::Input> geckoCandidates; if (!mCertStorage) { return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
}
nsTArray<uint8_t> subject;
subject.AppendElements(encodedIssuerName.UnsafeGetData(),
encodedIssuerName.GetLength());
nsTArray<nsTArray<uint8_t>> certs;
nsresult rv = mCertStorage->FindCertsBySubject(subject, certs); if (NS_FAILED(rv)) { return mozilla::pkix::Result::FATAL_ERROR_LIBRARY_FAILURE;
} for (auto& cert : certs) {
pkix::Input certDER;
mozilla::pkix::Result rv = certDER.Init(cert.Elements(), cert.Length()); if (rv != pkix::Success) { continue; // probably too big
} if (!geckoCandidates.append(certDER)) { return mozilla::pkix::Result::FATAL_ERROR_NO_MEMORY;
}
}
for (constauto& thirdPartyCertificate : mThirdPartyCertificates) {
pkix::Input thirdPartyCertificateInput;
mozilla::pkix::Result rv = thirdPartyCertificateInput.Init(
thirdPartyCertificate.Elements(), thirdPartyCertificate.Length()); if (rv != pkix::Success) { continue; // probably too big
} if (!geckoCandidates.append(thirdPartyCertificateInput)) { return mozilla::pkix::Result::FATAL_ERROR_NO_MEMORY;
}
}
SECItem encodedIssuerNameItem =
pkix::UnsafeMapInputToSECItem(encodedIssuerName); // NSS seems not to differentiate between "no potential issuers found" and // "there was an error trying to retrieve the potential issuers." We assume // there was no error if CERT_CreateSubjectCertList returns nullptr.
UniqueCERTCertList candidates(CERT_CreateSubjectCertList(
nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameItem, 0, false));
Vector<pkix::Input> nssCandidates; if (candidates) { for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
pkix::Input certDER;
mozilla::pkix::Result rv =
certDER.Init(n->cert->derCert.data, n->cert->derCert.len); if (rv != pkix::Success) { continue; // probably too big
} if (!nssCandidates.append(certDER)) { return mozilla::pkix::Result::FATAL_ERROR_NO_MEMORY;
}
}
}
for (pkix::Input candidate : nssCandidates) {
mozilla::pkix::Result rv = checker.Check(candidate, nullptr, keepGoing); if (rv != pkix::Success) { return rv;
} if (!keepGoing) { return pkix::Success;
}
} return pkix::Success;
}
if (clientAuthInfo.ProviderTlsFlags() != 0) { returnfalse;
}
nsCOMPtr<nsIClientAuthRememberService> clientAuthRememberService(
do_GetService(NS_CLIENTAUTHREMEMBERSERVICE_CONTRACTID)); if (!clientAuthRememberService) { returnfalse;
}
nsCString rememberedDBKey; bool found;
nsresult rv = clientAuthRememberService->HasRememberedDecision(
clientAuthInfo.HostName(), clientAuthInfo.OriginAttributesRef(),
rememberedDBKey, &found); if (NS_FAILED(rv)) { returnfalse;
} if (!found) { returnfalse;
} // An empty dbKey indicates that the user chose not to use a certificate // and chose to remember this decision if (rememberedDBKey.IsEmpty()) { returntrue;
}
nsCOMPtr<nsIX509CertDB> certdb(do_GetService(NS_X509CERTDB_CONTRACTID)); if (!certdb) { returnfalse;
}
nsCOMPtr<nsIX509Cert> foundCert;
rv = certdb->FindCertByDBKey(rememberedDBKey, getter_AddRefs(foundCert)); if (NS_FAILED(rv)) { returnfalse;
} if (!foundCert) { returnfalse;
}
rv = foundCert->GetRawDER(rememberedCertBytes); if (NS_FAILED(rv)) { returnfalse;
} if (BuildChainForCertificate(rememberedCertBytes, rememberedCertChainBytes,
caNames, enterpriseCertificates) != Success) { returnfalse;
} returntrue;
}
// Filter potential client certificates by the specified CA names, if any. This // operation potentially builds a certificate chain for each candidate client // certificate. Keeping those chains around means they don't have to be // re-built later when the user selects a particular client certificate. void FilterPotentialClientCertificatesByCANames(
UniqueCERTCertList& potentialClientCertificates, const nsTArray<nsTArray<uint8_t>>& caNames, const nsTArray<nsTArray<uint8_t>>& enterpriseCertificates,
nsTArray<nsTArray<nsTArray<uint8_t>>>& potentialClientCertificateChains) { if (!potentialClientCertificates) { return;
}
CERTCertListNode* n = CERT_LIST_HEAD(potentialClientCertificates); while (!CERT_LIST_END(n, potentialClientCertificates)) {
nsTArray<nsTArray<uint8_t>> builtChain;
nsTArray<uint8_t> certBytes;
certBytes.AppendElements(n->cert->derCert.data, n->cert->derCert.len);
mozilla::pkix::Result result = BuildChainForCertificate(
certBytes, builtChain, caNames, enterpriseCertificates); if (result != pkix::Success) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("removing cert '%s'", n->cert->subjectName));
CERTCertListNode* toRemove = n;
n = CERT_LIST_NEXT(n);
CERT_RemoveCertListNode(toRemove); continue;
}
potentialClientCertificateChains.AppendElement(std::move(builtChain));
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("keeping cert '%s'\n", n->cert->subjectName));
n = CERT_LIST_NEXT(n);
}
}
void SelectClientAuthCertificate::DispatchContinuation(
nsTArray<uint8_t>&& selectedCertBytes) {
nsTArray<nsTArray<uint8_t>> selectedCertChainBytes; // Attempt to find a pre-built certificate chain corresponding to the // selected certificate. for (constauto& clientCertificateChain : mPotentialClientCertificateChains) { if (clientCertificateChain.Length() > 0 &&
clientCertificateChain[0] == selectedCertBytes) { for (constauto& certificateBytes : clientCertificateChain) {
selectedCertChainBytes.AppendElement(certificateBytes.Clone());
} break;
}
}
mContinuation->SetSelectedClientAuthData(std::move(selectedCertBytes),
std::move(selectedCertChainBytes));
nsCOMPtr<nsIEventTarget> socketThread(
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID)); if (socketThread) {
(void)socketThread->Dispatch(mContinuation, NS_DISPATCH_NORMAL);
}
}
// Helper function to build a certificate chain from the given certificate to a // trust anchor in the set indicated by the peer (mCANames). This is essentially // best-effort, so no signature verification occurs.
mozilla::pkix::Result BuildChainForCertificate(
nsTArray<uint8_t>& certBytes, nsTArray<nsTArray<uint8_t>>& certChainBytes, const nsTArray<nsTArray<uint8_t>>& caNames, const nsTArray<nsTArray<uint8_t>>& enterpriseCertificates) {
ClientAuthCertNonverifyingTrustDomain trustDomain(caNames,
enterpriseCertificates);
pkix::Input certDER;
mozilla::pkix::Result result =
certDER.Init(certBytes.Elements(), certBytes.Length()); if (result != pkix::Success) { return result;
} // Client certificates shouldn't be CAs, but for interoperability reasons we // attempt to build a path with each certificate as an end entity and then as // a CA if that fails. const pkix::EndEntityOrCA kEndEntityOrCAParams[] = {
pkix::EndEntityOrCA::MustBeEndEntity, pkix::EndEntityOrCA::MustBeCA}; // mozilla::pkix rejects certificates with id-kp-OCSPSigning unless it is // specifically required. A client certificate should never have this EKU. // Unfortunately, there are some client certificates in private PKIs that // have this EKU. For interoperability, we attempt to work around this // restriction in mozilla::pkix by first building the certificate chain with // no particular EKU required and then again with id-kp-OCSPSigning required // if that fails. const pkix::KeyPurposeId kKeyPurposeIdParams[] = {
pkix::KeyPurposeId::anyExtendedKeyUsage,
pkix::KeyPurposeId::id_kp_OCSPSigning}; for (constauto& endEntityOrCAParam : kEndEntityOrCAParams) { for (constauto& keyPurposeIdParam : kKeyPurposeIdParams) {
mozilla::pkix::Result result = BuildCertChain(
trustDomain, certDER, Now(), endEntityOrCAParam,
KeyUsage::noParticularKeyUsageRequired, keyPurposeIdParam,
pkix::CertPolicyId::anyPolicy, nullptr); if (result == pkix::Success) {
certChainBytes = trustDomain.TakeBuiltChain(); return pkix::Success;
}
}
} return mozilla::pkix::Result::ERROR_UNKNOWN_ISSUER;
}
class ClientAuthDialogCallback : public nsIClientAuthDialogCallback { public:
NS_DECL_ISUPPORTS
NS_DECL_NSICLIENTAUTHDIALOGCALLBACK
NS_IMETHODIMP
SelectClientAuthCertificate::Run() { // We check the value of a pref, so this should only be run on the main // thread.
MOZ_ASSERT(NS_IsMainThread());
// find valid user cert and key pair if (nsGetUserCertChoice() == UserCertChoice::Auto) { // automatically find the right cert
UniqueCERTCertificate lowPrioNonrepCert; // loop through the list until we find a cert with a key for (CERTCertListNode* node = CERT_LIST_HEAD(mPotentialClientCertificates);
!CERT_LIST_END(node, mPotentialClientCertificates);
node = CERT_LIST_NEXT(node)) {
UniqueSECKEYPrivateKey tmpKey(PK11_FindKeyByAnyCert(node->cert, nullptr)); if (tmpKey) { if (hasExplicitKeyUsageNonRepudiation(node->cert)) { // Not a preferred cert if (!lowPrioNonrepCert) { // did not yet find a low prio cert
lowPrioNonrepCert.reset(CERT_DupCertificate(node->cert));
}
} else { // this is a good cert to present
selectedCertBytes.AppendElements(node->cert->derCert.data,
node->cert->derCert.len);
DispatchContinuation(std::move(selectedCertBytes)); return NS_OK;
}
} if (PR_GetError() == SEC_ERROR_BAD_PASSWORD) { // problem with password: bail break;
}
}
if (lowPrioNonrepCert) {
selectedCertBytes.AppendElements(lowPrioNonrepCert->derCert.data,
lowPrioNonrepCert->derCert.len);
}
DispatchContinuation(std::move(selectedCertBytes)); return NS_OK;
}
// Not Auto => ask the user to select a certificate
nsTArray<RefPtr<nsIX509Cert>> certArray; for (CERTCertListNode* node = CERT_LIST_HEAD(mPotentialClientCertificates);
!CERT_LIST_END(node, mPotentialClientCertificates);
node = CERT_LIST_NEXT(node)) {
RefPtr<nsIX509Cert> tempCert(new nsNSSCertificate(node->cert));
certArray.AppendElement(tempCert);
}
if (info->GetDenyClientCert()) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] Not returning client cert due to denyClientCert attribute",
socket)); return SECSuccess;
}
if (info->GetJoined()) { // We refuse to send a client certificate when there are multiple hostnames // joined on this connection, because we only show the user one hostname // (mHostName) in the client certificate UI.
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] Not returning client cert due to previous join", socket)); return SECSuccess;
}
UniqueCERTCertificate serverCert(SSL_PeerCertificate(socket)); if (!serverCert) {
PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0); return SECFailure;
}
uint64_t browserId; if (NS_FAILED(info->GetBrowserId(&browserId))) {
PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); return SECFailure;
}
// Currently, the IPC client certs module only refreshes its view of // available certificates and keys if the platform issues a search for all // certificates or keys. In the socket process, such a search may not have // happened, so this ensures it has. // Additionally, instantiating certificates in NSS is not thread-safe and has // performance implications, so search for them here (on the socket thread) // when not in the socket process.
UniqueCERTCertList potentialClientCertificates(
FindClientCertificatesWithPrivateKeys());
RefPtr<ClientAuthCertificateSelected> continuation( new ClientAuthCertificateSelected(info)); // If this is the socket process, dispatch an IPC call to select a client // authentication certificate in the parent process. // Otherwise, dispatch an event to the main thread to do the selection. // When those events finish, they will run the continuation, which gives the // appropriate information to the NSSSocketControl, which then calls // SSL_ClientCertCallbackComplete to continue the connection. if (XRE_IsSocketProcess()) {
RefPtr<SelectTLSClientAuthCertChild> selectClientAuthCertificate( new SelectTLSClientAuthCertChild(continuation));
nsAutoCString hostname(info->GetHostName());
nsTArray<uint8_t> serverCertBytes;
nsTArray<ByteArray> caNamesBytes; for (constauto& caName : caNames) {
caNamesBytes.AppendElement(ByteArray(std::move(caName)));
}
serverCertBytes.AppendElements(serverCert->derCert.data,
serverCert->derCert.len);
OriginAttributes originAttributes(info->GetOriginAttributes());
int32_t port(info->GetPort());
uint32_t providerFlags(info->GetProviderFlags());
uint32_t providerTlsFlags(info->GetProviderTlsFlags());
nsCOMPtr<nsIRunnable> remoteSelectClientAuthCertificate(
NS_NewRunnableFunction( "RemoteSelectClientAuthCertificate",
[selectClientAuthCertificate(
std::move(selectClientAuthCertificate)),
hostname(std::move(hostname)),
originAttributes(std::move(originAttributes)), port, providerFlags,
providerTlsFlags, serverCertBytes(std::move(serverCertBytes)),
caNamesBytes(std::move(caNamesBytes)),
browserId(browserId)]() mutable {
ipc::Endpoint<PSelectTLSClientAuthCertParent> parentEndpoint;
ipc::Endpoint<PSelectTLSClientAuthCertChild> childEndpoint;
PSelectTLSClientAuthCert::CreateEndpoints(&parentEndpoint,
&childEndpoint); if (NS_FAILED(net::SocketProcessBackgroundChild::WithActor( "SendInitSelectTLSClientAuthCert",
[endpoint = std::move(parentEndpoint),
hostname(std::move(hostname)),
originAttributes(std::move(originAttributes)), port,
providerFlags, providerTlsFlags,
serverCertBytes(std::move(serverCertBytes)),
caNamesBytes(std::move(caNamesBytes)), browserId](
net::SocketProcessBackgroundChild* aActor) mutable {
Unused << aActor->SendInitSelectTLSClientAuthCert(
std::move(endpoint), hostname, originAttributes,
port, providerFlags, providerTlsFlags,
ByteArray(serverCertBytes), caNamesBytes,
browserId);
}))) { return;
}
nsTArray<nsTArray<nsTArray<uint8_t>>> potentialClientCertificateChains;
FilterPotentialClientCertificatesByCANames(potentialClientCertificates,
caNames, enterpriseCertificates,
potentialClientCertificateChains); if (!potentialClientCertificates ||
CERT_LIST_EMPTY(potentialClientCertificates)) {
MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
("[%p] no client certificates available after filtering by CA",
socket)); return SECSuccess;
}
nsCOMPtr<nsIRunnable> selectClientAuthCertificate( new SelectClientAuthCertificate(
std::move(authInfo), std::move(serverCert),
std::move(potentialClientCertificates),
std::move(potentialClientCertificateChains), continuation,
browserId));
info->SetPendingSelectClientAuthCertificate(
std::move(selectClientAuthCertificate));
// Meanwhile, tell NSS this connection is blocking for now.
PR_SetError(PR_WOULD_BLOCK_ERROR, 0); return SECWouldBlock;
}
// Helper continuation for when a client authentication certificate has been // selected in the parent process and the information needs to be sent to the // socket process. class RemoteClientAuthCertificateSelected
: public ClientAuthCertificateSelectedBase { public: explicit RemoteClientAuthCertificateSelected(
SelectTLSClientAuthCertParent* selectTLSClientAuthCertParent)
: mSelectTLSClientAuthCertParent(selectTLSClientAuthCertParent),
mEventTarget(GetCurrentSerialEventTarget()) {}
NS_IMETHODIMP
RemoteClientAuthCertificateSelected::Run() { // When this runs, it dispatches an event to the IPC thread it originally came // from in order to send the IPC call to the socket process that a client // authentication certificate has been selected. return mEventTarget->Dispatch(
NS_NewRunnableFunction( "psm::RemoteClientAuthCertificateSelected::Run",
[parent(mSelectTLSClientAuthCertParent),
certBytes(std::move(mSelectedCertBytes)),
builtCertChain(std::move(mSelectedCertChainBytes))]() mutable {
parent->TLSClientAuthCertSelected(certBytes,
std::move(builtCertChain));
}),
NS_DISPATCH_NORMAL);
}
namespace mozilla::psm {
// Given some information from the socket process about a connection that // requested a client authentication certificate, this function dispatches an // event to the main thread to ask the user to select one. When the user does so // (or selects no certificate), the continuation runs and sends the information // back via IPC. bool SelectTLSClientAuthCertParent::Dispatch( const nsACString& aHostName, const OriginAttributes& aOriginAttributes, const int32_t& aPort, const uint32_t& aProviderFlags, const uint32_t& aProviderTlsFlags, const ByteArray& aServerCertBytes,
nsTArray<ByteArray>&& aCANames, const uint64_t& aBrowserId) {
RefPtr<ClientAuthCertificateSelectedBase> continuation( new RemoteClientAuthCertificateSelected(this));
ClientAuthInfo authInfo(aHostName, aOriginAttributes, aPort, aProviderFlags,
aProviderTlsFlags);
nsCOMPtr<nsIEventTarget> socketThread =
do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID); if (NS_WARN_IF(!socketThread)) { returnfalse;
} // Dispatch the work of instantiating a CERTCertificate and searching for // client certificates to the socket thread.
nsresult rv = socketThread->Dispatch(NS_NewRunnableFunction( "SelectTLSClientAuthCertParent::Dispatch",
[authInfo(std::move(authInfo)), continuation(std::move(continuation)),
serverCertBytes(aServerCertBytes), caNames(std::move(aCANames)),
browserId(aBrowserId)]() mutable {
SECItem serverCertItem{
siBuffer, const_cast<uint8_t*>(serverCertBytes.data().Elements()), static_cast<unsignedint>(serverCertBytes.data().Length()),
};
UniqueCERTCertificate serverCert(CERT_NewTempCertificate(
CERT_GetDefaultCertDB(), &serverCertItem, nullptr, false, true)); if (!serverCert) { return;
}
nsTArray<nsTArray<uint8_t>> caNamesArray; for (auto& caName : caNames) {
caNamesArray.AppendElement(std::move(caName.data()));
}
nsTArray<nsTArray<uint8_t>> enterpriseCertificates(
GetEnterpriseCertificates());
nsTArray<uint8_t> rememberedCertBytes;
nsTArray<nsTArray<uint8_t>> rememberedCertChainBytes; if (FindRememberedDecision(authInfo, caNamesArray,
enterpriseCertificates, rememberedCertBytes,
rememberedCertChainBytes)) {
continuation->SetSelectedClientAuthData(
std::move(rememberedCertBytes),
std::move(rememberedCertChainBytes));
(void)NS_DispatchToCurrentThread(continuation); return;
}
UniqueCERTCertList potentialClientCertificates(
FindClientCertificatesWithPrivateKeys());
nsTArray<nsTArray<nsTArray<uint8_t>>> potentialClientCertificateChains;
FilterPotentialClientCertificatesByCANames(
potentialClientCertificates, caNamesArray, enterpriseCertificates,
potentialClientCertificateChains);
RefPtr<SelectClientAuthCertificate> selectClientAuthCertificate( new SelectClientAuthCertificate(
std::move(authInfo), std::move(serverCert),
std::move(potentialClientCertificates),
std::move(potentialClientCertificateChains), continuation,
browserId));
Unused << NS_DispatchToMainThread(selectClientAuthCertificate);
})); return NS_SUCCEEDED(rv);
}
// When the user has selected (or not) a client authentication certificate in // the parent, this function receives that information in the socket process and // dispatches a continuation to the socket process to continue the connection.
ipc::IPCResult SelectTLSClientAuthCertChild::RecvTLSClientAuthCertSelected(
ByteArray&& aSelectedCertBytes,
nsTArray<ByteArray>&& aSelectedCertChainBytes) {
nsTArray<uint8_t> selectedCertBytes(std::move(aSelectedCertBytes.data()));
nsTArray<nsTArray<uint8_t>> selectedCertChainBytes; for (auto& certBytes : aSelectedCertChainBytes) {
selectedCertChainBytes.AppendElement(std::move(certBytes.data()));
}
mContinuation->SetSelectedClientAuthData(std::move(selectedCertBytes),
std::move(selectedCertChainBytes));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.