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