Loading core/java/android/security/keymaster/KeyCharacteristics.java +57 −44 Original line number Diff line number Diff line /** /* * Copyright (c) 2015, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); Loading @@ -19,6 +19,7 @@ package android.security.keymaster; import android.os.Parcel; import android.os.Parcelable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.List; Loading @@ -30,8 +31,8 @@ public class KeyCharacteristics implements Parcelable { public KeymasterArguments swEnforced; public KeymasterArguments hwEnforced; public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new Parcelable.Creator<KeyCharacteristics>() { public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new Parcelable.Creator<KeyCharacteristics>() { @Override public KeyCharacteristics createFromParcel(Parcel in) { return new KeyCharacteristics(in); Loading Loading @@ -65,73 +66,85 @@ public class KeyCharacteristics implements Parcelable { hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in); } public Integer getInteger(int tag) { /** * Returns the value of the specified enum tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not an enum tag. */ public Integer getEnum(int tag) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getInt(tag, -1); return hwEnforced.getEnum(tag, -1); } else if (swEnforced.containsTag(tag)) { return swEnforced.getInt(tag, -1); return swEnforced.getEnum(tag, -1); } else { return null; } } public int getInt(int tag, int defaultValue) { Integer result = getInteger(tag); return (result != null) ? result : defaultValue; } public List<Integer> getInts(int tag) { /** * Returns all values of the specified repeating enum tag. * * throws IllegalArgumentException if {@code tag} is not a repeating enum tag. */ public List<Integer> getEnums(int tag) { List<Integer> result = new ArrayList<Integer>(); result.addAll(hwEnforced.getInts(tag)); result.addAll(swEnforced.getInts(tag)); result.addAll(hwEnforced.getEnums(tag)); result.addAll(swEnforced.getEnums(tag)); return result; } public Long getLong(int tag) { /** * Returns the value of the specified unsigned 32-bit int tag or {@code defaultValue} if the tag * is not present. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag. */ public long getUnsignedInt(int tag, long defaultValue) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getLong(tag, -1); } else if (swEnforced.containsTag(tag)) { return swEnforced.getLong(tag, -1); return hwEnforced.getUnsignedInt(tag, defaultValue); } else { return null; } return swEnforced.getUnsignedInt(tag, defaultValue); } public long getLong(int tag, long defaultValue) { Long result = getLong(tag); return (result != null) ? result : defaultValue; } public List<Long> getLongs(int tag) { List<Long> result = new ArrayList<Long>(); result.addAll(hwEnforced.getLongs(tag)); result.addAll(swEnforced.getLongs(tag)); /** * Returns all values of the specified repeating unsigned 64-bit long tag. * * @throws IllegalArgumentException if {@code tag} is not a repeating unsigned 64-bit long tag. */ public List<BigInteger> getUnsignedLongs(int tag) { List<BigInteger> result = new ArrayList<BigInteger>(); result.addAll(hwEnforced.getUnsignedLongs(tag)); result.addAll(swEnforced.getUnsignedLongs(tag)); return result; } /** * Returns the value of the specified date tag or {@code null} if the tag is not present. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if the tag's value * represents a time instant which is after {@code 2^63 - 1} milliseconds since Unix * epoch. */ public Date getDate(int tag) { Date result = hwEnforced.getDate(tag, null); if (result == null) { result = swEnforced.getDate(tag, null); } Date result = swEnforced.getDate(tag, null); if (result != null) { return result; } public Date getDate(int tag, Date defaultValue) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getDate(tag, null); } else if (hwEnforced.containsTag(tag)) { return swEnforced.getDate(tag, null); } else { return defaultValue; } } /** * Returns {@code true} if the provided boolean tag is present, {@code false} if absent. * * @throws IllegalArgumentException if {@code tag} is not a boolean tag. */ public boolean getBoolean(int tag) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getBoolean(tag, false); return hwEnforced.getBoolean(tag); } else { return swEnforced.getBoolean(tag, false); return swEnforced.getBoolean(tag); } } } Loading core/java/android/security/keymaster/KeymasterArgument.java +3 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ abstract class KeymasterArgument implements Parcelable { public static final Parcelable.Creator<KeymasterArgument> CREATOR = new Parcelable.Creator<KeymasterArgument>() { @Override public KeymasterArgument createFromParcel(Parcel in) { final int pos = in.dataPosition(); final int tag = in.readInt(); Loading @@ -55,6 +56,8 @@ abstract class KeymasterArgument implements Parcelable { throw new ParcelFormatException("Bad tag: " + tag + " at " + pos); } } @Override public KeymasterArgument[] newArray(int size) { return new KeymasterArgument[size]; } Loading core/java/android/security/keymaster/KeymasterArguments.java +245 −89 Original line number Diff line number Diff line /** /* * Copyright (c) 2015, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); Loading @@ -19,6 +19,7 @@ package android.security.keymaster; import android.os.Parcel; import android.os.Parcelable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.List; Loading @@ -30,7 +31,14 @@ import java.util.List; * @hide */ public class KeymasterArguments implements Parcelable { List<KeymasterArgument> mArguments; private static final long UINT32_RANGE = 1L << 32; public static final long UINT32_MAX_VALUE = UINT32_RANGE - 1; private static final BigInteger UINT64_RANGE = BigInteger.ONE.shiftLeft(64); public static final BigInteger UINT64_MAX_VALUE = UINT64_RANGE.subtract(BigInteger.ONE); private List<KeymasterArgument> mArguments; public static final Parcelable.Creator<KeymasterArguments> CREATOR = new Parcelable.Creator<KeymasterArguments>() { Loading @@ -53,156 +61,292 @@ public class KeymasterArguments implements Parcelable { mArguments = in.createTypedArrayList(KeymasterArgument.CREATOR); } public void addInt(int tag, int value) { mArguments.add(new KeymasterIntArgument(tag, value)); /** * Adds an enum tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not an enum tag. */ public void addEnum(int tag, int value) { int tagType = KeymasterDefs.getTagType(tag); if ((tagType != KeymasterDefs.KM_ENUM) && (tagType != KeymasterDefs.KM_ENUM_REP)) { throw new IllegalArgumentException("Not an enum or repeating enum tag: " + tag); } addEnumTag(tag, value); } public void addInts(int tag, int... values) { /** * Adds a repeated enum tag with the provided values. * * @throws IllegalArgumentException if {@code tag} is not a repeating enum tag. */ public void addEnums(int tag, int... values) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM_REP) { throw new IllegalArgumentException("Not a repeating enum tag: " + tag); } for (int value : values) { addInt(tag, value); addEnumTag(tag, value); } } public void addLongs(int tag, long... values) { for (long value : values) { addLong(tag, value); /** * Returns the value of the specified enum tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not an enum tag. */ public int getEnum(int tag, int defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM) { throw new IllegalArgumentException("Not an enum tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } return getEnumTagValue(arg); } public void addBoolean(int tag) { mArguments.add(new KeymasterBooleanArgument(tag)); /** * Returns all values of the specified repeating enum tag. * * throws IllegalArgumentException if {@code tag} is not a repeating enum tag. */ public List<Integer> getEnums(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM_REP) { throw new IllegalArgumentException("Not a repeating enum tag: " + tag); } List<Integer> values = new ArrayList<Integer>(); for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { values.add(getEnumTagValue(arg)); } } return values; } public void addLong(int tag, long value) { mArguments.add(new KeymasterLongArgument(tag, value)); private void addEnumTag(int tag, int value) { mArguments.add(new KeymasterIntArgument(tag, value)); } public void addBlob(int tag, byte[] value) { mArguments.add(new KeymasterBlobArgument(tag, value)); private int getEnumTagValue(KeymasterArgument arg) { return ((KeymasterIntArgument) arg).value; } public void addDate(int tag, Date value) { mArguments.add(new KeymasterDateArgument(tag, value)); /** * Adds an unsigned 32-bit int tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag or if * {@code value} is outside of the permitted range [0; 2^32). */ public void addUnsignedInt(int tag, long value) { int tagType = KeymasterDefs.getTagType(tag); if ((tagType != KeymasterDefs.KM_INT) && (tagType != KeymasterDefs.KM_INT_REP)) { throw new IllegalArgumentException("Not an int or repeating int tag: " + tag); } // Keymaster's KM_INT is unsigned 32 bit. if ((value < 0) || (value > UINT32_MAX_VALUE)) { throw new IllegalArgumentException("Int tag value out of range: " + value); } mArguments.add(new KeymasterIntArgument(tag, (int) value)); } public void addDateIfNotNull(int tag, Date value) { if (value != null) { mArguments.add(new KeymasterDateArgument(tag, value)); /** * Returns the value of the specified unsigned 32-bit int tag or {@code defaultValue} if the tag * is not present. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag. */ public long getUnsignedInt(int tag, long defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_INT) { throw new IllegalArgumentException("Not an int tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } // Keymaster's KM_INT is unsigned 32 bit. return ((KeymasterIntArgument) arg).value & 0xffffffffL; } private KeymasterArgument getArgumentByTag(int tag) { /** * Adds an unsigned 64-bit long tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 64-bit long tag or if * {@code value} is outside of the permitted range [0; 2^64). */ public void addUnsignedLong(int tag, BigInteger value) { int tagType = KeymasterDefs.getTagType(tag); if ((tagType != KeymasterDefs.KM_LONG) && (tagType != KeymasterDefs.KM_LONG_REP)) { throw new IllegalArgumentException("Not a long or repeating long tag: " + tag); } addLongTag(tag, value); } /** * Returns all values of the specified repeating unsigned 64-bit long tag. * * @throws IllegalArgumentException if {@code tag} is not a repeating unsigned 64-bit long tag. */ public List<BigInteger> getUnsignedLongs(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) { throw new IllegalArgumentException("Tag is not a repeating long: " + tag); } List<BigInteger> values = new ArrayList<BigInteger>(); for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { return arg; values.add(getLongTagValue(arg)); } } return null; return values; } public boolean containsTag(int tag) { return getArgumentByTag(tag) != null; private void addLongTag(int tag, BigInteger value) { // Keymaster's KM_LONG is unsigned 64 bit. if ((value.signum() == -1) || (value.compareTo(UINT64_MAX_VALUE) > 0)) { throw new IllegalArgumentException("Long tag value out of range: " + value); } mArguments.add(new KeymasterLongArgument(tag, value.longValue())); } private BigInteger getLongTagValue(KeymasterArgument arg) { // Keymaster's KM_LONG is unsigned 64 bit. We're forced to use BigInteger for type safety // because there's no unsigned long type. return toUint64(((KeymasterLongArgument) arg).value); } /** * Adds the provided boolean tag. Boolean tags are considered to be set to {@code true} if * present and {@code false} if absent. * * @throws IllegalArgumentException if {@code tag} is not a boolean tag. */ public void addBoolean(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { throw new IllegalArgumentException("Not a boolean tag: " + tag); } mArguments.add(new KeymasterBooleanArgument(tag)); } public int getInt(int tag, int defaultValue) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_ENUM: case KeymasterDefs.KM_INT: break; // Accepted types case KeymasterDefs.KM_INT_REP: case KeymasterDefs.KM_ENUM_REP: throw new IllegalArgumentException("Repeatable tags must use getInts: " + tag); default: throw new IllegalArgumentException("Tag is not an int type: " + tag); /** * Returns {@code true} if the provided boolean tag is present, {@code false} if absent. * * @throws IllegalArgumentException if {@code tag} is not a boolean tag. */ public boolean getBoolean(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { throw new IllegalArgumentException("Not a boolean tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; return false; } return ((KeymasterIntArgument) arg).value; return true; } /** * Adds a bytes tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not a bytes tag. */ public void addBytes(int tag, byte[] value) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) { throw new IllegalArgumentException("Not a bytes tag: " + tag); } if (value == null) { throw new NullPointerException("value == nulll"); } mArguments.add(new KeymasterBlobArgument(tag, value)); } public long getLong(int tag, long defaultValue) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_LONG: break; // Accepted type case KeymasterDefs.KM_LONG_REP: throw new IllegalArgumentException("Repeatable tags must use getLongs: " + tag); default: throw new IllegalArgumentException("Tag is not a long type: " + tag); /** * Returns the value of the specified bytes tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not a bytes tag. */ public byte[] getBytes(int tag, byte[] defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) { throw new IllegalArgumentException("Not a bytes tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } return ((KeymasterLongArgument) arg).value; return ((KeymasterBlobArgument) arg).blob; } public Date getDate(int tag, Date defaultValue) { /** * Adds a date tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if {@code value} is * before the start of Unix epoch. */ public void addDate(int tag, Date value) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { throw new IllegalArgumentException("Tag is not a date type: " + tag); throw new IllegalArgumentException("Not a date tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; if (value == null) { throw new NullPointerException("value == nulll"); } return ((KeymasterDateArgument) arg).date; // Keymaster's KM_DATE is unsigned, but java.util.Date is signed, thus preventing us from // using values larger than 2^63 - 1. if (value.getTime() < 0) { throw new IllegalArgumentException("Date tag value out of range: " + value); } mArguments.add(new KeymasterDateArgument(tag, value)); } public boolean getBoolean(int tag, boolean defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { throw new IllegalArgumentException("Tag is not a boolean type: " + tag); /** * Adds a date tag with the provided value, if the value is not {@code null}. Does nothing if * the {@code value} is null. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if {@code value} is * before the start of Unix epoch. */ public void addDateIfNotNull(int tag, Date value) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { throw new IllegalArgumentException("Not a date tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; if (value != null) { addDate(tag, value); } return true; } public byte[] getBlob(int tag, byte[] defaultValue) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_BYTES: case KeymasterDefs.KM_BIGNUM: break; // Allowed types. default: throw new IllegalArgumentException("Tag is not a blob type: " + tag); /** * Returns the value of the specified date tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if the tag's value * represents a time instant which is after {@code 2^63 - 1} milliseconds since Unix * epoch. */ public Date getDate(int tag, Date defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { throw new IllegalArgumentException("Tag is not a date type: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } return ((KeymasterBlobArgument) arg).blob; Date result = ((KeymasterDateArgument) arg).date; // Keymaster's KM_DATE is unsigned, but java.util.Date is signed, thus preventing us from // using values larger than 2^63 - 1. if (result.getTime() < 0) { throw new IllegalArgumentException("Tag value too large. Tag: " + tag); } public List<Integer> getInts(int tag) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_INT_REP: case KeymasterDefs.KM_ENUM_REP: break; // Allowed types. default: throw new IllegalArgumentException("Tag is not a repeating type: " + tag); return result; } List<Integer> values = new ArrayList<Integer>(); private KeymasterArgument getArgumentByTag(int tag) { for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { values.add(((KeymasterIntArgument) arg).value); return arg; } } return values; return null; } public List<Long> getLongs(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) { throw new IllegalArgumentException("Tag is not a repeating long: " + tag); } List<Long> values = new ArrayList<Long>(); for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { values.add(((KeymasterLongArgument) arg).value); } } return values; public boolean containsTag(int tag) { return getArgumentByTag(tag) != null; } public int size() { Loading @@ -222,4 +366,16 @@ public class KeymasterArguments implements Parcelable { public int describeContents() { return 0; } /** * Converts the provided value to non-negative {@link BigInteger}, treating the sign bit of the * provided value as the most significant bit of the result. */ public static BigInteger toUint64(long value) { if (value >= 0) { return BigInteger.valueOf(value); } else { return BigInteger.valueOf(value).add(UINT64_RANGE); } } } keystore/java/android/security/KeyStore.java +5 −4 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.UserNotAuthenticatedException; import android.util.Log; import java.math.BigInteger; import java.security.InvalidKeyException; import java.util.List; import java.util.Locale; Loading Loading @@ -663,14 +664,14 @@ public class KeyStore { "Failed to obtained key characteristics", getKeyStoreException(getKeyCharacteristicsErrorCode)); } List<Long> keySids = keyCharacteristics.getLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); List<BigInteger> keySids = keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); if (keySids.isEmpty()) { // Key is not bound to any SIDs -- no amount of authentication will help here. return new KeyPermanentlyInvalidatedException(); } long rootSid = GateKeeper.getSecureUserId(); if ((rootSid != 0) && (keySids.contains(Long.valueOf(rootSid)))) { if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) { // One of the key's SIDs is the current root SID -- user can be authenticated // against that SID. return new UserNotAuthenticatedException(); Loading @@ -678,7 +679,7 @@ public class KeyStore { long fingerprintOnlySid = getFingerprintOnlySid(); if ((fingerprintOnlySid != 0) && (keySids.contains(Long.valueOf(fingerprintOnlySid)))) { && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) { // One of the key's SIDs is the current fingerprint SID -- user can be // authenticated against that SID. return new UserNotAuthenticatedException(); Loading keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java +7 −7 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/security/keymaster/KeyCharacteristics.java +57 −44 Original line number Diff line number Diff line /** /* * Copyright (c) 2015, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); Loading @@ -19,6 +19,7 @@ package android.security.keymaster; import android.os.Parcel; import android.os.Parcelable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.List; Loading @@ -30,8 +31,8 @@ public class KeyCharacteristics implements Parcelable { public KeymasterArguments swEnforced; public KeymasterArguments hwEnforced; public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new Parcelable.Creator<KeyCharacteristics>() { public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new Parcelable.Creator<KeyCharacteristics>() { @Override public KeyCharacteristics createFromParcel(Parcel in) { return new KeyCharacteristics(in); Loading Loading @@ -65,73 +66,85 @@ public class KeyCharacteristics implements Parcelable { hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in); } public Integer getInteger(int tag) { /** * Returns the value of the specified enum tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not an enum tag. */ public Integer getEnum(int tag) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getInt(tag, -1); return hwEnforced.getEnum(tag, -1); } else if (swEnforced.containsTag(tag)) { return swEnforced.getInt(tag, -1); return swEnforced.getEnum(tag, -1); } else { return null; } } public int getInt(int tag, int defaultValue) { Integer result = getInteger(tag); return (result != null) ? result : defaultValue; } public List<Integer> getInts(int tag) { /** * Returns all values of the specified repeating enum tag. * * throws IllegalArgumentException if {@code tag} is not a repeating enum tag. */ public List<Integer> getEnums(int tag) { List<Integer> result = new ArrayList<Integer>(); result.addAll(hwEnforced.getInts(tag)); result.addAll(swEnforced.getInts(tag)); result.addAll(hwEnforced.getEnums(tag)); result.addAll(swEnforced.getEnums(tag)); return result; } public Long getLong(int tag) { /** * Returns the value of the specified unsigned 32-bit int tag or {@code defaultValue} if the tag * is not present. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag. */ public long getUnsignedInt(int tag, long defaultValue) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getLong(tag, -1); } else if (swEnforced.containsTag(tag)) { return swEnforced.getLong(tag, -1); return hwEnforced.getUnsignedInt(tag, defaultValue); } else { return null; } return swEnforced.getUnsignedInt(tag, defaultValue); } public long getLong(int tag, long defaultValue) { Long result = getLong(tag); return (result != null) ? result : defaultValue; } public List<Long> getLongs(int tag) { List<Long> result = new ArrayList<Long>(); result.addAll(hwEnforced.getLongs(tag)); result.addAll(swEnforced.getLongs(tag)); /** * Returns all values of the specified repeating unsigned 64-bit long tag. * * @throws IllegalArgumentException if {@code tag} is not a repeating unsigned 64-bit long tag. */ public List<BigInteger> getUnsignedLongs(int tag) { List<BigInteger> result = new ArrayList<BigInteger>(); result.addAll(hwEnforced.getUnsignedLongs(tag)); result.addAll(swEnforced.getUnsignedLongs(tag)); return result; } /** * Returns the value of the specified date tag or {@code null} if the tag is not present. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if the tag's value * represents a time instant which is after {@code 2^63 - 1} milliseconds since Unix * epoch. */ public Date getDate(int tag) { Date result = hwEnforced.getDate(tag, null); if (result == null) { result = swEnforced.getDate(tag, null); } Date result = swEnforced.getDate(tag, null); if (result != null) { return result; } public Date getDate(int tag, Date defaultValue) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getDate(tag, null); } else if (hwEnforced.containsTag(tag)) { return swEnforced.getDate(tag, null); } else { return defaultValue; } } /** * Returns {@code true} if the provided boolean tag is present, {@code false} if absent. * * @throws IllegalArgumentException if {@code tag} is not a boolean tag. */ public boolean getBoolean(int tag) { if (hwEnforced.containsTag(tag)) { return hwEnforced.getBoolean(tag, false); return hwEnforced.getBoolean(tag); } else { return swEnforced.getBoolean(tag, false); return swEnforced.getBoolean(tag); } } } Loading
core/java/android/security/keymaster/KeymasterArgument.java +3 −0 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ abstract class KeymasterArgument implements Parcelable { public static final Parcelable.Creator<KeymasterArgument> CREATOR = new Parcelable.Creator<KeymasterArgument>() { @Override public KeymasterArgument createFromParcel(Parcel in) { final int pos = in.dataPosition(); final int tag = in.readInt(); Loading @@ -55,6 +56,8 @@ abstract class KeymasterArgument implements Parcelable { throw new ParcelFormatException("Bad tag: " + tag + " at " + pos); } } @Override public KeymasterArgument[] newArray(int size) { return new KeymasterArgument[size]; } Loading
core/java/android/security/keymaster/KeymasterArguments.java +245 −89 Original line number Diff line number Diff line /** /* * Copyright (c) 2015, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); Loading @@ -19,6 +19,7 @@ package android.security.keymaster; import android.os.Parcel; import android.os.Parcelable; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.List; Loading @@ -30,7 +31,14 @@ import java.util.List; * @hide */ public class KeymasterArguments implements Parcelable { List<KeymasterArgument> mArguments; private static final long UINT32_RANGE = 1L << 32; public static final long UINT32_MAX_VALUE = UINT32_RANGE - 1; private static final BigInteger UINT64_RANGE = BigInteger.ONE.shiftLeft(64); public static final BigInteger UINT64_MAX_VALUE = UINT64_RANGE.subtract(BigInteger.ONE); private List<KeymasterArgument> mArguments; public static final Parcelable.Creator<KeymasterArguments> CREATOR = new Parcelable.Creator<KeymasterArguments>() { Loading @@ -53,156 +61,292 @@ public class KeymasterArguments implements Parcelable { mArguments = in.createTypedArrayList(KeymasterArgument.CREATOR); } public void addInt(int tag, int value) { mArguments.add(new KeymasterIntArgument(tag, value)); /** * Adds an enum tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not an enum tag. */ public void addEnum(int tag, int value) { int tagType = KeymasterDefs.getTagType(tag); if ((tagType != KeymasterDefs.KM_ENUM) && (tagType != KeymasterDefs.KM_ENUM_REP)) { throw new IllegalArgumentException("Not an enum or repeating enum tag: " + tag); } addEnumTag(tag, value); } public void addInts(int tag, int... values) { /** * Adds a repeated enum tag with the provided values. * * @throws IllegalArgumentException if {@code tag} is not a repeating enum tag. */ public void addEnums(int tag, int... values) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM_REP) { throw new IllegalArgumentException("Not a repeating enum tag: " + tag); } for (int value : values) { addInt(tag, value); addEnumTag(tag, value); } } public void addLongs(int tag, long... values) { for (long value : values) { addLong(tag, value); /** * Returns the value of the specified enum tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not an enum tag. */ public int getEnum(int tag, int defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM) { throw new IllegalArgumentException("Not an enum tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } return getEnumTagValue(arg); } public void addBoolean(int tag) { mArguments.add(new KeymasterBooleanArgument(tag)); /** * Returns all values of the specified repeating enum tag. * * throws IllegalArgumentException if {@code tag} is not a repeating enum tag. */ public List<Integer> getEnums(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM_REP) { throw new IllegalArgumentException("Not a repeating enum tag: " + tag); } List<Integer> values = new ArrayList<Integer>(); for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { values.add(getEnumTagValue(arg)); } } return values; } public void addLong(int tag, long value) { mArguments.add(new KeymasterLongArgument(tag, value)); private void addEnumTag(int tag, int value) { mArguments.add(new KeymasterIntArgument(tag, value)); } public void addBlob(int tag, byte[] value) { mArguments.add(new KeymasterBlobArgument(tag, value)); private int getEnumTagValue(KeymasterArgument arg) { return ((KeymasterIntArgument) arg).value; } public void addDate(int tag, Date value) { mArguments.add(new KeymasterDateArgument(tag, value)); /** * Adds an unsigned 32-bit int tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag or if * {@code value} is outside of the permitted range [0; 2^32). */ public void addUnsignedInt(int tag, long value) { int tagType = KeymasterDefs.getTagType(tag); if ((tagType != KeymasterDefs.KM_INT) && (tagType != KeymasterDefs.KM_INT_REP)) { throw new IllegalArgumentException("Not an int or repeating int tag: " + tag); } // Keymaster's KM_INT is unsigned 32 bit. if ((value < 0) || (value > UINT32_MAX_VALUE)) { throw new IllegalArgumentException("Int tag value out of range: " + value); } mArguments.add(new KeymasterIntArgument(tag, (int) value)); } public void addDateIfNotNull(int tag, Date value) { if (value != null) { mArguments.add(new KeymasterDateArgument(tag, value)); /** * Returns the value of the specified unsigned 32-bit int tag or {@code defaultValue} if the tag * is not present. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag. */ public long getUnsignedInt(int tag, long defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_INT) { throw new IllegalArgumentException("Not an int tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } // Keymaster's KM_INT is unsigned 32 bit. return ((KeymasterIntArgument) arg).value & 0xffffffffL; } private KeymasterArgument getArgumentByTag(int tag) { /** * Adds an unsigned 64-bit long tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not an unsigned 64-bit long tag or if * {@code value} is outside of the permitted range [0; 2^64). */ public void addUnsignedLong(int tag, BigInteger value) { int tagType = KeymasterDefs.getTagType(tag); if ((tagType != KeymasterDefs.KM_LONG) && (tagType != KeymasterDefs.KM_LONG_REP)) { throw new IllegalArgumentException("Not a long or repeating long tag: " + tag); } addLongTag(tag, value); } /** * Returns all values of the specified repeating unsigned 64-bit long tag. * * @throws IllegalArgumentException if {@code tag} is not a repeating unsigned 64-bit long tag. */ public List<BigInteger> getUnsignedLongs(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) { throw new IllegalArgumentException("Tag is not a repeating long: " + tag); } List<BigInteger> values = new ArrayList<BigInteger>(); for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { return arg; values.add(getLongTagValue(arg)); } } return null; return values; } public boolean containsTag(int tag) { return getArgumentByTag(tag) != null; private void addLongTag(int tag, BigInteger value) { // Keymaster's KM_LONG is unsigned 64 bit. if ((value.signum() == -1) || (value.compareTo(UINT64_MAX_VALUE) > 0)) { throw new IllegalArgumentException("Long tag value out of range: " + value); } mArguments.add(new KeymasterLongArgument(tag, value.longValue())); } private BigInteger getLongTagValue(KeymasterArgument arg) { // Keymaster's KM_LONG is unsigned 64 bit. We're forced to use BigInteger for type safety // because there's no unsigned long type. return toUint64(((KeymasterLongArgument) arg).value); } /** * Adds the provided boolean tag. Boolean tags are considered to be set to {@code true} if * present and {@code false} if absent. * * @throws IllegalArgumentException if {@code tag} is not a boolean tag. */ public void addBoolean(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { throw new IllegalArgumentException("Not a boolean tag: " + tag); } mArguments.add(new KeymasterBooleanArgument(tag)); } public int getInt(int tag, int defaultValue) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_ENUM: case KeymasterDefs.KM_INT: break; // Accepted types case KeymasterDefs.KM_INT_REP: case KeymasterDefs.KM_ENUM_REP: throw new IllegalArgumentException("Repeatable tags must use getInts: " + tag); default: throw new IllegalArgumentException("Tag is not an int type: " + tag); /** * Returns {@code true} if the provided boolean tag is present, {@code false} if absent. * * @throws IllegalArgumentException if {@code tag} is not a boolean tag. */ public boolean getBoolean(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { throw new IllegalArgumentException("Not a boolean tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; return false; } return ((KeymasterIntArgument) arg).value; return true; } /** * Adds a bytes tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not a bytes tag. */ public void addBytes(int tag, byte[] value) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) { throw new IllegalArgumentException("Not a bytes tag: " + tag); } if (value == null) { throw new NullPointerException("value == nulll"); } mArguments.add(new KeymasterBlobArgument(tag, value)); } public long getLong(int tag, long defaultValue) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_LONG: break; // Accepted type case KeymasterDefs.KM_LONG_REP: throw new IllegalArgumentException("Repeatable tags must use getLongs: " + tag); default: throw new IllegalArgumentException("Tag is not a long type: " + tag); /** * Returns the value of the specified bytes tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not a bytes tag. */ public byte[] getBytes(int tag, byte[] defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) { throw new IllegalArgumentException("Not a bytes tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } return ((KeymasterLongArgument) arg).value; return ((KeymasterBlobArgument) arg).blob; } public Date getDate(int tag, Date defaultValue) { /** * Adds a date tag with the provided value. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if {@code value} is * before the start of Unix epoch. */ public void addDate(int tag, Date value) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { throw new IllegalArgumentException("Tag is not a date type: " + tag); throw new IllegalArgumentException("Not a date tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; if (value == null) { throw new NullPointerException("value == nulll"); } return ((KeymasterDateArgument) arg).date; // Keymaster's KM_DATE is unsigned, but java.util.Date is signed, thus preventing us from // using values larger than 2^63 - 1. if (value.getTime() < 0) { throw new IllegalArgumentException("Date tag value out of range: " + value); } mArguments.add(new KeymasterDateArgument(tag, value)); } public boolean getBoolean(int tag, boolean defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { throw new IllegalArgumentException("Tag is not a boolean type: " + tag); /** * Adds a date tag with the provided value, if the value is not {@code null}. Does nothing if * the {@code value} is null. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if {@code value} is * before the start of Unix epoch. */ public void addDateIfNotNull(int tag, Date value) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { throw new IllegalArgumentException("Not a date tag: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; if (value != null) { addDate(tag, value); } return true; } public byte[] getBlob(int tag, byte[] defaultValue) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_BYTES: case KeymasterDefs.KM_BIGNUM: break; // Allowed types. default: throw new IllegalArgumentException("Tag is not a blob type: " + tag); /** * Returns the value of the specified date tag or {@code defaultValue} if the tag is not * present. * * @throws IllegalArgumentException if {@code tag} is not a date tag or if the tag's value * represents a time instant which is after {@code 2^63 - 1} milliseconds since Unix * epoch. */ public Date getDate(int tag, Date defaultValue) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { throw new IllegalArgumentException("Tag is not a date type: " + tag); } KeymasterArgument arg = getArgumentByTag(tag); if (arg == null) { return defaultValue; } return ((KeymasterBlobArgument) arg).blob; Date result = ((KeymasterDateArgument) arg).date; // Keymaster's KM_DATE is unsigned, but java.util.Date is signed, thus preventing us from // using values larger than 2^63 - 1. if (result.getTime() < 0) { throw new IllegalArgumentException("Tag value too large. Tag: " + tag); } public List<Integer> getInts(int tag) { switch (KeymasterDefs.getTagType(tag)) { case KeymasterDefs.KM_INT_REP: case KeymasterDefs.KM_ENUM_REP: break; // Allowed types. default: throw new IllegalArgumentException("Tag is not a repeating type: " + tag); return result; } List<Integer> values = new ArrayList<Integer>(); private KeymasterArgument getArgumentByTag(int tag) { for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { values.add(((KeymasterIntArgument) arg).value); return arg; } } return values; return null; } public List<Long> getLongs(int tag) { if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) { throw new IllegalArgumentException("Tag is not a repeating long: " + tag); } List<Long> values = new ArrayList<Long>(); for (KeymasterArgument arg : mArguments) { if (arg.tag == tag) { values.add(((KeymasterLongArgument) arg).value); } } return values; public boolean containsTag(int tag) { return getArgumentByTag(tag) != null; } public int size() { Loading @@ -222,4 +366,16 @@ public class KeymasterArguments implements Parcelable { public int describeContents() { return 0; } /** * Converts the provided value to non-negative {@link BigInteger}, treating the sign bit of the * provided value as the most significant bit of the result. */ public static BigInteger toUint64(long value) { if (value >= 0) { return BigInteger.valueOf(value); } else { return BigInteger.valueOf(value).add(UINT64_RANGE); } } }
keystore/java/android/security/KeyStore.java +5 −4 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import android.security.keystore.KeyPermanentlyInvalidatedException; import android.security.keystore.UserNotAuthenticatedException; import android.util.Log; import java.math.BigInteger; import java.security.InvalidKeyException; import java.util.List; import java.util.Locale; Loading Loading @@ -663,14 +664,14 @@ public class KeyStore { "Failed to obtained key characteristics", getKeyStoreException(getKeyCharacteristicsErrorCode)); } List<Long> keySids = keyCharacteristics.getLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); List<BigInteger> keySids = keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID); if (keySids.isEmpty()) { // Key is not bound to any SIDs -- no amount of authentication will help here. return new KeyPermanentlyInvalidatedException(); } long rootSid = GateKeeper.getSecureUserId(); if ((rootSid != 0) && (keySids.contains(Long.valueOf(rootSid)))) { if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) { // One of the key's SIDs is the current root SID -- user can be authenticated // against that SID. return new UserNotAuthenticatedException(); Loading @@ -678,7 +679,7 @@ public class KeyStore { long fingerprintOnlySid = getFingerprintOnlySid(); if ((fingerprintOnlySid != 0) && (keySids.contains(Long.valueOf(fingerprintOnlySid)))) { && (keySids.contains(KeymasterArguments.toUint64(fingerprintOnlySid)))) { // One of the key's SIDs is the current fingerprint SID -- user can be // authenticated against that SID. return new UserNotAuthenticatedException(); Loading
keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java +7 −7 File changed.Preview size limit exceeded, changes collapsed. Show changes