kmsp11/main/bridge.cc (722 lines of code) (raw):

// Copyright 2021 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "absl/status/status.h" #include "absl/types/optional.h" #include "common/status_macros.h" #include "glog/logging.h" #include "kmsp11/config/config.h" #include "kmsp11/cryptoki.h" #include "kmsp11/kmsp11.h" #include "kmsp11/main/fork_support.h" #include "kmsp11/main/function_list.h" #include "kmsp11/provider.h" #include "kmsp11/util/crypto_utils.h" #include "kmsp11/util/errors.h" #include "kmsp11/util/global_provider.h" #include "kmsp11/util/logging.h" #include "kmsp11/util/status_utils.h" namespace cloud_kms::kmsp11 { namespace { constexpr CK_FUNCTION_LIST kFunctionList = NewFunctionList(); absl::StatusOr<Provider*> GetProvider() { Provider* provider = GetGlobalProvider(); if (!provider) { return NotInitializedError(SOURCE_LOCATION); } return provider; } absl::StatusOr<Token*> GetToken(CK_SLOT_ID slot_id) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); return provider->TokenAt(slot_id); } absl::StatusOr<std::shared_ptr<Session>> GetSession( CK_SESSION_HANDLE session_handle) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); return provider->GetSession(session_handle); } } // namespace // Initialize the library. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002322 absl::Status Initialize(CK_VOID_PTR pInitArgs) { auto* init_args = static_cast<CK_C_INITIALIZE_ARGS*>(pInitArgs); if (init_args) { if ((init_args->flags & CKF_OS_LOCKING_OK) != CKF_OS_LOCKING_OK && (init_args->CreateMutex || init_args->DestroyMutex || init_args->LockMutex || init_args->UnlockMutex)) { return NewInvalidArgumentError("library requires os locking", CKR_CANT_LOCK, SOURCE_LOCATION); } if ((init_args->flags & CKF_LIBRARY_CANT_CREATE_OS_THREADS) == CKF_LIBRARY_CANT_CREATE_OS_THREADS) { return NewInvalidArgumentError("library requires thread creation", CKR_NEED_TO_CREATE_THREADS, SOURCE_LOCATION); } } LibraryConfig config; if (init_args && init_args->pReserved) { // This behavior isn't part of the spec, but there are numerous libraries // in the wild that allow specifying a config file in pInitArgs->pReserved. // There's also support for providing config this way in the OpenSSL engine: // https://github.com/OpenSC/libp11/blob/4084f83ee5ea51353facf151126b7d6d739d0784/src/eng_front.c#L62 ASSIGN_OR_RETURN( config, LoadConfigFromFile(static_cast<char*>(init_args->pReserved))); } else { ASSIGN_OR_RETURN(config, LoadConfigFromEnvironment()); } // Registering fork handlers is a one-time operation. if (!config.skip_fork_handlers()) { static const absl::Status kForkHandlersRegistered = RegisterForkHandlers(); RETURN_IF_ERROR(kForkHandlersRegistered); } Provider* existing_provider = GetGlobalProvider(); if (existing_provider) { return FailedPreconditionError("the library is already initialized", CKR_CRYPTOKI_ALREADY_INITIALIZED, SOURCE_LOCATION); } CHECK(kCryptoLibraryInitialized); if (config.require_fips_mode()) { absl::Status self_test_result = CheckFipsSelfTest(); CHECK(self_test_result.ok()) << "FIPS tests failed: " << self_test_result; } // Provider::New emits info log messages (for example, noting that a CKV is // being skipped due to state DISABLED), so logging should be initialized // before it is invoked. RETURN_IF_ERROR( InitializeLogging(config.log_directory(), config.log_filename_suffix())); absl::StatusOr<std::unique_ptr<Provider>> new_provider = Provider::New(config); if (!new_provider.ok()) { ShutdownLogging(); return new_provider.status(); } return SetGlobalProvider(std::move(new_provider).value()); } // Shut down the library. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc383864872 absl::Status Finalize(CK_VOID_PTR pReserved) { RETURN_IF_ERROR(GetProvider()); RETURN_IF_ERROR(ReleaseGlobalProvider()); ShutdownLogging(); return absl::OkStatus(); } // Get basic information about the library. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002324 absl::Status GetInfo(CK_INFO_PTR pInfo) { ASSIGN_OR_RETURN(const Provider* provider, GetProvider()); if (!pInfo) { return NullArgumentError("pInfo", SOURCE_LOCATION); } *pInfo = provider->info(); return absl::OkStatus(); } // Get pointers to the functions exposed in this library. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc319313512 absl::Status GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { // Note that GetFunctionList is the only Cryptoki function that may be called // before the library is initialized. if (!ppFunctionList) { return NullArgumentError("ppFunctionList", SOURCE_LOCATION); } *ppFunctionList = const_cast<CK_FUNCTION_LIST*>(&kFunctionList); return absl::OkStatus(); } // Get the list of slots in this library. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002327 // Note that tokenPresent is always ignored in our library, since we do not have // removable tokens. absl::Status GetSlotList(CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { ASSIGN_OR_RETURN(const Provider* provider, GetProvider()); if (!pulCount) { return NullArgumentError("pulCount", SOURCE_LOCATION); } if (!pSlotList) { *pulCount = provider->token_count(); return absl::OkStatus(); } if (*pulCount < provider->token_count()) { absl::Status result = OutOfRangeError(absl::StrFormat("*pulCount=%d but there are %d tokens", *pulCount, provider->token_count()), SOURCE_LOCATION); *pulCount = provider->token_count(); return result; } for (size_t i = 0; i < provider->token_count(); i++) { pSlotList[i] = i; } *pulCount = provider->token_count(); return absl::OkStatus(); } // Get information about a slot in the system. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002328 absl::Status GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { ASSIGN_OR_RETURN(const Token* token, GetToken(slotID)); if (!pInfo) { return NullArgumentError("pInfo", SOURCE_LOCATION); } *pInfo = token->slot_info(); return absl::OkStatus(); } // Get information about a token in the system. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002329 absl::Status GetTokenInfo(CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { ASSIGN_OR_RETURN(const Token* token, GetToken(slotID)); if (!pInfo) { return NullArgumentError("pInfo", SOURCE_LOCATION); } *pInfo = token->token_info(); return absl::OkStatus(); } // Open a session between an application and a token in a particular slot. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002337 // Note that `pApplication` and `notify` are always ignored in our library, // which does not support notifications. absl::Status OpenSession(CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY notify, CK_SESSION_HANDLE_PTR phSession) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); if ((flags & CKF_SERIAL_SESSION) != CKF_SERIAL_SESSION) { return NewError(absl::StatusCode::kInvalidArgument, "parallel sessions are not supported", CKR_SESSION_PARALLEL_NOT_SUPPORTED, SOURCE_LOCATION); } if (!phSession) { return NullArgumentError("phSession", SOURCE_LOCATION); } SessionType session_type = (flags & CKF_RW_SESSION) == CKF_RW_SESSION ? SessionType::kReadWrite : SessionType::kReadOnly; ASSIGN_OR_RETURN(*phSession, provider->OpenSession(slotID, session_type)); return absl::OkStatus(); } // Close a session between an application and a token. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc383864884 absl::Status CloseSession(CK_SESSION_HANDLE hSession) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); return provider->CloseSession(hSession); } // Close all sessions between an application and a token. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002339 absl::Status CloseAllSessions(CK_SLOT_ID slotID) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); return provider->CloseAllSessions(slotID); } // Get information about a session. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002340 absl::Status GetSessionInfo(CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); ASSIGN_OR_RETURN(std::shared_ptr<Session> session, provider->GetSession(hSession)); if (!pInfo) { return NullArgumentError("pInfo", SOURCE_LOCATION); } *pInfo = session->info(); return absl::OkStatus(); } // Log a user into a token. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002343 // Note that pPin and ulPinLen are always ignored in this library. absl::Status Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); ASSIGN_OR_RETURN(std::shared_ptr<Session> session, provider->GetSession(hSession)); return session->token()->Login(userType); } // Log a user out from a token. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002344 absl::Status Logout(CK_SESSION_HANDLE hSession) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); ASSIGN_OR_RETURN(std::shared_ptr<Session> session, provider->GetSession(hSession)); return session->token()->Logout(); } // Get a list of mechanisms supported in a token. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002331 absl::Status GetMechanismList(CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); RETURN_IF_ERROR(GetToken(slotID).status()); // ensure slotID is valid if (!pulCount) { return NullArgumentError("pulCount", SOURCE_LOCATION); } absl::Span<const CK_MECHANISM_TYPE> types = provider->Mechanisms(); if (!pMechanismList) { *pulCount = types.size(); return absl::OkStatus(); } if (*pulCount < types.size()) { absl::Status result = OutOfRangeError( absl::StrFormat("*pulCount=%d but there are %d mechanisms", *pulCount, types.size()), SOURCE_LOCATION); *pulCount = types.size(); return result; } for (size_t i = 0; i < types.size(); i++) { pMechanismList[i] = types[i]; } *pulCount = types.size(); return absl::OkStatus(); } // Get information about a mechanism supported in a token. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002332 absl::Status GetMechanismInfo(CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); RETURN_IF_ERROR(GetToken(slotID).status()); // ensure slotID is valid if (!pInfo) { return NullArgumentError("pInfo", SOURCE_LOCATION); } ASSIGN_OR_RETURN(*pInfo, provider->MechanismInfo(type)); return absl::OkStatus(); } // Get the values of the supplied attributes for the given object. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002350 absl::Status GetAttributeValue(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); ASSIGN_OR_RETURN(std::shared_ptr<Object> object, session->token()->GetObject(hObject)); if (!pTemplate) { return NullArgumentError("pTemplate", SOURCE_LOCATION); } absl::Status result = absl::OkStatus(); for (CK_ATTRIBUTE& attr : absl::MakeSpan(pTemplate, ulCount)) { absl::StatusOr<std::string_view> value = object->attributes().Value(attr.type); // C_GetAttributeValue cases 1 and 2 if (!value.ok()) { result = value.status(); attr.ulValueLen = CK_UNAVAILABLE_INFORMATION; continue; } // C_GetAttributeValue case 3 if (!attr.pValue) { attr.ulValueLen = value->size(); continue; } // C_GetAttributeValue case 4 if (attr.ulValueLen >= value->size()) { std::copy(value->begin(), value->end(), static_cast<char*>(attr.pValue)); attr.ulValueLen = value->size(); continue; } // C_GetAttributeValue case 5 attr.ulValueLen = CK_UNAVAILABLE_INFORMATION; result = OutOfRangeError( absl::StrFormat( "attribute %#X is of length %d, received buffer of length %d", attr.type, value->size(), attr.ulValueLen), SOURCE_LOCATION); } return result; } // Begin an object browsing operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002352 absl::Status FindObjectsInit(CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (ulCount > 0 && !pTemplate) { return NullArgumentError("pTemplate", SOURCE_LOCATION); } return session->FindObjectsInit(absl::MakeConstSpan(pTemplate, ulCount)); } // Continue an object browsing operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002353 absl::Status FindObjects(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!phObject) { return NullArgumentError("phObject", SOURCE_LOCATION); } if (!pulObjectCount) { return NullArgumentError("pulObjectCount", SOURCE_LOCATION); } ASSIGN_OR_RETURN(absl::Span<const CK_OBJECT_HANDLE> handles, session->FindObjects(ulMaxObjectCount)); std::copy(handles.begin(), handles.end(), phObject); *pulObjectCount = handles.size(); return absl::OkStatus(); } // End an object browsing operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002354 absl::Status FindObjectsFinal(CK_SESSION_HANDLE hSession) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); return session->FindObjectsFinal(); } // Begin a decrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002361 absl::Status DecryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); ASSIGN_OR_RETURN(std::shared_ptr<Object> key, session->token()->GetKey(hKey)); if (!pMechanism) { return NullArgumentError("pMechanism", SOURCE_LOCATION); } return session->DecryptInit(key, pMechanism); } // Complete a decrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002362 absl::Status Decrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pEncryptedData) { session->ReleaseOperation(); return NullArgumentError("pEncryptedData", SOURCE_LOCATION); } if (!pulDataLen) { session->ReleaseOperation(); return NullArgumentError("pulDataLen", SOURCE_LOCATION); } absl::StatusOr<absl::Span<const uint8_t>> plaintext = session->Decrypt(absl::MakeConstSpan(pEncryptedData, ulEncryptedDataLen)); if (!plaintext.ok()) { session->ReleaseOperation(); return plaintext.status(); } if (!pData) { *pulDataLen = plaintext->size(); return absl::OkStatus(); } if (*pulDataLen < plaintext->size()) { absl::Status result = OutOfRangeError( absl::StrFormat( "plaintext of length %d cannot fit in buffer of length %d", plaintext->size(), *pulDataLen), SOURCE_LOCATION); *pulDataLen = plaintext->size(); return result; } std::copy(plaintext->begin(), plaintext->end(), pData); *pulDataLen = plaintext->size(); session->ReleaseOperation(); return absl::OkStatus(); } // Continue a multi-part encrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc385057935 absl::Status DecryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen, CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pEncryptedPart) { session->ReleaseOperation(); return NullArgumentError("pEncryptedPart", SOURCE_LOCATION); } if (!pulPartLen) { session->ReleaseOperation(); return NullArgumentError("pulPartLen", SOURCE_LOCATION); } absl::Status result = session->DecryptUpdate( absl::MakeConstSpan(pEncryptedPart, ulEncryptedPartLen)); if (!result.ok()) { session->ReleaseOperation(); } // The library does not return partial decrypted plaintext, so we set the // partial output length to 0. *pulPartLen = 0; return result; } // Complete a multi-part encrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024136 absl::Status DecryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastPart, CK_ULONG_PTR pulLastPartLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pulLastPartLen) { session->ReleaseOperation(); return NullArgumentError("pulLastPartLen", SOURCE_LOCATION); } absl::StatusOr<absl::Span<const uint8_t>> plaintext = session->DecryptFinal(); if (!plaintext.ok()) { session->ReleaseOperation(); return plaintext.status(); } if (!pLastPart) { *pulLastPartLen = plaintext->size(); return absl::OkStatus(); } if (*pulLastPartLen < plaintext->size()) { absl::Status result = OutOfRangeError( absl::StrFormat( "plaintext of length %d cannot fit in buffer of length %d", plaintext->size(), *pulLastPartLen), SOURCE_LOCATION); *pulLastPartLen = plaintext->size(); return result; } std::copy(plaintext->begin(), plaintext->end(), pLastPart); *pulLastPartLen = plaintext->size(); session->ReleaseOperation(); return absl::OkStatus(); } // Begin an encrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002356 absl::Status EncryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); ASSIGN_OR_RETURN(std::shared_ptr<Object> key, session->token()->GetKey(hKey)); if (!pMechanism) { return NullArgumentError("pMechanism", SOURCE_LOCATION); } return session->EncryptInit(key, pMechanism); } // Complete an encrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002357 absl::Status Encrypt(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pData) { session->ReleaseOperation(); return NullArgumentError("pData", SOURCE_LOCATION); } if (!pulEncryptedDataLen) { session->ReleaseOperation(); return NullArgumentError("pulEncryptedDataLen", SOURCE_LOCATION); } absl::StatusOr<absl::Span<const uint8_t>> ciphertext = session->Encrypt(absl::MakeConstSpan(pData, ulDataLen)); if (!ciphertext.ok()) { session->ReleaseOperation(); return ciphertext.status(); } if (!pEncryptedData) { *pulEncryptedDataLen = ciphertext->size(); return absl::OkStatus(); } if (*pulEncryptedDataLen < ciphertext->size()) { absl::Status result = OutOfRangeError( absl::StrFormat( "ciphertext of length %d cannot fit in buffer of length %d", ciphertext->size(), *pulEncryptedDataLen), SOURCE_LOCATION); *pulEncryptedDataLen = ciphertext->size(); return result; } std::copy(ciphertext->begin(), ciphertext->end(), pEncryptedData); *pulEncryptedDataLen = ciphertext->size(); session->ReleaseOperation(); return absl::OkStatus(); } // Continue a multi-part encrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024131 absl::Status EncryptUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen, CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pPart) { session->ReleaseOperation(); return NullArgumentError("pPart", SOURCE_LOCATION); } if (!pulEncryptedPartLen) { session->ReleaseOperation(); return NullArgumentError("pulEncryptedPartLen", SOURCE_LOCATION); } absl::Status result = session->EncryptUpdate(absl::MakeConstSpan(pPart, ulPartLen)); if (!result.ok()) { session->ReleaseOperation(); } // The library does not return partial encrypted ciphertext, so we set the // partial output length to 0. *pulEncryptedPartLen = 0; return result; } // Complete a multi-part encrypt operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024132 absl::Status EncryptFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pLastEncryptedPart, CK_ULONG_PTR pulLastEncryptedPartLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pulLastEncryptedPartLen) { session->ReleaseOperation(); return NullArgumentError("pulLastEncryptedPartLen", SOURCE_LOCATION); } absl::StatusOr<absl::Span<const uint8_t>> ciphertext = session->EncryptFinal(); if (!ciphertext.ok()) { session->ReleaseOperation(); return ciphertext.status(); } if (!pLastEncryptedPart) { *pulLastEncryptedPartLen = ciphertext->size(); return absl::OkStatus(); } if (*pulLastEncryptedPartLen < ciphertext->size()) { absl::Status result = OutOfRangeError( absl::StrFormat( "ciphertext of length %d cannot fit in buffer of length %d", ciphertext->size(), *pulLastEncryptedPartLen), SOURCE_LOCATION); *pulLastEncryptedPartLen = ciphertext->size(); return result; } std::copy(ciphertext->begin(), ciphertext->end(), pLastEncryptedPart); *pulLastEncryptedPartLen = ciphertext->size(); session->ReleaseOperation(); return absl::OkStatus(); } // Begin a single-part or multi-part sign operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002372 absl::Status SignInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); ASSIGN_OR_RETURN(std::shared_ptr<Object> key, session->token()->GetKey(hKey)); if (!pMechanism) { return NullArgumentError("pMechanism", SOURCE_LOCATION); } return session->SignInit(key, pMechanism); } // Complete a single-part sign operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002373 absl::Status Sign(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pData) { session->ReleaseOperation(); return NullArgumentError("pData", SOURCE_LOCATION); } if (!pulSignatureLen) { session->ReleaseOperation(); return NullArgumentError("pulSignatureLen", SOURCE_LOCATION); } absl::StatusOr<size_t> sig_length = session->SignatureLength(); if (!sig_length.ok()) { session->ReleaseOperation(); return sig_length.status(); } if (!pSignature) { *pulSignatureLen = *sig_length; return absl::OkStatus(); } if (*pulSignatureLen < *sig_length) { absl::Status result = OutOfRangeError( absl::StrFormat( "signature of length %d cannot fit in buffer of length %d", *sig_length, *pulSignatureLen), SOURCE_LOCATION); *pulSignatureLen = *sig_length; return result; } absl::Status result = session->Sign(absl::MakeConstSpan(pData, ulDataLen), absl::MakeSpan(pSignature, *sig_length)); session->ReleaseOperation(); if (result.ok()) { *pulSignatureLen = *sig_length; } return result; } // Continue a multi-part sign operation. // https://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024145 absl::Status SignUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pPart) { session->ReleaseOperation(); return NullArgumentError("pData", SOURCE_LOCATION); } absl::Status result = session->SignUpdate(absl::MakeConstSpan(pPart, ulPartLen)); if (!result.ok()) { session->ReleaseOperation(); } return result; } // Complete a multi-part sign operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024146 absl::Status SignFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pulSignatureLen) { session->ReleaseOperation(); return NullArgumentError("pulSignatureLen", SOURCE_LOCATION); } absl::StatusOr<size_t> sig_length = session->SignatureLength(); if (!sig_length.ok()) { session->ReleaseOperation(); return sig_length.status(); } if (!pSignature) { *pulSignatureLen = *sig_length; return absl::OkStatus(); } if (*pulSignatureLen < *sig_length) { absl::Status result = OutOfRangeError( absl::StrFormat( "signature of length %d cannot fit in buffer of length %d", *sig_length, *pulSignatureLen), SOURCE_LOCATION); *pulSignatureLen = *sig_length; return result; } absl::Status result = session->SignFinal(absl::MakeSpan(pSignature, *sig_length)); session->ReleaseOperation(); if (result.ok()) { *pulSignatureLen = *sig_length; } return result; } // Begin a single-part or multi-part verify operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002379 absl::Status VerifyInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); ASSIGN_OR_RETURN(std::shared_ptr<Object> key, session->token()->GetKey(hKey)); if (!pMechanism) { return NullArgumentError("pMechanism", SOURCE_LOCATION); } return session->VerifyInit(key, pMechanism); } // Complete a single-part verify operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc235002380 absl::Status Verify(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pData) { session->ReleaseOperation(); return NullArgumentError("pData", SOURCE_LOCATION); } if (!pSignature) { session->ReleaseOperation(); return NullArgumentError("pSignature", SOURCE_LOCATION); } absl::Status result = session->Verify(absl::MakeConstSpan(pData, ulDataLen), absl::MakeConstSpan(pSignature, ulSignatureLen)); session->ReleaseOperation(); return result; } // Continue a multi-part verify operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024151 absl::Status VerifyUpdate(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pPart) { session->ReleaseOperation(); return NullArgumentError("pData", SOURCE_LOCATION); } absl::Status result = session->VerifyUpdate(absl::MakeConstSpan(pPart, ulPartLen)); if (!result.ok()) { session->ReleaseOperation(); } return result; } // Complete a multi-part verify operation. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html#_Toc323024152 absl::Status VerifyFinal(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pSignature) { session->ReleaseOperation(); return NullArgumentError("pSignature", SOURCE_LOCATION); } absl::Status result = session->VerifyFinal(absl::MakeConstSpan(pSignature, ulSignatureLen)); session->ReleaseOperation(); return result; } // Generate a new secret key. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html#_Toc323024156 absl::Status GenerateKey(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pMechanism) { return NullArgumentError("pMechanism", SOURCE_LOCATION); } if (!phKey) { return NullArgumentError("phKey", SOURCE_LOCATION); } absl::Span<const CK_ATTRIBUTE> attributes; if (ulCount > 0) { if (!pTemplate) { return NullArgumentError("pTemplate", SOURCE_LOCATION); } attributes = absl::MakeConstSpan(pTemplate, ulCount); } ASSIGN_OR_RETURN( CK_OBJECT_HANDLE handle, session->GenerateKey( *pMechanism, attributes, provider->library_config().experimental_create_multiple_versions(), provider->library_config().allow_software_keys())); *phKey = handle; return absl::OkStatus(); } // Generate a new asymmetric key pair. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/os/pkcs11-base-v2.40-os.html#_Toc323024157 absl::Status GenerateKeyPair( CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { ASSIGN_OR_RETURN(Provider * provider, GetProvider()); ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pMechanism) { return NullArgumentError("pMechanism", SOURCE_LOCATION); } if (!phPublicKey) { return NullArgumentError("phPublicKey", SOURCE_LOCATION); } if (!phPrivateKey) { return NullArgumentError("phPrivateKey", SOURCE_LOCATION); } absl::Span<const CK_ATTRIBUTE> pub_attributes; if (ulPublicKeyAttributeCount > 0) { if (!pPublicKeyTemplate) { return NullArgumentError("pPublicKeyTemplate", SOURCE_LOCATION); } pub_attributes = absl::MakeConstSpan(pPublicKeyTemplate, ulPublicKeyAttributeCount); } absl::Span<const CK_ATTRIBUTE> prv_attributes; if (ulPrivateKeyAttributeCount > 0) { if (!pPrivateKeyTemplate) { return NullArgumentError("pPrivateKeyTemplate", SOURCE_LOCATION); } prv_attributes = absl::MakeConstSpan(pPrivateKeyTemplate, ulPrivateKeyAttributeCount); } ASSIGN_OR_RETURN( AsymmetricHandleSet handles, session->GenerateKeyPair( *pMechanism, pub_attributes, prv_attributes, provider->library_config().experimental_create_multiple_versions(), provider->library_config().allow_software_keys())); *phPublicKey = handles.public_key_handle; *phPrivateKey = handles.private_key_handle; return absl::OkStatus(); } absl::Status DestroyObject(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); ASSIGN_OR_RETURN(std::shared_ptr<Object> object, session->token()->GetObject(hObject)); return session->DestroyObject(object); } // Retrieve HSM randomness. // http://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/errata01/os/pkcs11-base-v2.40-errata01-os-complete.html#_Toc323024163 absl::Status GenerateRandom(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { ASSIGN_OR_RETURN(std::shared_ptr<Session> session, GetSession(hSession)); if (!pRandomData) { return NullArgumentError("pRandomData", SOURCE_LOCATION); } return session->GenerateRandom(absl::MakeSpan(pRandomData, ulRandomLen)); } } // namespace cloud_kms::kmsp11