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