| /* |
| * Copyright (C) 2021 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 "FakeCompOs.h" |
| |
| #include "CertUtils.h" |
| #include "KeyConstants.h" |
| |
| #include <android-base/file.h> |
| #include <android-base/logging.h> |
| #include <android-base/result.h> |
| #include <android-base/scopeguard.h> |
| |
| #include <binder/IServiceManager.h> |
| |
| #include <openssl/nid.h> |
| #include <openssl/rand.h> |
| #include <openssl/rsa.h> |
| #include <openssl/sha.h> |
| |
| using android::String16; |
| |
| using android::hardware::security::keymint::Algorithm; |
| using android::hardware::security::keymint::Digest; |
| using android::hardware::security::keymint::KeyParameter; |
| using android::hardware::security::keymint::KeyParameterValue; |
| using android::hardware::security::keymint::KeyPurpose; |
| using android::hardware::security::keymint::PaddingMode; |
| using android::hardware::security::keymint::SecurityLevel; |
| using android::hardware::security::keymint::Tag; |
| |
| using android::system::keystore2::CreateOperationResponse; |
| using android::system::keystore2::Domain; |
| |
| using android::base::Error; |
| using android::base::Result; |
| |
| using android::binder::Status; |
| |
| // TODO: Allocate a namespace for CompOS |
| const int64_t kCompOsNamespace = 101; |
| |
| Result<std::unique_ptr<FakeCompOs>> |
| FakeCompOs::startInstance(const std::string& /*instanceImagePath*/) { |
| std::unique_ptr<FakeCompOs> compOs(new FakeCompOs); |
| auto init = compOs->initialize(); |
| if (init.ok()) { |
| return compOs; |
| } else { |
| return init.error(); |
| } |
| } |
| |
| FakeCompOs::FakeCompOs() {} |
| |
| Result<void> FakeCompOs::initialize() { |
| auto sm = android::defaultServiceManager(); |
| if (!sm) { |
| return Error() << "No ServiceManager"; |
| } |
| auto rawService = sm->getService(String16("android.system.keystore2.IKeystoreService/default")); |
| if (!rawService) { |
| return Error() << "No Keystore service"; |
| } |
| mService = interface_cast<android::system::keystore2::IKeystoreService>(rawService); |
| if (!mService) { |
| return Error() << "Bad Keystore service"; |
| } |
| |
| // TODO: We probably want SecurityLevel::SOFTWARE here, in the VM, but Keystore doesn't do it |
| auto status = mService->getSecurityLevel(SecurityLevel::TRUSTED_ENVIRONMENT, &mSecurityLevel); |
| if (!status.isOk()) { |
| return Error() << status; |
| } |
| |
| return {}; |
| } |
| |
| Result<FakeCompOs::ByteVector> FakeCompOs::signData(const ByteVector& keyBlob, |
| const ByteVector& data) const { |
| KeyDescriptor descriptor; |
| descriptor.domain = Domain::BLOB; |
| descriptor.nspace = kCompOsNamespace; |
| descriptor.blob = keyBlob; |
| |
| std::vector<KeyParameter> parameters; |
| |
| { |
| KeyParameter algo; |
| algo.tag = Tag::ALGORITHM; |
| algo.value = KeyParameterValue::make<KeyParameterValue::algorithm>(Algorithm::RSA); |
| parameters.push_back(algo); |
| |
| KeyParameter digest; |
| digest.tag = Tag::DIGEST; |
| digest.value = KeyParameterValue::make<KeyParameterValue::digest>(Digest::SHA_2_256); |
| parameters.push_back(digest); |
| |
| KeyParameter padding; |
| padding.tag = Tag::PADDING; |
| padding.value = KeyParameterValue::make<KeyParameterValue::paddingMode>( |
| PaddingMode::RSA_PKCS1_1_5_SIGN); |
| parameters.push_back(padding); |
| |
| KeyParameter purpose; |
| purpose.tag = Tag::PURPOSE; |
| purpose.value = KeyParameterValue::make<KeyParameterValue::keyPurpose>(KeyPurpose::SIGN); |
| parameters.push_back(purpose); |
| } |
| |
| Status status; |
| |
| CreateOperationResponse response; |
| status = mSecurityLevel->createOperation(descriptor, parameters, /*forced=*/false, &response); |
| if (!status.isOk()) { |
| return Error() << "Failed to create operation: " << status; |
| } |
| |
| auto operation = response.iOperation; |
| auto abort_guard = android::base::make_scope_guard([&] { operation->abort(); }); |
| |
| if (response.operationChallenge.has_value()) { |
| return Error() << "Key requires user authorization"; |
| } |
| |
| std::optional<ByteVector> signature; |
| status = operation->finish(data, {}, &signature); |
| if (!status.isOk()) { |
| return Error() << "Failed to sign data: " << status; |
| } |
| |
| abort_guard.Disable(); |
| |
| if (!signature.has_value()) { |
| return Error() << "No signature received from keystore."; |
| } |
| |
| return signature.value(); |
| } |
| |
| Result<void> FakeCompOs::loadAndVerifyKey(const ByteVector& keyBlob, |
| const ByteVector& publicKey) const { |
| // To verify the key is valid, we use it to sign some data, and then verify the signature using |
| // the supplied public key. |
| |
| ByteVector data(32); |
| if (RAND_bytes(data.data(), data.size()) != 1) { |
| return Error() << "No random bytes"; |
| } |
| |
| auto signature = signData(keyBlob, data); |
| if (!signature.ok()) { |
| return signature.error(); |
| } |
| |
| std::string signatureString(reinterpret_cast<char*>(signature.value().data()), |
| signature.value().size()); |
| std::string dataString(reinterpret_cast<char*>(data.data()), data.size()); |
| return verifyRsaPublicKeySignature(dataString, signatureString, publicKey); |
| } |