summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/security/keymaster/KeyCharacteristics.java101
-rw-r--r--core/java/android/security/keymaster/KeymasterArgument.java3
-rw-r--r--core/java/android/security/keymaster/KeymasterArguments.java334
3 files changed, 305 insertions, 133 deletions
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index 03248e5..c91e20c 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2015, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -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;
@@ -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);
@@ -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);
- }
- 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;
+ Date result = swEnforced.getDate(tag, null);
+ if (result != null) {
+ return result;
}
+ return hwEnforced.getDate(tag, null);
}
+ /**
+ * 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);
}
}
}
diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java
index 9adde35..d1d8371 100644
--- a/core/java/android/security/keymaster/KeymasterArgument.java
+++ b/core/java/android/security/keymaster/KeymasterArgument.java
@@ -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();
@@ -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];
}
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index 363376c..ee0ad6d 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (c) 2015, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -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;
@@ -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>() {
@@ -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;
}
- 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);
+ /**
+ * 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));
+ }
+
+ /**
+ * 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");
+ }
+ // 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);
}
- return ((KeymasterDateArgument) arg).date;
+ 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);
+ }
+ return result;
}
- 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);
- }
- 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() {
@@ -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);
+ }
+ }
}