1ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin/*
28effa36ca6440604cf10bbc34fba2b60ff304f54Alex Klyubin * Copyright (C) 2015 The Android Open Source Project
345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker *
445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * Licensed under the Apache License, Version 2.0 (the "License");
545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * you may not use this file except in compliance with the License.
645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * You may obtain a copy of the License at
745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker *
88effa36ca6440604cf10bbc34fba2b60ff304f54Alex Klyubin *      http://www.apache.org/licenses/LICENSE-2.0
945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker *
1045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * Unless required by applicable law or agreed to in writing, software
1145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * distributed under the License is distributed on an "AS IS" BASIS,
1245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * See the License for the specific language governing permissions and
1445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * limitations under the License.
1545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker */
1645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
1745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerpackage android.security.keymaster;
1845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
1945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerimport android.os.Parcel;
2045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerimport android.os.Parcelable;
2145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
22ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubinimport java.math.BigInteger;
2345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerimport java.util.ArrayList;
2445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerimport java.util.Date;
2545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerimport java.util.List;
2645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
2745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker/**
2845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * Utility class for the java side of user specified Keymaster arguments.
2945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * <p>
3045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * Serialization code for this and subclasses must be kept in sync with system/security/keystore
3145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker * @hide
3245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker */
3345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubakerpublic class KeymasterArguments implements Parcelable {
34ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
35ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private static final long UINT32_RANGE = 1L << 32;
36ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public static final long UINT32_MAX_VALUE = UINT32_RANGE - 1;
37ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
38ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private static final BigInteger UINT64_RANGE = BigInteger.ONE.shiftLeft(64);
39ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public static final BigInteger UINT64_MAX_VALUE = UINT64_RANGE.subtract(BigInteger.ONE);
40ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
41ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private List<KeymasterArgument> mArguments;
4245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
4345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
4445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            Parcelable.Creator<KeymasterArguments>() {
455927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin                @Override
4645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker                public KeymasterArguments createFromParcel(Parcel in) {
4745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker                    return new KeymasterArguments(in);
4845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker                }
495927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin
505927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin                @Override
5145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker                public KeymasterArguments[] newArray(int size) {
5245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker                    return new KeymasterArguments[size];
5345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker                }
5445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            };
5545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
5645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    public KeymasterArguments() {
5745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        mArguments = new ArrayList<KeymasterArgument>();
5845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
5945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
6045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    private KeymasterArguments(Parcel in) {
6145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        mArguments = in.createTypedArrayList(KeymasterArgument.CREATOR);
6245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
6345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
64ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
65ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds an enum tag with the provided value.
66ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
67ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not an enum tag.
68ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
69ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addEnum(int tag, int value) {
70ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        int tagType = KeymasterDefs.getTagType(tag);
71ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if ((tagType != KeymasterDefs.KM_ENUM) && (tagType != KeymasterDefs.KM_ENUM_REP)) {
72ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not an enum or repeating enum tag: " + tag);
73ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
74ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        addEnumTag(tag, value);
7545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
7645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
77ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
78ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds a repeated enum tag with the provided values.
79ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
80ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a repeating enum tag.
81ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
82ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addEnums(int tag, int... values) {
83ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM_REP) {
84ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a repeating enum tag: " + tag);
85ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
865927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin        for (int value : values) {
87ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            addEnumTag(tag, value);
885927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin        }
895927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin    }
905927c9f1b12f597839a664c1c6593114175cbcd8Alex Klyubin
91ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
92ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns the value of the specified enum tag or {@code defaultValue} if the tag is not
93ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * present.
94ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
95ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not an enum tag.
96ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
97ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public int getEnum(int tag, int defaultValue) {
98ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM) {
99ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not an enum tag: " + tag);
100b543b393549ccb2f1aa2cf3a198811fafbc309ebChad Brubaker        }
101ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        KeymasterArgument arg = getArgumentByTag(tag);
102ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (arg == null) {
103ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            return defaultValue;
104ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
105ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return getEnumTagValue(arg);
106b543b393549ccb2f1aa2cf3a198811fafbc309ebChad Brubaker    }
107b543b393549ccb2f1aa2cf3a198811fafbc309ebChad Brubaker
108ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
109ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns all values of the specified repeating enum tag.
110ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
111ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * throws IllegalArgumentException if {@code tag} is not a repeating enum tag.
112ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
113ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public List<Integer> getEnums(int tag) {
114ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ENUM_REP) {
115ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a repeating enum tag: " + tag);
116ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
117ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        List<Integer> values = new ArrayList<Integer>();
118ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        for (KeymasterArgument arg : mArguments) {
119ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            if (arg.tag == tag) {
120ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin                values.add(getEnumTagValue(arg));
121ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            }
122ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
123ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return values;
12445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
12545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
126ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private void addEnumTag(int tag, int value) {
127ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        mArguments.add(new KeymasterIntArgument(tag, value));
12845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
12945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
130ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private int getEnumTagValue(KeymasterArgument arg) {
131ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return ((KeymasterIntArgument) arg).value;
13245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
13345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
134ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
135ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds an unsigned 32-bit int tag with the provided value.
136ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
137ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag or if
138ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *         {@code value} is outside of the permitted range [0; 2^32).
139ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
140ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addUnsignedInt(int tag, long value) {
141ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        int tagType = KeymasterDefs.getTagType(tag);
1423e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        if ((tagType != KeymasterDefs.KM_UINT) && (tagType != KeymasterDefs.KM_UINT_REP)) {
143ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not an int or repeating int tag: " + tag);
144ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
1453e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        // Keymaster's KM_UINT is unsigned 32 bit.
146ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if ((value < 0) || (value > UINT32_MAX_VALUE)) {
147ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Int tag value out of range: " + value);
148ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
149ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        mArguments.add(new KeymasterIntArgument(tag, (int) value));
15045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
15145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
152ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
153ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns the value of the specified unsigned 32-bit int tag or {@code defaultValue} if the tag
154ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * is not present.
155ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
156ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not an unsigned 32-bit int tag.
157ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
158ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public long getUnsignedInt(int tag, long defaultValue) {
1593e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_UINT) {
160ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not an int tag: " + tag);
161ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
162ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        KeymasterArgument arg = getArgumentByTag(tag);
163ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (arg == null) {
164ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            return defaultValue;
165d6c7799b9a8b00d160a1d2d32c7326132cbc7b7bAlex Klyubin        }
1663e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        // Keymaster's KM_UINT is unsigned 32 bit.
167ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return ((KeymasterIntArgument) arg).value & 0xffffffffL;
168d6c7799b9a8b00d160a1d2d32c7326132cbc7b7bAlex Klyubin    }
169d6c7799b9a8b00d160a1d2d32c7326132cbc7b7bAlex Klyubin
170ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
171ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds an unsigned 64-bit long tag with the provided value.
172ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
173ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not an unsigned 64-bit long tag or if
174ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *         {@code value} is outside of the permitted range [0; 2^64).
175ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
176ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addUnsignedLong(int tag, BigInteger value) {
177ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        int tagType = KeymasterDefs.getTagType(tag);
1783e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        if ((tagType != KeymasterDefs.KM_ULONG) && (tagType != KeymasterDefs.KM_ULONG_REP)) {
179ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a long or repeating long tag: " + tag);
180ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
181ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        addLongTag(tag, value);
182ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    }
183ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
184ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
185ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns all values of the specified repeating unsigned 64-bit long tag.
186ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
187ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a repeating unsigned 64-bit long tag.
188ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
189ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public List<BigInteger> getUnsignedLongs(int tag) {
1903e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_ULONG_REP) {
191ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Tag is not a repeating long: " + tag);
192ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
193ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        List<BigInteger> values = new ArrayList<BigInteger>();
19445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        for (KeymasterArgument arg : mArguments) {
19545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            if (arg.tag == tag) {
196ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin                values.add(getLongTagValue(arg));
19745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            }
19845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
199ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return values;
20045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
20145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
202ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private void addLongTag(int tag, BigInteger value) {
2033e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        // Keymaster's KM_ULONG is unsigned 64 bit.
204ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if ((value.signum() == -1) || (value.compareTo(UINT64_MAX_VALUE) > 0)) {
205ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Long tag value out of range: " + value);
206ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
207ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        mArguments.add(new KeymasterLongArgument(tag, value.longValue()));
208ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    }
209ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
210ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private BigInteger getLongTagValue(KeymasterArgument arg) {
2113e7a9e4ec611a1306f8aa5e593c95237030bb5baAlex Klyubin        // Keymaster's KM_ULONG is unsigned 64 bit. We're forced to use BigInteger for type safety
212ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        // because there's no unsigned long type.
213ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return toUint64(((KeymasterLongArgument) arg).value);
214ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    }
215ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
216ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
217ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds the provided boolean tag. Boolean tags are considered to be set to {@code true} if
218ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * present and {@code false} if absent.
219ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
220ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a boolean tag.
221ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
222ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addBoolean(int tag) {
223ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) {
224ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a boolean tag: " + tag);
225ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
226ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        mArguments.add(new KeymasterBooleanArgument(tag));
22745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
22845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
229ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
230ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns {@code true} if the provided boolean tag is present, {@code false} if absent.
231ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
232ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a boolean tag.
233ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
234ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public boolean getBoolean(int tag) {
235ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) {
236ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a boolean tag: " + tag);
23745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
23845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        KeymasterArgument arg = getArgumentByTag(tag);
23945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        if (arg == null) {
240ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            return false;
24145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
242ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return true;
24345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
24445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
245ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
246ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds a bytes tag with the provided value.
247ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
248ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a bytes tag.
249ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
250ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addBytes(int tag, byte[] value) {
251ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) {
252ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a bytes tag: " + tag);
253ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
254ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (value == null) {
255ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new NullPointerException("value == nulll");
256ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
257ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        mArguments.add(new KeymasterBlobArgument(tag, value));
258ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    }
259ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
260ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
261ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns the value of the specified bytes tag or {@code defaultValue} if the tag is not
262ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * present.
263ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
264ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a bytes tag.
265ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
266ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public byte[] getBytes(int tag, byte[] defaultValue) {
267ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BYTES) {
268ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a bytes tag: " + tag);
26945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
27045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        KeymasterArgument arg = getArgumentByTag(tag);
27145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        if (arg == null) {
27245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            return defaultValue;
27345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
274ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return ((KeymasterBlobArgument) arg).blob;
27545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
27645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
277ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
278ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds a date tag with the provided value.
279ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
280ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a date tag or if {@code value} is
281ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *         before the start of Unix epoch.
282ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
283ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addDate(int tag, Date value) {
28445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) {
285ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a date tag: " + tag);
28645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
287ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (value == null) {
288ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new NullPointerException("value == nulll");
289ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
290ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        // Keymaster's KM_DATE is unsigned, but java.util.Date is signed, thus preventing us from
291ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        // using values larger than 2^63 - 1.
292ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (value.getTime() < 0) {
293ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Date tag value out of range: " + value);
29445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
295ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        mArguments.add(new KeymasterDateArgument(tag, value));
29645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
29745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
298ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
299ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Adds a date tag with the provided value, if the value is not {@code null}. Does nothing if
300ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * the {@code value} is null.
301ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
302ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a date tag or if {@code value} is
303ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *         before the start of Unix epoch.
304ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
305ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public void addDateIfNotNull(int tag, Date value) {
306ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) {
307ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Not a date tag: " + tag);
30845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
309ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (value != null) {
310ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            addDate(tag, value);
31145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
31245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
31345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
314ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
315ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Returns the value of the specified date tag or {@code defaultValue} if the tag is not
316ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * present.
317ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *
318ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * @throws IllegalArgumentException if {@code tag} is not a date tag or if the tag's value
319ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *         represents a time instant which is after {@code 2^63 - 1} milliseconds since Unix
320ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     *         epoch.
321ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
322ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public Date getDate(int tag, Date defaultValue) {
323ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) {
324ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Tag is not a date type: " + tag);
32545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
32645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        KeymasterArgument arg = getArgumentByTag(tag);
32745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        if (arg == null) {
32845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            return defaultValue;
32945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
330ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        Date result = ((KeymasterDateArgument) arg).date;
331ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        // Keymaster's KM_DATE is unsigned, but java.util.Date is signed, thus preventing us from
332ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        // using values larger than 2^63 - 1.
333ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (result.getTime() < 0) {
334ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            throw new IllegalArgumentException("Tag value too large. Tag: " + tag);
335ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
336ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return result;
33745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
33845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
339ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    private KeymasterArgument getArgumentByTag(int tag) {
34045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        for (KeymasterArgument arg : mArguments) {
34145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            if (arg.tag == tag) {
342ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin                return arg;
34345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker            }
34445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        }
345ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return null;
34645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
34745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
348ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public boolean containsTag(int tag) {
349ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        return getArgumentByTag(tag) != null;
350b543b393549ccb2f1aa2cf3a198811fafbc309ebChad Brubaker    }
351b543b393549ccb2f1aa2cf3a198811fafbc309ebChad Brubaker
35245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    public int size() {
35345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        return mArguments.size();
35445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
35545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
35645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    @Override
35745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    public void writeToParcel(Parcel out, int flags) {
35845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        out.writeTypedList(mArguments);
35945ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
36045ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
36145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    public void readFromParcel(Parcel in) {
36245ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        in.readTypedList(mArguments, KeymasterArgument.CREATOR);
36345ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
36445ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker
36545ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    @Override
36645ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    public int describeContents() {
36745ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker        return 0;
36845ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker    }
369ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin
370ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    /**
371ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * Converts the provided value to non-negative {@link BigInteger}, treating the sign bit of the
372ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     * provided value as the most significant bit of the result.
373ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin     */
374ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    public static BigInteger toUint64(long value) {
375ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        if (value >= 0) {
376ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            return BigInteger.valueOf(value);
377ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        } else {
378ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin            return BigInteger.valueOf(value).add(UINT64_RANGE);
379ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin        }
380ae6cb7aad56bb006769cd8a69b92af7236644fc1Alex Klyubin    }
38145ff13ea28005b5af0caa80dbdeb09d49bd73fafChad Brubaker}
382