Я использую xmlseclibs, чтобы попытаться подписать документ SOAP, но он, похоже, не канонизирует вещи одинаково, в зависимости от того, подписываю ли я или проверяю.
Я приведу вам пример. Это XML, который я пытаюсь подписать:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header/> <soapenv:Body> <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" IssueInstant="2010-02-04T15:27:43Z" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a"> <samlp:Status> <samlp:StatusCode Value="samlp:Requester"/> </samlp:Status> </samlp:Response> </soapenv:Body> </soapenv:Envelope>
Я получил код, работающий в PHP, чтобы подписать его, используя комбинацию открытых ключей и сертификатов секретного ключа, и, похоже, это сработало. Он добавил элемент <ds:Signature>
со всеми необходимыми материалами, и он выглядел великолепно. Но затем я протестировал его, сразу же попытавшись проверить его после его подписания, опять же с помощью xmlseclibs (и сертификата открытого ключа), но проверка не прошла. Таким образом, одна и та же библиотека кода выполняет как подпись, так и проверку, но по некоторым причинам эти два процесса не согласны.
Я добавил некоторый код отладки в xmlseclibs, чтобы узнать, что он делает, и я понял, что причина, по которой он подпишет ключ, и ключ проверки, который он придумал, различны, потому что он канонизирует вещи по-разному в двух ситуациях. Когда я говорю ему, чтобы подписать элемент <samlp:Response>
, это каноническая форма, которую он подписывает (я добавил новые строки здесь для удобства чтения):
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"> <samlp:Status> <samlp:StatusCode Value="samlp:Requester"> </samlp:StatusCode> </samlp:Status> </samlp:Response>
Однако, когда он идет, чтобы проверить подпись, это каноническая форма, которую он вычисляет для проверки (опять же, я добавил новые строки здесь):
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a"> <samlp:Status> <samlp:StatusCode Value="samlp:Requester"> </samlp:StatusCode> </samlp:Status> </samlp:Response>
Итак, как вы можете видеть, в этой версии отсутствует атрибут xmlns:saml
из элемента <samlp:Response>
, а первый – нет. (Обратите внимание, что это отличается от атрибута xmlns:samlp
, который включен в оба.) Это выглядит довольно явно как ошибка в xmlseclibs, но тем не менее это тот, который я был бы счастлив исправить, если бы я только знал, какая каноническая форма была правильный. Следует ли исключить этот атрибут исключительной канонизацией? Или он должен быть включен? Какая из них является правильной исключительной канонической формой?
Вы неправильно создаете документ DOM и пытаетесь использовать недопустимое дерево в памяти. Либо сериализуйте и используйте сериализованный результат, либо правильно создайте объявления пространства имен в дереве, прежде чем пытаться подписать. Дополнительную информацию см. В отчете об ошибке: http://code.google.com/p/xmlseclibs/issues/detail?id=6
Неправильная каноническая форма!
Подписывающий XML имеет объявление пространства имен, которое появляется после атрибутов пространства имен, что нарушает правило порядка документа:
Узлы пространства имен имеют меньшую позицию порядка документа, чем узлы атрибутов.
В верификационном XML отсутствует узел пространства имен saml
. Canonicalisation не удаляет узлы пространства имен только потому, что не существует дочернего контента, который ссылается на них. Он удаляет избыточные узлы пространства имен (т. Е. Пространства имен, которые уже действуют на родителя).
Я не знаю достаточно о xmlseclibs, чтобы сказать, почему это происходит, но это определенно неправильно по обоим показателям. FWIW функция c14n на моем DOM здесь говорит:
<samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2010-02-04T15:27:43Z" MajorVersion="1" MinorVersion="1" ResponseID="pfxe85313e6-e688-299a-df06-30f55e24f65a"> <samlp:Status> <samlp:StatusCode Value="samlp:Requester"></samlp:StatusCode> </samlp:Status> </samlp:Response>
eta: Я просто посмотрел на xmlseclibs.php
в SVN, и для этого нет простого решения, так как его нынешний подход в корне ошибочен. Он пытается создать «canonicalised» DOM, а затем сериализует его с помощью простого старого saveXML()
. Поскольку существуют правила сериализации C14N об атрибутных порядках и символьных saveXML
которые saveXML
не обещает следовать, нет никакого способа, которым это может работать.