| /* |
| * Copyright(C) 2021 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.javacard.keymaster; |
| |
| import javacard.framework.ISO7816; |
| import javacard.framework.ISOException; |
| import javacard.framework.Util; |
| |
| /** |
| * This class represents the a key-value types. This is basically a map containing key value pairs. |
| * The label for the key can be (uint / int / tstr) and the value can be of any type. But this class |
| * is confined to support only key and value types which are required for remote key provisioning. |
| * So keys of type (int / uint) and values of type (int / uint / simple / bstr) only are supported. |
| * The structure representing all the sub classes of KMCosePairTagType is as follows: |
| * KM_COSE_PAIR_TAG_TYPE(1byte), Length(2 bytes), COSE_PAIR_*_TAG_TYPE(2 bytes), Key(2 bytes), |
| * Value(2 bytes). Key can be either KMInteger or KMNInteger and Value can be either KMIntger or |
| * KMNinteger or KMSimpleValue or KMByteBlob or KMTextString or KMCoseKey. Each subclass of |
| * KMCosePairTagType is named after their corresponding value type of the Cose pair. |
| */ |
| public abstract class KMCosePairTagType extends KMType { |
| |
| /** |
| * Below table represents the allowed values for a key. The maximum length of the key can be 4 |
| * bytes so each key is represented as 4 bytes. The allowed values are placed next to their |
| * corresponding key. |
| */ |
| public static Object[] allowedKeyPairs; |
| |
| private static void createAllowedKeyPairs() { |
| if (allowedKeyPairs == null) { |
| allowedKeyPairs = |
| new Object[] { |
| // Key type |
| (Object) new byte[] {0, 0, 0, KMCose.COSE_KEY_KEY_TYPE}, |
| (Object) new byte[] {KMCose.COSE_KEY_TYPE_EC2, KMCose.COSE_KEY_TYPE_SYMMETRIC_KEY}, |
| // Key Algorithm |
| (Object) new byte[] {0, 0, 0, KMCose.COSE_KEY_ALGORITHM}, |
| (Object) |
| new byte[] { |
| KMCose.COSE_ALG_AES_GCM_256, |
| KMCose.COSE_ALG_HMAC_256, |
| KMCose.COSE_ALG_ECDH_ES_HKDF_256, |
| KMCose.COSE_ALG_ES256 |
| }, |
| // Key Curve |
| (Object) new byte[] {0, 0, 0, KMCose.COSE_KEY_CURVE}, |
| (Object) new byte[] {KMCose.COSE_ECCURVE_256}, |
| // Header Label Algorithm |
| (Object) new byte[] {0, 0, 0, KMCose.COSE_LABEL_ALGORITHM}, |
| (Object) |
| new byte[] { |
| KMCose.COSE_ALG_AES_GCM_256, |
| KMCose.COSE_ALG_HMAC_256, |
| KMCose.COSE_ALG_ES256, |
| KMCose.COSE_ALG_ECDH_ES_HKDF_256 |
| }, |
| // Test Key |
| KMCose.COSE_TEST_KEY, |
| (Object) new byte[] {KMSimpleValue.NULL}, |
| }; |
| } |
| } |
| |
| /** |
| * Validates the key and the values corresponding to key. |
| * |
| * @param key Buffer containing the key. |
| * @param keyOff Offset in the buffer from where key starts. |
| * @param keyLen Length of the key buffer. |
| * @param value Value corresponding to the key. |
| * @return true if key pair is valid, otherwise false. |
| */ |
| public static boolean isKeyPairValid(byte[] key, short keyOff, short keyLen, short value) { |
| short index = 0; |
| short valueIdx; |
| byte[] values; |
| boolean valid = false; |
| createAllowedKeyPairs(); |
| while (index < allowedKeyPairs.length) { |
| valueIdx = 0; |
| if (isEqual( |
| (byte[]) allowedKeyPairs[index], |
| (short) 0, |
| (short) ((byte[]) allowedKeyPairs[index]).length, |
| key, |
| keyOff, |
| keyLen)) { |
| values = (byte[]) allowedKeyPairs[(short) (index + 1)]; |
| while (valueIdx < values.length) { |
| if (values[valueIdx] == (byte) value) { |
| valid = true; |
| break; |
| } |
| valueIdx++; |
| } |
| if (valid) { |
| break; |
| } |
| } |
| index += (short) 2; |
| } |
| return valid; |
| } |
| |
| /** |
| * Compares two key buffers. |
| * |
| * @param key1 First buffer containing the key. |
| * @param offset1 Offset of the first buffer. |
| * @param length1 Length of the first buffer. |
| * @param key2 Second buffer containing the key. |
| * @param offset2 Offset of the second buffer. |
| * @param length2 Length of the second buffer. |
| * @return true if both keys are equal, otherwise false. |
| */ |
| private static boolean isEqual( |
| byte[] key1, short offset1, short length1, byte[] key2, short offset2, short length2) { |
| if (length1 != length2) { |
| return false; |
| } |
| return (0 == KMInteger.unsignedByteArrayCompare(key1, offset1, key2, offset2, length1)); |
| } |
| |
| /** |
| * Returns the short value of the key. |
| * |
| * @param keyPtr Pointer to either KMInteger or KMNInteger |
| * @return value of the key as short. |
| */ |
| public static short getKeyValueShort(short keyPtr) { |
| short type = KMType.getType(keyPtr); |
| short value = 0; |
| if (type == INTEGER_TYPE) { |
| value = KMInteger.cast(keyPtr).getShort(); |
| } else if (type == NEG_INTEGER_TYPE) { |
| value = KMNInteger.cast(keyPtr).getShort(); |
| } else { |
| ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); |
| } |
| return value; |
| } |
| |
| /** |
| * Returns the significant short value of the key. |
| * |
| * @param keyPtr Pointer to either KMInteger or KMNInteger |
| * @return value of the key as short. |
| */ |
| public static short getKeyValueSignificantShort(short keyPtr) { |
| short type = KMType.getType(keyPtr); |
| short value = 0; |
| if (type == INTEGER_TYPE) { |
| value = KMInteger.cast(keyPtr).getSignificantShort(); |
| } else if (type == NEG_INTEGER_TYPE) { |
| value = KMNInteger.cast(keyPtr).getSignificantShort(); |
| } else { |
| ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); |
| } |
| return value; |
| } |
| |
| /** |
| * Returns the key offset from the key pointer. |
| * |
| * @param keyPtr Pointer to either KMInteger or KMNInteger |
| * @return offset from where the key starts. |
| */ |
| public static short getKeyStartOffset(short keyPtr) { |
| short type = KMType.getType(keyPtr); |
| short offset = 0; |
| if (type == INTEGER_TYPE) { |
| offset = KMInteger.cast(keyPtr).getStartOff(); |
| } else if (type == NEG_INTEGER_TYPE) { |
| offset = KMNInteger.cast(keyPtr).getStartOff(); |
| } else { |
| ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); |
| } |
| return offset; |
| } |
| |
| /** |
| * This function returns one of COSE_KEY_TAG_*_VALUE_TYPE tag information. |
| * |
| * @param ptr Pointer to one of the KMCoseKey*Value class. |
| * @return Tag value type. |
| */ |
| public static short getTagValueType(short ptr) { |
| return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); |
| } |
| |
| /** |
| * This function returns the key pointer. |
| * |
| * @return key pointer. |
| */ |
| public abstract short getKeyPtr(); |
| |
| /** |
| * This function returns the value pointer. |
| * |
| * @return value pointer. |
| */ |
| public abstract short getValuePtr(); |
| } |