java.lang.Object
↳androidx.security.identity.IdentityCredential
Gradle dependencies
compile group: 'androidx.security', name: 'security-identity-credential', version: '1.0.0-alpha03'
- groupId: androidx.security
- artifactId: security-identity-credential
- version: 1.0.0-alpha03
Artifact androidx.security:security-identity-credential:1.0.0-alpha03 it located at Google repository (https://maven.google.com/)
Overview
Class used to read data from a previously provisioned credential.
Use IdentityCredentialStore.getCredentialByName(String, int) to get a
IdentityCredential instance.
Summary
Methods |
---|
public abstract java.security.KeyPair | createEphemeralKeyPair()
Create an ephemeral key pair to use to establish a secure channel with a reader. |
public abstract byte[] | decryptMessageFromReader(byte[] messageCiphertext[])
Decrypt a message received from the reader. |
public byte[] | delete(byte[] challenge[])
Deletes a credential. |
public abstract byte[] | encryptMessageToReader(byte[] messagePlaintext[])
Encrypt a message for transmission to the reader. |
public abstract int[] | getAuthenticationDataUsageCount()
Get the number of times the dynamic authentication keys have been used. |
public abstract java.util.Collection<java.security.cert.X509Certificate> | getAuthKeysNeedingCertification()
Gets a collection of dynamic authentication keys that need certification. |
public abstract java.util.Collection<java.security.cert.X509Certificate> | getCredentialKeyCertificateChain()
Gets the X.509 certificate chain for the CredentialKey which identifies this
credential to the issuing authority. |
public abstract BiometricPrompt.CryptoObject | getCryptoObject()
Gets a which can be used with this
IdentityCredential. |
public abstract ResultData | getEntries(byte[] requestMessage[], java.util.Map<java.lang.String, java.util.Collection> entriesToRequest, byte[] readerSignature[])
Retrieve data entries and associated data from this IdentityCredential. |
public byte[] | proveOwnership(byte[] challenge[])
Proves ownership of a credential. |
public abstract void | setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys)
Sets whether to allow using an authentication key which use count has been exceeded if no
other key is available. |
public void | setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys)
Sets whether to allow using an authentication key which has been expired if no
other key is available. |
public abstract void | setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey)
Sets the number of dynamic authentication keys the IdentityCredential will maintain,
and the number of times each should be used. |
public abstract void | setReaderEphemeralPublicKey(java.security.PublicKey readerEphemeralPublicKey)
Set the ephemeral public key provided by the reader. |
public abstract void | setSessionTranscript(byte[] sessionTranscript[])
Set the session transcript. |
public abstract void | storeStaticAuthenticationData(java.security.cert.X509Certificate authenticationKey, byte[] staticAuthData[])
Store authentication data associated with a dynamic authentication key. |
public void | storeStaticAuthenticationData(java.security.cert.X509Certificate authenticationKey, Calendar expirationDate, byte[] staticAuthData[])
Store authentication data associated with a dynamic authentication key. |
public byte[] | update(PersonalizationData personalizationData)
Updates the credential with new access control profiles and data items. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Constructors
protected
IdentityCredential()
Methods
public abstract java.security.KeyPair
createEphemeralKeyPair()
Create an ephemeral key pair to use to establish a secure channel with a reader.
Most applications will use only the public key, and only to send it to the reader,
allowing the private key to be used internally for IdentityCredential.encryptMessageToReader(byte[])
and IdentityCredential.decryptMessageFromReader(byte[]). The private key is also provided for
applications that wish to use a cipher suite that is not supported by
IdentityCredentialStore.
Returns:
ephemeral key pair to use to establish a secure channel with a reader.
public abstract void
setReaderEphemeralPublicKey(java.security.PublicKey readerEphemeralPublicKey)
Set the ephemeral public key provided by the reader. This must be called before
IdentityCredential.encryptMessageToReader(byte[]) or IdentityCredential.decryptMessageFromReader(byte[]) can be called.
Parameters:
readerEphemeralPublicKey: The ephemeral public key provided by the reader to
establish a secure session.
public abstract void
setSessionTranscript(byte[] sessionTranscript[])
Set the session transcript. This must be called before
IdentityCredential.encryptMessageToReader(byte[]) or IdentityCredential.decryptMessageFromReader(byte[]) can be called.
This method can only be called once per IdentityCredential instance.
Parameters:
sessionTranscript: the session transcript.
public abstract byte[]
encryptMessageToReader(byte[] messagePlaintext[])
Encrypt a message for transmission to the reader.
In order for this to work, IdentityCredential.setSessionTranscript(byte[]) and
IdentityCredential.setReaderEphemeralPublicKey(PublicKey) must have already been
called.
Parameters:
messagePlaintext: unencrypted message to encrypt.
Returns:
encrypted message.
public abstract byte[]
decryptMessageFromReader(byte[] messageCiphertext[])
Decrypt a message received from the reader.
In order for this to work, IdentityCredential.setSessionTranscript(byte[]) and
IdentityCredential.setReaderEphemeralPublicKey(PublicKey) must have already been
called.
Parameters:
messageCiphertext: encrypted message to decrypt.
Returns:
decrypted message.
public abstract java.util.Collection<java.security.cert.X509Certificate>
getCredentialKeyCertificateChain()
Gets the X.509 certificate chain for the CredentialKey which identifies this
credential to the issuing authority. This is the same certificate chain that
was returned by WritableIdentityCredential.getCredentialKeyCertificateChain(byte[])
when the credential was first created and its Android Keystore extension will
contain the challenge
data set at that time. See the documentation
for that method for important information about this certificate chain.
Returns:
the certificate chain for this credential's CredentialKey.
public abstract void
setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys)
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
IdentityCredential.getEntries(byte[], Map>, byte[]) or using a
which references this object.
By default this is set to true.
Parameters:
allowUsingExhaustedKeys: whether to allow using an authentication key which use count
has been exceeded if no other key is available.
public void
setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys)
Sets whether to allow using an authentication key which has been expired if no
other key is available. This must be called prior to calling
IdentityCredential.getEntries(byte[], Map>, byte[]) or using a
which references this object.
By default this is set to false.
This is only implemented if
IdentityCredentialStoreCapabilities.isStaticAuthenticationDataExpirationSupported()
returns true. If not the call fails with java.lang.UnsupportedOperationException
.
Parameters:
allowUsingExpiredKeys: whether to allow using an authentication key which use count
has been exceeded if no other key is available.
Gets a which can be used with this
IdentityCredential.
If IdentityCredential is not hardware-backed the returned
is associated with a java.security.Signature
object. If IdentityCredential is hardware-backed, the returned
is associated
object from the Android Framework.
Because of this, this method is the preferred way
to obtain a rather than to construct it
manually.
If the credential has no access control profiles with user-authentication, the value
null may be returned.
Returns:
A which can be used with
BiometricPrompt or null.
public abstract
ResultData getEntries(byte[] requestMessage[], java.util.Map<java.lang.String, java.util.Collection> entriesToRequest, byte[] readerSignature[])
Retrieve data entries and associated data from this IdentityCredential.
If an access control check fails for one of the requested entries or if the entry
doesn't exist, the entry is simply not returned. The application can detect this
by using the ResultData.getStatus(String, String) method on each of the requested
entries.
It is the responsibility of the calling application to know if authentication is needed
and use e.g. BiometricPrompt to make the user
authenticate using a BiometricPrompt.CryptoObject which
references this object. If needed, this must be done before calling
IdentityCredential.getEntries(byte[], Map>, byte[]).
It is permissible to call this method multiple times using the same instance.
If not null the requestMessage parameter must contain data for the request
from the verifier. The content can be defined in the way appropriate for the credential, but
there are three requirements that must be met to work with this API:
- The content must be a CBOR-encoded structure.
- The CBOR structure must be a map.
- The map must contain a tstr key "nameSpaces" whose value contains a map, as described in
the example below.
If these requirements are not met the InvalidRequestMessageException exception
is thrown.
Here's an example of CBOR which conforms to this requirement:
ItemsRequest = {
? "docType" : DocType,
"nameSpaces" : NameSpaces,
? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide
}
DocType = tstr
NameSpaces = {
+ NameSpace => DataElements ; Requested data elements for each NameSpace
}
NameSpace = tstr
DataElements = {
+ DataElement => IntentToRetain
}
DataElement = tstr
IntentToRetain = bool
If the IdentityCredential.setSessionTranscript(byte[]) was called, the X and Y coordinates
of the public part of the key-pair previously generated by IdentityCredential.createEphemeralKeyPair()
must appear somewhere in the byte array that was set. Each of these coordinates must appear
encoded with the most significant bits first and use the exact amount of bits indicated by
the key size of the ephemeral keys. For example, if the ephemeral key is using the P-256
curve then the 32 bytes for the X coordinate encoded with the most significant bits first
must appear somewhere in the CBOR and ditto for the 32 bytes for the Y coordinate.
If readerAuth is not null it must be the bytes of a COSE_Sign1
structure as defined in RFC 8152. For the payload nil shall be used and the
detached payload is the ReaderAuthenticationBytes CBOR described below.
ReaderAuthentication = [
"ReaderAuthentication",
SessionTranscript,
ItemsRequestBytes
]
ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication)
where ItemsRequestBytes are the bytes in the requestMessage parameter.
The public key corresponding to the key used to make the signature, can be found in the
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,
each certificate must be signed by its successor).
Data elements protected by reader authentication are returned if, and only if, they are
mentioned in requestMessage, requestMessage is signed by the top-most
certificate in the reader's certificate chain, and the data element is configured
with an AccessControlProfile configured with an X.509 certificate which appears
in the certificate chain.
Note that only items referenced in entriesToRequest are returned - the
requestMessage parameter is used only for enforcing reader authentication.
The reason for having requestMessage and entriesToRequest as separate
parameters is that the former represents a request from the remote verifier device
(optionally signed) and this allows the application to filter the request to not include
data elements which the user has not consented to sharing.
Parameters:
requestMessage: If not null, must contain CBOR data conforming to
the schema mentioned above.
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.
readerSignature: A COSE_Sign1 structure as described above or
null if reader authentication is not being used.
Returns:
A ResultData object containing entry data organized by namespace and a
cryptographically authenticated representation of the same data.
public abstract void
setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey)
Sets the number of dynamic authentication keys the IdentityCredential will maintain,
and the number of times each should be used.
IdentityCredentials will select the least-used dynamic authentication key each
time IdentityCredential.getEntries(byte[], Map>, byte[]) is called. IdentityCredentials
for which this method has not been called behave as though it had been called wit
keyCount 0 and maxUsesPerKey 1.
Parameters:
keyCount: The number of active, certified dynamic authentication keys the
IdentityCredential will try to keep available. This value
must be non-negative.
maxUsesPerKey: The maximum number of times each of the keys will be used before it's
eligible for replacement. This value must be greater than zero.
public abstract java.util.Collection<java.security.cert.X509Certificate>
getAuthKeysNeedingCertification()
Gets a collection of dynamic authentication keys that need certification.
When there aren't enough certified dynamic authentication keys (either because the key
count has been increased, one or more keys have reached their usage count, or keys have
expired), 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 IdentityCredential using
IdentityCredential.storeStaticAuthenticationData(X509Certificate, Calendar, byte[]).
Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey
can be obtained using the IdentityCredential.getCredentialKeyCertificateChain() method.
The following non-optional fields for the X.509 certificate are set as follows:
- version: INTEGER 2 (means v3 certificate).
- serialNumber: INTEGER 1 (fixed value: same on all certs).
- signature: must be set to ECDSA.
- subject: CN shall be set to "Android Identity Credential Authentication Key" (fixed
value: same on all certs).
- issuer: CN shall be set to "Android Identity Credential Key" (fixed value: same on
all certs).
- validity: should be from current time and one year in the future (365 days).
- subjectPublicKeyInfo: must contain attested public key.
If IdentityCredentialStoreCapabilities.isUpdateSupported() returns
true, each X.509 certificate contains an X.509 extension at OID 1.3.6.1.4.1.11129
.2.1.26 which contains a DER encoded OCTET STRING with the bytes of the CBOR with the
following CDDL:
ProofOfBinding = [
"ProofOfBinding",
bstr, // Contains SHA-256(ProofOfProvisioning)
]
This CBOR enables an issuer to determine the exact state of the credential it
returns issuer-signed data for.
Returns:
A collection of X.509 certificates for dynamic authentication keys that need issuer
certification.
public abstract void
storeStaticAuthenticationData(java.security.cert.X509Certificate authenticationKey, byte[] staticAuthData[])
Deprecated: Use IdentityCredential.storeStaticAuthenticationData(X509Certificate, Calendar, byte[])
instead.
Store authentication data associated with a dynamic authentication key.
This should only be called for an authenticated key returned by
IdentityCredential.getAuthKeysNeedingCertification().
Parameters:
authenticationKey: The dynamic authentication key for which certification and
associated static authentication data is being provided.
staticAuthData: Static authentication data provided by the issuer that validates
the authenticity
and integrity of the credential data fields.
public void
storeStaticAuthenticationData(java.security.cert.X509Certificate authenticationKey, Calendar expirationDate, byte[] staticAuthData[])
Store authentication data associated with a dynamic authentication key.
This should only be called for an authenticated key returned by
IdentityCredential.getAuthKeysNeedingCertification().
This is only implemented if
IdentityCredentialStoreCapabilities.isStaticAuthenticationDataExpirationSupported()
returns true. If not the call fails with java.lang.UnsupportedOperationException
.
Parameters:
authenticationKey: The dynamic authentication key for which certification and
associated static authentication data is being provided.
expirationDate: The expiration date of the static authentication data.
staticAuthData: Static authentication data provided by the issuer that validates
the authenticity
and integrity of the credential data fields.
public abstract int[]
getAuthenticationDataUsageCount()
Get the number of times the dynamic authentication keys have been used.
Returns:
int array of dynamic authentication key usage counts.
public byte[]
proveOwnership(byte[] challenge[])
Proves ownership of a credential.
This method returns a COSE_Sign1 data structure signed by the CredentialKey
with payload set to ProofOfOwnership as defined below.
ProofOfOwnership = [
"ProofOfOwnership", ; tstr
tstr, ; DocType
bstr, ; Challenge
bool ; true if this is a test credential, should
; always be false.
]
This is only implemented if
IdentityCredentialStoreCapabilities.isProveOwnershipSupported()
returns true. If not the call fails with java.lang.UnsupportedOperationException
.
Parameters:
challenge: is a non-empty byte array whose contents should be unique, fresh and
provided by the issuing authority. The value provided is embedded in the
generated CBOR and enables the issuing authority to verify that the
returned proof is fresh.
Returns:
the COSE_Sign1 data structure above
public byte[]
delete(byte[] challenge[])
Deletes a credential.
This method returns a COSE_Sign1 data structure signed by the CredentialKey
with payload set to ProofOfDeletion as defined below.
ProofOfDeletion = [
"ProofOfDeletion", ; tstr
tstr, ; DocType
bstr, ; Challenge
bool ; true if this is a test credential, should
; always be false.
]
This is only implemented if
IdentityCredentialStoreCapabilities.isDeleteSupported()
returns true. If not the call fails with java.lang.UnsupportedOperationException
.
Parameters:
challenge: is a non-empty byte array whose contents should be unique, fresh and
provided by the issuing authority. The value provided is embedded in the
generated CBOR and enables the issuing authority to verify that the
returned proof is fresh.
Returns:
the COSE_Sign1 data structure above
Updates the credential with new access control profiles and data items.
This method is similar to
WritableIdentityCredential.personalize(PersonalizationData) except that it operates
on an existing credential, see the documentation for that method for the format of the
returned data.
If this call succeeds an side-effect is that all dynamic authentication keys for the
credential are deleted. The application will need to use
IdentityCredential.getAuthKeysNeedingCertification() to generate replacement keys and return
them for issuer certification.
This is only implemented if
IdentityCredentialStoreCapabilities.isUpdateSupported()
returns true. If not the call fails with java.lang.UnsupportedOperationException
.
Parameters:
personalizationData: The data to update, including access control profiles
and data elements and their values, grouped into namespaces.
Returns:
A COSE_Sign1 data structure, see above.
Source
/*
* Copyright 2019 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.
*/
package androidx.security.identity;
import android.icu.util.Calendar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.biometric.BiometricPrompt;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Map;
/**
* Class used to read data from a previously provisioned credential.
*
* Use {@link IdentityCredentialStore#getCredentialByName(String, int)} to get a
* {@link IdentityCredential} instance.
*/
public abstract class IdentityCredential {
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.SUBCLASSES)
protected IdentityCredential() {}
/**
* Create an ephemeral key pair to use to establish a secure channel with a reader.
*
* <p>Most applications will use only the public key, and only to send it to the reader,
* allowing the private key to be used internally for {@link #encryptMessageToReader(byte[])}
* and {@link #decryptMessageFromReader(byte[])}. The private key is also provided for
* applications that wish to use a cipher suite that is not supported by
* {@link IdentityCredentialStore}.
*
* @return ephemeral key pair to use to establish a secure channel with a reader.
*/
public @NonNull abstract KeyPair createEphemeralKeyPair();
/**
* Set the ephemeral public key provided by the reader. This must be called before
* {@link #encryptMessageToReader} or {@link #decryptMessageFromReader} can be called.
*
* @param readerEphemeralPublicKey The ephemeral public key provided by the reader to
* establish a secure session.
* @throws InvalidKeyException if the given key is invalid.
*/
public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey)
throws InvalidKeyException;
/**
* Set the session transcript. This must be called before
* {@link #encryptMessageToReader} or {@link #decryptMessageFromReader} can be called.
*
* <p>This method can only be called once per {@link IdentityCredential} instance.
*
* @param sessionTranscript the session transcript.
*/
public abstract void setSessionTranscript(@NonNull byte[] sessionTranscript);
/**
* Encrypt a message for transmission to the reader.
*
* <p>In order for this to work, {@link #setSessionTranscript(byte[])} and
* {@link #setReaderEphemeralPublicKey(PublicKey)} must have already been
* called.
*
* @param messagePlaintext unencrypted message to encrypt.
* @return encrypted message.
*/
public @NonNull abstract byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext);
/**
* Decrypt a message received from the reader.
*
* <p>In order for this to work, {@link #setSessionTranscript(byte[])} and
* {@link #setReaderEphemeralPublicKey(PublicKey)} must have already been
* called.
*
* @param messageCiphertext encrypted message to decrypt.
* @return decrypted message.
* @throws MessageDecryptionException if the ciphertext couldn't be decrypted.
*/
public @NonNull abstract byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext)
throws MessageDecryptionException;
/**
* Gets the X.509 certificate chain for the CredentialKey which identifies this
* credential to the issuing authority. This is the same certificate chain that
* was returned by {@link WritableIdentityCredential#getCredentialKeyCertificateChain(byte[])}
* when the credential was first created and its Android Keystore extension will
* contain the <code>challenge</code> data set at that time. See the documentation
* for that method for important information about this certificate chain.
*
* @return the certificate chain for this credential's CredentialKey.
*/
public @NonNull abstract Collection<X509Certificate> getCredentialKeyCertificateChain();
/**
* 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[])} or using a {@link BiometricPrompt.CryptoObject}
* which references this object.
*
* <p>By default this is set to true.</p>
*
* @param allowUsingExhaustedKeys whether to allow using an authentication key which use count
* has been exceeded if no other key is available.
*/
public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys);
/**
* Sets whether to allow using an authentication key which has been expired if no
* other key is available. This must be called prior to calling
* {@link #getEntries(byte[], Map, byte[])} or using a {@link BiometricPrompt.CryptoObject}
* which references this object.
*
* <p>By default this is set to false.
*
* <p>This is only implemented if
* {@link IdentityCredentialStoreCapabilities#isStaticAuthenticationDataExpirationSupported()}
* returns {@code true}. If not the call fails with {@link UnsupportedOperationException}.
*
* @param allowUsingExpiredKeys whether to allow using an authentication key which use count
* has been exceeded if no other key is available.
*/
public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) {
throw new UnsupportedOperationException();
}
/**
* Gets a {@link BiometricPrompt.CryptoObject} which can be used with this
* {@link IdentityCredential}.
*
* <p>If {@link IdentityCredential} is not hardware-backed the returned
* {@link BiometricPrompt.CryptoObject} is associated with a {@link java.security.Signature}
* object. If {@link IdentityCredential} is hardware-backed, the returned
* {@link BiometricPrompt.CryptoObject} is associated
* {@link android.security.identity.IdentityCredential} object from the Android Framework.
* Because of this, this method is the preferred way
* to obtain a {@link BiometricPrompt.CryptoObject} rather than to construct it
* manually.</p>
*
* <p>If the credential has no access control profiles with user-authentication, the value
* {@code null} may be returned.</p>
*
* @return A {@link BiometricPrompt.CryptoObject} which can be used with
* {@link BiometricPrompt} or {@code null}.
*/
@Nullable
public abstract BiometricPrompt.CryptoObject getCryptoObject();
/**
* Retrieve data entries and associated data from this {@code IdentityCredential}.
*
* <p>If an access control check fails for one of the requested entries or if the entry
* doesn't exist, the entry is simply not returned. The application can detect this
* by using the {@link ResultData#getStatus(String, String)} method on each of the requested
* entries.
*
* <p>It is the responsibility of the calling application to know if authentication is needed
* and use e.g. {@link androidx.biometric.BiometricPrompt} to make the user
* authenticate using a {@link androidx.biometric.BiometricPrompt.CryptoObject} which
* references this object. If needed, this must be done before calling
* {@link #getEntries(byte[], Map, byte[])}.
*
* <p>It is permissible to call this method multiple times using the same instance.
*
* <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, but
* there are three requirements that must be met to work with this API:
* <ul>
* <li>The content must be a CBOR-encoded structure.</li>
* <li>The CBOR structure must be a map.</li>
* <li>The map must contain a tstr key "nameSpaces" whose value contains a map, as described in
* 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 = {
* ? "docType" : DocType,
* "nameSpaces" : NameSpaces,
* ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide
* }
*
* DocType = tstr
*
* NameSpaces = {
* + NameSpace => DataElements ; Requested data elements for each NameSpace
* }
*
* NameSpace = tstr
*
* DataElements = {
* + DataElement => IntentToRetain
* }
*
* DataElement = tstr
* IntentToRetain = bool
* </pre>
*
* <p>If the {@link #setSessionTranscript(byte[])} was called, the X and Y coordinates
* of the public part of the key-pair previously generated by {@link #createEphemeralKeyPair()}
* must appear somewhere in the byte array that was set. Each of these coordinates must appear
* encoded with the most significant bits first and use the exact amount of bits indicated by
* the key size of the ephemeral keys. For example, if the ephemeral key is using the P-256
* curve then the 32 bytes for the X coordinate encoded with the most significant bits first
* must appear somewhere in the CBOR and ditto for the 32 bytes for the Y coordinate.
*
* <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 ReaderAuthenticationBytes CBOR described below.
* <pre>
* ReaderAuthentication = [
* "ReaderAuthentication",
* SessionTranscript,
* ItemsRequestBytes
* ]
*
* ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest)
*
* ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication)
* </pre>
*
* <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 are returned if, and only if, they are
* mentioned in {@code requestMessage}, {@code requestMessage} is signed by the top-most
* 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 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
* (optionally signed) and this allows the application to filter the request to not include
* data elements which the user has not consented to sharing.
*
* @param requestMessage If not {@code null}, must contain CBOR data conforming to
* the schema mentioned above.
* @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 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 NoAuthenticationKeyAvailableException is thrown if authentication keys were never
* provisioned, none are available, or the
* available ones are all exhausted and
* {@link #setAllowUsingExhaustedKeys(boolean)}
* was called with {@code false}.
* @throws InvalidReaderSignatureException if the reader signature is invalid, or it
* doesn't contain a certificate chain, or if
* the signature failed to validate.
* @throws InvalidRequestMessageException if the requestMessage is malformed.
* @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in
* the session transcript.
*/
public abstract @NonNull ResultData getEntries(
@Nullable byte[] requestMessage,
@NonNull Map<String, Collection<String>> entriesToRequest,
@Nullable byte[] readerSignature)
throws NoAuthenticationKeyAvailableException,
InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException,
InvalidRequestMessageException;
/**
* 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[])} is called. {@code IdentityCredential}s
* for which this method has not been called behave as though it had been called wit
* {@code keyCount} 0 and {@code maxUsesPerKey} 1.
*
* @param keyCount The number of active, certified dynamic authentication keys the
* {@code IdentityCredential} will try to keep available. This value
* must be non-negative.
* @param maxUsesPerKey The maximum number of times each of the keys will be used before it's
* eligible for replacement. This value must be greater than zero.
*/
public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
/**
* Gets a collection of dynamic authentication keys that need certification.
*
* <p>When there aren't enough certified dynamic authentication keys (either because the key
* count has been increased, one or more keys have reached their usage count, or keys have
* expired), 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, Calendar, byte[])}.
*
* <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey
* can be obtained using the {@link #getCredentialKeyCertificateChain()} method.
*
* <p>The following non-optional fields for the X.509 certificate are set as follows:
* <ul>
* <li>version: INTEGER 2 (means v3 certificate).</li>
* <li>serialNumber: INTEGER 1 (fixed value: same on all certs).</li>
* <li>signature: must be set to ECDSA.</li>
* <li>subject: CN shall be set to "Android Identity Credential Authentication Key" (fixed
* value: same on all certs).</li>
* <li>issuer: CN shall be set to "Android Identity Credential Key" (fixed value: same on
* all certs).</li>
* <li>validity: should be from current time and one year in the future (365 days).</li>
* <li>subjectPublicKeyInfo: must contain attested public key.</li>
* </ul>
*
* <p>If {@link IdentityCredentialStoreCapabilities#isUpdateSupported()} returns
* {@code true}, each X.509 certificate contains an X.509 extension at OID 1.3.6.1.4.1.11129
* .2.1.26 which contains a DER encoded OCTET STRING with the bytes of the CBOR with the
* following CDDL:
* <pre>
* ProofOfBinding = [
* "ProofOfBinding",
* bstr, // Contains SHA-256(ProofOfProvisioning)
* ]
* </pre>
* <p>This CBOR enables an issuer to determine the exact state of the credential it
* returns issuer-signed data for.
*
* @return A collection of X.509 certificates for dynamic authentication keys that need issuer
* certification.
*/
public @NonNull abstract Collection<X509Certificate> getAuthKeysNeedingCertification();
/**
* Store authentication data associated with a dynamic authentication key.
*
* <p>This should only be called for an authenticated key returned by
* {@link #getAuthKeysNeedingCertification()}.</p>
*
* @param authenticationKey The dynamic authentication key for which certification and
* associated static authentication data is being provided.
* @param staticAuthData Static authentication data provided by the issuer that validates
* the authenticity
* and integrity of the credential data fields.
* @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
* @deprecated Use {@link #storeStaticAuthenticationData(X509Certificate, Calendar, byte[])}
* instead.
*/
@Deprecated
public abstract void storeStaticAuthenticationData(
@NonNull X509Certificate authenticationKey,
@NonNull byte[] staticAuthData)
throws UnknownAuthenticationKeyException;
/**
* Store authentication data associated with a dynamic authentication key.
*
* <p>This should only be called for an authenticated key returned by
* {@link #getAuthKeysNeedingCertification()}.</p>
*
* <p>This is only implemented if
* {@link IdentityCredentialStoreCapabilities#isStaticAuthenticationDataExpirationSupported()}
* returns {@code true}. If not the call fails with {@link UnsupportedOperationException}.
*
* @param authenticationKey The dynamic authentication key for which certification and
* associated static authentication data is being provided.
* @param expirationDate The expiration date of the static authentication data.
* @param staticAuthData Static authentication data provided by the issuer that validates
* the authenticity
* and integrity of the credential data fields.
* @throws UnknownAuthenticationKeyException If the given authentication key is not recognized.
*/
public void storeStaticAuthenticationData(
@NonNull X509Certificate authenticationKey,
@NonNull Calendar expirationDate,
@NonNull byte[] staticAuthData)
throws UnknownAuthenticationKeyException {
throw new UnsupportedOperationException();
}
/**
* Get the number of times the dynamic authentication keys have been used.
*
* @return int array of dynamic authentication key usage counts.
*/
public @NonNull abstract int[] getAuthenticationDataUsageCount();
/**
* Proves ownership of a credential.
*
* <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
* with payload set to {@code ProofOfOwnership} as defined below.</p>
* <pre>
* ProofOfOwnership = [
* "ProofOfOwnership", ; tstr
* tstr, ; DocType
* bstr, ; Challenge
* bool ; true if this is a test credential, should
* ; always be false.
* ]
* </pre>
*
* <p>This is only implemented if
* {@link IdentityCredentialStoreCapabilities#isProveOwnershipSupported()}
* returns {@code true}. If not the call fails with {@link UnsupportedOperationException}.
*
* @param challenge is a non-empty byte array whose contents should be unique, fresh and
* provided by the issuing authority. The value provided is embedded in the
* generated CBOR and enables the issuing authority to verify that the
* returned proof is fresh.
* @return the COSE_Sign1 data structure above
*/
public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) {
throw new UnsupportedOperationException();
}
/**
* Deletes a credential.
*
* <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey
* with payload set to {@code ProofOfDeletion} as defined below.</p>
* <pre>
* ProofOfDeletion = [
* "ProofOfDeletion", ; tstr
* tstr, ; DocType
* bstr, ; Challenge
* bool ; true if this is a test credential, should
* ; always be false.
* ]
* </pre>
*
* <p>This is only implemented if
* {@link IdentityCredentialStoreCapabilities#isDeleteSupported()}
* returns {@code true}. If not the call fails with {@link UnsupportedOperationException}.
*
* @param challenge is a non-empty byte array whose contents should be unique, fresh and
* provided by the issuing authority. The value provided is embedded in the
* generated CBOR and enables the issuing authority to verify that the
* returned proof is fresh.
* @return the COSE_Sign1 data structure above
*/
public @NonNull byte[] delete(@NonNull byte[] challenge) {
throw new UnsupportedOperationException();
}
/**
* Updates the credential with new access control profiles and data items.
*
* <p>This method is similar to
* {@link WritableIdentityCredential#personalize(PersonalizationData)} except that it operates
* on an existing credential, see the documentation for that method for the format of the
* returned data.
*
* <p>If this call succeeds an side-effect is that all dynamic authentication keys for the
* credential are deleted. The application will need to use
* {@link #getAuthKeysNeedingCertification()} to generate replacement keys and return
* them for issuer certification.
*
* <p>This is only implemented if
* {@link IdentityCredentialStoreCapabilities#isUpdateSupported()}
* returns {@code true}. If not the call fails with {@link UnsupportedOperationException}.
*
* @param personalizationData The data to update, including access control profiles
* and data elements and their values, grouped into namespaces.
* @return A COSE_Sign1 data structure, see above.
*/
public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) {
throw new UnsupportedOperationException();
}
}