/* * The MIT License * * Copyright 2014 Rui Martinho (rmartinho@gmail.com), António Braz (antoniocbraz@gmail.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.poreid.applet.autenticacao; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.security.InvalidKeyException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.Security; import java.security.Signature; import java.security.SignatureException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JApplet; import netscape.javascript.JSException; import netscape.javascript.JSObject; import org.poreid.CardFactory; import org.poreid.CardNotPresentException; import org.poreid.CardTerminalNotPresentException; import org.poreid.CertificateNotFound; import org.poreid.POReIDException; import org.poreid.SmartCardFileException; import org.poreid.UnknownCardException; import org.poreid.cc.CitizenCard; import org.poreid.config.POReIDConfig; import org.poreid.crypto.POReIDKeyStoreParameter; import org.poreid.crypto.POReIDProvider; import org.poreid.dialogs.pindialogs.PinBlockedException; import org.poreid.dialogs.pindialogs.PinEntryCancelledException; import org.poreid.dialogs.pindialogs.PinTimeoutException; import org.poreid.dialogs.selectcard.CanceledSelectionException; /** * * @author ruim */ public class AppletAutenticacao extends JApplet { private static final String HTTPS = "https"; private String nonce; private URL postURL; private String[] requestedData = null; @Override public String[][] getParameterInfo() { String pinfo[][] = { {"nonce", "string", "identificador único"}, {"post.url", "url", "url para onde efetuar o post"}, {"data.requested", "string", "dados requisitados para além da assinatura (id, morada, foto) em formato csv"} }; return pinfo; } @Override public void init() { if (!HTTPS.equalsIgnoreCase(this.getCodeBase().getProtocol())) { Logger.getLogger(AppletAutenticacao.class.getName()).log(Level.SEVERE, "Erro: necessário utilizar https"); System.exit(0); } else { nonce = getParameter("nonce"); String url = getParameter("post.url"); String requestedDataList = getParameter("data.requested"); Security.addProvider(new POReIDProvider()); if (null != url && !url.isEmpty()) { try { postURL = new URL(url); if (!HTTPS.equalsIgnoreCase(postURL.getProtocol())) { postError(postURL, new ErrorMessage("Erro: parâmetro post.url não usa https")); } if (null == nonce || nonce.isEmpty()) { postError(postURL, new ErrorMessage("Erro: falta parâmetro nonce")); } if (null != requestedDataList && !requestedDataList.isEmpty()) { requestedData = requestedDataList.split(","); } } catch (MalformedURLException ex) { Logger.getLogger(AppletAutenticacao.class.getName()).log(Level.SEVERE, "parâmetro post.url inválido", ex); System.exit(0); } } else { Logger.getLogger(AppletAutenticacao.class.getName()).log(Level.SEVERE, "parâmetro post.url não fornecido"); System.exit(0); } } } @Override public void start() { byte[] id = null; byte[] morada = null; byte[] foto = null; CitizenData cd = new CitizenData(); try { CitizenCard cc = CardFactory.getCard(); if (null != requestedData) { for (String reqData : requestedData) { switch (reqData.toLowerCase()) { case "id": id = cc.getID().getRawData(); cd.setId(id); break; case "morada": morada = cc.getAddress().getRawData(); cd.setAddress(morada); break; case "foto": foto = cc.getPhotoData().getRawData(); cd.setPhoto(foto); break; } } } if (null != id || null != morada || null != foto) { cd.setSod(cc.getSOD()); } cd.setCertificate(cc.getAuthenticationCertificate().getEncoded()); MessageDigest md = MessageDigest.getInstance("SHA-256"); if (null != id) { md.update(id); } if (null != morada){ md.update(morada); } if (null != foto){ md.update(foto); } md.update(nonce.getBytes()); POReIDKeyStoreParameter ksParam = new POReIDKeyStoreParameter(); ksParam.setCard(cc); KeyStore ks = KeyStore.getInstance(POReIDConfig.POREID); ks.load(ksParam); Signature signature = Signature.getInstance("SHA256withRSA"); PrivateKey pk = (PrivateKey) ks.getKey(POReIDConfig.AUTENTICACAO, null); signature.initSign(pk); signature.update(md.digest()); cd.setSignature(signature.sign()); createOkSubmitForm(postURL, cd); } catch (PinTimeoutException | PinEntryCancelledException | PinBlockedException | CardNotPresentException | CertificateNotFound | CardTerminalNotPresentException | UnknownCardException | CanceledSelectionException | POReIDException | SmartCardFileException | NoSuchAlgorithmException | KeyStoreException | IOException | CertificateException | UnrecoverableKeyException | InvalidKeyException | SignatureException ex) { createErrorSubmitForm(postURL,new ErrorMessage("Erro: verifique exceção", ex)); } System.exit(0); } private void postError(URL postURL, ErrorMessage message){ createErrorSubmitForm(postURL, message); System.exit(0); } private void createErrorSubmitForm(URL submitUrl, ErrorMessage message) throws JSException { JSObject document = (JSObject) JSObject.getWindow(this).getMember("document"); JSObject body = (JSObject) document.getMember("body"); JSObject redirectForm = (JSObject) document.call("createElement", new Object[]{"form"}); redirectForm.setMember("name", "redirectForm"); redirectForm.setMember("method", "POST"); redirectForm.setMember("action", submitUrl.getPath()); addInputField(document, redirectForm, "mensagem", message.getMessage()); addInputField(document, redirectForm, "excecao", message.getThrowableMessage()); body.call("appendChild", new Object[]{redirectForm}); redirectForm.call("submit"); } private void createOkSubmitForm(URL submitUrl, CitizenData data) throws JSException { JSObject document = (JSObject) JSObject.getWindow(this).getMember("document"); JSObject body = (JSObject) document.getMember("body"); JSObject redirectForm = (JSObject) document.call("createElement", new Object[]{"form"}); redirectForm.setMember("name", "redirectForm"); redirectForm.setMember("method", "POST"); redirectForm.setMember("action", submitUrl.getPath()); addInputField(document, redirectForm, "id", data.getID()); addInputField(document, redirectForm, "morada", data.getAddress()); addInputField(document, redirectForm, "foto", data.getPhoto()); addInputField(document, redirectForm, "sod", data.getSod()); addInputField(document, redirectForm, "certificado", data.getCertificate()); addInputField(document, redirectForm, "assinatura", data.getSignature()); addInputField(document, redirectForm, "nonce", nonce); body.call("appendChild", new Object[]{redirectForm}); redirectForm.call("submit"); } private void addInputField(JSObject parentDocument, JSObject targetForm, String fieldName, String fieldValue) throws JSException { if (null != fieldValue) { JSObject newField = (JSObject) parentDocument.call("createElement", new Object[]{"input"}); newField.setMember("type", "hidden"); newField.setMember("name", fieldName); newField.setMember("value", fieldValue); targetForm.call("appendChild", new Object[]{newField}); } } }