blob: b09de0fd64ebdfd57269393d36ffda9e6d5c9ef1 [file] [log] [blame]
/*
* Copyright(C) 2020 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 com.android.javacard.seprovider.KMException;
import javacard.framework.ISO7816;
import javacard.framework.ISOException;
import javacard.framework.Util;
/**
* Represents 8 bit, 16 bit, 32 bit and 64 bit unsigned integer. It corresponds to CBOR uint type.
* struct{byte INTEGER_TYPE; short length; 4 or 8 bytes of value}
*/
public class KMInteger extends KMType {
public static final byte UINT_32 = 4;
public static final byte UINT_64 = 8;
private static KMInteger prototype;
protected KMInteger() {}
private static KMInteger proto(short ptr) {
if (prototype == null) {
prototype = new KMInteger();
}
KMType.instanceTable[KM_INTEGER_OFFSET] = ptr;
return prototype;
}
// | TYPE(1) | LEN(2) | DATA(4 / 8) |
public static short exp() {
return KMType.exp(INTEGER_TYPE);
}
// return an empty integer instance
public static short instance(short length) {
if ((length <= 0) || (length > 8)) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
if (length > 4) {
length = UINT_64;
} else {
length = UINT_32;
}
return KMType.instance(INTEGER_TYPE, length);
}
public static short instance(byte[] num, short srcOff, short length) {
if (length > 8) {
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}
if (length == 1) {
return uint_8(num[srcOff]);
} else if (length == 2) {
return uint_16(Util.getShort(num, srcOff));
} else if (length == 4) {
return uint_32(num, srcOff);
} else {
return uint_64(num, srcOff);
}
}
public static KMInteger cast(short ptr) {
byte[] heap = repository.getHeap();
if (heap[ptr] != INTEGER_TYPE) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
if (Util.getShort(heap, (short) (ptr + 1)) == INVALID_VALUE) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
return proto(ptr);
}
// create integer and copy byte value
public static short uint_8(byte num) {
short ptr = instance(UINT_32);
heap[(short) (ptr + TLV_HEADER_SIZE + 3)] = num;
return ptr;
}
// create integer and copy short value
public static short uint_16(short num) {
short ptr = instance(UINT_32);
Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), num);
return ptr;
}
// create integer and copy integer value
public static short uint_32(byte[] num, short offset) {
short ptr = instance(UINT_32);
Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_32);
return ptr;
}
// create integer and copy integer value
public static short uint_64(byte[] num, short offset) {
short ptr = instance(UINT_64);
Util.arrayCopy(num, offset, heap, (short) (ptr + TLV_HEADER_SIZE), UINT_64);
return ptr;
}
public static short compare(short num1, short num2) {
short num1Buf = repository.alloc((short) 8);
short num2Buf = repository.alloc((short) 8);
Util.arrayFillNonAtomic(repository.getHeap(), num1Buf, (short) 8, (byte) 0);
Util.arrayFillNonAtomic(repository.getHeap(), num2Buf, (short) 8, (byte) 0);
short len = KMInteger.cast(num1).length();
KMInteger.cast(num1).getValue(repository.getHeap(), (short) (num1Buf + (short) (8 - len)), len);
len = KMInteger.cast(num2).length();
KMInteger.cast(num2).getValue(repository.getHeap(), (short) (num2Buf + (short) (8 - len)), len);
return KMInteger.unsignedByteArrayCompare(
repository.getHeap(), num1Buf, repository.getHeap(), num2Buf, (short) 8);
}
public static byte unsignedByteArrayCompare(
byte[] a1, short offset1, byte[] a2, short offset2, short length) {
byte count = (byte) 0;
short val1 = (short) 0;
short val2 = (short) 0;
for (; count < length; count++) {
val1 = (short) (a1[(short) (count + offset1)] & 0x00FF);
val2 = (short) (a2[(short) (count + offset2)] & 0x00FF);
if (val1 < val2) {
return -1;
}
if (val1 > val2) {
return 1;
}
}
return 0;
}
// Get the length of the integer
public short length() {
return Util.getShort(heap, (short) (getBaseOffset() + 1));
}
// Get the buffer pointer in which blob is contained.
public byte[] getBuffer() {
return heap;
}
// Get the start of value
public short getStartOff() {
return (short) (getBaseOffset() + TLV_HEADER_SIZE);
}
public void getValue(byte[] dest, short destOff, short length) {
if (length < length()) {
KMException.throwIt(KMError.UNKNOWN_ERROR);
}
if (length > length()) {
length = length();
destOff += length;
}
Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length);
}
public void setValue(byte[] src, short srcOff) {
Util.arrayCopyNonAtomic(src, srcOff, heap, getStartOff(), length());
}
public short value(byte[] dest, short destOff) {
Util.arrayCopyNonAtomic(heap, getStartOff(), dest, destOff, length());
return length();
}
public short toLittleEndian(byte[] dest, short destOff) {
short index = (short) (length() - 1);
while (index >= 0) {
dest[destOff++] = heap[(short) (instanceTable[KM_INTEGER_OFFSET] + TLV_HEADER_SIZE + index)];
index--;
}
return length();
}
public short getShort() {
return Util.getShort(heap, (short) (getStartOff() + 2));
}
public short getSignificantShort() {
return Util.getShort(heap, getStartOff());
}
public byte getByte() {
return heap[(short) (getStartOff() + 3)];
}
public boolean isZero() {
if (getShort() == 0 && getSignificantShort() == 0) {
return true;
}
return false;
}
protected short getBaseOffset() {
return instanceTable[KM_INTEGER_OFFSET];
}
}