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