diff options
Diffstat (limited to 'smcc/src/main/java')
3 files changed, 302 insertions, 179 deletions
| diff --git a/smcc/src/main/java/at/gv/egiz/smcc/CypriotEID.java b/smcc/src/main/java/at/gv/egiz/smcc/CypriotEID.java index 35556049..c1695278 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/CypriotEID.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/CypriotEID.java @@ -26,6 +26,7 @@ package at.gv.egiz.smcc;  import iaik.me.asn1.*;  import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream;  import java.io.IOException;  import java.io.InputStream;  import java.io.OutputStream; @@ -34,6 +35,7 @@ import java.nio.CharBuffer;  import java.nio.charset.Charset;  import java.security.MessageDigest;  import java.security.NoSuchAlgorithmException; +import java.util.Iterator;  import javax.smartcardio.Card;  import javax.smartcardio.CardChannel; @@ -51,6 +53,8 @@ import at.gv.egiz.smcc.pin.gui.ModifyPINGUI;  import at.gv.egiz.smcc.pin.gui.PINGUI;  import at.gv.egiz.smcc.util.ISO7816Utils;  import at.gv.egiz.smcc.util.SMCCHelper; +import at.gv.egiz.smcc.util.TLV; +import at.gv.egiz.smcc.util.TLVSequence;  import at.gv.egiz.smcc.util.TransparentFileInputStream;  public class CypriotEID extends AbstractSignatureCard implements @@ -63,7 +67,7 @@ public class CypriotEID extends AbstractSignatureCard implements  	public static final byte KID_PIN_SIG = (byte) 0x01;  	public static final byte[] CD_ID = new byte[] { (byte) 0x70, (byte) 0x05 }; -	 +  	public static final byte[] MF_ID = new byte[] { (byte) 0x3f, (byte) 0x00 };  	public static final byte[] ADF_AWP_ID = new byte[] { (byte) 0xad, @@ -79,32 +83,32 @@ public class CypriotEID extends AbstractSignatureCard implements  	ObjectDirectory od;  	protected byte[] cert_id; -	 +  	@Override  	public void init(Card card, CardTerminal cardTerminal) {  		super.init(card, cardTerminal);  		log.info("Cypriot EID found"); -		pinPinInfo = new PinInfo(4, 8, "[0-9]", "at/gv/egiz/smcc/CypriotEID", +		pinPinInfo = new PinInfo(4, 64, "[0-9]", "at/gv/egiz/smcc/CypriotEID",  				"sig.pin", KID_PIN_SIG, AID_SIG, 3); -		//pinPinInfo.setActive(3); -		 -		pukPinInfo = new PinInfo(4, 8, "[0-9]", "at/gv/egiz/smcc/CypriotEID", +		// pinPinInfo.setActive(3); + +		pukPinInfo = new PinInfo(4, 64, "[0-9]", "at/gv/egiz/smcc/CypriotEID",  				"sig.puk", KID_PUK_SIG, AID_SIG, 3); -		 +  		try {  			this.exec_readcd(getCardChannel());  		} catch (CardException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +			log.warn("Failed to read the certificate ID", e); +			cert_id = null;  		} catch (SignatureCardException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +			log.warn("Failed to read the certificate ID", e); +			cert_id = null;  		} catch (IOException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +			log.warn("Failed to read the certificate ID", e); +			cert_id = null;  		}  	} @@ -116,14 +120,14 @@ public class CypriotEID extends AbstractSignatureCard implements  		try {  			return exec_readcert(channel);  		} catch (CardException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +			log.info("Failed to get the certificate.", e); +			throw new SignatureCardException("Failed to get the certificate.", +					e);  		} catch (IOException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +			log.info("Failed to get the certificate.", e); +			throw new SignatureCardException("Failed to get the certificate.", +					e);  		} -		 -		return null;  	}  	@Override @@ -137,58 +141,92 @@ public class CypriotEID extends AbstractSignatureCard implements  	public byte[] createSignature(InputStream input, KeyboxName keyboxName,  			PINGUI pinGUI, String alg) throws SignatureCardException,  			InterruptedException, IOException { -		 +  		byte AlgID = 0; -	     -	    MessageDigest md; -	    try { -	      if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName) -	          && (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1".equals(alg))) { -	    	  AlgID = (byte) 0x12; // SHA-1 with padding according to PKCS#1 block type 01 -	        md = MessageDigest.getInstance("SHA-1"); -	      } else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName) -	          && "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256".equals(alg)) { -	    	  AlgID = (byte) 0x41; // SHA-256 with padding according to PKCS#1 -	        md = MessageDigest.getInstance("SHA256"); -	      }  else { -	        throw new SignatureCardException("Card does not support signature algorithm " + alg + "."); -	      } -	    } catch (NoSuchAlgorithmException e) { -	      log.error("Failed to get MessageDigest.", e); -	      throw new SignatureCardException(e); -	    } -	     -	    byte[] digest = new byte[md.getDigestLength()]; -	    for (int l; (l = input.read(digest)) != -1;) { -	      md.update(digest, 0, l); -	    } -	    digest = md.digest(); -	     -	    try -	    { -	    	CardChannel channel = getCardChannel(); - -	        // SELECT application -	        exec_selectADF(channel); -	         -	        // MANAGE SECURITY ENVIRONMENT : SET DST -	        exec_MSE(channel, AlgID); -	        // VERIFY -	        verifyPINLoop(channel, pinPinInfo, pinGUI); -	         -	        // PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE -	        return exec_sign(channel, digest); -	    } -	    catch (Exception e) { -	    	e.printStackTrace(); -	    	return null; + +		MessageDigest md; +		try { +			if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName) +					&& (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1" +							.equals(alg))) { +				AlgID = (byte) 0x12; // SHA-1 with padding according to PKCS#1 +										// block type 01 +				md = MessageDigest.getInstance("SHA-1"); +			} else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName) +					&& "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" +							.equals(alg)) { +				AlgID = (byte) 0x41; // SHA-256 with padding according to PKCS#1 +				md = MessageDigest.getInstance("SHA256"); +			} else { +				throw new SignatureCardException( +						"Card does not support signature algorithm " + alg +								+ "."); +			} +		} catch (NoSuchAlgorithmException e) { +			log.error("Failed to get MessageDigest.", e); +			throw new SignatureCardException(e); +		} + +		byte[] digest = new byte[md.getDigestLength()]; +		for (int l; (l = input.read(digest)) != -1;) { +			md.update(digest, 0, l);  		} +		digest = md.digest(); + +		CardChannel channel = getCardChannel(); + +		try { +			try { +				// SELECT application +				exec_selectADF(channel); + +				// MANAGE SECURITY ENVIRONMENT : SET DST +				exec_MSE(channel, AlgID); + +				// PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE +				return exec_sign(channel, digest); +			} catch (SecurityStatusNotSatisfiedException e) { +				// NEED to provide PIN code ... + +				// SELECT application +				exec_selectADF(channel); + +				// MANAGE SECURITY ENVIRONMENT : SET DST +				exec_MSE(channel, AlgID); + +				// VERIFY +				verifyPINLoop(channel, pinPinInfo, pinGUI); + +				// PERFORM SECURITY OPERATION : COMPUTE DIGITAL SIGNATRE +				return exec_sign(channel, digest); +			} +		} catch (CardException e) { +			log.info("Failed to create digital signature", e); +			throw new SignatureCardException("Failed to create digital signature", e); +		} +  	}  	@Override  	public PinInfo[] getPinInfos() throws SignatureCardException { -		// TODO Auto-generated method stub -		return new PinInfo[] { pinPinInfo }; +		PinInfo[] pinInfos = new PinInfo[] { pinPinInfo, pukPinInfo }; +		 +		CardChannel channel = getCardChannel(); +		for (PinInfo pinInfo : pinInfos) { +		      if (pinInfo.getState() == PinInfo.STATE.UNKNOWN ) { +		        try { +		          log.debug("Query pin status for {}.", pinInfo.getLocalizedName()); +		          testPIN(channel, pinInfo); +		        } catch (Exception e) { +		          log.trace("Failed to execute command.", e); +		          // status already set by verifyPIN +		        } +		      } else if (log.isTraceEnabled()) { +		        log.trace("assume pin status {} to be up to date", pinInfo.getState()); +		      } +		    } +		 +		return pinInfos;  	}  	@Override @@ -209,12 +247,23 @@ public class CypriotEID extends AbstractSignatureCard implements  	}  	@Override +	  public String toString() { +	    return ("Oberthur Thechnologies ID-ONE Token SLIM"); +	  } +	 +	@Override  	public void changePIN(PinInfo pinInfo, ModifyPINGUI changePINGUI)  			throws LockedException, NotActivatedException, CancelledException,  			PINFormatException, SignatureCardException, InterruptedException { +		  		CardChannel channel = getCardChannel(); -		exec_unblockPIN(channel, changePINGUI); +		try { +			unblockPINLoop(channel, changePINGUI, pinInfo); +		} catch (CardException e) { +			log.info("Failed to change PIN.", e); +			throw new SignatureCardException("Failed to change PIN.", e); +		}  	}  	@Override @@ -222,7 +271,8 @@ public class CypriotEID extends AbstractSignatureCard implements  			throws CancelledException, SignatureCardException,  			InterruptedException {  		log.error("ACTIVATE PIN not supported by Cypriotic EID"); -	    throw new SignatureCardException("PIN activation not supported by this card."); +		throw new SignatureCardException( +				"PIN activation not supported by this card.");  	}  	@Override @@ -231,7 +281,12 @@ public class CypriotEID extends AbstractSignatureCard implements  			InterruptedException {  		CardChannel channel = getCardChannel(); -		exec_unblockPIN(channel, pukGUI); +		try { +			unblockPINLoop(channel, pukGUI, pinInfo); +		} catch (CardException e) { +			log.info("Failed to unblock PIN.", e); +			throw new SignatureCardException("Failed to unblock PIN.", e); +		}  	}  	// ////////////////////////////////////////////////////////////////////// @@ -248,16 +303,28 @@ public class CypriotEID extends AbstractSignatureCard implements  		} while (retries > 0);  	} +	protected void unblockPINLoop(CardChannel channel, +			ModifyPINGUI provider, PinInfo pin) throws InterruptedException, CardException, SignatureCardException{ + +		int retries = -1; +		do { +			retries = exec_unblockPIN(channel, provider, pin); +		} while (retries > 0); +	} +	 +	/* +	 * Verify PIN/PUK entry +	 */  	protected int verifyPIN(CardChannel channel, PinInfo pinInfo,  			PINGUI provider, int retries) throws InterruptedException,  			CardException, SignatureCardException {  		char[] pin = provider.providePIN(pinInfo, pinInfo.retries); -		 +  		byte[] ascii_pin = encodePIN(pin);  		exec_selectADF(channel); -		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00,  +		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00,  				pinInfo.getKID(), ascii_pin));  		if (resp.getSW() == 0x9000) { @@ -284,99 +351,149 @@ public class CypriotEID extends AbstractSignatureCard implements  		}  	} +	 +	protected int testPIN(CardChannel channel, PinInfo pinInfo) throws InterruptedException, +			CardException, SignatureCardException { + +		exec_selectADF(channel); + +		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, +				pinInfo.getKID())); + +		if (resp.getSW() == 0x9000) { +			pinInfo.setActive(pinInfo.maxRetries); +			return -1; +		} +		if (resp.getSW() >> 4 == 0x63c) { +			pinInfo.setActive(0x0f & resp.getSW()); +			return 0x0f & resp.getSW(); +		} + +		switch (resp.getSW()) { +		case 0x6983: +			// authentication method blocked +			pinInfo.setBlocked(); +			throw new LockedException(); + +		default: +			String msg = "VERIFY failed. SW=" +					+ Integer.toHexString(resp.getSW()); +			log.info(msg); +			pinInfo.setUnknown(); +			throw new SignatureCardException(msg); +		} + +	} -	private byte[] encodePIN(char[] pin) -	{ -		return  Charset.forName("ASCII").encode( -				CharBuffer.wrap(pin)).array(); +	private byte[] encodePIN(char[] pin) { +		return Charset.forName("ASCII").encode(CharBuffer.wrap(pin)).array();  	} -	 -	protected void exec_unblockPIN(CardChannel channel, ModifyPINGUI changePINGUI) throws CancelledException, InterruptedException -	{ -		char[] PUK = changePINGUI.provideCurrentPIN(pukPinInfo, pukPinInfo.retries); -		char[] newPIN = changePINGUI.provideNewPIN(pinPinInfo); + +	/* +	 * Unblock PIN with PUK code +	 */ +	protected int exec_unblockPIN(CardChannel channel, ModifyPINGUI changePINGUI, PinInfo pin) +			throws InterruptedException, CardException, SignatureCardException { -		byte[] ascii_puk = encodePIN(PUK); -		byte[] ascii_pin = encodePIN(newPIN); +		char[] PUK = changePINGUI.providePUK(pin, pukPinInfo, +				pukPinInfo.retries); -		try { -			log.debug("PUK: " + new String(PUK) + "(" + getHexString(ascii_puk) + ") NEW PIN: " +  -			new String(newPIN) + "(" + getHexString(ascii_pin) + ")"); -		} catch (Exception e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); -		} +		char[] newPIN = changePINGUI.provideNewPIN(pin); -		// TODO: INPUT checking PIN SIZES etc. -		/* -		try { -			exec_selectADF(channel); +		byte[] ascii_puk = encodePIN(PUK); -			ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00,  -					pukPinInfo.getKID(), ascii_puk)); -			 -			if (resp.getSW() == 0x9000) { -				pukPinInfo.setActive(pukPinInfo.maxRetries); -			} -			else -			{ -				log.debug("WRONG PUK CODE!! SW=" + resp.getSW()); -				return; -			} -			 -			resp = channel.transmit(new CommandAPDU(0x00, 0x2C, 0x02,  -					pinPinInfo.getKID(), ascii_pin)); -			 -			if (resp.getSW() == 0x9000) { -				pinPinInfo.setActive(pinPinInfo.maxRetries); -			} -			else -			{ -				log.debug("FAILED TO SET PIN! SW=" + resp.getSW()); -			} -			 -		} catch (CardException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); -		} catch (SignatureCardException e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); +		byte[] ascii_pin = encodePIN(newPIN); + +		exec_selectADF(channel); + +		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x20, 0x00, +				pukPinInfo.getKID(), ascii_puk)); + +		if (resp.getSW() == 0x9000) { +			pukPinInfo.setActive(pukPinInfo.maxRetries); +		} else if (resp.getSW() >> 4 == 0x63c) { +			pukPinInfo.setActive(0x0f & resp.getSW()); +			return 0x0f & resp.getSW(); +		} else if (resp.getSW() == 0x6983) { +			// authentication method blocked +			pukPinInfo.setBlocked(); +			throw new LockedException(); +		} else { +			String msg = "VERIFY failed. SW=" +					+ Integer.toHexString(resp.getSW()); +			log.info(msg); +			pukPinInfo.setUnknown(); +			throw new SignatureCardException(msg); +		} + +		resp = channel.transmit(new CommandAPDU(0x00, 0x2C, 0x02, pin +				.getKID(), ascii_pin)); + +		if (resp.getSW() == 0x9000) { +			pin.setActive(pin.maxRetries); +			return -1; +		} else { +			String msg = "SET PIN failed. SW=" +					+ Integer.toHexString(resp.getSW()); +			log.info(msg); +			pin.setUnknown(); +			throw new SignatureCardException(msg);  		} -		*/ +  	} -	 + +	/* +	 * Read certificate based on certificate ID +	 */  	protected byte[] exec_readcert(CardChannel channel) throws CardException, -	SignatureCardException, IOException { -		if(cert_id == null) -		{ +			SignatureCardException, IOException { +		if (cert_id == null) {  			exec_readcd(channel);  		} -		 -		/*if(cert_id == null) -		{ -			throw CardException("Failed to read the certificate id"); -		}*/ -		 + +		if (cert_id == null) { +			throw new CardException("Failed to read the certificate id"); +		} +  		exec_selectADF(channel);  		exec_selectFILE(channel, cert_id); -		 +  		return exec_readBinary(channel);  	} -	 + +	/* +	 * Read and parse CD file to determine certificate ID +	 */  	protected void exec_readcd(CardChannel channel) throws CardException, -		SignatureCardException, IOException -	{ +			SignatureCardException, IOException {  		exec_selectADF(channel);  		exec_selectFILE(channel, CD_ID); -		 +  		byte[] cd_buffer = exec_readBinary(channel); -		 -		// TODO interpret CD => get CERT ID -		 -		cert_id = new byte[] { (byte) 0x34, (byte) 0x01 }; + +		ASN1 asn = new ASN1(cd_buffer); + +		for (int i = 0; i < asn.getSize(); i++) { + +			ASN1 element = asn.getElementAt(i); + +			if (element.getTagClass() == ASN1.TAG_CONTEXT_SPECIFIC +					&& element.getTypeOnly() == ASN1.TYPE_BOOLEAN) { +				ASN1 ele = element.gvASN1().getElementAt(0).getElementAt(0); +				if (ele.getTypeOnly() == ASN1.TYPE_OCTET_STRING) { +					cert_id = ele.gvByteArray(); +					return; +				} +			} +		} +		cert_id = null; +		throw new CardException("Failed to read the certificate ID.");  	} -	 + +	/* +	 * Select the ADF application +	 */  	protected void exec_selectADF(CardChannel channel) throws CardException,  			SignatureCardException { @@ -385,8 +502,9 @@ public class CypriotEID extends AbstractSignatureCard implements  	} -	 -	 +	/* +	 * Select a file in the current context by its id +	 */  	protected byte[] exec_selectFILE(CardChannel channel, byte[] file_id)  			throws CardException, SignatureCardException {  		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xA4, 0x01, @@ -403,23 +521,43 @@ public class CypriotEID extends AbstractSignatureCard implements  		return resp.getBytes();  	} -	protected void exec_MSE(CardChannel channel, byte algoID) throws CardException -	{ -		byte[] secure_setup = new byte[] { (byte) 0x80, (byte) 0x01, algoID, // Algorithm setup +	/* +	 * Setup Manage Security Environment (MSE) for cryptographic signatur !fixed +	 * key id +	 */ +	protected void exec_MSE(CardChannel channel, byte algoID) +			throws CardException { +		byte[] secure_setup = new byte[] { (byte) 0x80, (byte) 0x01, algoID, // Algorithm +																				// setup  				(byte) 0x84, (byte) 0x01, (byte) 0x81 }; // Key setup -		 -		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x22, -				0x41, 0xB6, secure_setup)); + +		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x22, 0x41, +				0xB6, secure_setup));  	} -	 -	protected byte[] exec_sign(CardChannel channel, byte[] hash) throws CardException -	{ -		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x2A, -				0x9E, 0x9A, hash)); -		 -		return resp.getData(); + +	/* +	 * Execute signature command +	 */ +	protected byte[] exec_sign(CardChannel channel, byte[] hash) +			throws CardException, SignatureCardException { +		ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0x2A, 0x9E, +				0x9A, hash)); + +		if (resp.getSW() == 0x6982) { +			throw new SecurityStatusNotSatisfiedException(); +		} +		if (resp.getSW() != 0x9000) { +			throw new SignatureCardException( +					"PSO - COMPUTE DIGITAL SIGNATRE failed: SW=" +							+ Integer.toHexString(resp.getSW())); +		} else { +			return resp.getData(); +		}  	} +	/* +	 * Read current binary information +	 */  	protected byte[] exec_readBinary(CardChannel channel) throws CardException,  			IOException, SignatureCardException {  		ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -428,8 +566,8 @@ public class CypriotEID extends AbstractSignatureCard implements  		int offset = 0;  		do { -			int offset_lo = offset % 0xFF; -			int offset_hi = offset / 0xFF; +			int offset_lo = (byte) offset; +			int offset_hi = (byte) (offset >> 8);  			ResponseAPDU resp = channel.transmit(new CommandAPDU(0x00, 0xB0,  					offset_hi, offset_lo, 0x00)); @@ -451,26 +589,8 @@ public class CypriotEID extends AbstractSignatureCard implements  		} while (repeat);  		byte[] buf = buffer.toByteArray(); -		 -		log.debug("BINARY READ: "); -		 -		try { -			log.debug(getHexString(buf)); -		} catch (Exception e) { -			// TODO Auto-generated catch block -			e.printStackTrace(); -		} -		 +  		return buf;  	} -	 -	 -	public static String getHexString(byte[] b) throws Exception { -		  String result = ""; -		  for (int i=0; i < b.length; i++) { -		    result += ":" + -		          Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); -		  } -		  return result; -		} +  } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java index c06c3296..1f0f5c4c 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/LogCardChannel.java @@ -69,6 +69,7 @@ public class LogCardChannel extends CardChannel {        switch (command.getINS()) {        case 0x20:    // VERIFY        case 0x21:    // VERIFY +      case 0x2C:	// RESET RETRY COUNTER         case 0x24: {  // CHANGE REFERENCE DATA          // Don't log possibly sensitive command data          StringBuilder sb = new StringBuilder(); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java index 5a29e6ce..2d1ec970 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/pin/gui/ModifyPINProvider.java @@ -53,4 +53,6 @@ public interface ModifyPINProvider {    public char[] provideNewPIN(PinInfo pinInfo)            throws CancelledException, InterruptedException; +  public char[] providePUK(PinInfo pinInfo, PinInfo pukInfo, int retries) +		  throws CancelledException, InterruptedException;  } | 
