diff options
| author | Andreas Fitzek <andreas.fitzek@iaik.tugraz.at> | 2014-11-18 12:50:40 +0100 | 
|---|---|---|
| committer | Andreas Fitzek <andreas.fitzek@iaik.tugraz.at> | 2014-11-18 12:50:40 +0100 | 
| commit | f6e55fe06d5512afeb1981b37df00a45f2d6d5d3 (patch) | |
| tree | 62c362c6d780f7b04431834d41851454d9684b1e /smcc/src/main | |
| parent | 42ce4de107f26807bd27dc295c0ad8ecf10bb5ac (diff) | |
| download | mocca-f6e55fe06d5512afeb1981b37df00a45f2d6d5d3.tar.gz mocca-f6e55fe06d5512afeb1981b37df00a45f2d6d5d3.tar.bz2 mocca-f6e55fe06d5512afeb1981b37df00a45f2d6d5d3.zip | |
Gemalto ID .Net extension, latest certificate selection algorithm and key Identifiers 00 - 14 for direct addressing
Diffstat (limited to 'smcc/src/main')
| -rw-r--r-- | smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java | 288 | 
1 files changed, 226 insertions, 62 deletions
| diff --git a/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java b/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java index 6a9b0393..d53f52a3 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/GemaltoNetV2_0Card.java @@ -10,6 +10,8 @@ import java.io.IOException;  import java.io.InputStream;  import java.nio.CharBuffer;  import java.nio.charset.Charset; +import java.util.regex.Matcher; +import java.util.regex.Pattern;  import java.util.zip.DataFormatException;  import java.util.zip.Inflater; @@ -30,28 +32,80 @@ import at.gv.egiz.smcc.util.MSCMService;  public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		PINMgmtSignatureCard { +	private static final String KSC_PATTERN = "ksc(\\p{XDigit}\\p{XDigit})"; +	private static final String CERT_FILE = "mscp\\ksc"; + +	private static final String CONTAINER_00 = "00"; +	private static final String CONTAINER_01 = "01"; +	private static final String CONTAINER_02 = "02"; +	private static final String CONTAINER_03 = "03"; +	private static final String CONTAINER_04 = "04"; +	private static final String CONTAINER_05 = "05"; +	private static final String CONTAINER_06 = "06"; +	private static final String CONTAINER_07 = "07"; +	private static final String CONTAINER_08 = "08"; +	private static final String CONTAINER_09 = "09"; +	private static final String CONTAINER_10 = "10"; +	private static final String CONTAINER_11 = "11"; +	private static final String CONTAINER_12 = "12"; +	private static final String CONTAINER_13 = "13"; +	private static final String CONTAINER_14 = "14"; + +	private static final KeyboxName KEYBOX_CONTAINER_00 = KeyboxName +			.getKeyboxName(CONTAINER_00); +	private static final KeyboxName KEYBOX_CONTAINER_01 = KeyboxName +			.getKeyboxName(CONTAINER_01); +	private static final KeyboxName KEYBOX_CONTAINER_02 = KeyboxName +			.getKeyboxName(CONTAINER_02); +	private static final KeyboxName KEYBOX_CONTAINER_03 = KeyboxName +			.getKeyboxName(CONTAINER_03); +	private static final KeyboxName KEYBOX_CONTAINER_04 = KeyboxName +			.getKeyboxName(CONTAINER_04); +	private static final KeyboxName KEYBOX_CONTAINER_05 = KeyboxName +			.getKeyboxName(CONTAINER_05); +	private static final KeyboxName KEYBOX_CONTAINER_06 = KeyboxName +			.getKeyboxName(CONTAINER_06); +	private static final KeyboxName KEYBOX_CONTAINER_07 = KeyboxName +			.getKeyboxName(CONTAINER_07); +	private static final KeyboxName KEYBOX_CONTAINER_08 = KeyboxName +			.getKeyboxName(CONTAINER_08); +	private static final KeyboxName KEYBOX_CONTAINER_09 = KeyboxName +			.getKeyboxName(CONTAINER_09); +	private static final KeyboxName KEYBOX_CONTAINER_10 = KeyboxName +			.getKeyboxName(CONTAINER_10); +	private static final KeyboxName KEYBOX_CONTAINER_11 = KeyboxName +			.getKeyboxName(CONTAINER_11); +	private static final KeyboxName KEYBOX_CONTAINER_12 = KeyboxName +			.getKeyboxName(CONTAINER_12); +	private static final KeyboxName KEYBOX_CONTAINER_13 = KeyboxName +			.getKeyboxName(CONTAINER_13); +	private static final KeyboxName KEYBOX_CONTAINER_14 = KeyboxName +			.getKeyboxName(CONTAINER_14); +  	private final Logger log = LoggerFactory  			.getLogger(GemaltoNetV2_0Card.class);  	PinInfo pinPinInfo;  	PinInfo pukPinInfo; -	 + +	Pattern pattern; +  	private final byte[] SHA1_PADDING = new byte[] { -			(byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, -					(byte) 0x05, (byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02, -					(byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 }; -	 +	(byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, +			(byte) 0x05, (byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02, +			(byte) 0x1A, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 }; +  	private final byte[] SHA256_PADDING = new byte[] { -			(byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06, -					(byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, -					(byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01, -					(byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20 }; +	(byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06, +			(byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, +			(byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01, +			(byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20 };  	public void init(Card card, CardTerminal cardTerminal) {  		super.init(card, cardTerminal); - +		pattern = Pattern.compile(KSC_PATTERN);  		log.info("GemaltoNetV2 card found");  		pinPinInfo = new PinInfo(4, 64, "[0-9]", @@ -62,15 +116,89 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  				"at/gv/egiz/smcc/GemaltoNetV2_0Card", "sig.puk", (byte) 2,  				new byte[] {}, 3);  	} -	 +  	public static byte[] hexStringToByteArray(String s) { -	    int len = s.length(); -	    byte[] data = new byte[len / 2]; -	    for (int i = 0; i < len; i += 2) { -	        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) -	                             + Character.digit(s.charAt(i+1), 16)); -	    } -	    return data; +		int len = s.length(); +		byte[] data = new byte[len / 2]; +		for (int i = 0; i < len; i += 2) { +			data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character +					.digit(s.charAt(i + 1), 16)); +		} +		return data; +	} + +	private int findKeyIndex() throws IOException, CardException, MSCMException { +		MSCMService service = new MSCMService(this.getCardChannel()); +		String[] files = service.getFiles("mscp"); +		int currentMax = -1; +		for (int i = 0; i < files.length; i++) { +			String fileName = files[i]; +			log.trace("Checking file: " + files[i]); +			Matcher matcher = pattern.matcher(fileName); +			if (matcher.find()) { +				if (matcher.groupCount() == 1) { +					String fidx = matcher.group(1); +					log.trace("Found idx: " + fidx); +					try { +						int curr = Integer.parseInt(fidx, 16); +						if (currentMax < curr) { +							currentMax = curr; +						} +					} catch (NumberFormatException e) { +						log.warn("Matched Regex but is no integer!", e); +					} +				} +			} +		} +		return currentMax; +	} + +	private String getCertificateFileFormIdx(int idx) { +		return String.format("%s%02x", CERT_FILE, idx); +	} + +	private int resolveKeyboxIdx(KeyboxName keyboxName) { +		if (keyboxName.equals(KEYBOX_CONTAINER_00)) { +			return 0; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_01)) { +			return 1; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_02)) { +			return 2; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_03)) { +			return 3; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_04)) { +			return 4; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_05)) { +			return 5; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_06)) { +			return 6; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_07)) { +			return 7; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_08)) { +			return 8; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_09)) { +			return 9; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_10)) { +			return 10; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_11)) { +			return 11; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_12)) { +			return 12; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_13)) { +			return 13; +		} else if (keyboxName.equals(KEYBOX_CONTAINER_14)) { +			return 14; +		} +		return -1; +	} +	 +	private String resolveKeybox(KeyboxName keyboxName) { +		int idx = resolveKeyboxIdx(keyboxName); +		if(idx < 0) { +			return null; +		} +		 +		return getCertificateFileFormIdx(idx);  	}  	@Override @@ -79,7 +207,19 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		try {  			CardChannel channel = this.getCardChannel();// this.getCard().getBasicChannel();  			MSCMService service = new MSCMService(channel); -			byte[] filecnt = service.readFile("mscp\\ksc00"); +			String certFile = resolveKeybox(keyboxName); +			 +			if(certFile == null) { +				int idx = findKeyIndex(); +				if(idx < 0) { +					throw new SignatureCardException("There is no certificate available on this token!"); +				} +				certFile = getCertificateFileFormIdx(idx); +			} +			 +			log.info("Reading certificate: " + certFile); +			 +			byte[] filecnt = service.readFile(certFile);  			Inflater inflater = new Inflater();  			inflater.setInput(filecnt, 4, filecnt.length - 4); @@ -111,8 +251,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  	@Override  	public byte[] getInfobox(String infobox, PINGUI pinGUI, String domainId)  			throws SignatureCardException, InterruptedException { -		throw new IllegalArgumentException("Infobox '" + infobox -				+ "' not supported."); +		return getCertificate(KeyboxName.getKeyboxName(infobox), pinGUI);  	}  	@Override @@ -122,15 +261,31 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		boolean sha1 = false;  		MessageDigest md; +		int ctrIdx = -1;  		try { -			if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName) -					&& (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1" -							.equals(alg))) { +			 +			ctrIdx = resolveKeyboxIdx(keyboxName); +			 +			if(ctrIdx < 0) { +				ctrIdx = findKeyIndex(); +				if(ctrIdx < 0) { +					throw new SignatureCardException("There is no private key available on this token!"); +				} +			} +			 +			if(ctrIdx > 14) { +				log.error("Key Index is bigger the maximum container available"); +				throw new SignatureCardException("There is no private key available on this token!"); +			} +			 +			log.info("Signing with key: " + ctrIdx); +			 +			if (alg == null || "http://www.w3.org/2000/09/xmldsig#rsa-sha1" +							.equals(alg)) {  				md = MessageDigest.getInstance("SHA-1");  				sha1 = true; -			} else if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName) -					&& ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" -							.equals(alg))) { +			} else if ("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" +							.equals(alg)) {  				md = MessageDigest.getInstance("SHA-256");  			} else {  				throw new SignatureCardException( @@ -140,6 +295,12 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		} catch (CryptoException e) {  			log.error("Failed to get MessageDigest.", e);  			throw new SignatureCardException(e); +		} catch (CardException e) { +			log.error("Failed to get MessageDigest.", e); +			throw new SignatureCardException(e); +		} catch (MSCMException e) { +			log.error("Failed to get MessageDigest.", e); +			throw new SignatureCardException(e);  		}  		byte[] digest = new byte[md.getDigestLength()]; @@ -156,11 +317,10 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  			MSCMService service = new MSCMService(channel);  			verifyPINLoop(channel, pinPinInfo, pinGUI); -			 +  			ByteArrayOutputStream fdata = new ByteArrayOutputStream(); -			 -			 -			if(sha1) { + +			if (sha1) {  				fdata.write(SHA1_PADDING);  			} else {  				fdata.write(SHA256_PADDING); @@ -169,7 +329,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  			fdata.close();  			byte[] msg = fdata.toByteArray();  			byte[] paded = padding.pad(msg); -			byte[] sign = service.privateKeyDecrypt((byte) 0, (byte) 2, paded); +			byte[] sign = service.privateKeyDecrypt((byte) ctrIdx, (byte) 2, paded);  			return sign;  		} catch (Throwable e) {  			log.warn("Failed to execute command.", e); @@ -177,35 +337,37 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		}  	} -	protected void unblockPINLoop(CardChannel channel, -			ModifyPINGUI provider, PinInfo pin) throws InterruptedException, CardException, SignatureCardException{ +	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);  	} -	 +  	/*  	 * Unblock PIN with PUK code  	 */ -	protected int exec_unblockPIN(CardChannel channel, ModifyPINGUI changePINGUI, PinInfo pin) +	protected int exec_unblockPIN(CardChannel channel, +			ModifyPINGUI changePINGUI, PinInfo pin)  			throws InterruptedException, CardException, SignatureCardException { -		 -		 +  		char[] oldPIN = changePINGUI.providePUK(pin, pukPinInfo,  				pukPinInfo.retries);  		char[] newPIN = changePINGUI.provideNewPIN(pin); -		 +  		byte[] ascii_pin = encodePIN(newPIN);  		MSCMService service = new MSCMService(channel); -		 +  		try {  			byte[] key = hexStringToByteArray(new String(oldPIN)); -			if(key.length != 24) { -				throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!"); +			if (key.length != 24) { +				throw new SignatureCardException( +						"Invalid ADMIN PIN (not 24 bytes long)!");  			}  			byte[] challenge = service.getChallenge();  			byte[] response = service.cryptoResponse(challenge, key); @@ -235,7 +397,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		}  	} -	 +  	protected void verifyPINLoop(CardChannel channel, PinInfo spec,  			PINGUI provider) throws InterruptedException, CardException,  			SignatureCardException { @@ -256,11 +418,12 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		char[] pin = provider.providePIN(pinInfo, pinInfo.retries);  		byte[] ascii_pin = hexStringToByteArray(new String(pin)); -		 -		if(ascii_pin.length != 24) { -			throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!"); + +		if (ascii_pin.length != 24) { +			throw new SignatureCardException( +					"Invalid ADMIN PIN (not 24 bytes long)!");  		} -		 +  		MSCMService service = new MSCMService(channel);  		try { @@ -283,7 +446,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  			throw new SignatureCardException(e);  		}  	} -	 +  	/*  	 * Verify PIN/PUK entry  	 */ @@ -303,7 +466,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		} catch (MSCMException e) {  			try {  				int tries = service.getTriesRemaining(pinInfo.getKID()); -				if(tries == 0) { +				if (tries == 0) {  					pinInfo.setBlocked();  					throw new LockedException();  				} @@ -328,7 +491,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		int retries = -1;  		do { -			if(pin.getKID() == 2) { +			if (pin.getKID() == 2) {  				retries = exec_changePUK(channel, provider, pin);  			} else {  				retries = exec_changePIN(channel, provider, pin); @@ -372,11 +535,13 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		try {  			byte[] key = hexStringToByteArray(new String(oldPIN));  			byte[] keynew = hexStringToByteArray(new String(newPIN)); -			if(key.length != 24) { -				throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!"); +			if (key.length != 24) { +				throw new SignatureCardException( +						"Invalid ADMIN PIN (not 24 bytes long)!");  			} -			if(keynew.length != 24) { -				throw new SignatureCardException("Invalid ADMIN PIN (not 24 bytes long)!"); +			if (keynew.length != 24) { +				throw new SignatureCardException( +						"Invalid ADMIN PIN (not 24 bytes long)!");  			}  			byte[] challenge = service.getChallenge();  			byte[] response = service.cryptoResponse(challenge, key); @@ -392,7 +557,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  			log.info(e.getMessage());  			try {  				int tries = service.getTriesRemaining(pin.getKID()); -				if(tries == 0) { +				if (tries == 0) {  					pin.setBlocked();  					throw new LockedException();  				} @@ -412,7 +577,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		}  	} -	 +  	/*  	 * Unblock PIN with PUK code  	 */ @@ -433,8 +598,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  		try {  			// service -> change pin -			service.changePIN((byte) 1, ascii_puk, ascii_pin, -					pin.maxRetries); +			service.changePIN((byte) 1, ascii_puk, ascii_pin, pin.maxRetries);  			pin.setActive(pin.maxRetries);  			return -1;  		} catch (IOException e) { @@ -446,7 +610,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  			log.info(e.getMessage());  			try {  				int tries = service.getTriesRemaining(pin.getKID()); -				if(tries == 0) { +				if (tries == 0) {  					pin.setBlocked();  					throw new LockedException();  				} @@ -480,10 +644,10 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  	public void verifyPIN(PinInfo pinInfo, PINGUI pinGUI)  			throws LockedException, NotActivatedException, CancelledException,  			SignatureCardException, InterruptedException { -		 +  		try {  			CardChannel channel = this.getCardChannel(); -			if(pinInfo.getKID() == 2) { +			if (pinInfo.getKID() == 2) {  				verifyPUK(channel, pinInfo, pinGUI, pinInfo.retries);  			} else {  				verifyPIN(channel, pinInfo, pinGUI, pinInfo.retries); @@ -519,7 +683,7 @@ public class GemaltoNetV2_0Card extends AbstractSignatureCard implements  	public void unblockPIN(PinInfo pinInfo, ModifyPINGUI pukGUI)  			throws CancelledException, SignatureCardException,  			InterruptedException { -		if(pinInfo.getKID() == 2) { +		if (pinInfo.getKID() == 2) {  			throw new SignatureCardException("Unable to unblock PUK");  		} else {  			CardChannel channel = getCardChannel(); | 
