diff options
author | David Zeuthen <zeuthen@google.com> | 2020-10-16 11:27:24 -0400 |
---|---|---|
committer | David Zeuthen <zeuthen@google.com> | 2021-01-23 13:35:57 -0500 |
commit | 49f2d2558ac417d090dfae9c78ab372d71e5140c (patch) | |
tree | be240ccdfb0fa1e45aa03648cb385ff7ce82d84f /identity/aidl/default/libeic | |
parent | eafa06164d1e1bafbe20562d540ab5420bb0f825 (diff) |
Identity Credential changes for Android 12
- Add IIdentityCredential.deleteCredentialWithChallenge()
- Deprecate IIdentityCredential.deleteCredential()
- Add IIdentityCredential.proveOwership()
- Add IIdentityCredential.updateCredential()
- Add ProofOfBinding CBOR to AuthenticationKey X.509 certificate
- Document which API versions new methods/features appeared in.
- Mention need to declare android.hardware.identity_credential system
feature (w/ feature version number) and do this for the default
implementation.
Bug: 170146643
Test: atest VtsHalIdentityTargetTest
Change-Id: Ib47c7caa5f3d6fff6919f019eee44a735dba9cf8
Diffstat (limited to 'identity/aidl/default/libeic')
-rw-r--r-- | identity/aidl/default/libeic/EicCbor.c | 9 | ||||
-rw-r--r-- | identity/aidl/default/libeic/EicCbor.h | 11 | ||||
-rw-r--r-- | identity/aidl/default/libeic/EicOps.h | 7 | ||||
-rw-r--r-- | identity/aidl/default/libeic/EicPresentation.c | 148 | ||||
-rw-r--r-- | identity/aidl/default/libeic/EicPresentation.h | 21 | ||||
-rw-r--r-- | identity/aidl/default/libeic/EicProvisioning.c | 93 | ||||
-rw-r--r-- | identity/aidl/default/libeic/EicProvisioning.h | 23 |
7 files changed, 288 insertions, 24 deletions
diff --git a/identity/aidl/default/libeic/EicCbor.c b/identity/aidl/default/libeic/EicCbor.c index ec049b1c0d..fe131eb8b7 100644 --- a/identity/aidl/default/libeic/EicCbor.c +++ b/identity/aidl/default/libeic/EicCbor.c @@ -17,6 +17,7 @@ #include "EicCbor.h" void eicCborInit(EicCbor* cbor, uint8_t* buffer, size_t bufferSize) { + eicMemSet(cbor, '\0', sizeof(EicCbor)); cbor->size = 0; cbor->bufferSize = bufferSize; cbor->buffer = buffer; @@ -26,6 +27,7 @@ void eicCborInit(EicCbor* cbor, uint8_t* buffer, size_t bufferSize) { void eicCborInitHmacSha256(EicCbor* cbor, uint8_t* buffer, size_t bufferSize, const uint8_t* hmacKey, size_t hmacKeySize) { + eicMemSet(cbor, '\0', sizeof(EicCbor)); cbor->size = 0; cbor->bufferSize = bufferSize; cbor->buffer = buffer; @@ -33,6 +35,10 @@ void eicCborInitHmacSha256(EicCbor* cbor, uint8_t* buffer, size_t bufferSize, eicOpsHmacSha256Init(&cbor->digester.hmacSha256, hmacKey, hmacKeySize); } +void eicCborEnableSecondaryDigesterSha256(EicCbor* cbor, EicSha256Ctx* sha256) { + cbor->secondaryDigesterSha256 = sha256; +} + void eicCborFinal(EicCbor* cbor, uint8_t digest[EIC_SHA256_DIGEST_SIZE]) { switch (cbor->digestType) { case EIC_CBOR_DIGEST_TYPE_SHA256: @@ -53,6 +59,9 @@ void eicCborAppend(EicCbor* cbor, const uint8_t* data, size_t size) { eicOpsHmacSha256Update(&cbor->digester.hmacSha256, data, size); break; } + if (cbor->secondaryDigesterSha256 != NULL) { + eicOpsSha256Update(cbor->secondaryDigesterSha256, data, size); + } if (cbor->size >= cbor->bufferSize) { cbor->size += size; diff --git a/identity/aidl/default/libeic/EicCbor.h b/identity/aidl/default/libeic/EicCbor.h index 4686b38447..9c0f531e4a 100644 --- a/identity/aidl/default/libeic/EicCbor.h +++ b/identity/aidl/default/libeic/EicCbor.h @@ -53,6 +53,9 @@ typedef struct { EicHmacSha256Ctx hmacSha256; } digester; + // The secondary digester, may be unset. + EicSha256Ctx* secondaryDigesterSha256; + // The buffer used for building up CBOR or NULL if bufferSize is 0. uint8_t* buffer; } EicCbor; @@ -70,6 +73,14 @@ void eicCborInit(EicCbor* cbor, uint8_t* buffer, size_t bufferSize); void eicCborInitHmacSha256(EicCbor* cbor, uint8_t* buffer, size_t bufferSize, const uint8_t* hmacKey, size_t hmacKeySize); +/* Enables a secondary digester. + * + * May be enabled midway through processing, this can be used to e.g. calculate + * a digest of Sig_structure (for COSE_Sign1) and a separate digest of its + * payload. + */ +void eicCborEnableSecondaryDigesterSha256(EicCbor* cbor, EicSha256Ctx* sha256); + /* Finishes building CBOR and returns the digest. */ void eicCborFinal(EicCbor* cbor, uint8_t digest[EIC_SHA256_DIGEST_SIZE]); diff --git a/identity/aidl/default/libeic/EicOps.h b/identity/aidl/default/libeic/EicOps.h index da4dabf879..d4fcf0e1bb 100644 --- a/identity/aidl/default/libeic/EicOps.h +++ b/identity/aidl/default/libeic/EicOps.h @@ -207,14 +207,17 @@ bool eicOpsCreateCredentialKey(uint8_t privateKey[EIC_P256_PRIV_KEY_SIZE], const // Generate an X.509 certificate for the key identified by |publicKey| which // must be of the form returned by eicOpsCreateEcKey(). // +// If proofOfBinding is not NULL, it will be included as an OCTET_STRING +// X.509 extension at OID 1.3.6.1.4.1.11129.2.1.26. +// // The certificate will be signed by the key identified by |signingKey| which // must be of the form returned by eicOpsCreateEcKey(). // bool eicOpsSignEcKey(const uint8_t publicKey[EIC_P256_PUB_KEY_SIZE], const uint8_t signingKey[EIC_P256_PRIV_KEY_SIZE], unsigned int serial, const char* issuerName, const char* subjectName, time_t validityNotBefore, - time_t validityNotAfter, uint8_t* cert, - size_t* certSize); // inout + time_t validityNotAfter, const uint8_t* proofOfBinding, + size_t proofOfBindingSize, uint8_t* cert, size_t* certSize); // inout // Uses |privateKey| to create an ECDSA signature of some data (the SHA-256 must // be given by |digestOfData|). Returns the signature in |signature|. diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c index d3f5556f66..5e9a280d09 100644 --- a/identity/aidl/default/libeic/EicPresentation.c +++ b/identity/aidl/default/libeic/EicPresentation.c @@ -19,13 +19,28 @@ #include <inttypes.h> bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType, - const uint8_t encryptedCredentialKeys[80]) { - uint8_t credentialKeys[52]; + const uint8_t* encryptedCredentialKeys, + size_t encryptedCredentialKeysSize) { + uint8_t credentialKeys[86]; + bool expectPopSha256 = false; + + // For feature version 202009 it's 52 bytes long and for feature version 202101 it's 86 + // bytes (the additional data is the ProofOfProvisioning SHA-256). We need + // to support loading all feature versions. + // + if (encryptedCredentialKeysSize == 52 + 28) { + /* do nothing */ + } else if (encryptedCredentialKeysSize == 86 + 28) { + expectPopSha256 = true; + } else { + eicDebug("Unexpected size %zd for encryptedCredentialKeys", encryptedCredentialKeysSize); + return false; + } eicMemSet(ctx, '\0', sizeof(EicPresentation)); if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys, - 80, + encryptedCredentialKeysSize, // DocType is the additionalAuthenticatedData (const uint8_t*)docType, eicStrLen(docType), credentialKeys)) { eicDebug("Error decrypting CredentialKeys"); @@ -34,25 +49,42 @@ bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* // It's supposed to look like this; // + // Feature version 202009: + // // CredentialKeys = [ // bstr, ; storageKey, a 128-bit AES key - // bstr ; credentialPrivKey, the private key for credentialKey + // bstr, ; credentialPrivKey, the private key for credentialKey // ] // - // where storageKey is 16 bytes and credentialPrivateKey is 32 bytes. + // Feature version 202101: // - // So the first two bytes will be 0x82 0x50 indicating resp. an array of two elements - // and a bstr of 16 elements. Sixteen bytes later (offset 18 and 19) there will be - // a bstr of 32 bytes. It's encoded as two bytes 0x58 and 0x20. + // CredentialKeys = [ + // bstr, ; storageKey, a 128-bit AES key + // bstr, ; credentialPrivKey, the private key for credentialKey + // bstr ; proofOfProvisioning SHA-256 + // ] // - if (credentialKeys[0] != 0x82 || credentialKeys[1] != 0x50 || credentialKeys[18] != 0x58 || - credentialKeys[19] != 0x20) { + // where storageKey is 16 bytes, credentialPrivateKey is 32 bytes, and proofOfProvisioning + // SHA-256 is 32 bytes. + // + if (credentialKeys[0] != (expectPopSha256 ? 0x83 : 0x82) || // array of two or three elements + credentialKeys[1] != 0x50 || // 16-byte bstr + credentialKeys[18] != 0x58 || credentialKeys[19] != 0x20) { // 32-byte bstr eicDebug("Invalid CBOR for CredentialKeys"); return false; } + if (expectPopSha256) { + if (credentialKeys[52] != 0x58 || credentialKeys[53] != 0x20) { // 32-byte bstr + eicDebug("Invalid CBOR for CredentialKeys"); + return false; + } + } eicMemCpy(ctx->storageKey, credentialKeys + 2, EIC_AES_128_KEY_SIZE); eicMemCpy(ctx->credentialPrivateKey, credentialKeys + 20, EIC_P256_PRIV_KEY_SIZE); ctx->testCredential = testCredential; + if (expectPopSha256) { + eicMemCpy(ctx->proofOfProvisioningSha256, credentialKeys + 54, EIC_SHA256_DIGEST_SIZE); + } return true; } @@ -61,6 +93,35 @@ bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* doc uint8_t signingKeyBlob[60]) { uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE]; uint8_t signingKeyPub[EIC_P256_PUB_KEY_SIZE]; + uint8_t cborBuf[64]; + + // Generate the ProofOfBinding CBOR to include in the X.509 certificate in + // IdentityCredentialAuthenticationKeyExtension CBOR. This CBOR is defined + // by the following CDDL + // + // ProofOfBinding = [ + // "ProofOfBinding", + // bstr, // Contains the SHA-256 of ProofOfProvisioning + // ] + // + // This array may grow in the future if other information needs to be + // conveyed. + // + // The bytes of ProofOfBinding is is represented as an OCTET_STRING + // and stored at OID 1.3.6.1.4.1.11129.2.1.26. + // + + EicCbor cbor; + eicCborInit(&cbor, cborBuf, sizeof cborBuf); + eicCborAppendArray(&cbor, 2); + eicCborAppendString(&cbor, "ProofOfBinding"); + eicCborAppendByteString(&cbor, ctx->proofOfProvisioningSha256, EIC_SHA256_DIGEST_SIZE); + if (cbor.size > sizeof(cborBuf)) { + eicDebug("Exceeded buffer size"); + return false; + } + const uint8_t* proofOfBinding = cborBuf; + size_t proofOfBindingSize = cbor.size; if (!eicOpsCreateEcKey(signingKeyPriv, signingKeyPub)) { eicDebug("Error creating signing key"); @@ -73,7 +134,8 @@ bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* doc if (!eicOpsSignEcKey(signingKeyPub, ctx->credentialPrivateKey, 1, "Android Identity Credential Key", // issuer CN "Android Identity Credential Authentication Key", // subject CN - validityNotBefore, validityNotAfter, publicKeyCert, publicKeyCertSize)) { + validityNotBefore, validityNotAfter, proofOfBinding, proofOfBindingSize, + publicKeyCert, publicKeyCertSize)) { eicDebug("Error creating certificate for signing key"); return false; } @@ -674,7 +736,8 @@ bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMac } bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType, - size_t proofOfDeletionCborSize, + const uint8_t* challenge, size_t challengeSize, + bool includeChallenge, size_t proofOfDeletionCborSize, uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]) { EicCbor cbor; @@ -712,9 +775,12 @@ bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType, eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, proofOfDeletionCborSize); // Finally, the CBOR that we're actually signing. - eicCborAppendArray(&cbor, 3); + eicCborAppendArray(&cbor, includeChallenge ? 4 : 3); eicCborAppendString(&cbor, "ProofOfDeletion"); eicCborAppendString(&cbor, docType); + if (includeChallenge) { + eicCborAppendByteString(&cbor, challenge, challengeSize); + } eicCborAppendBool(&cbor, ctx->testCredential); uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE]; @@ -726,3 +792,59 @@ bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType, return true; } + +bool eicPresentationProveOwnership(EicPresentation* ctx, const char* docType, bool testCredential, + const uint8_t* challenge, size_t challengeSize, + size_t proofOfOwnershipCborSize, + uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]) { + EicCbor cbor; + + eicCborInit(&cbor, NULL, 0); + + // What we're going to sign is the COSE ToBeSigned structure which + // looks like the following: + // + // Sig_structure = [ + // context : "Signature" / "Signature1" / "CounterSignature", + // body_protected : empty_or_serialized_map, + // ? sign_protected : empty_or_serialized_map, + // external_aad : bstr, + // payload : bstr + // ] + // + eicCborAppendArray(&cbor, 4); + eicCborAppendString(&cbor, "Signature1"); + + // The COSE Encoded protected headers is just a single field with + // COSE_LABEL_ALG (1) -> COSE_ALG_ECSDA_256 (-7). For simplicitly we just + // hard-code the CBOR encoding: + static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x26}; + eicCborAppendByteString(&cbor, coseEncodedProtectedHeaders, + sizeof(coseEncodedProtectedHeaders)); + + // We currently don't support Externally Supplied Data (RFC 8152 section 4.3) + // so external_aad is the empty bstr + static const uint8_t externalAad[0] = {}; + eicCborAppendByteString(&cbor, externalAad, sizeof(externalAad)); + + // For the payload, the _encoded_ form follows here. We handle this by simply + // opening a bstr, and then writing the CBOR. This requires us to know the + // size of said bstr, ahead of time. + eicCborBegin(&cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, proofOfOwnershipCborSize); + + // Finally, the CBOR that we're actually signing. + eicCborAppendArray(&cbor, 4); + eicCborAppendString(&cbor, "ProofOfOwnership"); + eicCborAppendString(&cbor, docType); + eicCborAppendByteString(&cbor, challenge, challengeSize); + eicCborAppendBool(&cbor, testCredential); + + uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE]; + eicCborFinal(&cbor, cborSha256); + if (!eicOpsEcDsa(ctx->credentialPrivateKey, cborSha256, signatureOfToBeSigned)) { + eicDebug("Error signing proofOfDeletion"); + return false; + } + + return true; +} diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h index d79896212e..7cad068772 100644 --- a/identity/aidl/default/libeic/EicPresentation.h +++ b/identity/aidl/default/libeic/EicPresentation.h @@ -31,6 +31,8 @@ extern "C" { #define EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE 65 typedef struct { + int featureLevel; + uint8_t storageKey[EIC_AES_128_KEY_SIZE]; uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE]; @@ -79,12 +81,17 @@ typedef struct { // SHA-256 for AdditionalData, updated for each entry. uint8_t additionalDataSha256[EIC_SHA256_DIGEST_SIZE]; + // SHA-256 of ProofOfProvisioning. Set to NUL-bytes or initialized from CredentialKeys data + // if credential was created with feature version 202101 or later. + uint8_t proofOfProvisioningSha256[EIC_SHA256_DIGEST_SIZE]; + size_t expectedCborSizeAtEnd; EicCbor cbor; } EicPresentation; bool eicPresentationInit(EicPresentation* ctx, bool testCredential, const char* docType, - const uint8_t encryptedCredentialKeys[80]); + const uint8_t* encryptedCredentialKeys, + size_t encryptedCredentialKeysSize); bool eicPresentationGenerateSigningKeyPair(EicPresentation* ctx, const char* docType, time_t now, uint8_t* publicKeyCert, size_t* publicKeyCertSize, @@ -219,9 +226,19 @@ bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMac // where content is set to the ProofOfDeletion CBOR. // bool eicPresentationDeleteCredential(EicPresentation* ctx, const char* docType, - size_t proofOfDeletionCborSize, + const uint8_t* challenge, size_t challengeSize, + bool includeChallenge, size_t proofOfDeletionCborSize, uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]); +// The data returned in |signatureOfToBeSigned| contains the ECDSA signature of +// the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process" +// where content is set to the ProofOfOwnership CBOR. +// +bool eicPresentationProveOwnership(EicPresentation* ctx, const char* docType, bool testCredential, + const uint8_t* challenge, size_t challengeSize, + size_t proofOfOwnershipCborSize, + uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]); + #ifdef __cplusplus } #endif diff --git a/identity/aidl/default/libeic/EicProvisioning.c b/identity/aidl/default/libeic/EicProvisioning.c index f16605cfad..3b4148e571 100644 --- a/identity/aidl/default/libeic/EicProvisioning.c +++ b/identity/aidl/default/libeic/EicProvisioning.c @@ -26,10 +26,84 @@ bool eicProvisioningInit(EicProvisioning* ctx, bool testCredential) { return true; } +bool eicProvisioningInitForUpdate(EicProvisioning* ctx, bool testCredential, const char* docType, + const uint8_t* encryptedCredentialKeys, + size_t encryptedCredentialKeysSize) { + uint8_t credentialKeys[86]; + + // For feature version 202009 it's 52 bytes long and for feature version 202101 it's 86 + // bytes (the additional data is the ProofOfProvisioning SHA-256). We need + // to support loading all feature versions. + // + bool expectPopSha256 = false; + if (encryptedCredentialKeysSize == 52 + 28) { + /* do nothing */ + } else if (encryptedCredentialKeysSize == 86 + 28) { + expectPopSha256 = true; + } else { + eicDebug("Unexpected size %zd for encryptedCredentialKeys", encryptedCredentialKeysSize); + return false; + } + + eicMemSet(ctx, '\0', sizeof(EicProvisioning)); + ctx->testCredential = testCredential; + + if (!eicOpsDecryptAes128Gcm(eicOpsGetHardwareBoundKey(testCredential), encryptedCredentialKeys, + encryptedCredentialKeysSize, + // DocType is the additionalAuthenticatedData + (const uint8_t*)docType, eicStrLen(docType), credentialKeys)) { + eicDebug("Error decrypting CredentialKeys"); + return false; + } + + // It's supposed to look like this; + // + // Feature version 202009: + // + // CredentialKeys = [ + // bstr, ; storageKey, a 128-bit AES key + // bstr, ; credentialPrivKey, the private key for credentialKey + // ] + // + // Feature version 202101: + // + // CredentialKeys = [ + // bstr, ; storageKey, a 128-bit AES key + // bstr, ; credentialPrivKey, the private key for credentialKey + // bstr ; proofOfProvisioning SHA-256 + // ] + // + // where storageKey is 16 bytes, credentialPrivateKey is 32 bytes, and proofOfProvisioning + // SHA-256 is 32 bytes. + // + if (credentialKeys[0] != (expectPopSha256 ? 0x83 : 0x82) || // array of two or three elements + credentialKeys[1] != 0x50 || // 16-byte bstr + credentialKeys[18] != 0x58 || credentialKeys[19] != 0x20) { // 32-byte bstr + eicDebug("Invalid CBOR for CredentialKeys"); + return false; + } + if (expectPopSha256) { + if (credentialKeys[52] != 0x58 || credentialKeys[53] != 0x20) { // 32-byte bstr + eicDebug("Invalid CBOR for CredentialKeys"); + return false; + } + } + eicMemCpy(ctx->storageKey, credentialKeys + 2, EIC_AES_128_KEY_SIZE); + eicMemCpy(ctx->credentialPrivateKey, credentialKeys + 20, EIC_P256_PRIV_KEY_SIZE); + // Note: We don't care about the previous ProofOfProvisioning SHA-256 + ctx->isUpdate = true; + return true; +} + bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge, size_t challengeSize, const uint8_t* applicationId, size_t applicationIdSize, uint8_t* publicKeyCert, size_t* publicKeyCertSize) { + if (ctx->isUpdate) { + eicDebug("Cannot create CredentialKey on update"); + return false; + } + if (!eicOpsCreateCredentialKey(ctx->credentialPrivateKey, challenge, challengeSize, applicationId, applicationIdSize, ctx->testCredential, publicKeyCert, publicKeyCertSize)) { @@ -96,6 +170,9 @@ bool eicProvisioningStartPersonalization(EicProvisioning* ctx, int accessControl eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedProofOfProvisioningSize); ctx->expectedCborSizeAtEnd = expectedProofOfProvisioningSize + ctx->cbor.size; + eicOpsSha256Init(&ctx->proofOfProvisioningDigester); + eicCborEnableSecondaryDigesterSha256(&ctx->cbor, &ctx->proofOfProvisioningDigester); + eicCborAppendArray(&ctx->cbor, 5); eicCborAppendString(&ctx->cbor, "ProofOfProvisioning"); eicCborAppendString(&ctx->cbor, docType); @@ -260,14 +337,23 @@ bool eicProvisioningFinishAddingEntries( } bool eicProvisioningFinishGetCredentialData(EicProvisioning* ctx, const char* docType, - uint8_t encryptedCredentialKeys[80]) { + uint8_t* encryptedCredentialKeys, + size_t* encryptedCredentialKeysSize) { EicCbor cbor; - uint8_t cborBuf[52]; + uint8_t cborBuf[86]; + + if (*encryptedCredentialKeysSize < 86 + 28) { + eicDebug("encryptedCredentialKeysSize is %zd which is insufficient"); + return false; + } eicCborInit(&cbor, cborBuf, sizeof(cborBuf)); - eicCborAppendArray(&cbor, 2); + eicCborAppendArray(&cbor, 3); eicCborAppendByteString(&cbor, ctx->storageKey, EIC_AES_128_KEY_SIZE); eicCborAppendByteString(&cbor, ctx->credentialPrivateKey, EIC_P256_PRIV_KEY_SIZE); + uint8_t popSha256[EIC_SHA256_DIGEST_SIZE]; + eicOpsSha256Final(&ctx->proofOfProvisioningDigester, popSha256); + eicCborAppendByteString(&cbor, popSha256, EIC_SHA256_DIGEST_SIZE); if (cbor.size > sizeof(cborBuf)) { eicDebug("Exceeded buffer size"); return false; @@ -285,6 +371,7 @@ bool eicProvisioningFinishGetCredentialData(EicProvisioning* ctx, const char* do eicDebug("Error encrypting CredentialKeys"); return false; } + *encryptedCredentialKeysSize = cbor.size + 28; return true; } diff --git a/identity/aidl/default/libeic/EicProvisioning.h b/identity/aidl/default/libeic/EicProvisioning.h index 836d16e444..f064787b1b 100644 --- a/identity/aidl/default/libeic/EicProvisioning.h +++ b/identity/aidl/default/libeic/EicProvisioning.h @@ -31,7 +31,7 @@ extern "C" { #define EIC_MAX_NUM_ACCESS_CONTROL_PROFILE_IDS 32 typedef struct { - // Set by eicCreateCredentialKey. + // Set by eicCreateCredentialKey() OR eicProvisioningInitForUpdate() uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE]; int numEntryCounts; @@ -43,6 +43,7 @@ typedef struct { size_t curEntrySize; size_t curEntryNumBytesReceived; + // Set by eicProvisioningInit() OR eicProvisioningInitForUpdate() uint8_t storageKey[EIC_AES_128_KEY_SIZE]; size_t expectedCborSizeAtEnd; @@ -50,13 +51,23 @@ typedef struct { // SHA-256 for AdditionalData, updated for each entry. uint8_t additionalDataSha256[EIC_SHA256_DIGEST_SIZE]; + // Digester just for ProofOfProvisioning (without Sig_structure). + EicSha256Ctx proofOfProvisioningDigester; + EicCbor cbor; bool testCredential; + + // Set to true if this is an update. + bool isUpdate; } EicProvisioning; bool eicProvisioningInit(EicProvisioning* ctx, bool testCredential); +bool eicProvisioningInitForUpdate(EicProvisioning* ctx, bool testCredential, const char* docType, + const uint8_t* encryptedCredentialKeys, + size_t encryptedCredentialKeysSize); + bool eicProvisioningCreateCredentialKey(EicProvisioning* ctx, const uint8_t* challenge, size_t challengeSize, const uint8_t* applicationId, size_t applicationIdSize, uint8_t* publicKeyCert, @@ -107,14 +118,18 @@ bool eicProvisioningFinishAddingEntries( // CredentialKeys = [ // bstr, ; storageKey, a 128-bit AES key // bstr ; credentialPrivKey, the private key for credentialKey +// bstr ; SHA-256(ProofOfProvisioning) // ] // +// for feature version 202101. For feature version 202009 the third field was not present. +// // Since |storageKey| is 16 bytes and |credentialPrivKey| is 32 bytes, the -// encoded CBOR for CredentialKeys is 52 bytes and consequently -// |encryptedCredentialKeys| will be 52 + 28 = 80 bytes. +// encoded CBOR for CredentialKeys is 86 bytes and consequently +// |encryptedCredentialKeys| will be no longer than 86 + 28 = 114 bytes. // bool eicProvisioningFinishGetCredentialData(EicProvisioning* ctx, const char* docType, - uint8_t encryptedCredentialKeys[80]); + uint8_t* encryptedCredentialKeys, + size_t* encryptedCredentialKeysSize); #ifdef __cplusplus } |