1 /* 2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.security.identity; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 22 import java.security.InvalidKeyException; 23 import java.security.KeyPair; 24 import java.security.PublicKey; 25 import java.security.cert.X509Certificate; 26 import java.time.Instant; 27 import java.util.Collection; 28 import java.util.Map; 29 30 /** 31 * Class used to read data from a previously provisioned credential. 32 * 33 * Use {@link IdentityCredentialStore#getCredentialByName(String, int)} to get a 34 * {@link IdentityCredential} instance. 35 */ 36 public abstract class IdentityCredential { 37 /** 38 * @hide 39 */ IdentityCredential()40 protected IdentityCredential() {} 41 42 /** 43 * Create an ephemeral key pair to use to establish a secure channel with a reader. 44 * 45 * <p>Applications should use this key-pair for the communications channel with the reader 46 * using a protocol / cipher-suite appropriate for the application. One example of such a 47 * protocol is the one used for Mobile Driving Licenses, see ISO 18013-5 section 9.2.1 "Session 48 * encryption". 49 * 50 * @return ephemeral key pair to use to establish a secure channel with a reader. 51 */ createEphemeralKeyPair()52 public @NonNull abstract KeyPair createEphemeralKeyPair(); 53 54 /** 55 * Set the ephemeral public key provided by the reader. If called, this must be called before 56 * {@link #getEntries(byte[], Map, byte[], byte[])} is called. 57 * 58 * @param readerEphemeralPublicKey The ephemeral public key provided by the reader to 59 * establish a secure session. 60 * @throws InvalidKeyException if the given key is invalid. 61 */ setReaderEphemeralPublicKey(@onNull PublicKey readerEphemeralPublicKey)62 public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey) 63 throws InvalidKeyException; 64 65 /** 66 * Encrypt a message for transmission to the reader. 67 * 68 * <p>Do not use. In this version of the API, this method produces an incorrect 69 * result. Instead, applications should implement message encryption/decryption themselves as 70 * detailed in the {@link #createEphemeralKeyPair()} method. In a future API-level, this 71 * method will be deprecated. 72 * 73 * @param messagePlaintext unencrypted message to encrypt. 74 * @return encrypted message. 75 */ encryptMessageToReader(@onNull byte[] messagePlaintext)76 public @NonNull abstract byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext); 77 78 /** 79 * Decrypt a message received from the reader. 80 * 81 * <p>Do not use. In this version of the API, this method produces an incorrect 82 * result. Instead, applications should implement message encryption/decryption themselves as 83 * detailed in the {@link #createEphemeralKeyPair()} method. In a future API-level, this 84 * method will be deprecated. 85 * 86 * @param messageCiphertext encrypted message to decrypt. 87 * @return decrypted message. 88 * @throws MessageDecryptionException if the ciphertext couldn't be decrypted. 89 */ decryptMessageFromReader(@onNull byte[] messageCiphertext)90 public @NonNull abstract byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext) 91 throws MessageDecryptionException; 92 93 /** 94 * Gets the X.509 certificate chain for the CredentialKey which identifies this 95 * credential to the issuing authority. This is the same certificate chain that 96 * was returned by {@link WritableIdentityCredential#getCredentialKeyCertificateChain(byte[])} 97 * when the credential was first created and its Android Keystore extension will 98 * contain the <code>challenge</code> data set at that time. See the documentation 99 * for that method for important information about this certificate chain. 100 * 101 * @return the certificate chain for this credential's CredentialKey. 102 */ getCredentialKeyCertificateChain()103 public @NonNull abstract Collection<X509Certificate> getCredentialKeyCertificateChain(); 104 105 /** 106 * Sets whether to allow using an authentication key which use count has been exceeded if no 107 * other key is available. This must be called prior to calling 108 * {@link #getEntries(byte[], Map, byte[], byte[])}. 109 * 110 * By default this is set to true. 111 * 112 * @param allowUsingExhaustedKeys whether to allow using an authentication key which use count 113 * has been exceeded if no other key is available. 114 */ setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys)115 public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys); 116 117 /** 118 * Sets whether to allow using an authentication key which has been expired if no 119 * other key is available. This must be called prior to calling 120 * {@link #getEntries(byte[], Map, byte[], byte[])}. 121 * 122 * <p>By default this is set to false. 123 * 124 * <p>This is only implemented in feature version 202101 or later. If not implemented, the call 125 * fails with {@link UnsupportedOperationException}. See 126 * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known 127 * feature versions. 128 * 129 * @param allowUsingExpiredKeys whether to allow using an authentication key which use count 130 * has been exceeded if no other key is available. 131 */ setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys)132 public void setAllowUsingExpiredKeys(boolean allowUsingExpiredKeys) { 133 throw new UnsupportedOperationException(); 134 } 135 136 /** 137 * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an 138 * operation handle. 139 * 140 * @hide 141 */ getCredstoreOperationHandle()142 public abstract long getCredstoreOperationHandle(); 143 144 /** 145 * Retrieve data entries and associated data from this {@code IdentityCredential}. 146 * 147 * <p>If an access control check fails for one of the requested entries or if the entry 148 * doesn't exist, the entry is simply not returned. The application can detect this 149 * by using the {@link ResultData#getStatus(String, String)} method on each of the requested 150 * entries. 151 * 152 * <p>It is the responsibility of the calling application to know if authentication is needed 153 * and use e.g. {@link android.hardware.biometrics.BiometricPrompt} to make the user 154 * authenticate using a {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which 155 * references this object. If needed, this must be done before calling 156 * {@link #getEntries(byte[], Map, byte[], byte[])}. 157 * 158 * <p>It is permissible to call this method multiple times using the same instance but if this 159 * is done, the {@code sessionTranscript} parameter must be identical for each call. If this is 160 * not the case, the {@link SessionTranscriptMismatchException} exception is thrown. 161 * 162 * <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request 163 * from the verifier. The content can be defined in the way appropriate for the credential, byt 164 * there are three requirements that must be met to work with this API: 165 * <ul> 166 * <li>The content must be a CBOR-encoded structure.</li> 167 * <li>The CBOR structure must be a map.</li> 168 * <li>The map must contain a tstr key "nameSpaces" whose value contains a map, as described in 169 * the example below.</li> 170 * </ul> 171 * 172 * <p>If these requirements are not met the {@link InvalidRequestMessageException} exception 173 * is thrown. 174 * 175 * <p>Here's an example of CBOR which conforms to this requirement: 176 * <pre> 177 * ItemsRequest = { 178 * ? "docType" : DocType, 179 * "nameSpaces" : NameSpaces, 180 * ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide 181 * } 182 * 183 * DocType = tstr 184 * 185 * NameSpaces = { 186 * + NameSpace => DataElements ; Requested data elements for each NameSpace 187 * } 188 * 189 * NameSpace = tstr 190 * 191 * DataElements = { 192 * + DataElement => IntentToRetain 193 * } 194 * 195 * DataElement = tstr 196 * IntentToRetain = bool 197 * </pre> 198 * 199 * <p>If the {@code sessionTranscript} parameter is not {@code null}, the X and Y coordinates 200 * of the public part of the key-pair previously generated by {@link #createEphemeralKeyPair()} 201 * must appear somewhere in the bytes of the CBOR. Each of these coordinates must appear 202 * encoded with the most significant bits first and use the exact amount of bits indicated by 203 * the key size of the ephemeral keys. For example, if the ephemeral key is using the P-256 204 * curve then the 32 bytes for the X coordinate encoded with the most significant bits first 205 * must appear somewhere in {@code sessionTranscript} and ditto for the 32 bytes for the Y 206 * coordinate. 207 * 208 * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a {@code COSE_Sign1} 209 * structure as defined in RFC 8152. For the payload nil shall be used and the 210 * detached payload is the ReaderAuthenticationBytes CBOR described below. 211 * <pre> 212 * ReaderAuthentication = [ 213 * "ReaderAuthentication", 214 * SessionTranscript, 215 * ItemsRequestBytes 216 * ] 217 * 218 * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) 219 * 220 * ReaderAuthenticationBytes = #6.24(bstr .cbor ReaderAuthentication) 221 * </pre> 222 * 223 * <p>where {@code ItemsRequestBytes} are the bytes in the {@code requestMessage} parameter. 224 * 225 * <p>The public key corresponding to the key used to make the signature, can be found in the 226 * {@code x5chain} unprotected header element of the {@code COSE_Sign1} structure (as as 227 * described in 228 * <a href="https://tools.ietf.org/html/draft-ietf-cose-x509-04">draft-ietf-cose-x509-04</a>). 229 * There will be at least one certificate in said element and there may be more (and if so, 230 * each certificate must be signed by its successor). 231 * 232 * <p>Data elements protected by reader authentication are returned if, and only if, they are 233 * mentioned in {@code requestMessage}, {@code requestMessage} is signed by the top-most 234 * certificate in the reader's certificate chain, and the data element is configured 235 * with an {@link AccessControlProfile} configured with an X.509 certificate which appears 236 * in the certificate chain. 237 * 238 * <p>Note that only items referenced in {@code entriesToRequest} are returned - the 239 * {@code requestMessage} parameter is used only for enforcing reader authentication. 240 * 241 * <p>The reason for having {@code requestMessage} and {@code entriesToRequest} as separate 242 * parameters is that the former represents a request from the remote verifier device 243 * (optionally signed) and this allows the application to filter the request to not include 244 * data elements which the user has not consented to sharing. 245 * 246 * @param requestMessage If not {@code null}, must contain CBOR data conforming to 247 * the schema mentioned above. 248 * @param entriesToRequest The entries to request, organized as a map of namespace 249 * names with each value being a collection of data elements 250 * in the given namespace. 251 * @param readerSignature A {@code COSE_Sign1} structure as described above or 252 * {@code null} if reader authentication is not being used. 253 * @return A {@link ResultData} object containing entry data organized by namespace and a 254 * cryptographically authenticated representation of the same data. 255 * @throws SessionTranscriptMismatchException Thrown when trying use multiple different 256 * session transcripts. 257 * @throws NoAuthenticationKeyAvailableException if authentication keys were never 258 * provisioned, the method 259 * {@link #setAvailableAuthenticationKeys(int, int)} 260 * was called with {@code keyCount} set to 0, 261 * the method 262 * {@link #setAllowUsingExhaustedKeys(boolean)} 263 * was called with {@code false} and all 264 * available authentication keys have been 265 * exhausted. 266 * @throws InvalidReaderSignatureException if the reader signature is invalid, or it 267 * doesn't contain a certificate chain, or if 268 * the signature failed to validate. 269 * @throws InvalidRequestMessageException if the requestMessage is malformed. 270 * @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in 271 * the session transcript. 272 */ getEntries( @ullable byte[] requestMessage, @NonNull Map<String, Collection<String>> entriesToRequest, @Nullable byte[] sessionTranscript, @Nullable byte[] readerSignature)273 public abstract @NonNull ResultData getEntries( 274 @Nullable byte[] requestMessage, 275 @NonNull Map<String, Collection<String>> entriesToRequest, 276 @Nullable byte[] sessionTranscript, 277 @Nullable byte[] readerSignature) 278 throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException, 279 InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException, 280 InvalidRequestMessageException; 281 282 /** 283 * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain, 284 * and the number of times each should be used. 285 * 286 * <p>The Identity Credential system will select the least-used dynamic authentication key each 287 * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. Identity Credentials 288 * for which this method has not been called behave as though it had been called wit 289 * {@code keyCount} 0 and {@code maxUsesPerKey} 1. 290 * 291 * @param keyCount The number of active, certified dynamic authentication keys the 292 * {@code IdentityCredential} will try to keep available. This value 293 * must be non-negative. 294 * @param maxUsesPerKey The maximum number of times each of the keys will be used before it's 295 * eligible for replacement. This value must be greater than zero. 296 */ setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey)297 public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey); 298 299 /** 300 * Gets a collection of dynamic authentication keys that need certification. 301 * 302 * <p>When there aren't enough certified dynamic authentication keys, either because the key 303 * count has been increased or because one or more keys have reached their usage count, this 304 * method will generate replacement keys and certificates and return them for issuer 305 * certification. The issuer certificates and associated static authentication data must then 306 * be provided back to the Identity Credential using 307 * {@link #storeStaticAuthenticationData(X509Certificate, byte[])}. The private part of 308 * each authentication key never leaves secure hardware. 309 * 310 * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey 311 * can be obtained using the {@link #getCredentialKeyCertificateChain()} method. 312 313 * <p>If the implementation is feature version 202101 or later, 314 * each X.509 certificate contains an X.509 extension at OID 1.3.6.1.4.1.11129.2.1.26 which 315 * contains a DER encoded OCTET STRING with the bytes of the CBOR with the following CDDL: 316 * <pre> 317 * ProofOfBinding = [ 318 * "ProofOfBinding", 319 * bstr, // Contains SHA-256(ProofOfProvisioning) 320 * ] 321 * </pre> 322 * <p>This CBOR enables an issuer to determine the exact state of the credential it 323 * returns issuer-signed data for. 324 * 325 * <p> See {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for 326 * known feature versions. 327 * 328 * @return A collection of X.509 certificates for dynamic authentication keys that need issuer 329 * certification. 330 */ getAuthKeysNeedingCertification()331 public @NonNull abstract Collection<X509Certificate> getAuthKeysNeedingCertification(); 332 333 /** 334 * Store authentication data associated with a dynamic authentication key. 335 * 336 * This should only be called for an authenticated key returned by 337 * {@link #getAuthKeysNeedingCertification()}. 338 * 339 * @param authenticationKey The dynamic authentication key for which certification and 340 * associated static 341 * authentication data is being provided. 342 * @param staticAuthData Static authentication data provided by the issuer that validates 343 * the authenticity 344 * and integrity of the credential data fields. 345 * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized. 346 * @deprecated Use {@link #storeStaticAuthenticationData(X509Certificate, Instant, byte[])} 347 * instead. 348 */ 349 @Deprecated storeStaticAuthenticationData( @onNull X509Certificate authenticationKey, @NonNull byte[] staticAuthData)350 public abstract void storeStaticAuthenticationData( 351 @NonNull X509Certificate authenticationKey, 352 @NonNull byte[] staticAuthData) 353 throws UnknownAuthenticationKeyException; 354 355 /** 356 * Store authentication data associated with a dynamic authentication key. 357 * 358 * This should only be called for an authenticated key returned by 359 * {@link #getAuthKeysNeedingCertification()}. 360 * 361 * <p>This is only implemented in feature version 202101 or later. If not implemented, the call 362 * fails with {@link UnsupportedOperationException}. See 363 * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known 364 * feature versions. 365 * 366 * @param authenticationKey The dynamic authentication key for which certification and 367 * associated static 368 * authentication data is being provided. 369 * @param expirationDate The expiration date of the static authentication data. 370 * @param staticAuthData Static authentication data provided by the issuer that validates 371 * the authenticity 372 * and integrity of the credential data fields. 373 * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized. 374 */ storeStaticAuthenticationData( @onNull X509Certificate authenticationKey, @NonNull Instant expirationDate, @NonNull byte[] staticAuthData)375 public void storeStaticAuthenticationData( 376 @NonNull X509Certificate authenticationKey, 377 @NonNull Instant expirationDate, 378 @NonNull byte[] staticAuthData) 379 throws UnknownAuthenticationKeyException { 380 throw new UnsupportedOperationException(); 381 } 382 383 /** 384 * Get the number of times the dynamic authentication keys have been used. 385 * 386 * @return int array of dynamic authentication key usage counts. 387 */ getAuthenticationDataUsageCount()388 public @NonNull abstract int[] getAuthenticationDataUsageCount(); 389 390 /** 391 * Proves ownership of a credential. 392 * 393 * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey 394 * with payload set to {@code ProofOfDeletion} as defined below.</p> 395 * 396 * <p>The returned CBOR is the following:</p> 397 * <pre> 398 * ProofOfOwnership = [ 399 * "ProofOfOwnership", ; tstr 400 * tstr, ; DocType 401 * bstr, ; Challenge 402 * bool ; true if this is a test credential, should 403 * ; always be false. 404 * ] 405 * </pre> 406 * 407 * <p>This is only implemented in feature version 202101 or later. If not implemented, the call 408 * fails with {@link UnsupportedOperationException}. See 409 * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known 410 * feature versions. 411 * 412 * @param challenge is a non-empty byte array whose contents should be unique, fresh and 413 * provided by the issuing authority. The value provided is embedded in the 414 * generated CBOR and enables the issuing authority to verify that the 415 * returned proof is fresh. 416 * @return the COSE_Sign1 data structure above 417 */ proveOwnership(@onNull byte[] challenge)418 public @NonNull byte[] proveOwnership(@NonNull byte[] challenge) { 419 throw new UnsupportedOperationException(); 420 } 421 422 /** 423 * Deletes a credential. 424 * 425 * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey 426 * with payload set to {@code ProofOfDeletion} as defined below.</p> 427 * 428 * <pre> 429 * ProofOfDeletion = [ 430 * "ProofOfDeletion", ; tstr 431 * tstr, ; DocType 432 * bstr, ; Challenge 433 * bool ; true if this is a test credential, should 434 * ; always be false. 435 * ] 436 * </pre> 437 * 438 * <p>This is only implemented in feature version 202101 or later. If not implemented, the call 439 * fails with {@link UnsupportedOperationException}. See 440 * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known 441 * feature versions. 442 * 443 * @param challenge is a non-empty byte array whose contents should be unique, fresh and 444 * provided by the issuing authority. The value provided is embedded in the 445 * generated CBOR and enables the issuing authority to verify that the 446 * returned proof is fresh. 447 * @return the COSE_Sign1 data structure above 448 */ delete(@onNull byte[] challenge)449 public @NonNull byte[] delete(@NonNull byte[] challenge) { 450 throw new UnsupportedOperationException(); 451 } 452 453 /** 454 * Updates the credential with new access control profiles and data items. 455 * 456 * <p>This method is similar to 457 * {@link WritableIdentityCredential#personalize(PersonalizationData)} except that it operates 458 * on an existing credential, see the documentation for that method for the format of the 459 * returned data. 460 * 461 * <p>If this call succeeds an side-effect is that all dynamic authentication keys for the 462 * credential are deleted. The application will need to use 463 * {@link #getAuthKeysNeedingCertification()} to generate replacement keys and return 464 * them for issuer certification. 465 * 466 * <p>This is only implemented in feature version 202101 or later. If not implemented, the call 467 * fails with {@link UnsupportedOperationException}. See 468 * {@link android.content.pm.PackageManager#FEATURE_IDENTITY_CREDENTIAL_HARDWARE} for known 469 * feature versions. 470 * 471 * @param personalizationData The data to update, including access control profiles 472 * and data elements and their values, grouped into namespaces. 473 * @return A COSE_Sign1 data structure, see above. 474 */ update(@onNull PersonalizationData personalizationData)475 public @NonNull byte[] update(@NonNull PersonalizationData personalizationData) { 476 throw new UnsupportedOperationException(); 477 } 478 } 479