From 6cb4a071eab9a3b8cf78b8ec7e407aa148f2d038 Mon Sep 17 00:00:00 2001 From: mcentner Date: Wed, 1 Jul 2009 13:03:41 +0000 Subject: Major refactoring of SMCC git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@381 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../egiz/smcc/starcos/STARCOSCardChannelEmul.java | 375 +++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java (limited to 'smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java') diff --git a/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java new file mode 100644 index 00000000..89030894 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/starcos/STARCOSCardChannelEmul.java @@ -0,0 +1,375 @@ +/* +* Copyright 2008 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.smcc.starcos; + +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.HashMap; + +import javax.smartcardio.Card; +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import at.gv.egiz.smcc.AbstractAppl; +import at.gv.egiz.smcc.CardChannelEmul; +import at.gv.egiz.smcc.CardEmul; +import at.gv.egiz.smcc.File; +import at.gv.egiz.smcc.PIN; + +@SuppressWarnings("restriction") +public class STARCOSCardChannelEmul extends CardChannelEmul { + + public static final int KID_PIN_Glob = 0x01; + + /** + * + */ + protected CardEmul cardEmul; + + public final HashMap globalPins = new HashMap(); + + public STARCOSCardChannelEmul(CardEmul cardEmul) { + this.cardEmul = cardEmul; + globalPins.put(KID_PIN_Glob, new PIN(new byte[] { (byte) 0x24, (byte) 0x00, + (byte) 0x00, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF }, KID_PIN_Glob, 10)); + } + + @Override + public Card getCard() { + return cardEmul; + } + + protected ResponseAPDU cmdSELECT(CommandAPDU command) throws CardException { + + byte[] fid = command.getData(); + + switch (command.getP1()) { + case 0x00: // MF + if (fid.length !=0) { + return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x80}); + } else { + currentFile = null; + currentAppl = null; + return new ResponseAPDU(new byte[] {(byte) 0x90, (byte) 0x00}); + } + + case 0x01: // Lower-level DF + throw new CardException("Not supported."); + + case 0x02: // EF in current DF + if (currentAppl != null) { + if (command.getP2() != 0x04) { + throw new CardException("Not supported."); + } + for (File file : currentAppl.getFiles()) { + if (Arrays.equals(fid, file.fid)) { + currentFile = file; + byte[] response = new byte[file.fcx.length + 2]; + System.arraycopy(file.fcx, 0, response, 0, file.fcx.length); + response[file.fcx.length] = (byte) 0x90; + response[file.fcx.length + 1] = (byte) 0x00; + return new ResponseAPDU(response); + } + } + return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x82}); + } else { + throw new CardException("Not supported."); + } + + case 0x03: // Higher-level DF + throw new CardException("Not supported."); + + case 0x04: // Selection by DF name + AbstractAppl appl = cardEmul.getApplication(fid); + if (appl != null) { + if (command.getP2() != 0x00) { + throw new CardException("Not supported."); + } + if (currentAppl != null && currentAppl != appl) { + currentAppl.leaveApplContext(); + currentFile = null; + } + currentAppl = appl; + + byte[] fci = currentAppl.getFCI(); + byte[] response = new byte[fci.length + 2]; + System.arraycopy(fci, 0, response, 0, fci.length); + response[fci.length] = (byte) 0x90; + response[fci.length + 1] = (byte) 0x00; + return new ResponseAPDU(response); + } + + default: + return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x86}); + } + + } + + protected ResponseAPDU cmdREAD_BINARY(CommandAPDU command) throws CardException { + + if (command.getINS() != 0xB0) { + throw new IllegalArgumentException("INS has to be 0xB0."); + } + + if (currentFile == null) { + return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x86}); + } + + if ((command.getP1() & 0x80) > 0) { + throw new CardException("Not implemented."); + } + + int offset = command.getP2() + (command.getP1() << 8); + if (offset > currentFile.file.length) { + // Wrong length + return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00}); + } + + if (command.getNe() == 0) { + throw new CardException("Not implemented."); + } + + if (currentFile.kid != -1) { + PIN pin; + if ((currentFile.kid & 0x80) > 0) { + if (currentAppl == null + || (pin = currentAppl.pins.get(currentFile.kid)) == null + || pin.state != PIN.STATE_PIN_VERIFIED) { + return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82}); + } + } else { + if ((pin = globalPins.get(currentFile.kid)) == null + || pin.state != PIN.STATE_PIN_VERIFIED) { + return new ResponseAPDU(new byte[] {(byte) 0x69, (byte) 0x82}); + } + } + } + + if (command.getNe() == 256 || command.getNe() <= currentFile.file.length - offset) { + int len = Math.min(command.getNe(), currentFile.file.length - offset); + byte[] response = new byte[len + 2]; + System.arraycopy(currentFile.file, offset, response, 0, len); + response[len] = (byte) 0x90; + response[len + 1] = (byte) 0x00; + return new ResponseAPDU(response); + } else if (command.getNe() >= currentFile.file.length - offset) { + return new ResponseAPDU(new byte[] {(byte) 0x62, (byte) 0x82}); + } else { + return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00}); + } + + } + + + @Override + public ResponseAPDU transmit(CommandAPDU command) throws CardException { + + if (command.getCLA() == 0x00) { + + switch (command.getINS()) { + + // SELECT + case 0xA4: + return cmdSELECT(command); + + // READ BINARY + case 0xB0: + return cmdREAD_BINARY(command); + + // VERIFY + case 0x20: + return cmdVERIFY(command); + + // MANAGE SECURITY ENVIRONMENT + case 0x22: { + if (currentAppl != null) { + return currentAppl.cmdMANAGE_SECURITY_ENVIRONMENT(command, this); + } else { + return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05}); + } + } + + // CHANGE REFERENCE DATA + case 0x24: { + return cmdCHANGE_REFERENCE_DATA(command); + } + + // PERFORM SECURITY OPERATION + case 0x2A: { + if (currentAppl != null) { + return currentAppl.cmdPERFORM_SECURITY_OPERATION(command, this); + } else { + return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05}); + } + } + + // INTERNAL AUTHENTICATE + case 0x88: { + if (currentAppl != null) { + return currentAppl.cmdINTERNAL_AUTHENTICATE(command, this); + } else { + return new ResponseAPDU(new byte[] {(byte) 0x6F, (byte) 0x05}); + } + } + + default: + return new ResponseAPDU(new byte[] { (byte) 0x6D, (byte) 0x00}); + } + + } else { + return new ResponseAPDU(new byte[] { (byte) 0x6E, (byte) 0x00}); + } + + } + + protected ResponseAPDU verifyPin(int kid, byte[] reference) { + + PIN pin; + if ((kid & 0x80) > 0 && currentAppl != null) { + pin = currentAppl.pins.get(kid); + } else { + pin = globalPins.get(kid); + } + + if (pin != null) { + + if (reference.length == 0) { + return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)}); + } + + if (reference.length != 8) { + return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00}); + } + + if (Arrays.equals(reference, pin.pin)) { + switch (pin.state) { + case PIN.STATE_PIN_BLOCKED: + return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 }); + + case PIN.STATE_RESET: + pin.state = PIN.STATE_PIN_VERIFIED; + + default: + pin.kfpc = 10; + return new ResponseAPDU(new byte[] { (byte) 0x90, (byte) 0x00 }); + } + } else { + switch (pin.state) { + case PIN.STATE_PIN_BLOCKED: + return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 }); + + default: + if (--pin.kfpc > 0) { + return new ResponseAPDU(new byte[] { (byte) 0x63, (byte) (pin.kfpc | 0xC0)}); + } else { + pin.state = PIN.STATE_PIN_BLOCKED; + return new ResponseAPDU(new byte[] { (byte) 0x69, (byte) 0x83 }); + } + } + + } + + } else { + return new ResponseAPDU(new byte[] {(byte) 0x6A, (byte) 0x00}); + } + + } + + protected ResponseAPDU cmdVERIFY(CommandAPDU command) throws CardException { + + if (command.getINS() != 0x20) { + throw new IllegalArgumentException("INS has to be 0x20."); + } + + if (command.getP1() != 00) { + return new ResponseAPDU(new byte[] {(byte) 0x6B, (byte) 0x00}); + } + + return verifyPin(command.getP2(), command.getData()); + + } + + protected ResponseAPDU cmdCHANGE_REFERENCE_DATA(CommandAPDU command) { + + if (command.getINS() != 0x24) { + throw new IllegalArgumentException("INS has to be 0x24."); + } + + byte[] data = command.getData(); + + ResponseAPDU response; + + if (command.getP1() == 0x01) { + + if (data.length != 8) { + return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00}); + } + + response = verifyPin(0xFF & command.getP2(), data); + + } else if (command.getP1() == 0x00) { + + if (data.length != 16) { + return new ResponseAPDU(new byte[] {(byte) 0x67, (byte) 0x00}); + } + + response = verifyPin(0xFF & command.getP2(), Arrays.copyOf(data, 8)); + + } else { + return new ResponseAPDU(new byte[] { (byte) 0x6A, (byte) 0x81 }); + } + + if (response.getSW() == 0x9000) { + PIN pin; + if (currentAppl != null) { + pin = currentAppl.pins.get(command.getP2()); + } else { + pin = globalPins.get(command.getP2()); + } + pin.pin = Arrays.copyOfRange(data, 8, 16); + } + + return response; + + } + + public void setPin(int kid, char[] value) { + PIN pin = globalPins.get(kid); + if (pin != null) { + if (value == null) { + pin.pin = null; + } else { + byte[] b = new byte[8]; + b[0] = (byte) (0x20 | value.length); + for(int i = 1, j = 0; i < b.length; i++) { + int h = ((j < value.length) + ? Character.digit(value[j++], 10) + : 0x0F); + int l = ((j < value.length) + ? Character.digit(value[j++], 10) + : 0x0F); + b[i] = (byte) ((h << 4) | l); + } + pin.pin = b; + } + } + } + + +} \ No newline at end of file -- cgit v1.2.3