NSSSocketControl.cpp (25321B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "NSSSocketControl.h" 8 9 #include "ssl.h" 10 #include "sslexp.h" 11 #include "nsISocketProvider.h" 12 #include "secerr.h" 13 #include "mozilla/Base64.h" 14 #include "mozilla/dom/Promise.h" 15 #include "mozilla/glean/SecurityManagerSslMetrics.h" 16 #include "nsNSSCallbacks.h" 17 #include "nsNSSComponent.h" 18 #include "nsProxyRelease.h" 19 20 using namespace mozilla; 21 using namespace mozilla::psm; 22 23 extern LazyLogModule gPIPNSSLog; 24 25 NSSSocketControl::NSSSocketControl( 26 const nsCString& aHostName, int32_t aPort, 27 already_AddRefed<nsSSLIOLayerHelpers> aSSLIOLayerHelpers, 28 uint32_t providerFlags, uint32_t providerTlsFlags) 29 : CommonSocketControl(aHostName, aPort, providerFlags), 30 mFd(nullptr), 31 mCertVerificationState(BeforeCertVerification), 32 mSSLIOLayerHelpers(aSSLIOLayerHelpers), 33 mForSTARTTLS(false), 34 mTLSVersionRange{0, 0}, 35 mHandshakePending(true), 36 mPreliminaryHandshakeDone(false), 37 mEarlyDataAccepted(false), 38 mDenyClientCert(false), 39 mFalseStartCallbackCalled(false), 40 mFalseStarted(false), 41 mIsFullHandshake(false), 42 mNotedTimeUntilReady(false), 43 mEchExtensionStatus(EchExtensionStatus::kNotPresent), 44 mSentMlkemShare(false), 45 mHasTls13HandshakeSecrets(false), 46 mIsShortWritePending(false), 47 mShortWritePendingByte(0), 48 mShortWriteOriginalAmount(-1), 49 mKEAUsed(nsITLSSocketControl::KEY_EXCHANGE_UNKNOWN), 50 mKEAKeyBits(0), 51 mMACAlgorithmUsed(nsITLSSocketControl::SSL_MAC_UNKNOWN), 52 mProviderTlsFlags(providerTlsFlags), 53 mSocketCreationTimestamp(TimeStamp::Now()), 54 mPlaintextBytesRead(0), 55 mClaimed(!(providerFlags & nsISocketProvider::IS_SPECULATIVE_CONNECTION)), 56 mClientAuthCertificateRequest(Nothing()), 57 mBrowserId(0) {} 58 59 NS_IMETHODIMP 60 NSSSocketControl::GetKEAUsed(int16_t* aKea) { 61 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 62 *aKea = mKEAUsed; 63 return NS_OK; 64 } 65 66 NS_IMETHODIMP 67 NSSSocketControl::GetKEAKeyBits(uint32_t* aKeyBits) { 68 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 69 *aKeyBits = mKEAKeyBits; 70 return NS_OK; 71 } 72 73 NS_IMETHODIMP 74 NSSSocketControl::GetSSLVersionOffered(int16_t* aSSLVersionOffered) { 75 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 76 *aSSLVersionOffered = mTLSVersionRange.max; 77 return NS_OK; 78 } 79 80 NS_IMETHODIMP 81 NSSSocketControl::GetMACAlgorithmUsed(int16_t* aMac) { 82 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 83 *aMac = mMACAlgorithmUsed; 84 return NS_OK; 85 } 86 87 void NSSSocketControl::NoteTimeUntilReady() { 88 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 89 if (mNotedTimeUntilReady) { 90 return; 91 } 92 mNotedTimeUntilReady = true; 93 94 auto duration = TimeStamp::Now() - mSocketCreationTimestamp; 95 if (!(mProviderFlags & nsISocketProvider::IS_RETRY)) { 96 glean::ssl::time_until_ready_first_try.AccumulateRawDuration(duration); 97 } 98 99 if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) { 100 glean::ssl::time_until_ready_conservative.AccumulateRawDuration(duration); 101 } 102 103 switch (GetEchExtensionStatus()) { 104 case EchExtensionStatus::kGREASE: 105 glean::ssl::time_until_ready_ech_grease.AccumulateRawDuration(duration); 106 break; 107 case EchExtensionStatus::kReal: 108 glean::ssl::time_until_ready_ech.AccumulateRawDuration(duration); 109 break; 110 default: 111 break; 112 } 113 // This will include TCP and proxy tunnel wait time 114 glean::ssl::time_until_ready.AccumulateRawDuration(duration); 115 116 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 117 ("[%p] NSSSocketControl::NoteTimeUntilReady\n", mFd)); 118 } 119 120 void NSSSocketControl::SetHandshakeCompleted() { 121 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 122 if (!mHandshakeCompleted) { 123 enum HandshakeType { 124 Resumption = 1, 125 FalseStarted = 2, 126 ChoseNotToFalseStart = 3, 127 NotAllowedToFalseStart = 4, 128 }; 129 130 HandshakeType handshakeType = !IsFullHandshake() ? Resumption 131 : mFalseStarted ? FalseStarted 132 : mFalseStartCallbackCalled 133 ? ChoseNotToFalseStart 134 : NotAllowedToFalseStart; 135 // This will include TCP and proxy tunnel wait time 136 if (mKeaGroupName.isSome()) { 137 glean::ssl::time_until_handshake_finished_keyed_by_ka.Get(*mKeaGroupName) 138 .AccumulateRawDuration(TimeStamp::Now() - mSocketCreationTimestamp); 139 } 140 141 // If the handshake is completed for the first time from just 1 callback 142 // that means that TLS session resumption must have been used. 143 glean::ssl::resumed_session 144 .EnumGet(static_cast<glean::ssl::ResumedSessionLabel>(handshakeType == 145 Resumption)) 146 .Add(); 147 glean::ssl_handshake::completed.AccumulateSingleSample(handshakeType); 148 } 149 150 // Remove the plaintext layer as it is not needed anymore. 151 // The plaintext layer is not always present - so it's not a fatal error if it 152 // cannot be removed. 153 // Note that PR_PopIOLayer may modify its stack, so a pointer returned by 154 // PR_GetIdentitiesLayer may not point to what we think it points to after 155 // calling PR_PopIOLayer. We must operate on the pointer returned by 156 // PR_PopIOLayer. 157 if (PR_GetIdentitiesLayer(mFd, 158 nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) { 159 PRFileDesc* poppedPlaintext = 160 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity); 161 poppedPlaintext->dtor(poppedPlaintext); 162 } 163 164 mHandshakeCompleted = true; 165 166 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 167 ("[%p] NSSSocketControl::SetHandshakeCompleted\n", (void*)mFd)); 168 169 mIsFullHandshake = false; // reset for next handshake on this connection 170 171 if (mTlsHandshakeCallback) { 172 auto callback = std::move(mTlsHandshakeCallback); 173 (void)callback->HandshakeDone(); 174 } 175 } 176 177 void NSSSocketControl::SetNegotiatedNPN(const char* value, uint32_t length) { 178 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 179 if (!value) { 180 mNegotiatedNPN.Truncate(); 181 } else { 182 mNegotiatedNPN.Assign(value, length); 183 } 184 mNPNCompleted = true; 185 } 186 187 #define MAX_ALPN_LENGTH 255 188 189 NS_IMETHODIMP 190 NSSSocketControl::GetAlpnEarlySelection(nsACString& aAlpnSelected) { 191 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 192 aAlpnSelected.Truncate(); 193 194 SSLPreliminaryChannelInfo info; 195 SECStatus rv = SSL_GetPreliminaryChannelInfo(mFd, &info, sizeof(info)); 196 if (rv != SECSuccess || !info.canSendEarlyData) { 197 return NS_ERROR_NOT_AVAILABLE; 198 } 199 200 SSLNextProtoState alpnState; 201 unsigned char chosenAlpn[MAX_ALPN_LENGTH]; 202 unsigned int chosenAlpnLen; 203 rv = SSL_GetNextProto(mFd, &alpnState, chosenAlpn, &chosenAlpnLen, 204 AssertedCast<unsigned int>(std::size(chosenAlpn))); 205 206 if (rv != SECSuccess) { 207 return NS_ERROR_NOT_AVAILABLE; 208 } 209 210 if (alpnState == SSL_NEXT_PROTO_EARLY_VALUE) { 211 aAlpnSelected.Assign(BitwiseCast<char*, unsigned char*>(chosenAlpn), 212 chosenAlpnLen); 213 } 214 215 return NS_OK; 216 } 217 218 NS_IMETHODIMP 219 NSSSocketControl::GetEarlyDataAccepted(bool* aAccepted) { 220 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 221 *aAccepted = mEarlyDataAccepted; 222 return NS_OK; 223 } 224 225 void NSSSocketControl::SetEarlyDataAccepted(bool aAccepted) { 226 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 227 mEarlyDataAccepted = aAccepted; 228 } 229 230 bool NSSSocketControl::GetDenyClientCert() { 231 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 232 return mDenyClientCert; 233 } 234 235 void NSSSocketControl::SetDenyClientCert(bool aDenyClientCert) { 236 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 237 mDenyClientCert = aDenyClientCert; 238 } 239 240 NS_IMETHODIMP 241 NSSSocketControl::DriveHandshake() { 242 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 243 if (!mFd) { 244 return NS_ERROR_FAILURE; 245 } 246 if (IsCanceled()) { 247 PRErrorCode errorCode = GetErrorCode(); 248 MOZ_DIAGNOSTIC_ASSERT(errorCode, "handshake cancelled without error code"); 249 return GetXPCOMFromNSSError(errorCode); 250 } 251 252 SECStatus rv = SSL_ForceHandshake(mFd); 253 254 if (rv != SECSuccess) { 255 PRErrorCode errorCode = PR_GetError(); 256 MOZ_ASSERT(errorCode, "handshake failed without error code"); 257 // There is a bug in NSS. Sometimes SSL_ForceHandshake will return 258 // SECFailure without setting an error code. In these cases, cancel 259 // the connection with SEC_ERROR_LIBRARY_FAILURE. 260 if (!errorCode) { 261 errorCode = SEC_ERROR_LIBRARY_FAILURE; 262 } 263 if (errorCode == PR_WOULD_BLOCK_ERROR) { 264 return NS_BASE_STREAM_WOULD_BLOCK; 265 } 266 267 SetCanceled(errorCode); 268 return GetXPCOMFromNSSError(errorCode); 269 } 270 return NS_OK; 271 } 272 273 bool NSSSocketControl::GetForSTARTTLS() { 274 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 275 return mForSTARTTLS; 276 } 277 278 void NSSSocketControl::SetForSTARTTLS(bool aForSTARTTLS) { 279 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 280 mForSTARTTLS = aForSTARTTLS; 281 } 282 283 NS_IMETHODIMP 284 NSSSocketControl::ProxyStartSSL() { 285 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 286 return ActivateSSL(); 287 } 288 289 NS_IMETHODIMP 290 NSSSocketControl::StartTLS() { 291 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 292 return ActivateSSL(); 293 } 294 295 NS_IMETHODIMP 296 NSSSocketControl::AsyncStartTLS(JSContext* aCx, 297 mozilla::dom::Promise** aPromise) { 298 MOZ_RELEASE_ASSERT(NS_IsMainThread()); 299 NS_ENSURE_ARG_POINTER(aCx); 300 NS_ENSURE_ARG_POINTER(aPromise); 301 302 nsIGlobalObject* globalObject = xpc::CurrentNativeGlobal(aCx); 303 if (!globalObject) { 304 return NS_ERROR_UNEXPECTED; 305 } 306 307 ErrorResult result; 308 RefPtr<mozilla::dom::Promise> promise = 309 mozilla::dom::Promise::Create(globalObject, result); 310 if (result.Failed()) { 311 return result.StealNSResult(); 312 } 313 314 nsCOMPtr<nsIEventTarget> target( 315 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID)); 316 if (!target) { 317 return NS_ERROR_UNEXPECTED; 318 } 319 320 auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>( 321 "AsyncStartTLS promise", promise); 322 323 nsCOMPtr<nsIRunnable> runnable(NS_NewRunnableFunction( 324 "AsyncStartTLS::StartTLS", 325 [promiseHolder = std::move(promiseHolder), self = RefPtr{this}]() { 326 nsresult rv = self->StartTLS(); 327 NS_DispatchToMainThread(NS_NewRunnableFunction( 328 "AsyncStartTLS::Resolve", [rv, promiseHolder]() { 329 dom::Promise* promise = promiseHolder.get()->get(); 330 if (NS_FAILED(rv)) { 331 promise->MaybeReject(rv); 332 } else { 333 promise->MaybeResolveWithUndefined(); 334 } 335 })); 336 })); 337 338 nsresult rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL); 339 if (NS_FAILED(rv)) { 340 return rv; 341 } 342 343 promise.forget(aPromise); 344 return NS_OK; 345 } 346 347 NS_IMETHODIMP 348 NSSSocketControl::SetNPNList(nsTArray<nsCString>& protocolArray) { 349 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 350 if (!mFd) return NS_ERROR_FAILURE; 351 352 // the npn list is a concatenated list of 8 bit byte strings. 353 nsCString npnList; 354 355 for (uint32_t index = 0; index < protocolArray.Length(); ++index) { 356 if (protocolArray[index].IsEmpty() || protocolArray[index].Length() > 255) 357 return NS_ERROR_ILLEGAL_VALUE; 358 359 npnList.Append(protocolArray[index].Length()); 360 npnList.Append(protocolArray[index]); 361 } 362 363 if (SSL_SetNextProtoNego( 364 mFd, BitwiseCast<const unsigned char*, const char*>(npnList.get()), 365 npnList.Length()) != SECSuccess) 366 return NS_ERROR_FAILURE; 367 368 return NS_OK; 369 } 370 371 nsresult NSSSocketControl::ActivateSSL() { 372 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 373 if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true)) 374 return NS_ERROR_FAILURE; 375 if (SECSuccess != SSL_ResetHandshake(mFd, false)) return NS_ERROR_FAILURE; 376 377 mHandshakePending = true; 378 379 return SetResumptionTokenFromExternalCache(mFd); 380 } 381 382 nsresult NSSSocketControl::GetFileDescPtr(PRFileDesc** aFilePtr) { 383 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 384 *aFilePtr = mFd; 385 return NS_OK; 386 } 387 388 nsresult NSSSocketControl::SetFileDescPtr(PRFileDesc* aFilePtr) { 389 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 390 mFd = aFilePtr; 391 return NS_OK; 392 } 393 394 void NSSSocketControl::SetCertVerificationWaiting() { 395 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 396 // mCertVerificationState may be BeforeCertVerification for the first 397 // handshake on the connection, or AfterCertVerification for subsequent 398 // renegotiation handshakes. 399 MOZ_ASSERT(mCertVerificationState != WaitingForCertVerification, 400 "Invalid state transition to WaitingForCertVerification"); 401 mCertVerificationState = WaitingForCertVerification; 402 } 403 404 // Be careful that SetCertVerificationResult does NOT get called while we are 405 // processing a SSL callback function, because SSL_AuthCertificateComplete will 406 // attempt to acquire locks that are already held by libssl when it calls 407 // callbacks. 408 void NSSSocketControl::SetCertVerificationResult(PRErrorCode errorCode) { 409 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 410 MOZ_ASSERT(mCertVerificationState == WaitingForCertVerification, 411 "Invalid state transition to AfterCertVerification"); 412 413 if (mFd) { 414 PRErrorCode passCode = errorCode; 415 if (errorCode == MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT) { 416 passCode = 0; 417 } 418 SECStatus rv = SSL_AuthCertificateComplete(mFd, passCode); 419 // Only replace errorCode if there was originally no error. 420 // SSL_AuthCertificateComplete will return SECFailure with the error code 421 // set to PR_WOULD_BLOCK_ERROR if there is a pending event to select a 422 // client authentication certificate. This is not an error. 423 if (rv != SECSuccess && PR_GetError() != PR_WOULD_BLOCK_ERROR && 424 errorCode == 0) { 425 errorCode = PR_GetError(); 426 if (errorCode == 0) { 427 NS_ERROR("SSL_AuthCertificateComplete didn't set error code"); 428 errorCode = PR_INVALID_STATE_ERROR; 429 } 430 } 431 } 432 433 if (errorCode && 434 errorCode != MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT) { 435 mFailedVerification = true; 436 SetCanceled(errorCode); 437 } 438 439 if (mPlaintextBytesRead && !errorCode) { 440 glean::ssl::bytes_before_cert_callback.Accumulate( 441 AssertedCast<uint32_t>(mPlaintextBytesRead)); 442 } 443 444 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 445 ("[%p] SetCertVerificationResult to AfterCertVerification, " 446 "mTlsHandshakeCallback=%p", 447 (void*)mFd, mTlsHandshakeCallback.get())); 448 449 mCertVerificationState = AfterCertVerification; 450 if (mTlsHandshakeCallback) { 451 (void)mTlsHandshakeCallback->CertVerificationDone(); 452 } 453 } 454 455 void NSSSocketControl::ClientAuthCertificateSelected( 456 nsTArray<uint8_t>& certBytes, nsTArray<nsTArray<uint8_t>>& certChainBytes) { 457 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 458 // If mFd is nullptr, the connection has been closed already, so we don't 459 // need to do anything here. 460 if (!mFd) { 461 return; 462 } 463 SECItem certItem = { 464 siBuffer, 465 const_cast<uint8_t*>(certBytes.Elements()), 466 static_cast<unsigned int>(certBytes.Length()), 467 }; 468 // Ensure that osclientcerts (or ipcclientcerts, in the socket process) will 469 // populate its list of certificates and keys. 470 AutoSearchingForClientAuthCertificates _; 471 UniqueCERTCertificate cert(CERT_NewTempCertificate( 472 CERT_GetDefaultCertDB(), &certItem, nullptr, false, true)); 473 UniqueSECKEYPrivateKey key; 474 if (cert) { 475 key.reset(PK11_FindKeyByAnyCert(cert.get(), nullptr)); 476 mClientCertChain.reset(CERT_NewCertList()); 477 if (key && mClientCertChain) { 478 for (const auto& certBytes : certChainBytes) { 479 SECItem certItem = { 480 siBuffer, 481 const_cast<uint8_t*>(certBytes.Elements()), 482 static_cast<unsigned int>(certBytes.Length()), 483 }; 484 UniqueCERTCertificate cert(CERT_NewTempCertificate( 485 CERT_GetDefaultCertDB(), &certItem, nullptr, false, true)); 486 if (cert) { 487 if (CERT_AddCertToListTail(mClientCertChain.get(), cert.get()) == 488 SECSuccess) { 489 (void)cert.release(); 490 } 491 } 492 } 493 } 494 } 495 496 bool sendingClientAuthCert = cert && key; 497 if (sendingClientAuthCert) { 498 mSentClientCert = true; 499 glean::security::client_auth_cert_usage.Get("sent"_ns).Add(1); 500 } 501 502 (void)SSL_ClientCertCallbackComplete( 503 mFd, sendingClientAuthCert ? SECSuccess : SECFailure, 504 sendingClientAuthCert ? key.release() : nullptr, 505 sendingClientAuthCert ? cert.release() : nullptr); 506 507 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 508 ("[%p] ClientAuthCertificateSelected mTlsHandshakeCallback=%p", 509 (void*)mFd, mTlsHandshakeCallback.get())); 510 if (mTlsHandshakeCallback) { 511 (void)mTlsHandshakeCallback->ClientAuthCertificateSelected(); 512 } 513 } 514 515 NS_IMETHODIMP 516 NSSSocketControl::DisableEarlyData() { 517 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 518 if (!mFd) { 519 return NS_OK; 520 } 521 if (IsCanceled()) { 522 return NS_OK; 523 } 524 525 if (SSL_OptionSet(mFd, SSL_ENABLE_0RTT_DATA, false) != SECSuccess) { 526 return NS_ERROR_FAILURE; 527 } 528 return NS_OK; 529 } 530 531 NS_IMETHODIMP 532 NSSSocketControl::SetHandshakeCallbackListener( 533 nsITlsHandshakeCallbackListener* callback) { 534 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 535 mTlsHandshakeCallback = callback; 536 return NS_OK; 537 } 538 539 PRStatus NSSSocketControl::CloseSocketAndDestroy() { 540 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 541 542 mClientAuthCertificateRequest.reset(); 543 544 PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER); 545 MOZ_ASSERT( 546 popped && popped->identity == nsSSLIOLayerHelpers::nsSSLIOLayerIdentity, 547 "SSL Layer not on top of stack"); 548 549 // The plaintext layer is not always present - so it's not a fatal error if it 550 // cannot be removed. 551 // Note that PR_PopIOLayer may modify its stack, so a pointer returned by 552 // PR_GetIdentitiesLayer may not point to what we think it points to after 553 // calling PR_PopIOLayer. We must operate on the pointer returned by 554 // PR_PopIOLayer. 555 if (PR_GetIdentitiesLayer(mFd, 556 nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity)) { 557 PRFileDesc* poppedPlaintext = 558 PR_PopIOLayer(mFd, nsSSLIOLayerHelpers::nsSSLPlaintextLayerIdentity); 559 poppedPlaintext->dtor(poppedPlaintext); 560 } 561 562 // We need to clear the callback to make sure the ssl layer cannot call the 563 // callback after mFD is nulled. 564 SSL_SetResumptionTokenCallback(mFd, nullptr, nullptr); 565 566 PRStatus status = mFd->methods->close(mFd); 567 568 // the NSSSocketControl instance can out-live the connection, so we need some 569 // indication that the connection has been closed. mFd == nullptr is that 570 // indication. This is needed, for example, when the connection is closed 571 // before we have finished validating the server's certificate. 572 mFd = nullptr; 573 574 if (status != PR_SUCCESS) return status; 575 576 popped->identity = PR_INVALID_IO_LAYER; 577 popped->dtor(popped); 578 579 return PR_SUCCESS; 580 } 581 582 NS_IMETHODIMP 583 NSSSocketControl::GetEsniTxt(nsACString& aEsniTxt) { 584 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 585 aEsniTxt = mEsniTxt; 586 return NS_OK; 587 } 588 589 NS_IMETHODIMP 590 NSSSocketControl::SetEsniTxt(const nsACString& aEsniTxt) { 591 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 592 mEsniTxt = aEsniTxt; 593 594 if (mEsniTxt.Length()) { 595 nsAutoCString esniBin; 596 if (NS_OK != Base64Decode(mEsniTxt, esniBin)) { 597 MOZ_LOG(gPIPNSSLog, LogLevel::Error, 598 ("[%p] Invalid ESNIKeys record. Couldn't base64 decode\n", 599 (void*)mFd)); 600 return NS_OK; 601 } 602 603 if (SECSuccess != 604 SSL_EnableESNI(mFd, reinterpret_cast<const PRUint8*>(esniBin.get()), 605 esniBin.Length(), nullptr)) { 606 MOZ_LOG(gPIPNSSLog, LogLevel::Error, 607 ("[%p] Invalid ESNIKeys record %s\n", (void*)mFd, 608 PR_ErrorToName(PR_GetError()))); 609 return NS_OK; 610 } 611 } 612 613 return NS_OK; 614 } 615 616 NS_IMETHODIMP 617 NSSSocketControl::GetEchConfig(nsACString& aEchConfig) { 618 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 619 aEchConfig = mEchConfig; 620 return NS_OK; 621 } 622 623 NS_IMETHODIMP 624 NSSSocketControl::SetEchConfig(const nsACString& aEchConfig) { 625 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 626 mEchConfig = aEchConfig; 627 628 if (mEchConfig.Length()) { 629 if (SECSuccess != 630 SSL_SetClientEchConfigs( 631 mFd, reinterpret_cast<const PRUint8*>(aEchConfig.BeginReading()), 632 aEchConfig.Length())) { 633 MOZ_LOG(gPIPNSSLog, LogLevel::Error, 634 ("[%p] Invalid EchConfig record %s\n", (void*)mFd, 635 PR_ErrorToName(PR_GetError()))); 636 return NS_OK; 637 } 638 UpdateEchExtensionStatus(EchExtensionStatus::kReal); 639 } 640 return NS_OK; 641 } 642 643 NS_IMETHODIMP 644 NSSSocketControl::GetRetryEchConfig(nsACString& aEchConfig) { 645 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 646 if (!mFd) { 647 return NS_ERROR_FAILURE; 648 } 649 650 ScopedAutoSECItem retryConfigItem; 651 SECStatus rv = SSL_GetEchRetryConfigs(mFd, &retryConfigItem); 652 if (rv != SECSuccess) { 653 return NS_ERROR_FAILURE; 654 } 655 aEchConfig = nsCString(reinterpret_cast<const char*>(retryConfigItem.data), 656 retryConfigItem.len); 657 return NS_OK; 658 } 659 660 NS_IMETHODIMP 661 NSSSocketControl::GetPeerId(nsACString& aResult) { 662 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 663 if (!mPeerId.IsEmpty()) { 664 aResult.Assign(mPeerId); 665 return NS_OK; 666 } 667 668 if (mProviderFlags & 669 nsISocketProvider::ANONYMOUS_CONNECT) { // See bug 466080 670 mPeerId.AppendLiteral("anon:"); 671 } 672 if (mProviderFlags & nsISocketProvider::NO_PERMANENT_STORAGE) { 673 mPeerId.AppendLiteral("private:"); 674 } 675 if (mProviderFlags & nsISocketProvider::BE_CONSERVATIVE) { 676 mPeerId.AppendLiteral("beConservative:"); 677 } 678 679 mPeerId.AppendPrintf("tlsflags0x%08x:", mProviderTlsFlags); 680 681 mPeerId.Append(mHostName); 682 mPeerId.Append(':'); 683 mPeerId.AppendInt(GetPort()); 684 nsAutoCString suffix; 685 mOriginAttributes.CreateSuffix(suffix); 686 mPeerId.Append(suffix); 687 688 aResult.Assign(mPeerId); 689 return NS_OK; 690 } 691 692 nsresult NSSSocketControl::SetResumptionTokenFromExternalCache(PRFileDesc* fd) { 693 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 694 if (!fd) { 695 return NS_ERROR_INVALID_ARG; 696 } 697 698 // If SSL_NO_CACHE option was set, we must not use the cache 699 PRIntn val; 700 if (SSL_OptionGet(fd, SSL_NO_CACHE, &val) != SECSuccess) { 701 return NS_ERROR_FAILURE; 702 } 703 704 if (val != 0) { 705 return NS_OK; 706 } 707 708 nsTArray<uint8_t> token; 709 nsAutoCString peerId; 710 nsresult rv = GetPeerId(peerId); 711 if (NS_FAILED(rv)) { 712 return rv; 713 } 714 715 uint64_t tokenId = 0; 716 mozilla::net::SessionCacheInfo info; 717 rv = mozilla::net::SSLTokensCache::Get(peerId, token, info, &tokenId); 718 if (NS_FAILED(rv)) { 719 if (rv == NS_ERROR_NOT_AVAILABLE) { 720 // It's ok if we can't find the token. 721 return NS_OK; 722 } 723 724 return rv; 725 } 726 727 SECStatus srv = SSL_SetResumptionToken(fd, token.Elements(), token.Length()); 728 if (srv == SECFailure) { 729 PRErrorCode error = PR_GetError(); 730 mozilla::net::SSLTokensCache::Remove(peerId, tokenId); 731 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 732 ("Setting token failed with NSS error %d [id=%s]", error, 733 PromiseFlatCString(peerId).get())); 734 // We don't consider SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR as a hard error, 735 // since this error means this token is just expired or can't be decoded 736 // correctly. 737 if (error == SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR) { 738 return NS_OK; 739 } 740 741 return NS_ERROR_FAILURE; 742 } 743 744 SetSessionCacheInfo(std::move(info)); 745 746 return NS_OK; 747 } 748 749 void NSSSocketControl::SetPreliminaryHandshakeInfo( 750 const SSLChannelInfo& channelInfo, const SSLCipherSuiteInfo& cipherInfo) { 751 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 752 mResumed = channelInfo.resumed; 753 mCipherSuite.emplace(channelInfo.cipherSuite); 754 mProtocolVersion.emplace(channelInfo.protocolVersion & 0xFF); 755 mKeaGroupName.emplace(getKeaGroupName(channelInfo.keaGroup)); 756 mSignatureSchemeName.emplace(getSignatureName(channelInfo.signatureScheme)); 757 mIsDelegatedCredential.emplace(channelInfo.peerDelegCred); 758 mIsAcceptedEch.emplace(channelInfo.echAccepted); 759 } 760 761 void NSSSocketControl::MaybeSelectClientAuthCertificate() { 762 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 763 if (!IsWaitingForCertVerification() && mClaimed && 764 mClientAuthCertificateRequest.isSome()) { 765 MOZ_LOG(gPIPNSSLog, mozilla::LogLevel::Debug, 766 ("[%p] selecting client auth certificate", (void*)mFd)); 767 ClientAuthCertificateRequest request( 768 mClientAuthCertificateRequest.extract()); 769 DoSelectClientAuthCertificate(this, std::move(request.mServerCertificate), 770 std::move(request.mCANames)); 771 } 772 } 773 774 NS_IMETHODIMP NSSSocketControl::Claim() { 775 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 776 mClaimed = true; 777 return NS_OK; 778 } 779 780 NS_IMETHODIMP NSSSocketControl::SetBrowserId(uint64_t browserId) { 781 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 782 mBrowserId = browserId; 783 return NS_OK; 784 } 785 786 NS_IMETHODIMP NSSSocketControl::GetBrowserId(uint64_t* browserId) { 787 COMMON_SOCKET_CONTROL_ASSERT_ON_OWNING_THREAD(); 788 if (!browserId) { 789 return NS_ERROR_INVALID_ARG; 790 } 791 *browserId = mBrowserId; 792 return NS_OK; 793 }