XML-подпись - Другое значение подписи в PHP?


Я хочу реализовать цифровую подпись XML в PHP. Я проверяю правильность подписи в этом верификаторе.

Я получаю неверное значение подписи, поэтому я собираюсь шаг за шагом объяснить, что я делаю, и, пожалуйста, исправьте то, что я делаю неправильно.

XML, который я хочу подписать (без новых строк):

<root>
    <node1>test</node1>
    <node2 attr="value" />
</root>

Сначала я канонизирую XML, а затем хэширую его с помощью sha256, что дает правильный дайджест ценность.

Второй , создание XML-элемента SignedInfo и его канонизация (без новых строк):

<SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></CanonicalizationMethod>
    <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"></SignatureMethod>
    <Reference URI="">
        <Transforms>
            <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></Transform>
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"></DigestMethod>
        <DigestValue>EdtGJKqTvnmb0Z72M8ZxTO6Jv2jyXOohMgxVKe2Gkbo=</DigestValue>
    </Reference>
</SignedInfo>

Наконец, подпись элемента SignedInfo с использованием RSA-SHA256. Это та часть, которая дает неверный результат.

Подпись вычисляется с использованием следующих строк кода:

openssl_sign($c14nSignedInfo,$signature,$privateKey,"sha256WithRSAEncryption");
$signature = base64_encode($signature);

Но это дает неверное значение подписи, как указано в верификаторе . Если я подпишу один и тот же XML в C#, используя один и тот же закрытый ключ, я получу правильная подпись. Итак, что я делаю не так? Что я упускаю? Ясно, что я подписываю не то, что нужно, но что я должен подписать тогда? Должен ли я хэшировать элемент SignedInfo перед его подписанием?

Это мой окончательный результат (что неверно):

<root><node1>test</node1><node2 attr="value" /><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>EdtGJKqTvnmb0Z72M8ZxTO6Jv2jyXOohMgxVKe2Gkbo=</DigestValue></Reference></SignedInfo><SignatureValue>cqkvNxWf8Z03K01SQFk/J5Z7F/l8scSFpRECCknTH840rUm2L9lKHC8UF/SGKJ4LoVxOmYKJHyq0Dx8j6shTXTK1Abm0a3Ty3IP/V0Roj+3EApq4Hwr7VOpvZjcToQj1snuUtgPZFJ6pxPWdYJ5hZhxm0C+mDMlOCgcTuWP7UIDNQ3CSC1GMcKESEkxsfEAzIXNh9wHoIY2e2HnedceFzOsJLPaLnltd1qhewJvqYCq7M1gD8e+Hv5Lyo+wG7ipvxvhAQ4Ui+BAOD9mROzSQaiirrxg6nC/dMJyWketTjKwEprZDm5BOoMoJC+kb2PvShfXrdRgA/ezWZHIaT0mLGQ==</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>nENZ+u9FZ5DSDlFRZ+0f0tZ2Kvl6QY+cjUzSc89fhixKFuexGJQcEvCrs67x8QcgwxZCuoWHk/Cdh8qd3x0EZaC+ZoZ+AF7ofoxWPHioZ86CIuxhI4Zgk0bHWibSKx8Z7EIXVrQ1nM2OvX9CdM9iVjM0yfn1ohdd1o4EKmRBbJQf6kCZMTbCdOdr8UI0xGUMjjaZN6+vGj3VYoxlQXXi11NMHDlxsCyyyjBjyCvewnTerkXAomwf92xV77siOn1VZD2/YwWarv1Hk/0WtW1c6QGj0VNd4EbzUqvMtnkzY3301hz5MRqvPiPNez9tWMaawDzbMrGGkwbF2ivVAW3LHQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></root>

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

<root><node1>test</node1><node2 attr="value" /><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" /><SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /><DigestValue>EdtGJKqTvnmb0Z72M8ZxTO6Jv2jyXOohMgxVKe2Gkbo=</DigestValue></Reference></SignedInfo><SignatureValue>OzQtkphZ+eg8JnVHzf8BVZpUZ/xMFQJhkmw5j4h2+eu8PAJh8Z9mRZH5uN/hfPFgkByBTshS/VWDNyWyF6TclQRSc8m89L8sCBQhKqGxZKjCd7V8XUIXgRgh2+Zl1JZQ/hD36XESEPazFyQ26KWq+T+m1Tc541Rv3mklfOKv2qBOqZLd/n/nRnGhFJYMp6PtPMNk/BezosGaQFUu/IhSI5tiud5ia4qETk/1G1eXAXmE4RbnVMefkysarTjizJYkGRqW10f0cF0trGxbCPyohMMfb2msnYiQfZXZd0tW41mMpH0R0AHFeC7RPxK2GzxRMRJCkNeWe65brneUtUSHzA==</SignatureValue><KeyInfo><KeyValue><RSAKeyValue><Modulus>nENZ+u9FZ5DSDlFRZ+0f0tZ2Kvl6QY+cjUzSc89fhixKFuexGJQcEvCrs67x8QcgwxZCuoWHk/Cdh8qd3x0EZaC+ZoZ+AF7ofoxWPHioZ86CIuxhI4Zgk0bHWibSKx8Z7EIXVrQ1nM2OvX9CdM9iVjM0yfn1ohdd1o4EKmRBbJQf6kCZMTbCdOdr8UI0xGUMjjaZN6+vGj3VYoxlQXXi11NMHDlxsCyyyjBjyCvewnTerkXAomwf92xV77siOn1VZD2/YwWarv1Hk/0WtW1c6QGj0VNd4EbzUqvMtnkzY3301hz5MRqvPiPNez9tWMaawDzbMrGGkwbF2ivVAW3LHQ==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue></KeyValue></KeyInfo></Signature></root>

Чтобы проверить оба результата или получить более подробную информацию, просто скопируйте их здесь и нажмите "Проверить подпись".

Author: GregaMohorko, 2017-02-02

2 answers

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

Итак, канонизированный элемент SignedInfo теперь выглядит так (без новых строк):

<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
    ...
</SignedInfo>

Таким образом, после подписания этого элемента SignedInfo значение подписи является правильным.

 1
Author: GregaMohorko, 2017-02-05 13:21:15

На всякий случай: вы также можете использовать метод C14N, который является частью DOM PHP.

Может быть что-то вроде этого для вашего примера:

$xml = new DOMDocument();
$xml->load('file.xml);
// Here, PHP takes care of canonicalization
$c14nSignedInfo = $xml->getElementsByTagName('SignedInfo')->C14N();
// From here, it's your own code:
openssl_sign($c14nSignedInfo, $signature, $privateKey, 'sha256WithRSAEncryption');
$signature = base64_encode($signature);
 1
Author: Sebastian, 2017-12-01 03:57:54