/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * Copyright (c) 2013, MPL CodeInside http://codeinside.ru */ package ru.codeinside.gses.activiti; import com.vaadin.ui.Form; import org.osgi.framework.ServiceReference; import ru.codeinside.adm.AdminServiceProvider; import ru.codeinside.gses.activiti.forms.FormID; import ru.codeinside.gses.activiti.forms.Signatures; import ru.codeinside.gses.cert.NameParts; import ru.codeinside.gses.cert.X509; import ru.codeinside.gses.webui.CertificateInvalid; import ru.codeinside.gses.webui.CertificateReader; import ru.codeinside.gses.webui.CertificateVerifier; import ru.codeinside.gses.webui.CertificateVerifyClientProvider; import ru.codeinside.gses.webui.Flash; import ru.codeinside.gses.webui.components.sign.SignApplet; import ru.codeinside.gses.webui.components.sign.SignAppletListener; import ru.codeinside.gses.webui.form.DataAccumulator; import ru.codeinside.gses.webui.form.FormOvSignatureSeq; import ru.codeinside.gses.webui.form.FormSpSignatureSeq; import ru.codeinside.gses.webui.form.ProtocolUtils; import ru.codeinside.gses.webui.osgi.Activator; import ru.codeinside.gws.api.Client; import ru.codeinside.gws.api.ClientProtocol; import ru.codeinside.gws.api.CryptoProvider; import ru.codeinside.gws.api.Enclosure; import ru.codeinside.gws.api.Server; import ru.codeinside.gws.api.ServerProtocol; import ru.codeinside.gws.api.ServiceDefinition; import ru.codeinside.gws.api.Signature; import ru.codeinside.gws.api.WrappedAppData; import ru.codeinside.gws.api.XmlSignatureInjector; import javax.xml.namespace.QName; import javax.xml.soap.SOAPMessage; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.nio.charset.Charset; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.List; import java.util.logging.Logger; public class SignatureProtocol implements SignAppletListener { private static final long serialVersionUID = 1L; final private FormID formID; final private String fieldId; final private String[] ids; final private byte[][] blocks; final private boolean[] files; final private byte[][] signs; final private String caption; final private Form form; final private DataAccumulator dataAccumulator; public SignatureProtocol(FormID formID, String fieldId, String caption, byte[][] blocks, boolean[] files, String[] ids, Form form, DataAccumulator dataAccumulator) { this.formID = formID; this.fieldId = fieldId; this.caption = caption; this.form = form; this.blocks = blocks; this.files = files; this.ids = ids; this.dataAccumulator = dataAccumulator; signs = new byte[blocks.length][]; } public SignatureProtocol(FormID formID, String fieldId, String caption, byte[][] blocks, boolean[] files, String[] ids, Form form) { this(formID, fieldId, caption, blocks, files, ids, form, null); } @Override public void onLoading(SignApplet signApplet) { } @Override public void onNoJcp(SignApplet signApplet) { form.removeItemProperty(fieldId); ReadOnly field = new ReadOnly("В вашей операционной системе требуется установить КриптоПРО JCP", false); field.setCaption(caption); form.addField(fieldId, field); } @Override public void onCert(SignApplet signApplet, X509Certificate certificate) { boolean ok = false; String errorClause = null; try { boolean link = AdminServiceProvider.getBoolProperty(CertificateVerifier.LINK_CERTIFICATE); if (link) { byte[] x509 = AdminServiceProvider.get().withEmployee(Flash.login(), new CertificateReader()); ok = Arrays.equals(x509, certificate.getEncoded()); } else { ok = true; } CertificateVerifyClientProvider.getInstance().verifyCertificate(certificate); } catch (CertificateEncodingException e) { } catch (CertificateInvalid err) { errorClause = err.getMessage(); ok = false; } if (ok) { signApplet.block(1, blocks.length); } else { form.removeItemProperty(fieldId); NameParts subject = X509.getSubjectParts(certificate); String fieldValue = (errorClause == null) ? "Сертификат " + subject.getShortName() + " отклонён" : errorClause; ReadOnly field = new ReadOnly(fieldValue, false); field.setCaption(caption); form.addField(fieldId, field); } } @Override public void onBlockAck(SignApplet signApplet, int i) { logger().fine("AckBlock:" + i); if (1 <= i && i <= blocks.length) { signApplet.chunk(1, 1, blocks[i - 1]); } } @Override public void onChunkAck(SignApplet signApplet, int i) { logger().fine("AckChunk:" + i); if (1 <= i && i <= blocks.length) { blocks[i - 1] = null; } } @Override public void onSign(SignApplet signApplet, byte[] sign) { final int i = signApplet.getBlockAck(); logger().fine("done block:" + i); if (1 <= i && i <= blocks.length) { signs[i - 1] = sign; if (i < blocks.length) { signApplet.block(i + 1, blocks.length); } else { form.removeItemProperty(fieldId); NameParts subjectParts = X509.getSubjectParts(signApplet.getCertificate()); FormSignaturesField field2 = new FormSignaturesField(subjectParts.getShortName(), new Signatures(formID, signApplet.getCertificate(), ids, files, signs)); if (ids.length > 0 && ids[0].equals(FormSpSignatureSeq.SP_SIGN)) { Signatures spSignatures = (Signatures) field2.getValue(); dataAccumulator.setSpSignatures(spSignatures); if (dataAccumulator.getServiceName() != null) { linkSignaturesWithEnclosures(signApplet, spSignatures, toList(dataAccumulator.getClientRequest().enclosures)); if (dataAccumulator.getClientRequest().signRequired) { dataAccumulator.getClientRequest().appData = injectSignatureToAppData(spSignatures, dataAccumulator.getClientRequest().appData); } } else if (dataAccumulator.getRequestType() != null) { linkSignaturesWithEnclosures(signApplet, spSignatures, dataAccumulator.getServerResponse().attachmens); if (dataAccumulator.getServerResponse().signRequired) { dataAccumulator.getServerResponse().appData = injectSignatureToAppData(spSignatures, dataAccumulator.getServerResponse().appData); } } // если нет следующего шага, формируем сообщение и пишем clientRequest (или serverResponse для поставщика) в базу if (!dataAccumulator.isNeedOv()) { if (dataAccumulator.getClientRequest() != null) { buildClientRequest(); } else if (dataAccumulator.getServerResponse() != null) { buildServerResponse(); } } } else if (ids.length > 0 && ids[0].equals(FormOvSignatureSeq.OV_SIGN)) { Signatures ovSignatures = (Signatures) field2.getValue(); dataAccumulator.setOvSignatures(ovSignatures); injectSignatureToSoapHeader(dataAccumulator.getSoapMessage(), ovSignatures); if (dataAccumulator.getServiceName() != null) { dataAccumulator.getClientRequest().requestMessage = ProtocolUtils.getBytesFromSoapMessage(dataAccumulator.getSoapMessage()); } else if (dataAccumulator.getRequestType() != null) { dataAccumulator.getServerResponse().responseMessage = ProtocolUtils.getBytesFromSoapMessage(dataAccumulator.getSoapMessage()); } else { throw new IllegalStateException("Ошибка в маршруте"); } } else { Signatures signatures = field2.getValue() instanceof Signatures ? (Signatures) field2.getValue() : null; dataAccumulator.setSignatures(signatures); } field2.setCaption(caption); field2.setRequired(true); form.addField(fieldId, field2); } } } private List<Enclosure> toList(Enclosure[] enclosures) { if (enclosures != null) { return Arrays.asList(enclosures); } return null; } /** * Связать полученные подписи с вложениями * @param signApplet аплет подписания * @param spSignatures полученные сигнатуры */ private void linkSignaturesWithEnclosures(SignApplet signApplet, Signatures spSignatures, List<Enclosure> enclosures) { if (enclosures != null) { for (Enclosure e : enclosures) { String propId = e.code != null && !e.code.isEmpty() ? e.code : e.fileName; int signPos = spSignatures.findSign(propId); if (signPos > -1) { e.signature = new Signature(signApplet.getCertificate(), e.content, spSignatures.signs[signPos], getDigest(e.content), true); } } } } private String injectSignatureToAppData(Signatures spSignatures, String appData) { if (appData == null) { return null; } ServiceReference serviceReference = null; try { serviceReference = Activator.getContext().getServiceReference(XmlSignatureInjector.class.getName()); XmlSignatureInjector injector = (XmlSignatureInjector) Activator.getContext().getService(serviceReference); CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); InputStream in = new ByteArrayInputStream(spSignatures.certificate); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in); byte[] signatureValue = spSignatures.signs[0]; byte[] content = appData.getBytes(Charset.forName("UTF-8")); byte[] digest = getDigest(content); Signature signature = new Signature(cert, content, signatureValue, digest, true); WrappedAppData wrappedAppData = new WrappedAppData(appData, signature); return injector.injectSpToAppData(wrappedAppData); } catch (CertificateException e) { throw new RuntimeException("Injection signature to AppData error"); } finally { if (serviceReference != null) { Activator.getContext().ungetService(serviceReference); } } } private void injectSignatureToSoapHeader(SOAPMessage soapMessage, Signatures ovSignatures) { ServiceReference serviceReference = null; try { serviceReference = Activator.getContext().getServiceReference(XmlSignatureInjector.class.getName()); XmlSignatureInjector injector = (XmlSignatureInjector) Activator.getContext().getService(serviceReference); CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); InputStream in = new ByteArrayInputStream(ovSignatures.certificate); X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in); byte[] content = blocks[0]; byte[] signatureValue = ovSignatures.signs[0]; byte[] digest = getDigest(content); Signature signature = new Signature(cert, content, signatureValue, digest, true); injector.injectOvToSoapHeader(soapMessage, signature); } catch (CertificateException e) { throw new RuntimeException("Injection signature to SoapHeader error"); } finally { if (serviceReference != null) { Activator.getContext().ungetService(serviceReference); } } } private byte[] getDigest(byte[] signedContent) { ServiceReference cryptoProviderReference = null; byte[] digest = null; try { cryptoProviderReference = Activator.getContext().getServiceReference(CryptoProvider.class.getName()); if (cryptoProviderReference == null) { throw new IllegalStateException("Ошибка получения DigestValue: сервис CryptoProvider недоступен"); } CryptoProvider cryptoProvider = ProtocolUtils.getService(cryptoProviderReference, CryptoProvider.class); ByteArrayInputStream is = new ByteArrayInputStream(signedContent); digest = cryptoProvider.digest(is); } finally { if (cryptoProviderReference != null) { Activator.getContext().ungetService(cryptoProviderReference); } } return digest; } private void buildClientRequest() { ServiceReference reference = null; ServiceReference cryptoReference = null; try { reference = ProtocolUtils.getServiceReference(dataAccumulator.getServiceName(), Client.class); final Client client = ProtocolUtils.getService(reference, Client.class); cryptoReference = Activator.getContext().getServiceReference(CryptoProvider.class.getName()); final CryptoProvider crypto = (CryptoProvider) Activator.getContext().getService(cryptoReference); ClientProtocol clientProtocol = ProtocolUtils.getClientProtocol(client); SOAPMessage message = clientProtocol.createMessage(client.getWsdlUrl(), dataAccumulator.getClientRequest(), null, null); dataAccumulator.setSoapMessage(message); crypto.sign(message); dataAccumulator.getClientRequest().requestMessage = ProtocolUtils.getBytesFromSoapMessage(message); } catch (Exception e) { e.printStackTrace(); throw new IllegalStateException("Ошибка получения подготовительных данных: " + e.getMessage(), e); } finally { if (reference != null) { Activator.getContext().ungetService(reference); } if (cryptoReference != null) { Activator.getContext().ungetService(cryptoReference); } } } private void buildServerResponse() { ServiceReference reference = null; ServiceReference cryptoReference = null; try { String serviceName = ProtocolUtils.getServerName(dataAccumulator.getTaskId()); reference = ProtocolUtils.getServiceReference(serviceName, Server.class); final Server server = ProtocolUtils.getService(reference, Server.class); cryptoReference = Activator.getContext().getServiceReference(CryptoProvider.class.getName()); final CryptoProvider crypto = (CryptoProvider) Activator.getContext().getService(cryptoReference); List<Object> serviceInfo = ProtocolUtils.getQNameAndServicePort(server); QName qName = (QName) serviceInfo.get(0); ServiceDefinition.Port port = (ServiceDefinition.Port) serviceInfo.get(1); ServerProtocol serverProtocol = ProtocolUtils.getServerProtocol(server); SOAPMessage message = serverProtocol.createMessage( dataAccumulator.getServerResponse(), qName, //Service port, //Port null, //Log null ); dataAccumulator.setSoapMessage(message); crypto.sign(message); dataAccumulator.getServerResponse().responseMessage = ProtocolUtils.getBytesFromSoapMessage(message); } catch (RuntimeException e) { e.printStackTrace(); throw new IllegalStateException("Ошибка получения подготовительных данных: " + e.getMessage(), e); } finally { if (reference != null) { Activator.getContext().ungetService(reference); } if (cryptoReference != null) { Activator.getContext().ungetService(cryptoReference); } } } private Logger logger() { return Logger.getLogger(getClass().getName()); } }