Невозможно проверить подпись XML с помощью Apache Santuario 1.4.6 - PullRequest
2 голосов
/ 13 ноября 2011

Мне нужна помощь в решении проблемы с проверкой подписи XML с использованием библиотеки Java Apache Santuario версии 1.4.6.У меня есть решение клиент / сервер, где клиент подписывает документ DOM перед отправкой документа на сервер.Я применяю подпись к документу следующим образом:

public static void applySignature(X509Certificate cert, PrivateKey privateKey, Document doc)
{
    try
    {
        XMLSignature sig = new XMLSignature(doc, 
                                            "", 
                                            XMLSignature.ALGO_ID_SIGNATURE_RSA);

        sig.addResourceResolver(new XmlSignatureResolver());
        doc.getDocumentElement().appendChild(sig.getElement());

        Transforms transforms = new Transforms(doc);
        transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
        transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);

        sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);

        sig.addKeyInfo(cert);
        sig.addKeyInfo(cert.getPublicKey());

        sig.sign(privateKey);
    }
    catch (XMLSecurityException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Я проверяю подпись следующим образом:

public static boolean verifySignature(X509Certificate cert, Document doc)
{
    boolean validSignature = false;

    try
    {
        Element nscontext = createDSctx(doc, "ds", Constants.SignatureSpecNS); 

        // Remove any attributes of Signed Info
        Node signInfoNode = XPathAPI.selectSingleNode(doc, "//ds:SignedInfo", nscontext);

        int numAttributes = signInfoNode.getAttributes().getLength();
        if (numAttributes > 0)
        {
            for (int i = 0; i < numAttributes; i++)
            {
                String attrName = signInfoNode.getAttributes().item(0).getNodeName();
                signInfoNode.getAttributes().removeNamedItem(attrName);
            }    
        }

        Element sigElement = 
            (Element) XPathAPI.selectSingleNode(doc, "//ds:Signature", nscontext); 
        XMLSignature signature = new XMLSignature(sigElement, "");

        signature.setFollowNestedManifests(true); 
        signature.addResourceResolver(new XmlSignatureResolver());

        validSignature = signature.checkSignatureValue(cert);

        //  Remove the signature
        sigElement.getParentNode().removeChild(sigElement);            
    }
    catch (XMLSignatureException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (XMLSecurityException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    catch (TransformerException e)
    {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return validSignature;// validSignature;
}

Проблема, с которой я сталкиваюсь, заключается в том, что при проверке подписи на сервере (это работает на клиенте, если я проверяю сразу после применения подписи), я получаю следующее предупреждение:

2011-11-12 18:30:27 Ссылка [ПРЕДУПРЕЖДЕНИЕ] Ошибка проверки для URI ""
2011-11-12 18:30:27 Ссылка [WARN] Ожидаемый дайджест: EEl + J / jsY8Im2rgjsozBXRxkQjQ =
2011-11-12 18:30:27 Ссылка [WARN] Фактический дайджест: Y7C0HCjugZbegkZT4E8A7Bd4qm0 * 101*

Спасибо за помощь,
Эрни Берлисон

=============

Код, который я использую дляотправьте dom с клиента на сервер:

                // Use a Transformer for output
                TransformerFactory tFactory = TransformerFactory.newInstance();
                Transformer transformer = tFactory.newTransformer();
                transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
                transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
                transformer.setOutputProperty(OutputKeys.INDENT, "no");

                DOMSource source = new DOMSource(doc);
                StreamResult result = new StreamResult(m_SenderOutput);

                m_Logger.debug("Transforming...");
                transformer.transform(source, result);   
                m_SenderOutput.flush();
                m_Logger.debug("Transform complete...");
                m_ClientSocket.shutdownOutput();

Код, который читает dom на стороне сервера:

                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                dbf.setNamespaceAware(true);
                DocumentBuilder db = dbf.newDocumentBuilder();

                m_Logger.debug("Parsing Document");
                Document doc = db.parse(m_SenderInput);
                m_Logger.debug("Received DOM");   

DOM до применения подписи похож наследующее (данные зашифрованы до применения подписи):

<?xml version="1.0" encoding="UTF-8"?><SmMessageSet xmlns="urn:ccsds:recommendation:service_management:schema:sccs:R1.0" xmlns:ns2="urn:ccsds:recommendation:navigation:schema:ndmxml:R1.5"><xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Content"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/><ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"><xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/><xenc:CipherData><xenc:CipherValue>VosyFTcuAkzo6WPPLnnM2Nka+gpyD9r2cNy3fbSX8RjGg5dKktK9SGZAar5t3ci2mU6Nw9Ski2Td
g1WNei+kgns6vFET5Ff8m5/VIO24sBz30DPO5cAwfLax0slTjZWDRu7XXs/ORSK2PrB8B8qaO+me
W5iPLXjkkL4LnLwZfIvCSdG3JJoOTUhR6CstquTejRBLvTdvry8jB2RncjpV244eng7Bmk7HWcNd
Mz20DujfX14MTyKAQcVAgUhM9MpisveiDRdKYtXWCkma2NcUhpxqzjyPtyJtHVJQfaPZ2kla2NQV
DcMPUvmM+V0Y3kI5NBZq1vlIAg1i5JsZRniB+Q==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey></ds:KeyInfo><xenc:CipherData><xenc:CipherValue>8UCDr2ZzDvD5JczkPU7UnxRYBdxs6ZgL5s2ksHyn/FZvBVSwYh6o/Rnx41fnN6uygcylW++zoxSq
a9qcpuS8rFxtw6TtRzZeixJYBgZWVHp9NYiB4WbtZF6iR5EjaGKZdghUgCVtvKKbpbMQTTPRCBym
7HA2iQzNpGH1tcGegDB8+w3ALDP8QN5q3PG2uFBk880KXRozxAxKZVNKZfEZyat0fnzf6J8bTCac
n1lxV02jCWyz1/2Gd/jfo8B2BLXVMZWm0WiM7Z/uk4PFsTQjPmb1CD+E+7Oh8TRJzIqC1dyPQVV+
kgdoJbM/2sZka1VCuUzEIEQ1fhH+iUE0ymtuw+djwhfqDAow1pfRJOsak2cXzLoYO7mwqmIHoeaM
hN9IAtI/TfXDHNSL8ledhYT/ZL2gmNSR1Jze6JZPaXgqkmBEGVgqbzLex/5drxOf/DQVcugSnqEw
uHrikLsjU4jHozNg4PGidJNPCKLPgJaiLX1rgyo9N6pUDMVrNH+Tz1G7EFydzZOrZt+yY8Je17NL
ah8mBQb/S5zGD7642aDR4UmVQthD3LTMIG/oxbzMIh/OOcC432SZ+ShAvUD+bU+GDDdcOKzemLPB
EV6QLstFqonyHLSTQqgIMU5z2NxFpJIKRBClX09q5fOytaRVrGIZgJtOfuT4zFwjmwF66yuiQp0H
gD9O95A+ifmwe8k9KUsAO9Q8alxrXrqhptfsySCYDo2nSXbhSn5cKgsdK4jw5B6zsoQQZxJmzsYT
ZSbo0DhjAbZVszsU0HeTMRKRNlOABXAJPxSmqz2hT/wgYnWSMZt839swJyOZhaMuOUfShAP1iVo+
m5xM+zw7SnsAwFozNw==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData></SmMessageSet>

XML идентичен после applySignature и послеSignedInfo модифицируется в методе verifyysignature.Похоже, проблема связана со ссылочными элементами SignedInfo, когда я отправляю документ через сокет;каким-то образом преобразование, которое происходит во время проверки, добавляет 46 байтов, что приводит к сбою проверки.

Не уверен, откуда это происходит.У кого-нибудь есть идеи?

Ответы [ 3 ]

0 голосов
/ 17 ноября 2011

Проблема была не в SignedInfo, а в узле KeyInfo. К узлу KeyInfo добавлен атрибут пространства имен, которого не было при применении исходной подписи. Удаление атрибута KeyInfo перед проверкой значения подписи устраняет проблему, с которой я столкнулся.

0 голосов
/ 08 ноября 2013

краткий ответ: в исходный вопрос добавьте doc.normalizeDocument(); в начале applySignature, поэтому перед добавлением подписи.

больше информации:

Я знаю, что это старый вопрос, но у меня была похожая проблема, которая не была решена ни одним из ответов. На самом деле, я думаю, что один из ответов неправильный, он говорит, что проблема в проверке. Тем не менее, я считаю, что это в подписании! Я надеюсь, что использование моего опыта и решений поможет кому-то с подобной проблемой.

Я генерировал документ XML, а затем подписывал его. Я пытался подписать с Apache Santuario. Когда это не сработало, я переключился на javax.xml.crypto.dsig.

Оба эти метода генерировали XML-документы, которые были неправильно подписаны, когда я проверял их с помощью Santuario и внешних инструментов!

Первый пример подписанного XML, который я пытался сгенерировать:

<signed-envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="somenamespace" xsi:schemaLocation="someshemelocation">
   <object xml:id="object0">
      ...
   </object>
   <signatures>
      <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
         ...
         <SignedInfo>
            <Reference URI="#object0">
            ...
         </SignedInfo>
      </Signature>
   </signatures>
</signed-envelope>

Пространства имен signed-envelope имеют решающее значение! Все отлично работало без пространств имен. Но когда я добавил необходимое пространство имен в signed-envelope, подпись сгенерировала файл XML, который не удалось проверить. Также не с помощью внешнего инструмента (что означает, что подпись не удалась, а не проверка)!

Santuario предлагает отличные результаты отладки с помощью log4j. Эти выходные данные показали, что при проверке следующее пространство имен было добавлено к <object> и <SignedInfo>:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

Это правильный способ проверки! Один из ответов здесь предполагает, что это не правильно, и пытается это исправить, но на самом деле это правильно. Проблема здесь не в проверке, а в подписании!

Проблема в том, что Santuario показал, что это пространство имен НЕ было добавлено при подписании документа! Это заставило меня поверить, что что-то не так с Document объектом, который я сгенерировал. Мой XML-документ был сгенерирован с пространством имен, добавленным в корневой элемент, например:

rootElement.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:noNamespaceSchemaLocation", "some_namespace");

После долгих поисков я обнаружил, что doc.normalizeDocument() решил похожую проблему. Я попробовал, и все работает!
Я понятия не имею, почему doc.normalizeDocument() заставляет все работать, но теперь я могу правильно подписать и Apache Santuario, и javax.xml.crypto.dsig. Таким образом, они оба нуждаются в этом, чтобы подписать правильно.

0 голосов
/ 13 ноября 2011

Это не имеет прямого отношения к вашей ошибке, но позже приведет к ошибке: вы не должны удалять или изменять что-либо внутри элемента SignedInfo. Окончательное значение подписи вычисляется по дайджесту канонизированного элемента SignedInfo. Поэтому, если вы что-то там поменяете, прежде чем проверять подпись, вы обязательно сломаете это.

Относительно того, почему ваш дайджест документа является недействительным - это может иметь несколько причин, которые трудно проанализировать, просто угадав. Что могло бы помочь, если бы вы могли опубликовать неподписанный документ здесь, тогда я мог бы сказать вам, каково будет правильное значение дайджеста, по крайней мере ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...