diff options
25 files changed, 1149 insertions, 389 deletions
diff --git a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java index 8ae9d7a3..2054ae86 100644 --- a/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java +++ b/BKUCommonGUI/src/main/java/at/gv/egiz/bku/gui/PinDocument.java @@ -46,7 +46,7 @@ class PINDocument extends PlainDocument { @Override public void insertString(int offs, String str, AttributeSet a) throws BadLocationException { - if (pinSpec.getMaxLength() >= (getLength() + str.length())) { + if (pinSpec.getMaxLength() < 0 || pinSpec.getMaxLength() >= (getLength() + str.length())) { boolean matches = true; for (int i = 0; i < str.length(); i++) { Matcher m = pinPattern.matcher(str.substring(i, i + 1)); diff --git a/BKUOnline/src/main/java/at/gv/egiz/bku/online/webapp/BKURequestHandler.java b/BKUOnline/src/main/java/at/gv/egiz/bku/online/webapp/BKURequestHandler.java index 6f3b9d7f..9092e3f9 100644 --- a/BKUOnline/src/main/java/at/gv/egiz/bku/online/webapp/BKURequestHandler.java +++ b/BKUOnline/src/main/java/at/gv/egiz/bku/online/webapp/BKURequestHandler.java @@ -44,6 +44,8 @@ import at.gv.egiz.org.apache.tomcat.util.http.AcceptLanguage; */ public class BKURequestHandler extends SpringBKUServlet { + private static final long serialVersionUID = 1L; + public final static String REDIRECT_URL = "appletPage.jsp"; protected Log log = LogFactory.getLog(BKURequestHandler.class); @@ -105,6 +107,8 @@ public class BKURequestHandler extends SpringBKUServlet { String width = getStringFromStream(bindingProcessor.getFormData("appletWidth"), charset); String height = getStringFromStream(bindingProcessor.getFormData("appletHeight"), charset); String background = getStringFromStream(bindingProcessor.getFormData("appletBackground"), charset); + String guiStyle = getStringFromStream(bindingProcessor.getFormData("appletGuiStyle"), charset); + String hashDataDisplay = getStringFromStream(bindingProcessor.getFormData("appletHashDataDisplay"), charset); if (width != null) { try { log.trace("Found applet width parameter: " + width); @@ -124,12 +128,16 @@ public class BKURequestHandler extends SpringBKUServlet { } } if (background != null) { - try { - log.trace("Found applet background parameter: " + background); - session.setAttribute("appletBackground", background); - } catch (NumberFormatException nfe) { - log.warn(nfe); - } + log.trace("Found applet background parameter: " + background); + session.setAttribute("appletBackground", background); + } + if (guiStyle != null) { + log.trace("Found applet GUI style parameter: " + guiStyle); + session.setAttribute("appletGuiStyle", guiStyle); + } + if (hashDataDisplay != null) { + log.trace("Found applet hash data display parameter: " + hashDataDisplay); + session.setAttribute("appletHashDataDisplay", hashDataDisplay); } resp.sendRedirect(REDIRECT_URL); diff --git a/BKUOnline/src/main/webapp/HTTP-ohne.html b/BKUOnline/src/main/webapp/HTTP-ohne.html index 1923113e..044432ce 100644 --- a/BKUOnline/src/main/webapp/HTTP-ohne.html +++ b/BKUOnline/src/main/webapp/HTTP-ohne.html @@ -92,8 +92,17 @@ legend { name="appletHeight" value="130" id="appletHeight"> <p><label for="appletBackground">Applet Background</label> <input name="appletBackground" value="" id="appletBackground"> +<p> + <label for="appletGuiStyle">GUI Style</label> + <input type="radio" name="appletGuiStyle" value="simple" checked="checked">simple + <input type="radio" name="appletGuiStyle" value="advanced">advanced +</p> +<p> + <label for="appletHashDataDisplay">GUI Style</label> + <input type="radio" name="appletHashDataDisplay" value="external" checked="checked">external + <input type="radio" name="appletHashDataDisplay" value="internal">internal +</p> -</textarea></p> <!-- <p><label for="RedirectURL">RedirectURL</label> <input name="RedirectURL" value="" id="RedirectURL"></p> diff --git a/BKUOnline/src/main/webapp/appletPage.jsp b/BKUOnline/src/main/webapp/appletPage.jsp index 950141c4..ffb67828 100644 --- a/BKUOnline/src/main/webapp/appletPage.jsp +++ b/BKUOnline/src/main/webapp/appletPage.jsp @@ -20,7 +20,7 @@ <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> -<title>MOCCA Appletpage</title> +<title>MOCCA Applet</title> <link rel="shortcut icon" href="img/favicon.ico" type="image/x-icon"> <script type="text/javascript" src="js/deployJava.js"></script> <META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE"> @@ -29,19 +29,18 @@ </head> <body> <% - int width = session.getAttribute("appletWidth") == null - ? 190 - : (Integer) session.getAttribute("appletWidth"); - int height = session.getAttribute("appletHeight") == null - ? 130 - : (Integer) session.getAttribute("appletHeight"); - String backgroundImg = (String) session - .getAttribute("appletBackground"); + int width = session.getAttribute("appletWidth") == null ? 190 + : (Integer) session.getAttribute("appletWidth"); + int height = session.getAttribute("appletHeight") == null ? 130 + : (Integer) session.getAttribute("appletHeight"); + String backgroundImg = (String) session.getAttribute("appletBackground"); + String guiStyle = (String) session.getAttribute("appletGuiStyle"); + String hashDataDisplay = (String) session.getAttribute("appletHashDataDisplay"); %> <script> if (!deployJava.versionCheck('1.6.0_04+')) { document - .write('<b>Diese Anwendung benötigt die Java Platform Version 1.6.0 oder höher.</b>' + '<input type="submit" value="Java Platform 1.6.0_02 installieren" onclick="deployJava.installLatestJRE();">'); + .write('<b>Diese Anwendung benötigt die Java Platform Version 1.6.0_04 oder höher.</b>' + '<input type="submit" value="Java Platform 1.6.0_02 installieren" onclick="deployJava.installLatestJRE();">'); } else { var attributes = { codebase :'applet', @@ -51,15 +50,15 @@ height :<%=height%> }; var parameters = { - GuiStyle : 'simple', + GuiStyle : '<%=guiStyle%>', Background : '<%=backgroundImg%>', - WSDL_URL :'../stal?wsdl', - HashDataDisplay : 'external', - HashDataURL : '../hashDataInput', + WSDL_URL : '../stal?wsdl', + HashDataDisplay : '<%=hashDataDisplay%>', + HashDataURL : '../hashDataInput', SessionID : '<%=session.getId()%>', RedirectURL : '../bkuResult' }; - var version = '1.6.0_02'; + var version = '1.6.0_04'; deployJava.runApplet(attributes, parameters, version); } </script> diff --git a/STAL/src/main/java/at/gv/egiz/stal/util/JCEAlgorithmNames.java b/STAL/src/main/java/at/gv/egiz/stal/util/JCEAlgorithmNames.java index 7e8a767e..c162eed4 100644 --- a/STAL/src/main/java/at/gv/egiz/stal/util/JCEAlgorithmNames.java +++ b/STAL/src/main/java/at/gv/egiz/stal/util/JCEAlgorithmNames.java @@ -31,7 +31,7 @@ public class JCEAlgorithmNames { public static String[] SHA_1_ALGORITMS = {
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1",
- "http://www.w3.org/2000/09/xmldsig#sha1" };
+ "http://www.w3.org/2000/09/xmldsig#rsa-sha1" };
private static JCEAlgorithmNames instance = new JCEAlgorithmNames();
@@ -42,7 +42,7 @@ public class JCEAlgorithmNames { }
public static String getJCEHashName(String xmlAlgorithmURI) {
- return instance.hashNameMap.get(xmlAlgorithmURI);
+ return instance.hashNameMap.get(xmlAlgorithmURI);
}
public void registerHash(String xmlAlgorithmURI, String jceName) {
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java index 5e44e82b..4a22874c 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/binding/HTTPBindingProcessor.java @@ -564,6 +564,7 @@ public class HTTPBindingProcessor extends AbstractBindingProcessor implements SLCommandContext commandCtx = new SLCommandContext(); commandCtx.setSTAL(getSTAL()); commandCtx.setURLDereferencerContext(new SimpleFormDataContextImpl(this)); + commandCtx.setLocale(locale); slCommand = SLCommandFactory.getInstance().createSLCommand(source, commandCtx); log.debug("Created new command: " + slCommand); @@ -731,7 +732,7 @@ public class HTTPBindingProcessor extends AbstractBindingProcessor implements protected void handleBindingProcessorError(OutputStream os, String encoding, Templates templates) throws IOException { log.debug("Writing error as result"); - ErrorResultImpl error = new ErrorResultImpl(bindingProcessorError); + ErrorResultImpl error = new ErrorResultImpl(bindingProcessorError, locale); error.writeTo(new StreamResult(new OutputStreamWriter(os, encoding)), templates); } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java index c95736bd..5af2afac 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/SLCommandContext.java @@ -16,13 +16,17 @@ */ package at.gv.egiz.bku.slcommands;
+import java.util.Locale; + import at.gv.egiz.bku.utils.urldereferencer.URLDereferencerContext;
import at.gv.egiz.stal.STAL;
public class SLCommandContext {
private STAL stal;
- private URLDereferencerContext urlDerefCtx;
+ private URLDereferencerContext urlDerefCtx; + + private Locale locale;
public void setSTAL(STAL aStal) {
this.stal = aStal;
@@ -38,5 +42,14 @@ public class SLCommandContext { public URLDereferencerContext getURLDereferencerContext() {
return urlDerefCtx;
- }
+ } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } +
}
\ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java index 628326cf..6462bcf6 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateXMLSignatureCommandImpl.java @@ -216,8 +216,8 @@ public class CreateXMLSignatureCommandImpl extends SLCommandImpl<CreateXMLSignat return new CreateXMLSignatureResultImpl(signature.getDocument());
- } catch (SLException e) {
- return new ErrorResultImpl(e);
+ } catch (SLException e) { + return new ErrorResultImpl(e, cmdCtx.getLocale());
}
}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java index 176ba001..5d0f0de0 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImpl.java @@ -16,6 +16,8 @@ */ package at.gv.egiz.bku.slcommands.impl;
+import java.util.Locale; + import javax.xml.transform.Result; import javax.xml.transform.Templates; @@ -32,22 +34,34 @@ public class ErrorResultImpl extends SLResultImpl implements ErrorResult { /**
* The exception containing information provided in the <code>ErrorResponse</code>.
*/
- protected SLException slException;
-
- /**
- * Creates a new instance of this ErrorResultImpl with the given
- * <code>slException</code> containing information provided in the
- * <code>ErrorResponse</code>.
- *
- * @param slException the exception
- */
- public ErrorResultImpl(SLException slException) {
- this.slException = slException;
- }
-
+ protected SLException slException; + + /** + * The locale to be used for rendering an <code>ErrorResponse</code>. + */ + protected Locale locale; + + /** + * Creates a new instance of this ErrorResultImpl with the given + * <code>slException</code> containing information provided in the + * <code>ErrorResponse</code> and the <code>locale</code> for rendering + * the <code>ErrorResponse</code>. + * + * @param slException the exception + * @param locale the locale + */ + public ErrorResultImpl(SLException slException, Locale locale) { + this.slException = slException; + this.locale = locale; + } + @Override public void writeTo(Result result, Templates templates) { - writeErrorTo(slException, result, templates); + if (locale == null) { + writeErrorTo(slException, result, templates); + } else { + writeErrorTo(slException, result, templates, locale); + } } }
\ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java index d23c0598..c7bb5205 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/InfoboxReadCommandImpl.java @@ -279,7 +279,7 @@ public class InfoboxReadCommandImpl extends SLCommandImpl<InfoboxReadRequestType throw new SLCommandException(4000); } } catch (SLCommandException e) {
- return new ErrorResultImpl(e);
+ return new ErrorResultImpl(e, cmdCtx.getLocale());
}
}
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java index 57309182..7306b237 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/SLResultImpl.java @@ -16,6 +16,8 @@ */ package at.gv.egiz.bku.slcommands.impl; +import java.util.Locale; + import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; @@ -181,6 +183,10 @@ public abstract class SLResultImpl implements SLResult { } protected void writeErrorTo(SLException slException, Result result, Templates templates) { + writeErrorTo(slException, result, templates, Locale.getDefault()); + } + + protected void writeErrorTo(SLException slException, Result result, Templates templates, Locale locale) { TransformerHandler transformerHandler = null; if (templates != null) { @@ -195,7 +201,7 @@ public abstract class SLResultImpl implements SLResult { ObjectFactory factory = new ObjectFactory(); ErrorResponseType responseType = factory.createErrorResponseType(); responseType.setErrorCode(slException.getErrorCode()); - responseType.setInfo(slException.getDetailedMsg()); + responseType.setInfo(slException.getLocalizedMessage(locale)); JAXBElement<ErrorResponseType> response = factory.createErrorResponse(responseType); Marshaller marshaller = getMarshaller(); diff --git a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java index 8455e934..f10ca520 100644 --- a/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java +++ b/bkucommon/src/test/java/at/gv/egiz/bku/slcommands/impl/ErrorResultImplTest.java @@ -17,6 +17,7 @@ package at.gv.egiz.bku.slcommands.impl; import java.io.ByteArrayOutputStream; +import java.util.Locale; import javax.xml.transform.stream.StreamResult; @@ -31,7 +32,7 @@ public class ErrorResultImplTest { public void writeTo() { SLException slException = new SLException(0,"test.noerror", null); - ErrorResult errorResult = new ErrorResultImpl(slException); + ErrorResult errorResult = new ErrorResultImpl(slException, Locale.getDefault()); ByteArrayOutputStream stream = new ByteArrayOutputStream(); StreamResult result = new StreamResult(stream); diff --git a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java index abe086ee..9e56701f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/ACOSCard.java @@ -30,12 +30,18 @@ package at.gv.egiz.smcc; import java.nio.charset.Charset; +import javax.smartcardio.Card; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + public class ACOSCard extends AbstractSignatureCard implements SignatureCard { + + private static Log log = LogFactory.getLog(ACOSCard.class); public static final byte[] AID_DEC = new byte[] { (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E }; @@ -97,7 +103,145 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { super("at/gv/egiz/smcc/ACOSCard"); } - byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { + /* (non-Javadoc) + * @see at.gv.egiz.smcc.SignatureCard#getCertificate(at.gv.egiz.smcc.SignatureCard.KeyboxName) + */ + public byte[] getCertificate(KeyboxName keyboxName) + throws SignatureCardException { + + byte[] aid; + byte[] efc; + int maxsize; + if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { + aid = AID_SIG; + efc = EF_C_CH_DS; + maxsize = EF_C_CH_DS_MAX_SIZE; + } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { + aid = AID_DEC; + efc = EF_C_CH_EKEY; + maxsize = EF_C_CH_EKEY_MAX_SIZE; + } else { + throw new IllegalArgumentException("Keybox " + keyboxName + + " not supported."); + } + + log.debug("Get certificate for keybox '" + keyboxName.getKeyboxName() + "'" + + " (AID=" + toString(aid) + " EF=" + toString(efc) + ")."); + + try { + Card card = getCardChannel().getCard(); + try { + card.beginExclusive(); + return readTLVFile(aid, efc, maxsize + 15000); + } catch (FileNotFoundException e) { + // if certificate is not present, + // the citizen card application has not been activated + throw new NotActivatedException(); + } finally { + card.endExclusive(); + } + } catch (CardException e) { + throw new SignatureCardException("Failed to get exclusive card access."); + } + + + } + + /* (non-Javadoc) + * @see at.gv.egiz.smcc.SignatureCard#getInfobox(java.lang.String, at.gv.egiz.smcc.PINProvider, java.lang.String) + */ + public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + throws SignatureCardException { + + if ("IdentityLink".equals(infobox)) { + + PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("inf.pin.name")); + + try { + Card card = getCardChannel().getCard(); + try { + card.beginExclusive(); + return readTLVFilePIN(AID_DEC, EF_INFOBOX, KID_PIN_INF, provider, + spec, EF_INFOBOX_MAX_SIZE); + } catch (FileNotFoundException e) { + // if certificate is not present, + // the citizen card application has not been activated + throw new NotActivatedException(); + } finally { + card.endExclusive(); + } + } catch (CardException e) { + throw new SignatureCardException("Failed to get exclusive card access."); + } + + } else { + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + } + + public byte[] createSignature(byte[] hash, KeyboxName keyboxName, + PINProvider provider) throws SignatureCardException { + + if (hash.length != 20) { + throw new IllegalArgumentException("Hash value must be of length 20."); + } + + try { + Card card = getCardChannel().getCard(); + try { + card.beginExclusive(); + + if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { + + // SELECT DF + selectFileFID(DF_SIG); + // VERIFY + verifyPIN(provider, new PINSpec(6, 10, "[0-9]", getResourceBundle() + .getString("sig.pin.name")), KID_PIN_SIG); + // MSE: SET DST + mseSetDST(0x81, 0xb6, DST_SIG); + // PSO: HASH + psoHash(hash); + // PSO: COMPUTE DIGITAL SIGNATURE + return psoComputDigitalSiganture(); + + } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { + + // SELECT DF + selectFileFID(DF_DEC); + // VERIFY + verifyPIN(provider, new PINSpec(4, 4, "[0-9]", getResourceBundle() + .getString("dec.pin.name")), KID_PIN_DEC); + // MSE: SET DST + mseSetDST(0x41, 0xa4, DST_DEC); + // INTERNAL AUTHENTICATE + return internalAuthenticate(hash); + + + // 00 88 10 00 23 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 54 26 F0 EA AF EA F0 4E D4 A1 AD BF 66 D4 A5 9B 45 6F AF 79 00 + // 00 88 10 00 23 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 DF 8C AB 8F E2 AD AC 7B 5A AF BE E9 44 5E 95 99 FA AF 2F 48 00 + + } else { + throw new IllegalArgumentException("KeyboxName '" + keyboxName + + "' not supported."); + } + + } catch (FileNotFoundException e) { + // if certificate is not present, + // the citizen card application has not been activated + throw new NotActivatedException(); + } finally { + card.endExclusive(); + } + } catch (CardException e) { + throw new SignatureCardException("Failed to get exclusive card access."); + } + + } + + protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { CardChannel channel = getCardChannel(); ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, 0x00, fid, 256)); @@ -109,18 +253,40 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { } } - byte[] selectFileFID(byte[] fid) throws CardException, SignatureCardException { + protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException { CardChannel channel = getCardChannel(); - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, + return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x00, 0x00, fid, 256)); - if (resp.getSW() == 0x6a82) { - throw new SignatureCardException("Failed to select file (FID=" - + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + ")"); + } + + protected int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException { + + CardChannel channel = getCardChannel(); + + byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII")); + byte[] encodedPIN = new byte[8]; + System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length, + encodedPIN.length)); + + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, + kid, encodedPIN), false); + + if (resp.getSW() == 0x63c0) { + throw new LockedException("PIN locked."); + } else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { + // return number of possible retries + return resp.getSW2() & 0x0f; + } else if (resp.getSW() == 0x6983) { + throw new NotActivatedException(); + } else if (resp.getSW() == 0x9000) { + return -1; } else { - return resp.getBytes(); + throw new SignatureCardException("Failed to verify pin: SW=" + + Integer.toHexString(resp.getSW()) + "."); } - } + } + /** * * @param pinProvider @@ -128,56 +294,30 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { * the PIN spec to be given to the pinProvider * @param kid * the KID (key identifier) of the PIN to be verified - * @param kfpc - * acutal value of the KFCP (key fault presentation counter) or less - * than 0 if actual value is unknown - * - * @return -1 if the PIN has been verifyed successfully, or else the new value - * of the KFCP (key fault presentation counter) - * * @throws CancelledException * if the user canceld the operation * @throws javax.smartcardio.CardException * @throws at.gv.egiz.smcc.SignatureCardException */ - int verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid, int kfpc) + protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid) throws CardException, CancelledException, SignatureCardException { - CardChannel channel = getCardChannel(); - - // get PIN - String pin = pinProvider.providePIN(spec, kfpc); - if (pin == null) { - // User canceld operation - // throw new CancelledException("User canceld PIN entry"); - return -2; - } - - byte[] asciiPIN = pin.getBytes(Charset.forName("ASCII")); - byte[] encodedPIN = new byte[8]; - System.arraycopy(asciiPIN, 0, encodedPIN, 0, Math.min(asciiPIN.length, - encodedPIN.length)); - - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, - kid, encodedPIN)); - if (resp.getSW1() == (byte) 0x63 && resp.getSW2() >> 4 == (byte) 0xc) { - return resp.getSW2() & (byte) 0x0f; - } else if (resp.getSW() == 0x6983) { - // PIN blocked - throw new SignatureCardException(spec.getLocalizedName() + " blocked."); - } else if (resp.getSW() != 0x9000) { - throw new SignatureCardException("Failed to verify pin: SW=" - + Integer.toHexString(resp.getSW()) + "."); - } else { - return -1; - } - + int retries = -1; + do { + String pin = pinProvider.providePIN(spec, retries); + if (pin == null) { + // user canceled operation + throw new CancelledException("User canceled operation"); + } + retries = verifyPIN(pin, kid); + } while (retries > 0); + } - - void mseSetDST(byte[] dst) throws CardException, SignatureCardException { + + void mseSetDST(int p1, int p2, byte[] dst) throws CardException, SignatureCardException { CardChannel channel = getCardChannel(); - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, 0x81, - 0xB6, dst)); + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x22, p1, + p2, dst)); if (resp.getSW() != 0x9000) { throw new SignatureCardException("MSE:SET DST failed: SW=" + Integer.toHexString(resp.getSW())); @@ -207,102 +347,30 @@ public class ACOSCard extends AbstractSignatureCard implements SignatureCard { return resp.getData(); } } - - public byte[] getCertificate(KeyboxName keyboxName) - throws SignatureCardException { - - if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { - return readTLVFile(AID_SIG, EF_C_CH_DS, EF_C_CH_DS_MAX_SIZE); - } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { - return readTLVFile(AID_DEC, EF_C_CH_EKEY, EF_C_CH_EKEY_MAX_SIZE); - } else { - throw new IllegalArgumentException("Keybox " + keyboxName - + " not supported."); - } - - } - - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) - throws SignatureCardException { - - if ("IdentityLink".equals(infobox)) { - - PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString( - "inf.pin.name")); - try { - byte[] res = readTLVFilePIN(AID_DEC, EF_INFOBOX, KID_PIN_INF, provider, - spec, EF_INFOBOX_MAX_SIZE); - return res; - } catch (Exception e) { - throw new SecurityException(e); - } - + + byte[] internalAuthenticate(byte[] hash) throws CardException, SignatureCardException { + byte[] digestInfo = 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[] data = new byte[digestInfo.length + hash.length + 1]; + + System.arraycopy(digestInfo, 0, data, 0, digestInfo.length); + data[digestInfo.length] = (byte) hash.length; + System.arraycopy(hash, 0, data, digestInfo.length + 1, hash.length); + + CardChannel channel = getCardChannel(); + + ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0x88, 0x10, 0x00, data, 256)); + if (resp.getSW() != 0x9000) { + throw new SignatureCardException("INTERNAL AUTHENTICATE failed: SW=" + Integer.toHexString(resp.getSW())); } else { - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); + return resp.getData(); } - } public String toString() { return "a-sign premium"; } - - public byte[] createSignature(byte[] hash, KeyboxName keyboxName, - PINProvider provider) throws SignatureCardException { - - if (hash.length != 20) { - throw new IllegalArgumentException("Hash value must be of length 20"); - } - - byte[] fid; - byte kid; - byte[] dst; - PINSpec spec; - if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - fid = DF_SIG; - kid = KID_PIN_SIG; - dst = DST_SIG; - spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString( - "sig.pin.name")); - - } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - fid = DF_DEC; - kid = KID_PIN_DEC; - dst = DST_DEC; - spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString( - "dec.pin.name")); - - } else { - throw new IllegalArgumentException("KeyboxName '" + keyboxName - + "' not supported."); - } - - try { - - // SELECT DF - selectFileFID(fid); - // VERIFY - int kfpc = -1; - while (true) { - kfpc = verifyPIN(provider, spec, kid, kfpc); - if (kfpc < -1) { - return null; - } else if (kfpc < 0) { - break; - } - } - // MSE: SET DST - mseSetDST(dst); - // PSO: HASH - psoHash(hash); - // PSO: COMPUTE DIGITAL SIGNATURE - byte[] rs = psoComputDigitalSiganture(); - - return rs; - - } catch (CardException e) { - throw new SignatureCardException("Failed to create signature.", e); - } - } } 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 77a3e2ea..cebc63fc 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/AbstractSignatureCard.java @@ -31,7 +31,6 @@ package at.gv.egiz.smcc; import java.nio.ByteBuffer; import java.util.Locale; import java.util.ResourceBundle; -import java.util.logging.Logger; import javax.smartcardio.ATR; import javax.smartcardio.Card; @@ -60,7 +59,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { this.resourceBundleName = resourceBundleName; } - String toString(byte[] b) { + protected String toString(byte[] b) { StringBuffer sb = new StringBuffer(); if (b != null && b.length > 0) { sb.append(Integer.toHexString((b[0] & 240) >> 4)); @@ -74,13 +73,46 @@ public abstract class AbstractSignatureCard implements SignatureCard { return sb.toString(); } - abstract byte[] selectFileAID(byte[] fid) throws CardException, + protected abstract byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException; - abstract byte[] selectFileFID(byte[] fid) throws CardException, + protected abstract ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException; - byte[] readBinary(CardChannel channel, int offset, int len) + /** + * VERIFY PIN + * + * <p> + * Implementations of this method should call + * {@link PINProvider#providePIN(PINSpec, int)} to retrieve the PIN entered by + * the user and VERIFY PIN on the smart card until the PIN has been + * successfully verified. + * </p> + * + * @param pinProvider + * the PINProvider + * @param spec + * the PINSpec + * @param kid + * the key ID (KID) of the PIN to verify + * + * @throws CardException + * if smart card communication fails + * + * @throws CancelledException + * if the PINProvider indicated that the user canceled the PIN entry + * @throws NotActivatedException + * if the card application has not been activated + * @throws LockedException + * if the card application is locked + * + * @throws SignatureCardException + * if VERIFY PIN fails + */ + protected abstract void verifyPIN(PINProvider pinProvider, PINSpec spec, + byte kid) throws CardException, SignatureCardException; + + protected byte[] readBinary(CardChannel channel, int offset, int len) throws CardException, SignatureCardException { ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xB0, @@ -94,7 +126,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { } - int readBinary(int offset, int len, byte[] b) throws CardException, + protected int readBinary(int offset, int len, byte[] b) throws CardException, SignatureCardException { if (b.length < len) { @@ -114,7 +146,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { } - byte[] readBinaryTLV(int maxSize, byte expectedType) throws CardException, + protected byte[] readBinaryTLV(int maxSize, byte expectedType) throws CardException, SignatureCardException { CardChannel channel = getCardChannel(); @@ -150,15 +182,38 @@ public abstract class AbstractSignatureCard implements SignatureCard { } - abstract int verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid, - int kfpc) throws CardException, SignatureCardException; - - public byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength) + /** + * 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 + */ + protected byte[] readTLVFile(byte[] aid, byte[] ef, int maxLength) throws SignatureCardException { return readTLVFilePIN(aid, ef, (byte) 0, null, null, maxLength); } - public byte[] readTLVFilePIN(byte[] aid, byte[] ef, byte kid, + + /** + * Read the content of a TLV file wich may require 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 provider the PINProvider + * @param spec the PINSpec + * @param maxLength the maximum length of the file + * + * @return the content of the file + * + * @throws SignatureCardException + */ + protected byte[] readTLVFilePIN(byte[] aid, byte[] ef, byte kid, PINProvider provider, PINSpec spec, int maxLength) throws SignatureCardException { @@ -179,33 +234,38 @@ public abstract class AbstractSignatureCard implements SignatureCard { } // SELECT FILE (EF) - rb = selectFileFID(ef); - if (rb[rb.length - 2] != (byte) 0x90 || rb[rb.length - 1] != (byte) 0x00) { + 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((0xFF & (int) rb[rb.length - 1]) - | (0xFF & (int) rb[rb.length - 2]) << 8) + ")."); + + Integer.toHexString(resp.getSW()) + ")."); + } // try to READ BINARY - int sw = readBinary(0, 1, new byte[1]); + byte[] b = new byte[1]; + int sw = readBinary(0, 1, b); + if (provider != null && sw == 0x6982) { // VERIFY - int kfpc = -1; // unknown - while (true) { - kfpc = verifyPIN(provider, spec, kid, kfpc); - if (kfpc < -1) { - return null; - } else if (kfpc < 0) { - break; - } + verifyPIN(provider, spec, kid); + + } else if (sw == 0x9000) { + // not expected type + if (b[0] != 0x30) { + throw new NotActivatedException(); } - } else if (sw != 0x9000) { + } else { throw new SignatureCardException("READ BINARY failed (SW=" + Integer.toHexString(sw) + ")."); } @@ -221,17 +281,56 @@ public abstract class AbstractSignatureCard implements SignatureCard { } - ResponseAPDU transmit(CardChannel channel, CommandAPDU commandAPDU) + /** + * Transmit the given command APDU using the given card channel. + * + * @param channel + * the card channel + * @param commandAPDU + * the command APDU + * @param logData + * <code>true</code> if command APDU data may be logged, or + * <code>false</code> 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 { - log.trace(commandAPDU + "\n" + toString(commandAPDU.getBytes())); - long t0 = System.currentTimeMillis(); - ResponseAPDU responseAPDU = channel.transmit(commandAPDU); - long t1 = System.currentTimeMillis(); - log.trace(responseAPDU + "\n[" + (t1 - t0) + "ms] " - + toString(responseAPDU.getBytes())); - return responseAPDU; + return transmit(channel, commandAPDU, true); } + public void init(Card card) { card_ = card; ATR atr = card.getATR(); @@ -242,7 +341,7 @@ public abstract class AbstractSignatureCard implements SignatureCard { } } - CardChannel getCardChannel() { + protected CardChannel getCardChannel() { return card_.getBasicChannel(); } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java b/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java new file mode 100644 index 00000000..f96611c2 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/FileNotFoundException.java @@ -0,0 +1,38 @@ +/* +* 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; + +public class FileNotFoundException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + + public FileNotFoundException() { + } + + public FileNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + public FileNotFoundException(String message) { + super(message); + } + + public FileNotFoundException(Throwable cause) { + super(cause); + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java b/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java new file mode 100644 index 00000000..e00322a0 --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/LockedException.java @@ -0,0 +1,38 @@ +/* +* 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; + +public class LockedException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + + public LockedException() { + } + + public LockedException(String message, Throwable cause) { + super(message, cause); + } + + public LockedException(String message) { + super(message); + } + + public LockedException(Throwable cause) { + super(cause); + } + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java b/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java new file mode 100644 index 00000000..9181fc5f --- /dev/null +++ b/smcc/src/main/java/at/gv/egiz/smcc/NotActivatedException.java @@ -0,0 +1,44 @@ +/* +* 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; + +/** + * This exception is thrown upon a call to a function that + * has not been activated (e.g. not yet activated citizen card). + */ +public class NotActivatedException extends SignatureCardException { + + private static final long serialVersionUID = 1L; + + public NotActivatedException() { + super(); + } + + public NotActivatedException(String message, Throwable cause) { + super(message, cause); + } + + public NotActivatedException(String message) { + super(message); + } + + public NotActivatedException(Throwable cause) { + super(cause); + } + + +} diff --git a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java index 79e2663e..99acbc0f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/STARCOSCard.java @@ -31,12 +31,21 @@ package at.gv.egiz.smcc; import java.math.BigInteger; import java.util.Arrays; +import javax.smartcardio.Card; import javax.smartcardio.CardChannel; import javax.smartcardio.CardException; import javax.smartcardio.CommandAPDU; import javax.smartcardio.ResponseAPDU; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + public class STARCOSCard extends AbstractSignatureCard implements SignatureCard { + + /** + * Logging facility. + */ + private static Log log = LogFactory.getLog(STARCOSCard.class); public static final byte[] MF = new byte[] { (byte) 0x3F, (byte) 0x00 }; @@ -83,7 +92,7 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard public static final byte KID_PIN_SS = (byte) 0x81; - // Gew�hnliche Signatur (GS) + // Gewöhnliche Signatur (GS) public static final byte[] AID_DF_GS = new byte[] { (byte) 0xd0, (byte) 0x40, (byte) 0x00, (byte) 0x00, (byte) 0x17, (byte) 0x00, (byte) 0x13, @@ -104,31 +113,157 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard // . // ) (byte) 0x80, (byte) 0x02, (byte) 0x00, // local, key ID, key version - (byte) 0x89, (byte) 0x01, // tag, length (algorithm ID) - (byte) 0x14 // ECDSA + (byte) 0x89, (byte) 0x03, // tag, length (algorithm ID) + (byte) 0x13, (byte) 0x35, (byte) 0x10 // ECDSA }; public static final byte KID_PIN_CARD = (byte) 0x01; + /** + * Creates an new instance. + */ public STARCOSCard() { super("at/gv/egiz/smcc/STARCOSCard"); } + /* (non-Javadoc) + * @see at.gv.egiz.smcc.SignatureCard#getCertificate(at.gv.egiz.smcc.SignatureCard.KeyboxName) + */ public byte[] getCertificate(KeyboxName keyboxName) throws SignatureCardException { + byte[] aid; + byte[] efc; if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { - return readTLVFile(AID_DF_SS, EF_C_X509_CH_DS, 2000); + aid = AID_DF_SS; + efc = EF_C_X509_CH_DS; } else if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { - return readTLVFile(AID_DF_GS, EF_C_X509_CH_AUT, 2000); + aid = AID_DF_GS; + efc = EF_C_X509_CH_AUT; } else { throw new IllegalArgumentException("Keybox " + keyboxName + " not supported."); } + log.debug("Get certificate for keybox '" + keyboxName.getKeyboxName() + "'" + + " (AID=" + toString(aid) + " EF=" + toString(efc) + ")."); + + try { + Card card = getCardChannel().getCard(); + try { + card.beginExclusive(); + return readTLVFile(aid, efc, 2000); + } catch (FileNotFoundException e) { + // if certificate is not present, + // the citizen card application has not been activated + throw new NotActivatedException(); + } finally { + card.endExclusive(); + } + } catch (CardException e) { + throw new SignatureCardException("Failed to get exclusive card access."); + } + + } + + /* (non-Javadoc) + * @see at.gv.egiz.smcc.SignatureCard#getInfobox(java.lang.String, at.gv.egiz.smcc.PINProvider, java.lang.String) + */ + public byte[] getInfobox(String infobox, PINProvider provider, String domainId) + throws SignatureCardException { + + if ("IdentityLink".equals(infobox)) { + + PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); + + try { + Card card = getCardChannel().getCard(); + try { + card.beginExclusive(); + return readTLVFilePIN(AID_INFOBOX, EF_INFOBOX, KID_PIN_CARD, + provider, spec, 2000); + } catch (FileNotFoundException e) { + // if certificate is not present, + // the citizen card application has not been activated + throw new NotActivatedException(); + } finally { + card.endExclusive(); + } + } catch (CardException e) { + throw new SignatureCardException("Failed to get exclusive card access."); + } + + } else { + throw new IllegalArgumentException("Infobox '" + infobox + + "' not supported."); + } + + } + + /* (non-Javadoc) + * @see at.gv.egiz.smcc.SignatureCard#createSignature(byte[], at.gv.egiz.smcc.SignatureCard.KeyboxName, at.gv.egiz.smcc.PINProvider) + */ + public byte[] createSignature(byte[] hash, KeyboxName keyboxName, + PINProvider provider) throws SignatureCardException { + + if (hash.length != 20) { + throw new IllegalArgumentException("Hash value must be of length 20."); + } + + byte[] aid; + byte kid; + byte[] dst; + PINSpec spec; + if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { + aid = AID_DF_SS; + kid = KID_PIN_SS; + dst = DST_SS; + spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); + + } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { + aid = AID_DF_GS; + kid = KID_PIN_CARD; + dst = DST_GS; + spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); + + } else { + throw new IllegalArgumentException("KeyboxName '" + keyboxName + + "' not supported."); + } + + try { + Card card = getCardChannel().getCard(); + try { + card.beginExclusive(); + + // SELECT MF + selectMF(); + // SELECT DF + selectFileAID(aid); + // VERIFY + verifyPIN(provider, spec, kid); + // MSE: SET DST + mseSetDST(dst); + // PSO: HASH + psoHash(hash); + // PSO: COMPUTE DIGITAL SIGNATURE + return psoComputDigitalSiganture(); + + + } catch (FileNotFoundException e) { + // if certificate is not present, + // the citizen card application has not been activated + throw new NotActivatedException(); + } finally { + card.endExclusive(); + } + } catch (CardException e) { + throw new SignatureCardException("Failed to get exclusive card access."); + } + } - byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { + protected byte[] selectFileAID(byte[] fid) throws CardException, SignatureCardException { CardChannel channel = getCardChannel(); ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x04, 0x04, fid, 256)); @@ -150,16 +285,10 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard } } - byte[] selectFileFID(byte[] fid) throws CardException, SignatureCardException { + protected ResponseAPDU selectFileFID(byte[] fid) throws CardException, SignatureCardException { CardChannel channel = getCardChannel(); - ResponseAPDU resp = transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02, + return transmit(channel, new CommandAPDU(0x00, 0xA4, 0x02, 0x04, fid, 256)); - if (resp.getSW() == 0x6a82) { - throw new SignatureCardException("Failed to select file (FID=" - + toString(fid) + "): SW=" + Integer.toHexString(resp.getSW()) + "."); - } else { - return resp.getBytes(); - } } void mseSetDST(byte[] dst) throws CardException, SignatureCardException { @@ -201,134 +330,86 @@ public class STARCOSCard extends AbstractSignatureCard implements SignatureCard } } - int verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid, int kfpc) - throws CardException, SignatureCardException { - + /** + * VERIFY PIN + * <p> + * If <code>pin</code> is <code>null</code> only the PIN status is checked and + * returned. + * </p> + * + * @param pin + * the PIN (may be <code>null</code>) + * @param kid + * the KID of the PIN to be verified + * + * @return -1 if VERIFY PIN was successful, or the number of possible retries + * + * @throws CardException + * if communication with the smart card fails. + * @throws NotActivatedException + * if the card application has not been activated + * @throws SignatureCardException + * if VERIFY PIN fails + */ + private int verifyPIN(String pin, byte kid) throws CardException, SignatureCardException { + CardChannel channel = getCardChannel(); - // get number of possible retries - ResponseAPDU resp = transmit(channel, - new CommandAPDU(0x00, 0x20, 0x00, kid)); - int retries; - if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { - retries = resp.getSW2() & 0x0f; - } else if (resp.getSW() == 0x6984) { - // PIN LCS = "Initilized" (not activated) - throw new SignatureCardException(spec.getLocalizedName() + " not set."); - } else { - throw new SignatureCardException("Failed to get PIN retries: SW=" - + Integer.toHexString(resp.getSW())); - } - - // get PIN - String pin = pinProvider.providePIN(spec, retries); + ResponseAPDU resp; if (pin == null) { - // User canceled operation - // throw new CancelledException("User canceld PIN entry"); - return -2; - } - // PIN length in bytes - int len = (int) Math.ceil(pin.length() / 2); - - // BCD encode PIN and marshal PIN block - byte[] pinBytes = new BigInteger(pin, 16).toByteArray(); - byte[] pinBlock = new byte[8]; - if (len < pinBytes.length) { - System.arraycopy(pinBytes, pinBytes.length - len, pinBlock, 1, len); + resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid)); } else { - System.arraycopy(pinBytes, 0, pinBlock, len - pinBytes.length + 1, - pinBytes.length); + // PIN length in bytes + int len = (int) Math.ceil(pin.length() / 2); + + // BCD encode PIN and marshal PIN block + byte[] pinBytes = new BigInteger(pin, 16).toByteArray(); + byte[] pinBlock = new byte[8]; + if (len < pinBytes.length) { + System.arraycopy(pinBytes, pinBytes.length - len, pinBlock, 1, len); + } else { + System.arraycopy(pinBytes, 0, pinBlock, len - pinBytes.length + 1, + pinBytes.length); + } + pinBlock[0] = (byte) (0x20 + len * 2); + Arrays.fill(pinBlock, len + 1, 8, (byte) 0xff); + + resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock), false); + } - pinBlock[0] = (byte) (0x20 + len * 2); - Arrays.fill(pinBlock, len + 1, 8, (byte) 0xff); - resp = transmit(channel, new CommandAPDU(0x00, 0x20, 0x00, kid, pinBlock)); - if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { + if (resp.getSW() == 0x63c0) { + throw new LockedException("PIN locked."); + } else if (resp.getSW1() == 0x63 && resp.getSW2() >> 4 == 0xc) { + // return number of possible retries return resp.getSW2() & 0x0f; - } else if (resp.getSW() != 0x9000) { + } else if (resp.getSW() == 0x6984) { + // PIN LCS = "Initialized" (-> not activated) + throw new NotActivatedException("PIN not set."); + } else if (resp.getSW() == 0x9000) { + return -1; // success + } else { throw new SignatureCardException("Failed to verify pin: SW=" + Integer.toHexString(resp.getSW())); - } else { - return -1; - } - - } - - public byte[] createSignature(byte[] hash, KeyboxName keyboxName, - PINProvider provider) throws SignatureCardException { - - if (hash.length != 20) { - throw new IllegalArgumentException("Hash value must be of length 20"); - } - - byte[] aid; - byte kid; - byte[] dst; - PINSpec spec; - if (KeyboxName.SECURE_SIGNATURE_KEYPAIR.equals(keyboxName)) { - aid = AID_DF_SS; - kid = KID_PIN_SS; - dst = DST_SS; - spec = new PINSpec(6, 10, "[0-9]", getResourceBundle().getString("sig.pin.name")); - - } else if (KeyboxName.CERITIFIED_KEYPAIR.equals(keyboxName)) { - aid = AID_DF_GS; - kid = KID_PIN_CARD; - dst = DST_GS; - spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); - - } else { - throw new IllegalArgumentException("KeyboxName '" + keyboxName - + "' not supported."); } - - try { - - // SELECT MF - selectMF(); - // SELECT DF - selectFileAID(aid); - // VERIFY - int retr = -1; // unknown - while (true) { - retr = verifyPIN(provider, spec, kid, retr); - if (retr < -1) { - return null; - } else if (retr < 0) { - break; - } - } - // MSE: SET DST - mseSetDST(dst); - // PSO: HASH - psoHash(hash); - // PSO: COMPUTE DIGITAL SIGNATURE - byte[] rs = psoComputDigitalSiganture(); - return rs; - - } catch (CardException e) { - throw new SignatureCardException("Failed to create signature.", e); - } - + } + + /* (non-Javadoc) + * @see at.gv.egiz.smcc.AbstractSignatureCard#verifyPIN(at.gv.egiz.smcc.PINProvider, at.gv.egiz.smcc.PINSpec, byte, int) + */ + protected void verifyPIN(PINProvider pinProvider, PINSpec spec, byte kid) + throws CardException, SignatureCardException { - public byte[] getInfobox(String infobox, PINProvider provider, String domainId) - throws SignatureCardException { - - if ("IdentityLink".equals(infobox)) { - - PINSpec spec = new PINSpec(4, 4, "[0-9]", getResourceBundle().getString("card.pin.name")); - try { - byte[] res = readTLVFilePIN(AID_INFOBOX, EF_INFOBOX, KID_PIN_CARD, - provider, spec, 2000); - return res; - } catch (Exception e) { - throw new SignatureCardException(e); + int retries = verifyPIN(null, kid); + do { + String pin = pinProvider.providePIN(spec, retries); + if (pin == null) { + // user canceled operation + throw new CancelledException("User canceld operation."); } - } else { - throw new IllegalArgumentException("Infobox '" + infobox - + "' not supported."); - } + retries = verifyPIN(pin, kid); + } while (retries > 0); } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java index 68a6f6df..22a66c3f 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SWCard.java @@ -25,6 +25,8 @@ import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.Charset; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyStore; @@ -52,16 +54,20 @@ import org.apache.commons.logging.LogFactory; */ public class SWCard implements SignatureCard { - private static final String BKU_USER_DIR = ".bku"; + private static final String BKU_USER_DIR = ".mocca"; private static final String SWCARD_DIR = "smcc"; private static final String KEYSTORE_CERTIFIED_KEYPAIR = "certified.p12"; + private static final String KEYSTORE_PASSWORD_CERTIFIED_KEYPAIR = "certified.pwd"; + private static final String CERTIFICATE_CERTIFIED_KEYPAIR = "certified.cer"; private static final String KEYSTORE_SECURE_KEYPAIR = "secure.p12"; + private static final String KEYSTORE_PASSWORD_SECURE_KEYPAIR = "secure.pwd"; + private static final String CERTIFICATE_SECURE_KEYPAIR = "secure.cer"; private static String swCardDir; @@ -70,8 +76,12 @@ public class SWCard implements SignatureCard { private KeyStore certifiedKeyStore; + private String certifiedKeyStorePassword; + private KeyStore secureKeyStore; + private String secureKeyStorePassword; + private Certificate certifiedCertificate; private Certificate secureCertificate; @@ -168,7 +178,7 @@ public class SWCard implements SignatureCard { } try { - keyStore.load(keyStoreFile, null); + keyStore.load(keyStoreFile, password); } catch (Exception e) { String msg = "Failed to load KeyStore from file '" + fileName + "'."; log.info(msg, e); @@ -176,10 +186,33 @@ public class SWCard implements SignatureCard { } return keyStore; - } + private String loadKeyStorePassword(String passwordFileName) throws SignatureCardException { + + String fileName = getFileName(passwordFileName); + FileInputStream keyStorePasswordFile; + try { + keyStorePasswordFile = new FileInputStream(fileName); + } catch (FileNotFoundException e) { + return null; + } + + try { + InputStreamReader reader = new InputStreamReader(keyStorePasswordFile, Charset.forName("UTF-8")); + StringBuilder sb = new StringBuilder(); + char b[] = new char[16]; + for (int l; (l = reader.read(b)) != -1;) { + sb.append(b, 0, l); + } + return sb.toString(); + } catch (IOException e) { + throw new SignatureCardException("Failed to read file '" + passwordFileName + "'."); + } + + } + private KeyStore getKeyStore(KeyboxName keyboxName, char[] password) throws SignatureCardException { if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { @@ -198,6 +231,23 @@ public class SWCard implements SignatureCard { } + private String getPassword(KeyboxName keyboxName) throws SignatureCardException { + + if (keyboxName == KeyboxName.CERITIFIED_KEYPAIR) { + if (certifiedKeyStorePassword == null) { + certifiedKeyStorePassword = loadKeyStorePassword(KEYSTORE_PASSWORD_CERTIFIED_KEYPAIR); + } + return certifiedKeyStorePassword; + } else if (keyboxName == KeyboxName.SECURE_SIGNATURE_KEYPAIR) { + if (secureKeyStorePassword == null) { + secureKeyStorePassword = loadKeyStorePassword(KEYSTORE_PASSWORD_SECURE_KEYPAIR); + } + return secureKeyStorePassword; + } else { + throw new SignatureCardException("Keybox of type '" + keyboxName + "' not supported."); + } + + } public byte[] getCertificate(KeyboxName keyboxName) throws SignatureCardException { @@ -254,9 +304,21 @@ public class SWCard implements SignatureCard { public byte[] createSignature(byte[] hash, KeyboxName keyboxName, PINProvider provider) throws SignatureCardException { // KeyStore password - PINSpec pinSpec = new PINSpec(0, -1, ".", "KeyStore-Password"); - - KeyStore keyStore = getKeyStore(keyboxName, null); + String password = getPassword(keyboxName); + + if (password == null) { + + PINSpec pinSpec = new PINSpec(0, -1, ".", "KeyStore-Password"); + + password = provider.providePIN(pinSpec, -1); + + if (password == null) { + return null; + } + + } + + KeyStore keyStore = getKeyStore(keyboxName, password.toCharArray()); PrivateKey privateKey = null; @@ -269,8 +331,7 @@ public class SWCard implements SignatureCard { Key key = null; while (key == null) { try { - String pin = provider.providePIN(pinSpec, -1); - key = keyStore.getKey(alias, pin.toCharArray()); + key = keyStore.getKey(alias, password.toCharArray()); } catch (UnrecoverableKeyException e) { log.info("Failed to get Key from KeyStore. Wrong password?", e); } @@ -315,8 +376,6 @@ public class SWCard implements SignatureCard { @Override public void setLocale(Locale locale) { - // TODO Auto-generated method stub - throw new UnsupportedOperationException("Not supported yet."); } @Override diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java index f2a964fe..f296f3a2 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardException.java @@ -34,7 +34,7 @@ public class SignatureCardException extends Exception { * */ private static final long serialVersionUID = 1L; - + /** * Creates a new instance of this <code>SignatureCardException</code>. * diff --git a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java index 2131a737..777299d9 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/SignatureCardFactory.java @@ -28,19 +28,189 @@ // package at.gv.egiz.smcc; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import javax.smartcardio.ATR; import javax.smartcardio.Card; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A factory for creating {@link SignatureCard}s from {@link Card}s. + */ public class SignatureCardFactory { + + /** + * This class represents a supported smart card. + */ + private class SupportedCard { + + /** + * The ATR pattern. + */ + private byte[] atrPattern; + + /** + * The ATR mask. + */ + private byte[] atrMask; + + /** + * The implementation class. + */ + private String impl; - public static SignatureCardFactory getInstance() { - return new SignatureCardFactory(); + /** + * Creates a new SupportedCard instance with the given ATR pattern and mask + * und the corresponding implementation class. + * + * @param atrPattern + * the ATR pattern + * @param atrMask + * the ATR mask + * @param implementationClass + * the name of the implementation class + * + * @throws NullPointerException + * if <code>atrPattern</code> or <code>atrMask</code> is + * <code>null</code>. + * @throws IllegalArgumentException + * if the lengths of <code>atrPattern</code> and + * <code>atrMask</code> of not equal. + */ + public SupportedCard(byte[] atrPattern, byte[] atrMask, String implementationClass) { + if (atrPattern.length != atrMask.length) { + throw new IllegalArgumentException("Length of 'atr' and 'mask' must be equal."); + } + this.atrPattern = atrPattern; + this.atrMask = atrMask; + this.impl = implementationClass; + } + + /** + * Returns true if the given ATR matches the ATR pattern and mask this + * SupportedCard object. + * + * @param atr + * the ATR + * + * @return <code>true</code> if the given ATR matches the ATR pattern and + * mask of this SupportedCard object, or <code>false</code> + * otherwise. + */ + public boolean matches(ATR atr) { + + byte[] bytes = atr.getBytes(); + if (bytes == null) { + return false; + } + if (bytes.length < atrMask.length) { + // we cannot test for equal length here, as we get ATRs with + // additional bytes on systems using PCSClite (e.g. linux and OS X) sometimes + return false; + } + + int l = Math.min(atrMask.length, bytes.length); + for (int i = 0; i < l; i++) { + if ((bytes[i] & atrMask[i]) != atrPattern[i]) { + return false; + } + } + return true; + + } + + /** + * @return the corresponding implementation class. + */ + public String getImplementationClassName() { + return impl; + } + + } + + /** + * Logging facility. + */ + private static Log log = LogFactory.getLog(SignatureCardFactory.class); + + /** + * The instance to be returned by {@link #getInstance()}. + */ + private static SignatureCardFactory instance; + + /** + * The list of supported smart cards. + */ + private List<SupportedCard> supportedCards; + + /** + * @return an instance of this SignatureCardFactory. + */ + public static synchronized SignatureCardFactory getInstance() { + if (instance == null) { + instance = new SignatureCardFactory(); + } + return instance; } + /** + * Private constructor. + */ private SignatureCardFactory() { + + supportedCards = new ArrayList<SupportedCard>(); + + // e-card + supportedCards.add(new SupportedCard( + // ATR (3b:bd:18:00:81:31:fe:45:80:51:02:00:00:00:00:00:00:00:00:00:00:00) + new byte[] { + (byte) 0x3b, (byte) 0xbd, (byte) 0x18, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45, + (byte) 0x80, (byte) 0x51, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }, + // mask (ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00:00) + new byte[] { + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }, + "at.gv.egiz.smcc.STARCOSCard")); + // a-sign premium + supportedCards.add(new SupportedCard( + // ATR (3b:bf:11:00:81:31:fe:45:45:50:41:00:00:00:00:00:00:00:00:00:00:00:00:00) + new byte[] { + (byte) 0x3b, (byte) 0xbf, (byte) 0x11, (byte) 0x00, (byte) 0x81, (byte) 0x31, (byte) 0xfe, (byte) 0x45, + (byte) 0x45, (byte) 0x50, (byte) 0x41, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }, + // mask (ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:00:00:00:00:00:00:00:00:00:00:00:00:00) + new byte[] { + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 + }, + "at.gv.egiz.smcc.ACOSCard")); + } + /** + * Creates a SignatureCard instance with the given smart card. + * + * @param card + * the smart card, or <code>null</code> if a software card should be + * created + * + * @return a SignatureCard instance + * + * @throws CardNotSupportedException + * if no implementation of the given <code>card</code> could be + * found + */ public SignatureCard createSignatureCard(Card card) throws CardNotSupportedException { @@ -51,31 +221,34 @@ public class SignatureCardFactory { } ATR atr = card.getATR(); - byte[] historicalBytes = atr.getHistoricalBytes(); - if(historicalBytes == null || historicalBytes.length < 3) { - throw new CardNotSupportedException("Card not supported: ATR=" + toString(atr.getBytes())); + Iterator<SupportedCard> cards = supportedCards.iterator(); + while (cards.hasNext()) { + SupportedCard supportedCard = cards.next(); + if(supportedCard.matches(atr)) { + + ClassLoader cl = SignatureCardFactory.class.getClassLoader(); + SignatureCard sc; + try { + Class<?> scClass = cl.loadClass(supportedCard.getImplementationClassName()); + sc = (SignatureCard) scClass.newInstance(); + sc.init(card); + return sc; + + } catch (ClassNotFoundException e) { + log.warn("Cannot find signature card implementation class.", e); + throw new CardNotSupportedException("Cannot find signature card implementation class.", e); + } catch (InstantiationException e) { + log.warn("Failed to instantiate signature card implementation.", e); + throw new CardNotSupportedException("Failed to instantiate signature card implementation.", e); + } catch (IllegalAccessException e) { + log.warn("Failed to instantiate signature card implementation.", e); + throw new CardNotSupportedException("Failed to instantiate signature card implementation.", e); + } + + } } - int t = ((0xFF & (int) historicalBytes[0]) << 16) + - ((0xFF & (int) historicalBytes[1]) << 8) + - (0xFF & (int) historicalBytes[2]); - - SignatureCard sCard; - switch (t) { - case 0x455041 : - case 0x4D4341 : - sCard = new ACOSCard(); - break; - - case 0x805102 : - sCard = new STARCOSCard(); - break; - - default : - throw new CardNotSupportedException("Card not supported: ATR=" + toString(atr.getBytes())); - } - sCard.init(card); - return sCard; + throw new CardNotSupportedException("Card not supported: ATR=" + toString(atr.getBytes())); } diff --git a/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java b/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java index ffffd3af..b70b44a7 100644 --- a/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java +++ b/smcc/src/main/java/at/gv/egiz/smcc/util/SmartCardIO.java @@ -142,7 +142,8 @@ public class SmartCardIO { for (CardTerminal terminal : cardTerminals_.list(CardTerminals.State.CARD_INSERTION)) {
Card card = null;
- try {
+ try { + log.trace("Trying to connect to card."); // try to connect to card
card = terminal.connect("*");
} catch (CardException e) {
diff --git a/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java new file mode 100644 index 00000000..b921a5d5 --- /dev/null +++ b/smcc/src/test/java/at/gv/egiz/smcc/STARCOSCardTest.java @@ -0,0 +1,92 @@ +/* +* 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 java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Locale; + +import javax.smartcardio.CardException; +import javax.smartcardio.CommandAPDU; +import javax.smartcardio.ResponseAPDU; + +import at.gv.egiz.smcc.SignatureCard.KeyboxName; +import at.gv.egiz.smcc.util.SMCCHelper; + +public class STARCOSCardTest { + + /** + * @param args + * @throws CardException + * @throws NoSuchAlgorithmException + */ + public static void main(String[] args) throws CardException, NoSuchAlgorithmException { + + SMCCHelper helper = new SMCCHelper(); + while (helper.getResultCode() != SMCCHelper.CARD_FOUND) { + System.out.println("Did not get a signature card ... " + helper.getResultCode()); + helper.update(); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + SignatureCard signatureCard = helper.getSignatureCard(Locale.getDefault()); + + System.out.println("Found '" + signatureCard + "'."); + + try { +// signatureCard.getCertificate(KeyboxName.SECURE_SIGNATURE_KEYPAIR); +// signatureCard.getCertificate(KeyboxName.CERITIFIED_KEYPAIR); +// signatureCard.getInfobox("IdentityLink", new CommandLinePINProvider(), null); + MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + byte[] digest = messageDigest.digest("test".getBytes()); + signatureCard.createSignature(digest, KeyboxName.CERITIFIED_KEYPAIR, new CommandLinePINProvider()); + } catch (SignatureCardException e) { + e.printStackTrace(); + } + + } + + private static class CommandLinePINProvider implements PINProvider { + + @Override + public String providePIN(PINSpec spec, int retries) { + + InputStreamReader inputStreamReader = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(inputStreamReader); + + System.out.print("Enter " + spec.getLocalizedName() + " [" + + spec.getMinLength() + "-" + spec.getMaxLength() + "] (" + retries + + " retries):"); + + try { + return in.readLine(); + } catch (IOException e) { + return null; + } + + } + + } + +} diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java index b48d6d50..cfac8cf5 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/InfoBoxReadRequestHandler.java @@ -20,6 +20,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.LockedException; +import at.gv.egiz.smcc.NotActivatedException; import at.gv.egiz.smcc.PINProvider; import at.gv.egiz.smcc.PINSpec; import at.gv.egiz.smcc.SignatureCard; @@ -100,6 +102,12 @@ public class InfoBoxReadRequestHandler extends AbstractRequestHandler implements stalResp.setInfoboxValue(resp); return stalResp; } + } catch (NotActivatedException e) { + log.info("Citizen card not activated.", e); + return new ErrorResponse(6001); + } catch (LockedException e) { + log.info("Citizen card locked.", e); + return new ErrorResponse(6001); } catch (CancelledException cx) { log.debug("User cancelled request", cx); return new ErrorResponse(6001); diff --git a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java index dcd12b02..466ec2a9 100644 --- a/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java +++ b/smccSTAL/src/main/java/at/gv/egiz/bku/smccstal/SignRequestHandler.java @@ -32,6 +32,8 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import at.gv.egiz.smcc.CancelledException; +import at.gv.egiz.smcc.LockedException; +import at.gv.egiz.smcc.NotActivatedException; import at.gv.egiz.smcc.PINProvider; import at.gv.egiz.smcc.PINSpec; import at.gv.egiz.smcc.SignatureCard; @@ -78,7 +80,7 @@ public abstract class SignRequestHandler extends AbstractRequestHandler implemen String jceName = JCEAlgorithmNames.getJCEHashName(signatureMethod); if (jceName == null) { log.error("Hash algorithm not supported:"); - return new ErrorResponse(1000); + return new ErrorResponse(4006); } MessageDigest md = MessageDigest.getInstance(jceName); md.update(signReq.getSignedInfo()); @@ -90,6 +92,12 @@ public abstract class SignRequestHandler extends AbstractRequestHandler implemen SignResponse stalResp = new SignResponse(); stalResp.setSignatureValue(resp); return stalResp; + } catch (NotActivatedException e) { + log.info("Citizen card not activated.", e); + return new ErrorResponse(6001); + } catch (LockedException e) { + log.info("Citizen card locked.", e); + return new ErrorResponse(6001); } catch (CancelledException cx) { log.debug("User cancelled request"); return new ErrorResponse(6001); |