2010-12-11 2 views
8

Я могу успешно выполнить проверку ссылочной ссылки (канонизировать каждый ссылочный элемент -> SHA1 -> Base64 -> проверить, совпадает ли это с содержимым DigestValue), но я терпеть неудачу с проверкой SignatureValue. Вот SignedInfo канонизировать и хэш:Ручная проверка XML-подписи

<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> 
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod> 
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod> 
<ds:Reference URI="#element-1-1291739860070-11803898"> 
    <ds:Transforms> 
    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform> 
    </ds:Transforms> 
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod> 
    <ds:DigestValue>d2cIarD4atw3HFADamfO9YTKkKs=</ds:DigestValue> 
</ds:Reference> 
<ds:Reference URI="#timestamp"> 
    <ds:Transforms> 
    <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform> 
    </ds:Transforms> 
    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod> 
    <ds:DigestValue>YR/fZlwJdw+KbyP24UYiyDv8/Dc=</ds:DigestValue> 
</ds:Reference> 
</ds:SignedInfo> 

Атер удаления всех пробелов между тегами (и поэтому получать весь элемент на одной линии), я получаю эту sha1 переваривать (в Base64):

6l26iBH7il/yrCQW6eEfv/VqAVo =

Теперь я ожидаю, чтобы найти тот же переваривать после расшифровки содержания SignatureValue, но я получаю Differente и больше значение:

MCEwCQYFKw4DAhoFAAQ U3M24VwKG02yUu6jlEH + u6R4N8Ig =

Вот некоторые Java-код для decyption:

 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();  
    DocumentBuilder builder = dbf.newDocumentBuilder(); 
    Document doc = builder.parse(new File(inputFilePath)); 
    NodeList nl = doc.getElementsByTagName("ds:SignatureValue"); 
    if (nl.getLength() == 0) { 
    throw new Exception("Cannot find SignatureValue element"); 
    } 
    String signature = "OZg96GMrGh0cEwbpHwv3KDhFtFcnzPxbwp9Xv0pgw8Mr9+NIjRlg/G1OyIZ3SdcOYqqzF4/TVLDi5VclwnjBAFl3SEdkyUbbjXVAGkSsxPQcC4un9UYcecESETlAgV8UrHV3zTrjAWQvDg/YBKveoH90FIhfAthslqeFu3h9U20="; 
    X509Certificate cert = X509Certificate.getInstance(new FileInputStream(<a file path>)); 
    PublicKey pubkey = cert.getPublicKey(); 
    Cipher cipher = Cipher.getInstance("RSA","SunJCE"); 
    cipher.init(Cipher.DECRYPT_MODE, pubkey); 
    byte[] decodedSignature = Base64Coder.decode(signature); 
    cipher.update(decodedSignature); 
    byte[] sha1 = cipher.doFinal(); 


    System.out.println(Base64Coder.encode(sha1)); 

Дело в том, что меня смущает многое, что два дайджесты имеют разный размер, но я, конечно, также необходимо получить точно такое же значение из двух расчетов. Какие-либо предложения? Спасибо.

+0

«Атер, удаляющий все промежутки между тегами» ... это правильно? Глядя на http://www.w3.org/TR/2001/REC-xml-c14n-20010315#Example-WhitespaceInContent, похоже, что вы удаляете слишком много пробелов. –

+0

Спасибо за ответ. Я понимаю вашу точку зрения, но, как я сказал в начале вопроса, я могу успешно выполнить проверку ссылок (две ссылки, это не может быть случайностью) одного и того же сообщения SOAP, и только путем удаления этих пространств, поэтому я должен предположить это верно. – Johnca

+0

Канонизация - это гораздо больше, чем удаление пробелов. Он обрабатывает проблемы с префиксом пространства имен, упорядочивание атрибутов и, как правило, все, что изменяет порядок байтов файла phisicaly (и, следовательно, хеш-дайджест), но не изменяет XML-информацию (== смысл полезной нагрузки XML) – m0sa

ответ

8

MCEwCQYFKw4DAhoFAAQU3M24VwKG02yUu6jlEH+u6R4N8Ig= является Base64 кодирование для DER-закодированные структуры ASN.1: а SEQUENCE содержащий первый AlgorithmIdentifier (в котором говорится, что это SHA-1, без каких-либо параметров, так как SHA-1 не принимает ни), то OCTET STRING, который содержит фактическое 20-байтовое значение. В шестнадцатеричном значении: dccdb8570286d36c94bba8e5107faee91e0df088.

Эта структура ASN.1 является частью стандартного механизма RSA signature. Вы используете RSA дешифрование для доступа к этой структуре, которая является нестандартной. На самом деле вам повезло получить что-либо вообще, поскольку RSA-шифрование и RSA-подпись - это два разных алгоритма. Так получилось, что они оба питаются одинаковыми парами ключей и что схемы подписи и шифрования «старого стиля» (например, «PKCS # 1 v1.5») используют аналогичные методы заполнения (аналогичные, но не идентичные; уже немного удивительно, что реализация Java RSA не задушила отладку подписи при использовании в режиме дешифрования).

В любом случае, 6l26iBH7il/yrCQW6eEfv/VqAVo= является кодировкой Base64 для 20-байтового значения, которое в шестнадцатеричном виде: ea5dba8811fb8a5ff2ac2416e9e11fbff56a015a. Это то, что вы получаете посредством хэширования структуры XML, которую вы показываете выше, после удаления всех пробелов между тегами. Удаление всех пробелов не надлежащая канонизация. Фактически, насколько мне известно, пробелы затрагиваются только между атрибутами, внутри тегов, но внешние пробелы должны сохраняться без изменений (кроме нормализации окончания строки [LF/CR + LF вещь]).

Значение, которое использовалось для генерации подписи (dccdb85...), может быть получено с помощью объекта XML, который вы показываете, и путем удаления ведущих пробелов. Чтобы быть ясным: вы копируете + вставляете XML в файл, а затем удаляете ведущие пробелы (от 0 до 3 пробелов) в каждой строке. Вы убедитесь, что все конечные линии используют один LF (0x0A байт), и вы удаляете конечный LF (тот сразу после </ds:SignedInfo>). Результирующий файл должен иметь длину 930 байт, а его SHA-1 - ожидаемое значение dccdb85....

+0

СПАСИБО за ясный и разрешающий ответ !!! Откуда взялась идея «удалить ведущие пространства»? В любом случае мне интересно, почему org.apache.xml.security .c14n.Canonicalizer не удаляет их и почему мне нужны два разных представления xml для двух задач: для проверки ссылок мне нужно удалить все пробелы между тегами, тогда как для проверки подписи я должен делать то, что вы написали. xml-сообщение было отправлено из развернутого сервлета JBoss и получено с помощью развернутой веб-службы JBoss. Может быть, JBoss выполняет нестандартную работу? – Johnca

+0

Я видел «удалить ведущие пробелы» на веб-странице, которая пытается объяснить канонизацию (я не помню (каноникализатор Apache корректен в том, что он не удаляет их). Так как пробелы являются неудобными, рекомендуется сначала создать XML без ny indentation (т.е. нет ведущего пространства). Я предполагаю, что исходный XML не имел ведущих пробелов, и они были добавлены в какой-то момент (_after_ signature computation) в качестве «помощника чтения» (который помещает подпись). –

0

Рассматривая конкретный XML-токен, я могу вам кое-что сказать.

  • Вы используете метод канонизации Exclusive XML Канонизация Version 1.0. Это очень ВАЖНО фактор в обеспечении того, что вы производите правильные значения дайджеста и подпись.

  • Вы, используя тот же метод канонизации как для вычисления эталонных дайджестов, а также для канонизации в SignedInfo перед производить подпись.

Спецификация Exclusive XML Canonicalizaiton версии 1.0 производится W3C и могут быть найдены в соответствующей W3C Recommendation. Если вы вычисляете свои значения вручную, убедитесь, что вы точно соответствуете спецификации, потому что канонизация является трудной задачей для правильного выбора, и очень важно сделать это правильно, иначе ваши значения будут неверными.

Я просто написал обширную статью, описывающую процесс проверки подписи XML. Статья находится по адресу my blog. Он описывает процесс гораздо более подробно, чем мой ответ, так как существует множество тонкостей для XML-подписи. Он также содержит ссылки на распространенные спецификации и RFC.

Смежные вопросы