Signature with file attachments
cholokla opened this issue ยท 10 comments
Hello,
I would like to sign XML document with references to the file attachments using browser.
Attachments are:
https://i.picsum.photos/id/360/536/111.jpg
https://i.picsum.photos/id/237/536/555.jpg
If I use dedicated signing software I can open XML file to sign, select attachments and result will contain file names with digests for every file, as shown below.
<xml> <test>123</test> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="ID-94100763-8da0-4023-b13f-58d9d046c244"> <ds:SignedInfo Id="ID-daa7f869-4d1c-415c-afbc-eee64c9d421d"> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference Id="ID-f6a916f3-b195-45b0-8c81-99b4a5b121d4" URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116"> <ds:XPath xmlns="http://uri.etsi.org/01903/v1.3.2#">not(ancestor-or-self::ds:Signature)</ds:XPath> </ds:Transform> <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>9nRkKviccL1aDWE6kLNsrUA9EZQoIEJfYv3Vm4cIaYg=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-1bd339a0-9a8b-49e8-8afc-13919c54304d" URI="111.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>A75NtFdNywCxe/W2KPL2XeP0iOUyWZy072xZKBDhCZs=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-e9cc3262-30b7-49e8-b8cb-f71857eb5220" URI="555.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>KXrbTTYzL3WDh0Ehb+OU+eDG2lkpkpA1uoA/FODtno8=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-67c3385a-d048-48a3-b323-243eb10f8395" Type="http://uri.etsi.org/01903#SignedProperties" URI="#ID-717a243b-71cc-4173-ae07-f680ddf48f76"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>8o2Lv+QVZ49bSr/iyPQB5leJXwwKrrejA76e6AwElrQ=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> ...
With your library I can add OptionsSignReference for every file (have file URL's) but the digest is not calculated (in fact it's the same as in the main element).
<xml> <test>456</test> <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="id-5a1ba3578966"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-0" URI="111.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-1" URI="555.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> <ds:Reference URI="#xades-id-5a1ba3578966" Type="http://uri.etsi.org/01903#SignedProperties"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>d4EJq8Ojca8oXyspPQ0QCOk6UArBU/GvV2uKOa+cDOY=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> ...
Is there a possiblity to automatically calculate digests for every file using http uri's or at least manually specify digests for every reference?
Regards,
cholo
Please try an updated version of xmldsigjs@next
See working example PeculiarVentures/xmldsigjs#44
Let me know if it works. I'll publish production version
Let me know if it works. I'll publish production version
Thanks for the extremely fast response :)
Could you please give me any clue how to download file via url on the frontend (Chrome/Firefox/IE11) and pass to the "crypto.subtle.digest" function - is that even possible?
Use fetch or XmlHttpRequest
Yeah, it seems to work perfectly, now I can calculate digest and set in the reference.
Please, update xadesjs library too.
Maybe I'm doing something wrong, but for XmlDSigJs I'm getting proper digests:
<ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference Id="ID-99e50a74-2b6b-433b-8ccd-570e50b8b337" URI="111.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>A75NtFdNywCxe/W2KPL2XeP0iOUyWZy072xZKBDhCZs=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-f8977bf2-aec7-42fc-8f08-e32b77f7c05c" URI="555.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>KXrbTTYzL3WDh0Ehb+OU+eDG2lkpkpA1uoA/FODtno8=</ds:DigestValue> </ds:Reference> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> </ds:SignedInfo>
but if I use XAdES - digests are the same:
<ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/> <ds:Reference Id="ID-f45f7041-457c-427d-99e4-669c69d83e49" URI="111.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> <ds:Reference Id="ID-a4dfcc6c-b9bf-47cd-8b88-0c2be88a28f4" URI="555.jpg"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> <ds:Reference URI=""> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>dGJZXYeN0uqOG5NB6O8UjKvQ1GHMtS7my/2Qm7QgDkw=</ds:DigestValue> </ds:Reference> <ds:Reference URI="#xades-id-5ecc4f25a357" Type="http://uri.etsi.org/01903#SignedProperties"> <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/> <ds:DigestValue>xgfLJoBdz27ne0Zz1d3f8viHYfsYatYYhQ6EONljQPI=</ds:DigestValue> </ds:Reference> </ds:SignedInfo>
Here is my code:
`function prepareSignDocumentsPromises() {
var x509Cert = stripPemHeaderFromCertificate(cryptoKey.cert);
var promises = []
for (var i = 0; i < _documents.length; ++i) {
if (_documents[i].isBase64) {
_documents[i].body = decodeB64(_documents[i].body);
_documents[i].isBase64 = false;
}
var referencesPromises = [];
if (_documents[i].attachmentsUris) {
for (var j = 0; j < _documents[i].attachmentsUris.length; ++j) {
(function(attachment) {
var refPromise = downloadAsBuffer(attachment).then(function(buffer) {
return crypto.subtle.digest("SHA-256", new Uint8Array(buffer)).then(function(digest) {
var ref = new XmlDSigJs.Reference();
var uri = attachment.replace(/\\/g, '/').substring((attachment.lastIndexOf('/') + 1), attachment.length);
ref.Id = "ID-" + uuidv4();
ref.Uri = uri;
ref.DigestMethod.Algorithm = XmlDSigJs.SHA256_NAMESPACE;
ref.DigestValue = new Uint8Array(digest);
return ref;
});
});
referencesPromises.push(refPromise);
})(_documents[i].attachmentsUris[j]);
}
}
(function(document) {
promises.push(Promise.all(referencesPromises).then(function(references) {
var xml = new XmlDSigJs.SignedXml();
// var xml = new XAdES.SignedXml();
for (var j = 0; j < references.length; ++j) {
xml.XmlSignature.SignedInfo.References.Add(references[j]);
}
signedXml.push(xml);
return xml.Sign(
{ name: "RSASSA-PKCS1-v1_5", hash: { name: "SHA-256" } },
cryptoKey.privateKey,
XmlDSigJs.Parse(document),
{
keyValue: cryptoKey.publicKey,
references: [ { hash: "SHA-256", transforms: ["enveloped"] } ],
x509: [x509Cert],
signingCertificate: x509Cert
}
);
}));
})(_documents[i].body);
}
return promises;
}`
@cholokla Please double-check deps
npm list xmldsigjs
It must be
โโโฌ xadesjs@2.0.16
โ โโโ xmldsigjs@2.0.28 deduped
โโโ xmldsigjs@2.0.28
Otherwise you've got 2 different versions of xmldsigjs
I'm signing inside the html page in the browser so I have:
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.7.0/polyfill.min.js" type="text/javascript"></script>
<script src="https://cdn.jsdelivr.net/npm/node-forge@0.7.0/dist/forge.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/xadesjs@2.0.16/build/xades.min.js" type="text/javascript"></script>
<script src="https://unpkg.com/xmldsigjs@2.0.28/build/xmldsig.min.js" type="text/javascript"></script>
I've even downloaded libs via npm and included as a static content on the page but same problem occurs when I use "new XAdES.SignedXml()" to create signing object.
For "new XmlDSigJs.SignedXml()" everything works perfect.
I see. The problem is that xadesjs
bundle includes xmldisgjs
Please try a new version of xadesjs@2.0.17
. Just published it
Wow, great, it's working now.
Best tech support ever!!! :D