| /* |
| * 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. |
| */ |
| |
| #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_PRESENTATION_H |
| #define ANDROID_HARDWARE_IDENTITY_EIC_PRESENTATION_H |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| #include "EicCbor.h" |
| |
| // 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]; |
| uint8_t credentialPrivateKey[EIC_P256_PRIV_KEY_SIZE]; |
| |
| 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; |
| |
| // Set by eicPresentationSetAuthToken() and contains the fields |
| // from the passed in authToken and verificationToken. |
| // |
| uint64_t authTokenChallenge; |
| uint64_t authTokenSecureUserId; |
| uint64_t authTokenTimestamp; |
| uint64_t verificationTokenTimestamp; |
| |
| // The public key for the reader. |
| // |
| // (During the process of pushing reader certificates, this is also used to store |
| // the public key of the previously pushed certificate.) |
| // |
| uint8_t readerPublicKey[EIC_PRESENTATION_MAX_READER_PUBLIC_KEY_SIZE]; |
| size_t readerPublicKeySize; |
| |
| // This is set to true only if eicPresentationValidateRequestMessage() successfully |
| // validated the requestMessage. |
| // |
| // Why even record this? Because there's no requirement the HAL actually calls that |
| // function and we validate ACPs before it's called... so it's possible that a |
| // compromised HAL could trick us into marking ACPs as authorized while they in fact |
| // aren't. |
| bool requestMessageValidated; |
| bool buildCbor; |
| bool buildCborEcdsa; |
| |
| // Set to true initialized as a test credential. |
| bool testCredential; |
| |
| // Set to true if the evaluation of access control checks in |
| // eicPresentationStartRetrieveEntryValue() resulted EIC_ACCESS_CHECK_RESULT_OK |
| bool accessCheckOk; |
| |
| // These are bitmasks indicating which of the possible 32 access control profiles are |
| // authorized. They are built up by eicPresentationValidateAccessControlProfile(). |
| // |
| uint32_t accessControlProfileMaskValidated; // True if the profile was validated. |
| uint32_t accessControlProfileMaskUsesReaderAuth; // True if the ACP is using reader auth |
| uint32_t accessControlProfileMaskFailedReaderAuth; // True if failed reader auth |
| uint32_t accessControlProfileMaskFailedUserAuth; // True if failed user auth |
| |
| // 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; |
| |
| // The selected DeviceKey / AuthKey |
| uint8_t deviceKeyPriv[EIC_P256_PRIV_KEY_SIZE]; |
| |
| EicCbor cborEcdsa; |
| size_t expectedCborEcdsaSizeAtEnd; |
| } EicPresentation; |
| |
| // 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, |
| uint8_t signingKeyBlob[60]); |
| |
| // Create an ephemeral key-pair. |
| // |
| // The private key is stored in |ctx->ephemeralPrivateKey| and also returned in |
| // |ephemeralPrivateKey|. |
| // |
| bool eicPresentationCreateEphemeralKeyPair(EicPresentation* ctx, |
| uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]); |
| |
| // Returns a non-zero challenge in |authChallenge|. |
| bool eicPresentationCreateAuthChallenge(EicPresentation* ctx, uint64_t* authChallenge); |
| |
| // Starts retrieveing entries. |
| // |
| bool eicPresentationStartRetrieveEntries(EicPresentation* ctx); |
| |
| // Sets the auth-token. |
| 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, |
| uint64_t verificationTokenChallenge, |
| uint64_t verificationTokenTimeStamp, |
| int verificationTokenSecurityLevel, |
| const uint8_t* verificationTokenMac, |
| size_t verificationTokenMacSize); |
| |
| // Function to push certificates in the reader certificate chain. |
| // |
| // This should start with the root certificate (e.g. the last in the chain) and |
| // continue up the chain, ending with the certificate for the reader. |
| // |
| // Calls to this function should be interleaved with calls to the |
| // eicPresentationValidateAccessControlProfile() function, see below. |
| // |
| bool eicPresentationPushReaderCert(EicPresentation* ctx, const uint8_t* certX509, |
| size_t certX509Size); |
| |
| // Checks an access control profile. |
| // |
| // Returns false if an error occurred while checking the profile (e.g. MAC doesn't check out). |
| // |
| // Returns in |accessGranted| whether access is granted. |
| // |
| // If |readerCertificate| is non-empty and the public key of one of those |
| // certificates appear in the chain presented by the reader, this function must |
| // be called after pushing that certificate using |
| // eicPresentationPushReaderCert(). |
| // |
| // The scratchSpace should be set to a buffer at least 512 bytes. It's done |
| // this way to avoid allocating stack space. |
| // |
| bool 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); |
| |
| // Validates that the given requestMessage is signed by the public key in the |
| // certificate last set with eicPresentationPushReaderCert(). |
| // |
| // The format of the signature is the same encoding as the 'signature' field of |
| // COSE_Sign1 - that is, it's the R and S integers both with the same length as |
| // the key-size. |
| // |
| // Must be called after eicPresentationPushReaderCert() have been used to push |
| // the final certificate. Which is the certificate of the reader itself. |
| // |
| bool 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); |
| |
| typedef enum { |
| // Returned if access is granted. |
| EIC_ACCESS_CHECK_RESULT_OK, |
| |
| // Returned if an error occurred checking for access. |
| EIC_ACCESS_CHECK_RESULT_FAILED, |
| |
| // Returned if access was denied because item is configured without any |
| // access control profiles. |
| EIC_ACCESS_CHECK_RESULT_NO_ACCESS_CONTROL_PROFILES, |
| |
| // Returned if access was denied because of user authentication. |
| EIC_ACCESS_CHECK_RESULT_USER_AUTHENTICATION_FAILED, |
| |
| // Returned if access was denied because of reader authentication. |
| EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED, |
| } EicAccessCheckResult; |
| |
| // Passes enough information to calculate the MACing key and/or prepare ECDSA signing |
| // |
| bool 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); |
| |
| // The scratchSpace should be set to a buffer at least 512 bytes (ideally 1024 |
| // bytes, the bigger the better). It's done this way to avoid allocating stack |
| // space. |
| // |
| EicAccessCheckResult 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); |
| |
| // Note: |content| must be big enough to hold |encryptedContentSize| - 28 bytes. |
| // |
| // The scratchSpace should be set to a buffer at least 512 bytes. It's done this way to |
| // avoid allocating stack space. |
| // |
| bool 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); |
| |
| // Returns the HMAC-SHA256 of |ToBeMaced| as per RFC 8051 "6.3. How to Compute |
| // and Verify a MAC". |
| bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMaced, |
| size_t* digestToBeMacedSize); |
| |
| // Like eicPresentationFinishRetrieval() but also returns an ECDSA signature. |
| // |
| bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced, |
| size_t* digestToBeMacedSize, |
| uint8_t* signatureOfToBeSigned, |
| size_t* signatureOfToBeSignedSize); |
| |
| // 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 ProofOfDeletion CBOR. |
| // |
| bool 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]); |
| |
| // 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, size_t docTypeLength, |
| bool testCredential, const uint8_t* challenge, size_t challengeSize, |
| size_t proofOfOwnershipCborSize, |
| uint8_t signatureOfToBeSigned[EIC_ECDSA_P256_SIGNATURE_SIZE]); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif // ANDROID_HARDWARE_IDENTITY_EIC_PRESENTATION_H |