Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
Коллеги, доброго дня. Имеется серверное приложение, которое валидирует подпись в формате 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 трансформация. Как с этим бороться?
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
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));
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
Коллеги, если кто знает решение, прошу помочь :)
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
Коллеги из техподдержки, неужели никто не знает ответа на вопрос? :)
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 4,003 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Крипто-Про Сказал(а) «Спасибо»: 21 раз Поблагодарили: 714 раз в 674 постах
|
Здравствуйте. Проблема, скорее всего, в этих строках: Автор: AIvanov ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) 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>);
? |
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
Автор: afev ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) Здравствуйте. Проблема, скорее всего, в этих строках: Автор: AIvanov ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) 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>);
? Если не передавать документ на сервер и проверять подпись на клиенте (не используя приведенные вами строки кода), то подпись верифицируется - все ок. Но наша система построена так, что клиент должен отправить подписанный запрос на сервер.
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
Автор: AIvanov ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) Автор: afev ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) Здравствуйте. Проблема, скорее всего, в этих строках: Автор: AIvanov ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) 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>);
? Если не передавать документ на сервер и проверять подпись на клиенте (не используя приведенные вами строки кода), то подпись верифицируется - все ок. Но наша система построена так, что клиент должен отправить подписанный запрос на сервер. То есть наша система - небольшой аналог СМЭВа
|
|
|
|
Статус: Сотрудник
Группы: Участники
Зарегистрирован: 06.12.2008(UTC) Сообщений: 4,003 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Крипто-Про Сказал(а) «Спасибо»: 21 раз Поблагодарили: 714 раз в 674 постах
|
Тогда Автор: afev ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным. |
|
|
|
|
Статус: Участник
Группы: Участники
Зарегистрирован: 31.08.2017(UTC) Сообщений: 13 ![Российская Федерация Российская Федерация](/forum2/Content/images/flags/RU.png) Откуда: Москва
|
Автор: afev ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) Тогда Автор: afev ![Перейти к цитате Перейти к цитате](/forum2/Themes/soclean/icon_latest_reply.gif) Попробуйте вывести отдельно проверяемый документ, совпадает ли он с подписанным. Полагаю, что не совпадает, так как digestValue разные.
|
|
|
|
Быстрый переход
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.
Important Information:
The Форум КриптоПро uses cookies. By continuing to browse this site, you are agreeing to our use of cookies.
More Details
Close