Loading keystore/java/android/security/keystore/AttestationUtils.java +14 −93 Original line number Diff line number Diff line Loading @@ -21,18 +21,13 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; import android.os.Build; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterCertificateChain; import android.security.keymaster.KeymasterDefs; import android.telephony.TelephonyManager; import android.util.ArraySet; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.ProviderException; import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; Loading @@ -41,7 +36,6 @@ import java.security.spec.ECGenParameterSpec; import java.util.Arrays; import java.util.Collection; import java.util.Random; import java.util.Set; /** * Utilities for attesting the device's hardware identifiers. Loading Loading @@ -110,92 +104,6 @@ public abstract class AttestationUtils { } } @NonNull private static KeymasterArguments prepareAttestationArgumentsForDeviceId( Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { // Verify that device ID attestation types are provided. if (idTypes == null) { throw new NullPointerException("Missing id types"); } return prepareAttestationArguments(context, idTypes, attestationChallenge); } /** * Prepares Keymaster Arguments with attestation data. * @hide should only be used by KeyChain. */ @NonNull public static KeymasterArguments prepareAttestationArguments(Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { // Check method arguments, retrieve requested device IDs and prepare attestation arguments. if (attestationChallenge == null) { throw new NullPointerException("Missing attestation challenge"); } final KeymasterArguments attestArgs = new KeymasterArguments(); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge); // Return early if the caller did not request any device identifiers to be included in the // attestation record. if (idTypes == null) { return attestArgs; } final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length); for (int idType : idTypes) { idTypesSet.add(idType); } TelephonyManager telephonyService = null; if (idTypesSet.contains(ID_TYPE_IMEI) || idTypesSet.contains(ID_TYPE_MEID)) { telephonyService = (TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE); if (telephonyService == null) { throw new DeviceIdAttestationException("Unable to access telephony service"); } } for (final Integer idType : idTypesSet) { switch (idType) { case ID_TYPE_SERIAL: attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL, Build.getSerial().getBytes(StandardCharsets.UTF_8)); break; case ID_TYPE_IMEI: { final String imei = telephonyService.getImei(0); if (imei == null) { throw new DeviceIdAttestationException("Unable to retrieve IMEI"); } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI, imei.getBytes(StandardCharsets.UTF_8)); break; } case ID_TYPE_MEID: { final String meid = telephonyService.getMeid(0); if (meid == null) { throw new DeviceIdAttestationException("Unable to retrieve MEID"); } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID, meid.getBytes(StandardCharsets.UTF_8)); break; } case USE_INDIVIDUAL_ATTESTATION: { attestArgs.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION); break; } default: throw new IllegalArgumentException("Unknown device ID type " + idType); } } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND, Build.BRAND.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE, Build.DEVICE.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT, Build.PRODUCT.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER, Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL, Build.MODEL.getBytes(StandardCharsets.UTF_8)); return attestArgs; } /** * Performs attestation of the device's identifiers. This method returns a certificate chain * whose first element contains the requested device identifiers in an extension. The device's Loading Loading @@ -229,6 +137,13 @@ public abstract class AttestationUtils { @NonNull public static X509Certificate[] attestDeviceIds(Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { if (attestationChallenge == null) { throw new NullPointerException("Missing attestation challenge"); } if (idTypes == null) { throw new NullPointerException("Missing id types"); } String keystoreAlias = generateRandomAlias(); KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN) Loading Loading @@ -265,6 +180,12 @@ public abstract class AttestationUtils { if (e.getCause() instanceof DeviceIdAttestationException) { throw (DeviceIdAttestationException) e.getCause(); } // Illegal argument errors are wrapped up by a ProviderException. Catch those so that // we can unwrap them into a more meaningful exception type for the caller. if (e instanceof ProviderException && e.getCause() instanceof IllegalArgumentException) { throw (IllegalArgumentException) e.getCause(); } throw new DeviceIdAttestationException("Unable to perform attestation", e); } } Loading Loading
keystore/java/android/security/keystore/AttestationUtils.java +14 −93 Original line number Diff line number Diff line Loading @@ -21,18 +21,13 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; import android.os.Build; import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterCertificateChain; import android.security.keymaster.KeymasterDefs; import android.telephony.TelephonyManager; import android.util.ArraySet; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.charset.StandardCharsets; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.ProviderException; import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; Loading @@ -41,7 +36,6 @@ import java.security.spec.ECGenParameterSpec; import java.util.Arrays; import java.util.Collection; import java.util.Random; import java.util.Set; /** * Utilities for attesting the device's hardware identifiers. Loading Loading @@ -110,92 +104,6 @@ public abstract class AttestationUtils { } } @NonNull private static KeymasterArguments prepareAttestationArgumentsForDeviceId( Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { // Verify that device ID attestation types are provided. if (idTypes == null) { throw new NullPointerException("Missing id types"); } return prepareAttestationArguments(context, idTypes, attestationChallenge); } /** * Prepares Keymaster Arguments with attestation data. * @hide should only be used by KeyChain. */ @NonNull public static KeymasterArguments prepareAttestationArguments(Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { // Check method arguments, retrieve requested device IDs and prepare attestation arguments. if (attestationChallenge == null) { throw new NullPointerException("Missing attestation challenge"); } final KeymasterArguments attestArgs = new KeymasterArguments(); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, attestationChallenge); // Return early if the caller did not request any device identifiers to be included in the // attestation record. if (idTypes == null) { return attestArgs; } final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length); for (int idType : idTypes) { idTypesSet.add(idType); } TelephonyManager telephonyService = null; if (idTypesSet.contains(ID_TYPE_IMEI) || idTypesSet.contains(ID_TYPE_MEID)) { telephonyService = (TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE); if (telephonyService == null) { throw new DeviceIdAttestationException("Unable to access telephony service"); } } for (final Integer idType : idTypesSet) { switch (idType) { case ID_TYPE_SERIAL: attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL, Build.getSerial().getBytes(StandardCharsets.UTF_8)); break; case ID_TYPE_IMEI: { final String imei = telephonyService.getImei(0); if (imei == null) { throw new DeviceIdAttestationException("Unable to retrieve IMEI"); } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI, imei.getBytes(StandardCharsets.UTF_8)); break; } case ID_TYPE_MEID: { final String meid = telephonyService.getMeid(0); if (meid == null) { throw new DeviceIdAttestationException("Unable to retrieve MEID"); } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID, meid.getBytes(StandardCharsets.UTF_8)); break; } case USE_INDIVIDUAL_ATTESTATION: { attestArgs.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION); break; } default: throw new IllegalArgumentException("Unknown device ID type " + idType); } } attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND, Build.BRAND.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE, Build.DEVICE.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT, Build.PRODUCT.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER, Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8)); attestArgs.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL, Build.MODEL.getBytes(StandardCharsets.UTF_8)); return attestArgs; } /** * Performs attestation of the device's identifiers. This method returns a certificate chain * whose first element contains the requested device identifiers in an extension. The device's Loading Loading @@ -229,6 +137,13 @@ public abstract class AttestationUtils { @NonNull public static X509Certificate[] attestDeviceIds(Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { if (attestationChallenge == null) { throw new NullPointerException("Missing attestation challenge"); } if (idTypes == null) { throw new NullPointerException("Missing id types"); } String keystoreAlias = generateRandomAlias(); KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN) Loading Loading @@ -265,6 +180,12 @@ public abstract class AttestationUtils { if (e.getCause() instanceof DeviceIdAttestationException) { throw (DeviceIdAttestationException) e.getCause(); } // Illegal argument errors are wrapped up by a ProviderException. Catch those so that // we can unwrap them into a more meaningful exception type for the caller. if (e instanceof ProviderException && e.getCause() instanceof IllegalArgumentException) { throw (IllegalArgumentException) e.getCause(); } throw new DeviceIdAttestationException("Unable to perform attestation", e); } } Loading