Repository navigation
WIP: Firestore: Use Apple's SecTrust to validate gRPC TLS certificates instead of hardcoded certs - #16946
WIP: Firestore: Use Apple's SecTrust to validate gRPC TLS certificates instead of hardcoded certs#16946dconeybe wants to merge 31 commits into
Conversation
Remove the unreferenced Hexa-era GrpcConnection::UseTestCertificate() hook and replace HostConfig/HostConfigMap with a minimal thread-safe InsecureHosts set before introducing platform TLS credential providers.
Extract CreateDefaultTlsCredentials() into grpc_tls_credentials_provider.{h,_embedded.cc} so Apple and non-Apple platforms can supply link-time TLS credential implementations without #if __APPLE__ conditionals in grpc_connection.cc.
Delegate Apple gRPC server TLS certificate and hostname verification to Security.framework (SecPolicyCreateSSL and SecTrustEvaluateWithError) via grpc::experimental::ExternalCertificateVerifier instead of BoringSSL's static embedded root store. Link Security.framework and exclude embedded root certificate sources on Apple builds across CMake, CocoaPods, and SwiftPM.
Add comprehensive Apple Security.framework unit tests and end-to-end localhost gRPC TLS loopback tests covering hostname extraction, fail-closed PEM parsing, SecTrust chain verification, and TlsCredentials handshakes using in-memory P-256 X.509v3 test certificates.
…n changelog Document the migration to Security.framework SecTrust gRPC TLS server verification on Apple platforms in Firestore CHANGELOG.md.
Document each architectural, policy, execution-mode, testing, and changelog question, the options considered, and the selected design in Firestore/DECISIONS.md.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
note to self: the AI conversation ID is: `0516c0fc-eba6-45aa-8b77-cffc6175ed08`
…hain private helpers
…d remove handwritten helpers
…ain and KeepBoth check_call_host
…eTlsCertificateChain
…CreateSSL and format
…prevent log injection
…ntrolCharacterSet
This PR migrates Firestore's gRPC TLS server certificate and hostname verification on Apple platforms from a static embedded root certificate bundle to Apple's
Security.framework(SecTrust), enabling automatic OS root store updates, enterprise MDM trust, and pushed Over-The-Air (trustd) CA revocations while reducing SDK binary size. This change applies only to Apple platforms (iOS, macOS, Mac Catalyst, tvOS, and visionOS) and does not change anything for Windows and Linux targets.Background & Motivation
Previously, Firestore validated gRPC TLS server connections using a hardcoded PEM root certificate bundle (
grpc_root_certificates_generated.cc) compiled directly into the SDK binary. Because an embedded trust store remains static until an app ships a new SDK version, responding to a CA compromise required regenerating the embedded bundle and publishing an emergency SDK update—as done in the quick fix #16930 to mitigate the October 2026 compromised eMudhra certificate.This PR is the long-term follow-up to #16930. Instead of relying on hardcoded certificates, Firestore on Apple platforms now delegates TLS certificate chain and hostname validation to Apple's native
Security.framework(SecPolicyCreateSSLandSecTrustEvaluateWithError). This aligns Firestore's gRPC transport withURLSessionand the rest offirebase-ios-sdk, automatically inheriting OS root store updates, enterprise/MDM root certificates, Certificate Transparency enforcement, and Apple's background Over-The-Air (trustd) pushed certificate revocations without requiring an SDK release, while also excluding the ~3.3 MB generated certificate source file from Apple builds.Platform Scope: This fix only applies to Apple platforms (e.g., iOS, macOS, Mac Catalyst, tvOS, and visionOS). It does not change anything for Windows and Linux targets, which continue to validate TLS connections using the embedded root certificate bundle.
Highlights
Security.framework(SecTrust) TLS Verification: AddedAppleSecTrustCertificateVerifier(grpc::experimental::ExternalCertificateVerifier) andCreateAppleTlsCredentialsingrpc_tls_credentials_provider_apple.{h,mm}to configuregrpc::experimental::TlsCredentialswithset_verify_server_certs(false)(bypassing BoringSSL's staticX509_STOREwhile keeping its cryptographic TLS handshake) and evaluate the peer certificate chain and target hostname viaSecPolicyCreateSSLandSecTrustEvaluateWithError.GrpcConnection::CreateChannelinto a link-timeCreateDefaultTlsCredentials()factory (grpc_tls_credentials_provider.h), backed bygrpc_tls_credentials_provider_apple.mmon Apple platforms andgrpc_tls_credentials_provider_embedded.cc(LoadGrpcRootCertificate()) on Windows and Linux. Removed the unreferencedGrpcConnection::UseTestCertificate()andHostConfigMapmachinery fromgrpc_connection.{h,cc}in favor of a minimal thread-safeInsecureHostsset and optionalCFArrayRef anchor_certsparameters on the internal Apple helpers.Security.frameworkand excludedgrpc_root_certificates_generated.cc,grpc_root_certificate_finder_generated.cc, andgrpc_tls_credentials_provider_embedded.ccon Apple builds across CocoaPods (FirebaseFirestoreInternal.podspec), Swift Package Manager (Package.swift), and CMake (core/CMakeLists.txt).NSURLComponentsand POSIXinet_pton, parsed PEM chains fail-closed usingNSScannerwith strict RFC 7468 ASCII whitespace andNSData(options:0), snapshotted custom trust anchors immutably viaCFArrayCreateCopy, usedutil::MakeStringfor null-safeNSStringconversions, and escaped rejected target names withabsl::CHexEscapeto prevent log injection.grpc::ServerTLS loopback tests ingrpc_tls_credentials_provider_apple_test.mmusing dynamically generated 3-tier P-256 X.509v3 certificate chains to cover DNS/IPv4/IPv6 SAN matching,SslTargetNameOverride, malformed target and PEM rejection, expired/not-yet-valid certificates, untrusted roots, and missing intermediates.Alternatives & Design Decisions
SecPolicyCreateSSLPolicy vs. Explicit Revocation/Offline Flags: PassingSecPolicyCreateSSL(/*server=*/true, cf_host)directly toSecTrustCreateWithCertificates(withoutkSecRevocationNetworkAccessDisabledorSecTrustSetNetworkFetchAllowed(trust, false)) matchesURLSessionand Apple'sSecurity.frameworkguidance. It enforces Apple'sValidOver-The-Air (trustd) revocation database, system/MDM trust settings, and Certificate Transparency, while preservingtrustd's ability to fetch missing intermediate CA certificates via Authority Information Access (AIA) if a customFIRFirestoreSettings.hostendpoint serves an incomplete chain.TlsCredentialsOptions::set_check_call_host(false)setter or maintaining handwritten URI/IPv6 character-loop parsers, this PR keeps gRPC's defaultcheck_call_host(true)(ClientAuthFilter->SslCheckCallHost) active alongside handshake-timeSecPolicyCreateSSL(true, cf_host)and delegates authority parsing inExtractTlsHostNameto Foundation'sNSURLComponentsand POSIXinet_pton(AF_INET6, ...). Handshake-timeSecPolicyCreateSSLenforces Apple's RFC 9525 / HT210176 SAN and wildcard rules, while per-RPCcheck_call_host(true)verifies the HTTP/2:authorityheader before attaching Firebase Auth and App Check bearer tokens.PEM_read_bio_X509or Handwritten Parsers:CreateCertificateChainFromPemuses Foundation'sNSScanner, strict RFC 7468 ASCII whitespace (" \t\r\n"), and[[NSData alloc] initWithBase64EncodedString:options:0]rather than custom Base64 loops or BoringSSL'sPEM_read_bio_X509. Unlike aPEM_read_bio_X509loop—which silently skips non-CERTIFICATEPEM blocks, ignores pre-header text, and returnsPEM_R_NO_START_LINEon both clean EOF and a trailing block missing its-----BEGINline (risking silent chain truncation)—theNSScanner+ strictNSDataapproach fails closed on extraneous text, unclosed/corrupted trailing blocks, and non-ASCII whitespace, uses ARC-managed memory, and avoids exposing directBoringSSL-GRPCheader dependencies across CMake, CocoaPods, and SwiftPM.CreateAppleTlsCredentialsallocates a freshAppleSecTrustCertificateVerifierinstance per channel credentials object instead of sharing a singleton verifier. Because gRPC'sTlsCredentials::cmp_implcompares credentials by verifier pointer identity, sharing a singleton verifier causedGlobalSubchannelPoolto pool subchannels across independentGrpcConnectionchannels—preventingGrpcConnection::RegisterConnectivityMonitor'sgrpc_channel_.reset()from immediately dropping dead TCP sockets during Wi-Fi/cellular handovers when an in-flight call or secondaryFirestoreinstance still held a reference.Changelog
# Unreleased[changed]entry documenting the migration toSecurity.framework(SecTrust) TLS server certificate verification on Apple platforms.grpc_root_certificate_finder_generated.cc,grpc_root_certificates_generated.cc, andgrpc_tls_credentials_provider_embedded.ccfrom Apple pod builds.Securityframework on iOS, macOS, and tvOS.grpc_root_certificate_finder_generated.cc,grpc_root_certificates_generated.cc, andgrpc_tls_credentials_provider_embedded.ccfrom theFirebaseFirestoreInternalWrappertarget.Securityframework in Firestore SwiftPM targets.grpc_tls_credentials_provider_apple.*, excluded embedded root certificate sources, and linked-framework SecuritywhenAPPLEis enabled.grpc_tls_credentials_provider_apple_test.mmto the Firestore unit test targets in Xcode.GrpcConnection::UseTestCertificatedeclaration and unused header includes.LoadGrpcRootCertificate()andCreateSslCredentialscalls inGrpcConnection::CreateChannelwithCreateDefaultTlsCredentials().GrpcConnection::UseTestCertificate,HostConfig, andHostConfigMap, replacing them with a thread-safeInsecureHostsset forGrpcConnection::UseInsecureChannel.CreateDefaultTlsCredentials()factory.CreateDefaultTlsCredentials()backed byLoadGrpcRootCertificate()andgrpc::SslCredentialsfor Windows and Linux targets.VerifyAppleTlsCertificateChainandCreateAppleTlsCredentialswith optional customCFArrayRef anchor_certssupport for deterministic testing.CreateDefaultTlsCredentials(),CreateAppleTlsCredentials,VerifyAppleTlsCertificateChain,AppleSecTrustCertificateVerifier,ExtractTlsHostName, andCreateCertificateChainFromPemusingSecurity.frameworkandFoundation.*.mm) test sources tofirestore_remote_teston Apple builds.SecTrustchain evaluation, and end-to-end gRPC TLS handshakes.