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 <android/security/remoteprovisioning/IRemotelyProvisionedKeyPool.h>
26 #include <android/security/remoteprovisioning/RemotelyProvisionedKey.h>
27 #include <binder/IPCThreadState.h>
28 #include <binder/IServiceManager.h>
29
30 #include "Credential.h"
31 #include "CredentialData.h"
32 #include "CredentialStore.h"
33 #include "Session.h"
34 #include "Util.h"
35 #include "WritableCredential.h"
36
37 namespace android {
38 namespace security {
39 namespace identity {
40 namespace {
41
42 using ::android::hardware::security::keymint::IRemotelyProvisionedComponent;
43 using ::android::hardware::security::keymint::RpcHardwareInfo;
44 using ::android::security::remoteprovisioning::IRemotelyProvisionedKeyPool;
45 using ::android::security::remoteprovisioning::RemotelyProvisionedKey;
46
47 std::optional<std::string>
getRemotelyProvisionedComponentId(const sp<IIdentityCredentialStore> & hal)48 getRemotelyProvisionedComponentId(const sp<IIdentityCredentialStore>& hal) {
49 auto init = [](const sp<IIdentityCredentialStore>& hal) -> std::optional<std::string> {
50 sp<IRemotelyProvisionedComponent> remotelyProvisionedComponent;
51 Status status = hal->getRemotelyProvisionedComponent(&remotelyProvisionedComponent);
52 if (!status.isOk()) {
53 LOG(ERROR) << "Error getting remotely provisioned component: " << status;
54 return std::nullopt;
55 }
56
57 RpcHardwareInfo rpcHwInfo;
58 status = remotelyProvisionedComponent->getHardwareInfo(&rpcHwInfo);
59 if (!status.isOk()) {
60 LOG(ERROR) << "Error getting remotely provisioned component hardware info: " << status;
61 return std::nullopt;
62 }
63
64 if (!rpcHwInfo.uniqueId) {
65 LOG(ERROR) << "Remotely provisioned component is missing a unique id, which is "
66 << "required for credential key remotely provisioned attestation keys. "
67 << "This is a bug in the vendor implementation.";
68 return std::nullopt;
69 }
70
71 // This id is required to later fetch remotely provisioned attestation keys.
72 return *rpcHwInfo.uniqueId;
73 };
74
75 static std::optional<std::string> id = init(hal);
76 return id;
77 }
78
79 } // namespace
80
CredentialStore(const std::string & dataPath,sp<IIdentityCredentialStore> hal)81 CredentialStore::CredentialStore(const std::string& dataPath, sp<IIdentityCredentialStore> hal)
82 : dataPath_(dataPath), hal_(hal) {}
83
init()84 bool CredentialStore::init() {
85 Status status = hal_->getHardwareInformation(&hwInfo_);
86 if (!status.isOk()) {
87 LOG(ERROR) << "Error getting hardware information: " << status.toString8();
88 return false;
89 }
90 halApiVersion_ = hal_->getInterfaceVersion();
91
92 if (hwInfo_.isRemoteKeyProvisioningSupported) {
93 keyPool_ = android::waitForService<IRemotelyProvisionedKeyPool>(
94 IRemotelyProvisionedKeyPool::descriptor);
95 if (keyPool_.get() == nullptr) {
96 LOG(ERROR) << "Error getting IRemotelyProvisionedKeyPool HAL with service name '"
97 << IRemotelyProvisionedKeyPool::descriptor << "'";
98 return false;
99 }
100 }
101
102 LOG(INFO) << "Connected to Identity Credential HAL with API version " << halApiVersion_
103 << " and name '" << hwInfo_.credentialStoreName << "' authored by '"
104 << hwInfo_.credentialStoreAuthorName << "' with chunk size " << hwInfo_.dataChunkSize
105 << " and directoAccess set to " << (hwInfo_.isDirectAccess ? "true" : "false");
106 return true;
107 }
108
~CredentialStore()109 CredentialStore::~CredentialStore() {}
110
getSecurityHardwareInfo(SecurityHardwareInfoParcel * _aidl_return)111 Status CredentialStore::getSecurityHardwareInfo(SecurityHardwareInfoParcel* _aidl_return) {
112 SecurityHardwareInfoParcel info;
113 info.directAccess = hwInfo_.isDirectAccess;
114 info.supportedDocTypes = hwInfo_.supportedDocTypes;
115 *_aidl_return = info;
116 return Status::ok();
117 };
118
createCredential(const std::string & credentialName,const std::string & docType,sp<IWritableCredential> * _aidl_return)119 Status CredentialStore::createCredential(const std::string& credentialName,
120 const std::string& docType,
121 sp<IWritableCredential>* _aidl_return) {
122 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
123 optional<bool> credentialExists =
124 CredentialData::credentialExists(dataPath_, callingUid, credentialName);
125 if (!credentialExists.has_value()) {
126 return Status::fromServiceSpecificError(
127 ERROR_GENERIC, "Error determining if credential with given name exists");
128 }
129 if (credentialExists.value()) {
130 return Status::fromServiceSpecificError(ERROR_ALREADY_PERSONALIZED,
131 "Credential with given name already exists");
132 }
133
134 if (hwInfo_.supportedDocTypes.size() > 0) {
135 if (std::find(hwInfo_.supportedDocTypes.begin(), hwInfo_.supportedDocTypes.end(),
136 docType) == hwInfo_.supportedDocTypes.end()) {
137 return Status::fromServiceSpecificError(ERROR_DOCUMENT_TYPE_NOT_SUPPORTED,
138 "No support for given document type");
139 }
140 }
141
142 sp<IWritableIdentityCredential> halWritableCredential;
143 Status status = hal_->createCredential(docType, false, &halWritableCredential);
144 if (!status.isOk()) {
145 return halStatusToGenericError(status);
146 }
147
148 if (hwInfo_.isRemoteKeyProvisioningSupported) {
149 status = setRemotelyProvisionedAttestationKey(halWritableCredential.get());
150 if (!status.isOk()) {
151 return halStatusToGenericError(status);
152 }
153 }
154
155 sp<IWritableCredential> writableCredential = new WritableCredential(
156 dataPath_, credentialName, docType, false, hwInfo_, halWritableCredential);
157 *_aidl_return = writableCredential;
158 return Status::ok();
159 }
160
getCredentialCommon(const std::string & credentialName,int32_t cipherSuite,sp<IPresentationSession> halSessionBinder,sp<ICredential> * _aidl_return)161 Status CredentialStore::getCredentialCommon(const std::string& credentialName, int32_t cipherSuite,
162 sp<IPresentationSession> halSessionBinder,
163 sp<ICredential>* _aidl_return) {
164 *_aidl_return = nullptr;
165
166 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
167 optional<bool> credentialExists =
168 CredentialData::credentialExists(dataPath_, callingUid, credentialName);
169 if (!credentialExists.has_value()) {
170 return Status::fromServiceSpecificError(
171 ERROR_GENERIC, "Error determining if credential with given name exists");
172 }
173 if (!credentialExists.value()) {
174 return Status::fromServiceSpecificError(ERROR_NO_SUCH_CREDENTIAL,
175 "Credential with given name doesn't exist");
176 }
177
178 // Note: IdentityCredentialStore.java's CipherSuite enumeration and CipherSuite from the
179 // HAL is manually kept in sync. So this cast is safe.
180 sp<Credential> credential =
181 new Credential(CipherSuite(cipherSuite), dataPath_, credentialName, callingUid, hwInfo_,
182 hal_, halSessionBinder, halApiVersion_);
183
184 Status loadStatus = credential->ensureOrReplaceHalBinder();
185 if (!loadStatus.isOk()) {
186 LOG(ERROR) << "Error loading credential";
187 } else {
188 *_aidl_return = credential;
189 }
190 return loadStatus;
191 }
192
getCredentialByName(const std::string & credentialName,int32_t cipherSuite,sp<ICredential> * _aidl_return)193 Status CredentialStore::getCredentialByName(const std::string& credentialName, int32_t cipherSuite,
194 sp<ICredential>* _aidl_return) {
195 return getCredentialCommon(credentialName, cipherSuite, nullptr, _aidl_return);
196 }
197
createPresentationSession(int32_t cipherSuite,sp<ISession> * _aidl_return)198 Status CredentialStore::createPresentationSession(int32_t cipherSuite, sp<ISession>* _aidl_return) {
199 sp<IPresentationSession> halPresentationSession;
200 Status status =
201 hal_->createPresentationSession(CipherSuite(cipherSuite), &halPresentationSession);
202 if (!status.isOk()) {
203 return halStatusToGenericError(status);
204 }
205
206 *_aidl_return = new Session(cipherSuite, halPresentationSession, this);
207 return Status::ok();
208 }
209
setRemotelyProvisionedAttestationKey(IWritableIdentityCredential * halWritableCredential)210 Status CredentialStore::setRemotelyProvisionedAttestationKey(
211 IWritableIdentityCredential* halWritableCredential) {
212 std::optional<std::string> rpcId = getRemotelyProvisionedComponentId(hal_);
213 if (!rpcId) {
214 return Status::fromServiceSpecificError(ERROR_GENERIC,
215 "Error getting remotely provisioned component id");
216 }
217
218 uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
219 RemotelyProvisionedKey key;
220 Status status = keyPool_->getAttestationKey(callingUid, *rpcId, &key);
221 if (!status.isOk()) {
222 LOG(WARNING) << "Unable to fetch remotely provisioned attestation key, falling back "
223 << "to the factory-provisioned attestation key.";
224 return Status::ok();
225 }
226
227 status = halWritableCredential->setRemotelyProvisionedAttestationKey(key.keyBlob,
228 key.encodedCertChain);
229 if (!status.isOk()) {
230 LOG(ERROR) << "Error setting remotely provisioned attestation key on credential";
231 return status;
232 }
233
234 return Status::ok();
235 }
236
237 } // namespace identity
238 } // namespace security
239 } // namespace android
240