// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "net/cert/cert_database.h" #include #include "base/apple/osstatus_logging.h" #include "base/check.h" #include "base/functional/bind.h" #include "base/location.h" #include "base/notreached.h" #include "base/process/process_handle.h" #include "net/base/network_notification_thread_mac.h" namespace net { namespace { // Helper that observes events from the Keychain and forwards them to the // CertDatabase. class Notifier { public: Notifier() { GetNetworkNotificationThreadMac()->PostTask( FROM_HERE, base::BindOnce(&Notifier::Init, base::Unretained(this))); } ~Notifier() = delete; // Much of the Keychain API was marked deprecated as of the macOS 13 SDK. // Removal of its use is tracked in https://crbug.com/1348251 but deprecation // warnings are disabled in the meanwhile. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" private: void Init() { SecKeychainEventMask event_mask = kSecKeychainListChangedMask | kSecTrustSettingsChangedEventMask; SecKeychainAddCallback(&Notifier::KeychainCallback, event_mask, nullptr); } #pragma clang diagnostic pop // SecKeychainCallback function that receives notifications from securityd // and forwards them to the |cert_db_|. static OSStatus KeychainCallback(SecKeychainEvent keychain_event, SecKeychainCallbackInfo* info, void* context); }; // static OSStatus Notifier::KeychainCallback(SecKeychainEvent keychain_event, SecKeychainCallbackInfo* info, void* context) { if (info->version > SEC_KEYCHAIN_SETTINGS_VERS1) { NOTREACHED(); return errSecWrongSecVersion; } if (info->pid == base::GetCurrentProcId()) { // Ignore events generated by the current process, as the assumption is // that they have already been handled. This may miss events that // originated as a result of spawning native dialogs that allow the user // to modify Keychain settings. However, err on the side of missing // events rather than sending too many events. return errSecSuccess; } switch (keychain_event) { case kSecKeychainListChangedEvent: CertDatabase::GetInstance()->NotifyObserversClientCertStoreChanged(); break; case kSecTrustSettingsChangedEvent: CertDatabase::GetInstance()->NotifyObserversTrustStoreChanged(); break; default: break; } return errSecSuccess; } } // namespace void CertDatabase::StartListeningForKeychainEvents() { static base::NoDestructor notifier; } } // namespace net