| // Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // This is the Chaps client. Essentially it forwards all PKCS #11 calls to the |
| // Chaps Daemon (chapsd) via D-Bus. |
| |
| #include <string> |
| #include <vector> |
| |
| #include <base/basictypes.h> |
| #include <base/logging.h> |
| #include <base/synchronization/waitable_event.h> |
| |
| #include "chaps/chaps.h" |
| #include "chaps/chaps_proxy.h" |
| #include "chaps/chaps_utility.h" |
| #include "pkcs11/cryptoki.h" |
| |
| using base::WaitableEvent; |
| using std::string; |
| using std::vector; |
| |
| static const CK_BYTE kChapsLibraryVersionMajor = 0; |
| static const CK_BYTE kChapsLibraryVersionMinor = 1; |
| |
| // The global proxy instance. This is valid only when g_is_initialized is true. |
| static scoped_ptr<chaps::ChapsInterface> g_proxy; |
| |
| // Set to true when using a mock proxy. |
| static bool g_is_using_mock = false; |
| |
| // Set to true when C_Initialize has been called successfully. |
| // When not using a mock proxy this is synonymous with (g_proxy != NULL). |
| static bool g_is_initialized = false; |
| |
| // This event is not signaled until C_Finalize is called and then becomes |
| // signaled. |
| static scoped_ptr<WaitableEvent> g_finalize_event; |
| |
| // Tear down helper. |
| static void TearDown() { |
| if (g_is_initialized && !g_is_using_mock) |
| g_proxy.reset(); |
| g_is_initialized = false; |
| } |
| |
| namespace chaps { |
| |
| // Helpers to support a mock proxy (useful in testing). |
| void EnableMockProxy(ChapsInterface* proxy, bool is_initialized) { |
| g_proxy.reset(proxy); |
| g_is_using_mock = true; |
| g_is_initialized = is_initialized; |
| } |
| |
| void DisableMockProxy() { |
| // We want to release, not reset b/c we don't own the mock proxy. |
| ChapsInterface* ignore = g_proxy.release(); |
| (void)ignore; |
| g_is_using_mock = false; |
| g_is_initialized = false; |
| } |
| |
| } // namespace chaps |
| |
| // The following functions are PKCS #11 entry points. They are intentionally |
| // in the root namespace and are declared 'extern "C"' in pkcs11.h. |
| |
| // PKCS #11 v2.20 section 11.4 page 102. |
| // Connects to the D-Bus service. |
| CK_RV C_Initialize(CK_VOID_PTR pInitArgs) { |
| LOG_CK_RV_AND_RETURN_IF(g_is_initialized, CKR_CRYPTOKI_ALREADY_INITIALIZED); |
| // Validate args (if any). |
| if (pInitArgs) { |
| CK_C_INITIALIZE_ARGS_PTR args = |
| reinterpret_cast<CK_C_INITIALIZE_ARGS_PTR>(pInitArgs); |
| LOG_CK_RV_AND_RETURN_IF(args->pReserved, CKR_ARGUMENTS_BAD); |
| // If one of the following is NULL, they all must be NULL. |
| if ((!args->CreateMutex || !args->DestroyMutex || |
| !args->LockMutex || !args->UnlockMutex) && |
| (args->CreateMutex || args->DestroyMutex || |
| args->LockMutex || args->UnlockMutex)) { |
| LOG_CK_RV_AND_RETURN(CKR_ARGUMENTS_BAD); |
| } |
| // We require OS locking. |
| if (((args->flags & CKF_OS_LOCKING_OK) == 0) && args->CreateMutex) { |
| LOG_CK_RV_AND_RETURN(CKR_CANT_LOCK); |
| } |
| } |
| // If we're not using a mock proxy instance we need to create one. |
| if (!g_is_using_mock) |
| g_proxy.reset(new chaps::ChapsProxyImpl()); |
| CHECK(g_proxy.get()); |
| |
| g_finalize_event.reset(new WaitableEvent(true, false)); |
| CHECK(g_finalize_event.get()); |
| |
| g_is_initialized = true; |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.4 page 104. |
| // Closes the D-Bus service connection. |
| CK_RV C_Finalize(CK_VOID_PTR pReserved) { |
| LOG_CK_RV_AND_RETURN_IF(pReserved, CKR_ARGUMENTS_BAD); |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| if (g_finalize_event.get()) |
| g_finalize_event->Signal(); |
| TearDown(); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.4 page 105. |
| // Provide library info locally. |
| // TODO(dkrahn): i18n of strings - crosbug.com/20637 |
| CK_RV C_GetInfo(CK_INFO_PTR pInfo) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pInfo, CKR_ARGUMENTS_BAD); |
| pInfo->cryptokiVersion.major = CRYPTOKI_VERSION_MAJOR; |
| pInfo->cryptokiVersion.minor = CRYPTOKI_VERSION_MINOR; |
| chaps::CopyToCharBuffer("Chromium OS", pInfo->manufacturerID, |
| arraysize(pInfo->manufacturerID)); |
| pInfo->flags = 0; |
| chaps::CopyToCharBuffer("Chaps Client Library", pInfo->libraryDescription, |
| arraysize(pInfo->libraryDescription)); |
| pInfo->libraryVersion.major = kChapsLibraryVersionMajor; |
| pInfo->libraryVersion.minor = kChapsLibraryVersionMinor; |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 106. |
| CK_RV C_GetSlotList(CK_BBOOL tokenPresent, |
| CK_SLOT_ID_PTR pSlotList, |
| CK_ULONG_PTR pulCount) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pulCount, CKR_ARGUMENTS_BAD); |
| vector<uint32_t> slot_list; |
| CK_RV result = g_proxy->GetSlotList((tokenPresent != CK_FALSE), &slot_list); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| size_t max_copy = static_cast<size_t>(*pulCount); |
| *pulCount = static_cast<CK_ULONG>(slot_list.size()); |
| if (!pSlotList) |
| return CKR_OK; |
| LOG_CK_RV_AND_RETURN_IF(slot_list.size() > max_copy, CKR_BUFFER_TOO_SMALL); |
| for (size_t i = 0; i < slot_list.size(); ++i) { |
| pSlotList[i] = slot_list[i]; |
| } |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 108. |
| CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pInfo, CKR_ARGUMENTS_BAD); |
| string slot_description; |
| string manufacturer_id; |
| CK_RV result = g_proxy->GetSlotInfo( |
| slotID, |
| &slot_description, |
| &manufacturer_id, |
| chaps::PreservedCK_ULONG(&pInfo->flags), |
| static_cast<uint8_t*>(&pInfo->hardwareVersion.major), |
| static_cast<uint8_t*>(&pInfo->hardwareVersion.minor), |
| static_cast<uint8_t*>(&pInfo->firmwareVersion.major), |
| static_cast<uint8_t*>(&pInfo->firmwareVersion.minor)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| chaps::CopyToCharBuffer(slot_description.c_str(), pInfo->slotDescription, |
| arraysize(pInfo->slotDescription)); |
| chaps::CopyToCharBuffer(manufacturer_id.c_str(), pInfo->manufacturerID, |
| arraysize(pInfo->manufacturerID)); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 109. |
| CK_RV C_GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pInfo, CKR_ARGUMENTS_BAD); |
| string label; |
| string manufacturer_id; |
| string model; |
| string serial_number; |
| CK_RV result = g_proxy->GetTokenInfo( |
| slotID, |
| &label, |
| &manufacturer_id, |
| &model, |
| &serial_number, |
| chaps::PreservedCK_ULONG(&pInfo->flags), |
| chaps::PreservedCK_ULONG(&pInfo->ulMaxSessionCount), |
| chaps::PreservedCK_ULONG(&pInfo->ulSessionCount), |
| chaps::PreservedCK_ULONG(&pInfo->ulMaxRwSessionCount), |
| chaps::PreservedCK_ULONG(&pInfo->ulRwSessionCount), |
| chaps::PreservedCK_ULONG(&pInfo->ulMaxPinLen), |
| chaps::PreservedCK_ULONG(&pInfo->ulMinPinLen), |
| chaps::PreservedCK_ULONG(&pInfo->ulTotalPublicMemory), |
| chaps::PreservedCK_ULONG(&pInfo->ulFreePublicMemory), |
| chaps::PreservedCK_ULONG(&pInfo->ulTotalPrivateMemory), |
| chaps::PreservedCK_ULONG(&pInfo->ulFreePrivateMemory), |
| static_cast<uint8_t*>(&pInfo->hardwareVersion.major), |
| static_cast<uint8_t*>(&pInfo->hardwareVersion.minor), |
| static_cast<uint8_t*>(&pInfo->firmwareVersion.major), |
| static_cast<uint8_t*>(&pInfo->firmwareVersion.minor)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| chaps::CopyToCharBuffer(label.c_str(), pInfo->label, arraysize(pInfo->label)); |
| chaps::CopyToCharBuffer(manufacturer_id.c_str(), pInfo->manufacturerID, |
| arraysize(pInfo->manufacturerID)); |
| chaps::CopyToCharBuffer(model.c_str(), pInfo->model, arraysize(pInfo->model)); |
| chaps::CopyToCharBuffer(serial_number.c_str(), pInfo->serialNumber, |
| arraysize(pInfo->serialNumber)); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 110. |
| // Currently, slot events via D-Bus are not supported because no slot events |
| // occur with TPM-based tokens. We want this call to behave properly so we'll |
| // block the calling thread (if not CKF_DONT_BLOCK) until C_Finalize is called. |
| CK_RV C_WaitForSlotEvent(CK_FLAGS flags, |
| CK_SLOT_ID_PTR pSlot, |
| CK_VOID_PTR pReserved) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pSlot, CKR_ARGUMENTS_BAD); |
| // Currently, all supported tokens are not removable - i.e. no slot events. |
| if (CKF_DONT_BLOCK & flags) |
| return CKR_NO_EVENT; |
| // Block until C_Finalize. |
| CHECK(g_finalize_event.get()); |
| g_finalize_event->Wait(); |
| return CKR_CRYPTOKI_NOT_INITIALIZED; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 111. |
| CK_RV C_GetMechanismList(CK_SLOT_ID slotID, |
| CK_MECHANISM_TYPE_PTR pMechanismList, |
| CK_ULONG_PTR pulCount) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pulCount, CKR_ARGUMENTS_BAD); |
| vector<uint32_t> mechanism_list; |
| CK_RV result = g_proxy->GetMechanismList(slotID, &mechanism_list); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| // Copy the mechanism list to caller-supplied memory. |
| size_t max_copy = static_cast<size_t>(*pulCount); |
| *pulCount = static_cast<CK_ULONG>(mechanism_list.size()); |
| if (!pMechanismList) |
| return CKR_OK; |
| LOG_CK_RV_AND_RETURN_IF(mechanism_list.size() > max_copy, |
| CKR_BUFFER_TOO_SMALL); |
| for (size_t i = 0; i < mechanism_list.size(); ++i) { |
| pMechanismList[i] = static_cast<CK_MECHANISM_TYPE>(mechanism_list[i]); |
| } |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 112. |
| CK_RV C_GetMechanismInfo(CK_SLOT_ID slotID, |
| CK_MECHANISM_TYPE type, |
| CK_MECHANISM_INFO_PTR pInfo) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pInfo, CKR_ARGUMENTS_BAD); |
| vector<uint32_t> mechanism_list; |
| CK_RV result = g_proxy->GetMechanismInfo( |
| slotID, |
| type, |
| chaps::PreservedCK_ULONG(&pInfo->ulMinKeySize), |
| chaps::PreservedCK_ULONG(&pInfo->ulMaxKeySize), |
| chaps::PreservedCK_ULONG(&pInfo->flags)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 113. |
| CK_RV C_InitToken(CK_SLOT_ID slotID, |
| CK_UTF8CHAR_PTR pPin, |
| CK_ULONG ulPinLen, |
| CK_UTF8CHAR_PTR pLabel) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pLabel, CKR_ARGUMENTS_BAD); |
| string pin = chaps::CharBufferToString(pPin, ulPinLen); |
| string label = chaps::CharBufferToString(pLabel, chaps::kTokenLabelSize); |
| string* pin_ptr = (!pPin) ? NULL : &pin; |
| CK_RV result = g_proxy->InitToken(slotID, pin_ptr, label); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 115. |
| CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, |
| CK_UTF8CHAR_PTR pPin, |
| CK_ULONG ulPinLen) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| string pin = chaps::CharBufferToString(pPin, ulPinLen); |
| string* pin_ptr = (!pPin) ? NULL : &pin; |
| CK_RV result = g_proxy->InitPIN(hSession, pin_ptr); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.5 page 116. |
| CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, |
| CK_UTF8CHAR_PTR pOldPin, |
| CK_ULONG ulOldLen, |
| CK_UTF8CHAR_PTR pNewPin, |
| CK_ULONG ulNewLen) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| string old_pin = chaps::CharBufferToString(pOldPin, ulOldLen); |
| string* old_pin_ptr = (!pOldPin) ? NULL : &old_pin; |
| string new_pin = chaps::CharBufferToString(pNewPin, ulNewLen); |
| string* new_pin_ptr = (!pNewPin) ? NULL : &new_pin; |
| CK_RV result = g_proxy->SetPIN(hSession, old_pin_ptr, new_pin_ptr); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 117. |
| CK_RV C_OpenSession(CK_SLOT_ID slotID, |
| CK_FLAGS flags, |
| CK_VOID_PTR pApplication, |
| CK_NOTIFY Notify, |
| CK_SESSION_HANDLE_PTR phSession) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!phSession, CKR_ARGUMENTS_BAD); |
| // pApplication and Notify are intentionally ignored. We don't support |
| // notification callbacks and the PKCS #11 specification does not require us |
| // to. See PKCS #11 v2.20 section 11.17 for details. |
| CK_RV result = g_proxy->OpenSession(slotID, flags, |
| chaps::PreservedCK_ULONG(phSession)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 118. |
| CK_RV C_CloseSession(CK_SESSION_HANDLE hSession) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| CK_RV result = g_proxy->CloseSession(hSession); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 120. |
| CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| CK_RV result = g_proxy->CloseAllSessions(slotID); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 120. |
| CK_RV C_GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pInfo, CKR_ARGUMENTS_BAD); |
| |
| CK_RV result = g_proxy->GetSessionInfo( |
| hSession, |
| chaps::PreservedCK_ULONG(&pInfo->slotID), |
| chaps::PreservedCK_ULONG(&pInfo->state), |
| chaps::PreservedCK_ULONG(&pInfo->flags), |
| chaps::PreservedCK_ULONG(&pInfo->ulDeviceError)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 121. |
| CK_RV C_GetOperationState(CK_SESSION_HANDLE hSession, |
| CK_BYTE_PTR pOperationState, |
| CK_ULONG_PTR pulOperationStateLen) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pulOperationStateLen, CKR_ARGUMENTS_BAD); |
| |
| std::vector<uint8_t> operation_state; |
| CK_RV result = g_proxy->GetOperationState(hSession, &operation_state); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| // Copy the data and length to caller-supplied memory. |
| size_t max_copy = static_cast<size_t>(*pulOperationStateLen); |
| *pulOperationStateLen = static_cast<CK_ULONG>(operation_state.size()); |
| if (!pOperationState) |
| return CKR_OK; |
| LOG_CK_RV_AND_RETURN_IF(operation_state.size() > max_copy, |
| CKR_BUFFER_TOO_SMALL); |
| memcpy(pOperationState, &operation_state.front(), operation_state.size()); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 123. |
| CK_RV C_SetOperationState(CK_SESSION_HANDLE hSession, |
| CK_BYTE_PTR pOperationState, |
| CK_ULONG ulOperationStateLen, |
| CK_OBJECT_HANDLE hEncryptionKey, |
| CK_OBJECT_HANDLE hAuthenticationKey) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| LOG_CK_RV_AND_RETURN_IF(!pOperationState, CKR_ARGUMENTS_BAD); |
| |
| vector<uint8_t> operation_state(&pOperationState[0], |
| &pOperationState[ulOperationStateLen]); |
| CK_RV result = g_proxy->SetOperationState(hSession, |
| operation_state, |
| hEncryptionKey, |
| hAuthenticationKey); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 125. |
| CK_RV C_Login(CK_SESSION_HANDLE hSession, |
| CK_USER_TYPE userType, |
| CK_UTF8CHAR_PTR pPin, |
| CK_ULONG ulPinLen) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| string pin = chaps::CharBufferToString(pPin, ulPinLen); |
| string* pin_ptr = (!pPin) ? NULL : &pin; |
| CK_RV result = g_proxy->Login(hSession, userType, pin_ptr); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.6 page 127. |
| CK_RV C_Logout(CK_SESSION_HANDLE hSession) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| CK_RV result = g_proxy->Logout(hSession); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.7 page 128. |
| CK_RV C_CreateObject(CK_SESSION_HANDLE hSession, |
| CK_ATTRIBUTE_PTR pTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR phObject) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| if (pTemplate == NULL_PTR || phObject == NULL_PTR) |
| LOG_CK_RV_AND_RETURN(CKR_ARGUMENTS_BAD); |
| CK_RV result = g_proxy->CreateObject( |
| hSession, |
| chaps::EncodeAttributes(pTemplate, ulCount), |
| chaps::PreservedCK_ULONG(phObject)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.7 page 130. |
| CK_RV C_CopyObject(CK_SESSION_HANDLE hSession, |
| CK_OBJECT_HANDLE hObject, |
| CK_ATTRIBUTE_PTR pTemplate, |
| CK_ULONG ulCount, |
| CK_OBJECT_HANDLE_PTR phNewObject) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| if (pTemplate == NULL_PTR || phNewObject == NULL_PTR) |
| LOG_CK_RV_AND_RETURN(CKR_ARGUMENTS_BAD); |
| CK_RV result = g_proxy->CopyObject( |
| hSession, |
| hObject, |
| chaps::EncodeAttributes(pTemplate, ulCount), |
| chaps::PreservedCK_ULONG(phNewObject)); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |
| |
| // PKCS #11 v2.20 section 11.7 page 131. |
| CK_RV C_DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { |
| LOG_CK_RV_AND_RETURN_IF(!g_is_initialized, CKR_CRYPTOKI_NOT_INITIALIZED); |
| CK_RV result = g_proxy->DestroyObject(hSession, hObject); |
| LOG_CK_RV_AND_RETURN_IF_ERR(result); |
| return CKR_OK; |
| } |