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