SSLServerCertVerification.cpp (51866B)
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 // During certificate authentication, we call CertVerifier::VerifySSLServerCert. 8 // This function may make zero or more HTTP requests (e.g. to gather revocation 9 // information). Our fetching logic for these requests processes them on the 10 // socket transport service thread. 11 // 12 // Because the connection for which we are verifying the certificate is 13 // happening on the socket transport thread, if our cert auth hook were to call 14 // VerifySSLServerCert directly, there would be a deadlock: VerifySSLServerCert 15 // would cause an event to be asynchronously posted to the socket transport 16 // thread, and then it would block the socket transport thread waiting to be 17 // notified of the HTTP response. However, the HTTP request would never actually 18 // be processed because the socket transport thread would be blocked and so it 19 // wouldn't be able process HTTP requests. 20 // 21 // Consequently, when we are asked to verify a certificate, we must always call 22 // VerifySSLServerCert on another thread. To accomplish this, our auth cert hook 23 // dispatches a SSLServerCertVerificationJob to a pool of background threads, 24 // and then immediately returns SECWouldBlock to libssl. These jobs are where 25 // VerifySSLServerCert is actually called. 26 // 27 // When our auth cert hook returns SECWouldBlock, libssl will carry on the 28 // handshake while we validate the certificate. This will free up the socket 29 // transport thread so that HTTP requests--including the OCSP requests needed 30 // for cert verification as mentioned above--can be processed. 31 // 32 // Once VerifySSLServerCert returns, the cert verification job dispatches a 33 // SSLServerCertVerificationResult to the socket transport thread; the 34 // SSLServerCertVerificationResult will notify libssl that the certificate 35 // authentication is complete. Once libssl is notified that the authentication 36 // is complete, it will continue the TLS handshake (if it hasn't already 37 // finished) and it will begin allowing us to send/receive data on the 38 // connection. 39 // 40 // Timeline of events (for connections managed by the socket transport service): 41 // 42 // * libssl calls SSLServerCertVerificationJob::Dispatch on the socket 43 // transport thread. 44 // * SSLServerCertVerificationJob::Dispatch queues a job 45 // (instance of SSLServerCertVerificationJob) to its background thread 46 // pool and returns. 47 // * One of the background threads calls CertVerifier::VerifySSLServerCert, 48 // which may enqueue some HTTP request(s) onto the socket transport thread, 49 // and then blocks that background thread waiting for the responses and/or 50 // timeouts or errors for those requests. 51 // * Once those HTTP responses have all come back or failed, the 52 // CertVerifier::VerifySSLServerCert function returns a result indicating 53 // that the validation succeeded or failed. 54 // * If the validation succeeded, then a SSLServerCertVerificationResult 55 // event is posted to the socket transport thread, and the cert 56 // verification thread becomes free to verify other certificates. 57 // * Otherwise, we do cert override processing to see if the validation 58 // error can be convered by override rules. The result of this processing 59 // is similarly dispatched in a SSLServerCertVerificationResult. 60 // * The SSLServerCertVerificationResult event will either wake up the 61 // socket (using SSL_AuthCertificateComplete) if validation succeeded or 62 // there was an error override, or it will set an error flag so that the 63 // next I/O operation on the socket will fail, causing the socket transport 64 // thread to close the connection. 65 // 66 // SSLServerCertVerificationResult must be dispatched to the socket transport 67 // thread because we must only call SSL_* functions on the socket transport 68 // thread since they may do I/O, because many parts of NSSSocketControl and the 69 // PSM NSS I/O layer are not thread-safe, and because we need the event to 70 // interrupt the PR_Poll that may waiting for I/O on the socket for which we 71 // are validating the cert. 72 // 73 // When socket process is enabled, libssl is running on socket process. To 74 // perform certificate authentication with CertVerifier, we have to send all 75 // needed information to parent process and send the result back to socket 76 // process via IPC. The workflow is described below. 77 // 1. In AuthCertificateHookInternal(), we call RemoteProcessCertVerification() 78 // instead of SSLServerCertVerificationJob::Dispatch when we are on socket 79 // process. 80 // 2. In RemoteProcessCertVerification(), PVerifySSLServerCert actors will be 81 // created on IPDL background thread for carrying needed information via IPC. 82 // 3. On parent process, VerifySSLServerCertParent is created and it calls 83 // SSLServerCertVerificationJob::Dispatch for doing certificate verification 84 // on one of CertVerificationThreads. 85 // 4. When validation is done, OnVerifiedSSLServerCertSuccess IPC message is 86 // sent through the IPDL background thread when 87 // CertVerifier::VerifySSLServerCert returns Success. Otherwise, 88 // OnVerifiedSSLServerCertFailure is sent. 89 // 5. After setp 4, PVerifySSLServerCert actors will be released. The 90 // verification result will be dispatched via 91 // SSLServerCertVerificationResult. 92 93 #include "SSLServerCertVerification.h" 94 95 #include <cstring> 96 97 #include "CertVerifier.h" 98 #include "CryptoTask.h" 99 #include "ExtendedValidation.h" 100 #include "NSSCertDBTrustDomain.h" 101 #include "NSSSocketControl.h" 102 #include "PSMRunnable.h" 103 #include "RootCertificateTelemetryUtils.h" 104 #include "ScopedNSSTypes.h" 105 #include "SharedCertVerifier.h" 106 #include "VerifySSLServerCertChild.h" 107 #include "cert.h" 108 #include "mozilla/Assertions.h" 109 #include "mozilla/RefPtr.h" 110 #include "mozilla/StaticPrefs_security.h" 111 #include "mozilla/UniquePtr.h" 112 #include "mozilla/glean/SecurityManagerSslMetrics.h" 113 #include "nsComponentManagerUtils.h" 114 #include "nsContentUtils.h" 115 #include "nsICertOverrideService.h" 116 #include "nsIPublicKeyPinningService.h" 117 #include "nsISiteSecurityService.h" 118 #include "nsISocketProvider.h" 119 #include "nsThreadPool.h" 120 #include "nsNetUtil.h" 121 #include "nsNSSCertificate.h" 122 #include "nsNSSComponent.h" 123 #include "nsNSSIOLayer.h" 124 #include "nsServiceManagerUtils.h" 125 #include "nsString.h" 126 #include "nsURLHelper.h" 127 #include "nsXPCOMCIDInternal.h" 128 #include "mozpkix/pkix.h" 129 #include "mozpkix/pkixcheck.h" 130 #include "mozpkix/pkixnss.h" 131 #include "mozpkix/pkixutil.h" 132 #include "secerr.h" 133 #include "secport.h" 134 #include "ssl.h" 135 #include "sslerr.h" 136 #include "sslexp.h" 137 138 #include "IOnionAliasService.h" 139 140 extern mozilla::LazyLogModule gPIPNSSLog; 141 142 using namespace mozilla::pkix; 143 144 namespace mozilla { 145 namespace psm { 146 147 // do not use a nsCOMPtr to avoid static initializer/destructor 148 nsIThreadPool* gCertVerificationThreadPool = nullptr; 149 150 // Called when the socket transport thread starts, to initialize the SSL cert 151 // verification thread pool. By tying the thread pool startup/shutdown directly 152 // to the STS thread's lifetime, we ensure that they are *always* available for 153 // SSL connections and that there are no races during startup and especially 154 // shutdown. (Previously, we have had multiple problems with races in PSM 155 // background threads, and the race-prevention/shutdown logic used there is 156 // brittle. Since this service is critical to things like downloading updates, 157 // we take no chances.) Also, by doing things this way, we avoid the need for 158 // locks, since gCertVerificationThreadPool is only ever accessed on the socket 159 // transport thread. 160 void InitializeSSLServerCertVerificationThreads() { 161 // TODO: tuning, make parameters preferences 162 gCertVerificationThreadPool = new nsThreadPool(); 163 NS_ADDREF(gCertVerificationThreadPool); 164 165 (void)gCertVerificationThreadPool->SetThreadLimit(5); 166 (void)gCertVerificationThreadPool->SetIdleThreadLimit(1); 167 (void)gCertVerificationThreadPool->SetIdleThreadMaximumTimeout(30 * 1000); 168 (void)gCertVerificationThreadPool->SetIdleThreadGraceTimeout(500); 169 (void)gCertVerificationThreadPool->SetName("SSL Cert"_ns); 170 } 171 172 // Called when the socket transport thread finishes, to destroy the thread 173 // pool. Since the socket transport service has stopped processing events, it 174 // will not attempt any more SSL I/O operations, so it is clearly safe to shut 175 // down the SSL cert verification infrastructure. Also, the STS will not 176 // dispatch many SSL verification result events at this point, so any pending 177 // cert verifications will (correctly) fail at the point they are dispatched. 178 // 179 // The other shutdown race condition that is possible is a race condition with 180 // shutdown of the nsNSSComponent service. We use the 181 // nsNSSShutdownPreventionLock where needed (not here) to prevent that. 182 void StopSSLServerCertVerificationThreads() { 183 if (gCertVerificationThreadPool) { 184 gCertVerificationThreadPool->Shutdown(); 185 NS_RELEASE(gCertVerificationThreadPool); 186 } 187 } 188 189 // A probe value of 1 means "no error". 190 uint32_t MapOverridableErrorToProbeValue(PRErrorCode errorCode) { 191 switch (errorCode) { 192 case SEC_ERROR_UNKNOWN_ISSUER: 193 return 2; 194 case SEC_ERROR_CA_CERT_INVALID: 195 return 3; 196 case SEC_ERROR_UNTRUSTED_ISSUER: 197 return 4; 198 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: 199 return 5; 200 case SEC_ERROR_UNTRUSTED_CERT: 201 return 6; 202 case SEC_ERROR_INADEQUATE_KEY_USAGE: 203 return 7; 204 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: 205 return 8; 206 case SSL_ERROR_BAD_CERT_DOMAIN: 207 return 9; 208 case SEC_ERROR_EXPIRED_CERTIFICATE: 209 return 10; 210 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: 211 return 11; 212 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: 213 return 12; 214 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE: 215 return 13; 216 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE: 217 return 14; 218 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE: 219 return 15; 220 case SEC_ERROR_INVALID_TIME: 221 return 16; 222 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME: 223 return 17; 224 // mozilla::pkix::MOZILLA_PKIX_ERROR_ADDITIONAL_POLICY_CONSTRAINT_FAILED was 225 // 18 226 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT: 227 return 19; 228 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED: 229 return 20; 230 case mozilla::pkix:: 231 MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY: 232 return 21; 233 } 234 NS_WARNING( 235 "Unknown certificate error code. Does MapOverridableErrorToProbeValue " 236 "handle everything in CategorizeCertificateError?"); 237 return 0; 238 } 239 240 static uint32_t MapCertErrorToProbeValue(PRErrorCode errorCode) { 241 uint32_t probeValue; 242 switch (errorCode) { 243 // see security/pkix/include/pkix/Result.h 244 #define MOZILLA_PKIX_MAP(name, value, nss_name) \ 245 case nss_name: \ 246 probeValue = value; \ 247 break; 248 MOZILLA_PKIX_MAP_LIST 249 #undef MOZILLA_PKIX_MAP 250 default: 251 return 0; 252 } 253 254 // Since FATAL_ERROR_FLAG is 0x800, fatal error values are much larger than 255 // non-fatal error values. To conserve space, we remap these so they start at 256 // (decimal) 90 instead of 0x800. Currently there are ~50 non-fatal errors 257 // mozilla::pkix might return, so saving space for 90 should be sufficient 258 // (similarly, there are 4 fatal errors, so saving space for 10 should also 259 // be sufficient). 260 static_assert( 261 FATAL_ERROR_FLAG == 0x800, 262 "mozilla::pkix::FATAL_ERROR_FLAG is not what we were expecting"); 263 if (probeValue & FATAL_ERROR_FLAG) { 264 probeValue ^= FATAL_ERROR_FLAG; 265 probeValue += 90; 266 } 267 return probeValue; 268 } 269 270 // If the given PRErrorCode is an overridable certificate error, return which 271 // category (trust, time, domain mismatch) it falls in. If it is not 272 // overridable, return Nothing. 273 Maybe<nsITransportSecurityInfo::OverridableErrorCategory> 274 CategorizeCertificateError(PRErrorCode certificateError) { 275 switch (certificateError) { 276 case SEC_ERROR_CA_CERT_INVALID: 277 case SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED: 278 case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: 279 case SEC_ERROR_UNKNOWN_ISSUER: 280 case mozilla::pkix::MOZILLA_PKIX_ERROR_CA_CERT_USED_AS_END_ENTITY: 281 case mozilla::pkix::MOZILLA_PKIX_ERROR_EMPTY_ISSUER_NAME: 282 case mozilla::pkix::MOZILLA_PKIX_ERROR_INADEQUATE_KEY_SIZE: 283 case mozilla::pkix:: 284 MOZILLA_PKIX_ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY: 285 case mozilla::pkix::MOZILLA_PKIX_ERROR_MITM_DETECTED: 286 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_ISSUER_CERTIFICATE: 287 case mozilla::pkix::MOZILLA_PKIX_ERROR_SELF_SIGNED_CERT: 288 case mozilla::pkix::MOZILLA_PKIX_ERROR_V1_CERT_USED_AS_CA: 289 case mozilla::pkix::MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT: 290 return Some( 291 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TRUST); 292 293 case SSL_ERROR_BAD_CERT_DOMAIN: 294 return Some( 295 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_DOMAIN); 296 297 case SEC_ERROR_EXPIRED_CERTIFICATE: 298 case SEC_ERROR_INVALID_TIME: 299 case mozilla::pkix::MOZILLA_PKIX_ERROR_NOT_YET_VALID_CERTIFICATE: 300 return Some( 301 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_TIME); 302 303 default: 304 break; 305 } 306 return Nothing(); 307 } 308 309 // Helper function to determine if overrides are allowed for this host. 310 // Overrides are not allowed for known HSTS hosts or hosts with pinning 311 // information. However, IP addresses can never be HSTS hosts and don't have 312 // pinning information. 313 static nsresult OverrideAllowedForHost( 314 uint64_t aPtrForLog, const nsACString& aHostname, 315 const OriginAttributes& aOriginAttributes, /*out*/ bool& aOverrideAllowed) { 316 aOverrideAllowed = false; 317 318 // If this is an IP address, overrides are allowed, because an IP address is 319 // never an HSTS host. nsISiteSecurityService takes this into account 320 // already, but the real problem here is that calling NS_NewURI with an IPv6 321 // address fails. We do this to avoid that. A more comprehensive fix would be 322 // to have Necko provide an nsIURI to PSM and to use that here (and 323 // everywhere). However, that would be a wide-spanning change. 324 if (net_IsValidIPv6Addr(aHostname)) { 325 aOverrideAllowed = true; 326 return NS_OK; 327 } 328 329 // If this is an HTTP Strict Transport Security host or a pinned host and the 330 // certificate is bad, don't allow overrides (RFC 6797 section 12.1). 331 bool strictTransportSecurityEnabled = false; 332 bool isStaticallyPinned = false; 333 nsCOMPtr<nsISiteSecurityService> sss(do_GetService(NS_SSSERVICE_CONTRACTID)); 334 if (!sss) { 335 MOZ_LOG( 336 gPIPNSSLog, LogLevel::Debug, 337 ("[0x%" PRIx64 "] Couldn't get nsISiteSecurityService to check HSTS", 338 aPtrForLog)); 339 return NS_ERROR_FAILURE; 340 } 341 342 nsCOMPtr<nsIURI> uri; 343 nsresult rv = NS_NewURI(getter_AddRefs(uri), "https://"_ns + aHostname); 344 if (NS_FAILED(rv)) { 345 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 346 ("[0x%" PRIx64 "] Creating new URI failed", aPtrForLog)); 347 return rv; 348 } 349 350 rv = 351 sss->IsSecureURI(uri, aOriginAttributes, &strictTransportSecurityEnabled); 352 if (NS_FAILED(rv)) { 353 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 354 ("[0x%" PRIx64 "] checking for HSTS failed", aPtrForLog)); 355 return rv; 356 } 357 358 nsCOMPtr<nsIPublicKeyPinningService> pkps = 359 do_GetService(NS_PKPSERVICE_CONTRACTID, &rv); 360 if (!pkps) { 361 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 362 ("[0x%" PRIx64 363 "] Couldn't get nsIPublicKeyPinningService to check pinning", 364 aPtrForLog)); 365 return NS_ERROR_FAILURE; 366 } 367 rv = pkps->HostHasPins(uri, &isStaticallyPinned); 368 if (NS_FAILED(rv)) { 369 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 370 ("[0x%" PRIx64 "] checking for static pin failed", aPtrForLog)); 371 return rv; 372 } 373 374 aOverrideAllowed = !strictTransportSecurityEnabled && !isStaticallyPinned; 375 return NS_OK; 376 } 377 378 // This function assumes that we will only use the SPDY connection coalescing 379 // feature on connections where we have negotiated SPDY using NPN. If we ever 380 // talk SPDY without having negotiated it with SPDY, this code will give wrong 381 // and perhaps unsafe results. 382 // 383 // Returns SECSuccess on the initial handshake of all connections, on 384 // renegotiations for any connections where we did not negotiate SPDY, or on any 385 // SPDY connection where the server's certificate did not change. 386 // 387 // Prohibit changing the server cert only if we negotiated SPDY, 388 // in order to support SPDY's cross-origin connection pooling. 389 static SECStatus BlockServerCertChangeForSpdy( 390 NSSSocketControl* socketControl, const UniqueCERTCertificate& serverCert) { 391 if (!socketControl->IsHandshakeCompleted()) { 392 // first handshake on this connection, not a 393 // renegotiation. 394 return SECSuccess; 395 } 396 397 // Filter out sockets that did not neogtiate SPDY via NPN 398 nsCOMPtr<nsITransportSecurityInfo> securityInfo; 399 nsresult rv = socketControl->GetSecurityInfo(getter_AddRefs(securityInfo)); 400 MOZ_ASSERT(NS_SUCCEEDED(rv), "GetSecurityInfo() failed during renegotiation"); 401 if (NS_FAILED(rv) || !securityInfo) { 402 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 403 return SECFailure; 404 } 405 nsAutoCString negotiatedNPN; 406 rv = securityInfo->GetNegotiatedNPN(negotiatedNPN); 407 MOZ_ASSERT(NS_SUCCEEDED(rv), 408 "GetNegotiatedNPN() failed during renegotiation"); 409 410 if (NS_SUCCEEDED(rv) && !StringBeginsWith(negotiatedNPN, "spdy/"_ns)) { 411 return SECSuccess; 412 } 413 // If GetNegotiatedNPN() failed we will assume spdy for safety's safe 414 if (NS_FAILED(rv)) { 415 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 416 ("BlockServerCertChangeForSpdy failed GetNegotiatedNPN() call." 417 " Assuming spdy.")); 418 } 419 420 // Check to see if the cert has actually changed 421 nsCOMPtr<nsIX509Cert> cert(socketControl->GetServerCert()); 422 if (!cert) { 423 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 424 return SECFailure; 425 } 426 nsTArray<uint8_t> certDER; 427 if (NS_FAILED(cert->GetRawDER(certDER))) { 428 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 429 return SECFailure; 430 } 431 if (certDER.Length() == serverCert->derCert.len && 432 memcmp(certDER.Elements(), serverCert->derCert.data, certDER.Length()) == 433 0) { 434 return SECSuccess; 435 } 436 437 // Report an error - changed cert is confirmed 438 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 439 ("SPDY refused to allow new cert during renegotiation")); 440 PR_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED, 0); 441 return SECFailure; 442 } 443 444 void GatherTelemetryForSingleSCT(const ct::VerifiedSCT& verifiedSct) { 445 // See scts_verification_status in metrics.yaml. 446 uint32_t verificationStatus = 0; 447 switch (verifiedSct.logState) { 448 case ct::CTLogState::Admissible: 449 verificationStatus = 1; 450 break; 451 case ct::CTLogState::Retired: 452 verificationStatus = 5; 453 break; 454 } 455 glean::ssl::scts_verification_status.AccumulateSingleSample( 456 verificationStatus); 457 } 458 459 void GatherCertificateTransparencyTelemetry( 460 const nsTArray<uint8_t>& rootCert, 461 const CertificateTransparencyInfo& info) { 462 if (!info.enabled) { 463 // No telemetry is gathered when CT is disabled. 464 return; 465 } 466 467 for (const ct::VerifiedSCT& sct : info.verifyResult.verifiedScts) { 468 GatherTelemetryForSingleSCT(sct); 469 } 470 471 // See scts_verification_status in metrics.yaml. 472 for (size_t i = 0; i < info.verifyResult.decodingErrors; ++i) { 473 glean::ssl::scts_verification_status.AccumulateSingleSample(0); 474 } 475 for (size_t i = 0; i < info.verifyResult.sctsFromUnknownLogs; ++i) { 476 glean::ssl::scts_verification_status.AccumulateSingleSample(2); 477 } 478 for (size_t i = 0; i < info.verifyResult.sctsWithInvalidSignatures; ++i) { 479 glean::ssl::scts_verification_status.AccumulateSingleSample(3); 480 } 481 for (size_t i = 0; i < info.verifyResult.sctsWithInvalidTimestamps; ++i) { 482 glean::ssl::scts_verification_status.AccumulateSingleSample(4); 483 } 484 for (size_t i = 0; i < info.verifyResult.sctsWithDistrustedTimestamps; ++i) { 485 glean::ssl::scts_verification_status.AccumulateSingleSample(6); 486 } 487 488 // See scts_origin in metrics.yaml. 489 for (size_t i = 0; i < info.verifyResult.embeddedSCTs; ++i) { 490 glean::ssl::scts_origin.AccumulateSingleSample(1); 491 } 492 for (size_t i = 0; i < info.verifyResult.sctsFromTLSHandshake; ++i) { 493 glean::ssl::scts_origin.AccumulateSingleSample(2); 494 } 495 for (size_t i = 0; i < info.verifyResult.sctsFromOCSP; ++i) { 496 glean::ssl::scts_origin.AccumulateSingleSample(3); 497 } 498 499 // Handle the histogram of SCTs counts. 500 uint32_t sctsCount = 501 static_cast<uint32_t>(info.verifyResult.verifiedScts.size()); 502 // Note that sctsCount can also be 0 in case we've received SCT binary data, 503 // but it failed to parse (e.g. due to unsupported CT protocol version). 504 glean::ssl::scts_per_connection.AccumulateSingleSample(sctsCount); 505 506 uint32_t sctsFromTiledLogs = 0; 507 for (auto verifiedSCT : info.verifyResult.verifiedScts) { 508 if (verifiedSCT.logFormat == ct::CTLogFormat::Tiled) { 509 sctsFromTiledLogs++; 510 } 511 } 512 glean::ssl::scts_from_tiled_logs_per_connection.AccumulateSingleSample( 513 sctsFromTiledLogs); 514 515 // Report CT Policy compliance by CA. 516 if (info.policyCompliance.isSome() && 517 *info.policyCompliance != ct::CTPolicyCompliance::Compliant) { 518 int32_t binId = RootCABinNumber(rootCert); 519 if (binId != ROOT_CERTIFICATE_HASH_FAILURE) { 520 glean::ssl::ct_policy_non_compliant_connections_by_ca_2 521 .AccumulateSingleSample(binId); 522 } 523 } 524 } 525 526 // This function collects telemetry about certs. It will be called on one of 527 // CertVerificationThread. When the socket process is used this will be called 528 // on the parent process. 529 static void CollectCertTelemetry( 530 mozilla::pkix::Result aCertVerificationResult, EVStatus aEVStatus, 531 CertVerifier::OCSPStaplingStatus aOcspStaplingStatus, 532 KeySizeStatus aKeySizeStatus, 533 const PinningTelemetryInfo& aPinningTelemetryInfo, 534 const nsTArray<nsTArray<uint8_t>>& aBuiltCertChain, 535 const CertificateTransparencyInfo& aCertificateTransparencyInfo, 536 const IssuerSources& issuerSources) { 537 uint32_t evStatus = (aCertVerificationResult != Success) ? 0 // 0 = Failure 538 : (aEVStatus != EVStatus::EV) ? 1 // 1 = DV 539 : 2; // 2 = EV 540 glean::cert::ev_status.AccumulateSingleSample(evStatus); 541 542 if (aOcspStaplingStatus != CertVerifier::OCSP_STAPLING_NEVER_CHECKED) { 543 glean::ssl::ocsp_stapling.AccumulateSingleSample(aOcspStaplingStatus); 544 } 545 546 if (aKeySizeStatus != KeySizeStatus::NeverChecked) { 547 glean::cert::chain_key_size_status.AccumulateSingleSample( 548 static_cast<uint32_t>(aKeySizeStatus)); 549 } 550 551 if (aPinningTelemetryInfo.accumulateForRoot) { 552 glean::cert_pinning::failures_by_ca_2.AccumulateSingleSample( 553 aPinningTelemetryInfo.rootBucket); 554 } 555 556 if (aPinningTelemetryInfo.accumulateResult) { 557 if (aPinningTelemetryInfo.isMoz) { 558 if (aPinningTelemetryInfo.testMode) { 559 glean::cert_pinning::moz_test_results_by_host.AccumulateSingleSample( 560 aPinningTelemetryInfo.certPinningResultBucket); 561 } else { 562 glean::cert_pinning::moz_results_by_host.AccumulateSingleSample( 563 aPinningTelemetryInfo.certPinningResultBucket); 564 } 565 } else { 566 if (aPinningTelemetryInfo.testMode) { 567 glean::cert_pinning::test_results 568 .EnumGet(static_cast<glean::cert_pinning::TestResultsLabel>( 569 aPinningTelemetryInfo.certPinningResultBucket)) 570 .Add(); 571 } else { 572 glean::cert_pinning::results 573 .EnumGet(static_cast<glean::cert_pinning::ResultsLabel>( 574 aPinningTelemetryInfo.certPinningResultBucket)) 575 .Add(); 576 } 577 } 578 } 579 580 if (aCertVerificationResult == Success && aBuiltCertChain.Length() > 0) { 581 const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement(); 582 int32_t binId = RootCABinNumber(rootCert); 583 if (binId != ROOT_CERTIFICATE_HASH_FAILURE) { 584 glean::cert::validation_success_by_ca_2.AccumulateSingleSample(binId); 585 } 586 587 mozilla::glean::tls::certificate_verifications.Add(1); 588 if (issuerSources.contains(IssuerSource::TLSHandshake)) { 589 mozilla::glean::verification_used_cert_from::tls_handshake.AddToNumerator( 590 1); 591 } 592 if (issuerSources.contains(IssuerSource::PreloadedIntermediates)) { 593 mozilla::glean::verification_used_cert_from::preloaded_intermediates 594 .AddToNumerator(1); 595 } 596 if (issuerSources.contains(IssuerSource::ThirdPartyCertificates)) { 597 mozilla::glean::verification_used_cert_from::third_party_certificates 598 .AddToNumerator(1); 599 } 600 if (issuerSources.contains(IssuerSource::NSSCertDB)) { 601 mozilla::glean::verification_used_cert_from::nss_cert_db.AddToNumerator( 602 1); 603 } 604 if (issuerSources.contains(IssuerSource::BuiltInRootsModule)) { 605 mozilla::glean::verification_used_cert_from::built_in_roots_module 606 .AddToNumerator(1); 607 } 608 } 609 610 if ((aCertVerificationResult == Success || 611 aCertVerificationResult == 612 Result::ERROR_INSUFFICIENT_CERTIFICATE_TRANSPARENCY) && 613 aBuiltCertChain.Length() > 0) { 614 const nsTArray<uint8_t>& rootCert = aBuiltCertChain.LastElement(); 615 GatherCertificateTransparencyTelemetry(rootCert, 616 aCertificateTransparencyInfo); 617 } 618 } 619 620 // Note: Takes ownership of |peerCertChain| if SECSuccess is not returned. 621 Result AuthCertificate( 622 CertVerifier& certVerifier, void* aPinArg, 623 const nsTArray<uint8_t>& certBytes, 624 const nsTArray<nsTArray<uint8_t>>& peerCertChain, 625 const nsACString& aHostName, const OriginAttributes& aOriginAttributes, 626 const Maybe<nsTArray<uint8_t>>& stapledOCSPResponse, 627 const Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, 628 const Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, 629 Time time, uint32_t certVerifierFlags, 630 /*out*/ nsTArray<nsTArray<uint8_t>>& builtCertChain, 631 /*out*/ EVStatus& evStatus, 632 /*out*/ CertificateTransparencyInfo& certificateTransparencyInfo, 633 /*out*/ bool& aIsBuiltCertChainRootBuiltInRoot, 634 /*out*/ bool& aMadeOCSPRequests) { 635 CertVerifier::OCSPStaplingStatus ocspStaplingStatus = 636 CertVerifier::OCSP_STAPLING_NEVER_CHECKED; 637 KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked; 638 PinningTelemetryInfo pinningTelemetryInfo; 639 640 nsTArray<nsTArray<uint8_t>> peerCertsBytes; 641 // Don't include the end-entity certificate. 642 if (!peerCertChain.IsEmpty()) { 643 std::transform( 644 peerCertChain.cbegin() + 1, peerCertChain.cend(), 645 MakeBackInserter(peerCertsBytes), 646 [](const auto& elementArray) { return elementArray.Clone(); }); 647 } 648 649 IssuerSources issuerSources; 650 Result rv = certVerifier.VerifySSLServerCert( 651 certBytes, time, aPinArg, aHostName, builtCertChain, certVerifierFlags, 652 Some(std::move(peerCertsBytes)), stapledOCSPResponse, 653 sctsFromTLSExtension, dcInfo, aOriginAttributes, &evStatus, 654 &ocspStaplingStatus, &keySizeStatus, &pinningTelemetryInfo, 655 &certificateTransparencyInfo, &aIsBuiltCertChainRootBuiltInRoot, 656 &aMadeOCSPRequests, &issuerSources); 657 658 CollectCertTelemetry(rv, evStatus, ocspStaplingStatus, keySizeStatus, 659 pinningTelemetryInfo, builtCertChain, 660 certificateTransparencyInfo, issuerSources); 661 662 return rv; 663 } 664 665 /** 666 * Check if the self-signed onion certificate error can be overridden by another 667 * error. 668 * 669 * Basically, this function restore part of the old functionalities of 670 * DetermineCertOverrideErrors, before it was changed in Bug 1781104. 671 */ 672 static PRErrorCode OverrideOnionSelfSignedError( 673 const nsCOMPtr<nsIX509Cert>& aCert, const nsACString& aHostName, 674 mozilla::pkix::Time aNow, PRErrorCode aCertVerificationError) { 675 nsTArray<uint8_t> certDER; 676 if (NS_FAILED(aCert->GetRawDER(certDER))) { 677 return SEC_ERROR_LIBRARY_FAILURE; 678 } 679 mozilla::pkix::Input certInput; 680 if (certInput.Init(certDER.Elements(), certDER.Length()) != Success) { 681 return SEC_ERROR_BAD_DER; 682 } 683 684 // First, check the hostname. 685 { 686 Input hostnameInput; 687 Result result = hostnameInput.Init( 688 BitwiseCast<const uint8_t*, const char*>(aHostName.BeginReading()), 689 aHostName.Length()); 690 if (result != Success) { 691 return SEC_ERROR_INVALID_ARGS; 692 } 693 result = CheckCertHostname(certInput, hostnameInput); 694 if (result == Result::ERROR_BAD_DER || 695 result == Result::ERROR_BAD_CERT_DOMAIN) { 696 aCertVerificationError = SSL_ERROR_BAD_CERT_DOMAIN; 697 } else if (IsFatalError(result)) { 698 // This should be then mapped to a fatal error by 699 // CategorizeCertificateError. 700 return MapResultToPRErrorCode(result); 701 } 702 } 703 704 // Then, check if the certificate has expired. 705 { 706 mozilla::pkix::BackCert backCert( 707 certInput, mozilla::pkix::EndEntityOrCA::MustBeEndEntity, nullptr); 708 Result rv = backCert.Init(); 709 if (rv != Success) { 710 PR_SetError(MapResultToPRErrorCode(rv), 0); 711 return SECFailure; 712 } 713 mozilla::pkix::Time notBefore(mozilla::pkix::Time::uninitialized); 714 mozilla::pkix::Time notAfter(mozilla::pkix::Time::uninitialized); 715 // If the validity can't be parsed, ParseValidity will return 716 // Result::ERROR_INVALID_DER_TIME. 717 rv = mozilla::pkix::ParseValidity(backCert.GetValidity(), ¬Before, 718 ¬After); 719 if (rv != Success) { 720 return MapResultToPRErrorCode(rv); 721 } 722 // If `now` is outside of the certificate's validity period, 723 // CheckValidity will return Result::ERROR_NOT_YET_VALID_CERTIFICATE or 724 // Result::ERROR_EXPIRED_CERTIFICATE, as appropriate, and Success 725 // otherwise. 726 rv = mozilla::pkix::CheckValidity(aNow, notBefore, notAfter); 727 if (rv != Success) { 728 return MapResultToPRErrorCode(rv); 729 } 730 } 731 732 // If we arrive here, the cert is okay, just self-signed, so return the 733 // original error. 734 return aCertVerificationError; 735 } 736 737 PRErrorCode AuthCertificateParseResults( 738 uint64_t aPtrForLog, const nsACString& aHostName, int32_t aPort, 739 const OriginAttributes& aOriginAttributes, 740 const nsCOMPtr<nsIX509Cert>& aCert, mozilla::pkix::Time aTime, 741 PRErrorCode aCertVerificationError, 742 /* out */ 743 nsITransportSecurityInfo::OverridableErrorCategory& 744 aOverridableErrorCategory) { 745 uint32_t probeValue = MapCertErrorToProbeValue(aCertVerificationError); 746 glean::ssl::cert_verification_errors.AccumulateSingleSample(probeValue); 747 748 if (aCertVerificationError == 749 mozilla::pkix::MOZILLA_PKIX_ERROR_ONION_WITH_SELF_SIGNED_CERT) { 750 aCertVerificationError = OverrideOnionSelfSignedError( 751 aCert, aHostName, aTime, aCertVerificationError); 752 } 753 754 Maybe<nsITransportSecurityInfo::OverridableErrorCategory> 755 maybeOverridableErrorCategory = 756 CategorizeCertificateError(aCertVerificationError); 757 // If this isn't an overridable error, return it now. This will stop the 758 // connection and report the given error. 759 if (!maybeOverridableErrorCategory.isSome()) { 760 return aCertVerificationError; 761 } 762 aOverridableErrorCategory = *maybeOverridableErrorCategory; 763 764 bool overrideAllowed = false; 765 nsresult rv = OverrideAllowedForHost(aPtrForLog, aHostName, aOriginAttributes, 766 overrideAllowed); 767 if (NS_FAILED(rv)) { 768 return aCertVerificationError; 769 } 770 771 if (!overrideAllowed) { 772 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 773 ("[0x%" PRIx64 "] HSTS or pinned host - no overrides allowed", 774 aPtrForLog)); 775 return aCertVerificationError; 776 } 777 778 nsCOMPtr<nsICertOverrideService> overrideService = 779 do_GetService(NS_CERTOVERRIDE_CONTRACTID); 780 if (!overrideService) { 781 return aCertVerificationError; 782 } 783 bool haveOverride; 784 bool isTemporaryOverride; 785 rv = overrideService->HasMatchingOverride(aHostName, aPort, aOriginAttributes, 786 aCert, &isTemporaryOverride, 787 &haveOverride); 788 if (NS_FAILED(rv)) { 789 return aCertVerificationError; 790 } 791 (void)isTemporaryOverride; 792 if (haveOverride) { 793 uint32_t probeValue = 794 MapOverridableErrorToProbeValue(aCertVerificationError); 795 glean::ssl::cert_error_overrides.AccumulateSingleSample(probeValue); 796 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 797 ("[0x%" PRIx64 "] certificate error overridden", aPtrForLog)); 798 return 0; 799 } 800 801 return aCertVerificationError; 802 } 803 804 static nsTArray<nsTArray<uint8_t>> CreateCertBytesArray( 805 const UniqueSECItemArray& aCertChain) { 806 nsTArray<nsTArray<uint8_t>> certsBytes; 807 for (size_t i = 0; i < aCertChain->len; i++) { 808 nsTArray<uint8_t> certBytes; 809 certBytes.AppendElements(aCertChain->items[i].data, 810 aCertChain->items[i].len); 811 certsBytes.AppendElement(std::move(certBytes)); 812 } 813 return certsBytes; 814 } 815 816 /*static*/ 817 SECStatus SSLServerCertVerificationJob::Dispatch( 818 uint64_t addrForLogging, void* aPinArg, 819 nsTArray<nsTArray<uint8_t>>&& peerCertChain, const nsACString& aHostName, 820 int32_t aPort, const OriginAttributes& aOriginAttributes, 821 Maybe<nsTArray<uint8_t>>& stapledOCSPResponse, 822 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, 823 Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, Time time, 824 uint32_t certVerifierFlags, 825 BaseSSLServerCertVerificationResult* aResultTask) { 826 // Runs on the socket transport thread 827 if (!aResultTask || peerCertChain.IsEmpty()) { 828 MOZ_ASSERT_UNREACHABLE( 829 "must have result task and non-empty peer cert chain"); 830 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 831 return SECFailure; 832 } 833 834 if (!gCertVerificationThreadPool) { 835 PR_SetError(PR_INVALID_STATE_ERROR, 0); 836 return SECFailure; 837 } 838 839 RefPtr<SSLServerCertVerificationJob> job(new SSLServerCertVerificationJob( 840 addrForLogging, aPinArg, std::move(peerCertChain), aHostName, aPort, 841 aOriginAttributes, stapledOCSPResponse, sctsFromTLSExtension, dcInfo, 842 providerFlags, time, certVerifierFlags, aResultTask)); 843 844 nsresult nrv = gCertVerificationThreadPool->Dispatch(job, NS_DISPATCH_NORMAL); 845 if (NS_FAILED(nrv)) { 846 // We can't call SetCertVerificationResult here to change 847 // mCertVerificationState because SetCertVerificationResult will call 848 // libssl functions that acquire SSL locks that are already being held at 849 // this point. However, we can set an error with PR_SetError and return 850 // SECFailure, and the correct thing will happen (the error will be 851 // propagated and this connection will be terminated). 852 PRErrorCode error = nrv == NS_ERROR_OUT_OF_MEMORY ? PR_OUT_OF_MEMORY_ERROR 853 : PR_INVALID_STATE_ERROR; 854 PR_SetError(error, 0); 855 return SECFailure; 856 } 857 858 PR_SetError(PR_WOULD_BLOCK_ERROR, 0); 859 return SECWouldBlock; 860 } 861 862 void SSLServerCertVerificationJob::FixOnionAlias() { 863 if (StringEndsWith(mHostName, ".tor.onion"_ns)) { 864 nsCOMPtr<IOnionAliasService> oas = do_GetService(ONIONALIAS_CID); 865 oas->GetOnionAlias(mHostName, mHostName); 866 } 867 } 868 869 NS_IMETHODIMP 870 SSLServerCertVerificationJob::Run() { 871 // Runs on a cert verification thread and only on parent process. 872 MOZ_ASSERT(XRE_IsParentProcess()); 873 874 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 875 ("[%" PRIx64 "] SSLServerCertVerificationJob::Run", mAddrForLogging)); 876 877 RefPtr<SharedCertVerifier> certVerifier(GetDefaultCertVerifier()); 878 if (!certVerifier) { 879 // We can't release this off the STS thread because some parts of it 880 // are not threadsafe. Just leak mResultTask. 881 mResultTask.forget().leak(); 882 return NS_ERROR_FAILURE; 883 } 884 885 TimeStamp jobStartTime = TimeStamp::Now(); 886 EVStatus evStatus; 887 CertificateTransparencyInfo certificateTransparencyInfo; 888 bool isCertChainRootBuiltInRoot = false; 889 bool madeOCSPRequests = false; 890 nsTArray<nsTArray<uint8_t>> builtChainBytesArray; 891 nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone()); 892 Result result = AuthCertificate( 893 *certVerifier, mPinArg, certBytes, mPeerCertChain, mHostName, 894 mOriginAttributes, mStapledOCSPResponse, mSCTsFromTLSExtension, mDCInfo, 895 mProviderFlags, mTime, mCertVerifierFlags, builtChainBytesArray, evStatus, 896 certificateTransparencyInfo, isCertChainRootBuiltInRoot, 897 madeOCSPRequests); 898 899 TimeDuration elapsed = TimeStamp::Now() - jobStartTime; 900 if (result == Success) { 901 mozilla::glean::cert_verification_time::success.AccumulateRawDuration( 902 elapsed); 903 glean::ssl::cert_error_overrides.AccumulateSingleSample(1); 904 905 nsresult rv = mResultTask->Dispatch( 906 std::move(builtChainBytesArray), std::move(mPeerCertChain), 907 TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus( 908 certificateTransparencyInfo), 909 evStatus, true, 0, 910 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET, 911 isCertChainRootBuiltInRoot, mProviderFlags, madeOCSPRequests); 912 if (NS_FAILED(rv)) { 913 // We can't release this off the STS thread because some parts of it 914 // are not threadsafe. Just leak mResultTask. 915 mResultTask.forget().leak(); 916 } 917 return rv; 918 } 919 920 mozilla::glean::cert_verification_time::failure.AccumulateRawDuration( 921 elapsed); 922 923 PRErrorCode error = MapResultToPRErrorCode(result); 924 nsITransportSecurityInfo::OverridableErrorCategory overridableErrorCategory = 925 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET; 926 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes))); 927 PRErrorCode finalError = AuthCertificateParseResults( 928 mAddrForLogging, mHostName, mPort, mOriginAttributes, cert, mTime, error, 929 overridableErrorCategory); 930 931 // NB: finalError may be 0 here, in which the connection will continue. 932 nsresult rv = mResultTask->Dispatch( 933 std::move(builtChainBytesArray), std::move(mPeerCertChain), 934 TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus( 935 certificateTransparencyInfo), 936 EVStatus::NotEV, false, finalError, overridableErrorCategory, 937 // If the certificate verifier returned Result::ERROR_BAD_CERT_DOMAIN, 938 // a chain was built, so isCertChainRootBuiltInRoot is valid and 939 // potentially useful. Otherwise, assume no chain was built. 940 result == Result::ERROR_BAD_CERT_DOMAIN ? isCertChainRootBuiltInRoot 941 : false, 942 mProviderFlags, madeOCSPRequests); 943 if (NS_FAILED(rv)) { 944 // We can't release this off the STS thread because some parts of it 945 // are not threadsafe. Just leak mResultTask. 946 mResultTask.forget().leak(); 947 } 948 return rv; 949 } 950 951 // Takes information needed for cert verification, does some consistency 952 // checks and calls SSLServerCertVerificationJob::Dispatch. 953 SECStatus AuthCertificateHookInternal( 954 CommonSocketControl* socketControl, const void* aPtrForLogging, 955 const nsACString& hostName, nsTArray<nsTArray<uint8_t>>&& peerCertChain, 956 Maybe<nsTArray<uint8_t>>& stapledOCSPResponse, 957 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, 958 Maybe<DelegatedCredentialInfo>& dcInfo, uint32_t providerFlags, 959 uint32_t certVerifierFlags) { 960 // Runs on the socket transport thread 961 962 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 963 ("[%p] starting AuthCertificateHookInternal\n", aPtrForLogging)); 964 965 if (!socketControl || peerCertChain.IsEmpty()) { 966 PR_SetError(PR_INVALID_STATE_ERROR, 0); 967 return SECFailure; 968 } 969 970 bool onSTSThread; 971 nsresult nrv; 972 nsCOMPtr<nsIEventTarget> sts = 973 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv); 974 if (NS_SUCCEEDED(nrv)) { 975 nrv = sts->IsOnCurrentThread(&onSTSThread); 976 } 977 978 if (NS_FAILED(nrv)) { 979 NS_ERROR("Could not get STS service or IsOnCurrentThread failed"); 980 PR_SetError(PR_UNKNOWN_ERROR, 0); 981 return SECFailure; 982 } 983 984 MOZ_ASSERT(onSTSThread); 985 986 if (!onSTSThread) { 987 PR_SetError(PR_INVALID_STATE_ERROR, 0); 988 return SECFailure; 989 } 990 991 uint64_t addr = reinterpret_cast<uintptr_t>(aPtrForLogging); 992 RefPtr<SSLServerCertVerificationResult> resultTask = 993 new SSLServerCertVerificationResult(socketControl); 994 995 if (XRE_IsSocketProcess()) { 996 return RemoteProcessCertVerification( 997 std::move(peerCertChain), hostName, socketControl->GetPort(), 998 socketControl->GetOriginAttributes(), stapledOCSPResponse, 999 sctsFromTLSExtension, dcInfo, providerFlags, certVerifierFlags, 1000 resultTask); 1001 } 1002 1003 // We *must* do certificate verification on a background thread because 1004 // we need the socket transport thread to be free for our OCSP requests, 1005 // and we *want* to do certificate verification on a background thread 1006 // because of the performance benefits of doing so. 1007 return SSLServerCertVerificationJob::Dispatch( 1008 addr, socketControl, std::move(peerCertChain), hostName, 1009 socketControl->GetPort(), socketControl->GetOriginAttributes(), 1010 stapledOCSPResponse, sctsFromTLSExtension, dcInfo, providerFlags, Now(), 1011 certVerifierFlags, resultTask); 1012 } 1013 1014 // Extracts whatever information we need out of fd (using SSL_*) and passes it 1015 // to AuthCertificateHookInternal. AuthCertificateHookInternal will call 1016 // SSLServerCertVerificationJob::Dispatch. SSLServerCertVerificationJob 1017 // should never do anything with fd except logging. 1018 SECStatus AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, 1019 PRBool isServer) { 1020 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1021 ("[%p] starting AuthCertificateHook\n", fd)); 1022 1023 // Modern libssl always passes PR_TRUE for checkSig, and we have no means of 1024 // doing verification without checking signatures. 1025 MOZ_ASSERT(checkSig, "AuthCertificateHook: checkSig unexpectedly false"); 1026 1027 // PSM never causes libssl to call this function with PR_TRUE for isServer, 1028 // and many things in PSM assume that we are a client. 1029 MOZ_ASSERT(!isServer, "AuthCertificateHook: isServer unexpectedly true"); 1030 1031 NSSSocketControl* socketInfo = static_cast<NSSSocketControl*>(arg); 1032 1033 UniqueCERTCertificate serverCert(SSL_PeerCertificate(fd)); 1034 1035 if (!checkSig || isServer || !socketInfo || !serverCert) { 1036 PR_SetError(PR_INVALID_STATE_ERROR, 0); 1037 return SECFailure; 1038 } 1039 socketInfo->SetFullHandshake(); 1040 1041 if (BlockServerCertChangeForSpdy(socketInfo, serverCert) != SECSuccess) { 1042 return SECFailure; 1043 } 1044 1045 UniqueSECItemArray peerCertChain; 1046 SECStatus rv = 1047 SSL_PeerCertificateChainDER(fd, TempPtrToSetter(&peerCertChain)); 1048 if (rv != SECSuccess) { 1049 PR_SetError(PR_INVALID_STATE_ERROR, 0); 1050 return SECFailure; 1051 } 1052 MOZ_ASSERT(peerCertChain, 1053 "AuthCertificateHook: peerCertChain unexpectedly null"); 1054 1055 nsTArray<nsTArray<uint8_t>> peerCertsBytes = 1056 CreateCertBytesArray(peerCertChain); 1057 1058 // SSL_PeerStapledOCSPResponses will never return a non-empty response if 1059 // OCSP stapling wasn't enabled because libssl wouldn't have let the server 1060 // return a stapled OCSP response. 1061 // We don't own these pointers. 1062 const SECItemArray* csa = SSL_PeerStapledOCSPResponses(fd); 1063 Maybe<nsTArray<uint8_t>> stapledOCSPResponse; 1064 // we currently only support single stapled responses 1065 if (csa && csa->len == 1) { 1066 stapledOCSPResponse.emplace(); 1067 stapledOCSPResponse->SetCapacity(csa->items[0].len); 1068 stapledOCSPResponse->AppendElements(csa->items[0].data, csa->items[0].len); 1069 } 1070 1071 Maybe<nsTArray<uint8_t>> sctsFromTLSExtension; 1072 const SECItem* sctsFromTLSExtensionSECItem = SSL_PeerSignedCertTimestamps(fd); 1073 if (sctsFromTLSExtensionSECItem) { 1074 sctsFromTLSExtension.emplace(); 1075 sctsFromTLSExtension->SetCapacity(sctsFromTLSExtensionSECItem->len); 1076 sctsFromTLSExtension->AppendElements(sctsFromTLSExtensionSECItem->data, 1077 sctsFromTLSExtensionSECItem->len); 1078 } 1079 1080 uint32_t providerFlags = 0; 1081 socketInfo->GetProviderFlags(&providerFlags); 1082 1083 uint32_t certVerifierFlags = 0; 1084 if (!StaticPrefs::security_ssl_enable_ocsp_stapling() || 1085 !StaticPrefs::security_ssl_enable_ocsp_must_staple()) { 1086 certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST; 1087 } 1088 1089 // Get DC information 1090 Maybe<DelegatedCredentialInfo> dcInfo; 1091 SSLPreliminaryChannelInfo channelPreInfo; 1092 rv = SSL_GetPreliminaryChannelInfo(fd, &channelPreInfo, 1093 sizeof(channelPreInfo)); 1094 if (rv != SECSuccess) { 1095 PR_SetError(PR_INVALID_STATE_ERROR, 0); 1096 return SECFailure; 1097 } 1098 if (channelPreInfo.peerDelegCred) { 1099 dcInfo.emplace(DelegatedCredentialInfo(channelPreInfo.signatureScheme, 1100 channelPreInfo.authKeyBits)); 1101 } 1102 1103 // If we configured an ECHConfig and NSS returned the public name 1104 // for verification, ECH was rejected. Proceed, verifying to the 1105 // public name. The result determines how NSS will fail (i.e. with 1106 // any provided retry_configs if successful). See draft-ietf-tls-esni-08. 1107 nsCString echConfig; 1108 nsresult nsrv = socketInfo->GetEchConfig(echConfig); 1109 bool verifyToEchPublicName = 1110 NS_SUCCEEDED(nsrv) && echConfig.Length() && channelPreInfo.echPublicName; 1111 1112 const nsCString echPublicName(channelPreInfo.echPublicName); 1113 const nsACString& hostname = 1114 verifyToEchPublicName ? echPublicName : socketInfo->GetHostName(); 1115 socketInfo->SetCertVerificationWaiting(); 1116 rv = AuthCertificateHookInternal(socketInfo, static_cast<const void*>(fd), 1117 hostname, std::move(peerCertsBytes), 1118 stapledOCSPResponse, sctsFromTLSExtension, 1119 dcInfo, providerFlags, certVerifierFlags); 1120 return rv; 1121 } 1122 1123 // Takes information needed for cert verification, does some consistency 1124 // checks and calls SSLServerCertVerificationJob::Dispatch. 1125 // This function is used for Quic. 1126 SECStatus AuthCertificateHookWithInfo( 1127 CommonSocketControl* socketControl, const nsACString& aHostName, 1128 const void* aPtrForLogging, nsTArray<nsTArray<uint8_t>>&& peerCertChain, 1129 Maybe<nsTArray<nsTArray<uint8_t>>>& stapledOCSPResponses, 1130 Maybe<nsTArray<uint8_t>>& sctsFromTLSExtension, uint32_t providerFlags) { 1131 if (peerCertChain.IsEmpty()) { 1132 PR_SetError(PR_INVALID_STATE_ERROR, 0); 1133 return SECFailure; 1134 } 1135 1136 // we currently only support single stapled responses 1137 Maybe<nsTArray<uint8_t>> stapledOCSPResponse; 1138 if (stapledOCSPResponses && (stapledOCSPResponses->Length() == 1)) { 1139 stapledOCSPResponse.emplace(stapledOCSPResponses->ElementAt(0).Clone()); 1140 } 1141 1142 uint32_t certVerifierFlags = 0; 1143 if (!StaticPrefs::security_ssl_enable_ocsp_stapling() || 1144 !StaticPrefs::security_ssl_enable_ocsp_must_staple()) { 1145 certVerifierFlags |= CertVerifier::FLAG_TLS_IGNORE_STATUS_REQUEST; 1146 } 1147 1148 // Need to update Quic stack to reflect the PreliminaryInfo fields 1149 // for Delegated Credentials. 1150 Maybe<DelegatedCredentialInfo> dcInfo; 1151 1152 return AuthCertificateHookInternal(socketControl, aPtrForLogging, aHostName, 1153 std::move(peerCertChain), 1154 stapledOCSPResponse, sctsFromTLSExtension, 1155 dcInfo, providerFlags, certVerifierFlags); 1156 } 1157 1158 NS_IMPL_ISUPPORTS_INHERITED0(SSLServerCertVerificationResult, Runnable) 1159 1160 SSLServerCertVerificationResult::SSLServerCertVerificationResult( 1161 CommonSocketControl* socketControl) 1162 : Runnable("psm::SSLServerCertVerificationResult"), 1163 mSocketControl(socketControl), 1164 mCertificateTransparencyStatus(0), 1165 mEVStatus(EVStatus::NotEV), 1166 mSucceeded(false), 1167 mFinalError(0), 1168 mOverridableErrorCategory( 1169 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET), 1170 mProviderFlags(0) {} 1171 1172 nsresult SSLServerCertVerificationResult::Dispatch( 1173 nsTArray<nsTArray<uint8_t>>&& aBuiltChain, 1174 nsTArray<nsTArray<uint8_t>>&& aPeerCertChain, 1175 uint16_t aCertificateTransparencyStatus, EVStatus aEVStatus, 1176 bool aSucceeded, PRErrorCode aFinalError, 1177 nsITransportSecurityInfo::OverridableErrorCategory 1178 aOverridableErrorCategory, 1179 bool aIsBuiltCertChainRootBuiltInRoot, uint32_t aProviderFlags, 1180 bool aMadeOCSPRequests) { 1181 mBuiltChain = std::move(aBuiltChain); 1182 mPeerCertChain = std::move(aPeerCertChain); 1183 mCertificateTransparencyStatus = aCertificateTransparencyStatus; 1184 mEVStatus = aEVStatus; 1185 mSucceeded = aSucceeded; 1186 mFinalError = aFinalError; 1187 mOverridableErrorCategory = aOverridableErrorCategory; 1188 mIsBuiltCertChainRootBuiltInRoot = aIsBuiltCertChainRootBuiltInRoot; 1189 mProviderFlags = aProviderFlags; 1190 mMadeOCSPRequests = aMadeOCSPRequests; 1191 1192 if (mSucceeded && 1193 (mBuiltChain.IsEmpty() || mFinalError != 0 || 1194 mOverridableErrorCategory != 1195 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET)) { 1196 MOZ_ASSERT_UNREACHABLE( 1197 "if certificate verification succeeded without overridden errors, the " 1198 "built chain shouldn't be empty and any error bits should be unset"); 1199 mSucceeded = false; 1200 mFinalError = SEC_ERROR_LIBRARY_FAILURE; 1201 } 1202 // Note that mSucceeded can be false while mFinalError is 0, in which case 1203 // the connection will proceed. 1204 if (!mSucceeded && mPeerCertChain.IsEmpty()) { 1205 MOZ_ASSERT_UNREACHABLE( 1206 "if certificate verification failed, the peer chain shouldn't be " 1207 "empty"); 1208 mFinalError = SEC_ERROR_LIBRARY_FAILURE; 1209 } 1210 1211 nsresult rv; 1212 nsCOMPtr<nsIEventTarget> stsTarget = 1213 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv); 1214 MOZ_ASSERT(stsTarget, "Failed to get socket transport service event target"); 1215 if (!stsTarget) { 1216 // This has to be released on STS; just leak it 1217 mSocketControl.forget().leak(); 1218 return NS_ERROR_FAILURE; 1219 } 1220 rv = stsTarget->Dispatch(this, NS_DISPATCH_NORMAL); 1221 MOZ_ASSERT(NS_SUCCEEDED(rv), 1222 "Failed to dispatch SSLServerCertVerificationResult"); 1223 return rv; 1224 } 1225 1226 NS_IMETHODIMP 1227 SSLServerCertVerificationResult::Run() { 1228 #ifdef DEBUG 1229 bool onSTSThread = false; 1230 nsresult nrv; 1231 nsCOMPtr<nsIEventTarget> sts = 1232 do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv); 1233 if (NS_SUCCEEDED(nrv)) { 1234 nrv = sts->IsOnCurrentThread(&onSTSThread); 1235 } 1236 1237 MOZ_ASSERT(onSTSThread); 1238 #endif 1239 1240 mSocketControl->SetMadeOCSPRequests(mMadeOCSPRequests); 1241 mSocketControl->SetIsBuiltCertChainRootBuiltInRoot( 1242 mIsBuiltCertChainRootBuiltInRoot); 1243 mSocketControl->SetCertificateTransparencyStatus( 1244 mCertificateTransparencyStatus); 1245 1246 if (mSucceeded) { 1247 MOZ_LOG(gPIPNSSLog, LogLevel::Debug, 1248 ("SSLServerCertVerificationResult::Run setting NEW cert")); 1249 nsTArray<uint8_t> certBytes(mBuiltChain.ElementAt(0).Clone()); 1250 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes))); 1251 mSocketControl->SetServerCert(cert, mEVStatus); 1252 mSocketControl->SetSucceededCertChain(std::move(mBuiltChain)); 1253 } else { 1254 nsTArray<uint8_t> certBytes(mPeerCertChain.ElementAt(0).Clone()); 1255 nsCOMPtr<nsIX509Cert> cert(new nsNSSCertificate(std::move(certBytes))); 1256 mSocketControl->SetServerCert(cert, EVStatus::NotEV); 1257 if (mOverridableErrorCategory != 1258 nsITransportSecurityInfo::OverridableErrorCategory::ERROR_UNSET) { 1259 mSocketControl->SetStatusErrorBits(mOverridableErrorCategory); 1260 } 1261 } 1262 1263 mSocketControl->SetHandshakeCertificates(std::move(mPeerCertChain)); 1264 mSocketControl->SetCertVerificationResult(mFinalError); 1265 // Release this reference to the socket control so that it will be freed on 1266 // the socket thread. 1267 mSocketControl = nullptr; 1268 return NS_OK; 1269 } 1270 1271 } // namespace psm 1272 } // namespace mozilla