Ключевое слово в защите информации
КЛЮЧЕВОЕ СЛОВО
в защите информации
Получить ГОСТ TLS-сертификат для домена (SSL-сертификат)
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

2 Страницы12>
Опции
К последнему сообщению К первому непрочитанному
Offline AIvanov  
#1 Оставлено : 16 сентября 2017 г. 15:01:56(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

Коллеги, доброго дня. Имеется серверное приложение, которое валидирует подпись в формате XMLDSIG, отправленную клиентом.

Валидация происходит следующим образом.

Код:

        StringWriter request = new StringWriter();
        JAXBContext requestContext = JAXBContext.newInstance(Request.class);
        Marshaller requestMarshaller = requestContext.createMarshaller();
        requestMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        requestMarshaller.marshal(parameters, request);

        org.apache.xml.security.Init.init();
        JCPXMLDSigInit.init();

        // Загружаем документ для проверки.
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().parse(new ByteArrayInputStream(request.toString().getBytes()));

        // Ищем элемент Signature.
        NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");

        if (nl.getLength() == 0) {
            throw new Exception("Cannot find Signature element");
        }

        // Создаем DOM XMLSignatureFactory для разбора документа с XMLSignature.
        String providerName = "ru.CryptoPro.JCPxml.dsig.internal.dom.XMLDSigRI";

        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",
                (Provider) Class.forName(providerName).newInstance());

        // Проверяем все подписи.
        for (int i = 0; i < nl.getLength(); i++) {

            // Создаем DOMValidateContext и задаем KeySelector для поиска
            // KeyValue или X509Data в контексте документа.
            DOMValidateContext valContext = new DOMValidateContext(
                    new X509CertificateSelector(),
                    nl.item(i));

            valContext.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", "JCP");

            // Разбор XMLSignature.
            XMLSignature signature = fac.unmarshalXMLSignature(valContext);

            // Проверка подписи XMLSignature.
            boolean coreValidity = signature.validate(valContext);

            // Вывод статуса проверки.
            if (!coreValidity) {

                System.out.println(String.format("Signature %s failed core validation", i));

                boolean sv = signature.getSignatureValue().validate(valContext);
                System.out.println(String.format("Signature %s validation status: %s", i, sv));

                // Првоерка статуса каждого Reference.
                Iterator it = signature.getSignedInfo().getReferences().iterator();

                for (int j = 0; it.hasNext(); j++) {

                    boolean refValid = ((Reference) it.next()).validate(valContext);
                    System.out.println(String.format("Signature %s ref['%s'] validity status: %s",
                            i, j, refValid));
                }
            }
            else {
                System.out.println(String.format("Signature %s passed core validation", i));
            }

            if (!coreValidity) {
                throw new Exception("Invalid signature detected");
            }

        }



Но, к сожалению, подпись не валидируется.

Signature 0 failed core validation
Signature 0 validation status: true
Signature 0 ref['0'] validity status: false


Полагаю, что при маршаллинге, сериализации, десериализации и т.д. немного меняются сами данные (добавляются, удаляются пробелы отступы), что в итоге приводит к изменению digestValue и по этой причине не проходит валидация. При подписании используется xml-exc-c14n трансформация.

Как с этим бороться?
Offline AIvanov  
#2 Оставлено : 16 сентября 2017 г. 15:04:57(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

PS. Для подписания запроса используется следующий код.

Код:

        
        org.apache.xml.security.Init.init();
        JCPXMLDSigInit.init();

        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setNamespaceAware(true);
        Document doc = dbFactory.newDocumentBuilder().parse(new ByteArrayInputStream(xmlFileData));

        String providerName = "ru.CryptoPro.JCPxml.dsig.internal.dom.XMLDSigRI";

        final XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance(
                "DOM", (Provider) Class.forName(providerName).newInstance());

        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();

        XPathExpression expr = xpath.compile(String.format("//*[@" + ID_NAME + "='%s']", ID));
        NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);

        if (nodes.getLength() == 0) {
            throw new Exception("Can't find node with " + ID_NAME + ": " + ID);
        }

        NodeList callerInformationSystemSignatureNodes =
                (NodeList) xpath.compile("//*[local-name()='CallerInformationSystemSignature']").evaluate(doc, XPathConstants.NODESET);

        if (callerInformationSystemSignatureNodes.getLength() == 0) {
            throw new Exception("Can't find CallerInformationSystemSignature node");
        }

        Node callerInformationSystemSignatureNode = callerInformationSystemSignatureNodes.item(0);

        String referenceURI = "#" + ID;

        KeyStore keyStore = KeyStore.getInstance(JCP.HD_STORE_NAME);
        keyStore.load(null, null);

        IXAdESConfig container = XmlContainer.createContainer(keyType);


        PrivateKey privateKey = (PrivateKey) keyStore.getKey(
                    keyStoreAlias,
                    keyStorePassword.toCharArray());

        X509Certificate cert = (X509Certificate) keyStore.getCertificate(keyStoreAlias);


        List<Transform> transformList = new ArrayList<>();
        Transform transformC14N =
            sigFactory.newTransform(Transforms.TRANSFORM_C14N_EXCL_WITH_COMMENTS, (XMLStructure) null);
        transformList.add(transformC14N);


        Reference ref = sigFactory.newReference(referenceURI,
                sigFactory.newDigestMethod(container.getDigestMethod(), null),
                transformList, null, null);

        SignedInfo signedInfo = sigFactory.newSignedInfo(
                sigFactory.newCanonicalizationMethod(
                        CanonicalizationMethod.EXCLUSIVE, (C14NMethodParameterSpec) null),
                sigFactory.newSignatureMethod(container.getSignatureMethod(), null),
                Collections.singletonList(ref)
        );

        KeyInfoFactory keyInfoFactory = sigFactory.getKeyInfoFactory();

        X509Data x509d = keyInfoFactory.newX509Data(Collections.singletonList(cert));

        KeyInfo keyInfo = keyInfoFactory.newKeyInfo(Collections.singletonList(x509d));


        DOMSignContext dsc = new DOMSignContext(privateKey, callerInformationSystemSignatureNode);

        //if (sigType == SignatureType.SIGN_BY_ID && nodeToSign != null) {
        //    dsc.setIdAttributeNS((Element) nodeToSign, null, ID_NAME);
        //} // if

        dsc.setProperty("org.jcp.xml.dsig.internal.dom.SignatureProvider", provider);

        XMLSignature signature = sigFactory.newXMLSignature(signedInfo, keyInfo);

        signature.sign(dsc);

        OutputStream os = new FileOutputStream(outputFile);
        Transformer trans = TransformerFactory.newInstance().newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
Offline AIvanov  
#3 Оставлено : 17 сентября 2017 г. 15:50:57(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

Коллеги, если кто знает решение, прошу помочь :)
Offline AIvanov  
#4 Оставлено : 19 сентября 2017 г. 12:57:32(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

Коллеги из техподдержки, неужели никто не знает ответа на вопрос? :)
Offline AIvanov  
#5 Оставлено : 21 сентября 2017 г. 12:08:54(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

UP
Offline Евгений Афанасьев  
#6 Оставлено : 21 сентября 2017 г. 12:33:28(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,926
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 691 раз в 652 постах
Здравствуйте.
Проблема, скорее всего, в этих строках:
Автор: AIvanov Перейти к цитате
JAXBContext requestContext = JAXBContext.newInstance(Request.class);
Marshaller requestMarshaller = requestContext.createMarshaller();
requestMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
requestMarshaller.marshal(parameters, request);

Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным. Нельзя ли после подписи сохранить документ в файл и перед проверкой выполнить только
Код:

dbf.newDocumentBuilder().parse(<signed-xml-file>);

?
Offline AIvanov  
#7 Оставлено : 21 сентября 2017 г. 12:40:54(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

Автор: afev Перейти к цитате
Здравствуйте.
Проблема, скорее всего, в этих строках:
Автор: AIvanov Перейти к цитате
JAXBContext requestContext = JAXBContext.newInstance(Request.class);
Marshaller requestMarshaller = requestContext.createMarshaller();
requestMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
requestMarshaller.marshal(parameters, request);

Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным. Нельзя ли после подписи сохранить документ в файл и перед проверкой выполнить только
Код:

dbf.newDocumentBuilder().parse(<signed-xml-file>);

?


Если не передавать документ на сервер и проверять подпись на клиенте (не используя приведенные вами строки кода), то подпись верифицируется - все ок.
Но наша система построена так, что клиент должен отправить подписанный запрос на сервер.
Offline AIvanov  
#8 Оставлено : 21 сентября 2017 г. 12:42:13(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

Автор: AIvanov Перейти к цитате
Автор: afev Перейти к цитате
Здравствуйте.
Проблема, скорее всего, в этих строках:
Автор: AIvanov Перейти к цитате
JAXBContext requestContext = JAXBContext.newInstance(Request.class);
Marshaller requestMarshaller = requestContext.createMarshaller();
requestMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
requestMarshaller.marshal(parameters, request);

Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным. Нельзя ли после подписи сохранить документ в файл и перед проверкой выполнить только
Код:

dbf.newDocumentBuilder().parse(<signed-xml-file>);

?


Если не передавать документ на сервер и проверять подпись на клиенте (не используя приведенные вами строки кода), то подпись верифицируется - все ок.
Но наша система построена так, что клиент должен отправить подписанный запрос на сервер.


То есть наша система - небольшой аналог СМЭВа
Offline Евгений Афанасьев  
#9 Оставлено : 21 сентября 2017 г. 13:08:34(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 3,926
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 20 раз
Поблагодарили: 691 раз в 652 постах
Тогда
Автор: afev Перейти к цитате
Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным.


Offline AIvanov  
#10 Оставлено : 21 сентября 2017 г. 13:25:46(UTC)
AIvanov

Статус: Участник

Группы: Участники
Зарегистрирован: 31.08.2017(UTC)
Сообщений: 13
Российская Федерация
Откуда: Москва

Автор: afev Перейти к цитате
Тогда
Автор: afev Перейти к цитате
Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным.




Полагаю, что не совпадает, так как digestValue разные.
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Guest
2 Страницы12>
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.