Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47686420 authored by Alex Klyubin's avatar Alex Klyubin Committed by Android Git Automerger
Browse files

am 0a6ac701: am d4e9e0e1: Merge "Keymaster INT, LONG and DATE tag values are...

am 0a6ac701: am d4e9e0e1: Merge "Keymaster INT, LONG and DATE tag values are unsigned." into mnc-dev

* commit '0a6ac701':
  Keymaster INT, LONG and DATE tag values are unsigned.
parents 6efe9e57 0a6ac701
Loading
Loading
Loading
Loading
+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");
@@ -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);
        }
        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);
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -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];
                }
+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");
@@ -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;
    }

    /**
     * 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() {
@@ -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);
        }
    }
}
+5 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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();
@@ -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();
+7 −7

File changed.

Preview size limit exceeded, changes collapsed.

Loading