/* * DrivingLicenseApplet - A reference implementation of the ISO18013 standards. * Based on the passport applet code developed by the JMRTD team, see * http://jmrtd.org * * Copyright (C) 2006 SoS group, Radboud University * Copyright (C) 2009 Wojciech Mostowski, Radboud University * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ package org.isodl.applet; import javacard.framework.ISO7816; import javacard.framework.ISOException; import javacard.framework.JCSystem; import javacard.framework.Util; import javacard.security.KeyBuilder; import javacard.security.RSAPublicKey; import javacard.security.Signature; /** * Encapsulation class for a card verifiable certificate according to ISO18013. * We assume there is only one instance of this class for the current EAP * certificate in chain. The root ana alternate root certificate data is also * stored in this class in persistent arrays. * * @author Wojciech Mostowski <woj@cs.ru.nl> * */ public class CVCertificate { /** * Offsets to where the particular data (offsets & lengths) of the current * certificate is (temporarily) stored in the data array */ private static final short OFFSET_PUB_KEY_MODULUS_OFFSET = 0; private static final short OFFSET_PUB_KEY_MODULUS_LENGTH = 1; private static final short OFFSET_PUB_KEY_EXPONENT_OFFSET = 2; private static final short OFFSET_PUB_KEY_EXPONENT_LENGTH = 3; private static final short OFFSET_SUB_ID_OFFSET = 4; private static final short OFFSET_SUB_ID_LENGTH = 5; private static final short OFFSET_AUTHORIZATION_OFFSET = 6; private static final short OFFSET_EFF_DATE_OFFSET = 7; private static final short OFFSET_EXP_DATE_OFFSET = 8; private static final short OFFSET_SIGNATURE_OFFSET = 9; private static final short OFFSET_SIGNATURE_LENGTH = 10; private static final short OFFSET_BODY_LENGTH = 11; /** Different tags to parse */ private static final short TAG_CERT_BODY = 0x7F4E; private static final short TAG_CERT_VERSION = 0x5F29; private static final short TAG_AUTH_ID = 0x42; private static final short TAG_PUB_KEY = 0x7F49; private static final short TAG_OID = 0x06; private static final short TAG_MODULUS = 0x81; private static final short TAG_EXPONENT = 0x82; private static final short TAG_SUBJECT_ID = 0x5F20; private static final short TAG_SUBJECT_AUTH = 0x7F4C; private static final short TAG_AUTHORIZATION = 0x53; private static final short TAG_EFF_DATE = 0x5F25; private static final short TAG_EXP_DATE = 0x5F24; private static final short TAG_SIGNATURE = 0x5F37; private static final byte AUTH_LEN_MASK = 0x0F; private static final byte ENTITY_MASK = (byte) 0xF0; private static final byte TRUST_ROOT = (byte) 0x20; private static final byte TRUST_TIME = (byte) 0x10; /** The ASN1 OID of the only algorithm our certificates support */ private static final byte[] RSA_SHA1_OID = { 0x28, (byte) 0x81, (byte) 0x8C, 0x5D, 0x03, 0x01, 0x14 }; /** The terminal OID, see ISO18013-3, C.2.1.5 */ private static final byte[] AR_TERMINAL_OID = { 0x28, (byte) 0x81, (byte) 0x8C, 0x5D, 0x03, 0x03, 0x01 }; private short[] data; private Object[] source; private RSAPublicKey currentCertPublicKey; private byte[] effectiveCertAuthorization; private byte[] currentCertAuthorization; private byte[] currentCertSubjectId; private byte[] currentCertEffDate; private byte[] currentCertExpDate; /** 2009-01-01 */ private byte[] currentDate = { 0x00, 0x09, 0x00, 0x01, 0x00, 0x01 }; private static final byte CERT_ROOT = 1; private static final byte CERT_ALT = 2; private byte[] currentCertNum; private byte[] rootCertHolderReference; private byte[] rootCertPublicKeyData; private byte[] rootCertAuthorization; private byte[] rootCertEffDate; private byte[] rootCertExpDate; private byte[] altCertHolderReference; private byte[] altCertPublicKeyData; private byte[] altCertAuthorization; private byte[] altCertEffDate; private byte[] altCertExpDate; private Signature signature; private byte[] comFile; private short cvcaRootIndex; private short cvcaAltIndex; CVCertificate() { data = JCSystem.makeTransientShortArray( (short) (OFFSET_BODY_LENGTH + 1), JCSystem.CLEAR_ON_DESELECT); source = JCSystem.makeTransientObjectArray((short) 1, JCSystem.CLEAR_ON_DESELECT); effectiveCertAuthorization = JCSystem.makeTransientByteArray((short)4, JCSystem.CLEAR_ON_DESELECT); currentCertAuthorization = JCSystem.makeTransientByteArray((short)4, JCSystem.CLEAR_ON_DESELECT); currentCertSubjectId = JCSystem.makeTransientByteArray((short) 17, JCSystem.CLEAR_ON_DESELECT); currentCertPublicKey = (RSAPublicKey) KeyBuilder.buildKey( KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_1024, false); currentCertEffDate = JCSystem.makeTransientByteArray((short)6, JCSystem.CLEAR_ON_DESELECT); currentCertExpDate = JCSystem.makeTransientByteArray((short)6, JCSystem.CLEAR_ON_DESELECT); currentCertNum = JCSystem.makeTransientByteArray((short)1, JCSystem.CLEAR_ON_DESELECT); signature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false); } /** * Checks if the provided subject id matches the current one, if any, or selects one of the root ones. * * @param data * byte[] with the subject id * @param offset * offset to data * @param length * length of the data * @return true if the current subject match or it was possible to select one of the root ones */ boolean selectSubjectId(byte[] data, short offset, short length) { if(currentCertSubjectId[0] == 0) { if(rootCertHolderReference != null && rootCertHolderReference[0] == (byte)length) { if(Util.arrayCompare(rootCertHolderReference, (short)1, data, offset, length) == 0) { setupCurrentKey(rootCertHolderReference, rootCertPublicKeyData, rootCertAuthorization, rootCertEffDate, rootCertExpDate); currentCertNum[0] = CERT_ROOT; return true; } }else if(altCertHolderReference != null && altCertHolderReference[0] == (byte)length) { if(Util.arrayCompare(altCertHolderReference, (short)1, data, offset, length) == 0) { setupCurrentKey(altCertHolderReference, altCertPublicKeyData, altCertAuthorization, altCertEffDate, altCertExpDate); currentCertNum[0] = CERT_ALT; return true; } } return false; } return length == currentCertSubjectId[0] && Util.arrayCompare(currentCertSubjectId, (short) 1, data, offset, length) == 0; } // Sets up the current certificate data from the certificate contained in one // of the CA certificates stored in this object private void setupCurrentKey(byte[] certHolderReference, byte[] certPublicKeyData, byte[] certAuthorization, byte[] certEffDate, byte[] certExpDate) { Util.arrayCopyNonAtomic(certHolderReference, (short)0, currentCertSubjectId, (short)0, (short)certHolderReference.length); Util.arrayCopyNonAtomic(certAuthorization, (short)0, effectiveCertAuthorization, (short)0, (short)effectiveCertAuthorization.length); Util.arrayCopyNonAtomic(certAuthorization, (short)0, currentCertAuthorization, (short)0, (short)currentCertAuthorization.length); Util.arrayCopyNonAtomic(certEffDate, (short)0, currentCertEffDate, (short)0, (short)6); Util.arrayCopyNonAtomic(certExpDate, (short)0, currentCertExpDate, (short)0, (short)6); currentCertPublicKey.setExponent(certPublicKeyData, (short)0, (short)3); currentCertPublicKey.setModulus(certPublicKeyData, (short)3, (short)128); } // Sets up the current certificate data from the certificate contained in source and data. private void setupCurrentKeyFromCurrentCertificate() { byte[] certData = (byte[])source[0]; short certHolderReferenceOffset = data[OFFSET_SUB_ID_OFFSET]; short certHolderReferenceLength = data[OFFSET_SUB_ID_LENGTH]; short pubKeyExpOffset = data[OFFSET_PUB_KEY_EXPONENT_OFFSET]; short pubKeyExpLength = data[OFFSET_PUB_KEY_EXPONENT_LENGTH]; short pubKeyModOffset = data[OFFSET_PUB_KEY_MODULUS_OFFSET]; short pubKeyModLength = data[OFFSET_PUB_KEY_MODULUS_LENGTH]; short authorizationOffset = data[OFFSET_AUTHORIZATION_OFFSET]; short effDateOffset = data[OFFSET_EFF_DATE_OFFSET]; short expDateOffset = data[OFFSET_EXP_DATE_OFFSET]; Util.arrayCopyNonAtomic(certData, certHolderReferenceOffset, currentCertSubjectId, (short)1, certHolderReferenceLength); currentCertSubjectId[0] = (byte)certHolderReferenceLength; currentCertPublicKey.setExponent(certData, pubKeyExpOffset, pubKeyExpLength); currentCertPublicKey.setModulus(certData, pubKeyModOffset, pubKeyModLength); byte nParent = (byte) (effectiveCertAuthorization[0] & AUTH_LEN_MASK); byte nCurrent = (byte) (certData[authorizationOffset] & AUTH_LEN_MASK); if (nParent != AUTH_LEN_MASK) { if (nCurrent == AUTH_LEN_MASK) { nCurrent = nParent; } else { nParent--; if (nParent < nCurrent) nCurrent = nParent; } } effectiveCertAuthorization[0] = (byte) ((byte) ((byte) (effectiveCertAuthorization[0] & certData[authorizationOffset]) & ENTITY_MASK) | nCurrent); for (short i = 1; i < 4; i++) { effectiveCertAuthorization[i] &= certData[(short) (authorizationOffset + i)]; } Util.arrayCopyNonAtomic(certData, authorizationOffset, currentCertAuthorization, (short)0, (short)4); Util.arrayCopyNonAtomic(certData, effDateOffset, currentCertEffDate, (short)0, (short)6); Util.arrayCopyNonAtomic(certData, expDateOffset, currentCertExpDate, (short)0, (short)6); } /** * Cleans up the current certificate information. * */ void clear() { cleanArray(data); Util.arrayFillNonAtomic(effectiveCertAuthorization, (short) 0, (short) 4, (byte) 0); Util.arrayFillNonAtomic(currentCertAuthorization, (short) 0, (short) 4, (byte) 0); Util.arrayFillNonAtomic(currentCertSubjectId, (short) 0, (short) 17, (byte) 0); Util.arrayFillNonAtomic(currentCertEffDate, (short) 0, (short) 6, (byte) 0); Util.arrayFillNonAtomic(currentCertExpDate, (short) 0, (short) 6, (byte) 0); Util.arrayFillNonAtomic(currentCertNum, (short) 0, (short) 1, (byte) 0); currentCertPublicKey.clearKey(); source[0] = null; } /** * Verify the current certificate (ie. the data in source) using the current * state of certificate verification data (publicKey, subject id, etc.) The * verification procedure is described in ISO18013-3 Section C.4.4.2. * * @return true if certificate verification succeeds */ boolean verify() { boolean result = (byte) (effectiveCertAuthorization[0] & AUTH_LEN_MASK) > 0; byte[] certData = (byte[])source[0]; short bodyLength =data[OFFSET_BODY_LENGTH]; short sigOffset =data[OFFSET_SIGNATURE_OFFSET]; short sigLength =data[OFFSET_SIGNATURE_LENGTH]; // check the actual signature signature.init(currentCertPublicKey, Signature.MODE_VERIFY); signature.update(certData, (short) 0, bodyLength); result = signature.verify(certData, bodyLength, (short) 0, certData, sigOffset, sigLength) && result; // check dates result = (compareDate(certData, data[OFFSET_EXP_DATE_OFFSET], currentDate, (short) 0) > 0) && result; short subjectIdOffset = data[OFFSET_SUB_ID_OFFSET]; short subjectIdLength = data[OFFSET_SUB_ID_LENGTH]; if((rootCertHolderReference != null && (byte)subjectIdLength == rootCertHolderReference[0] && Util.arrayCompare(rootCertHolderReference, (short)1, certData, subjectIdOffset, subjectIdLength) == 0) || (altCertHolderReference != null && (byte)subjectIdLength == altCertHolderReference[0] && Util.arrayCompare(altCertHolderReference, (short)1, certData, subjectIdOffset, subjectIdLength) == 0)){ result = false; } if (result) { setupCurrentKeyFromCurrentCertificate(); // Conditions necessary to update the current date boolean setTime = (byte) (effectiveCertAuthorization[0] & TRUST_TIME) == TRUST_TIME; setTime = setTime && compareDate(currentCertEffDate, (short)0, currentDate, (short)0) > 0; // Conditions necessary to update the current trust root certificate boolean setCert = (byte) (effectiveCertAuthorization[0] & TRUST_ROOT) == TRUST_ROOT; setCert = setCert && currentCertNum[0] == CERT_ROOT; setCert = setCert && compareDate(currentCertEffDate, (short)0, rootCertEffDate, (short) 0) > 0; // If the current root is not yet expired save it to alternate root boolean setAlt = compareDate(rootCertExpDate, (short)0, setTime ? currentCertEffDate : currentDate, (short) 0) >= 0; boolean cleanAlt = compareDate(altCertExpDate, (short)0, setTime ? currentCertEffDate : currentDate, (short) 0) < 0; if(setCert || setTime) { JCSystem.beginTransaction(); if(setCert) { if(setAlt) { Util.arrayCopy(rootCertHolderReference, (short)0, altCertHolderReference, (short)0, (short)rootCertHolderReference.length); Util.arrayCopy(rootCertPublicKeyData, (short)0, altCertPublicKeyData, (short)0, (short)rootCertPublicKeyData.length); Util.arrayCopy(rootCertEffDate, (short)0, altCertEffDate, (short)0, (short)rootCertEffDate.length); Util.arrayCopy(rootCertExpDate, (short)0, altCertExpDate, (short)0, (short)rootCertExpDate.length); Util.arrayCopy(rootCertAuthorization, (short)0, altCertAuthorization, (short)0, (short)rootCertAuthorization.length); }else if(cleanAlt) { cleanArray(altCertHolderReference); cleanArray(altCertPublicKeyData); cleanArray(altCertEffDate); cleanArray(altCertExpDate); cleanArray(altCertAuthorization); } Util.arrayCopy(currentCertSubjectId, (short)0, rootCertHolderReference, (short)0, (short)17); Util.arrayCopy(currentCertAuthorization, (short)0, rootCertAuthorization, (short)0, (short)17); Util.arrayCopy(currentCertEffDate, (short)0, rootCertEffDate, (short)0, (short)6); Util.arrayCopy(currentCertExpDate, (short)0, rootCertExpDate, (short)0, (short)6); Util.arrayCopy(rootCertHolderReference, (short)0, comFile, cvcaRootIndex, (short)rootCertHolderReference.length); Util.arrayCopy(altCertHolderReference, (short)0, comFile, cvcaAltIndex, (short)altCertHolderReference.length); currentCertPublicKey.getExponent(rootCertPublicKeyData, (short)0); currentCertPublicKey.getModulus(rootCertPublicKeyData, (short)3); } if(setTime) { Util.arrayCopy(currentCertEffDate, (short)0, currentDate, (short)0, (short)6); } // TODO copy stuff to COM file JCSystem.commitTransaction(); } if(setCert) { clear(); } } else { clear(); } return result; } /** * Sets the root certificate data * * @param in root certificate data array */ void setRootCertificate(byte[] in) { if(rootCertHolderReference != null) { // The root certificate is already initialized return; } short certHolderReferenceOffset = data[OFFSET_SUB_ID_OFFSET]; short certHolderReferenceLength = data[OFFSET_SUB_ID_LENGTH]; short pubKeyExpOffset = data[OFFSET_PUB_KEY_EXPONENT_OFFSET]; short pubKeyExpLength = data[OFFSET_PUB_KEY_EXPONENT_LENGTH]; short pubKeyModOffset = data[OFFSET_PUB_KEY_MODULUS_OFFSET]; short pubKeyModLength = data[OFFSET_PUB_KEY_MODULUS_LENGTH]; short authorizationOffset = data[OFFSET_AUTHORIZATION_OFFSET]; short effDateOffset = data[OFFSET_EFF_DATE_OFFSET]; short expDateOffset = data[OFFSET_EXP_DATE_OFFSET]; rootCertHolderReference = new byte[17]; altCertHolderReference = new byte[17]; Util.arrayCopyNonAtomic(in, certHolderReferenceOffset, rootCertHolderReference, (short)1, certHolderReferenceLength); rootCertHolderReference[0] = (byte)certHolderReferenceLength; rootCertPublicKeyData = new byte[(short)(pubKeyExpLength + pubKeyModLength)]; altCertPublicKeyData = new byte[(short)(pubKeyExpLength + pubKeyModLength)]; Util.arrayCopyNonAtomic(in, pubKeyExpOffset, rootCertPublicKeyData, (short)0, pubKeyExpLength); Util.arrayCopyNonAtomic(in, pubKeyModOffset, rootCertPublicKeyData, pubKeyExpLength, pubKeyModLength); rootCertAuthorization = new byte[4]; altCertAuthorization = new byte[4]; Util.arrayCopyNonAtomic(in, authorizationOffset, rootCertAuthorization, (short)0, (short)4); rootCertEffDate = new byte[6]; altCertEffDate = new byte[6]; Util.arrayCopyNonAtomic(in, effDateOffset, rootCertEffDate, (short)0, (short)6); rootCertExpDate = new byte[6]; altCertExpDate = new byte[6]; Util.arrayCopyNonAtomic(in, expDateOffset, rootCertExpDate, (short)0, (short)6); clear(); } /** * Parse the current certificate. The data in source/in is analyzed and * offsets and lengths of particular elements of the certificate are stored * in the data array. For the root certificate (root == true) we do not * parse the signature (we have chosen not to provide it). The format of the * certificate is described in ISO18013-3, Section C.2. * * @param in * the array with the certificate to be parsed * @param offset * offset to in * @param length * length of the data * @param root * whether we are parsing a root certificate */ void parseCertificate(byte[] in, short offset, short length, boolean root) { try { offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_CERT_BODY) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.readLength(in, offset); offset = BERTLVScanner.readTag(in, offset); offset = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_CERT_VERSION || BERTLVScanner.valueLength != (short) 1 || in[offset] != (byte) 0x00) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_AUTH_ID) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } BERTLVScanner.readLength(in, offset); offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_PUB_KEY) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.readLength(in, offset); offset = BERTLVScanner.readTag(in, offset); offset = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_OID || BERTLVScanner.valueLength != (short) 7 || Util.arrayCompare(in, offset, RSA_SHA1_OID, (short) 0, (short) 7) != 0) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_MODULUS) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } data[OFFSET_PUB_KEY_MODULUS_OFFSET] = BERTLVScanner.readLength(in, offset); data[OFFSET_PUB_KEY_MODULUS_LENGTH] = BERTLVScanner.valueLength; offset = BERTLVScanner.skipValue(); if (in[data[OFFSET_PUB_KEY_MODULUS_OFFSET]] == (byte) 0x00) { data[OFFSET_PUB_KEY_MODULUS_OFFSET]++; data[OFFSET_PUB_KEY_MODULUS_LENGTH]--; } offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_EXPONENT) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } data[OFFSET_PUB_KEY_EXPONENT_OFFSET] = BERTLVScanner.readLength(in, offset); data[OFFSET_PUB_KEY_EXPONENT_LENGTH] = BERTLVScanner.valueLength; offset = BERTLVScanner.skipValue(); if (in[data[OFFSET_PUB_KEY_EXPONENT_OFFSET]] == (byte) 0x00) { data[OFFSET_PUB_KEY_EXPONENT_OFFSET]++; data[OFFSET_PUB_KEY_EXPONENT_LENGTH]--; } offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_SUBJECT_ID) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } data[OFFSET_SUB_ID_OFFSET] = BERTLVScanner.readLength(in, offset); data[OFFSET_SUB_ID_LENGTH] = BERTLVScanner.valueLength; offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); offset = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_SUBJECT_AUTH || BERTLVScanner.valueLength != (short) 15) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.readTag(in, offset); offset = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_OID || BERTLVScanner.valueLength != (short) 7 || Util.arrayCompare(in, offset, AR_TERMINAL_OID, (short) 0, (short) 7) != 0) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); data[OFFSET_AUTHORIZATION_OFFSET] = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_AUTHORIZATION || BERTLVScanner.valueLength != (short) 4) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); data[OFFSET_EFF_DATE_OFFSET] = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_EFF_DATE || BERTLVScanner.valueLength != (short) 6) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.skipValue(); offset = BERTLVScanner.readTag(in, offset); data[OFFSET_EXP_DATE_OFFSET] = BERTLVScanner.readLength(in, offset); if (BERTLVScanner.tag != TAG_EXP_DATE || BERTLVScanner.valueLength != (short) 6) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } offset = BERTLVScanner.skipValue(); data[OFFSET_BODY_LENGTH] = offset; if (!root) { offset = BERTLVScanner.readTag(in, offset); if (BERTLVScanner.tag != TAG_SIGNATURE) { ISOException.throwIt(ISO7816.SW_WRONG_DATA); } data[OFFSET_SIGNATURE_OFFSET] = BERTLVScanner.readLength(in, offset); data[OFFSET_SIGNATURE_LENGTH] = BERTLVScanner.valueLength; source[0] = in; } } catch (Exception e) { clear(); ISOException.throwIt((short) (ISO7816.SW_WRONG_DATA)); } } boolean subjectIdSelected() { return currentCertSubjectId[0] != 0; } void selectRootHolderReference() throws ISOException { // This should never fail: if(!selectSubjectId(rootCertHolderReference, (short)1, (short)(rootCertHolderReference.length - 1))) { ISOException.throwIt(ISO7816.SW_UNKNOWN); } } RSAPublicKey getPublicKey() { return currentCertPublicKey; } byte[] getAuthorization() { return effectiveCertAuthorization; } /** * Compares two dates. * * @param date1 * the first date * @param offset1 * offset to the first date * @param date2 * the second date * @param offset2 * offset to the second date * @return -1 if the first date is before the second, 1 if it is after, 0 if * the same */ private byte compareDate(byte[] date1, short offset1, byte[] date2, short offset2) { short year1 = (short) ((short) (date1[offset1] * 10) + date1[(short) (offset1 + 1)]); short year2 = (short) ((short) (date2[offset2] * 10) + date2[(short) (offset2 + 1)]); short month1 = (short) ((short) (date1[(short) (offset1 + 2)] * 10) + date1[(short) (offset1 + 3)]); short month2 = (short) ((short) (date2[(short) (offset2 + 2)] * 10) + date2[(short) (offset2 + 3)]); short day1 = (short) ((short) (date1[(short) (offset1 + 4)] * 10) + date1[(short) (offset1 + 5)]); short day2 = (short) ((short) (date2[(short) (offset2 + 4)] * 10) + date2[(short) (offset2 + 5)]); if (year1 < year2) { return -1; } else if (year1 > year2) { return 1; } if (month1 < month2) { return -1; } else if (month1 > month2) { return 1; } if (day1 < day2) { return -1; } else if (day1 > day2) { return 1; } return 0; } // Normally this would be arrayFillNonAtomic, but this needs to // undergo a transaction treatment private static void cleanArray(byte[] array) { for(short i = 0; i<array.length; i++) { array[i] = (byte)0; } } // Same here private static void cleanArray(short[] array) { for(short i = 0; i<array.length; i++) { array[i] = (short)0; } } void setCOMFileData(byte[] file, short cvcaRootIndex, short cvcaAltIndex) { this.comFile = file; this.cvcaRootIndex = cvcaRootIndex; this.cvcaAltIndex = cvcaAltIndex; } }