// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "crypto/cssm_init.h" #include <Security/SecBase.h> #include "base/logging.h" #include "base/mac/scoped_cftyperef.h" #include "base/memory/singleton.h" #include "base/strings/sys_string_conversions.h" // When writing crypto code for Mac OS X, you may find the following // documentation useful: // - Common Security: CDSA and CSSM, Version 2 (with corrigenda) // http://www.opengroup.org/security/cdsa.htm // - Apple Cryptographic Service Provider Functional Specification // - CryptoSample: http://developer.apple.com/SampleCode/CryptoSample/ namespace { void* CSSMMalloc(CSSM_SIZE size, void* alloc_ref) { return malloc(size); } void CSSMFree(void* mem_ptr, void* alloc_ref) { free(mem_ptr); } void* CSSMRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) { return realloc(ptr, size); } void* CSSMCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) { return calloc(num, size); } class CSSMInitSingleton { public: static CSSMInitSingleton* GetInstance() { return Singleton<CSSMInitSingleton, LeakySingletonTraits<CSSMInitSingleton> >::get(); } CSSM_CSP_HANDLE csp_handle() const { return csp_handle_; } CSSM_CL_HANDLE cl_handle() const { return cl_handle_; } CSSM_TP_HANDLE tp_handle() const { return tp_handle_; } private: CSSMInitSingleton() : inited_(false), csp_loaded_(false), cl_loaded_(false), tp_loaded_(false), csp_handle_(CSSM_INVALID_HANDLE), cl_handle_(CSSM_INVALID_HANDLE), tp_handle_(CSSM_INVALID_HANDLE) { static CSSM_VERSION version = {2, 0}; // TODO(wtc): what should our caller GUID be? static const CSSM_GUID test_guid = { 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 } }; CSSM_RETURN crtn; CSSM_PVC_MODE pvc_policy = CSSM_PVC_NONE; crtn = CSSM_Init(&version, CSSM_PRIVILEGE_SCOPE_NONE, &test_guid, CSSM_KEY_HIERARCHY_NONE, &pvc_policy, NULL); if (crtn) { NOTREACHED(); return; } inited_ = true; crtn = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL); if (crtn) { NOTREACHED(); return; } csp_loaded_ = true; crtn = CSSM_ModuleLoad( &gGuidAppleX509CL, CSSM_KEY_HIERARCHY_NONE, NULL, NULL); if (crtn) { NOTREACHED(); return; } cl_loaded_ = true; crtn = CSSM_ModuleLoad( &gGuidAppleX509TP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL); if (crtn) { NOTREACHED(); return; } tp_loaded_ = true; const CSSM_API_MEMORY_FUNCS cssmMemoryFunctions = { CSSMMalloc, CSSMFree, CSSMRealloc, CSSMCalloc, NULL }; crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &cssmMemoryFunctions, 0, CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &csp_handle_); DCHECK_EQ(CSSM_OK, crtn); crtn = CSSM_ModuleAttach(&gGuidAppleX509CL, &version, &cssmMemoryFunctions, 0, CSSM_SERVICE_CL, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &cl_handle_); DCHECK_EQ(CSSM_OK, crtn); crtn = CSSM_ModuleAttach(&gGuidAppleX509TP, &version, &cssmMemoryFunctions, 0, CSSM_SERVICE_TP, 0, CSSM_KEY_HIERARCHY_NONE, NULL, 0, NULL, &tp_handle_); DCHECK_EQ(CSSM_OK, crtn); } ~CSSMInitSingleton() { CSSM_RETURN crtn; if (csp_handle_) { CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_); DCHECK_EQ(CSSM_OK, crtn); } if (cl_handle_) { CSSM_RETURN crtn = CSSM_ModuleDetach(cl_handle_); DCHECK_EQ(CSSM_OK, crtn); } if (tp_handle_) { CSSM_RETURN crtn = CSSM_ModuleDetach(tp_handle_); DCHECK_EQ(CSSM_OK, crtn); } if (csp_loaded_) { crtn = CSSM_ModuleUnload(&gGuidAppleCSP, NULL, NULL); DCHECK_EQ(CSSM_OK, crtn); } if (cl_loaded_) { crtn = CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL); DCHECK_EQ(CSSM_OK, crtn); } if (tp_loaded_) { crtn = CSSM_ModuleUnload(&gGuidAppleX509TP, NULL, NULL); DCHECK_EQ(CSSM_OK, crtn); } if (inited_) { crtn = CSSM_Terminate(); DCHECK_EQ(CSSM_OK, crtn); } } bool inited_; // True if CSSM_Init has been called successfully. bool csp_loaded_; // True if gGuidAppleCSP has been loaded bool cl_loaded_; // True if gGuidAppleX509CL has been loaded. bool tp_loaded_; // True if gGuidAppleX509TP has been loaded. CSSM_CSP_HANDLE csp_handle_; CSSM_CL_HANDLE cl_handle_; CSSM_TP_HANDLE tp_handle_; friend struct DefaultSingletonTraits<CSSMInitSingleton>; }; } // namespace namespace crypto { void EnsureCSSMInit() { CSSMInitSingleton::GetInstance(); } CSSM_CSP_HANDLE GetSharedCSPHandle() { return CSSMInitSingleton::GetInstance()->csp_handle(); } CSSM_CL_HANDLE GetSharedCLHandle() { return CSSMInitSingleton::GetInstance()->cl_handle(); } CSSM_TP_HANDLE GetSharedTPHandle() { return CSSMInitSingleton::GetInstance()->tp_handle(); } void* CSSMMalloc(CSSM_SIZE size) { return ::CSSMMalloc(size, NULL); } void CSSMFree(void* ptr) { ::CSSMFree(ptr, NULL); } void LogCSSMError(const char* fn_name, CSSM_RETURN err) { if (!err) return; base::ScopedCFTypeRef<CFStringRef> cfstr( SecCopyErrorMessageString(err, NULL)); LOG(ERROR) << fn_name << " returned " << err << " (" << base::SysCFStringRefToUTF8(cfstr) << ")"; } ScopedCSSMData::ScopedCSSMData() { memset(&data_, 0, sizeof(data_)); } ScopedCSSMData::~ScopedCSSMData() { if (data_.Data) { CSSMFree(data_.Data); data_.Data = NULL; } } } // namespace crypto