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 --- .../at/gv/egiz/smcc/AbstractSignatureCard.java | 541 +-------------------- 1 file changed, 20 insertions(+), 521 deletions(-) (limited to 'smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java') diff --git a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java index f0f8b8c8..54b4c7fe 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -1,55 +1,37 @@ -//Copyright (C) 2002 IAIK -//http://jce.iaik.at -// -//Copyright (C) 2003 Stiftung Secure Information and -// Communication Technologies SIC -//http://www.sic.st -// -//All rights reserved. -// -//This source is provided for inspection purposes and recompilation only, -//unless specified differently in a contract with IAIK. This source has to -//be kept in strict confidence and must not be disclosed to any third party -//under any circumstances. Redistribution in source and binary forms, with -//or without modification, are permitted in any case! -// -//THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -//IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -//ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -//FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -//DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -//OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -//HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -//LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -//OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -//SUCH DAMAGE. -// -// +/* +* 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; -import at.gv.egiz.smcc.ccid.CCID; -import at.gv.egiz.smcc.ccid.ReaderFactory; -import at.gv.egiz.smcc.util.SMCCHelper; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.ResourceBundle; -import javax.smartcardio.ATR; import javax.smartcardio.Card; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CardTerminal; -import javax.smartcardio.CommandAPDU; -import javax.smartcardio.ResponseAPDU; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import at.gv.egiz.smcc.ccid.CCID; +import at.gv.egiz.smcc.ccid.ReaderFactory; + public abstract class AbstractSignatureCard implements SignatureCard { private static Log log = LogFactory.getLog(AbstractSignatureCard.class); @@ -61,14 +43,8 @@ public abstract class AbstractSignatureCard implements SignatureCard { private Locale locale = Locale.getDefault(); - int ifs_ = 254; - private Card card_; - /** - * The card terminal that connects the {@link #card_}. - */ -// private CardTerminal cardTerminal; protected CCID reader; protected AbstractSignatureCard(String resourceBundleName) { @@ -89,379 +65,10 @@ public abstract class AbstractSignatureCard implements SignatureCard { return sb.toString(); } - /** - * Select an application using AID as DF name according to ISO/IEC 7816-4 - * section 8.2.2.2. - * - * @param dfName - * AID of the application to be selected - * - * @return the response data of the response APDU if SW=0x9000 - * - * @throws CardException - * if card communication fails - * - * @throws SignatureCardException - * if application selection fails (e.g. an application with the - * given AID is not present on the card) - */ - protected byte[] selectFileAID(byte[] dfName) throws CardException, SignatureCardException { - CardChannel channel = getCardChannel(); - ResponseAPDU resp = transmit(channel, - new CommandAPDU(0x00, 0xA4, 0x04, 0x00, dfName, 256)); -// new CommandAPDU(0x00, 0xa4, 0x04, 0x0c, dfName)); - if (resp.getSW() != 0x9000) { - String msg = "Failed to select application AID=" + SMCCHelper.toString(dfName) + - ": SW=" + Integer.toHexString(resp.getSW()); - log.error(msg); - throw new SignatureCardException(msg); - } else { - return resp.getBytes(); - } - } - - protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException, - SignatureCardException; - - /** - * VERIFY APDU without PIN BLOCK - * Not supported by ACOS cards (and GemPC Pinpad?) - * @param kid - * @return the number of possible tries until card is blocked or -1 if unknown - * (ACOS does not support this VERIFY APDU type) - * @throws at.gv.egiz.smcc.LockedException - * @throws at.gv.egiz.smcc.NotActivatedException - * @throws at.gv.egiz.smcc.SignatureCardException - */ - protected abstract int verifyPIN(byte kid) - throws LockedException, NotActivatedException, SignatureCardException; - - /** - * VERIFY APDU with PIN BLOCK - * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. - * @param kid - * @param pin to be encoded in the PIN BLOCK - * @return -1 if VERIFY PIN was successful, or the number of possible retries - * @throws at.gv.egiz.smcc.LockedException - * @throws at.gv.egiz.smcc.NotActivatedException - * @throws at.gv.egiz.smcc.SignatureCardException - */ - protected abstract int verifyPIN(byte kid, char[] pin) - throws LockedException, NotActivatedException, CancelledException, PINFormatException, TimeoutException, PINOperationAbortedException, SignatureCardException; - - /** - * CHANGE(?) APDU - * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. - * @param kid - * @param pin - * @throws at.gv.egiz.smcc.SignatureCardException if activation fails - */ - protected abstract void activatePIN(byte kid, char[] pin) - throws CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException; - - /** - * CHANGE(?) APDU - * If IFD supports VERIFY_PIN on pinpad, parameter pin may be empty. - * @param kid - * @param pin - * @return -1 if CHANGE PIN was successful, or the number of possible retries - * @throws at.gv.egiz.smcc.SignatureCardException if change fails - */ - protected abstract int changePIN(byte kid, char[] oldPin, char[] newPin) - throws LockedException, NotActivatedException, CancelledException, PINFormatException, PINConfirmationException, TimeoutException, PINOperationAbortedException, SignatureCardException; - - /** - * encode the pin as needed in VERIFY/CHANGE APDUs - * @param pin - * @return - * @throws at.gv.egiz.smcc.SignatureCardException if the provided pin does - * not meet the restrictions imposed by the encoding (not the pinSpec!), - * such as maximum Length - */ - protected abstract byte[] encodePINBlock(char[] pin) throws SignatureCardException; - - protected byte[] readRecord(int recordNumber) throws SignatureCardException, CardException { - return readRecord(getCardChannel(), recordNumber); - } - - protected byte[] readRecord(CardChannel channel, int recordNumber) throws SignatureCardException, CardException { - - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB2, - recordNumber, 0x04, 256)); - if (resp.getSW() == 0x9000) { - return resp.getData(); - } else { - throw new SignatureCardException("Failed to read records. SW=" + Integer.toHexString(resp.getSW())); - } - - } - - protected byte[] readBinary(CardChannel channel, int offset, int len) - throws CardException, SignatureCardException { - - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB0, - 0x7F & (offset >> 8), offset & 0xFF, len)); - if (resp.getSW() == 0x9000) { - return resp.getData(); - } else if (resp.getSW() == 0x6982) { - throw new SecurityStatusNotSatisfiedException(); - } else { - throw new SignatureCardException("Failed to read bytes (" + offset + "+" - + len + "): SW=" + Integer.toHexString(resp.getSW())); - } - - } - - protected int readBinary(int offset, int len, byte[] b) throws CardException, - SignatureCardException { - - if (b.length < len) { - throw new IllegalArgumentException( - "Length of b must not be less than len."); - } - - CardChannel channel = getCardChannel(); - - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB0, - 0x7F & (offset >> 8), offset & 0xFF, len)); - if (resp.getSW() == 0x9000) { - System.arraycopy(resp.getData(), 0, b, 0, len); - } - - return resp.getSW(); - - } - - protected byte[] readBinaryTLV(int maxSize, byte expectedType) throws CardException, - SignatureCardException { - - CardChannel channel = getCardChannel(); - - // read first chunk - int len = Math.min(maxSize, ifs_); - byte[] chunk = readBinary(channel, 0, len); - if (chunk.length > 0 && chunk[0] != expectedType) { - return null; - } - int offset = chunk.length; - int actualSize = maxSize; - if (chunk.length > 3) { - if ((chunk[1] & 0x80) > 0) { - int octets = (0x0F & chunk[1]); - actualSize = 2 + octets; - for (int i = 1; i <= octets; i++) { - actualSize += (0xFF & chunk[i + 1]) << ((octets - i) * 8); - } - } else { - actualSize = 2 + chunk[1]; - } - } - ByteBuffer buffer = ByteBuffer.allocate(actualSize); - buffer.put(chunk, 0, Math.min(actualSize, chunk.length)); - while (offset < actualSize) { - len = Math.min(ifs_, actualSize - offset); - chunk = readBinary(channel, offset, len); - buffer.put(chunk); - offset += chunk.length; - } - return buffer.array(); - - } - - protected byte[] readRecords(byte[] aid, byte[] ef, int start, int end) throws SignatureCardException, InterruptedException { - - try { - - // SELECT FILE (AID) - byte[] rb = selectFileAID(aid); - if (rb[rb.length - 2] != (byte) 0x90 || rb[rb.length - 1] != (byte) 0x00) { - - throw new SignatureCardException("SELECT FILE with " - + "AID=" - + toString(aid) - + " failed (" - + "SW=" - + Integer.toHexString((0xFF & (int) rb[rb.length - 1]) - | (0xFF & (int) rb[rb.length - 2]) << 8) + ")."); - - } - - // SELECT FILE (EF) - ResponseAPDU resp = selectFileFID(ef); - if (resp.getSW() == 0x6a82) { - - // EF not found - throw new FileNotFoundException("EF " + toString(ef) + " not found."); - - } else if (resp.getSW() != 0x9000) { - - throw new SignatureCardException("SELECT FILE with " - + "FID=" - + toString(ef) - + " failed (" - + "SW=" - + Integer.toHexString(resp.getSW()) + ")."); - - } - - ByteArrayOutputStream bytes = new ByteArrayOutputStream(); - - for (int i = start; i <= end; i++) { - bytes.write(readRecord(i)); - } - - return bytes.toByteArray(); - - } catch (CardException e) { - throw new SignatureCardException("Failed to acces card.", e); - } catch (IOException e) { - throw new SignatureCardException("Failed to read records.", e); - } - - } - - /** - * Read the content of a TLV file. - * - * @param aid the application ID (AID) - * @param ef the elementary file (EF) - * @param maxLength the maximum length of the file - * - * @return the content of the file - * - * @throws SignatureCardException - * @throws CardException - */ - protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength) - throws SignatureCardException, InterruptedException, CardException { - // SELECT FILE (AID) - selectFileAID(aid); - - // SELECT FILE (EF) - ResponseAPDU resp = selectFileFID(ef); - if (resp.getSW() == 0x6a82) { - // EF not found - throw new FileNotFoundException("EF " + toString(ef) + " not found."); - } else if (resp.getSW() != 0x9000) { - throw new SignatureCardException("SELECT FILE with " - + "FID=" - + toString(ef) - + " failed (" - + "SW=" - + Integer.toHexString(resp.getSW()) + ")."); - } - - return readBinaryTLV(maxLength, (byte) 0x30); -// return readTLVFile(aid, ef, null, (byte) 0, maxLength); - } - - /** - * Read the content of a TLV file wich requires a PIN. - * - * @param aid the application ID (AID) - * @param ef the elementary file (EF) - * @param kid the key ID (KID) of the corresponding PIN - * @param pin the pin or null if VERIFY on pinpad - * @param spec the PINSpec - * @param maxLength the maximum length of the file - * - * @return the content of the file - * - * @throws SignatureCardException - * @throws CardException - */ - protected byte[] readTLVFile(byte[] aid, byte[] ef, char[] pin, byte kid, int maxLength) - throws SignatureCardException, InterruptedException, CardException { - - - // SELECT FILE (AID) - selectFileAID(aid); - - // SELECT FILE (EF) - ResponseAPDU resp = selectFileFID(ef); - if (resp.getSW() == 0x6a82) { - // EF not found - throw new FileNotFoundException("EF " + toString(ef) + " not found."); - } else if (resp.getSW() != 0x9000) { - throw new SignatureCardException("SELECT FILE with " - + "FID=" - + toString(ef) - + " failed (" - + "SW=" - + Integer.toHexString(resp.getSW()) + ")."); - } - - // VERIFY - int retries = verifyPIN(kid, pin); - if (retries != -1) { - throw new VerificationFailedException(retries); - } - - return readBinaryTLV(maxLength, (byte) 0x30); - - - } - - /** - * Transmit the given command APDU using the given card channel. - * - * @param channel - * the card channel - * @param commandAPDU - * the command APDU - * @param logData - * true if command APDU data may be logged, or - * false otherwise - * - * @return the corresponding response APDU - * - * @throws CardException - * if smart card communication fails - */ - protected ResponseAPDU transmit(CardChannel channel, CommandAPDU commandAPDU, boolean logData) - throws CardException { - - if (log.isTraceEnabled()) { - log.trace(commandAPDU - + (logData ? "\n" + toString(commandAPDU.getBytes()) : "")); - long t0 = System.currentTimeMillis(); - ResponseAPDU responseAPDU = channel.transmit(commandAPDU); - long t1 = System.currentTimeMillis(); - log.trace(responseAPDU + "\n[" + (t1 - t0) + "ms] " - + (logData ? "\n" + toString(responseAPDU.getBytes()) : "")); - return responseAPDU; - } else { - return channel.transmit(commandAPDU); - } - - } - - /** - * Transmit the given command APDU using the given card channel. - * - * @param channel the card channel - * @param commandAPDU the command APDU - * - * @return the corresponding response APDU - * - * @throws CardException if smart card communication fails - */ - protected ResponseAPDU transmit(CardChannel channel, CommandAPDU commandAPDU) - throws CardException { - return transmit(channel, commandAPDU, true); - } - - @Override public void init(Card card, CardTerminal cardTerminal) { this.card_ = card; this.reader = ReaderFactory.getInstance().getReader(card, cardTerminal); - ATR atr = card.getATR(); - byte[] atrBytes = atr.getBytes(); - if (atrBytes.length >= 6) { - ifs_ = 0xFF & atr.getBytes()[6]; - log.trace("Setting IFS (information field size) to " + ifs_); - } } @Override @@ -470,7 +77,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { } protected CardChannel getCardChannel() { - return card_.getBasicChannel(); + return new LogCardChannel(card_.getBasicChannel()); } @Override @@ -517,112 +124,4 @@ public abstract class AbstractSignatureCard implements SignatureCard { } } - @Override - public List getPINSpecs() { - return pinSpecs; - } - - @Override - public void verifyPIN(PINSpec pinSpec, PINProvider pinProvider) - throws LockedException, NotActivatedException, CancelledException, TimeoutException, SignatureCardException, InterruptedException { - try { - getCard().beginExclusive(); - - if (pinSpec.getContextAID() != null) { - selectFileAID(pinSpec.getContextAID()); - } - - // -1 if ok or unknown - int retries = verifyPIN(pinSpec.getKID()); - do { - char[] pin = pinProvider.providePIN(pinSpec, retries); - retries = verifyPIN(pinSpec.getKID(), pin); - } while (retries > 0); - //return on -1, 0 never reached: verifyPIN throws LockedEx - - } catch (CardException ex) { - log.error("failed to verify " + pinSpec.getLocalizedName() + - ": " + ex.getMessage(), ex); - throw new SignatureCardException(ex); - } finally { - try { - getCard().endExclusive(); - } catch (CardException ex) { - log.trace("failed to end exclusive card access: " + ex.getMessage()); - } - } - } - - @Override - public void activatePIN(PINSpec pinSpec, PINProvider pinProvider) - throws CancelledException, SignatureCardException, CancelledException, TimeoutException, InterruptedException { - try { - getCard().beginExclusive(); - - if (pinSpec.getContextAID() != null) { - selectFileAID(pinSpec.getContextAID()); - } - char[] pin = pinProvider.providePIN(pinSpec, -1); - activatePIN(pinSpec.getKID(), pin); - - } catch (CardException ex) { - log.error("Failed to activate " + pinSpec.getLocalizedName() + - ": " + ex.getMessage()); - throw new SignatureCardException(ex.getMessage(), ex); - } finally { - try { - getCard().endExclusive(); - } catch (CardException ex) { - log.trace("failed to end exclusive card access: " + ex.getMessage()); - } - } - } - - /** - * activates pin (newPIN) if not active - * @param pinSpec - * @param oldPIN - * @param newPIN - * @throws at.gv.egiz.smcc.LockedException - * @throws at.gv.egiz.smcc.VerificationFailedException - * @throws at.gv.egiz.smcc.NotActivatedException - * @throws at.gv.egiz.smcc.SignatureCardException - */ - @Override - public void changePIN(PINSpec pinSpec, ChangePINProvider pinProvider) - throws LockedException, NotActivatedException, CancelledException, - TimeoutException, SignatureCardException, InterruptedException { - try { - getCard().beginExclusive(); - - if (pinSpec.getContextAID() != null) { - selectFileAID(pinSpec.getContextAID()); - } - - int retries = verifyPIN(pinSpec.getKID()); - do { - char[] newPin = pinProvider.providePIN(pinSpec, retries); - char[] oldPin = pinProvider.provideOldPIN(pinSpec, retries); - retries = changePIN(pinSpec.getKID(), oldPin, newPin); - } while (retries > 0); - //return on -1, 0 never reached: verifyPIN throws LockedEx - - } catch (CardException ex) { - log.error("Failed to change " + pinSpec.getLocalizedName() + - ": " + ex.getMessage()); - throw new SignatureCardException(ex.getMessage(), ex); - } finally { - try { - getCard().endExclusive(); - } catch (CardException ex) { - log.trace("failed to end exclusive card access: " + ex.getMessage()); - } - } - } - - @Override - public void unblockPIN(PINSpec pinSpec, PINProvider pinProvider) - throws CancelledException, SignatureCardException, InterruptedException { - throw new SignatureCardException("Unblock not supported yet"); - } } -- cgit v1.2.3