1 /*
2 * Copyright 2020, 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 "FakeSecureHardwareProxy"
18
19 #include "FakeSecureHardwareProxy.h"
20
21 #include <android/hardware/identity/support/IdentityCredentialSupport.h>
22
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <string.h>
26
27 #include <openssl/sha.h>
28
29 #include <openssl/aes.h>
30 #include <openssl/bn.h>
31 #include <openssl/crypto.h>
32 #include <openssl/ec.h>
33 #include <openssl/err.h>
34 #include <openssl/evp.h>
35 #include <openssl/hkdf.h>
36 #include <openssl/hmac.h>
37 #include <openssl/objects.h>
38 #include <openssl/pem.h>
39 #include <openssl/pkcs12.h>
40 #include <openssl/rand.h>
41 #include <openssl/x509.h>
42 #include <openssl/x509_vfy.h>
43
44 #include <libeic.h>
45
46 using ::std::optional;
47 using ::std::string;
48 using ::std::tuple;
49 using ::std::vector;
50
51 namespace android::hardware::identity {
52
53 // ----------------------------------------------------------------------
54
FakeSecureHardwareProvisioningProxy()55 FakeSecureHardwareProvisioningProxy::FakeSecureHardwareProvisioningProxy() {}
56
~FakeSecureHardwareProvisioningProxy()57 FakeSecureHardwareProvisioningProxy::~FakeSecureHardwareProvisioningProxy() {}
58
shutdown()59 bool FakeSecureHardwareProvisioningProxy::shutdown() {
60 LOG(INFO) << "FakeSecureHardwarePresentationProxy shutdown";
61 return true;
62 }
63
initialize(bool testCredential)64 bool FakeSecureHardwareProvisioningProxy::initialize(bool testCredential) {
65 LOG(INFO) << "FakeSecureHardwareProvisioningProxy created, sizeof(EicProvisioning): "
66 << sizeof(EicProvisioning);
67 return eicProvisioningInit(&ctx_, testCredential);
68 }
69
initializeForUpdate(bool testCredential,string docType,vector<uint8_t> encryptedCredentialKeys)70 bool FakeSecureHardwareProvisioningProxy::initializeForUpdate(
71 bool testCredential, string docType, vector<uint8_t> encryptedCredentialKeys) {
72 return eicProvisioningInitForUpdate(&ctx_, testCredential, docType.c_str(),
73 encryptedCredentialKeys.data(),
74 encryptedCredentialKeys.size());
75 }
76
77 // Returns public key certificate.
createCredentialKey(const vector<uint8_t> & challenge,const vector<uint8_t> & applicationId)78 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::createCredentialKey(
79 const vector<uint8_t>& challenge, const vector<uint8_t>& applicationId) {
80 uint8_t publicKeyCert[4096];
81 size_t publicKeyCertSize = sizeof publicKeyCert;
82 if (!eicProvisioningCreateCredentialKey(&ctx_, challenge.data(), challenge.size(),
83 applicationId.data(), applicationId.size(),
84 publicKeyCert, &publicKeyCertSize)) {
85 return {};
86 }
87 vector<uint8_t> pubKeyCert(publicKeyCertSize);
88 memcpy(pubKeyCert.data(), publicKeyCert, publicKeyCertSize);
89 return pubKeyCert;
90 }
91
startPersonalization(int accessControlProfileCount,vector<int> entryCounts,const string & docType,size_t expectedProofOfProvisioningSize)92 bool FakeSecureHardwareProvisioningProxy::startPersonalization(
93 int accessControlProfileCount, vector<int> entryCounts, const string& docType,
94 size_t expectedProofOfProvisioningSize) {
95 if (!eicProvisioningStartPersonalization(&ctx_, accessControlProfileCount, entryCounts.data(),
96 entryCounts.size(), docType.c_str(),
97 expectedProofOfProvisioningSize)) {
98 return false;
99 }
100 return true;
101 }
102
103 // Returns MAC (28 bytes).
addAccessControlProfile(int id,const vector<uint8_t> & readerCertificate,bool userAuthenticationRequired,uint64_t timeoutMillis,uint64_t secureUserId)104 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::addAccessControlProfile(
105 int id, const vector<uint8_t>& readerCertificate, bool userAuthenticationRequired,
106 uint64_t timeoutMillis, uint64_t secureUserId) {
107 vector<uint8_t> mac(28);
108 if (!eicProvisioningAddAccessControlProfile(
109 &ctx_, id, readerCertificate.data(), readerCertificate.size(),
110 userAuthenticationRequired, timeoutMillis, secureUserId, mac.data())) {
111 return {};
112 }
113 return mac;
114 }
115
beginAddEntry(const vector<int> & accessControlProfileIds,const string & nameSpace,const string & name,uint64_t entrySize)116 bool FakeSecureHardwareProvisioningProxy::beginAddEntry(const vector<int>& accessControlProfileIds,
117 const string& nameSpace, const string& name,
118 uint64_t entrySize) {
119 uint8_t scratchSpace[512];
120 return eicProvisioningBeginAddEntry(&ctx_, accessControlProfileIds.data(),
121 accessControlProfileIds.size(), nameSpace.c_str(),
122 name.c_str(), entrySize, scratchSpace, sizeof scratchSpace);
123 }
124
125 // Returns encryptedContent.
addEntryValue(const vector<int> & accessControlProfileIds,const string & nameSpace,const string & name,const vector<uint8_t> & content)126 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::addEntryValue(
127 const vector<int>& accessControlProfileIds, const string& nameSpace, const string& name,
128 const vector<uint8_t>& content) {
129 vector<uint8_t> eicEncryptedContent;
130 uint8_t scratchSpace[512];
131 eicEncryptedContent.resize(content.size() + 28);
132 if (!eicProvisioningAddEntryValue(
133 &ctx_, accessControlProfileIds.data(), accessControlProfileIds.size(),
134 nameSpace.c_str(), name.c_str(), content.data(), content.size(),
135 eicEncryptedContent.data(), scratchSpace, sizeof scratchSpace)) {
136 return {};
137 }
138 return eicEncryptedContent;
139 }
140
141 // Returns signatureOfToBeSigned (EIC_ECDSA_P256_SIGNATURE_SIZE bytes).
finishAddingEntries()142 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::finishAddingEntries() {
143 vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
144 if (!eicProvisioningFinishAddingEntries(&ctx_, signatureOfToBeSigned.data())) {
145 return {};
146 }
147 return signatureOfToBeSigned;
148 }
149
150 // Returns encryptedCredentialKeys.
finishGetCredentialData(const string & docType)151 optional<vector<uint8_t>> FakeSecureHardwareProvisioningProxy::finishGetCredentialData(
152 const string& docType) {
153 vector<uint8_t> encryptedCredentialKeys(116);
154 size_t size = encryptedCredentialKeys.size();
155 if (!eicProvisioningFinishGetCredentialData(&ctx_, docType.c_str(),
156 encryptedCredentialKeys.data(), &size)) {
157 return {};
158 }
159 encryptedCredentialKeys.resize(size);
160 return encryptedCredentialKeys;
161 }
162
163 // ----------------------------------------------------------------------
164
FakeSecureHardwarePresentationProxy()165 FakeSecureHardwarePresentationProxy::FakeSecureHardwarePresentationProxy() {}
166
~FakeSecureHardwarePresentationProxy()167 FakeSecureHardwarePresentationProxy::~FakeSecureHardwarePresentationProxy() {}
168
initialize(bool testCredential,string docType,vector<uint8_t> encryptedCredentialKeys)169 bool FakeSecureHardwarePresentationProxy::initialize(bool testCredential, string docType,
170 vector<uint8_t> encryptedCredentialKeys) {
171 LOG(INFO) << "FakeSecureHardwarePresentationProxy created, sizeof(EicPresentation): "
172 << sizeof(EicPresentation);
173 return eicPresentationInit(&ctx_, testCredential, docType.c_str(),
174 encryptedCredentialKeys.data(), encryptedCredentialKeys.size());
175 }
176
177 // Returns publicKeyCert (1st component) and signingKeyBlob (2nd component)
178 optional<pair<vector<uint8_t>, vector<uint8_t>>>
generateSigningKeyPair(string docType,time_t now)179 FakeSecureHardwarePresentationProxy::generateSigningKeyPair(string docType, time_t now) {
180 uint8_t publicKeyCert[512];
181 size_t publicKeyCertSize = sizeof(publicKeyCert);
182 vector<uint8_t> signingKeyBlob(60);
183
184 if (!eicPresentationGenerateSigningKeyPair(&ctx_, docType.c_str(), now, publicKeyCert,
185 &publicKeyCertSize, signingKeyBlob.data())) {
186 return {};
187 }
188
189 vector<uint8_t> cert;
190 cert.resize(publicKeyCertSize);
191 memcpy(cert.data(), publicKeyCert, publicKeyCertSize);
192
193 return std::make_pair(cert, signingKeyBlob);
194 }
195
196 // Returns private key
createEphemeralKeyPair()197 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::createEphemeralKeyPair() {
198 vector<uint8_t> priv(EIC_P256_PRIV_KEY_SIZE);
199 if (!eicPresentationCreateEphemeralKeyPair(&ctx_, priv.data())) {
200 return {};
201 }
202 return priv;
203 }
204
createAuthChallenge()205 optional<uint64_t> FakeSecureHardwarePresentationProxy::createAuthChallenge() {
206 uint64_t challenge;
207 if (!eicPresentationCreateAuthChallenge(&ctx_, &challenge)) {
208 return {};
209 }
210 return challenge;
211 }
212
shutdown()213 bool FakeSecureHardwarePresentationProxy::shutdown() {
214 LOG(INFO) << "FakeSecureHardwarePresentationProxy shutdown";
215 return true;
216 }
217
pushReaderCert(const vector<uint8_t> & certX509)218 bool FakeSecureHardwarePresentationProxy::pushReaderCert(const vector<uint8_t>& certX509) {
219 return eicPresentationPushReaderCert(&ctx_, certX509.data(), certX509.size());
220 }
221
validateRequestMessage(const vector<uint8_t> & sessionTranscript,const vector<uint8_t> & requestMessage,int coseSignAlg,const vector<uint8_t> & readerSignatureOfToBeSigned)222 bool FakeSecureHardwarePresentationProxy::validateRequestMessage(
223 const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& requestMessage,
224 int coseSignAlg, const vector<uint8_t>& readerSignatureOfToBeSigned) {
225 return eicPresentationValidateRequestMessage(
226 &ctx_, sessionTranscript.data(), sessionTranscript.size(), requestMessage.data(),
227 requestMessage.size(), coseSignAlg, readerSignatureOfToBeSigned.data(),
228 readerSignatureOfToBeSigned.size());
229 }
230
setAuthToken(uint64_t challenge,uint64_t secureUserId,uint64_t authenticatorId,int hardwareAuthenticatorType,uint64_t timeStamp,const vector<uint8_t> & mac,uint64_t verificationTokenChallenge,uint64_t verificationTokenTimestamp,int verificationTokenSecurityLevel,const vector<uint8_t> & verificationTokenMac)231 bool FakeSecureHardwarePresentationProxy::setAuthToken(
232 uint64_t challenge, uint64_t secureUserId, uint64_t authenticatorId,
233 int hardwareAuthenticatorType, uint64_t timeStamp, const vector<uint8_t>& mac,
234 uint64_t verificationTokenChallenge, uint64_t verificationTokenTimestamp,
235 int verificationTokenSecurityLevel, const vector<uint8_t>& verificationTokenMac) {
236 return eicPresentationSetAuthToken(&ctx_, challenge, secureUserId, authenticatorId,
237 hardwareAuthenticatorType, timeStamp, mac.data(), mac.size(),
238 verificationTokenChallenge, verificationTokenTimestamp,
239 verificationTokenSecurityLevel, verificationTokenMac.data(),
240 verificationTokenMac.size());
241 }
242
validateAccessControlProfile(int id,const vector<uint8_t> & readerCertificate,bool userAuthenticationRequired,int timeoutMillis,uint64_t secureUserId,const vector<uint8_t> & mac)243 optional<bool> FakeSecureHardwarePresentationProxy::validateAccessControlProfile(
244 int id, const vector<uint8_t>& readerCertificate, bool userAuthenticationRequired,
245 int timeoutMillis, uint64_t secureUserId, const vector<uint8_t>& mac) {
246 bool accessGranted = false;
247 if (!eicPresentationValidateAccessControlProfile(&ctx_, id, readerCertificate.data(),
248 readerCertificate.size(),
249 userAuthenticationRequired, timeoutMillis,
250 secureUserId, mac.data(), &accessGranted)) {
251 return {};
252 }
253 return accessGranted;
254 }
255
startRetrieveEntries()256 bool FakeSecureHardwarePresentationProxy::startRetrieveEntries() {
257 return eicPresentationStartRetrieveEntries(&ctx_);
258 }
259
calcMacKey(const vector<uint8_t> & sessionTranscript,const vector<uint8_t> & readerEphemeralPublicKey,const vector<uint8_t> & signingKeyBlob,const string & docType,unsigned int numNamespacesWithValues,size_t expectedProofOfProvisioningSize)260 bool FakeSecureHardwarePresentationProxy::calcMacKey(
261 const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& readerEphemeralPublicKey,
262 const vector<uint8_t>& signingKeyBlob, const string& docType,
263 unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) {
264 if (signingKeyBlob.size() != 60) {
265 eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size());
266 return false;
267 }
268 return eicPresentationCalcMacKey(&ctx_, sessionTranscript.data(), sessionTranscript.size(),
269 readerEphemeralPublicKey.data(), signingKeyBlob.data(),
270 docType.c_str(), numNamespacesWithValues,
271 expectedProofOfProvisioningSize);
272 }
273
startRetrieveEntryValue(const string & nameSpace,const string & name,unsigned int newNamespaceNumEntries,int32_t entrySize,const vector<int32_t> & accessControlProfileIds)274 AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue(
275 const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
276 int32_t entrySize, const vector<int32_t>& accessControlProfileIds) {
277 uint8_t scratchSpace[512];
278 EicAccessCheckResult result = eicPresentationStartRetrieveEntryValue(
279 &ctx_, nameSpace.c_str(), name.c_str(), newNamespaceNumEntries, entrySize,
280 accessControlProfileIds.data(), accessControlProfileIds.size(), scratchSpace,
281 sizeof scratchSpace);
282 switch (result) {
283 case EIC_ACCESS_CHECK_RESULT_OK:
284 return AccessCheckResult::kOk;
285 case EIC_ACCESS_CHECK_RESULT_NO_ACCESS_CONTROL_PROFILES:
286 return AccessCheckResult::kNoAccessControlProfiles;
287 case EIC_ACCESS_CHECK_RESULT_FAILED:
288 return AccessCheckResult::kFailed;
289 case EIC_ACCESS_CHECK_RESULT_USER_AUTHENTICATION_FAILED:
290 return AccessCheckResult::kUserAuthenticationFailed;
291 case EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED:
292 return AccessCheckResult::kReaderAuthenticationFailed;
293 }
294 eicDebug("Unknown result with code %d, returning kFailed", (int)result);
295 return AccessCheckResult::kFailed;
296 }
297
retrieveEntryValue(const vector<uint8_t> & encryptedContent,const string & nameSpace,const string & name,const vector<int32_t> & accessControlProfileIds)298 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::retrieveEntryValue(
299 const vector<uint8_t>& encryptedContent, const string& nameSpace, const string& name,
300 const vector<int32_t>& accessControlProfileIds) {
301 uint8_t scratchSpace[512];
302 vector<uint8_t> content;
303 content.resize(encryptedContent.size() - 28);
304 if (!eicPresentationRetrieveEntryValue(
305 &ctx_, encryptedContent.data(), encryptedContent.size(), content.data(),
306 nameSpace.c_str(), name.c_str(), accessControlProfileIds.data(),
307 accessControlProfileIds.size(), scratchSpace, sizeof scratchSpace)) {
308 return {};
309 }
310 return content;
311 }
312
finishRetrieval()313 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::finishRetrieval() {
314 vector<uint8_t> mac(32);
315 size_t macSize = 32;
316 if (!eicPresentationFinishRetrieval(&ctx_, mac.data(), &macSize)) {
317 return {};
318 }
319 mac.resize(macSize);
320 return mac;
321 }
322
deleteCredential(const string & docType,const vector<uint8_t> & challenge,bool includeChallenge,size_t proofOfDeletionCborSize)323 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::deleteCredential(
324 const string& docType, const vector<uint8_t>& challenge, bool includeChallenge,
325 size_t proofOfDeletionCborSize) {
326 vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
327 if (!eicPresentationDeleteCredential(&ctx_, docType.c_str(), challenge.data(), challenge.size(),
328 includeChallenge, proofOfDeletionCborSize,
329 signatureOfToBeSigned.data())) {
330 return {};
331 }
332 return signatureOfToBeSigned;
333 }
334
proveOwnership(const string & docType,bool testCredential,const vector<uint8_t> & challenge,size_t proofOfOwnershipCborSize)335 optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::proveOwnership(
336 const string& docType, bool testCredential, const vector<uint8_t>& challenge,
337 size_t proofOfOwnershipCborSize) {
338 vector<uint8_t> signatureOfToBeSigned(EIC_ECDSA_P256_SIGNATURE_SIZE);
339 if (!eicPresentationProveOwnership(&ctx_, docType.c_str(), testCredential, challenge.data(),
340 challenge.size(), proofOfOwnershipCborSize,
341 signatureOfToBeSigned.data())) {
342 return {};
343 }
344 return signatureOfToBeSigned;
345 }
346
347 } // namespace android::hardware::identity
348