Проверка XAdES не выполняется со ссылочным URI="" для документа с инструкцией по обработке таблицы стилей

Подписываемый мной документ выглядит так.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="CDA_PL_IG_1.3.1.xsl" type="text/xsl"?>
<ClinicalDocument></ClinicalDocument>

Я использую xadesjs чтобы подписать этот XML с помощью следующего кода:

const crypto = new Crypto();
xadesjs.Application.setEngine('NodeJS', crypto);

export async function sign(xml: string, { publicKey, privateKey }: any) {
    const hash = 'SHA-1';
    const alg = {
        name: 'RSASSA-PKCS1-v1_5',
        hash
    };
    const keyDer = pem2der(privateKey.toString());
    const key = await crypto.subtle.importKey('pkcs8', keyDer, alg, true, [ 'sign' ]);
    const parsed = xadesjs.Parse(xml.trim());
    const xadesXml = new xadesjs.SignedXml();
    const signature = await xadesXml.Sign(alg, key, parsed, {
        signingCertificate: preparePem(publicKey.toString()),
        references: [ { uri: '', hash, transforms: [ 'enveloped' ] } ],
        x509: [ preparePem(publicKey.toString()) ]
    });

    parsed.documentElement.appendChild(signature.GetXml()!);
    return parsed.toString();
}

function preparePem(pem: string) {
    return pem.replace(/-----(BEGIN|END)[\w\d\s]+-----/g, '').replace(/[\r\n]/g, '');
}

function pem2der(pem: string) {
    pem = preparePem(pem);
    return new Uint8Array(Buffer.from(pem, 'base64')).buffer;
}

Сгенерированная подпись действительна, только если я удалю объявление xml и инструкцию таблицы стилей. Таким образом, только подписание этого возвращает правильно подписанный документ:

<ClinicalDocument></ClinicalDocument>

Подписывая это

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="CDA_PL_IG_1.3.1.xsl" type="text/xsl"?>
<ClinicalDocument></ClinicalDocument>

ошибки с сообщением о том, что не весь документ подписан.

Я предполагаю, что проблема в URI=""ссылка. Он подписывает только<ClinicalDocument> и оставляет <?xml version> а также <?xml-stylesheet> без подписи.

Как мне все подписать?

1 ответ

Вам необходимо канонизировать (C14N) документ, прежде чем подписывать его. Я не могу комментировать использование xadesjs, но вот несколько общих советов.

Для подписи Xades вам необходимо вычислить дайджест сообщения, состоящий из трех частей, все из которых C14N-ed.

(1) полный документ, за исключением ds:Signature элемент - это дает вам дайджест-значение для URI="" ссылка.

(2) Подмножество xades:SignedPropertiesэлемент, который должен наследовать любые пространства имен от полного документа. Это дает значение дайджеста для ссылки SignedProperties.

(3) Последнее подмножество ds:SignedInfo элемент, который снова должен включать унаследованные пространства имен - это значение используется косвенно для вычисления значения подписи.

В <?xml version>всегда исключается. В<?xml-stylesheet>включается при вычислении значения дайджеста для подписи в оболочке (со ссылкой URI=""), но исключается, когда C14N-ing по двум подмножествам.

Вычислить преобразование C14n нетривиально. Я подключу сюда свою собственную утилиту канонизации, SC14N https://www.cryptosys.net/sc14n/.

Вы можете напрямую сгенерировать дайджест-значения следующим образом:

sc14n -d -x ds:Signature clindoc.xml
sc14n -d -s xades:SignedProperties clindoc.xml
sc14n -d -s ds:SignedInfo clindoc.xml

Чтобы увидеть вывод C14N-ed, опустите параметр -d

sc14n  -x ds:Signature clindoc.xml
<?xml-stylesheet href="CDA_PL_IG_1.3.1.xsl" type="text/xsl"?>
<ClinicalDocument ...>

Обратите внимание, что <xml-stylesheet строка включается в отдельную строку.

Другие вопросы по тегам