/* * 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.gws.signature.injector; import junit.framework.Assert; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.x509.X509V3CertificateGenerator; import org.junit.Before; import org.junit.Test; import ru.codeinside.gws.api.ClientRequest; import ru.codeinside.gws.api.Signature; import ru.codeinside.gws.api.WrappedAppData; import ru.codeinside.gws.api.XmlSignatureInjector; import ru.codeinside.gws.crypto.cryptopro.CryptoProvider; import ru.codeinside.gws.xml.normalizer.XmlNormalizerImpl; import javax.security.auth.x500.X500Principal; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPMessage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Security; import java.security.SignatureException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.security.spec.ECGenParameterSpec; import java.util.Date; public class InjectTest extends Assert { @Before public void setSecurityProvider() { Security.addProvider(new BouncyCastleProvider()); } @Test public void inject_sp_first() throws Exception { XmlSignatureInjector impl = new XmlSignatureInjectorImp(); ClientRequest request = new ClientRequest(); request.appData = "<rev:createRequestBean xmlns:rev=\"http://smev.gosuslugi.ru/rev110801\">" + "<Hello></Hello><rev:okato>11111111111</rev:okato><rev:requestType>558102100000</rev:requestType>" + "</rev:createRequestBean>"; request.signRequired = true; byte[] signedInfoBytes = impl.prepareAppData(request, false, new XmlNormalizerImpl(), new CryptoProvider()); assertTrue(signedInfoBytes.length > 0); X509Certificate certificate = genCertificate(genKeyPair()); byte[] content = request.appData.getBytes("UTF-8"); byte[] sign = {2, 3, 4, 5, 6, 7, 8}; byte[] digest = {1, 2, 3, 4, 5, 6, 7}; Signature signature = new Signature(certificate, content, sign, digest, true); String injected = impl.injectSpToAppData(new WrappedAppData(request.appData, signature)); assertTrue(injected.startsWith("<AppData Id=\"AppData\">" + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">")); assertFalse(injected.endsWith("</ds:Signature></ns:AppData>")); assertTrue("Is X509Certificate section present", injected.contains("X509Certificate")); } @Test public void inject_sp_last() throws Exception { XmlSignatureInjectorImp impl = new XmlSignatureInjectorImp(); ClientRequest request = new ClientRequest(); request.appData = "<rev:createRequestBean xmlns:rev=\"http://smev.gosuslugi.ru/rev110801\">" + "<Hello></Hello><rev:okato>11111111111</rev:okato><rev:requestType>558102100000</rev:requestType>" + "</rev:createRequestBean>"; request.signRequired = true; X509Certificate certificate = genCertificate(genKeyPair()); byte[] signedInfoBytes = impl.prepareAppData(request, true, new XmlNormalizerImpl(), new CryptoProvider()); assertTrue(signedInfoBytes.length > 0); byte[] content = request.appData.getBytes("UTF-8"); byte[] sign = {2, 3, 4, 5, 6, 7, 8}; byte[] digest = {1, 2, 3, 4, 5, 6, 7}; Signature signature = new Signature(certificate, content, sign, digest, true); String injected = impl.injectSpToAppData(new WrappedAppData(request.appData, signature)); assertFalse(injected.startsWith("<AppData Id=\"AppData\">" + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">")); assertTrue(injected.endsWith("</ds:Signature></AppData>")); assertTrue("Is X509Certificate section present", injected.contains("X509Certificate")); } @Test public void inject_ov_test() throws Exception { byte[] content = getPreparedResult().getBytes("UTF-8"); ByteArrayInputStream stream = new ByteArrayInputStream(content); final SOAPMessage message = MessageFactory.newInstance().createMessage(null, stream); X509Certificate certificate = genCertificate(genKeyPair()); byte[] sign = {2, 3, 4, 5, 6, 7, 8}; byte[] digest = {1, 2, 3, 4, 5, 6, 7}; Signature signature = new Signature(certificate, content, sign, digest, true); XmlSignatureInjectorImp impl = new XmlSignatureInjectorImp(); impl.injectOvToSoapHeader(message, signature); ByteArrayOutputStream out = new ByteArrayOutputStream(); message.writeTo(out); String result = out.toString("UTF-8"); assertTrue(result.contains(getResult()[0])); assertTrue(result.contains(getResult()[1])); } @Test public void prepare_soapMessage_test() throws Exception { byte[] source = getSource().getBytes("UTF-8"); ByteArrayInputStream stream = new ByteArrayInputStream(source); final SOAPMessage message = MessageFactory.newInstance().createMessage(null, stream); byte[] digest = {1, 2, 3, 4, 5, 6, 7}; XmlSignatureInjectorImp impl = new XmlSignatureInjectorImp(); impl.prepareSoapMessage(message, digest); ByteArrayOutputStream out = new ByteArrayOutputStream(); message.writeTo(out); String result = out.toString("UTF-8"); assertTrue(result.contains(getPreparedResult())); } private X509Certificate genCertificate(KeyPair pair) throws NoSuchAlgorithmException, CertificateEncodingException, NoSuchProviderException, InvalidKeyException, SignatureException { Date startDate = new Date(); Date expiryDate = new Date(startDate.getTime() + 10000); BigInteger serialNumber = new BigInteger("123456789"); X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); X500Principal dnName = new X500Principal("CN=Test CA Certificate"); certGen.setSerialNumber(serialNumber); certGen.setIssuerDN(dnName); certGen.setNotBefore(startDate); certGen.setNotAfter(expiryDate); certGen.setSubjectDN(dnName); certGen.setPublicKey(pair.getPublic()); certGen.setSignatureAlgorithm("GOST3411withECGOST3410"); return certGen.generate(pair.getPrivate(), "BC"); } private KeyPair genKeyPair() throws InvalidAlgorithmParameterException, NoSuchProviderException, NoSuchAlgorithmException { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ECGOST3410", "BC"); keyGen.initialize(new ECGenParameterSpec("GostR3410-2001-CryptoPro-A")); keyGen.initialize(new ECGenParameterSpec("GostR3410-2001-CryptoPro-A")); return keyGen.generateKeyPair(); } private String getSource() { return "<SOAP-ENV:Envelope " + "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " + "xmlns:smev=\"http://smev.gosuslugi.ru/rev120315\" " + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + "<SOAP-ENV:Header/>" + "<SOAP-ENV:Body wsu:Id=\"body\">" + "<SOAP-WS:putData xmlns:SOAP-WS=\"http://smev.gosuslugi.ru/rev120315\">" + "<smev:Message>" + "<smev:Sender>" + "<smev:Code>PNZR01581</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Sender>" + "<smev:Recipient>" + "<smev:Code>8201</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Recipient>" + "<smev:Originator>" + "<smev:Code>PNZR01581</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Originator>" + "<smev:ServiceName>PENZUniversalMVV</smev:ServiceName>" + "<smev:TypeCode>GSRV</smev:TypeCode>" + "<smev:Status>REQUEST</smev:Status>" + "<smev:Date>2015-06-26T00:38:59.798+03:00</smev:Date>" + "<smev:ExchangeType>1</smev:ExchangeType></smev:Message>" + "<smev:MessageData><smev:AppData>" + "<oep:result xmlns:oep=\"http://oep-penza.ru/com/oep\">" + "<oep:dataRow><oep:name>appData_addressRegister</oep:name><oep:value>г. Пенза ул. Попова 36</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_phone</oep:name><oep:value>+79023456789</oep:value></oep:dataRow><oep:dataRow>" + "<oep:name>appData_birthDay</oep:name><oep:value>12/03/1986</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_FIO</oep:name><oep:value>Иванов Иван Иванович</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_toOrganizationName</oep:name><oep:value>Оператор электронного правительства Пензы</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>procedureCode</oep:name><oep:value>123</oep:value></oep:dataRow>" + "<oep:params><oep:app_id>0</oep:app_id><oep:status_date>2015-06-26T00:38:59.798+03:00</oep:status_date></oep:params>" + "</oep:result></smev:AppData></smev:MessageData></SOAP-WS:putData></SOAP-ENV:Body></SOAP-ENV:Envelope>"; } //Добавляются блоки BinarySecurityToken и SignatureValue private String[] getResult() { String firstPart = "<SOAP-ENV:Envelope " + "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " + "xmlns:smev=\"http://smev.gosuslugi.ru/rev120315\" " + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + "<SOAP-ENV:Header>" + "<wsse:Security " + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " + "SOAP-ENV:actor=\"http://smev.gosuslugi.ru/actors/smev\">" + "<wsse:BinarySecurityToken " + "EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" " + "ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\" " + "wsu:Id=\"CertId\">"; String secondPart = "</wsse:BinarySecurityToken>" + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">" + "<ds:SignedInfo><ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>" + "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411\"/>" + "<ds:Reference URI=\"#body\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/></ds:Transforms>" + "<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#gostr3411\"/><ds:DigestValue>AQIDBAUGBw==</ds:DigestValue>" + "</ds:Reference></ds:SignedInfo>" + "<ds:SignatureValue>AgMEBQYHCA==</ds:SignatureValue>" + "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">" + "<SecurityTokenReference xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">" + "<Reference URI=\"#CertId\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\"/>" + "</SecurityTokenReference></KeyInfo></ds:Signature></wsse:Security></SOAP-ENV:Header>" + "<SOAP-ENV:Body wsu:Id=\"body\"><SOAP-WS:putData xmlns:SOAP-WS=\"http://smev.gosuslugi.ru/rev120315\">" + "<smev:Message>" + "<smev:Sender>" + "<smev:Code>PNZR01581</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Sender" + "><smev:Recipient>" + "<smev:Code>8201</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Recipient>" + "<smev:Originator>" + "<smev:Code>PNZR01581</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Originator>" + "<smev:ServiceName>PENZUniversalMVV</smev:ServiceName><smev:TypeCode>GSRV</smev:TypeCode><smev:Status>REQUEST</smev:Status>" + "<smev:Date>2015-06-26T00:38:59.798+03:00</smev:Date><smev:ExchangeType>1</smev:ExchangeType></smev:Message>" + "<smev:MessageData><smev:AppData><oep:result xmlns:oep=\"http://oep-penza.ru/com/oep\">" + "<oep:dataRow><oep:name>appData_addressRegister</oep:name><oep:value>г. Пенза ул. Попова 36</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_phone</oep:name><oep:value>+79023456789</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_birthDay</oep:name><oep:value>12/03/1986</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_FIO</oep:name><oep:value>Иванов Иван Иванович</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_toOrganizationName</oep:name><oep:value>Оператор электронного правительства Пензы</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>procedureCode</oep:name><oep:value>123</oep:value></oep:dataRow><oep:params><oep:app_id>0</oep:app_id>" + "<oep:status_date>2015-06-26T00:38:59.798+03:00</oep:status_date></oep:params></oep:result>" + "</smev:AppData></smev:MessageData></SOAP-WS:putData></SOAP-ENV:Body></SOAP-ENV:Envelope>"; String[] result = {firstPart, secondPart}; return result; } //добавляется блок Security private String getPreparedResult() { return "<SOAP-ENV:Envelope " + "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " + "xmlns:smev=\"http://smev.gosuslugi.ru/rev120315\" " + "xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" + "<SOAP-ENV:Header>" + "<wsse:Security " + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " + "SOAP-ENV:actor=\"http://smev.gosuslugi.ru/actors/smev\">" + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">" + "<ds:SignedInfo>" + "<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/>" + "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411\"/>" + "<ds:Reference URI=\"#body\"><ds:Transforms><ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\"/></ds:Transforms>" + "<ds:DigestMethod Algorithm=\"http://www.w3.org/2001/04/xmldsig-more#gostr3411\"/>" + "<ds:DigestValue>AQIDBAUGBw==</ds:DigestValue></ds:Reference></ds:SignedInfo>" + "<KeyInfo xmlns=\"http://www.w3.org/2000/09/xmldsig#\">" + "<SecurityTokenReference xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">" + "<Reference URI=\"#CertId\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\"/>" + "</SecurityTokenReference></KeyInfo></ds:Signature></wsse:Security></SOAP-ENV:Header>" + "<SOAP-ENV:Body wsu:Id=\"body\">" + "<SOAP-WS:putData xmlns:SOAP-WS=\"http://smev.gosuslugi.ru/rev120315\">" + "<smev:Message>" + "<smev:Sender>" + "<smev:Code>PNZR01581</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Sender>" + "<smev:Recipient>" + "<smev:Code>8201</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Recipient>" + "<smev:Originator>" + "<smev:Code>PNZR01581</smev:Code><smev:Name>Комплексная система предоставления государственных и муниципальных услуг Пензенской области</smev:Name>" + "</smev:Originator>" + "<smev:ServiceName>PENZUniversalMVV</smev:ServiceName>" + "<smev:TypeCode>GSRV</smev:TypeCode><smev:Status>REQUEST</smev:Status><smev:Date>2015-06-26T00:38:59.798+03:00</smev:Date>" + "<smev:ExchangeType>1</smev:ExchangeType></smev:Message>" + "<smev:MessageData><smev:AppData><oep:result xmlns:oep=\"http://oep-penza.ru/com/oep\">" + "<oep:dataRow><oep:name>appData_addressRegister</oep:name><oep:value>г. Пенза ул. Попова 36</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_phone</oep:name><oep:value>+79023456789</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_birthDay</oep:name><oep:value>12/03/1986</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_FIO</oep:name><oep:value>Иванов Иван Иванович</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>appData_toOrganizationName</oep:name><oep:value>Оператор электронного правительства Пензы</oep:value></oep:dataRow>" + "<oep:dataRow><oep:name>procedureCode</oep:name><oep:value>123</oep:value></oep:dataRow>" + "<oep:params><oep:app_id>0</oep:app_id><oep:status_date>2015-06-26T00:38:59.798+03:00</oep:status_date></oep:params></oep:result>" + "</smev:AppData></smev:MessageData></SOAP-WS:putData></SOAP-ENV:Body></SOAP-ENV:Envelope>"; } }