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 #include "EicPresentation.h"
18 
19 #include <inttypes.h>
20 
eicPresentationInit(EicPresentation * ctx,bool testCredential,const char * docType,const uint8_t * encryptedCredentialKeys,size_t encryptedCredentialKeysSize)21 bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
22                          const uint8_t* encryptedCredentialKeys,
23                          size_t encryptedCredentialKeysSize) {
24     uint8_t credentialKeys[86];
25     bool expectPopSha256 = false;
26 
27     // For feature version 202009 it's 52 bytes long and for feature version 202101 it's 86
28     // bytes (the additional data is the ProofOfProvisioning SHA-256). We need
29     // to support loading all feature versions.
30     //
31     if (encryptedCredentialKeysSize == 52 + 28) {
32         /* do nothing */
33     } else if (encryptedCredentialKeysSize == 86 + 28) {
34         expectPopSha256 = true;
35     } else {
36         eicDebug("Unexpected size %zd for encryptedCredentialKeys", encryptedCredentialKeysSize);
37         return false;
38     }
39 
40     eicMemSet(ctx, '\0', sizeof(EicPresentation));
41 
42     if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
43                                 encryptedCredentialKeysSize,
44                                 // DocType is the additionalAuthenticatedData
45                                 (const uint8_t*)docType, eicStrLen(docType), credentialKeys)) {
46         eicDebug("Error decrypting CredentialKeys");
47         return false;
48     }
49 
50     // It's supposed to look like this;
51     //
52     // Feature version 202009:
53     //
54     //         CredentialKeys = [
55     //              bstr,   ; storageKey, a 128-bit AES key
56     //              bstr,   ; credentialPrivKey, the private key for credentialKey
57     //         ]
58     //
59     // Feature version 202101:
60     //
61     //         CredentialKeys = [
62     //              bstr,   ; storageKey, a 128-bit AES key
63     //              bstr,   ; credentialPrivKey, the private key for credentialKey
64     //              bstr    ; proofOfProvisioning SHA-256
65     //         ]
66     //
67     // where storageKey is 16 bytes, credentialPrivateKey is 32 bytes, and proofOfProvisioning
68     // SHA-256 is 32 bytes.
69     //
70     if (credentialKeys[0] != (expectPopSha256 ? 0x83 : 0x82) ||  // array of two or three elements
71         credentialKeys[1] != 0x50 ||                             // 16-byte bstr
72         credentialKeys[18] != 0x58 || credentialKeys[19] != 0x20) {  // 32-byte bstr
73         eicDebug("Invalid CBOR for CredentialKeys");
74         return false;
75     }
76     if (expectPopSha256) {
77         if (credentialKeys[52] != 0x58 || credentialKeys[53] != 0x20) {  // 32-byte bstr
78             eicDebug("Invalid CBOR for CredentialKeys");
79             return false;
80         }
81     }
82     eicMemCpy(ctx->storageKey, credentialKeys + 2, EIC_AES_128_KEY_SIZE);
83     eicMemCpy(ctx->credentialPrivateKey, credentialKeys + 20, EIC_P256_PRIV_KEY_SIZE);
84     ctx->testCredential = testCredential;
85     if (expectPopSha256) {
86         eicMemCpy(ctx->proofOfProvisioningSha256, credentialKeys + 54, EIC_SHA256_DIGEST_SIZE);
87     }
88     return true;
89 }
90 
eicPresentationGenerateSigningKeyPair(EicPresentation * ctx,const char * docType,time_t now,uint8_t * publicKeyCert,size_t * publicKeyCertSize,uint8_t signingKeyBlob[60])91 bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* docType, time_t now,
92                                            uint8_t* publicKeyCert, size_t* publicKeyCertSize,
93                                            uint8_t signingKeyBlob[60]) {
94     uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
95     uint8_t signingKeyPub[EIC_P256_PUB_KEY_SIZE];
96     uint8_t cborBuf[64];
97 
98     // Generate the ProofOfBinding CBOR to include in the X.509 certificate in
99     // IdentityCredentialAuthenticationKeyExtension CBOR. This CBOR is defined
100     // by the following CDDL
101     //
102     //   ProofOfBinding = [
103     //     "ProofOfBinding",
104     //     bstr,                  // Contains the SHA-256 of ProofOfProvisioning
105     //   ]
106     //
107     // This array may grow in the future if other information needs to be
108     // conveyed.
109     //
110     // The bytes of ProofOfBinding is is represented as an OCTET_STRING
111     // and stored at OID 1.3.6.1.4.1.11129.2.1.26.
112     //
113 
114     EicCbor cbor;
115     eicCborInit(&cbor, cborBuf, sizeof cborBuf);
116     eicCborAppendArray(&cbor, 2);
117     eicCborAppendString(&cbor, "ProofOfBinding");
118     eicCborAppendByteString(&cbor, ctx->proofOfProvisioningSha256, EIC_SHA256_DIGEST_SIZE);
119     if (cbor.size > sizeof(cborBuf)) {
120         eicDebug("Exceeded buffer size");
121         return false;
122     }
123     const uint8_t* proofOfBinding = cborBuf;
124     size_t proofOfBindingSize = cbor.size;
125 
126     if (!eicOpsCreateEcKey(signingKeyPriv, signingKeyPub)) {
127         eicDebug("Error creating signing key");
128         return false;
129     }
130 
131     const int secondsInOneYear = 365 * 24 * 60 * 60;
132     time_t validityNotBefore = now;
133     time_t validityNotAfter = now + secondsInOneYear;  // One year from now.
134     if (!eicOpsSignEcKey(signingKeyPub, ctx->credentialPrivateKey, 1,
135                          "Android Identity Credential Key",                 // issuer CN
136                          "Android Identity Credential Authentication Key",  // subject CN
137                          validityNotBefore, validityNotAfter, proofOfBinding, proofOfBindingSize,
138                          publicKeyCert, publicKeyCertSize)) {
139         eicDebug("Error creating certificate for signing key");
140         return false;
141     }
142 
143     uint8_t nonce[12];
144     if (!eicOpsRandom(nonce, 12)) {
145         eicDebug("Error getting random");
146         return false;
147     }
148     if (!eicOpsEncryptAes128Gcm(ctx->storageKey, nonce, signingKeyPriv, sizeof(signingKeyPriv),
149                                 // DocType is the additionalAuthenticatedData
150                                 (const uint8_t*)docType, eicStrLen(docType), signingKeyBlob)) {
151         eicDebug("Error encrypting signing key");
152         return false;
153     }
154 
155     return true;
156 }
157 
eicPresentationCreateEphemeralKeyPair(EicPresentation * ctx,uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE])158 bool eicPresentationCreateEphemeralKeyPair(EicPresentation* ctx,
159                                            uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
160     uint8_t ephemeralPublicKey[EIC_P256_PUB_KEY_SIZE];
161     if (!eicOpsCreateEcKey(ctx->ephemeralPrivateKey, ephemeralPublicKey)) {
162         eicDebug("Error creating ephemeral key");
163         return false;
164     }
165     eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
166     return true;
167 }
168 
eicPresentationCreateAuthChallenge(EicPresentation * ctx,uint64_t * authChallenge)169 bool eicPresentationCreateAuthChallenge(EicPresentation* ctx, uint64_t* authChallenge) {
170     do {
171         if (!eicOpsRandom((uint8_t*)&(ctx->authChallenge), sizeof(uint64_t))) {
172             eicDebug("Failed generating random challenge");
173             return false;
174         }
175     } while (ctx->authChallenge == 0);
176     eicDebug("Created auth challenge %" PRIu64, ctx->authChallenge);
177     *authChallenge = ctx->authChallenge;
178     return true;
179 }
180 
181 // From "COSE Algorithms" registry
182 //
183 #define COSE_ALG_ECDSA_256 -7
184 
eicPresentationValidateRequestMessage(EicPresentation * ctx,const uint8_t * sessionTranscript,size_t sessionTranscriptSize,const uint8_t * requestMessage,size_t requestMessageSize,int coseSignAlg,const uint8_t * readerSignatureOfToBeSigned,size_t readerSignatureOfToBeSignedSize)185 bool eicPresentationValidateRequestMessage(EicPresentation* ctx, const uint8_t* sessionTranscript,
186                                            size_t sessionTranscriptSize,
187                                            const uint8_t* requestMessage, size_t requestMessageSize,
188                                            int coseSignAlg,
189                                            const uint8_t* readerSignatureOfToBeSigned,
190                                            size_t readerSignatureOfToBeSignedSize) {
191     if (ctx->readerPublicKeySize == 0) {
192         eicDebug("No public key for reader");
193         return false;
194     }
195 
196     // Right now we only support ECDSA with SHA-256 (e.g. ES256).
197     //
198     if (coseSignAlg != COSE_ALG_ECDSA_256) {
199         eicDebug(
200                 "COSE Signature algorithm for reader signature is %d, "
201                 "only ECDSA with SHA-256 is supported right now",
202                 coseSignAlg);
203         return false;
204     }
205 
206     // What we're going to verify is the COSE ToBeSigned structure which
207     // looks like the following:
208     //
209     //   Sig_structure = [
210     //     context : "Signature" / "Signature1" / "CounterSignature",
211     //     body_protected : empty_or_serialized_map,
212     //     ? sign_protected : empty_or_serialized_map,
213     //     external_aad : bstr,
214     //     payload : bstr
215     //   ]
216     //
217     // So we're going to build that CBOR...
218     //
219     EicCbor cbor;
220     eicCborInit(&cbor, NULL, 0);
221     eicCborAppendArray(&cbor, 4);
222     eicCborAppendString(&cbor, "Signature1");
223 
224     // The COSE Encoded protected headers is just a single field with
225     // COSE_LABEL_ALG (1) -> coseSignAlg (e.g. -7). For simplicitly we just
226     // hard-code the CBOR encoding:
227     static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x26};
228     eicCborAppendByteString(&cbor, coseEncodedProtectedHeaders,
229                             sizeof(coseEncodedProtectedHeaders));
230 
231     // External_aad is the empty bstr
232     static const uint8_t externalAad[0] = {};
233     eicCborAppendByteString(&cbor, externalAad, sizeof(externalAad));
234 
235     // For the payload, the _encoded_ form follows here. We handle this by simply
236     // opening a bstr, and then writing the CBOR. This requires us to know the
237     // size of said bstr, ahead of time... the CBOR to be written is
238     //
239     //   ReaderAuthentication = [
240     //      "ReaderAuthentication",
241     //      SessionTranscript,
242     //      ItemsRequestBytes
243     //   ]
244     //
245     //   ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
246     //
247     //   ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication)
248     //
249     // which is easily calculated below
250     //
251     size_t calculatedSize = 0;
252     calculatedSize += 1;  // Array of size 3
253     calculatedSize += 1;  // "ReaderAuthentication" less than 24 bytes
254     calculatedSize += sizeof("ReaderAuthentication") - 1;  // Don't include trailing NUL
255     calculatedSize += sessionTranscriptSize;               // Already CBOR encoded
256     calculatedSize += 2;  // Semantic tag EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR (24)
257     calculatedSize += 1 + eicCborAdditionalLengthBytesFor(requestMessageSize);
258     calculatedSize += requestMessageSize;
259 
260     // However note that we're authenticating ReaderAuthenticationBytes which
261     // is a tagged bstr of the bytes of ReaderAuthentication. So need to get
262     // that in front.
263     size_t rabCalculatedSize = 0;
264     rabCalculatedSize += 2;  // Semantic tag EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR (24)
265     rabCalculatedSize += 1 + eicCborAdditionalLengthBytesFor(calculatedSize);
266     rabCalculatedSize += calculatedSize;
267 
268     // Begin the bytestring for ReaderAuthenticationBytes;
269     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, rabCalculatedSize);
270 
271     eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
272 
273     // Begins the bytestring for ReaderAuthentication;
274     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
275 
276     // And now that we know the size, let's fill it in...
277     //
278     size_t payloadOffset = cbor.size;
279     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_ARRAY, 3);
280     eicCborAppendString(&cbor, "ReaderAuthentication");
281     eicCborAppend(&cbor, sessionTranscript, sessionTranscriptSize);
282     eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
283     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, requestMessageSize);
284     eicCborAppend(&cbor, requestMessage, requestMessageSize);
285 
286     if (cbor.size != payloadOffset + calculatedSize) {
287         eicDebug("CBOR size is %zd but we expected %zd", cbor.size, payloadOffset + calculatedSize);
288         return false;
289     }
290     uint8_t toBeSignedDigest[EIC_SHA256_DIGEST_SIZE];
291     eicCborFinal(&cbor, toBeSignedDigest);
292 
293     if (!eicOpsEcDsaVerifyWithPublicKey(
294                 toBeSignedDigest, EIC_SHA256_DIGEST_SIZE, readerSignatureOfToBeSigned,
295                 readerSignatureOfToBeSignedSize, ctx->readerPublicKey, ctx->readerPublicKeySize)) {
296         eicDebug("Request message is not signed by public key");
297         return false;
298     }
299     ctx->requestMessageValidated = true;
300     return true;
301 }
302 
303 // Validates the next certificate in the reader certificate chain.
eicPresentationPushReaderCert(EicPresentation * ctx,const uint8_t * certX509,size_t certX509Size)304 bool eicPresentationPushReaderCert(EicPresentation* ctx, const uint8_t* certX509,
305                                    size_t certX509Size) {
306     // If we had a previous certificate, use its public key to validate this certificate.
307     if (ctx->readerPublicKeySize > 0) {
308         if (!eicOpsX509CertSignedByPublicKey(certX509, certX509Size, ctx->readerPublicKey,
309                                              ctx->readerPublicKeySize)) {
310             eicDebug("Certificate is not signed by public key in the previous certificate");
311             return false;
312         }
313     }
314 
315     // Store the key of this certificate, this is used to validate the next certificate
316     // and also ACPs with certificates that use the same public key...
317     ctx->readerPublicKeySize = EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE;
318     if (!eicOpsX509GetPublicKey(certX509, certX509Size, ctx->readerPublicKey,
319                                 &ctx->readerPublicKeySize)) {
320         eicDebug("Error extracting public key from certificate");
321         return false;
322     }
323     if (ctx->readerPublicKeySize == 0) {
324         eicDebug("Zero-length public key in certificate");
325         return false;
326     }
327 
328     return true;
329 }
330 
eicPresentationSetAuthToken(EicPresentation * ctx,uint64_t challenge,uint64_t secureUserId,uint64_t authenticatorId,int hardwareAuthenticatorType,uint64_t timeStamp,const uint8_t * mac,size_t macSize,uint64_t verificationTokenChallenge,uint64_t verificationTokenTimestamp,int verificationTokenSecurityLevel,const uint8_t * verificationTokenMac,size_t verificationTokenMacSize)331 bool eicPresentationSetAuthToken(EicPresentation* ctx, uint64_t challenge, uint64_t secureUserId,
332                                  uint64_t authenticatorId, int hardwareAuthenticatorType,
333                                  uint64_t timeStamp, const uint8_t* mac, size_t macSize,
334                                  uint64_t verificationTokenChallenge,
335                                  uint64_t verificationTokenTimestamp,
336                                  int verificationTokenSecurityLevel,
337                                  const uint8_t* verificationTokenMac,
338                                  size_t verificationTokenMacSize) {
339     // It doesn't make sense to accept any tokens if eicPresentationCreateAuthChallenge()
340     // was never called.
341     if (ctx->authChallenge == 0) {
342         eicDebug("Trying validate tokens when no auth-challenge was previously generated");
343         return false;
344     }
345     // At least the verification-token must have the same challenge as what was generated.
346     if (verificationTokenChallenge != ctx->authChallenge) {
347         eicDebug("Challenge in verification token does not match the challenge "
348                  "previously generated");
349         return false;
350     }
351     if (!eicOpsValidateAuthToken(
352                 challenge, secureUserId, authenticatorId, hardwareAuthenticatorType, timeStamp, mac,
353                 macSize, verificationTokenChallenge, verificationTokenTimestamp,
354                 verificationTokenSecurityLevel, verificationTokenMac, verificationTokenMacSize)) {
355         return false;
356     }
357     ctx->authTokenChallenge = challenge;
358     ctx->authTokenSecureUserId = secureUserId;
359     ctx->authTokenTimestamp = timeStamp;
360     ctx->verificationTokenTimestamp = verificationTokenTimestamp;
361     return true;
362 }
363 
checkUserAuth(EicPresentation * ctx,bool userAuthenticationRequired,int timeoutMillis,uint64_t secureUserId)364 static bool checkUserAuth(EicPresentation* ctx, bool userAuthenticationRequired, int timeoutMillis,
365                           uint64_t secureUserId) {
366     if (!userAuthenticationRequired) {
367         return true;
368     }
369 
370     if (secureUserId != ctx->authTokenSecureUserId) {
371         eicDebug("secureUserId in profile differs from userId in authToken");
372         return false;
373     }
374 
375     // Only ACP with auth-on-every-presentation - those with timeout == 0 - need the
376     // challenge to match...
377     if (timeoutMillis == 0) {
378         if (ctx->authTokenChallenge != ctx->authChallenge) {
379             eicDebug("Challenge in authToken (%" PRIu64
380                      ") doesn't match the challenge "
381                      "that was created (%" PRIu64 ") for this session",
382                      ctx->authTokenChallenge, ctx->authChallenge);
383             return false;
384         }
385     }
386 
387     uint64_t now = ctx->verificationTokenTimestamp;
388     if (ctx->authTokenTimestamp > now) {
389         eicDebug("Timestamp in authToken is in the future");
390         return false;
391     }
392 
393     if (timeoutMillis > 0) {
394         if (now > ctx->authTokenTimestamp + timeoutMillis) {
395             eicDebug("Deadline for authToken is in the past");
396             return false;
397         }
398     }
399 
400     return true;
401 }
402 
checkReaderAuth(EicPresentation * ctx,const uint8_t * readerCertificate,size_t readerCertificateSize)403 static bool checkReaderAuth(EicPresentation* ctx, const uint8_t* readerCertificate,
404                             size_t readerCertificateSize) {
405     uint8_t publicKey[EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE];
406     size_t publicKeySize;
407 
408     if (readerCertificateSize == 0) {
409         return true;
410     }
411 
412     // Remember in this case certificate equality is done by comparing public
413     // keys, not bitwise comparison of the certificates.
414     //
415     publicKeySize = EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE;
416     if (!eicOpsX509GetPublicKey(readerCertificate, readerCertificateSize, publicKey,
417                                 &publicKeySize)) {
418         eicDebug("Error extracting public key from certificate");
419         return false;
420     }
421     if (publicKeySize == 0) {
422         eicDebug("Zero-length public key in certificate");
423         return false;
424     }
425 
426     if ((ctx->readerPublicKeySize != publicKeySize) ||
427         (eicCryptoMemCmp(ctx->readerPublicKey, publicKey, ctx->readerPublicKeySize) != 0)) {
428         return false;
429     }
430     return true;
431 }
432 
433 // Note: This function returns false _only_ if an error occurred check for access, _not_
434 // whether access is granted. Whether access is granted is returned in |accessGranted|.
435 //
eicPresentationValidateAccessControlProfile(EicPresentation * ctx,int id,const uint8_t * readerCertificate,size_t readerCertificateSize,bool userAuthenticationRequired,int timeoutMillis,uint64_t secureUserId,const uint8_t mac[28],bool * accessGranted)436 bool eicPresentationValidateAccessControlProfile(EicPresentation* ctx, int id,
437                                                  const uint8_t* readerCertificate,
438                                                  size_t readerCertificateSize,
439                                                  bool userAuthenticationRequired, int timeoutMillis,
440                                                  uint64_t secureUserId, const uint8_t mac[28],
441                                                  bool* accessGranted) {
442     *accessGranted = false;
443 
444     if (id < 0 || id >= 32) {
445         eicDebug("id value of %d is out of allowed range [0, 32[", id);
446         return false;
447     }
448 
449     // Validate the MAC
450     uint8_t cborBuffer[EIC_MAX_CBOR_SIZE_FOR_ACCESS_CONTROL_PROFILE];
451     EicCbor cborBuilder;
452     eicCborInit(&cborBuilder, cborBuffer, EIC_MAX_CBOR_SIZE_FOR_ACCESS_CONTROL_PROFILE);
453     if (!eicCborCalcAccessControl(&cborBuilder, id, readerCertificate, readerCertificateSize,
454                                   userAuthenticationRequired, timeoutMillis, secureUserId)) {
455         return false;
456     }
457     if (!eicOpsDecryptAes128Gcm(ctx->storageKey, mac, 28, cborBuilder.buffer, cborBuilder.size,
458                                 NULL)) {
459         eicDebug("MAC for AccessControlProfile doesn't match");
460         return false;
461     }
462 
463     bool passedUserAuth =
464             checkUserAuth(ctx, userAuthenticationRequired, timeoutMillis, secureUserId);
465     bool passedReaderAuth = checkReaderAuth(ctx, readerCertificate, readerCertificateSize);
466 
467     ctx->accessControlProfileMaskValidated |= (1 << id);
468     if (readerCertificateSize > 0) {
469         ctx->accessControlProfileMaskUsesReaderAuth |= (1 << id);
470     }
471     if (!passedReaderAuth) {
472         ctx->accessControlProfileMaskFailedReaderAuth |= (1 << id);
473     }
474     if (!passedUserAuth) {
475         ctx->accessControlProfileMaskFailedUserAuth |= (1 << id);
476     }
477 
478     if (passedUserAuth && passedReaderAuth) {
479         *accessGranted = true;
480         eicDebug("Access granted for id %d", id);
481     }
482     return true;
483 }
484 
eicPresentationCalcMacKey(EicPresentation * ctx,const uint8_t * sessionTranscript,size_t sessionTranscriptSize,const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],const uint8_t signingKeyBlob[60],const char * docType,unsigned int numNamespacesWithValues,size_t expectedDeviceNamespacesSize)485 bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
486                                size_t sessionTranscriptSize,
487                                const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
488                                const uint8_t signingKeyBlob[60], const char* docType,
489                                unsigned int numNamespacesWithValues,
490                                size_t expectedDeviceNamespacesSize) {
491     uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
492     if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
493                                 eicStrLen(docType), signingKeyPriv)) {
494         eicDebug("Error decrypting signingKeyBlob");
495         return false;
496     }
497 
498     uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
499     if (!eicOpsEcdh(readerEphemeralPublicKey, signingKeyPriv, sharedSecret)) {
500         eicDebug("ECDH failed");
501         return false;
502     }
503 
504     EicCbor cbor;
505     eicCborInit(&cbor, NULL, 0);
506     eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
507     eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
508     uint8_t salt[EIC_SHA256_DIGEST_SIZE];
509     eicCborFinal(&cbor, salt);
510 
511     const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
512     uint8_t derivedKey[32];
513     if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info, sizeof(info),
514                     derivedKey, sizeof(derivedKey))) {
515         eicDebug("HKDF failed");
516         return false;
517     }
518 
519     eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
520     ctx->buildCbor = true;
521 
522     // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
523     // structure which looks like the following:
524     //
525     // MAC_structure = [
526     //   context : "MAC" / "MAC0",
527     //   protected : empty_or_serialized_map,
528     //   external_aad : bstr,
529     //   payload : bstr
530     // ]
531     //
532     eicCborAppendArray(&ctx->cbor, 4);
533     eicCborAppendString(&ctx->cbor, "MAC0");
534 
535     // The COSE Encoded protected headers is just a single field with
536     // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
537     // hard-code the CBOR encoding:
538     static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
539     eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
540                             sizeof(coseEncodedProtectedHeaders));
541 
542     // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
543     // so external_aad is the empty bstr
544     static const uint8_t externalAad[0] = {};
545     eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
546 
547     // For the payload, the _encoded_ form follows here. We handle this by simply
548     // opening a bstr, and then writing the CBOR. This requires us to know the
549     // size of said bstr, ahead of time... the CBOR to be written is
550     //
551     //   DeviceAuthentication = [
552     //      "DeviceAuthentication",
553     //      SessionTranscript,
554     //      DocType,                ; DocType as used in Documents structure in OfflineResponse
555     //      DeviceNameSpacesBytes
556     //   ]
557     //
558     //   DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
559     //
560     //   DeviceAuthenticationBytes = #6.24(bstr .cbor DeviceAuthentication)
561     //
562     // which is easily calculated below
563     //
564     size_t calculatedSize = 0;
565     calculatedSize += 1;  // Array of size 4
566     calculatedSize += 1;  // "DeviceAuthentication" less than 24 bytes
567     calculatedSize += sizeof("DeviceAuthentication") - 1;  // Don't include trailing NUL
568     calculatedSize += sessionTranscriptSize;               // Already CBOR encoded
569     size_t docTypeLen = eicStrLen(docType);
570     calculatedSize += 1 + eicCborAdditionalLengthBytesFor(docTypeLen) + docTypeLen;
571     calculatedSize += 2;  // Semantic tag EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR (24)
572     calculatedSize += 1 + eicCborAdditionalLengthBytesFor(expectedDeviceNamespacesSize);
573     calculatedSize += expectedDeviceNamespacesSize;
574 
575     // However note that we're authenticating DeviceAuthenticationBytes which
576     // is a tagged bstr of the bytes of DeviceAuthentication. So need to get
577     // that in front.
578     size_t dabCalculatedSize = 0;
579     dabCalculatedSize += 2;  // Semantic tag EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR (24)
580     dabCalculatedSize += 1 + eicCborAdditionalLengthBytesFor(calculatedSize);
581     dabCalculatedSize += calculatedSize;
582 
583     // Begin the bytestring for DeviceAuthenticationBytes;
584     eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
585 
586     eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
587 
588     // Begins the bytestring for DeviceAuthentication;
589     eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
590 
591     eicCborAppendArray(&ctx->cbor, 4);
592     eicCborAppendString(&ctx->cbor, "DeviceAuthentication");
593     eicCborAppend(&ctx->cbor, sessionTranscript, sessionTranscriptSize);
594     eicCborAppendString(&ctx->cbor, docType);
595 
596     // For the payload, the _encoded_ form follows here. We handle this by simply
597     // opening a bstr, and then writing the CBOR. This requires us to know the
598     // size of said bstr, ahead of time.
599     eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
600     eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
601     ctx->expectedCborSizeAtEnd = expectedDeviceNamespacesSize + ctx->cbor.size;
602 
603     eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
604     return true;
605 }
606 
eicPresentationStartRetrieveEntries(EicPresentation * ctx)607 bool eicPresentationStartRetrieveEntries(EicPresentation* ctx) {
608     // HAL may use this object multiple times to retrieve data so need to reset various
609     // state objects here.
610     ctx->requestMessageValidated = false;
611     ctx->buildCbor = false;
612     ctx->accessControlProfileMaskValidated = 0;
613     ctx->accessControlProfileMaskUsesReaderAuth = 0;
614     ctx->accessControlProfileMaskFailedReaderAuth = 0;
615     ctx->accessControlProfileMaskFailedUserAuth = 0;
616     ctx->readerPublicKeySize = 0;
617     return true;
618 }
619 
eicPresentationStartRetrieveEntryValue(EicPresentation * ctx,const char * nameSpace,const char * name,unsigned int newNamespaceNumEntries,int32_t,const int * accessControlProfileIds,size_t numAccessControlProfileIds,uint8_t * scratchSpace,size_t scratchSpaceSize)620 EicAccessCheckResult eicPresentationStartRetrieveEntryValue(
621         EicPresentation* ctx, const char* nameSpace, const char* name,
622         unsigned int newNamespaceNumEntries, int32_t /* entrySize */,
623         const int* accessControlProfileIds, size_t numAccessControlProfileIds,
624         uint8_t* scratchSpace, size_t scratchSpaceSize) {
625     uint8_t* additionalDataCbor = scratchSpace;
626     const size_t additionalDataCborBufSize = scratchSpaceSize;
627     size_t additionalDataCborSize;
628 
629     if (newNamespaceNumEntries > 0) {
630         eicCborAppendString(&ctx->cbor, nameSpace);
631         eicCborAppendMap(&ctx->cbor, newNamespaceNumEntries);
632     }
633 
634     // We'll need to calc and store a digest of additionalData to check that it's the same
635     // additionalData being passed in for every eicPresentationRetrieveEntryValue() call...
636     //
637     ctx->accessCheckOk = false;
638     if (!eicCborCalcEntryAdditionalData(accessControlProfileIds, numAccessControlProfileIds,
639                                         nameSpace, name, additionalDataCbor,
640                                         additionalDataCborBufSize, &additionalDataCborSize,
641                                         ctx->additionalDataSha256)) {
642         return EIC_ACCESS_CHECK_RESULT_FAILED;
643     }
644 
645     if (numAccessControlProfileIds == 0) {
646         return EIC_ACCESS_CHECK_RESULT_NO_ACCESS_CONTROL_PROFILES;
647     }
648 
649     // Access is granted if at least one of the profiles grants access.
650     //
651     // If an item is configured without any profiles, access is denied.
652     //
653     EicAccessCheckResult result = EIC_ACCESS_CHECK_RESULT_FAILED;
654     for (size_t n = 0; n < numAccessControlProfileIds; n++) {
655         int id = accessControlProfileIds[n];
656         uint32_t idBitMask = (1 << id);
657 
658         // If the access control profile wasn't validated, this is an error and we
659         // fail immediately.
660         bool validated = ((ctx->accessControlProfileMaskValidated & idBitMask) != 0);
661         if (!validated) {
662             eicDebug("No ACP for profile id %d", id);
663             return EIC_ACCESS_CHECK_RESULT_FAILED;
664         }
665 
666         // Otherwise, we _did_ validate the profile. If none of the checks
667         // failed, we're done
668         bool failedUserAuth = ((ctx->accessControlProfileMaskFailedUserAuth & idBitMask) != 0);
669         bool failedReaderAuth = ((ctx->accessControlProfileMaskFailedReaderAuth & idBitMask) != 0);
670         if (!failedUserAuth && !failedReaderAuth) {
671             result = EIC_ACCESS_CHECK_RESULT_OK;
672             break;
673         }
674         // One of the checks failed, convey which one
675         if (failedUserAuth) {
676             result = EIC_ACCESS_CHECK_RESULT_USER_AUTHENTICATION_FAILED;
677         } else {
678             result = EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED;
679         }
680     }
681     eicDebug("Result %d for name %s", result, name);
682 
683     if (result == EIC_ACCESS_CHECK_RESULT_OK) {
684         eicCborAppendString(&ctx->cbor, name);
685         ctx->accessCheckOk = true;
686     }
687     return result;
688 }
689 
690 // Note: |content| must be big enough to hold |encryptedContentSize| - 28 bytes.
eicPresentationRetrieveEntryValue(EicPresentation * ctx,const uint8_t * encryptedContent,size_t encryptedContentSize,uint8_t * content,const char * nameSpace,const char * name,const int * accessControlProfileIds,size_t numAccessControlProfileIds,uint8_t * scratchSpace,size_t scratchSpaceSize)691 bool eicPresentationRetrieveEntryValue(EicPresentation* ctx, const uint8_t* encryptedContent,
692                                        size_t encryptedContentSize, uint8_t* content,
693                                        const char* nameSpace, const char* name,
694                                        const int* accessControlProfileIds,
695                                        size_t numAccessControlProfileIds, uint8_t* scratchSpace,
696                                        size_t scratchSpaceSize) {
697     uint8_t* additionalDataCbor = scratchSpace;
698     const size_t additionalDataCborBufSize = scratchSpaceSize;
699     size_t additionalDataCborSize;
700 
701     uint8_t calculatedSha256[EIC_SHA256_DIGEST_SIZE];
702     if (!eicCborCalcEntryAdditionalData(accessControlProfileIds, numAccessControlProfileIds,
703                                         nameSpace, name, additionalDataCbor,
704                                         additionalDataCborBufSize, &additionalDataCborSize,
705                                         calculatedSha256)) {
706         return false;
707     }
708 
709     if (eicCryptoMemCmp(calculatedSha256, ctx->additionalDataSha256, EIC_SHA256_DIGEST_SIZE) != 0) {
710         eicDebug("SHA-256 mismatch of additionalData");
711         return false;
712     }
713     if (!ctx->accessCheckOk) {
714         eicDebug("Attempting to retrieve a value for which access is not granted");
715         return false;
716     }
717 
718     if (!eicOpsDecryptAes128Gcm(ctx->storageKey, encryptedContent, encryptedContentSize,
719                                 additionalDataCbor, additionalDataCborSize, content)) {
720         eicDebug("Error decrypting content");
721         return false;
722     }
723 
724     eicCborAppend(&ctx->cbor, content, encryptedContentSize - 28);
725 
726     return true;
727 }
728 
eicPresentationFinishRetrieval(EicPresentation * ctx,uint8_t * digestToBeMaced,size_t * digestToBeMacedSize)729 bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMaced,
730                                     size_t* digestToBeMacedSize) {
731     if (!ctx->buildCbor) {
732         *digestToBeMacedSize = 0;
733         return true;
734     }
735     if (*digestToBeMacedSize != 32) {
736         return false;
737     }
738 
739     // This verifies that the correct expectedDeviceNamespacesSize value was
740     // passed in at eicPresentationCalcMacKey() time.
741     if (ctx->cbor.size != ctx->expectedCborSizeAtEnd) {
742         eicDebug("CBOR size is %zd, was expecting %zd", ctx->cbor.size, ctx->expectedCborSizeAtEnd);
743         return false;
744     }
745     eicCborFinal(&ctx->cbor, digestToBeMaced);
746     return true;
747 }
748 
eicPresentationDeleteCredential(EicPresentation * ctx,const char * docType,const uint8_t * challenge,size_t challengeSize,bool includeChallenge,size_t proofOfDeletionCborSize,uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE])749 bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType,
750                                      const uint8_t* challenge, size_t challengeSize,
751                                      bool includeChallenge, size_t proofOfDeletionCborSize,
752                                      uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]) {
753     EicCbor cbor;
754 
755     eicCborInit(&cbor, NULL, 0);
756 
757     // What we're going to sign is the COSE ToBeSigned structure which
758     // looks like the following:
759     //
760     // Sig_structure = [
761     //   context : "Signature" / "Signature1" / "CounterSignature",
762     //   body_protected : empty_or_serialized_map,
763     //   ? sign_protected : empty_or_serialized_map,
764     //   external_aad : bstr,
765     //   payload : bstr
766     //  ]
767     //
768     eicCborAppendArray(&cbor, 4);
769     eicCborAppendString(&cbor, "Signature1");
770 
771     // The COSE Encoded protected headers is just a single field with
772     // COSE_LABEL_ALG (1) -> COSE_ALG_ECSDA_256 (-7). For simplicitly we just
773     // hard-code the CBOR encoding:
774     static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x26};
775     eicCborAppendByteString(&cbor, coseEncodedProtectedHeaders,
776                             sizeof(coseEncodedProtectedHeaders));
777 
778     // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
779     // so external_aad is the empty bstr
780     static const uint8_t externalAad[0] = {};
781     eicCborAppendByteString(&cbor, externalAad, sizeof(externalAad));
782 
783     // For the payload, the _encoded_ form follows here. We handle this by simply
784     // opening a bstr, and then writing the CBOR. This requires us to know the
785     // size of said bstr, ahead of time.
786     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, proofOfDeletionCborSize);
787 
788     // Finally, the CBOR that we're actually signing.
789     eicCborAppendArray(&cbor, includeChallenge ? 4 : 3);
790     eicCborAppendString(&cbor, "ProofOfDeletion");
791     eicCborAppendString(&cbor, docType);
792     if (includeChallenge) {
793         eicCborAppendByteString(&cbor, challenge, challengeSize);
794     }
795     eicCborAppendBool(&cbor, ctx->testCredential);
796 
797     uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
798     eicCborFinal(&cbor, cborSha256);
799     if (!eicOpsEcDsa(ctx->credentialPrivateKey, cborSha256, signatureOfToBeSigned)) {
800         eicDebug("Error signing proofOfDeletion");
801         return false;
802     }
803 
804     return true;
805 }
806 
eicPresentationProveOwnership(EicPresentation * ctx,const char * docType,bool testCredential,const uint8_t * challenge,size_t challengeSize,size_t proofOfOwnershipCborSize,uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE])807 bool eicPresentationProveOwnership(EicPresentation* ctx, const char* docType, bool testCredential,
808                                    const uint8_t* challenge, size_t challengeSize,
809                                    size_t proofOfOwnershipCborSize,
810                                    uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]) {
811     EicCbor cbor;
812 
813     eicCborInit(&cbor, NULL, 0);
814 
815     // What we're going to sign is the COSE ToBeSigned structure which
816     // looks like the following:
817     //
818     // Sig_structure = [
819     //   context : "Signature" / "Signature1" / "CounterSignature",
820     //   body_protected : empty_or_serialized_map,
821     //   ? sign_protected : empty_or_serialized_map,
822     //   external_aad : bstr,
823     //   payload : bstr
824     //  ]
825     //
826     eicCborAppendArray(&cbor, 4);
827     eicCborAppendString(&cbor, "Signature1");
828 
829     // The COSE Encoded protected headers is just a single field with
830     // COSE_LABEL_ALG (1) -> COSE_ALG_ECSDA_256 (-7). For simplicitly we just
831     // hard-code the CBOR encoding:
832     static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x26};
833     eicCborAppendByteString(&cbor, coseEncodedProtectedHeaders,
834                             sizeof(coseEncodedProtectedHeaders));
835 
836     // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
837     // so external_aad is the empty bstr
838     static const uint8_t externalAad[0] = {};
839     eicCborAppendByteString(&cbor, externalAad, sizeof(externalAad));
840 
841     // For the payload, the _encoded_ form follows here. We handle this by simply
842     // opening a bstr, and then writing the CBOR. This requires us to know the
843     // size of said bstr, ahead of time.
844     eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, proofOfOwnershipCborSize);
845 
846     // Finally, the CBOR that we're actually signing.
847     eicCborAppendArray(&cbor, 4);
848     eicCborAppendString(&cbor, "ProofOfOwnership");
849     eicCborAppendString(&cbor, docType);
850     eicCborAppendByteString(&cbor, challenge, challengeSize);
851     eicCborAppendBool(&cbor, testCredential);
852 
853     uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
854     eicCborFinal(&cbor, cborSha256);
855     if (!eicOpsEcDsa(ctx->credentialPrivateKey, cborSha256, signatureOfToBeSigned)) {
856         eicDebug("Error signing proofOfDeletion");
857         return false;
858     }
859 
860     return true;
861 }
862