diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index e7d8252b..bb85b59e 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -245,8 +245,8 @@ private KMAttestationCert uniqueId(short obj) { @Override public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad) { if (!derEncoded) { - // convert milliseconds to UTC date - indexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad, true); + // convert milliseconds to UTC / Generalized time format + indexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad); } else { indexes[NOT_BEFORE] = KMByteBlob.instance( @@ -262,17 +262,8 @@ public KMAttestationCert notAfter( short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad) { if (!derEncoded) { if (usageExpiryTimeObj != KMType.INVALID_VALUE) { - // compare if the expiry time is greater then 2050 then use generalized - // time format else use utc time format. - short tmpVar = KMInteger.uint_64(KMUtils.firstJan2050, (short) 0); - if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { - usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, false); - } else { - usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, true); - } - indexes[NOT_AFTER] = usageExpiryTimeObj; - } else { - // notAfter = certExpirtyTimeObj; + // convert milliseconds to UTC / Generalized time format + indexes[NOT_AFTER] = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad); } } else { indexes[NOT_AFTER] = usageExpiryTimeObj; diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java index b7a66d28..738326b2 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMConfigurations.java @@ -27,6 +27,5 @@ public class KMConfigurations { // If the size of the attestation ids is known and lesser than 64 // then reduce the size here. It reduces the heap memory usage. public static final byte MAX_ATTESTATION_IDS_SIZE = 64; - // DER subject max length. public static final short MAX_SUBJECT_DER_LEN = 1095; } diff --git a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java index 95ee67fb..425e1c87 100644 --- a/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/AndroidSEProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -44,12 +44,6 @@ public class KMUtils { public static final byte[] fourYrsMsec = { 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 }; // 126230400000 - public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00 - }; // 1577836800000 msec - public static final byte[] firstJan2050 = { - 0, 0, 0x02, 0x4b, (byte) 0xCE, 0x5C, (byte) 0xF0, 0x00 - }; // 2524608000000 // msec public static final byte[] febMonthLeapMSec = { 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00 @@ -63,13 +57,31 @@ public class KMUtils { public static final byte[] ThirtDaysMonthMsec = { 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 }; // 2592000000 - public static final short year2051 = 2051; - public static final short year2020 = 2020; + public static final byte[] firstJan2000 = { + 0, 0, 0, (byte) 0xDC, 0x6A, (byte) 0xCF, (byte) 0xAC, 0x00 + }; // 946684800000 + private static final byte[] dec319999Ms = { + (byte) 0, (byte) 0, (byte) 0xE6, 0x77, (byte) 0xD2, 0x1F, (byte) 0xD8, 0x18 + }; // 253402300799000 + public static final byte[] fourHundredYrsMSec = { + 0x00, 0x00, 0x0B, 0x7A, (byte) 0xF8, 0x5D, (byte) 0x9C, 0x00 + }; // 12622780800000 ((365×400 + 100 - 3) * 24 * 60 * 60 * 1000) + public static final byte[] centuryWithLeapMSec = { + 0x00, 0x00, 0x02, (byte) 0xDE, (byte) 0xC1, (byte) 0xF4, (byte) 0x2C, 0x00 + }; // 3155760000000 ((100×365 + 25) * 24 * 60 * 60 * 1000) + public static final byte[] centuryMSec = { + 0x00, 0x00, 0x02, (byte) 0xDE, (byte) 0xBC, (byte) 0xCD, (byte) 0xD0, 0x00 + }; // 3155673600000 ((100×365 + 24) * 24 * 60 * 60 * 1000) + public static final short year1970 = 1970; + public static final short year2000 = 2000; + public static final short year2050 = 2050; // Convert to milliseconds constants public static final byte[] SEC_TO_MILLIS_SHIFT_POS = {9, 8, 7, 6, 5, 3}; + // Represents long integer size + public static final byte UINT8 = 8; // -------------------------------------- - public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag) { + public static short convertToDate(short time, byte[] scratchPad) { short yrsCount = 0; short monthCount = 1; @@ -77,8 +89,8 @@ public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag short hhCount = 0; short mmCount = 0; short ssCount = 0; + short inputOffset = 0; byte Z = 0x5A; - boolean from2020 = true; Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); Util.arrayCopyNonAtomic( KMInteger.cast(time).getBuffer(), @@ -86,157 +98,75 @@ public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag scratchPad, (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time).length()); - // If the time is less then 1 Jan 2020 then it is an error - if (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, firstJan2020, (short) 0, (short) 8) - < 0) { + if (KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, dec319999Ms, (short) 0, UINT8) + > 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - if (utcFlag - && KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, firstJan2050, (short) 0, (short) 8) - >= 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - - if (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, firstJan2050, (short) 0, (short) 8) - < 0) { - Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } else { - from2020 = false; - Util.arrayCopyNonAtomic(firstJan2050, (short) 0, scratchPad, (short) 8, (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - // divide the given time with four yrs msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, (short) 8) + short quotient = 0; + short endYear = 0; + short baseYear = year1970; + if (KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, firstJan2000, (short) 0, UINT8) >= 0) { - Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, (short) 8); - // quotient is multiple of 4 - yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - yrsCount = (short) (yrsCount * 4); // number of yrs. - // copy reminder as new dividend - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } - - // Get the leap year index starting from the (base Year + yrsCount) Year. - short leapYrIdx = getLeapYrIndex(from2020, yrsCount); - - // if leap year index is 0, then the number of days for the 1st year will be 366 days. - // if leap year index is not 0, then the number of days for the 1st year will be 365 days. - if (((leapYrIdx == 0) - && (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, leapYearMsec, (short) 0, (short) 8) - >= 0)) - || ((leapYrIdx != 0) - && (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, yearMsec, (short) 0, (short) 8) - >= 0))) { - for (short i = 0; i < 4; i++) { - yrsCount++; - if (i == leapYrIdx) { - Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, (short) 8, (short) 8); - } else { - Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, (short) 8); - } - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - if (((short) (i + 1) == leapYrIdx)) { - if (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, leapYearMsec, (short) 0, (short) 8) - < 0) { - break; - } - } else { - if (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, yearMsec, (short) 0, (short) 8) - < 0) { - break; - } + baseYear = year2000; + // difference in millis from year 2000 + subtractAndCopy(scratchPad, inputOffset, firstJan2000, (short) 0); + // divide the time with 400 year milliseconds + quotient = divideAndCopy(scratchPad, inputOffset, fourHundredYrsMSec, (short) 0); + yrsCount = (short) (400 * quotient); + // divide the remaining time with 100 year milliseconds + endYear = (short) (yrsCount + 400); + for (; yrsCount <= endYear; yrsCount += 100) { + byte[] centuryMillis = centuryToMillis((short) (baseYear + yrsCount)); + if ((KMInteger.unsignedByteArrayCompare( + scratchPad, inputOffset, centuryMillis, (short) 0, UINT8) + < 0)) { + break; } + subtractAndCopy(scratchPad, inputOffset, centuryMillis, (short) 0); } } - - // total yrs from 1970 - if (from2020) { - yrsCount = (short) (year2020 + yrsCount); - } else { - yrsCount = (short) (year2051 + yrsCount); + yrsCount += baseYear; + yrsCount = adjustBaseYearToLeapYearsRange(yrsCount, scratchPad, inputOffset); + // divide the given time with four years msec count + quotient = divideAndCopy(scratchPad, inputOffset, fourYrsMsec, (short) 0); + yrsCount += (short) (quotient * 4); // number of yrs. + // divide the given time with one year msec + endYear = (short) (yrsCount + 4); + for (; yrsCount <= endYear; yrsCount++) { + byte[] yearMillis = yearToMillis(yrsCount); + if ((KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, yearMillis, (short) 0, UINT8) + < 0)) { + break; + } + subtractAndCopy(scratchPad, inputOffset, yearMillis, (short) 0); } - // divide the given time with one month msec count - if (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, oneMonthMsec, (short) 0, (short) 8) - >= 0) { - for (short i = 0; i < 12; i++) { - if (i == 1) { - // Feb month - if (isLeapYear(yrsCount)) { - // Leap year 29 days - Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, (short) 8, (short) 8); - } else { - // 28 days - Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); - } - } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { - Util.arrayCopyNonAtomic( - ThirtyOneDaysMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); - } else { - // 30 Days - Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, (short) 8, (short) 8); - } - - if (KMInteger.unsignedByteArrayCompare( - scratchPad, (short) 0, scratchPad, (short) 8, (short) 8) - >= 0) { - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } else { - break; - } - monthCount++; + for (; monthCount <= 12; monthCount++) { + byte[] monthMillis = monthToMillis(yrsCount, monthCount); + if ((KMInteger.unsignedByteArrayCompare( + scratchPad, inputOffset, monthMillis, (short) 0, UINT8) + < 0)) { + break; } + subtractAndCopy(scratchPad, inputOffset, monthMillis, (short) 0); } // divide the given time with one day msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, (short) 8) - >= 0) { - Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, (short) 8); - dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - dayCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } + dayCount = divideAndCopy(scratchPad, inputOffset, oneDayMsec, (short) 0); + dayCount++; // divide the given time with one hour msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, (short) 8) - >= 0) { - Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, (short) 8); - hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } + hhCount = divideAndCopy(scratchPad, inputOffset, oneHourMsec, (short) 0); // divide the given time with one minute msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, (short) 8) - >= 0) { - Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, (short) 8); - mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } + mmCount = divideAndCopy(scratchPad, inputOffset, oneMinMsec, (short) 0); // divide the given time with one second msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, (short) 8) - >= 0) { - Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, (short) 8); - ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, (short) 8); - } + ssCount = divideAndCopy(scratchPad, inputOffset, oneSecMsec, (short) 0); // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - short len = numberToString(yrsCount, scratchPad, (short) 0); // returns YYYY + Util.arrayFillNonAtomic(scratchPad, inputOffset, (short) 256, (byte) 0); + short len = numberToString(yrsCount, scratchPad, inputOffset); // returns YYYY len += numberToString(monthCount, scratchPad, len); len += numberToString(dayCount, scratchPad, len); len += numberToString(hhCount, scratchPad, len); @@ -244,7 +174,7 @@ public static short convertToDate(short time, byte[] scratchPad, boolean utcFlag len += numberToString(ssCount, scratchPad, len); scratchPad[len] = Z; len++; - if (utcFlag) { + if (yrsCount < year2050) { return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY } else { return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY @@ -268,6 +198,19 @@ public static short numberToString(short number, byte[] scratchPad, short offset return len; } + // Divide the given input with the divisor and copy the remainder back to the + // input buffer from inputOff + private static short divideAndCopy( + byte[] scratchPad, short inputOff, byte[] divisor, short offset) { + short scratchPadOff = (short) (inputOff + 8); + Util.arrayCopyNonAtomic(divisor, offset, scratchPad, scratchPadOff, UINT8); + short q = divide(scratchPad, inputOff, scratchPadOff, (short) (scratchPadOff + 8)); + if (q != 0) { + Util.arrayCopyNonAtomic(scratchPad, (short) (scratchPadOff + 8), scratchPad, inputOff, UINT8); + } + return q; + } + // Use Euclid's formula: dividend = quotient*divisor + remainder // i.e. dividend - quotient*divisor = remainder where remainder < divisor. // so this is division by subtraction until remainder remains. @@ -363,6 +306,14 @@ public static void add(byte[] buf, short op1, short op2, short result) { } } + // Subtract the two operands and copy the difference back to the input buffer from inputOff + private static void subtractAndCopy(byte[] scratchPad, short inputOff, byte[] buf, short bufOff) { + short scratchpadOff = (short) (inputOff + 8); + Util.arrayCopyNonAtomic(buf, bufOff, scratchPad, scratchpadOff, UINT8); + subtract(scratchPad, inputOff, scratchpadOff, (short) (scratchpadOff + 8), UINT8); + Util.arrayCopyNonAtomic(scratchPad, (short) (scratchpadOff + 8), scratchPad, inputOff, UINT8); + } + // subtraction by borrowing. public static void subtract(byte[] buf, short op1, short op2, short result, byte sizeBytes) { byte borrow = 0; @@ -403,14 +354,51 @@ public static boolean isLeapYear(short year) { return false; } - public static short getLeapYrIndex(boolean from2020, short yrsCount) { - short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); - for (short i = 0; i < 4; i++) { - if (isLeapYear((short) (newBaseYr + i))) { - return i; + private static byte[] yearToMillis(short year) { + if (isLeapYear(year)) { + return leapYearMsec; + } else { + return yearMsec; + } + } + + private static byte[] centuryToMillis(short year) { + if (isLeapYear(year)) { + return centuryWithLeapMSec; + } else { + return centuryMSec; + } + } + + private static byte[] monthToMillis(short year, short month) { + if (month == 2) { + if (isLeapYear(year)) { + return febMonthLeapMSec; + } else { + return febMonthMsec; + } + } else if (((month <= 7) && ((month % 2 == 1))) || ((month > 7) && ((month % 2 == 0)))) { + return ThirtyOneDaysMonthMsec; + } else { + return ThirtDaysMonthMsec; + } + } + + private static short adjustBaseYearToLeapYearsRange( + short year, byte[] scratchPad, short inputOffset) { + if (!isLeapYear(year)) { + // The rounded base year must fall within the range of leap years, which occur every + // four years. If the rounded base year is not a leap year then add one year to it + // so that it comes in the range of leap years. This is necessary when we divide the + // difference of the given time and rounded base year with four year milliseconds + // value. + if (KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, yearMsec, (short) 0, UINT8) + >= 0) { + subtractAndCopy(scratchPad, inputOffset, yearMsec, (short) 0); + year += 1; } } - return -1; + return year; } public static void computeOnesCompliment(byte[] buf, short offset, short len) { diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java index 2721c076..ae5cc29b 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMAttestationCertImpl.java @@ -256,8 +256,8 @@ private KMAttestationCert uniqueId(short obj) { @Override public KMAttestationCert notBefore(short obj, boolean derEncoded, byte[] scratchpad) { if (!derEncoded) { - // convert milliseconds to UTC date - indexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad, true); + // convert milliseconds to UTC / Generalized time format + indexes[NOT_BEFORE] = KMUtils.convertToDate(obj, scratchpad); } else { indexes[NOT_BEFORE] = KMByteBlob.instance( @@ -273,17 +273,8 @@ public KMAttestationCert notAfter( short usageExpiryTimeObj, boolean derEncoded, byte[] scratchPad) { if (!derEncoded) { if (usageExpiryTimeObj != KMType.INVALID_VALUE) { - // compare if the expiry time is greater then 2050 then use generalized - // time format else use utc time format. - short tmpVar = KMInteger.uint_64(KMUtils.firstJan2050, (short) 0); - if (KMInteger.compare(usageExpiryTimeObj, tmpVar) >= 0) { - usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, false); - } else { - usageExpiryTimeObj = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad, true); - } - indexes[NOT_AFTER] = usageExpiryTimeObj; - } else { - // notAfter = certExpirtyTimeObj; + // convert milliseconds to UTC / Generalized time format + indexes[NOT_AFTER] = KMUtils.convertToDate(usageExpiryTimeObj, scratchPad); } } else { indexes[NOT_AFTER] = usageExpiryTimeObj; diff --git a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java index 9a696cd8..425e1c87 100644 --- a/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java +++ b/Applet/JCardSimProvider/src/com/android/javacard/keymaster/KMUtils.java @@ -44,12 +44,6 @@ public class KMUtils { public static final byte[] fourYrsMsec = { 0, 0, 0, 0x1D, 0x63, (byte) 0xEB, 0x0C, 0x00 }; // 126230400000 - public static final byte[] firstJan2020 = { - 0, 0, 0x01, 0x6F, 0x5E, 0x66, (byte) 0xE8, 0x00 - }; // 1577836800000 msec - public static final byte[] firstJan2050 = { - 0, 0, 0x02, 0x4b, (byte) 0xCE, 0x5C, (byte) 0xF0, 0x00 - }; // 2524608000000 // msec public static final byte[] febMonthLeapMSec = { 0, 0, 0, 0, (byte) 0x95, 0x58, 0x6C, 0x00 @@ -63,14 +57,31 @@ public class KMUtils { public static final byte[] ThirtDaysMonthMsec = { 0, 0, 0, 0, (byte) 0x9A, 0x7E, (byte) 0xC8, 0x00 }; // 2592000000 - public static final short year2051 = 2051; - public static final short year2020 = 2020; + public static final byte[] firstJan2000 = { + 0, 0, 0, (byte) 0xDC, 0x6A, (byte) 0xCF, (byte) 0xAC, 0x00 + }; // 946684800000 + private static final byte[] dec319999Ms = { + (byte) 0, (byte) 0, (byte) 0xE6, 0x77, (byte) 0xD2, 0x1F, (byte) 0xD8, 0x18 + }; // 253402300799000 + public static final byte[] fourHundredYrsMSec = { + 0x00, 0x00, 0x0B, 0x7A, (byte) 0xF8, 0x5D, (byte) 0x9C, 0x00 + }; // 12622780800000 ((365×400 + 100 - 3) * 24 * 60 * 60 * 1000) + public static final byte[] centuryWithLeapMSec = { + 0x00, 0x00, 0x02, (byte) 0xDE, (byte) 0xC1, (byte) 0xF4, (byte) 0x2C, 0x00 + }; // 3155760000000 ((100×365 + 25) * 24 * 60 * 60 * 1000) + public static final byte[] centuryMSec = { + 0x00, 0x00, 0x02, (byte) 0xDE, (byte) 0xBC, (byte) 0xCD, (byte) 0xD0, 0x00 + }; // 3155673600000 ((100×365 + 24) * 24 * 60 * 60 * 1000) + public static final short year1970 = 1970; + public static final short year2000 = 2000; + public static final short year2050 = 2050; // Convert to milliseconds constants public static final byte[] SEC_TO_MILLIS_SHIFT_POS = {9, 8, 7, 6, 5, 3}; + // Represents long integer size + public static final byte UINT8 = 8; // -------------------------------------- - public static short convertToDate(short time, byte[] scratchPad, - boolean utcFlag) { + public static short convertToDate(short time, byte[] scratchPad) { short yrsCount = 0; short monthCount = 1; @@ -78,178 +89,84 @@ public static short convertToDate(short time, byte[] scratchPad, short hhCount = 0; short mmCount = 0; short ssCount = 0; + short inputOffset = 0; byte Z = 0x5A; - boolean from2020 = true; Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - Util.arrayCopyNonAtomic(KMInteger.cast(time).getBuffer(), - KMInteger.cast(time).getStartOff(), scratchPad, - (short) (8 - KMInteger.cast(time).length()), KMInteger.cast(time) - .length()); - // If the time is less then 1 Jan 2020 then it is an error - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2020, (short) 0, - (short) 8) < 0) { - KMException.throwIt(KMError.INVALID_ARGUMENT); - } - if (utcFlag - && KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2050, - (short) 0, (short) 8) >= 0) { + Util.arrayCopyNonAtomic( + KMInteger.cast(time).getBuffer(), + KMInteger.cast(time).getStartOff(), + scratchPad, + (short) (8 - KMInteger.cast(time).length()), + KMInteger.cast(time).length()); + if (KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, dec319999Ms, (short) 0, UINT8) + > 0) { KMException.throwIt(KMError.INVALID_ARGUMENT); } - - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, firstJan2050, (short) 0, - (short) 8) < 0) { - Util.arrayCopyNonAtomic(firstJan2020, (short) 0, scratchPad, (short) 8, - (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } else { - from2020 = false; - Util.arrayCopyNonAtomic(firstJan2050, (short) 0, scratchPad, (short) 8, - (short) 8); - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - // divide the given time with four yrs msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, fourYrsMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(fourYrsMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - // quotient is multiple of 4 - yrsCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - yrsCount = (short) (yrsCount * 4); // number of yrs. - // copy reminder as new dividend - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } - - //Get the leap year index starting from the (base Year + yrsCount) Year. - short leapYrIdx = getLeapYrIndex(from2020, yrsCount); - - // if leap year index is 0, then the number of days for the 1st year will be 366 days. - // if leap year index is not 0, then the number of days for the 1st year will be 365 days. - if (((leapYrIdx == 0) && - (KMInteger - .unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, (short) 0, (short) 8) - >= 0)) || - ((leapYrIdx != 0) && - (KMInteger - .unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, (short) 0, (short) 8) - >= 0))) { - for (short i = 0; i < 4; i++) { - yrsCount++; - if (i == leapYrIdx) { - Util.arrayCopyNonAtomic(leapYearMsec, (short) 0, scratchPad, - (short) 8, (short) 8); - } else { - Util.arrayCopyNonAtomic(yearMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - } - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - if (((short) (i + 1) == leapYrIdx)) { - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, leapYearMsec, - (short) 0, (short) 8) < 0) { - break; - } - } else { - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, yearMsec, - (short) 0, (short) 8) < 0) { - break; - } + short quotient = 0; + short endYear = 0; + short baseYear = year1970; + if (KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, firstJan2000, (short) 0, UINT8) + >= 0) { + baseYear = year2000; + // difference in millis from year 2000 + subtractAndCopy(scratchPad, inputOffset, firstJan2000, (short) 0); + // divide the time with 400 year milliseconds + quotient = divideAndCopy(scratchPad, inputOffset, fourHundredYrsMSec, (short) 0); + yrsCount = (short) (400 * quotient); + // divide the remaining time with 100 year milliseconds + endYear = (short) (yrsCount + 400); + for (; yrsCount <= endYear; yrsCount += 100) { + byte[] centuryMillis = centuryToMillis((short) (baseYear + yrsCount)); + if ((KMInteger.unsignedByteArrayCompare( + scratchPad, inputOffset, centuryMillis, (short) 0, UINT8) + < 0)) { + break; } + subtractAndCopy(scratchPad, inputOffset, centuryMillis, (short) 0); } } - - // total yrs from 1970 - if (from2020) { - yrsCount = (short) (year2020 + yrsCount); - } else { - yrsCount = (short) (year2051 + yrsCount); + yrsCount += baseYear; + yrsCount = adjustBaseYearToLeapYearsRange(yrsCount, scratchPad, inputOffset); + // divide the given time with four years msec count + quotient = divideAndCopy(scratchPad, inputOffset, fourYrsMsec, (short) 0); + yrsCount += (short) (quotient * 4); // number of yrs. + // divide the given time with one year msec + endYear = (short) (yrsCount + 4); + for (; yrsCount <= endYear; yrsCount++) { + byte[] yearMillis = yearToMillis(yrsCount); + if ((KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, yearMillis, (short) 0, UINT8) + < 0)) { + break; + } + subtractAndCopy(scratchPad, inputOffset, yearMillis, (short) 0); } - // divide the given time with one month msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMonthMsec, (short) 0, - (short) 8) >= 0) { - for (short i = 0; i < 12; i++) { - if (i == 1) { - // Feb month - if (isLeapYear(yrsCount)) { - // Leap year 29 days - Util.arrayCopyNonAtomic(febMonthLeapMSec, (short) 0, scratchPad, - (short) 8, (short) 8); - } else { - // 28 days - Util.arrayCopyNonAtomic(febMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); - } - } else if (((i <= 6) && ((i % 2 == 0))) || ((i > 6) && ((i % 2 == 1)))) { - Util.arrayCopyNonAtomic(ThirtyOneDaysMonthMsec, (short) 0, - scratchPad, (short) 8, (short) 8); - } else { - // 30 Days - Util.arrayCopyNonAtomic(ThirtDaysMonthMsec, (short) 0, scratchPad, - (short) 8, (short) 8); - } - - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, scratchPad, (short) 8, - (short) 8) >= 0) { - subtract(scratchPad, (short) 0, (short) 8, (short) 16, (byte) 8); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } else { - break; - } - monthCount++; + for (; monthCount <= 12; monthCount++) { + byte[] monthMillis = monthToMillis(yrsCount, monthCount); + if ((KMInteger.unsignedByteArrayCompare( + scratchPad, inputOffset, monthMillis, (short) 0, UINT8) + < 0)) { + break; } + subtractAndCopy(scratchPad, inputOffset, monthMillis, (short) 0); } // divide the given time with one day msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneDayMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneDayMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - dayCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - dayCount++; - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } + dayCount = divideAndCopy(scratchPad, inputOffset, oneDayMsec, (short) 0); + dayCount++; // divide the given time with one hour msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneHourMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneHourMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - hhCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } + hhCount = divideAndCopy(scratchPad, inputOffset, oneHourMsec, (short) 0); // divide the given time with one minute msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneMinMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneMinMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - mmCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } + mmCount = divideAndCopy(scratchPad, inputOffset, oneMinMsec, (short) 0); // divide the given time with one second msec count - if (KMInteger.unsignedByteArrayCompare(scratchPad, (short) 0, oneSecMsec, (short) 0, - (short) 8) >= 0) { - Util.arrayCopyNonAtomic(oneSecMsec, (short) 0, scratchPad, (short) 8, - (short) 8); - ssCount = divide(scratchPad, (short) 0, (short) 8, (short) 16); - Util.arrayCopyNonAtomic(scratchPad, (short) 16, scratchPad, (short) 0, - (short) 8); - } + ssCount = divideAndCopy(scratchPad, inputOffset, oneSecMsec, (short) 0); // Now convert to ascii string YYMMDDhhmmssZ or YYYYMMDDhhmmssZ - Util.arrayFillNonAtomic(scratchPad, (short) 0, (short) 256, (byte) 0); - short len = numberToString(yrsCount, scratchPad, (short) 0); // returns YYYY + Util.arrayFillNonAtomic(scratchPad, inputOffset, (short) 256, (byte) 0); + short len = numberToString(yrsCount, scratchPad, inputOffset); // returns YYYY len += numberToString(monthCount, scratchPad, len); len += numberToString(dayCount, scratchPad, len); len += numberToString(hhCount, scratchPad, len); @@ -257,15 +174,14 @@ public static short convertToDate(short time, byte[] scratchPad, len += numberToString(ssCount, scratchPad, len); scratchPad[len] = Z; len++; - if (utcFlag) { + if (yrsCount < year2050) { return KMByteBlob.instance(scratchPad, (short) 2, (short) (len - 2)); // YY } else { return KMByteBlob.instance(scratchPad, (short) 0, len); // YYYY } } - public static short numberToString(short number, byte[] scratchPad, - short offset) { + public static short numberToString(short number, byte[] scratchPad, short offset) { byte zero = 0x30; byte len = 2; byte digit; @@ -282,11 +198,23 @@ public static short numberToString(short number, byte[] scratchPad, return len; } + // Divide the given input with the divisor and copy the remainder back to the + // input buffer from inputOff + private static short divideAndCopy( + byte[] scratchPad, short inputOff, byte[] divisor, short offset) { + short scratchPadOff = (short) (inputOff + 8); + Util.arrayCopyNonAtomic(divisor, offset, scratchPad, scratchPadOff, UINT8); + short q = divide(scratchPad, inputOff, scratchPadOff, (short) (scratchPadOff + 8)); + if (q != 0) { + Util.arrayCopyNonAtomic(scratchPad, (short) (scratchPadOff + 8), scratchPad, inputOff, UINT8); + } + return q; + } + // Use Euclid's formula: dividend = quotient*divisor + remainder // i.e. dividend - quotient*divisor = remainder where remainder < divisor. // so this is division by subtraction until remainder remains. - public static short divide(byte[] buf, short dividend, short divisor, - short remainder) { + public static short divide(byte[] buf, short dividend, short divisor, short remainder) { short expCnt = 1; short q = 0; // first increase divisor so that it becomes greater then dividend. @@ -364,7 +292,7 @@ public static void add(byte[] buf, short op1, short op2, short result) { byte carry = 0; short tmp; short val1 = 0; - short val2 = 0; + short val2 = 0; while (index >= 0) { val1 = (short) (buf[(short) (op1 + index)] & 0x00FF); val2 = (short) (buf[(short) (op2 + index)] & 0x00FF); @@ -378,6 +306,14 @@ public static void add(byte[] buf, short op1, short op2, short result) { } } + // Subtract the two operands and copy the difference back to the input buffer from inputOff + private static void subtractAndCopy(byte[] scratchPad, short inputOff, byte[] buf, short bufOff) { + short scratchpadOff = (short) (inputOff + 8); + Util.arrayCopyNonAtomic(buf, bufOff, scratchPad, scratchpadOff, UINT8); + subtract(scratchPad, inputOff, scratchpadOff, (short) (scratchpadOff + 8), UINT8); + Util.arrayCopyNonAtomic(scratchPad, (short) (scratchpadOff + 8), scratchPad, inputOff, UINT8); + } + // subtraction by borrowing. public static void subtract(byte[] buf, short op1, short op2, short result, byte sizeBytes) { byte borrow = 0; @@ -399,8 +335,8 @@ public static void subtract(byte[] buf, short op1, short op2, short result, byte } } - public static short countTemporalCount(byte[] bufTime, short timeOff, - short timeLen, byte[] scratchPad, short offset) { + public static short countTemporalCount( + byte[] bufTime, short timeOff, short timeLen, byte[] scratchPad, short offset) { Util.arrayFillNonAtomic(scratchPad, (short) offset, (short) 24, (byte) 0); Util.arrayCopyNonAtomic(bufTime, timeOff, scratchPad, (short) (offset + 8 - timeLen), timeLen); Util.arrayCopyNonAtomic( @@ -410,8 +346,7 @@ public static short countTemporalCount(byte[] bufTime, short timeOff, public static boolean isLeapYear(short year) { if ((short) (year % 4) == (short) 0) { - if (((short) (year % 100) == (short) 0) && - ((short) (year % 400)) != (short) 0) { + if (((short) (year % 100) == (short) 0) && ((short) (year % 400)) != (short) 0) { return false; } return true; @@ -419,14 +354,51 @@ public static boolean isLeapYear(short year) { return false; } - public static short getLeapYrIndex(boolean from2020, short yrsCount) { - short newBaseYr = (short) (from2020 ? (year2020 + yrsCount) : (year2051 + yrsCount)); - for (short i = 0; i < 4; i++) { - if (isLeapYear((short) (newBaseYr + i))) { - return i; + private static byte[] yearToMillis(short year) { + if (isLeapYear(year)) { + return leapYearMsec; + } else { + return yearMsec; + } + } + + private static byte[] centuryToMillis(short year) { + if (isLeapYear(year)) { + return centuryWithLeapMSec; + } else { + return centuryMSec; + } + } + + private static byte[] monthToMillis(short year, short month) { + if (month == 2) { + if (isLeapYear(year)) { + return febMonthLeapMSec; + } else { + return febMonthMsec; + } + } else if (((month <= 7) && ((month % 2 == 1))) || ((month > 7) && ((month % 2 == 0)))) { + return ThirtyOneDaysMonthMsec; + } else { + return ThirtDaysMonthMsec; + } + } + + private static short adjustBaseYearToLeapYearsRange( + short year, byte[] scratchPad, short inputOffset) { + if (!isLeapYear(year)) { + // The rounded base year must fall within the range of leap years, which occur every + // four years. If the rounded base year is not a leap year then add one year to it + // so that it comes in the range of leap years. This is necessary when we divide the + // difference of the given time and rounded base year with four year milliseconds + // value. + if (KMInteger.unsignedByteArrayCompare(scratchPad, inputOffset, yearMsec, (short) 0, UINT8) + >= 0) { + subtractAndCopy(scratchPad, inputOffset, yearMsec, (short) 0); + year += 1; } } - return -1; + return year; } public static void computeOnesCompliment(byte[] buf, short offset, short len) { @@ -439,8 +411,8 @@ public static void computeOnesCompliment(byte[] buf, short offset, short len) { } // i * 1000 = (i << 9) + (i << 8) + (i << 7) + (i << 6) + (i << 5) + ( i << 3) - public static void convertToMilliseconds(byte[] buf, short inputOff, short outputOff, - short scratchPadOff) { + public static void convertToMilliseconds( + byte[] buf, short inputOff, short outputOff, short scratchPadOff) { short index = 0; short length = (short) SEC_TO_MILLIS_SHIFT_POS.length; while (index < length) { diff --git a/Applet/src/com/android/javacard/keymaster/KMDecoder.java b/Applet/src/com/android/javacard/keymaster/KMDecoder.java index dd05b131..406f7076 100644 --- a/Applet/src/com/android/javacard/keymaster/KMDecoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMDecoder.java @@ -483,31 +483,51 @@ private short decodeArray(short exp) { return arrPtr; } - private short decodeEnumTag(short exp) { - readTagKey(KMEnumTag.cast(exp).getTagType()); + private short createInstanceEnumType(short instanceType, byte[] buf, short offset, short len) { + byte type = KMType.getType(instanceType); + short ptr = KMType.INVALID_VALUE; + switch (type) { + case KMType.ENUM_TYPE: + ptr = KMEnum.instance(KMEnum.cast(instanceType).getEnumType(), buf, offset, len); + break; + case KMType.TAG_TYPE: + ptr = KMEnumTag.instance(scratchBuf[TAG_KEY_OFFSET], buf, offset, len); + break; + default: + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + } + return ptr; + } + + private short decodeEnumAndCreateInstance(short instanceType) { byte[] buffer = (byte[]) bufferRef[0]; - short startOff = scratchBuf[START_OFFSET]; - // Enum Tag value will always be integer with max 1 byte length. - if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { + short offset = scratchBuf[START_OFFSET]; + if ((buffer[offset] & MAJOR_TYPE_MASK) != UINT_TYPE) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short len = (short) (buffer[startOff] & ADDITIONAL_MASK); - byte enumVal = 0; - if (len > UINT8_LENGTH) { + short addInfo = (short) (buffer[offset] & ADDITIONAL_MASK); + if (addInfo > UINT32_LENGTH) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); } - if (len < UINT8_LENGTH) { - enumVal = (byte) (len & ADDITIONAL_MASK); - incrementStartOff((short) 1); - } else if (len == UINT8_LENGTH) { - incrementStartOff((short) 1); - // startOff is incremented so update the startOff - // with latest value before using it. - startOff = scratchBuf[START_OFFSET]; - enumVal = buffer[startOff]; + if (addInfo >= UINT8_LENGTH) { incrementStartOff((short) 1); + offset = scratchBuf[START_OFFSET]; + } + byte originalValue = buffer[offset]; + if (addInfo < UINT8_LENGTH) { + // In this case additional info is the actual enum value. + buffer[offset] = (byte) addInfo; } - return KMEnumTag.instance(scratchBuf[TAG_KEY_OFFSET], enumVal); + short len = (short) ((addInfo > UINT8_LENGTH) ? ((addInfo == UINT32_LENGTH) ? 4 : 2) : 1); + short ptr = createInstanceEnumType(instanceType, buffer, offset, len); + buffer[offset] = originalValue; + incrementStartOff(len); + return ptr; + } + + private short decodeEnumTag(short exp) { + readTagKey(KMEnumTag.cast(exp).getTagType()); + return decodeEnumAndCreateInstance(exp); } private short decodeBoolTag(short exp) { @@ -526,29 +546,7 @@ private short decodeBoolTag(short exp) { } private short decodeEnum(short exp) { - byte[] buffer = (byte[]) bufferRef[0]; - short startOff = scratchBuf[START_OFFSET]; - // Enum value will always be integer with max 1 byte length. - if ((buffer[startOff] & MAJOR_TYPE_MASK) != UINT_TYPE) { - ISOException.throwIt(ISO7816.SW_DATA_INVALID); - } - short len = (short) (buffer[startOff] & ADDITIONAL_MASK); - byte enumVal; - if (len > UINT8_LENGTH) { - ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); - } - if (len < UINT8_LENGTH) { - enumVal = (byte) (len & ADDITIONAL_MASK); - incrementStartOff((short) 1); - } else { - incrementStartOff((short) 1); - // startOff is incremented so update the startOff - // with latest value before using it. - startOff = scratchBuf[START_OFFSET]; - enumVal = buffer[startOff]; - incrementStartOff((short) 1); - } - return KMEnum.instance(KMEnum.cast(exp).getEnumType(), enumVal); + return decodeEnumAndCreateInstance(exp); } private short decodeSimpleValue(short exp) { diff --git a/Applet/src/com/android/javacard/keymaster/KMEncoder.java b/Applet/src/com/android/javacard/keymaster/KMEncoder.java index 65394bd1..2146c821 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEncoder.java +++ b/Applet/src/com/android/javacard/keymaster/KMEncoder.java @@ -396,11 +396,19 @@ private void encodeBoolTag(short obj) { private void encodeEnumTag(short obj) { writeTag(KMEnumTag.cast(obj).getTagType(), KMEnumTag.cast(obj).getKey()); - writeByteValue(KMEnumTag.cast(obj).getValue()); + encodeInteger( + KMEnumTag.cast(obj).getBuffer(), + KMEnumTag.cast(obj).length(), + KMEnumTag.cast(obj).getStartOffset(), + UINT_TYPE); } private void encodeEnum(short obj) { - writeByteValue(KMEnum.cast(obj).getVal()); + encodeInteger( + KMEnum.cast(obj).getBuffer(), + KMEnum.cast(obj).length(), + KMEnum.cast(obj).getStartOffset(), + UINT_TYPE); } private void encodeInteger(byte[] val, short len, short startOff, short majorType) { diff --git a/Applet/src/com/android/javacard/keymaster/KMEnum.java b/Applet/src/com/android/javacard/keymaster/KMEnum.java index 44bf4770..7f13853f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnum.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnum.java @@ -73,7 +73,7 @@ public static short instance(short enumType) { if (!validateEnum(enumType, NO_VALUE)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = KMType.instance(ENUM_TYPE, (short) 2); + short ptr = KMType.instance(ENUM_TYPE, (short) 2 /* TAG_KEY */); Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), enumType); return ptr; } @@ -82,12 +82,28 @@ public static short instance(short enumType, byte val) { if (!validateEnum(enumType, val)) { ISOException.throwIt(ISO7816.SW_DATA_INVALID); } - short ptr = KMType.instance(ENUM_TYPE, (short) 3); + short ptr = KMType.instance(ENUM_TYPE, (short) (2 /* TAG_KEY */ + 1 /* Byte value */)); Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), enumType); heap[(short) (ptr + TLV_HEADER_SIZE + 2)] = val; return ptr; } + public static short instance(short key, byte[] num, short srcOff, short length) { + if (length == 1) { + return instance(key, num[srcOff]); + } + if (!validateEnum(key, num, srcOff, length)) { + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + } + short ptr = KMType.instance(ENUM_TYPE, (short) (2 /* TAG_KEY */ + KMInteger.UINT_32)); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), key); + short destValOff = (short) (ptr + TLV_HEADER_SIZE + 2); + Util.arrayFillNonAtomic(heap, destValOff, KMInteger.UINT_32, (byte) 0); + Util.arrayCopyNonAtomic( + num, srcOff, heap, (short) (destValOff + KMInteger.UINT_32 - length), length); + return ptr; + } + private static void create() { // The allowed enum values to corresponding enum types in the types array. if (enums == null) { @@ -145,13 +161,21 @@ private static boolean validateEnum(short key, byte value) { } public short length() { - return Util.getShort(heap, (short) (KMType.instanceTable[KM_ENUM_OFFSET] + 1)); + return (short) (Util.getShort(heap, (short) (KMType.instanceTable[KM_ENUM_OFFSET] + 1)) - 2); } public byte getVal() { return heap[(short) (KMType.instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE + 2)]; } + public short value(byte[] dest, short destOff) { + return copyToUint32(heap, getStartOffset(), length(), dest, destOff); + } + + public short getStartOffset() { + return (short) (KMType.instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE + 2); + } + public void setVal(byte val) { heap[(short) (KMType.instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE + 2)] = val; } @@ -163,4 +187,20 @@ public short getEnumType() { public void setEnumType(short type) { Util.setShort(heap, (short) (KMType.instanceTable[KM_ENUM_OFFSET] + TLV_HEADER_SIZE), type); } + + public static boolean validateEnum(short key, byte[] buf, short off, short len) { + if (len != KMInteger.UINT_32) { + return false; + } + switch (key) { + case KMType.USER_AUTH_TYPE: + // HardwareAuthenticatorType::ANY - 0xFFFFFFFF + short highShort = Util.getShort(buf, off); + short lowShort = Util.getShort(buf, (short) (off + 2)); + return ((short) 0xFFFF == (short) (highShort & lowShort)); + + default: + return false; + } + } } diff --git a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java index a7bcbe68..f4f7e29f 100644 --- a/Applet/src/com/android/javacard/keymaster/KMEnumTag.java +++ b/Applet/src/com/android/javacard/keymaster/KMEnumTag.java @@ -73,6 +73,24 @@ public static short instance(short key, byte val) { return ptr; } + public static short instance(short key, byte[] val, short valOff, short valLen) { + if (valLen == 1) { + return instance(key, val[valOff]); + } + if (!KMEnum.validateEnum(key, val, valOff, valLen)) { + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + } + short ptr = + KMType.instance(TAG_TYPE, (short) (2 /* TAG_TYPE */ + 2 /* TAG_KEY */ + KMInteger.UINT_32)); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE), ENUM_TAG); + Util.setShort(heap, (short) (ptr + TLV_HEADER_SIZE + 2), key); + short destValueOff = (short) (ptr + TLV_HEADER_SIZE + 4); + Util.arrayFillNonAtomic(heap, destValueOff, KMInteger.UINT_32, (byte) 0); + Util.arrayCopyNonAtomic( + val, valOff, heap, (short) (destValueOff + KMInteger.UINT_32 - valLen), valLen); + return ptr; + } + public static KMEnumTag cast(short ptr) { if (heap[ptr] != TAG_TYPE) { ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED); @@ -137,6 +155,19 @@ public static short getValue(short tagKey, short keyParameters) { return KMType.INVALID_VALUE; } + public short length() { + return (short) + (Util.getShort(heap, (short) (KMType.instanceTable[KM_ENUM_TAG_OFFSET] + 1)) - 4); + } + + public short getStartOffset() { + return (short) (KMType.instanceTable[KM_ENUM_TAG_OFFSET] + TLV_HEADER_SIZE + 4); + } + + public short value(byte[] dest, short destOff) { + return copyToUint32(heap, getStartOffset(), length(), dest, destOff); + } + public short getKey() { return Util.getShort( heap, (short) (KMType.instanceTable[KM_ENUM_TAG_OFFSET] + TLV_HEADER_SIZE + 2)); diff --git a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java index 02401e7f..a410e00c 100644 --- a/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java +++ b/Applet/src/com/android/javacard/keymaster/KMKeymasterApplet.java @@ -1656,6 +1656,7 @@ private boolean isKeyMintReady(byte apduIns) { case INS_GET_HMAC_SHARING_PARAM_CMD: case INS_COMPUTE_SHARED_HMAC_CMD: case INS_EARLY_BOOT_ENDED_CMD: + case INS_DELETE_ALL_KEYS_CMD: case INS_INIT_STRONGBOX_CMD: case INS_GET_ROT_CHALLENGE_CMD: case INS_SEND_ROT_DATA_CMD: @@ -2981,12 +2982,12 @@ private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchP // validate operation handle. short ptr = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getChallenge(); if (KMInteger.compare(ptr, op.getHandle()) != 0) { - KMException.throwIt(KMError.VERIFICATION_FAILED); + KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } tmpVariables[0] = op.getAuthTime(); tmpVariables[2] = KMVerificationToken.cast(data[VERIFICATION_TOKEN]).getTimestamp(); if (tmpVariables[2] == KMType.INVALID_VALUE) { - KMException.throwIt(KMError.VERIFICATION_FAILED); + KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } if (KMInteger.compare(tmpVariables[0], tmpVariables[2]) < 0) { KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); @@ -3000,7 +3001,8 @@ private void authorizeUpdateFinishOperation(KMOperationState op, byte[] scratchP if (KMInteger.compare(data[OP_HANDLE], tmpVariables[0]) != 0) { KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } - if (!authTokenMatches(op.getUserSecureId(), op.getAuthType(), scratchPad)) { + short len = op.getAuthType(scratchPad, (short) 0); + if (!authTokenMatches(op.getUserSecureId(), scratchPad, (short) 0, len, scratchPad, len)) { KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } } @@ -3077,10 +3079,10 @@ private void authorizeDeviceUnlock(byte[] scratchPad) { } // Now check if the device unlock requires password only authentication and whether // auth token is generated through password authentication or not. + scratchPad[0] = KMType.PASSWORD; + short authTypeLen = 1; if (kmDataStore.getDeviceLockPasswordOnly()) { - ptr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType(); - ptr = KMEnum.cast(ptr).getVal(); - if (((byte) ptr & KMType.PASSWORD) == 0) { + if (!hwAuthTypeMatches(scratchPad, (short) 0, authTypeLen, scratchPad, authTypeLen)) { KMException.throwIt(KMError.DEVICE_LOCKED); } } @@ -3131,11 +3133,11 @@ private void validateVerificationToken(short verToken, byte[] scratchPad) { short ptr = KMVerificationToken.cast(verToken).getMac(); // If mac length is zero then token is empty. if (KMByteBlob.cast(ptr).length() == 0) { - KMException.throwIt(KMError.INVALID_MAC_LENGTH); + KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } if (!verifyVerificationTokenMacInBigEndian(verToken, scratchPad)) { // Throw Exception if none of the combination works. - KMException.throwIt(KMError.VERIFICATION_FAILED); + KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } } @@ -3974,7 +3976,29 @@ private boolean isHwAuthTokenContainsMatchingSecureId(short hwAuthToken, short s return false; } - private boolean authTokenMatches(short userSecureIdsPtr, short authType, byte[] scratchPad) { + public boolean hwAuthTypeMatches( + byte[] buf, short off, short len, byte[] scratchPad, short scratchOff) { + Util.arrayFillNonAtomic(scratchPad, scratchOff, (short) (2 * KMInteger.UINT_32), (byte) 0); + short enumPtr = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType(); + if (KMInteger.UINT_32 != KMEnum.cast(enumPtr).value(scratchPad, scratchOff)) { + return false; + } + Util.arrayCopyNonAtomic( + buf, off, scratchPad, (short) (scratchOff + 2 * KMInteger.UINT_32 - len), len); + short highShort = Util.getShort(scratchPad, scratchOff); + short lowShort = Util.getShort(scratchPad, (short) (scratchOff + 2)); + short otherHighShort = Util.getShort(scratchPad, (short) (scratchOff + KMInteger.UINT_32)); + short otherLowShort = Util.getShort(scratchPad, (short) (scratchOff + KMInteger.UINT_32 + 2)); + return (0 != (lowShort & otherLowShort) || 0 != (highShort & otherHighShort)); + } + + private boolean authTokenMatches( + short userSecureIdsPtr, + byte[] buf, + short off, + short len, + byte[] scratchPad, + short scratchOff) { if (data[HW_TOKEN] == KMType.INVALID_VALUE) { return false; } @@ -3982,12 +4006,7 @@ private boolean authTokenMatches(short userSecureIdsPtr, short authType, byte[] return false; } // check auth type - tmpVariables[2] = KMHardwareAuthToken.cast(data[HW_TOKEN]).getHwAuthenticatorType(); - tmpVariables[2] = KMEnum.cast(tmpVariables[2]).getVal(); - if (((byte) tmpVariables[2] & (byte) authType) == 0) { - return false; - } - return true; + return hwAuthTypeMatches(buf, off, len, scratchPad, scratchOff); } private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratchPad) { @@ -4006,16 +4025,19 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc } // authenticator type must be provided. if (KMType.INVALID_VALUE - == (authType = KMEnumTag.getValue(KMType.USER_AUTH_TYPE, data[HW_PARAMETERS]))) { + == (authType = + KMKeyParameters.findTag( + KMType.ENUM_TAG, KMType.USER_AUTH_TYPE, data[HW_PARAMETERS]))) { // Authentication required, but no auth type found. KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } + short len = KMEnumTag.cast(authType).value(scratchPad, (short) 0); short authTimeoutTagPtr = KMKeyParameters.findTag(KMType.UINT_TAG, KMType.AUTH_TIMEOUT, data[HW_PARAMETERS]); if (authTimeoutTagPtr != KMType.INVALID_VALUE) { // authenticate user - if (!authTokenMatches(userSecureIdPtr, authType, scratchPad)) { + if (!authTokenMatches(userSecureIdPtr, scratchPad, (short) 0, len, scratchPad, len)) { KMException.throwIt(KMError.KEY_USER_NOT_AUTHENTICATED); } @@ -4040,7 +4062,7 @@ private void authorizeUserSecureIdAuthTimeout(KMOperationState op, byte[] scratc // auth per operation required // store user secure id and authType in OperationState. op.setUserSecureId(userSecureIdPtr); - op.setAuthType((byte) authType); + op.setAuthType(scratchPad, (short) 0, len); // set flags op.setOneTimeAuthReqd(false); op.setAuthPerOperationReqd(true); @@ -4075,7 +4097,7 @@ private boolean verifyHwTokenMacInBigEndian(short hwToken, byte[] scratchPad) { len += KMInteger.UINT_64; // concatenate authenticator type - 4 bytes ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); - scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); + KMEnum.cast(ptr).value(scratchPad, len); len += KMInteger.UINT_32; // concatenate timestamp -8 bytes ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); @@ -4117,7 +4139,7 @@ private boolean verifyHwTokenMacInLittleEndian(short hwToken, byte[] scratchPad) len += KMInteger.UINT_64; // concatenate authenticator type - 4 bytes ptr = KMHardwareAuthToken.cast(hwToken).getHwAuthenticatorType(); - scratchPad[(short) (len + 3)] = KMEnum.cast(ptr).getVal(); + KMEnum.cast(ptr).value(scratchPad, len); len += KMInteger.UINT_32; // concatenate timestamp - 8 bytes ptr = KMHardwareAuthToken.cast(hwToken).getTimestamp(); diff --git a/Applet/src/com/android/javacard/keymaster/KMOperationState.java b/Applet/src/com/android/javacard/keymaster/KMOperationState.java index 2a53acd2..64885778 100644 --- a/Applet/src/com/android/javacard/keymaster/KMOperationState.java +++ b/Applet/src/com/android/javacard/keymaster/KMOperationState.java @@ -31,7 +31,7 @@ public class KMOperationState { // sizes public static final byte OPERATION_HANDLE_SIZE = 8; - public static final byte DATA_SIZE = 11; + public static final byte DATA_SIZE = 12; public static final byte AUTH_TIME_SIZE = 8; // Secure user ids 5 * 8 = 40 bytes ( Considering Maximum 5 SECURE USER IDs) // First two bytes are reserved to store number of secure ids. So total 42 bytes. @@ -47,7 +47,7 @@ public class KMOperationState { private static final byte MAC_LENGTH = 7; private static final byte MGF_DIGEST = 8; private static final byte AUTH_TYPE = 9; - private static final byte MIN_MAC_LENGTH = 10; + private static final byte MIN_MAC_LENGTH = 11; private static final byte OPERATION = 0; private static final byte HMAC_SIGNER_OPERATION = 1; // Flag masks @@ -187,12 +187,16 @@ public void setOneTimeAuthReqd(boolean flag) { } } - public short getAuthType() { - return data[AUTH_TYPE]; + public short getAuthType(byte[] buf, short offset) { + Util.arrayFillNonAtomic(buf, offset, (short) 4, (byte) 0); + offset = Util.setShort(buf, offset, data[AUTH_TYPE]); + Util.setShort(buf, offset, data[AUTH_TYPE + 1]); + return (short) 4; } - public void setAuthType(byte authType) { - data[AUTH_TYPE] = authType; + public void setAuthType(byte[] buf, short offset, short len) { + data[AUTH_TYPE] = Util.getShort(buf, offset); + data[(short) (AUTH_TYPE + 1)] = Util.getShort(buf, (short) (offset + 2)); } public short getUserSecureId() { diff --git a/Applet/src/com/android/javacard/keymaster/KMType.java b/Applet/src/com/android/javacard/keymaster/KMType.java index a18cb7f1..fbee00b5 100644 --- a/Applet/src/com/android/javacard/keymaster/KMType.java +++ b/Applet/src/com/android/javacard/keymaster/KMType.java @@ -388,6 +388,21 @@ public static short getValue(short ptr) { return Util.getShort(heap, (short) (ptr + TLV_HEADER_SIZE)); } + protected static short copyToUint32( + byte[] src, short srcOff, short srcLen, byte[] dest, short destOff) { + if (srcLen > KMInteger.UINT_32) { + ISOException.throwIt(ISO7816.SW_DATA_INVALID); + } + Util.arrayFillNonAtomic(dest, destOff, KMInteger.UINT_32, (byte) 0); + Util.arrayCopyNonAtomic( + src, srcOff, dest, (short) (destOff + KMInteger.UINT_32 - srcLen), srcLen); + return KMInteger.UINT_32; + } + + protected byte[] getBuffer() { + return heap; + } + protected static short instance(byte type, short length) { if (length < 0) { ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); diff --git a/HAL/Android.bp b/HAL/Android.bp index 48dcca77..b05bb3e0 100644 --- a/HAL/Android.bp +++ b/HAL/Android.bp @@ -128,7 +128,6 @@ cc_binary { "service.cpp", ], required: [ - "RemoteProvisioner", "android.hardware.hardware_keystore.jc-strongbox-keymint.xml", ], } diff --git a/HAL/CborConverter.cpp b/HAL/CborConverter.cpp index d7e6c11e..24d38827 100644 --- a/HAL/CborConverter.cpp +++ b/HAL/CborConverter.cpp @@ -90,63 +90,63 @@ bool CborConverter::addAttestationKey(Array& array, bool CborConverter::addKeyparameters(Array& array, const vector& keyParams) { Map map; - std::map> enum_repetition; - std::map uint_repetition; + std::map> enum_repetition; + std::map uint_repetition; for (auto& param : keyParams) { auto tag = legacy_enum_conversion(param.tag); switch (typeFromTag(tag)) { case KM_ENUM: { auto paramEnum = aidlEnumParam2Uint32(param); if (paramEnum.has_value()) { - map.add(static_cast(tag), *paramEnum); + map.add(static_cast(tag), *paramEnum); } break; } case KM_UINT: if (param.value.getTag() == KeyParameterValue::integer) { - auto intVal = param.value.get(); - map.add(static_cast(tag), intVal); + uint32_t intVal = param.value.get(); + map.add(static_cast(tag), intVal); } break; case KM_UINT_REP: if (param.value.getTag() == KeyParameterValue::integer) { - auto intVal = param.value.get(); - uint_repetition[static_cast(tag)].add(intVal); + uint32_t intVal = param.value.get(); + uint_repetition[static_cast(tag)].add(intVal); } break; case KM_ENUM_REP: { auto paramEnumRep = aidlEnumParam2Uint32(param); if (paramEnumRep.has_value()) { - enum_repetition[static_cast(tag)].push_back(*paramEnumRep); + enum_repetition[static_cast(tag)].push_back(*paramEnumRep); } break; } case KM_ULONG: if (param.value.getTag() == KeyParameterValue::longInteger) { - auto longVal = param.value.get(); - map.add(static_cast(tag), longVal); + uint64_t longVal = param.value.get(); + map.add(static_cast(tag), longVal); } break; case KM_ULONG_REP: if (param.value.getTag() == KeyParameterValue::longInteger) { - auto longVal = param.value.get(); - uint_repetition[static_cast(tag & 0x00000000ffffffff)].add(longVal); + uint64_t longVal = param.value.get(); + uint_repetition[static_cast(tag)].add(longVal); } break; case KM_DATE: if (param.value.getTag() == KeyParameterValue::dateTime) { - auto dateVal = param.value.get(); - map.add(static_cast(tag), dateVal); + uint64_t dateVal = param.value.get(); + map.add(static_cast(tag), dateVal); } break; case KM_BOOL: - map.add(static_cast(tag), 1 /* true */); + map.add(static_cast(tag), 1 /* true */); break; case KM_BIGNUM: case KM_BYTES: if (param.value.getTag() == KeyParameterValue::blob) { const auto& value = param.value.get(); - map.add(static_cast(tag & 0x00000000ffffffff), value); + map.add(static_cast(tag), value); } break; case KM_INVALID: diff --git a/HAL/JavacardKeyMintDevice.cpp b/HAL/JavacardKeyMintDevice.cpp index bd68b48f..338fbe97 100644 --- a/HAL/JavacardKeyMintDevice.cpp +++ b/HAL/JavacardKeyMintDevice.cpp @@ -85,6 +85,7 @@ ScopedAStatus JavacardKeyMintDevice::getHardwareInfo(KeyMintHardwareInfo* info) ScopedAStatus JavacardKeyMintDevice::generateKey(const vector& keyParams, const optional& attestationKey, KeyCreationResult* creationResult) { + card_->sendPendingEvents(); cppbor::Array array; // add key params cbor_.addKeyparameters(array, keyParams); @@ -125,6 +126,7 @@ ScopedAStatus JavacardKeyMintDevice::importKey(const vector& keyPa const optional& attestationKey, KeyCreationResult* creationResult) { + card_->sendPendingEvents(); cppbor::Array request; // add key params cbor_.addKeyparameters(request, keyParams); @@ -160,6 +162,7 @@ ScopedAStatus JavacardKeyMintDevice::importWrappedKey(const vector& wra const vector& unwrappingParams, int64_t passwordSid, int64_t biometricSid, KeyCreationResult* creationResult) { + card_->sendPendingEvents(); cppbor::Array request; std::unique_ptr item; vector keyBlob; @@ -240,6 +243,7 @@ JavacardKeyMintDevice::sendFinishImportWrappedKeyCmd( ScopedAStatus JavacardKeyMintDevice::upgradeKey(const vector& keyBlobToUpgrade, const vector& upgradeParams, vector* keyBlob) { + card_->sendPendingEvents(); cppbor::Array request; // add key blob request.add(Bstr(keyBlobToUpgrade)); @@ -271,9 +275,10 @@ ScopedAStatus JavacardKeyMintDevice::deleteKey(const vector& keyBlob) { } ScopedAStatus JavacardKeyMintDevice::deleteAllKeys() { - auto [item, err] = card_->sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD); + auto [_, err] = card_->sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD); if (err != KM_ERROR_OK) { - LOG(ERROR) << "Error in sending in deleteAllKeys."; + LOG(ERROR) << "Error in sending deleteAllKeys."; + card_->setDeleteAllKeysPending(); return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); @@ -292,7 +297,7 @@ ScopedAStatus JavacardKeyMintDevice::begin(KeyPurpose purpose, const std::vector const std::vector& params, const std::optional& authToken, BeginResult* result) { - + card_->sendPendingEvents(); cppbor::Array array; std::vector response; // make request @@ -302,13 +307,6 @@ ScopedAStatus JavacardKeyMintDevice::begin(KeyPurpose purpose, const std::vector HardwareAuthToken token = authToken.value_or(HardwareAuthToken()); cbor_.addHardwareAuthToken(array, token); - // Send earlyBootEnded if there is any pending earlybootEnded event. - auto retErr = card_->sendEarlyBootEndedEvent(false); - if (retErr != KM_ERROR_OK) { - return km_utils::kmError2ScopedAStatus(retErr); - ; - } - auto [item, err] = card_->sendRequest(Instruction::INS_BEGIN_OPERATION_CMD, array); if (err != KM_ERROR_OK) { LOG(ERROR) << "Error in sending in begin."; @@ -350,9 +348,10 @@ JavacardKeyMintDevice::deviceLocked(bool passwordOnly, } ScopedAStatus JavacardKeyMintDevice::earlyBootEnded() { - auto err = card_->sendEarlyBootEndedEvent(true); + auto [_, err] = card_->sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD); if (err != KM_ERROR_OK) { - LOG(ERROR) << "Error in sending earlyBootEndedEvent."; + LOG(ERROR) << "Error in sending earlyBootEnded."; + card_->setEarlyBootEndedPending(); return km_utils::kmError2ScopedAStatus(err); } return ScopedAStatus::ok(); @@ -361,6 +360,7 @@ ScopedAStatus JavacardKeyMintDevice::earlyBootEnded() { ScopedAStatus JavacardKeyMintDevice::getKeyCharacteristics( const std::vector& keyBlob, const std::vector& appId, const std::vector& appData, std::vector* result) { + card_->sendPendingEvents(); cppbor::Array request; request.add(vector(keyBlob)); request.add(vector(appId)); diff --git a/HAL/JavacardSecureElement.cpp b/HAL/JavacardSecureElement.cpp index 7c4f0380..5b0fa507 100644 --- a/HAL/JavacardSecureElement.cpp +++ b/HAL/JavacardSecureElement.cpp @@ -42,19 +42,32 @@ keymaster_error_t JavacardSecureElement::initializeJavacard() { return err; } -keymaster_error_t JavacardSecureElement::sendEarlyBootEndedEvent(bool eventTriggered) { - isEarlyBootEventPending |= eventTriggered; - if (!isEarlyBootEventPending) { - return KM_ERROR_OK; +void JavacardSecureElement::setDeleteAllKeysPending() { + isDeleteAllKeysPending = true; +} + +void JavacardSecureElement::setEarlyBootEndedPending() { + isEarlyBootEndedPending = true; +} + +void JavacardSecureElement::sendPendingEvents() { + if (isDeleteAllKeysPending) { + auto [_, err] = sendRequest(Instruction::INS_DELETE_ALL_KEYS_CMD); + if (err == KM_ERROR_OK) { + isDeleteAllKeysPending = false; + } else { + LOG(ERROR) << "Error in sending deleteAllKeys."; + } } - auto [item, err] = sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD); - if (err != KM_ERROR_OK) { - // Incase of failure cache the event and send in the next immediate request to Applet. - isEarlyBootEventPending = true; - return err; + + if (isEarlyBootEndedPending) { + auto [_, err] = sendRequest(Instruction::INS_EARLY_BOOT_ENDED_CMD); + if (err == KM_ERROR_OK) { + isEarlyBootEndedPending = false; + } else { + LOG(ERROR) << "Error in sending earlyBootEnded."; + } } - isEarlyBootEventPending = false; - return KM_ERROR_OK; } keymaster_error_t JavacardSecureElement::constructApduMessage(Instruction& ins, diff --git a/HAL/JavacardSecureElement.h b/HAL/JavacardSecureElement.h index 2ea5fe42..b4535d84 100644 --- a/HAL/JavacardSecureElement.h +++ b/HAL/JavacardSecureElement.h @@ -76,10 +76,8 @@ enum class Instruction { class JavacardSecureElement { public: - explicit JavacardSecureElement(shared_ptr transport, uint32_t osVersion, - uint32_t osPatchLevel, uint32_t vendorPatchLevel) - : transport_(transport), osVersion_(osVersion), osPatchLevel_(osPatchLevel), - vendorPatchLevel_(vendorPatchLevel), isEarlyBootEventPending(false) { + explicit JavacardSecureElement(shared_ptr transport) + : transport_(transport), isEarlyBootEndedPending(false), isDeleteAllKeysPending(false) { transport_->openConnection(); } virtual ~JavacardSecureElement() { transport_->closeConnection(); } @@ -96,7 +94,10 @@ class JavacardSecureElement { keymaster_error_t constructApduMessage(Instruction& ins, std::vector& inputData, std::vector& apduOut); keymaster_error_t initializeJavacard(); - keymaster_error_t sendEarlyBootEndedEvent(bool eventTriggered); + void sendPendingEvents(); + void setEarlyBootEndedPending(); + void setDeleteAllKeysPending(); + inline uint16_t getApduStatus(std::vector& inputData) { // Last two bytes are the status SW0SW1 uint8_t SW0 = inputData.at(inputData.size() - 2); @@ -104,11 +105,10 @@ class JavacardSecureElement { return (SW0 << 8 | SW1); } + private: shared_ptr transport_; - uint32_t osVersion_; - uint32_t osPatchLevel_; - uint32_t vendorPatchLevel_; - bool isEarlyBootEventPending; + bool isEarlyBootEndedPending; + bool isDeleteAllKeysPending; CborConverter cbor_; }; } // namespace keymint::javacard diff --git a/HAL/JavacardSharedSecret.cpp b/HAL/JavacardSharedSecret.cpp index c5cf9a24..524f7823 100644 --- a/HAL/JavacardSharedSecret.cpp +++ b/HAL/JavacardSharedSecret.cpp @@ -31,13 +31,8 @@ ScopedAStatus JavacardSharedSecret::getSharedSecretParameters(SharedSecretParame ScopedAStatus JavacardSharedSecret::computeSharedSecret(const std::vector& params, std::vector* secret) { - - auto error = card_->sendEarlyBootEndedEvent(false); - if (error != KM_ERROR_OK) { - LOG(ERROR) << "Error in sending earlyBoot event javacard."; - return keymint::km_utils::kmError2ScopedAStatus(error); - } - error = card_->initializeJavacard(); + card_->sendPendingEvents(); + auto error = card_->initializeJavacard(); if (error != KM_ERROR_OK) { LOG(ERROR) << "Error in initializing javacard."; return keymint::km_utils::kmError2ScopedAStatus(error); diff --git a/HAL/service.cpp b/HAL/service.cpp index e83ee3d4..62a4094c 100644 --- a/HAL/service.cpp +++ b/HAL/service.cpp @@ -81,8 +81,8 @@ std::shared_ptr getTransportInstance() { int main() { ABinderProcess_setThreadPoolMaxThreadCount(0); // Javacard Secure Element - std::shared_ptr card = std::make_shared( - getTransportInstance(), getOsVersion(), getOsPatchlevel(), getVendorPatchlevel()); + std::shared_ptr card = + std::make_shared(getTransportInstance()); // Add Keymint Service addService(card); // Add Shared Secret Service