| // 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 <Security/Security.h> |
| |
| #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> notifier; |
| } |
| |
| } // namespace net |