Merge "Check for invalid device attestation parameters" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d8be4517b3
@@ -21,18 +21,13 @@ import android.annotation.NonNull;
|
|||||||
import android.annotation.RequiresPermission;
|
import android.annotation.RequiresPermission;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Build;
|
|
||||||
import android.security.keymaster.KeymasterArguments;
|
|
||||||
import android.security.keymaster.KeymasterCertificateChain;
|
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.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.KeyStore;
|
import java.security.KeyStore;
|
||||||
|
import java.security.ProviderException;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
@@ -41,7 +36,6 @@ import java.security.spec.ECGenParameterSpec;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utilities for attesting the device's hardware identifiers.
|
* Utilities for attesting the device's hardware identifiers.
|
||||||
@@ -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
|
* 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
|
* whose first element contains the requested device identifiers in an extension. The device's
|
||||||
@@ -229,6 +137,13 @@ public abstract class AttestationUtils {
|
|||||||
@NonNull public static X509Certificate[] attestDeviceIds(Context context,
|
@NonNull public static X509Certificate[] attestDeviceIds(Context context,
|
||||||
@NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
|
@NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws
|
||||||
DeviceIdAttestationException {
|
DeviceIdAttestationException {
|
||||||
|
if (attestationChallenge == null) {
|
||||||
|
throw new NullPointerException("Missing attestation challenge");
|
||||||
|
}
|
||||||
|
if (idTypes == null) {
|
||||||
|
throw new NullPointerException("Missing id types");
|
||||||
|
}
|
||||||
|
|
||||||
String keystoreAlias = generateRandomAlias();
|
String keystoreAlias = generateRandomAlias();
|
||||||
KeyGenParameterSpec.Builder builder =
|
KeyGenParameterSpec.Builder builder =
|
||||||
new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN)
|
new KeyGenParameterSpec.Builder(keystoreAlias, KeyProperties.PURPOSE_SIGN)
|
||||||
@@ -265,6 +180,12 @@ public abstract class AttestationUtils {
|
|||||||
if (e.getCause() instanceof DeviceIdAttestationException) {
|
if (e.getCause() instanceof DeviceIdAttestationException) {
|
||||||
throw (DeviceIdAttestationException) e.getCause();
|
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);
|
throw new DeviceIdAttestationException("Unable to perform attestation", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user