identity: Add multi-document presentation support.
This new IPresentationSession interface enables an application to do a
multi-document presentation, something which isn't possible with the
existing API. As a practical example of this consider presenting both
your Mobile Driving License and your Vaccination Certificate in a single
transaction.
Bug: 197965513
Test: New CTS tests and new screen in CtsVerifier
Change-Id: I11712dca35df7f1224debf454731bc17ea9bfb37
diff --git a/identity/aidl/default/libeic/EicCommon.h b/identity/aidl/default/libeic/EicCommon.h
index 476276e..2a08a35 100644
--- a/identity/aidl/default/libeic/EicCommon.h
+++ b/identity/aidl/default/libeic/EicCommon.h
@@ -21,6 +21,9 @@
#ifndef ANDROID_HARDWARE_IDENTITY_EIC_COMMON_H
#define ANDROID_HARDWARE_IDENTITY_EIC_COMMON_H
+// KeyMint auth-challenges are 64-bit numbers and 0 typically means unset.
+#define EIC_KM_AUTH_CHALLENGE_UNSET 0
+
// Feature version 202009:
//
// CredentialKeys = [
diff --git a/identity/aidl/default/libeic/EicOps.h b/identity/aidl/default/libeic/EicOps.h
index d4fcf0e..aa26e62 100644
--- a/identity/aidl/default/libeic/EicOps.h
+++ b/identity/aidl/default/libeic/EicOps.h
@@ -141,6 +141,10 @@
// String length, see strlen(3).
size_t eicStrLen(const char* s);
+// Locate a substring, see memmem(3)
+void* eicMemMem(const uint8_t* haystack, size_t haystackLen, const uint8_t* needle,
+ size_t needleLen);
+
// Memory compare, see CRYPTO_memcmp(3SSL)
//
// It takes an amount of time dependent on len, but independent of the contents of the
@@ -151,6 +155,12 @@
// Random number generation.
bool eicOpsRandom(uint8_t* buf, size_t numBytes);
+// Creates a new non-zero identifier in |id|.
+//
+// Is guaranteed to be non-zero and different than what is already in |id|.
+//
+bool eicNextId(uint32_t* id);
+
// If |testCredential| is true, returns the 128-bit AES Hardware-Bound Key (16 bytes).
//
// Otherwise returns all zeroes (16 bytes).
@@ -295,6 +305,8 @@
int verificationTokenSecurityLevel,
const uint8_t* verificationTokenMac, size_t verificationTokenMacSize);
+// Also see eicOpsLookupActiveSessionFromId() defined in EicSession.h
+
#ifdef __cplusplus
}
#endif
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index 0d03ae9..104a559 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -16,11 +16,17 @@
#include "EicPresentation.h"
#include "EicCommon.h"
+#include "EicSession.h"
#include <inttypes.h>
-bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
- size_t docTypeLength, const uint8_t* encryptedCredentialKeys,
+// Global used for assigning ids for presentation objects.
+//
+static uint32_t gPresentationLastIdAssigned = 0;
+
+bool eicPresentationInit(EicPresentation* ctx, uint32_t sessionId, bool testCredential,
+ const char* docType, size_t docTypeLength,
+ const uint8_t* encryptedCredentialKeys,
size_t encryptedCredentialKeysSize) {
uint8_t credentialKeys[EIC_CREDENTIAL_KEYS_CBOR_SIZE_FEATURE_VERSION_202101];
bool expectPopSha256 = false;
@@ -39,6 +45,13 @@
}
eicMemSet(ctx, '\0', sizeof(EicPresentation));
+ ctx->sessionId = sessionId;
+
+ if (!eicNextId(&gPresentationLastIdAssigned)) {
+ eicDebug("Error getting id for object");
+ return false;
+ }
+ ctx->id = gPresentationLastIdAssigned;
if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
encryptedCredentialKeysSize,
@@ -86,6 +99,23 @@
if (expectPopSha256) {
eicMemCpy(ctx->proofOfProvisioningSha256, credentialKeys + 54, EIC_SHA256_DIGEST_SIZE);
}
+
+ eicDebug("Initialized presentation with id %" PRIu32, ctx->id);
+ return true;
+}
+
+bool eicPresentationShutdown(EicPresentation* ctx) {
+ if (ctx->id == 0) {
+ eicDebug("Trying to shut down presentation with id 0");
+ return false;
+ }
+ eicDebug("Shut down presentation with id %" PRIu32, ctx->id);
+ eicMemSet(ctx, '\0', sizeof(EicPresentation));
+ return true;
+}
+
+bool eicPresentationGetId(EicPresentation* ctx, uint32_t* outId) {
+ *outId = ctx->id;
return true;
}
@@ -174,7 +204,7 @@
eicDebug("Failed generating random challenge");
return false;
}
- } while (ctx->authChallenge == 0);
+ } while (ctx->authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET);
eicDebug("Created auth challenge %" PRIu64, ctx->authChallenge);
*authChallenge = ctx->authChallenge;
return true;
@@ -190,6 +220,24 @@
int coseSignAlg,
const uint8_t* readerSignatureOfToBeSigned,
size_t readerSignatureOfToBeSignedSize) {
+ if (ctx->sessionId != 0) {
+ EicSession* session = eicSessionGetForId(ctx->sessionId);
+ if (session == NULL) {
+ eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+ return false;
+ }
+ EicSha256Ctx sha256;
+ uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+ eicOpsSha256Init(&sha256);
+ eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+ eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+ if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+ EIC_SHA256_DIGEST_SIZE) != 0) {
+ eicDebug("SessionTranscript mismatch");
+ return false;
+ }
+ }
+
if (ctx->readerPublicKeySize == 0) {
eicDebug("No public key for reader");
return false;
@@ -330,6 +378,20 @@
return true;
}
+static bool getChallenge(EicPresentation* ctx, uint64_t* outAuthChallenge) {
+ // Use authChallenge from session if applicable.
+ *outAuthChallenge = ctx->authChallenge;
+ if (ctx->sessionId != 0) {
+ EicSession* session = eicSessionGetForId(ctx->sessionId);
+ if (session == NULL) {
+ eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+ return false;
+ }
+ *outAuthChallenge = session->authChallenge;
+ }
+ return true;
+}
+
bool eicPresentationSetAuthToken(EicPresentation* ctx, uint64_t challenge, uint64_t secureUserId,
uint64_t authenticatorId, int hardwareAuthenticatorType,
uint64_t timeStamp, const uint8_t* mac, size_t macSize,
@@ -338,14 +400,19 @@
int verificationTokenSecurityLevel,
const uint8_t* verificationTokenMac,
size_t verificationTokenMacSize) {
+ uint64_t authChallenge;
+ if (!getChallenge(ctx, &authChallenge)) {
+ return false;
+ }
+
// It doesn't make sense to accept any tokens if eicPresentationCreateAuthChallenge()
// was never called.
- if (ctx->authChallenge == 0) {
- eicDebug("Trying validate tokens when no auth-challenge was previously generated");
+ if (authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET) {
+ eicDebug("Trying to validate tokens when no auth-challenge was previously generated");
return false;
}
// At least the verification-token must have the same challenge as what was generated.
- if (verificationTokenChallenge != ctx->authChallenge) {
+ if (verificationTokenChallenge != authChallenge) {
eicDebug("Challenge in verification token does not match the challenge "
"previously generated");
return false;
@@ -354,6 +421,7 @@
challenge, secureUserId, authenticatorId, hardwareAuthenticatorType, timeStamp, mac,
macSize, verificationTokenChallenge, verificationTokenTimestamp,
verificationTokenSecurityLevel, verificationTokenMac, verificationTokenMacSize)) {
+ eicDebug("Error validating authToken");
return false;
}
ctx->authTokenChallenge = challenge;
@@ -377,11 +445,16 @@
// Only ACP with auth-on-every-presentation - those with timeout == 0 - need the
// challenge to match...
if (timeoutMillis == 0) {
- if (ctx->authTokenChallenge != ctx->authChallenge) {
+ uint64_t authChallenge;
+ if (!getChallenge(ctx, &authChallenge)) {
+ return false;
+ }
+
+ if (ctx->authTokenChallenge != authChallenge) {
eicDebug("Challenge in authToken (%" PRIu64
") doesn't match the challenge "
"that was created (%" PRIu64 ") for this session",
- ctx->authTokenChallenge, ctx->authChallenge);
+ ctx->authTokenChallenge, authChallenge);
return false;
}
}
@@ -490,6 +563,25 @@
const uint8_t signingKeyBlob[60], const char* docType,
size_t docTypeLength, unsigned int numNamespacesWithValues,
size_t expectedDeviceNamespacesSize) {
+ if (ctx->sessionId != 0) {
+ EicSession* session = eicSessionGetForId(ctx->sessionId);
+ if (session == NULL) {
+ eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+ return false;
+ }
+ EicSha256Ctx sha256;
+ uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+ eicOpsSha256Init(&sha256);
+ eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+ eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+ if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+ EIC_SHA256_DIGEST_SIZE) != 0) {
+ eicDebug("SessionTranscript mismatch");
+ return false;
+ }
+ readerEphemeralPublicKey = session->readerEphemeralPublicKey;
+ }
+
uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
docTypeLength, signingKeyPriv)) {
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index 6f7f432..a031890 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -30,7 +30,13 @@
// The maximum size we support for public keys in reader certificates.
#define EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE 65
+// Constant used to convey that no session is associated with a presentation.
+#define EIC_PRESENTATION_ID_UNSET 0
+
typedef struct {
+ // A non-zero number unique for this EicPresentation instance
+ uint32_t id;
+
int featureLevel;
uint8_t storageKey[EIC_AES_128_KEY_SIZE];
@@ -38,6 +44,10 @@
uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE];
+ // If non-zero (not EIC_PRESENTATION_ID_UNSET), the id of the EicSession object this
+ // presentation object is associated with.
+ uint32_t sessionId;
+
// The challenge generated with eicPresentationCreateAuthChallenge()
uint64_t authChallenge;
@@ -93,10 +103,18 @@
EicCbor cbor;
} EicPresentation;
-bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType,
- size_t docTypeLength, const uint8_t* encryptedCredentialKeys,
+// If sessionId is zero (EIC_PRESENTATION_ID_UNSET), the presentation object is not associated
+// with a session object. Otherwise it's the id of the session object.
+//
+bool eicPresentationInit(EicPresentation* ctx, uint32_t sessionId, bool testCredential,
+ const char* docType, size_t docTypeLength,
+ const uint8_t* encryptedCredentialKeys,
size_t encryptedCredentialKeysSize);
+bool eicPresentationShutdown(EicPresentation* ctx);
+
+bool eicPresentationGetId(EicPresentation* ctx, uint32_t* outId);
+
bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* docType,
size_t docTypeLength, time_t now,
uint8_t* publicKeyCert, size_t* publicKeyCertSize,
diff --git a/identity/aidl/default/libeic/EicProvisioning.c b/identity/aidl/default/libeic/EicProvisioning.c
index c9df4fd..a241b71 100644
--- a/identity/aidl/default/libeic/EicProvisioning.c
+++ b/identity/aidl/default/libeic/EicProvisioning.c
@@ -17,8 +17,21 @@
#include "EicProvisioning.h"
#include "EicCommon.h"
+#include <inttypes.h>
+
+// Global used for assigning ids for provisioning objects.
+//
+static uint32_t gProvisioningLastIdAssigned = 0;
+
bool eicProvisioningInit(EicProvisioning* ctx, bool testCredential) {
eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+
+ if (!eicNextId(&gProvisioningLastIdAssigned)) {
+ eicDebug("Error getting id for object");
+ return false;
+ }
+ ctx->id = gProvisioningLastIdAssigned;
+
ctx->testCredential = testCredential;
if (!eicOpsRandom(ctx->storageKey, EIC_AES_128_KEY_SIZE)) {
return false;
@@ -47,6 +60,13 @@
}
eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+
+ if (!eicNextId(&gProvisioningLastIdAssigned)) {
+ eicDebug("Error getting id for object");
+ return false;
+ }
+ ctx->id = gProvisioningLastIdAssigned;
+
ctx->testCredential = testCredential;
if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys,
@@ -96,6 +116,21 @@
return true;
}
+bool eicProvisioningShutdown(EicProvisioning* ctx) {
+ if (ctx->id == 0) {
+ eicDebug("Trying to shut down provsioning with id 0");
+ return false;
+ }
+ eicDebug("Shut down provsioning with id %" PRIu32, ctx->id);
+ eicMemSet(ctx, '\0', sizeof(EicProvisioning));
+ return true;
+}
+
+bool eicProvisioningGetId(EicProvisioning* ctx, uint32_t* outId) {
+ *outId = ctx->id;
+ return true;
+}
+
bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
size_t challengeSize, const uint8_t* applicationId,
size_t applicationIdSize, uint8_t* publicKeyCert,
diff --git a/identity/aidl/default/libeic/EicProvisioning.h b/identity/aidl/default/libeic/EicProvisioning.h
index 92f1e4a..d94f8f1 100644
--- a/identity/aidl/default/libeic/EicProvisioning.h
+++ b/identity/aidl/default/libeic/EicProvisioning.h
@@ -31,6 +31,9 @@
#define EIC_MAX_NUM_ACCESS_CONTROL_PROFILE_IDS 32
typedef struct {
+ // A non-zero number unique for this EicProvisioning instance
+ uint32_t id;
+
// Set by eicCreateCredentialKey() OR eicProvisioningInitForUpdate()
uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE];
@@ -68,6 +71,10 @@
size_t docTypeLength, const uint8_t* encryptedCredentialKeys,
size_t encryptedCredentialKeysSize);
+bool eicProvisioningShutdown(EicProvisioning* ctx);
+
+bool eicProvisioningGetId(EicProvisioning* ctx, uint32_t* outId);
+
bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge,
size_t challengeSize, const uint8_t* applicationId,
size_t applicationIdSize, uint8_t* publicKeyCert,
diff --git a/identity/aidl/default/libeic/EicSession.c b/identity/aidl/default/libeic/EicSession.c
new file mode 100644
index 0000000..d0c7a0d
--- /dev/null
+++ b/identity/aidl/default/libeic/EicSession.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#include "EicCommon.h"
+#include "EicSession.h"
+
+// Global used for assigning ids for session objects.
+//
+static uint32_t gSessionLastIdAssigned = 0;
+
+// The current session object or NULL if never initialized or if it has been shut down.
+//
+static EicSession* gSessionCurrent = NULL;
+
+EicSession* eicSessionGetForId(uint32_t sessionId) {
+ if (gSessionCurrent != NULL && gSessionCurrent->id == sessionId) {
+ return gSessionCurrent;
+ }
+ return NULL;
+}
+
+bool eicSessionInit(EicSession* ctx) {
+ eicMemSet(ctx, '\0', sizeof(EicSession));
+
+ if (!eicNextId(&gSessionLastIdAssigned)) {
+ eicDebug("Error getting id for object");
+ return false;
+ }
+ ctx->id = gSessionLastIdAssigned;
+
+ do {
+ if (!eicOpsRandom((uint8_t*)&(ctx->authChallenge), sizeof(ctx->authChallenge))) {
+ eicDebug("Failed generating random challenge");
+ return false;
+ }
+ } while (ctx->authChallenge == EIC_KM_AUTH_CHALLENGE_UNSET);
+
+ if (!eicOpsCreateEcKey(ctx->ephemeralPrivateKey, ctx->ephemeralPublicKey)) {
+ eicDebug("Error creating ephemeral key-pair");
+ return false;
+ }
+
+ gSessionCurrent = ctx;
+ eicDebug("Initialized session with id %" PRIu32, ctx->id);
+ return true;
+}
+
+bool eicSessionShutdown(EicSession* ctx) {
+ if (ctx->id == 0) {
+ eicDebug("Trying to shut down session with id 0");
+ return false;
+ }
+ eicDebug("Shut down session with id %" PRIu32, ctx->id);
+ eicMemSet(ctx, '\0', sizeof(EicSession));
+ gSessionCurrent = NULL;
+ return true;
+}
+
+bool eicSessionGetId(EicSession* ctx, uint32_t* outId) {
+ *outId = ctx->id;
+ return true;
+}
+
+bool eicSessionGetAuthChallenge(EicSession* ctx, uint64_t* outAuthChallenge) {
+ *outAuthChallenge = ctx->authChallenge;
+ return true;
+}
+
+bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
+ uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
+ eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
+ return true;
+}
+
+bool eicSessionSetReaderEphemeralPublicKey(
+ EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]) {
+ eicMemCpy(ctx->readerEphemeralPublicKey, readerEphemeralPublicKey, EIC_P256_PUB_KEY_SIZE);
+ return true;
+}
+
+bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
+ size_t sessionTranscriptSize) {
+ // Only accept the SessionTranscript if X and Y from the ephemeral key
+ // we created is somewhere in SessionTranscript...
+ //
+ if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
+ EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+ eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
+ return false;
+ }
+ if (eicMemMem(sessionTranscript, sessionTranscriptSize,
+ ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
+ EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+ eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
+ return false;
+ }
+
+ // To save space we only store the SHA-256 of SessionTranscript
+ //
+ EicSha256Ctx shaCtx;
+ eicOpsSha256Init(&shaCtx);
+ eicOpsSha256Update(&shaCtx, sessionTranscript, sessionTranscriptSize);
+ eicOpsSha256Final(&shaCtx, ctx->sessionTranscriptSha256);
+ return true;
+}
diff --git a/identity/aidl/default/libeic/EicSession.h b/identity/aidl/default/libeic/EicSession.h
new file mode 100644
index 0000000..0303dae
--- /dev/null
+++ b/identity/aidl/default/libeic/EicSession.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#if !defined(EIC_INSIDE_LIBEIC_H) && !defined(EIC_COMPILATION)
+#error "Never include this file directly, include libeic.h instead."
+#endif
+
+#ifndef ANDROID_HARDWARE_IDENTITY_EIC_SESSION_H
+#define ANDROID_HARDWARE_IDENTITY_EIC_SESSION_H
+
+#include "EicOps.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ // A non-zero number unique for this EicSession instance
+ uint32_t id;
+
+ // The challenge generated at construction time by eicSessionInit().
+ uint64_t authChallenge;
+
+ uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE];
+ uint8_t ephemeralPublicKey[EIC_P256_PUB_KEY_SIZE];
+
+ uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE];
+
+ uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+
+} EicSession;
+
+bool eicSessionInit(EicSession* ctx);
+
+bool eicSessionShutdown(EicSession* ctx);
+
+bool eicSessionGetId(EicSession* ctx, uint32_t* outId);
+
+bool eicSessionGetAuthChallenge(EicSession* ctx, uint64_t* outAuthChallenge);
+
+bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
+ uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]);
+
+bool eicSessionSetReaderEphemeralPublicKey(
+ EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]);
+
+bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
+ size_t sessionTranscriptSize);
+
+// Looks up an active session with the given id.
+//
+// Returns NULL if no active session with the given id is found.
+//
+EicSession* eicSessionGetForId(uint32_t sessionId);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ANDROID_HARDWARE_IDENTITY_EIC_PRESENTATION_H
diff --git a/identity/aidl/default/libeic/libeic.h b/identity/aidl/default/libeic/libeic.h
index 20c8896..d89fc9a 100644
--- a/identity/aidl/default/libeic/libeic.h
+++ b/identity/aidl/default/libeic/libeic.h
@@ -27,10 +27,11 @@
*/
#define EIC_INSIDE_LIBEIC_H
#include "EicCbor.h"
+#include "EicCommon.h"
#include "EicOps.h"
#include "EicPresentation.h"
#include "EicProvisioning.h"
-#include "EicCommon.h"
+#include "EicSession.h"
#undef EIC_INSIDE_LIBEIC_H
#ifdef __cplusplus