| /* |
| * Copyright 2024, The Android Open Source Project |
| * |
| * 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 "SharedSecret.h" |
| |
| #include <algorithm> |
| #include <cstring> |
| #include <mutex> |
| #include <vector> |
| |
| #include <openssl/rand.h> |
| |
| #include <KeyMintUtils.h> |
| #include <aidl/android/hardware/security/sharedsecret/BnSharedSecret.h> |
| #include <aidl/android/hardware/security/sharedsecret/SharedSecretParameters.h> |
| #include <android-base/logging.h> |
| #include <keymaster/android_keymaster_messages.h> |
| #include <keymaster/android_keymaster_utils.h> |
| #include <keymaster/km_openssl/ckdf.h> |
| #include <keymaster/km_openssl/hmac.h> |
| |
| namespace aidl::android::hardware::security::sharedsecret { |
| |
| ::ndk::ScopedAStatus SoftSharedSecret::getSharedSecretParameters( |
| SharedSecretParameters* out_params) { |
| std::lock_guard lock(mutex_); |
| if (seed_.empty()) { |
| seed_.resize(32, 0); |
| } |
| out_params->seed = seed_; |
| if (nonce_.empty()) { |
| nonce_.resize(32, 0); |
| RAND_bytes(nonce_.data(), 32); |
| } |
| out_params->nonce = nonce_; |
| LOG(INFO) << "Presented shared secret parameters with seed size " << out_params->seed.size() |
| << " and nonce size " << out_params->nonce.size(); |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| |
| ::ndk::ScopedAStatus SoftSharedSecret::computeSharedSecret( |
| const std::vector<SharedSecretParameters>& params, std::vector<uint8_t>* sharing_check) { |
| std::lock_guard lock(mutex_); |
| LOG(INFO) << "Computing shared secret"; |
| // Reimplemented based on SoftKeymasterEnforcement, which does not expose |
| // enough functionality to satisfy the GateKeeper interface |
| keymaster::KeymasterKeyBlob key_agreement_key; |
| if (key_agreement_key.Reset(32) == nullptr) { |
| LOG(ERROR) << "key agreement key memory allocation failed"; |
| return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED); |
| } |
| // Matching: |
| // - kFakeAgreementKey in system/keymaster/km_openssl/soft_keymaster_enforcement.cpp |
| // - Keys::kak in hardware/interfaces/security/keymint/aidl/default/ta/soft.rs |
| std::memset(key_agreement_key.writable_data(), 0, 32); |
| keymaster::KeymasterBlob label((uint8_t*)KEY_AGREEMENT_LABEL, strlen(KEY_AGREEMENT_LABEL)); |
| if (label.data == nullptr) { |
| LOG(ERROR) << "label memory allocation failed"; |
| return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED); |
| } |
| |
| static_assert(sizeof(keymaster_blob_t) == sizeof(keymaster::KeymasterBlob)); |
| |
| bool found_mine = false; |
| std::vector<keymaster::KeymasterBlob> context_blobs; |
| for (const auto& param : params) { |
| auto& seed_blob = context_blobs.emplace_back(); |
| if (seed_blob.Reset(param.seed.size()) == nullptr) { |
| LOG(ERROR) << "seed memory allocation failed"; |
| return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED); |
| } |
| std::copy(param.seed.begin(), param.seed.end(), seed_blob.writable_data()); |
| auto& nonce_blob = context_blobs.emplace_back(); |
| if (nonce_blob.Reset(param.nonce.size()) == nullptr) { |
| LOG(ERROR) << "Nonce memory allocation failed"; |
| return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED); |
| } |
| std::copy(param.nonce.begin(), param.nonce.end(), nonce_blob.writable_data()); |
| if (param.seed == seed_ && param.nonce == nonce_) { |
| found_mine = true; |
| } |
| } |
| if (!found_mine) { |
| LOG(ERROR) << "Did not receive my own shared secret parameter back"; |
| return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_INVALID_ARGUMENT); |
| } |
| auto context_blobs_ptr = reinterpret_cast<keymaster_blob_t*>(context_blobs.data()); |
| if (hmac_key_.Reset(32) == nullptr) { |
| LOG(ERROR) << "hmac key allocation failed"; |
| return keymint::km_utils::kmError2ScopedAStatus(KM_ERROR_MEMORY_ALLOCATION_FAILED); |
| } |
| auto error = keymaster::ckdf(key_agreement_key, label, context_blobs_ptr, context_blobs.size(), |
| &hmac_key_); |
| if (error != KM_ERROR_OK) { |
| LOG(ERROR) << "CKDF failed"; |
| return keymint::km_utils::kmError2ScopedAStatus(error); |
| } |
| |
| keymaster::HmacSha256 hmac_impl; |
| if (!hmac_impl.Init(hmac_key_.key_material, hmac_key_.key_material_size)) { |
| LOG(ERROR) << "hmac initialization failed"; |
| return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| sharing_check->clear(); |
| sharing_check->resize(32, 0); |
| if (!hmac_impl.Sign((const uint8_t*)KEY_CHECK_LABEL, strlen(KEY_CHECK_LABEL), |
| sharing_check->data(), sharing_check->size())) { |
| return ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE); |
| } |
| return ::ndk::ScopedAStatus::ok(); |
| } |
| |
| keymaster::KeymasterKeyBlob SoftSharedSecret::HmacKey() const { |
| std::lock_guard lock(mutex_); |
| return hmac_key_; |
| } |
| |
| } // namespace aidl::android::hardware::security::sharedsecret |