Статьи

Проверьте эту библиотеку цифровой подписи для Node.js

Get xml-crypto на github

Node.js не всегда имеет подходящие библиотеки для операций Xml. Когда такие библиотеки существуют, они не всегда кроссплатформенные (читай: работа на windows). Я только что опубликовал xml-crypto , первую библиотеку цифровых подписей xml для узла. В качестве бонуса эта библиотека написана на чистом javascript, поэтому она кроссплатформенная.

Что такое цифровая подпись Xml?
Там в ТЛ, др версия здесь . Суть в том, что dig-sig позволяет защитить контент от несанкционированного изменения, сообщая нам, кто создал этот контент и кто-либо изменил его с тех пор. Xml dig-sig — это особый вариант, в котором есть несколько интересных аспектов реализации.

Типичная подпись XML выглядит так:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
    <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
    <Reference URI="#_0">
      <Transforms>
        <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      </Transforms>
      <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
      <DigestValue>b5GCZ2xpP5T7tbLWBTkOl4CYupQ=</DigestValue>
    </Reference>
  </SignedInfo>
 <SignatureValue>PI2xGt3XrVcxYZ3...</SignatureValue>
  <KeyInfo>
  </KeyInfo>
</Signature>

Установка Xml-Crypto

Установить с помощью npm :

npm install xml-crypto

Необходимым условием является наличие openssl и его / bin для системного пути. Я использовал версию 1.0.1c, но она должна работать и на старых версиях.

Подписание документа XML

Используйте этот код:

var SignedXml = require('xml-crypto').SignedXml
      , FileKeyInfo = require('xml-crypto').FileKeyInfo
      , fs = require('fs')

var xml = "<library>" +
             "<book>" +
               "<name>Harry Potter</name>" +
             "</book>"
           "</library>"

var sig = new SignedXml()
sig.addReference("//*[local-name(.)='book']")
sig.signingKey = fs.readFileSync("client.pem")
sig.computeSignature(xml)
fs.writeFileSync("signed.xml", sig.getSignedXml())

Результат будет:

<library>
  <book Id="_0">
    <name>Harry Potter</name>
  </book>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
      <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
      <Reference URI="#_0">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <DigestValue>cdiS43aFDQMnb3X8yaIUej3+z9Q=</DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>vhWzpQyIYuncHUZV9W...[long base64 removed]...</SignatureValue>
  </Signature>
</library>

Примечание:

sig.getSignedXml () возвращает исходный документ XML с подписью, выдвинутой как последний дочерний элемент корневого узла (как указано выше). Это предполагает, что вы не подписываете корневой узел, а только подузел (ы), иначе это недопустимо. Если вы подписываете корневой узел, вызовите sig.getSignatureXml (), чтобы получить только часть подписи, и sig.getOriginalXmlWithIds (), чтобы получить исходный xml с атрибутами Id, добавленными в соответствующие элементы (необходимые для проверки).

Проверка подписанного документа

Вы можете использовать любой dom-парсер в своем коде (или ни один, в зависимости от вашего использования). В этом примере используется xmldom, поэтому вы должны сначала установить его:

npm install xmldom

Затем запустите:

var select = require('xml-crypto').xpath.SelectNodes
  , dom = require('xmldom').DOMParser
  , SignedXml = require('xml-crypto').SignedXml
  , FileKeyInfo = require('xml-crypto').FileKeyInfo
  , fs = require('fs')

var xml = fs.readFileSync("signed.xml").toString()
var doc = new dom().parseFromString(xml)
var signature = select(doc, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0]
var sig = new SignedXml()
sig.keyInfoProvider = new FileKeyInfo("client_public.pem")
sig.loadSignature(signature.toString())
var res = sig.checkSignature(xml)
if (!res) console.log(sig.validationErrors)

Примечание.

Для xml-crypto api требуется отдельно указать подпись xml («<Signature> … </ Signature>» в loadSignature) и подписанный xml (в checkSignature). Подписанный xml может содержать или не содержать подпись, но вы все равно должны предоставить подпись отдельно.

Поддерживаемые алгоритмы

В первом выпуске всегда используются следующие алгоритмы:

  • Эксклюзивная канонизация http://www.w3.org/2001/10/xml-exc-c14n#
  • Дайджесты SHA1 http://www.w3.org/2000/09/xmldsig#sha1
  • Алгоритм подписи RSA-SHA1 http://www.w3.org/2000/09/xmldsig#rsa-sha1

    Вы можете расширить xml-crypto с помощью других алгоритмов. Я скоро напишу об этом.

    Ключевые форматы

    Вам необходимо использовать отформатированные сертификаты .pem как для подписи, так и для проверки. Если у вас есть сертификаты pfx x.509 , есть простой способ конвертировать их в pem. Я напишу пост об этом в ближайшее время.

    Код

    Get xml-crypto на github