Java tutorial
/* * Copyright (C) 2010 - 2012 Jenia Software. * * This file is part of Sinekarta * * Sinekarta 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 3 of the License, or * (at your option) any later version. * * Sinekarta 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. * */ package org.sinekartads.integration.cms; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.Security; import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.ClientContext; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.Test; import org.sinekartads.applet.AppletRequestDTO; import org.sinekartads.applet.AppletResponseDTO; import org.sinekartads.applet.AppletResponseDTO.ActionErrorDTO; import org.sinekartads.applet.AppletResponseDTO.FieldErrorDTO; import org.sinekartads.applet.SignNOApplet; import org.sinekartads.dto.ResultCode; import org.sinekartads.dto.domain.DocumentDTO; import org.sinekartads.dto.domain.SignatureDTO; import org.sinekartads.dto.domain.TimeStampRequestDTO; import org.sinekartads.dto.domain.VerifyDTO; import org.sinekartads.dto.request.BaseRequest; import org.sinekartads.dto.request.SkdsDocumentDetailsRequest; import org.sinekartads.dto.request.SkdsFindRefByNameRequest; import org.sinekartads.dto.request.SkdsSignRequest.SkdsPostSignRequest; import org.sinekartads.dto.request.SkdsSignRequest.SkdsPreSignRequest; import org.sinekartads.dto.response.BaseResponse; import org.sinekartads.dto.response.SkdsDocumentDetailsResponse; import org.sinekartads.dto.response.SkdsFindRefByNameResponse; import org.sinekartads.dto.response.SkdsSignResponse.SkdsPostSignResponse; import org.sinekartads.dto.response.SkdsSignResponse.SkdsPreSignResponse; import org.sinekartads.integration.BaseIntegrationTC; import org.sinekartads.model.domain.SecurityLevel.VerifyResult; import org.sinekartads.model.domain.SignDisposition; import org.sinekartads.model.domain.SignatureType.SignCategory; import org.sinekartads.model.domain.TimeStampInfo; import org.sinekartads.model.domain.Transitions.VerifiedSignature; import org.sinekartads.model.domain.VerifyInfo; import org.sinekartads.model.oid.DigestAlgorithm; import org.sinekartads.model.oid.SinekartaDsObjectIdentifiers; import org.sinekartads.util.DNParser; import org.sinekartads.util.HexUtils; import org.sinekartads.util.TemplateUtils; import org.sinekartads.util.x509.X509Utils; import org.sinekartads.utils.JSONUtils; public class SignCMSonAlfresco extends BaseIntegrationTC { static final DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); static Logger tracer = Logger.getLogger(SignCMSonAlfresco.class); private static final String SOURCE_NAME = "pippo.txt"; private static final int PORT = 8080; private static final String HOST_NAME = "localhost"; // private static final String HOST_NAME = "jeniasrv014.jenia.it"; private static final String USER = "admin"; private static final String PWD = "admin"; @Test public void test() throws Exception { if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { Security.addProvider(new BouncyCastleProvider()); } SignNOApplet applet = new SignNOApplet(); try { // Main options boolean applyMark = true; boolean useFakeSmartCard = true; String driver; String scPin; if (useFakeSmartCard) { driver = "fake"; scPin = "123"; } else { driver = "libbit4ipki.so"; scPin = "18071971"; } // Test products String[] aliases; String alias; X509Certificate certificate; X509Certificate[] certificateChain; byte[] fingerPrint; byte[] digitalSignature; // Communication unities DocumentDTO[] documents; String jsonResp; SkdsDocumentDetailsResponse detailsResp; SkdsPreSignResponse preSignResp; SkdsPostSignResponse postSignResp; AppletResponseDTO appletResponse; SignatureDTO emptySignatureDTO; SignatureDTO chainSignatureDTO; SignatureDTO digestSignatureDTO; SignatureDTO signedSignatureDTO; SignatureDTO finalizedSignatureDTO; VerifyDTO verifyDTO; // Init the applet try { AppletRequestDTO req = new AppletRequestDTO(); req.setDriver(driver); appletResponse = applet.selectDriver(req); } catch (Exception e) { tracer.error("error during the applet initialization", e); throw e; } // Login with the smartCard try { AppletRequestDTO req = new AppletRequestDTO(); req.setDriver(driver); req.setPin(scPin); appletResponse = applet.login(req); aliases = (String[]) JSONUtils.deserializeJSON(String[].class, extractJSON(appletResponse)); } catch (Exception e) { tracer.error("error during the applet login", e); throw e; } // Choose the signing alias StringBuilder buf = new StringBuilder(); for (String a : aliases) { buf.append(a).append(" "); } alias = aliases[0]; tracer.info(String.format("available aliases: %s", buf)); tracer.info(String.format("signing alias: %s", alias)); // Load the certificate chain from the applet try { AppletRequestDTO req = new AppletRequestDTO(); req.setDriver(driver); req.setPin(scPin); req.setAlias(alias); appletResponse = applet.selectCertificate(req); certificate = (X509Certificate) X509Utils.rawX509CertificateFromHex(extractJSON(appletResponse)); tracer.info(String.format("certificate: %s", certificate)); certificateChain = new X509Certificate[] { certificate }; } catch (Exception e) { tracer.error("error during the certificate selection", e); throw e; } // FindRefByName String sourceRef = null; try { SkdsFindRefByNameRequest req = new SkdsFindRefByNameRequest(); req.setName(SOURCE_NAME); SkdsFindRefByNameResponse findResp = postJsonRequest(req, SkdsFindRefByNameResponse.class); if (ResultCode.valueOf(findResp.getResultCode()) == ResultCode.SUCCESS) { sourceRef = findResp.getNodeRef(); } else { throw new Exception(findResp.getMessage()); } } catch (Exception e) { tracer.error("error during the pre sign phase", e); throw e; } // DocumentDetails try { // String sourceRef = getNodeRefId("pippo.txt"); SkdsDocumentDetailsRequest req = new SkdsDocumentDetailsRequest(); req.setNodeRefs(new String[] { sourceRef }); // req.setNodeRefs ( new String[] {SOURCE_REF} ); detailsResp = postJsonRequest(req, SkdsDocumentDetailsResponse.class); if (ResultCode.valueOf(detailsResp.getResultCode()) == ResultCode.SUCCESS) { documents = detailsResp.documentsFromBase64(); } else { throw new Exception(detailsResp.getMessage()); } String fileName = documents[0].getBaseDocument().getFileName(); if (applyMark) { documents[0].setDestName(fileName + ".p7m.tsd"); } else { documents[0].setDestName(fileName + ".p7m"); } } catch (Exception e) { tracer.error("error during the pre sign phase", e); throw e; } // empty signature - initialized with the SHA256withRSA and RSA algorithms emptySignatureDTO = new SignatureDTO(); emptySignatureDTO.setSignAlgorithm(conf.getSignatureAlgorithm().getName()); emptySignatureDTO.setDigestAlgorithm(conf.getDigestAlgorithm().getName()); emptySignatureDTO.signCategoryToString(SignCategory.CMS); // Add to the empty signature the timeStamp request if needed TimeStampRequestDTO tsRequestDTO = new TimeStampRequestDTO(); if (applyMark) { tsRequestDTO.timestampDispositionToString(SignDisposition.TimeStamp.ENVELOPING); tsRequestDTO.messageImprintAlgorithmToString(DigestAlgorithm.SHA256); tsRequestDTO.nounceToString(BigInteger.TEN); tsRequestDTO.setTsUrl("http://ca.signfiles.com/TSAServer.aspx"); } emptySignatureDTO.setTimeStampRequest(tsRequestDTO); // chain signature - contains the certificate chain chainSignatureDTO = TemplateUtils.Instantiation.clone(emptySignatureDTO); chainSignatureDTO.certificateChainToHex(certificateChain); documents[0].setSignatures(new SignatureDTO[] { chainSignatureDTO }); // PreSign phase - join the content with the certificate chain and evaluate the digest try { SkdsPreSignRequest req = new SkdsPreSignRequest(); req.documentsToBase64(documents); preSignResp = postJsonRequest(req, SkdsPreSignResponse.class); if (ResultCode.valueOf(preSignResp.getResultCode()) == ResultCode.SUCCESS) { documents = preSignResp.documentsFromBase64(); digestSignatureDTO = documents[0].getSignatures()[0]; } else { throw new Exception(preSignResp.getMessage()); } } catch (Exception e) { tracer.error("error during the pre sign phase", e); throw e; } // signed signature - sign the digest with the smartCard to obtain the digitalSignature try { fingerPrint = digestSignatureDTO.getDigest().fingerPrintFromHex(); tracer.info(String.format("fingerPrint: %s", HexUtils.encodeHex(fingerPrint))); AppletRequestDTO req = new AppletRequestDTO(); req.setDriver(driver); req.setPin(scPin); req.setAlias(alias); req.setHexDigest(HexUtils.encodeHex(fingerPrint)); appletResponse = applet.signDigest(req); digitalSignature = HexUtils.decodeHex((String) extractJSON(appletResponse)); tracer.info(String.format("digitalSignature: %s", HexUtils.encodeHex(digitalSignature))); signedSignatureDTO = TemplateUtils.Instantiation.clone(digestSignatureDTO); signedSignatureDTO.digitalSignatureToHex(digitalSignature); documents[0].getSignatures()[0] = signedSignatureDTO; } catch (Exception e) { tracer.error("error during the digital signature evaluation", e); throw e; } // PostSign phase - add the digitalSignature to the envelope and store the result into the JCLResultDTO try { SkdsPostSignRequest req = new SkdsPostSignRequest(); req.documentsToBase64(documents); postSignResp = postJsonRequest(req, SkdsPostSignResponse.class); if (ResultCode.valueOf(postSignResp.getResultCode()) == ResultCode.SUCCESS) { documents = postSignResp.documentsFromBase64(); finalizedSignatureDTO = documents[0].getSignatures()[0]; } else { throw new Exception(postSignResp.getMessage()); } } catch (Exception e) { tracer.error("error during the envelope generation", e); throw e; } // // Verify phase - load the envelope content and verify the nested signature // try { // jsonResp = signatureService.verify ( envelopeHex, null, null, VerifyResult.VALID.name() ); // verifyDTO = extractResult ( VerifyDTO.class, jsonResp ); // } catch(Exception e) { // tracer.error("error during the envelope verification", e); // throw e; // } // // // finalized signature - enveloped signed and eventually marked, not modifiable anymore // try { // verifyResult = (VerifyInfo) converter.toVerifyInfo( verifyDTO ); // } catch(Exception e) { // tracer.error("unable to obtain the verifyInfo from the DTO", e); // throw e; // } // // try { // for(VerifiedSignature < ?, ?, VerifyResult, ?> verifiedSignature : verifyResult.getSignatures() ) { // tracer.info(String.format ( "signature validity: %s", verifiedSignature.getVerifyResult().name() )); // tracer.info(String.format ( "signature type: %s", verifiedSignature.getSignType().name() )); // tracer.info(String.format ( "disposition: %s", verifiedSignature.getDisposition().name() )); // tracer.info(String.format ( "digest algorithm: %s", verifiedSignature.getDigest().getAlgorithm().name() )); // tracer.info(String.format ( "finger print: %s", HexUtils.encodeHex(verifiedSignature.getDigest().getFingerPrint()) )); // tracer.info(String.format ( "counter signature: %s", verifiedSignature.isCounterSignature() )); // tracer.info(String.format ( "signature algorithm: %s", verifiedSignature.getSignAlgorithm().name() )); // tracer.info(String.format ( "digital signature: %s", HexUtils.encodeHex(verifiedSignature.getDigitalSignature()) )); // tracer.info(String.format ( "reason: %s", verifiedSignature.getReason() )); // tracer.info(String.format ( "signing location: %s", verifiedSignature.getLocation() )); // tracer.info(String.format ( "signing time: %s", formatDate(verifiedSignature.getSigningTime()) )); // tracer.info(String.format ( "\n ")); // tracer.info(String.format ( "signing certificate chain: ")); // for ( X509Certificate cert : verifiedSignature.getRawX509Certificates() ) { // showCertificate(cert); // } // if ( verifiedSignature.getTimeStamps() != null ) { // tracer.info(String.format ( "\n ")); // tracer.info(String.format ( "timestamps: ")); // for ( TimeStampInfo mark : verifiedSignature.getTimeStamps() ) { // tracer.info(String.format ( "timestamp validity: %s", mark.getVerifyResult().name() )); // tracer.info(String.format ( "timestamp authority: %s", mark.getTsaName() )); // tracer.info(String.format ( "timestamp authority: %s", mark.getTsaName() )); // tracer.info(String.format ( "message imprint alg: %s", mark.getMessageInprintInfo().getAlgorithm().name() )); // tracer.info(String.format ( "message imprint: %s", HexUtils.encodeHex(mark.getMessageInprintInfo().getFingerPrint()) )); // tracer.info(String.format ( "digest algorithm: %s", mark.getDigestAlgorithm().name() )); // tracer.info(String.format ( "digital signature: %s", HexUtils.encodeHex(mark.getDigitalSignature()) )); // tracer.info(String.format ( "signature algorithm: %s", mark.getSignAlgorithm().name() )); // tracer.info(String.format ( "timestamp certificate: ")); // for ( X509Certificate cert : mark.getRawX509Certificates() ) { // showCertificate(cert); // } // } // } // } // } catch(Exception e) { // tracer.error("unable to print the verify results", e); // throw e; // } // } finally { applet.close(); } } private String extractJSON(AppletResponseDTO resp) throws Exception { String json; if (resp.checkSuccess()) { json = resp.getResult(); } else { StringBuilder buf = new StringBuilder(); for (FieldErrorDTO fieldError : resp.getFieldErrors()) { for (String errorMessage : fieldError.getErrors()) { buf.append(String.format("fieldError - %s: %s\n", fieldError.getField(), errorMessage)); } } for (ActionErrorDTO actionError : resp.getActionErrors()) { buf.append(String.format("actionError - %s\n", actionError.getErrorMessage())); } throw new Exception(buf.toString()); } return json; } private void showCertificate(X509Certificate certificate) { Map<String, String> dns = DNParser.parse(certificate.getSubjectDN()); tracer.info(String.format("subject: %s", dns.get(SinekartaDsObjectIdentifiers.dn_commonName))); tracer.info(String.format("country: %s", dns.get(SinekartaDsObjectIdentifiers.dn_countryName))); tracer.info(String.format("organization: %s", dns.get(SinekartaDsObjectIdentifiers.dn_organizationName))); tracer.info(String.format("organization unit: %s", dns.get(SinekartaDsObjectIdentifiers.dn_organizationUnitName))); tracer.info(String.format("not before: %s", formatDate(certificate.getNotBefore()))); tracer.info(String.format("not after: %s", formatDate(certificate.getNotAfter()))); dns = DNParser.parse(certificate.getIssuerDN()); tracer.info(String.format("issuer: %s", dns.get(SinekartaDsObjectIdentifiers.dn_commonName))); } private String formatDate(Date date) { if (date == null) return ""; return dateFormat.format(date); } public static <SkdsResponse extends BaseResponse> SkdsResponse postJsonRequest(BaseRequest request, Class<SkdsResponse> responseClass) throws IllegalStateException, IOException { SkdsResponse response = null; InputStream respIs = null; DefaultHttpClient httpclient = null; try { HttpHost targetHost = new HttpHost(HOST_NAME, PORT, "http"); httpclient = new DefaultHttpClient(); httpclient.getCredentialsProvider().setCredentials( new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials(USER, PWD)); AuthCache authCache = new BasicAuthCache(); BasicScheme basicAuth = new BasicScheme(); authCache.put(targetHost, basicAuth); BasicHttpContext localcontext = new BasicHttpContext(); localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache); HttpPost httppost = new HttpPost("/alfresco/service" + request.getJSONUrl() + ".json?requestType=json"); String req = request.toJSON(); ByteArrayEntity body = new ByteArrayEntity(req.getBytes()); httppost.setEntity(body); HttpResponse resp = httpclient.execute(targetHost, httppost, localcontext); HttpEntity entityResp = resp.getEntity(); respIs = entityResp.getContent(); response = TemplateUtils.Encoding.deserializeJSON(responseClass, respIs); EntityUtils.consume(entityResp); // } catch(Exception e) { // String message = e.getMessage(); // if ( StringUtils.isBlank(message) ) { // message = e.toString(); // } // tracer.error(message, e); // throw new RuntimeException(message, e); } finally { if (httpclient != null) { httpclient.getConnectionManager().shutdown(); } IOUtils.closeQuietly(respIs); } return response; } }