diff options
| author | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2011-02-01 14:55:29 +0000 | 
|---|---|---|
| committer | clemenso <clemenso@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2011-02-01 14:55:29 +0000 | 
| commit | f68975abc55b53a56ef80e1e7efe2e7f77aa2c22 (patch) | |
| tree | 9de7f36eda948f61470530a9cf056fba902d8a05 /smccTest/src/main/java/at | |
| parent | 58ebbe700d922af33b79886f715ee302fb62c523 (diff) | |
| download | mocca-f68975abc55b53a56ef80e1e7efe2e7f77aa2c22.tar.gz mocca-f68975abc55b53a56ef80e1e7efe2e7f77aa2c22.tar.bz2 mocca-f68975abc55b53a56ef80e1e7efe2e7f77aa2c22.zip | |
Authentication case 1b/2/3b/4
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@897 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
Diffstat (limited to 'smccTest/src/main/java/at')
| -rw-r--r-- | smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java | 225 | 
1 files changed, 110 insertions, 115 deletions
| diff --git a/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java b/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java index 0590dac2..f8f679e2 100644 --- a/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java +++ b/smccTest/src/main/java/at/gv/egiz/smcc/activation/SecureChannel.java @@ -91,30 +91,23 @@ public class SecureChannel extends CardChannel {  		try {  			if (apdu.length < 4) {  				throw new IllegalArgumentException("invalid Command APDU " + toString(apdu)); -			} else if (apdu.length == 4) { -				CommandAPDU capdu_ = new CommandAPDU(protectCase1b(apdu)); +			} else if (apdu.length < 6) { +				CommandAPDU capdu_ = new CommandAPDU( +								protectNoCommandData(apdu, apdu.length == 5));  				log.info("cmd apdu*: {}", toString(capdu_.getBytes()));  				ResponseAPDU resp_ = channel.transmit(capdu_);  				log.info(" -> resp*: {}", toString(resp_.getBytes())); -				return unProtectCase1b(resp_); -			} else if (apdu.length == 5) { -				CommandAPDU capdu_ = new CommandAPDU(protectCase2(apdu)); +				return unProtectResponse(resp_); + +			} else { +				CommandAPDU capdu_ = new CommandAPDU( +								protectCommandData(apdu, apdu.length > 5+apdu[4]));  				log.info("cmd apdu*: {}", toString(capdu_.getBytes()));  				ResponseAPDU resp_ = channel.transmit(capdu_);  				log.info(" -> resp*: {}", toString(resp_.getBytes())); -				return unProtectCase2(resp_); - -			} else if (apdu.length == 5 + apdu[4]) { -				// CLA|INS|P1|P2|Lc|Data    -> CLA'|INS|P1|P2|Lc'|TLplain|TLmac -				// 81 (plain value) 8e (cryptographic checksum) -			} else { -				// CLA|INS|P1|P2|Lc|Data|Le -> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00 -				// 81 (plain value) 97 (Ne) 8e (cryptographic checksum) -				// TODO extended APDUs +				return unProtectResponse(resp_); +				  			} - -			throw new UnsupportedOperationException("not implemented"); -			  		} catch (Exception ex) {  			System.out.println("failed to transmit protected APDU: " + ex.getMessage());  			throw new CardException(ex); @@ -132,36 +125,46 @@ public class SecureChannel extends CardChannel {  	}  	/** -	 * Case 1 of command-response pair defined in ISO 7816-3 -	 * no command data, no response data, status not protected +	 * Case 1b/2 of command-response pair defined in ISO 7816-3 +	 * no command data, response data +	 * +	 * CLA|INS|P1|P2    -> CLA'|INS|P1|P2|Lc'|TLmac|00 +	 * CLA|INS|P1|P2|Le -> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00  	 * -	 * CLA|INS|P1|P2 -> CLA'|INS|P1|P2|Lc'|TLmac  	 * @param apdu  	 * @return  	 * @throws GeneralSecurityException mac-calculation error  	 */ -	byte[] protectCase1b(byte[] apdu) throws GeneralSecurityException { +	byte[] protectNoCommandData(byte[] apdu, boolean responseData) throws GeneralSecurityException { -		byte[] apdu_ = new byte[16]; - -		// authenticate header: CLA* b3=1 -		apdu_[0] = (byte) (apdu[0] | (byte) 0x0c); // CLA*: b8-6=000 b4-3=11 +		int leLength = (responseData) ? 1 : 0; +		 +		byte[] apdu_ = new byte[16 + 3*leLength]; +		// authenticate header: CLA** b3=1 +		apdu_[0] = (byte) (apdu[0] | (byte) 0x0c); //CLA**: b8-6=000 b4-3=11  		apdu_[1] = apdu[1];  		apdu_[2] = apdu[2];  		apdu_[3] = apdu[3]; -		// Lc': TLmac -		apdu_[4] = (byte) (blocksize + 2); //0x0a; +		// Lc': [TLle] TLmac +		apdu_[4] = (byte) (3*leLength + 2 + blocksize); //0x0a or 0x0d; + +		// T*L Le +		if (responseData) { +			apdu_[5] = (byte) 0x97; +			apdu_[6] = (byte) 0x01; +			apdu_[7] = apdu[4]; +		}  		// cryptographic checksum -		apdu_[5] = (byte) 0x8e; -		apdu_[6] = (byte) blocksize; //0x08; +		apdu_[5 + 3*leLength] = (byte) 0x8e; +		apdu_[6 + 3*leLength] = (byte) blocksize; //0x08; -		// Le' (case 1b) -		apdu_[7 + blocksize] = 0x00; +		// Le' +		apdu_[apdu_.length-1] = 0x00; -		// 2 data objects: SSC, header -		byte[] mac_in = new byte[2 * blocksize]; +		// 3 data objects: SSC, header, Le +		byte[] mac_in = new byte[2*blocksize + blocksize*leLength];  		// SSC (rightmost blocksize bytes)  		incrementSSC(); @@ -171,32 +174,49 @@ public class SecureChannel extends CardChannel {  		byte[] paddedHeader = RetailCBCMac.pad(Arrays.copyOf(apdu_, 4), blocksize);  		System.arraycopy(paddedHeader, 0, mac_in, blocksize, blocksize); -		byte[] mac = RetailCBCMac.retailMac(mac_in, RetailCBCMac.PADDING.NoPadding, +		// TL Le +		if (responseData) { +			byte[] paddedTLLe = RetailCBCMac.pad(Arrays.copyOfRange(apdu_, 5, 8), blocksize); +			System.arraycopy(paddedTLLe, 0, mac_in, 2*blocksize, blocksize); +		} + +		byte[] mac = RetailCBCMac.retailMac(mac_in, RetailCBCMac.PADDING.NoPadding,   						"DES", "DESede", kmac, blocksize, blocksize);  		log.debug("cryptographic checksum ({}): {}", toString(mac_in), toString(mac));  		// insert mac in 8E object -		System.arraycopy(mac, 0, apdu_, 7, blocksize); +		System.arraycopy(mac, 0, apdu_, 7+3*leLength, blocksize);  		return apdu_;  	} -	ResponseAPDU unProtectCase1b(ResponseAPDU resp_) throws GeneralSecurityException, CardException { - -		if (resp_.getSW() == 0x9000) { +	/** +	 * Verify cryptographic checksum for cases 1b/2/3b/4 and decode response apdu +	 * +	 * T*Lsw1sw2 | TLcc            -> sw1sw2 +	 * T*Lplain | T*Lsw1sw2 | TLcc -> plain | sw1sw2 +	 * +	 * @param resp_ +	 * @return +	 * @throws GeneralSecurityException +	 * @throws CardException +	 */ +	ResponseAPDU unProtectResponse(ResponseAPDU resp_) throws GeneralSecurityException, CardException { -			byte[] respData = resp_.getData(); +		byte[] respData = resp_.getData(); -			// T*Lsw1sw2 | TLcc (CC size == blocksize) +		if (respData != null && respData.length > 0) { +			 +			int TLccInd = respData.length - (2 + blocksize); -			byte[] mac_in = new byte[blocksize + 4]; +			byte[] mac_in = new byte[respData.length - 2]; //+blocksize-blocksize -			// SSC +			// SSC (rightmost blocksize bytes)  			incrementSSC();  			System.arraycopy(kmacssc, kmacssc.length-blocksize, mac_in, 0, blocksize);  			// data -			System.arraycopy(respData, 0, resp_, blocksize, 4); +			System.arraycopy(respData, 0, mac_in, blocksize, TLccInd);  			byte[] mac_ = RetailCBCMac.retailMac(mac_in, RetailCBCMac.PADDING.ISO9797_2,  							"DES", "DESede", kmac, blocksize, blocksize); @@ -215,7 +235,15 @@ public class SecureChannel extends CardChannel {  				throw new CardException("invalid status-word object " + toString(sw));  			} -			return new ResponseAPDU(sw); +			byte[] plain = respSeq.getValue(0x81); +			if (plain != null) { +				byte[] resp = new byte[plain.length + 2]; +				System.arraycopy(plain, 0, resp, 0, plain.length); +				System.arraycopy(sw, 0, resp, plain.length, 2); +				return new ResponseAPDU(resp); +			} else { +				return new ResponseAPDU(sw); +			}  		}  		log.info("unexpected response " + toString(resp_.getBytes())); @@ -223,41 +251,57 @@ public class SecureChannel extends CardChannel {  	}  	/** -	 * Case 2 of command-response pair defined in ISO 7816-3 -	 * no command data, response data -	 * -	 * CLA|INS|P1|P2|Le -> CLA'|INS|P1|P2|Lc'|TLle|TLmac|00 +	 * Case 3b/4 of command-response pair defined in ISO 7816-3 +	 * command data, no response data  	 * +	 * CLA|INS|P1|P2|Lc|Data -> CLA'|INS|P1|P2|Lc'|TLplain|TLmac|00 +	 * CLA|INS|P1|P2|Lc|Data|Le -> CLA'|INS|P1|P2|Lc'|TLplain|TLle|TLmac|00 +	 *   	 * @param apdu  	 * @return  	 * @throws GeneralSecurityException mac-calculation error  	 */ -	byte[] protectCase2(byte[] apdu) throws GeneralSecurityException { +	byte[] protectCommandData(byte[] apdu, boolean responseData) throws GeneralSecurityException { + +		int leLength = (responseData) ? 1 : 0; + +		// header | Lc' | TLplain | [TLLe] | TLmac | 00 +		byte[] apdu_= new byte[4 + 1 + 2+apdu[4] + 3*leLength + 2+blocksize + 1]; -		byte[] apdu_ = new byte[19];  		// authenticate header: CLA** b3=1  		apdu_[0] = (byte) (apdu[0] | (byte) 0x0c); //CLA**: b8-6=000 b4-3=11  		apdu_[1] = apdu[1];  		apdu_[2] = apdu[2];  		apdu_[3] = apdu[3]; -		// Lc': TLle TLmac -		apdu_[4] = (byte) (blocksize + 2 + 3); //0x0d; +		// Lc': TLplain [TLLe] TLmac +		apdu_[4] = (byte) (2+apdu[4] + 3*leLength +  2+blocksize); -		// Ne -		apdu_[5] = (byte) 0x97; -		apdu_[6] = (byte) 0x01; -		apdu_[7] = apdu[4]; +		// T*L plain +		apdu_[5] = (byte) 0x81; +		apdu_[6] = apdu[4]; +		System.arraycopy(apdu, 5, apdu_, 7, apdu[4]); -		// cryptographic checksum -		apdu_[8] = (byte) 0x8e; -		apdu_[9] = (byte) blocksize; //0x08; +		// T*L Le +		if (responseData) { +			apdu_[7+apdu[4]] = (byte) 0x97; +			apdu_[8+apdu[4]] = (byte) 0x01; +			apdu_[9+apdu[4]] = apdu[apdu.length-1]; +		} -		// Le' -		apdu_[10 + blocksize] = 0x00; +		// TL cc +		apdu_[7 + apdu[4] + 3*leLength] = (byte) 0x8e; +		apdu_[8 + apdu[4] + 3*leLength] = (byte) blocksize; //0x08; -		// 3 data objects: SSC, header, Le -		byte[] mac_in = new byte[3 * blocksize]; +		apdu_[apdu_.length-1] = (byte) 0x00; + +		// TLplain [TLLe] Padding +		byte[] paddedPlainLe = RetailCBCMac.pad( +						Arrays.copyOfRange(apdu_, 5, 5+2+apdu[4] + 3*leLength), blocksize); +		log.trace("padded plain command data: " + toString(paddedPlainLe)); + +		// 3 blocks: SSC, header|padding, TLplain[TLLe]|padding +		byte[] mac_in = new byte[2*blocksize + paddedPlainLe.length];  		// SSC (rightmost blocksize bytes)  		incrementSSC(); @@ -267,67 +311,18 @@ public class SecureChannel extends CardChannel {  		byte[] paddedHeader = RetailCBCMac.pad(Arrays.copyOf(apdu_, 4), blocksize);  		System.arraycopy(paddedHeader, 0, mac_in, blocksize, blocksize); -		// TL Le -		byte[] paddedTLLe = RetailCBCMac.pad(Arrays.copyOfRange(apdu_, 5, 8), blocksize); -		System.arraycopy(paddedTLLe, 0, mac_in, 2*blocksize, blocksize); +		System.arraycopy(paddedPlainLe, 0, mac_in, 2*blocksize, paddedPlainLe.length); -		byte[] mac = RetailCBCMac.retailMac(mac_in, RetailCBCMac.PADDING.NoPadding,  +		byte[] mac = RetailCBCMac.retailMac(mac_in, RetailCBCMac.PADDING.NoPadding,  						"DES", "DESede", kmac, blocksize, blocksize);  		log.debug("cryptographic checksum ({}): {}", toString(mac_in), toString(mac));  		// insert mac in 8E object -		System.arraycopy(mac, 0, apdu_, 10, blocksize); +		System.arraycopy(mac, 0, apdu_, 9 + apdu[4] + 3*leLength, blocksize);  		return apdu_;  	} -	ResponseAPDU unProtectCase2(ResponseAPDU resp_) throws GeneralSecurityException, CardException { - -		if (resp_.getSW() == 0x9000) { - -			byte[] respData = resp_.getData(); - -			// T*Lplain | T*Lsw1sw2 | TLcc (CC size == blocksize) - -			int TLccInd = respData.length - 2 - blocksize; - -			byte[] mac_in = new byte[respData.length - 2]; //+blocksize-blocksize - -			// SSC (rightmost blocksize bytes) -			incrementSSC(); -			System.arraycopy(kmacssc, kmacssc.length-blocksize, mac_in, 0, blocksize); - -			// data -			System.arraycopy(respData, 0, mac_in, blocksize, TLccInd); -			 -			byte[] mac_ = RetailCBCMac.retailMac(mac_in, RetailCBCMac.PADDING.ISO9797_2, -							"DES", "DESede", kmac, blocksize, blocksize); - -			log.debug("cryptographic checksum ({}): {}", toString(mac_in), toString(mac_)); - -			TLVSequence respSeq = new TLVSequence(respData); - -			byte[] cc = respSeq.getValue(0x8e); -			if (!Arrays.equals(mac_, cc)) { -				throw new CardException("invalid cryptographic checksum " + toString(cc)); -			} - -			byte[] sw = respSeq.getValue(0x99); -			if (sw[0] != (byte) 0x90 || sw[1] != (byte) 0x00) { -				throw new CardException("invalid status-word object " + toString(sw)); -			} - -			byte[] plain = respSeq.getValue(0x81); -			byte[] resp = new byte[plain.length + 2]; -			System.arraycopy(plain, 0, resp, 0, plain.length); -			resp[resp.length - 2] = (byte) 0x90; -			resp[resp.length - 1] = (byte) 0x00; -			return new ResponseAPDU(resp); -		} - -		log.info("unexpected response " + toString(resp_.getBytes())); -		return resp_; -	}  	void incrementSSC() {  		//TODO | 
