📄 simplesignapplet.java
字号:
/** * j4sign - an open, multi-platform digital signature solution * Copyright (c) 2004 Roberto Resoli - Servizio Sistema Informativo - Comune di Trento. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * *//* * $Header: /cvsroot/j4sign/j4sign/src/java/core/it/trento/comune/j4sign/examples/SimpleSignApplet.java,v 1.4 2005/03/06 18:06:47 resoli Exp $ * $Revision: 1.4 $ * $Date: 2005/03/06 18:06:47 $ */package it.trento.comune.j4sign.examples;import iaik.pkcs.pkcs11.TokenException;import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;import it.trento.comune.j4sign.pcsc.CardInfo;import it.trento.comune.j4sign.pcsc.PCSCHelper;import it.trento.comune.j4sign.pkcs11.PKCS11Signer;import java.awt.*;import javax.swing.*;import java.io.*;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;import java.net.URLEncoder;import java.security.cert.CertificateException;import java.util.List;/** * This is the client side part of the j4sign usage example in a web environment.<br> * <code>SimpleSignApplet</code> is <i>simple</i> in the sense that raffinate GUI features * are avoided (like multiple threads used to correctly implement the progress bar), in favor * to a clear exposition of specific signature procedures. * <p> * The goal was to illustrate an approach in which the client side digesting - encryption, involving * cryptographic token management via JNI, is completely separated from server side CMS message building. * This lightens the applet, which has not to bear the wheight of the BouncyCastle classes. * <p> * Another feature is the encapsulation of the JNI part (the excellent pkcs11 wrapper developed * by IAIK of Graz University of Technology, and the pcsc wrapper taken from Open Card Framework project), * along with the corresponding native libraries, in a standard Java Extension, named <code>SmartCardAccess</code>. * See {@link it.trento.comune.j4sign.installer} and <a href="http://java.sun.com/j2se/1.4.2/docs/guide/plugin/developer_guide/extensions.html"> * Deploying Java Extensions<a>.<br> * The extension is deployed automatically the first time the applet is loaded.<br> * The ultimate dependency for the applet is the cryptoki library, which has to be provided from the * PKCS11 token manufacturer. The {@link it.trento.comune.j4sign.pcsc.PCSCHelper} class uses the pcsc wrapper * trying to infer the correct library from the ATR string returned from the token. * <p> * Some words about security; all downloaded jars, including the <code>SmartCardAccess</code> extension, * has to be signed in order to work; this is needed for tho reasons:<ul><li>the applet loads native libraries</li> * <li>the applet deploys a java extension.</li></ul> This gives more confidence about signing software integrity. * <p> * The entire example, with the {@link it.trento.comune.j4sign.examples.CMSServlet} server side counterpart, is * designed to permit the use of the standard JDK tools. * The applet can be executed with applet viewer tool (no HttpSession in the servlet, * nor HTML forms on the client side are used).<br> * This eases the use of an IDE for test and debugging; we use, and recommend, the <a href="http://www.eclipse.org">Eclipse</a>) IDE. * <p> * N.B.: IN A REAL WORLD WEB APPLICATION SCENARIO, YOU CAN (AND SHOULD) TAKE ADVANTAGE OF THE FULL SERVLET API, AND HTTP/HTML FEATURES. * <p> * * Here are the <code>SimpleSignApplet</code> operations in detail; the applet talks with the server (servlet) in HTTP: * <ol> * <li>The applet initialization method (init()) builds the GUI layout: a text area in the center, and, in the bottom, * a button to load data from server and a password field.<br> * A detailed log is shown on System out (Java Plugin console). * </li> * <li>When the "Load data" button is pressed, a GET request is generated, specifiying a <code>retrieve</code> parameter with value * <code>DATA</code>; the server returns the message to sign.<br>Immediately after, another GET request is sent, specifiying a * <code>retrieve</code> parameter with value <code>ENCODED_AUTHENTICATED_ATTRIBUTES</code>; the server calculates and * returns the data to digest and encrypt (authenticated attributes).<br> * The message and a textual representation of the authenticated attributes are presented in the text area.<br> * Note that authenticated attributes includes a timestamp, then even if the message is the same, the bytes to * digest and encrypt change every time the user loads the data from server. * </li> * <li>When the user insert the password in the field and press return, the signing process starts:<br> * <ol type="a"><li>the PCSC layer is invoked to query for an inserted token, and if one is found the relative * PKCS#11 cryptoki is (hopefully) detected and loaded. *</li> *<li>Then the token is checked for the required signature algorithm (RSA_PKCS), and queried for a suitable certificate - private key pair. *</li> **<li>Then MD5 digest of authenticated attributes is calculated in software and the result sent to the token *for the encryption procedure. *</li> *</ol> * <li>The signature is sent to the server via HTTP POST, along with the signer certificate extracted from the token. * </li> * <li> * The server acknowledges confirming signature verification and CMS building and saving. * </li> * </ol> * <p><b>N.B. note that in this example signature verification only ensures integrity; a complete verification * to ensure non-repudiation requires checking the full certification path including the * CA root certificate, and CRL verification on the CA side. (Good stuff for a next release ...)</b> * * * @see it.trento.comune.j4sign.examples.CMSServlet * @author Roberto Resoli */public class SimpleSignApplet extends JApplet implements java.awt.event.ActionListener { private JTextArea dataArea = null; private JButton loadButton = new JButton("Load Data"); private JPasswordField pwd = new JPasswordField(); private java.io.PrintStream log = null; private JProgressBar progressBar = null; private String textToSign = null; private String attrPrintout = null; private byte[] bytesToSign = null; private byte[] digest = null; private byte[] encryptedDigest = null; private java.lang.String cryptokiLib = null; private java.lang.String signerLabel = null; private java.lang.String baseHttpUrl = null; private byte[] certificate = null; private static final short SEARCH_BY_PRIVATE_KEY = 0; private static final short SEARCH_BY_CERTIFICATE_KEY_USAGE = 1; private short OBJECT_SEARCH_CRITERION = SEARCH_BY_CERTIFICATE_KEY_USAGE; public static final int ERROR = -1; public static final int RESET = 0; public static final int DATA_LOADED = 1; public static final int SIGN_DONE = 2; public static final int POST_ERROR = -1; public static final int POST_OK_VERIFY_OK = 0; public static final int POST_OK_VERIFY_ERROR = 1; public static final String DEFAULT_BASE_HTTP_URL = "http://localhost:8080/sc/cmsservlet"; /** * The implementation of the callback method for ActionListener. * Entry point for all applet operations: data loading, signature, data sending. * * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent) */ public void actionPerformed(java.awt.event.ActionEvent e) { try { if (e.getSource() == this.loadButton) { if(loadData()){ this.pwd.setEnabled(true); this.loadButton.setEnabled(false); setStatus(DATA_LOADED, "Read carefully the text above. Type pin and press RETURN to sign."); }else setStatus(ERROR, "Cannot Load data from server"); } if (e.getSource() == this.pwd) { if (detectCardAndCriptoki()) { log .println("\n============= PKCS11 SIGNATURE START =============\n"); sign(); log .println("\n============= PKCS11 SIGNATURE END =============\n"); int rc = sendSignatureAndCertificate(); switch (rc) { case POST_ERROR: setStatus(SIGN_DONE, "Signature done - error sending data to server."); break; case POST_OK_VERIFY_OK: setStatus(SIGN_DONE, "Signature done - data sent to server and verified."); break; case POST_OK_VERIFY_ERROR: setStatus(SIGN_DONE, "Signature done - data sent to server but NOT verified!"); break; default: break; } pwd.setEnabled(false); this.loadButton.setEnabled(true); } else setStatus(ERROR, "No token or no suitable objects on token."); } } catch (Exception ex) { log.println(ex.toString()); setStatus(ERROR, ex.toString()); } finally { pwd.setText(""); } } /** * Cleans up whatever resources are being held. If the applet is active it * is stopped. * Forces a system garbage collection to reclaim memory. * * @see #init * @see #start * @see #stop */ public void destroy() { super.destroy(); log.println("Destroying applet and garbage collecting..."); //task = null; System.gc(); log.println("Garbage collection done."); // insert code to release resources here } /** * Gets the signer certificate. * * @return byte the certificate bytes as extracted from the pkcs11 token. */ public byte[] getCertificate() { return certificate; } /** * Gets the native cryptoki library name; this is the library * provided by the token manufacturer that implements the PKCS#11 standard API. * * @return java.lang.String */ private java.lang.String getCryptokiLib() { return cryptokiLib; } /** * Returns the digest of the bytes to sign. * * @return byte[] data to be sento to the token for encryption. */ public byte[] getDigest() { return digest; } /** * The result of encryption of data obtained from {@link #getDigest()}; Encryption * is done on the token. * * @return iaik.pkcs.pkcs7.SignedData */ public byte[] getEncryptedDigest() { return encryptedDigest; } /** * The textual identifier of the objects related to the signer * on a PKCS#11 token; do not rely only on this to find objects; * labels are manufacturer dependent. * * @return java.lang.String */ private java.lang.String getSignerLabel() { return signerLabel; } /** * Triggers three different HTTP GET requests against the server: * <ol> * <li>The first for retrieving the textual content to sign (the message)</li> * <li>The second for retrieving the time-dependent * bytes to sign (the authenticated attributes)</li> * <li>The third for retrieving a textual rapresentetion of the bytes to sign * (the authenticated attributes printout)</li> * </ol> * * The local digest value is updated according with the new bytes to sign. * * @return true if all data retrieval operations were successful. */ private boolean loadData() { boolean dataLoaded = false; log.println("Retrieving data from server..."); this.textToSign = retrieveTextToSign(); this.bytesToSign = retrieveBytesToSign(); if ((this.textToSign != null) && (this.bytesToSign != null)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -