Цифровая подпись в сообщении SOAP

Я пытаюсь создать SOAP-сообщение с подписью (алгоритм российского ГОСТ34.10-2001) на Java для некоторых государственных служб. Дело в том, что сервис мне говорит, что Подпись недействительна и я не вижу, где я ошибся. Контейнер ключей, из которого я читаю закрытый ключ и сертификат, действителен. Где что-то идет не так? Я понимаю, что мой вопрос довольно специфичен, но я все же надеюсь, что кто-то может указать мне путь.

update1:небольшое обновление: тело сообщения содержит несколько узлов и значений кириллицы (utf)-8 update2: Итак, я прочитал этот вопрос и попытался получить PrivateKey таким же образом и получил это исключение: java.lang.IllegalArgumentException: закрытый ключ алгоритм не соответствует алгоритму открытого ключа в сертификате конечного объекта

Вот код:

Здесь я маршалирую классы в тело SOAP:

try {
            MessageFactory mf = MessageFactory.newInstance();
            SOAPMessage sm = mf.createMessage();
            SOAPPart sp = sm.getSOAPPart();
            SOAPEnvelope envelope = sp.getEnvelope();

            QName bodyId = new QName("http://ws.unisoft/", "SendFullULRequest");

            SOAPBody sb = (SOAPBody) envelope.getBody();
            SOAPHeader sh = (SOAPHeader) envelope.getHeader();

            javax.xml.bind.JAXBContext jaxbCtx = javax.xml.bind.JAXBContext.newInstance(FullULRq.class);
            javax.xml.bind.Marshaller marshaller = jaxbCtx.createMarshaller();

            marshaller.marshal(new JAXBElement<FullULRq>(bodyId, FullULRq.class, fulr),
                    sm.getSOAPBody());

            sm.saveChanges();

Затем я вычисляю значение дайджеста:

ReferenceType rt2 = new ReferenceType();
            rt2.setURI("#body");
            ////Пункт 7
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            Source xmlSource = new DOMSource(sm.getSOAPBody());
            Result outputTarget = new StreamResult(outputStream);
            try {
                Transformer transformer = TransformerFactory.newInstance().newTransformer();
                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
                transformer.setOutputProperty(OutputKeys.INDENT, "no");
                transformer.transform(xmlSource, outputTarget);
                Init.init();

                Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
                final ByteArrayInputStream is = new ByteArrayInputStream(canon.canonicalize(outputStream.toByteArray()));


                rt2.setDigestValue(computeDigestWithStream(is));
            } catch (Exception e) {
                e.printStackTrace();
            }

С помощью этого метода:

public static byte[] computeDigestWithStream(ByteArrayInputStream stream) throws Exception {
    final MessageDigest digest =
            MessageDigest.getInstance("GOST3411");

    // processing data
    final DigestInputStream digestStream =
            new DigestInputStream(stream, digest);
    while (digestStream.available() != 0) {
        digestStream.read();
    }

И, наконец, я генерирую подпись из блока (в котором элемент присутствует):

        ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
        Source xmlSource2 = new DOMSource(sm.getSOAPBody());
        Result outputTarget2 = new StreamResult(outputStream2);
        Transformer transformer = TransformerFactory.newInstance().newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.INDENT, "no");
        transformer.transform(xmlSource2, outputTarget2);
        Init.init();
        Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
        InputStream is2 = new ByteArrayInputStream(outputStream2.toByteArray());
        byte[] bb = canon.canonicalize(outputStream2.toByteArray());
        byte[] signval = sign("CryptoProSignature", key, bb);

Метод знака():

public static byte[] sign(String algorithmName, PrivateKey privateKey, byte[] data) throws Exception {
        final Signature sig = Signature.getInstance(algorithmName);
        sig.initSign(privateKey);
        sig.update(data);
        return sig.sign();
    }

И если это уместно, вот как я читаю privateKey из контейнера:

 KeyStore ks = KeyStore.getInstance("FloppyStore");

        String passwd = "*";
        String kalias = null; 

        ks.load(null, null);

        Enumeration enum1 = ks.aliases();
        for (; enum1.hasMoreElements();) {
            String tAlias = (String) enum1.nextElement();
            if (ks.isKeyEntry(tAlias)) {
                kalias = tAlias;
            }
            System.out.println(tAlias);
        }


        PrivateKey key = (PrivateKey) ks.getKey(kalias, passwd.toCharArray());

Спасибо!


person mikh    schedule 12.04.2012    source источник
comment
Правильно ли указан keytool -list Path_to_your_Floppystore.jks ваш закрытый ключ? Сохраняли ли вы пароль для хранилища ключей и закрытого ключа одинаковыми (рекомендуется -›)? Почему бы не использовать библиотеку WSS4J для ваших целей?   -  person Aydin K.    schedule 13.04.2012
comment
Привет, у меня такая же проблема. Сервер SOAP не примет мою подпись, какие бы элементы я ни изменил. Я уверен, что Ключи и Серт. в порядке, как вы. Я думаю, что мы что-то упускаем в канонизации или атрибутах. Можете ли вы опубликовать более подробную информацию о выведенном XML?   -  person Filippo Mazza    schedule 13.08.2012