Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1ad3bee authored by David Zeuthen's avatar David Zeuthen
Browse files

Update Identity Credential API docs.

This change contains no actual syntactical or semantic changes, just
clarifications on the inputs and outputs.

Test: N/A
Bug: 151082886
Merged-In: Ic7797aa53d292abdeb779cb55b404f8a433bce79
Change-Id: I90279c1ba434a9305b991863086b867309549ce8
parent bb366191
Loading
Loading
Loading
Loading
+39 −30
Original line number Diff line number Diff line
@@ -95,9 +95,7 @@ public abstract class IdentityCredential {
    /**
     * Sets whether to allow using an authentication key which use count has been exceeded if no
     * other key is available. This must be called prior to calling
     * {@link #getEntries(byte[], Map, byte[], byte[])} or using a
     * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this
     * object.
     * {@link #getEntries(byte[], Map, byte[], byte[])}.
     *
     * By default this is set to true.
     *
@@ -123,13 +121,14 @@ public abstract class IdentityCredential {
     * entries.
     *
     * <p>It is the responsibility of the calling application to know if authentication is needed
     * and use e.g. {@link android.hardware.biometrics.BiometricPrompt}) to make the user
     * and use e.g. {@link android.hardware.biometrics.BiometricPrompt} to make the user
     * authenticate using a {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which
     * references this object. If needed, this must be done before calling
     * {@link #getEntries(byte[], Map, byte[], byte[])}.
     *
     * <p>If this method returns successfully (i.e. without throwing an exception), it must not be
     * called again on this instance.
     * <p>It is permissible to call this method multiple times using the same instance but if this
     * is done, the {@code sessionTranscript} parameter must be identical for each call. If this is
     * not the case, the {@link SessionTranscriptMismatchException} exception is thrown.
     *
     * <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request
     * from the verifier. The content can be defined in the way appropriate for the credential, byt
@@ -141,6 +140,9 @@ public abstract class IdentityCredential {
     *     the example below.</li>
     * </ul>
     *
     * <p>If these requirements are not met the {@link InvalidRequestMessageException} exception
     * is thrown.
     *
     * <p>Here's an example of CBOR which conforms to this requirement:
     * <pre>
     *   ItemsRequest = {
@@ -149,6 +151,8 @@ public abstract class IdentityCredential {
     *     ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide
     *   }
     *
     *   DocType = tstr
     *
     *   NameSpaces = {
     *     + NameSpace => DataElements    ; Requested data elements for each NameSpace
     *   }
@@ -172,16 +176,18 @@ public abstract class IdentityCredential {
     *     EReaderKeyBytes
     *   ]
     *
     *   DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement)
     *   EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub)
     *   DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement)  ; Bytes of DeviceEngagement
     *   EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub)  ; Bytes of EReaderKey.pub
     *
     *   EReaderKey.Pub = COSE_Key    ; Ephemeral public key provided by reader
     * </pre>
     *
     * <p>If the SessionTranscript is not empty, a COSE_Key structure for the public part
     * of the key-pair previously generated by {@link #createEphemeralKeyPair()} must appear
     * somewhere in {@code DeviceEngagement} and the X and Y coordinates must both be present
     * <p>where a {@code COSE_Key} structure for the public part of the key-pair previously
     * generated by {@link #createEphemeralKeyPair()} must appear somewhere in
     * {@code DeviceEngagement} and the X and Y coordinates must both be present
     * in uncompressed form.
     *
     * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a COSE_Sign1
     * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a {@code COSE_Sign1}
     * structure as defined in RFC 8152. For the payload nil shall be used and the
     * detached payload is the ReaderAuthentication CBOR described below.
     * <pre>
@@ -194,20 +200,23 @@ public abstract class IdentityCredential {
     *     ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)   ; Bytes of ItemsRequest
     * </pre>
     *
     * <p>The public key corresponding to the key used to made signature, can be
     * found in the {@code x5chain} unprotected header element of the COSE_Sign1
     * structure (as as described in 'draft-ietf-cose-x509-04'). There will be at
     * least one certificate in said element and there may be more (and if so,
     * <p>where {@code ItemsRequestBytes} are the bytes in the {@code requestMessage} parameter.
     *
     * <p>The public key corresponding to the key used to make the signature, can be found in the
     * {@code x5chain} unprotected header element of the {@code COSE_Sign1} structure (as as
     * described in
     * <a href="https://tools.ietf.org/html/draft-ietf-cose-x509-04">draft-ietf-cose-x509-04</a>).
     * There will be at least one certificate in said element and there may be more (and if so,
     * each certificate must be signed by its successor).
     *
     * <p>Data elements protected by reader authentication is returned if, and only if, they are
     * <p>Data elements protected by reader authentication are returned if, and only if, they are
     * mentioned in {@code requestMessage}, {@code requestMessage} is signed by the top-most
     * certificate in {@code readerCertificateChain}, and the data element is configured
     * with an {@link AccessControlProfile} with a {@link X509Certificate} in
     * {@code readerCertificateChain}.
     * certificate in the reader's certificate chain, and the data element is configured
     * with an {@link AccessControlProfile} configured with an X.509 certificate which appears
     * in the certificate chain.
     *
     * <p>Note that only items referenced in {@code entriesToRequest} are returned - the
     * {@code requestMessage} parameter is only used to for enforcing reader authentication.
     * {@code requestMessage} parameter is used only for enforcing reader authentication.
     *
     * <p>The reason for having {@code requestMessage} and {@code entriesToRequest} as separate
     * parameters is that the former represents a request from the remote verifier device
@@ -219,13 +228,12 @@ public abstract class IdentityCredential {
     * @param entriesToRequest       The entries to request, organized as a map of namespace
     *                               names with each value being a collection of data elements
     *                               in the given namespace.
     * @param readerSignature        COSE_Sign1 structure as described above or {@code null}
     *                               if reader authentication is not being used.
     * @param readerSignature        A {@code COSE_Sign1} structure as described above or
     *                               {@code null} if reader authentication is not being used.
     * @return A {@link ResultData} object containing entry data organized by namespace and a
     *         cryptographically authenticated representation of the same data.
     * @throws SessionTranscriptMismatchException     Thrown when trying use multiple different
     *                                                session transcripts in the same presentation
     *                                                session.
     *                                                session transcripts.
     * @throws NoAuthenticationKeyAvailableException  if authentication keys were never
     *                                                provisioned, the method
     *                                             {@link #setAvailableAuthenticationKeys(int, int)}
@@ -255,8 +263,8 @@ public abstract class IdentityCredential {
     * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain,
     * and the number of times each should be used.
     *
     * <p>{@code IdentityCredential}s will select the least-used dynamic authentication key each
     * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. {@code IdentityCredential}s
     * <p>The Identity Credential system will select the least-used dynamic authentication key each
     * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. Identity Credentials
     * for which this method has not been called behave as though it had been called wit
     * {@code keyCount} 0 and {@code maxUsesPerKey} 1.
     *
@@ -275,8 +283,9 @@ public abstract class IdentityCredential {
     * count has been increased or because one or more keys have reached their usage count, this
     * method will generate replacement keys and certificates and return them for issuer
     * certification.  The issuer certificates and associated static authentication data must then
     * be provided back to the {@code IdentityCredential} using
     * {@link #storeStaticAuthenticationData(X509Certificate, byte[])}.
     * be provided back to the Identity Credential using
     * {@link #storeStaticAuthenticationData(X509Certificate, byte[])}.  The private part of
     * each authentication key never leaves secure hardware.
     *
     * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey
     * can be obtained using the {@link #getCredentialKeyCertificateChain()} method.
+27 −8
Original line number Diff line number Diff line
@@ -78,17 +78,21 @@ public abstract class IdentityCredentialStore {

    /**
     * Specifies that the cipher suite that will be used to secure communications between the reader
     * is:
     * and the prover is using the following primitives
     *
     * <ul>
     * <li>ECDHE with HKDF-SHA-256 for key agreement.</li>
     * <li>AES-256 with GCM block mode for authenticated encryption (nonces are incremented by one
     * for every message).</li>
     * <li>ECDSA with SHA-256 for signing (used for signing session transcripts to defeat
     * man-in-the-middle attacks), signing keys are not ephemeral. See {@link IdentityCredential}
     * for details on reader and prover signing keys.</li>
     * <li>ECKA-DH (Elliptic Curve Key Agreement Algorithm - Diffie-Hellman, see BSI TR-03111).</li>
     *
     * <li>HKDF-SHA-256 (see RFC 5869).</li>
     *
     * <li>AES-256-GCM (see NIST SP 800-38D).</li>
     *
     * <li>HMAC-SHA-256 (see RFC 2104).</li>
     * </ul>
     *
     * <p>The exact way these primitives are combined to derive the session key is specified in
     * section 9.2.1.4 of ISO/IEC 18013-5 (see description of cipher suite '1').<p>
     *
     * <p>
     * At present this is the only supported cipher suite.
     */
@@ -135,9 +139,20 @@ public abstract class IdentityCredentialStore {
    /**
     * Creates a new credential.
     *
     * <p>When a credential is created, a cryptographic key-pair - CredentialKey - is created which
     * is used to authenticate the store to the Issuing Authority.  The private part of this
     * key-pair never leaves secure hardware and the public part can be obtained using
     * {@link WritableIdentityCredential#getCredentialKeyCertificateChain(byte[])} on the
     * returned object.
     *
     * <p>In addition, all of the Credential data content is imported and a certificate for the
     * CredentialKey and a signature produced with the CredentialKey are created.  These latter
     * values may be checked by an issuing authority to verify that the data was imported into
     * secure hardware and that it was imported unmodified.
     *
     * @param credentialName The name used to identify the credential.
     * @param docType        The document type for the credential.
     * @return A @{link WritableIdentityCredential} that can be used to create a new credential.
     * @return A {@link WritableIdentityCredential} that can be used to create a new credential.
     * @throws AlreadyPersonalizedException if a credential with the given name already exists.
     * @throws DocTypeNotSupportedException if the given document type isn't supported by the store.
     */
@@ -148,6 +163,10 @@ public abstract class IdentityCredentialStore {
    /**
     * Retrieve a named credential.
     *
     * <p>The cipher suite used to communicate with the remote verifier must also be specified.
     * Currently only a single cipher-suite is supported. Support for other cipher suites may be
     * added in a future version of this API.
     *
     * @param credentialName the name of the credential to retrieve.
     * @param cipherSuite    the cipher suite to use for communicating with the verifier.
     * @return The named credential, or null if not found.
+21 −22
Original line number Diff line number Diff line
@@ -34,23 +34,23 @@ public abstract class ResultData {
    /** Value was successfully retrieved. */
    public static final int STATUS_OK = 0;

    /** Requested entry does not exist. */
    /** The entry does not exist. */
    public static final int STATUS_NO_SUCH_ENTRY = 1;

    /** Requested entry was not requested. */
    /** The entry was not requested. */
    public static final int STATUS_NOT_REQUESTED = 2;

    /** Requested entry wasn't in the request message. */
    /** The entry wasn't in the request message. */
    public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3;

    /** The requested entry was not retrieved because user authentication wasn't performed. */
    /** The entry was not retrieved because user authentication failed. */
    public static final int STATUS_USER_AUTHENTICATION_FAILED = 4;

    /** The requested entry was not retrieved because reader authentication wasn't performed. */
    /** The entry was not retrieved because reader authentication failed. */
    public static final int STATUS_READER_AUTHENTICATION_FAILED = 5;

    /**
     * The requested entry was not retrieved because it was configured without any access
     * The entry was not retrieved because it was configured without any access
     * control profile.
     */
    public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6;
@@ -88,11 +88,10 @@ public abstract class ResultData {
     *
     *   DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement)
     *   EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub)
     *
     *   DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces)
     * </pre>
     *
     * where
     * <p>where
     *
     * <pre>
     *   DeviceNameSpaces = {
@@ -116,15 +115,16 @@ public abstract class ResultData {
    public abstract @NonNull byte[] getAuthenticatedData();

    /**
     * Returns a message authentication code over the data returned by
     * {@link #getAuthenticatedData}, to prove to the reader that the data is from a trusted
     * credential.
     * Returns a message authentication code over the {@code DeviceAuthentication} CBOR
     * specified in {@link #getAuthenticatedData()}, to prove to the reader that the data
     * is from a trusted credential.
     *
     * <p>The MAC proves to the reader that the data is from a trusted credential. This code is
     * produced by using the key agreement and key derivation function from the ciphersuite
     * with the authentication private key and the reader ephemeral public key to compute a
     * shared message authentication code (MAC) key, then using the MAC function from the
     * ciphersuite to compute a MAC of the authenticated data.
     * ciphersuite to compute a MAC of the authenticated data. See section 9.2.3.5 of
     * ISO/IEC 18013-5 for details of this operation.
     *
     * <p>If the {@code sessionTranscript} parameter passed to
     * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])} was {@code null}
@@ -157,7 +157,7 @@ public abstract class ResultData {
    /**
     * Get the names of all entries.
     *
     * This includes the name of entries that wasn't successfully retrieved.
     * <p>This includes the name of entries that wasn't successfully retrieved.
     *
     * @param namespaceName the namespace name to get entries for.
     * @return A collection of names or {@code null} if there are no entries for the given
@@ -168,7 +168,7 @@ public abstract class ResultData {
    /**
     * Get the names of all entries that was successfully retrieved.
     *
     * This only return entries for which {@link #getStatus(String, String)} will return
     * <p>This only return entries for which {@link #getStatus(String, String)} will return
     * {@link #STATUS_OK}.
     *
     * @param namespaceName the namespace name to get entries for.
@@ -181,16 +181,15 @@ public abstract class ResultData {
    /**
     * Gets the status of an entry.
     *
     * This returns {@link #STATUS_OK} if the value was retrieved, {@link #STATUS_NO_SUCH_ENTRY}
     * <p>This returns {@link #STATUS_OK} if the value was retrieved, {@link #STATUS_NO_SUCH_ENTRY}
     * if the given entry wasn't retrieved, {@link #STATUS_NOT_REQUESTED} if it wasn't requested,
     * {@link #STATUS_NOT_IN_REQUEST_MESSAGE} if the request message was set but the entry wasn't
     * present in the request message,
     * {@link #STATUS_USER_AUTHENTICATION_FAILED} if the value
     * present in the request message, {@link #STATUS_USER_AUTHENTICATION_FAILED} if the value
     * wasn't retrieved because the necessary user authentication wasn't performed,
     * {@link #STATUS_READER_AUTHENTICATION_FAILED} if the supplied reader certificate chain
     * didn't match the set of certificates the entry was provisioned with, or
     * {@link #STATUS_NO_ACCESS_CONTROL_PROFILES} if the entry was configured without any
     * access control profiles.
     * {@link #STATUS_READER_AUTHENTICATION_FAILED} if the supplied reader certificate chain didn't
     * match the set of certificates the entry was provisioned with, or
     * {@link #STATUS_NO_ACCESS_CONTROL_PROFILES} if the entry was configured without any access
     * control profiles.
     *
     * @param namespaceName the namespace name of the entry.
     * @param name the name of the entry to get the value for.
@@ -201,7 +200,7 @@ public abstract class ResultData {
    /**
     * Gets the raw CBOR data for the value of an entry.
     *
     * This should only be called on an entry for which the {@link #getStatus(String, String)}
     * <p>This should only be called on an entry for which the {@link #getStatus(String, String)}
     * method returns {@link #STATUS_OK}.
     *
     * @param namespaceName the namespace name of the entry.
+8 −7
Original line number Diff line number Diff line
@@ -41,15 +41,16 @@ public abstract class WritableIdentityCredential {
     * <a href="https://source.android.com/security/keystore/attestation">Android Keystore</a>
     * attestation extension which describes the key and the security hardware in which it lives.
     *
     * <p>Additionally, the attestation extension will contain the tag TODO_IC_KEY which indicates
     * it is an Identity Credential key (which can only sign/MAC very specific messages) and not
     * an Android Keystore key (which can be used to sign/MAC anything).
     * <p>Additionally, the attestation extension will contain the tag Tag::IDENTITY_CREDENTIAL_KEY
     * which indicates it is an Identity Credential key (which can only sign/MAC very specific
     * messages) and not an Android Keystore key (which can be used to sign/MAC anything).
     *
     * <p>The issuer <b>MUST</b> carefully examine this certificate chain including (but not
     * limited to) checking that the root certificate is well-known, the tag TODO_IC_KEY is
     * present, the passed in challenge is present, the device has verified boot enabled, that each
     * certificate in the chain is signed by its successor, that none of the certificates have been
     * revoked and so on.
     * limited to) checking that the root certificate is well-known, the tag
     * Tag::IDENTITY_CREDENTIAL_KEY present, the passed in challenge is present, the tag
     * Tag::ATTESTATION_APPLICATION_ID is set to the expected Android application, the device
     * has verified boot enabled, each certificate in the chain is signed by its successor,
     * none of the certificates have been revoked, and so on.
     *
     * <p>It is not strictly necessary to use this method to provision a credential if the issuing
     * authority doesn't care about the nature of the security hardware. If called, however, this