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