This source file includes following definitions.
- called_shutdown_
- Notifier
- Shutdown
- Init
- KeychainCallback
- SetMessageLoopForKeychainEvents
- CheckUserCert
- AddUserCert
#include "net/cert/cert_database.h"
#include <Security/Security.h>
#include "base/logging.h"
#include "base/mac/mac_logging.h"
#include "base/message_loop/message_loop.h"
#include "base/observer_list_threadsafe.h"
#include "base/process/process_handle.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "crypto/mac_security_services_lock.h"
#include "net/base/net_errors.h"
#include "net/cert/x509_certificate.h"
namespace net {
class CertDatabase::Notifier {
public:
Notifier(CertDatabase* cert_db, base::MessageLoop* message_loop)
: cert_db_(cert_db),
registered_(false),
called_shutdown_(false) {
DCHECK(base::MessageLoopForUI::IsCurrent());
task_runner_ = message_loop->message_loop_proxy();
task_runner_->PostTask(FROM_HERE,
base::Bind(&Notifier::Init,
base::Unretained(this)));
}
~Notifier() {
DCHECK(called_shutdown_);
if (registered_ && task_runner_->RunsTasksOnCurrentThread())
SecKeychainRemoveCallback(&Notifier::KeychainCallback);
}
void Shutdown() {
called_shutdown_ = true;
if (!task_runner_->DeleteSoon(FROM_HERE, this)) {
delete this;
}
}
private:
void Init() {
SecKeychainEventMask event_mask =
kSecKeychainListChangedMask | kSecTrustSettingsChangedEventMask;
OSStatus status = SecKeychainAddCallback(&Notifier::KeychainCallback,
event_mask, this);
if (status == noErr)
registered_ = true;
}
static OSStatus KeychainCallback(SecKeychainEvent keychain_event,
SecKeychainCallbackInfo* info,
void* context);
CertDatabase* const cert_db_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
bool registered_;
bool called_shutdown_;
};
OSStatus CertDatabase::Notifier::KeychainCallback(
SecKeychainEvent keychain_event,
SecKeychainCallbackInfo* info,
void* context) {
Notifier* that = reinterpret_cast<Notifier*>(context);
if (info->version > SEC_KEYCHAIN_SETTINGS_VERS1) {
NOTREACHED();
return errSecWrongSecVersion;
}
if (info->pid == base::GetCurrentProcId()) {
return errSecSuccess;
}
switch (keychain_event) {
case kSecKeychainListChangedEvent:
case kSecTrustSettingsChangedEvent:
that->cert_db_->NotifyObserversOfCACertChanged(NULL);
break;
}
return errSecSuccess;
}
void CertDatabase::SetMessageLoopForKeychainEvents() {
if (notifier_.get())
notifier_.release()->Shutdown();
notifier_.reset(new Notifier(this, base::MessageLoopForUI::current()));
}
CertDatabase::CertDatabase()
: observer_list_(new ObserverListThreadSafe<Observer>) {
}
CertDatabase::~CertDatabase() {
if (notifier_.get())
notifier_.release()->Shutdown();
}
int CertDatabase::CheckUserCert(X509Certificate* cert) {
if (!cert)
return ERR_CERT_INVALID;
if (cert->HasExpired())
return ERR_CERT_DATE_INVALID;
SecIdentityRef identity = NULL;
OSStatus err = SecIdentityCreateWithCertificate(NULL, cert->os_cert_handle(),
&identity);
if (err == errSecItemNotFound)
return ERR_NO_PRIVATE_KEY_FOR_CERT;
if (err != noErr || !identity) {
return ERR_CERT_INVALID;
}
CFRelease(identity);
return OK;
}
int CertDatabase::AddUserCert(X509Certificate* cert) {
OSStatus err;
{
base::AutoLock locked(crypto::GetMacSecurityServicesLock());
err = SecCertificateAddToKeychain(cert->os_cert_handle(), NULL);
}
switch (err) {
case noErr:
CertDatabase::NotifyObserversOfCertAdded(cert);
case errSecDuplicateItem:
return OK;
default:
OSSTATUS_LOG(ERROR, err) << "CertDatabase failed to add cert to keychain";
return ERR_ADD_USER_CERT_FAILED;
}
}
}