1 /*
2 * Copyright (c) 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "credstore"
18
19 #include <algorithm>
20 #include <optional>
21
22 #include <android-base/logging.h>
23 #include <android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
24 #include <android/hardware/security/keymint/RpcHardwareInfo.h>
25 #include <binder/IPCThreadState.h>
26 #include <binder/IServiceManager.h>
27 #include <rkp/support/rkpd_client.h>
28
29 #include "Credential.h"
30 #include "CredentialData.h"
31 #include "CredentialStore.h"
32 #include "Session.h"
33 #include "Util.h"
34 #include "WritableCredential.h"
35
36 namespace android {
37 namespace security {
38 namespace identity {
39 namespace {
40
41 using ::android::security::rkp::RemotelyProvisionedKey;
42 using ::android::security::rkp::support::getRpcKey;
43
44 } // namespace
45
CredentialStore(const std::string & dataPath,sp<IIdentityCredentialStore> hal)46 CredentialStore::CredentialStore(const std::string& dataPath, sp<IIdentityCredentialStore> hal)
47 : dataPath_(dataPath), hal_(hal) {}
48
init()49 bool CredentialStore::init() {
50 Status status = hal_->getHardwareInformation(&hwInfo_);
51 if (!status.isOk()) {
52 LOG(ERROR) << "Error getting hardware information: " << status.toString8();
53 return false;
54 }
55 halApiVersion_ = hal_->getInterfaceVersion();
56
57 if (hwInfo_.isRemoteKeyProvisioningSupported) {
58 status = hal_->getRemotelyProvisionedComponent(&rpc_);
59 if (!status.isOk()) {
60 LOG(ERROR) << "Error getting remotely provisioned component: " << status;
61 return false;
62 }
63 }
64
65 LOG(INFO) << "Connected to Identity Credential HAL with API version " << halApiVersion_
66 << " and name '" << hwInfo_.credentialStoreName << "' authored by '"
67 << hwInfo_.credentialStoreAuthorName << "' with chunk size " << hwInfo_.dataChunkSize
68 << " directoAccess set to " << (hwInfo_.isDirectAccess ? "true" : "false")
69 << " and remote key provisioning support "
70 << (hwInfo_.isRemoteKeyProvisioningSupported ? "enabled" : "disabled");
71 return true;
72 }
73
~CredentialStore()74 CredentialStore::~CredentialStore() {}
75
getSecurityHardwareInfo(SecurityHardwareInfoParcel * _aidl_return)76 Status CredentialStore::getSecurityHardwareInfo(SecurityHardwareInfoParcel* _aidl_return) {
77 SecurityHardwareInfoParcel info;
78 info.directAccess = hwInfo_.isDirectAccess;
79 info.supportedDocTypes = hwInfo_.supportedDocTypes;
80 *_aidl_return = info;
81 return Status::ok();
82 };
83
createCredential(const std::string & credentialName,const std::string & docType,sp<IWritableCredential> * _aidl_return)84 Status CredentialStore::createCredential(const std::string& credentialName,
85 const std::string& docType,
86 sp<IWritableCredential>* _aidl_return) {
87 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
88 optional<bool> credentialExists =
89 CredentialData::credentialExists(dataPath_, callingUid, credentialName);
90 if (!credentialExists.has_value()) {
91 return Status::fromServiceSpecificError(
92 ERROR_GENERIC, "Error determining if credential with given name exists");
93 }
94 if (credentialExists.value()) {
95 return Status::fromServiceSpecificError(ERROR_ALREADY_PERSONALIZED,
96 "Credential with given name already exists");
97 }
98
99 if (hwInfo_.supportedDocTypes.size() > 0) {
100 if (std::find(hwInfo_.supportedDocTypes.begin(), hwInfo_.supportedDocTypes.end(),
101 docType) == hwInfo_.supportedDocTypes.end()) {
102 return Status::fromServiceSpecificError(ERROR_DOCUMENT_TYPE_NOT_SUPPORTED,
103 "No support for given document type");
104 }
105 }
106
107 sp<IWritableIdentityCredential> halWritableCredential;
108 Status status = hal_->createCredential(docType, false, &halWritableCredential);
109 if (!status.isOk()) {
110 return halStatusToGenericError(status);
111 }
112
113 if (hwInfo_.isRemoteKeyProvisioningSupported) {
114 status = setRemotelyProvisionedAttestationKey(halWritableCredential.get());
115 if (!status.isOk()) {
116 LOG(WARNING) << status.toString8()
117 << "\nUnable to fetch remotely provisioned attestation key, falling back "
118 << "to the factory-provisioned attestation key.";
119 }
120 }
121
122 sp<IWritableCredential> writableCredential = new WritableCredential(
123 dataPath_, credentialName, docType, false, hwInfo_, halWritableCredential);
124 *_aidl_return = writableCredential;
125 return Status::ok();
126 }
127
getCredentialCommon(const std::string & credentialName,int32_t cipherSuite,sp<IPresentationSession> halSessionBinder,sp<ICredential> * _aidl_return)128 Status CredentialStore::getCredentialCommon(const std::string& credentialName, int32_t cipherSuite,
129 sp<IPresentationSession> halSessionBinder,
130 sp<ICredential>* _aidl_return) {
131 *_aidl_return = nullptr;
132
133 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
134 optional<bool> credentialExists =
135 CredentialData::credentialExists(dataPath_, callingUid, credentialName);
136 if (!credentialExists.has_value()) {
137 return Status::fromServiceSpecificError(
138 ERROR_GENERIC, "Error determining if credential with given name exists");
139 }
140 if (!credentialExists.value()) {
141 return Status::fromServiceSpecificError(ERROR_NO_SUCH_CREDENTIAL,
142 "Credential with given name doesn't exist");
143 }
144
145 // Note: IdentityCredentialStore.java's CipherSuite enumeration and CipherSuite from the
146 // HAL is manually kept in sync. So this cast is safe.
147 sp<Credential> credential =
148 new Credential(CipherSuite(cipherSuite), dataPath_, credentialName, callingUid, hwInfo_,
149 hal_, halSessionBinder, halApiVersion_);
150
151 Status loadStatus = credential->ensureOrReplaceHalBinder();
152 if (!loadStatus.isOk()) {
153 LOG(ERROR) << "Error loading credential";
154 } else {
155 *_aidl_return = credential;
156 }
157 return loadStatus;
158 }
159
getCredentialByName(const std::string & credentialName,int32_t cipherSuite,sp<ICredential> * _aidl_return)160 Status CredentialStore::getCredentialByName(const std::string& credentialName, int32_t cipherSuite,
161 sp<ICredential>* _aidl_return) {
162 return getCredentialCommon(credentialName, cipherSuite, nullptr, _aidl_return);
163 }
164
createPresentationSession(int32_t cipherSuite,sp<ISession> * _aidl_return)165 Status CredentialStore::createPresentationSession(int32_t cipherSuite, sp<ISession>* _aidl_return) {
166 sp<IPresentationSession> halPresentationSession;
167 Status status =
168 hal_->createPresentationSession(CipherSuite(cipherSuite), &halPresentationSession);
169 if (!status.isOk()) {
170 return halStatusToGenericError(status);
171 }
172
173 *_aidl_return = new Session(cipherSuite, halPresentationSession, this);
174 return Status::ok();
175 }
176
setRemotelyProvisionedAttestationKey(IWritableIdentityCredential * halWritableCredential)177 Status CredentialStore::setRemotelyProvisionedAttestationKey(
178 IWritableIdentityCredential* halWritableCredential) {
179 std::vector<uint8_t> keyBlob;
180 std::vector<uint8_t> encodedCertChain;
181 Status status;
182
183 LOG(INFO) << "Fetching attestation key from RKPD";
184
185 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
186 std::optional<RemotelyProvisionedKey> key = getRpcKey(rpc_, callingUid);
187 if (!key) {
188 return Status::fromServiceSpecificError(
189 ERROR_GENERIC, "Failed to get remotely provisioned attestation key");
190 }
191
192 if (key->keyBlob.empty()) {
193 return Status::fromServiceSpecificError(
194 ERROR_GENERIC, "Remotely provisioned attestation key blob is empty");
195 }
196
197 keyBlob = std::move(key->keyBlob);
198 encodedCertChain = std::move(key->encodedCertChain);
199
200 status = halWritableCredential->setRemotelyProvisionedAttestationKey(keyBlob, encodedCertChain);
201 if (!status.isOk()) {
202 LOG(ERROR) << "Error setting remotely provisioned attestation key on credential";
203 return status;
204 }
205 return Status::ok();
206 }
207
208 } // namespace identity
209 } // namespace security
210 } // namespace android
211