Skip to content

Commit 3e1c2f9

Browse files
committed
-convert promises to callback for backwards compatibility
-fixed formatting -added async to README
1 parent 17bbd13 commit 3e1c2f9

File tree

3 files changed

+75
-40
lines changed

3 files changed

+75
-40
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,33 @@ Now do the signing. Note how we configure the signature to use the above algorit
365365

366366
You can always look at the actual code as a sample (or drop me a [mail](mailto:[email protected])).
367367

368+
## Asynchronous signing and verification
369+
370+
If the private key is not stored locally and you wish to use a signing server or Hardware Security Module (HSM) to sign documents you can create a custom signing algorithm that uses an asynchronous callback.
371+
372+
`````javascript
373+
function AsyncSignatureAlgorithm() {
374+
this.getSignature = function (signedInfo, signingKey, callback) {
375+
var signer = crypto.createSign("RSA-SHA1")
376+
signer.update(signedInfo)
377+
var res = signer.sign(signingKey, 'base64')
378+
//Do some asynchronous things here
379+
callback(null, res)
380+
}
381+
this.getAlgorithmName = function () {
382+
return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
383+
}
384+
}
385+
386+
SignedXml.SignatureAlgorithms["http://asyncSignatureAlgorithm"] = AsyncSignatureAlgorithm
387+
var sig = new SignedXml()
388+
sig.signatureAlgorithm = "http://asyncSignatureAlgorithm"
389+
sig.computeSignature(xml, opts, function(err){
390+
var signedResponse = sig.getSignedXml()
391+
})
392+
`````
393+
394+
The function `sig.checkSignature` may also use a callback if asynchronous verification is needed.
368395

369396
## X.509 / Key formats
370397
Xml-Crypto internally relies on node's crypto module. This means pem encoded certificates are supported. So to sign an xml use key.pem that looks like this (only the begining of the key content is shown):

lib/signed-xml.js

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ SignedXml.prototype.checkSignature = function(xml, callback) {
345345
var err = new Error("cannot validate signature since no key info resolver was provided")
346346
if (!callback){
347347
throw err
348-
}else{
348+
} else {
349349
callback(err)
350350
return
351351
}
@@ -356,7 +356,7 @@ SignedXml.prototype.checkSignature = function(xml, callback) {
356356
var err = new Error("key info provider could not resolve key info " + this.keyInfo)
357357
if (!callback){
358358
throw err
359-
}else{
359+
} else {
360360
callback(err)
361361
return
362362
}
@@ -367,21 +367,28 @@ SignedXml.prototype.checkSignature = function(xml, callback) {
367367
if (!this.validateReferences(doc)) {
368368
if (!callback){
369369
return false;
370-
}else{
370+
} else {
371371
callback(new Error('Could not validate references'))
372372
}
373373
}
374374

375-
var ret = this.validateSignatureValue(doc)
376-
if (ret instanceof Promise){
377-
ret.then((asyncValidateSig)=>{
378-
callback(null, asyncValidateSig)
379-
})
380-
}else{
381-
if (!ret) {
382-
return false;
375+
if (!callback){
376+
//Syncronous flow
377+
if (!this.validateSignatureValue(doc)) {
378+
return false
383379
}
384380
return true
381+
} else {
382+
//Asyncronous flow
383+
this.validateSignatureValue(doc, function (err, isValidSignature) {
384+
if (err) {
385+
this.validationErrors.push("invalid signature: the signature value " +
386+
this.signatureValue + " is incorrect")
387+
callback(err)
388+
} else {
389+
callback(null, isValidSignature)
390+
}
391+
})
385392
}
386393
}
387394

@@ -427,19 +434,19 @@ SignedXml.prototype.getCanonReferenceXml = function(doc, ref, node) {
427434
return this.getCanonXml(ref.transforms, node, c14nOptions)
428435
}
429436

430-
SignedXml.prototype.validateSignatureValue = function(doc) {
437+
SignedXml.prototype.validateSignatureValue = function(doc, callback) {
431438
var signedInfoCanon = this.getCanonSignedInfoXml(doc)
432439
var signer = this.findSignatureAlgorithm(this.signatureAlgorithm)
433-
var res = signer.verifySignature(signedInfoCanon, this.signingKey, this.signatureValue)
434-
if (!res) this.validationErrors.push("invalid signature: the signature value " +
440+
var res = signer.verifySignature(signedInfoCanon, this.signingKey, this.signatureValue, callback)
441+
if (!res && !callback) this.validationErrors.push("invalid signature: the signature value " +
435442
this.signatureValue + " is incorrect")
436443
return res
437444
}
438445

439-
SignedXml.prototype.calculateSignatureValue = function(doc) {
446+
SignedXml.prototype.calculateSignatureValue = function(doc, callback) {
440447
var signedInfoCanon = this.getCanonSignedInfoXml(doc)
441448
var signer = this.findSignatureAlgorithm(this.signatureAlgorithm)
442-
return this.signatureValue = signer.getSignature(signedInfoCanon, this.signingKey)
449+
this.signatureValue = signer.getSignature(signedInfoCanon, this.signingKey, callback)
443450
}
444451

445452
SignedXml.prototype.findSignatureAlgorithm = function(name) {
@@ -716,7 +723,7 @@ SignedXml.prototype.computeSignature = function(xml, opts, callback) {
716723
", must be any of the following values: " + validActions.join(", "));
717724
if (!callback){
718725
throw err;
719-
}else{
726+
} else {
720727
callback(err, null)
721728
return
722729
}
@@ -764,7 +771,7 @@ SignedXml.prototype.computeSignature = function(xml, opts, callback) {
764771
var err = new Error("the following xpath cannot be used because it was not found: " + location.reference);
765772
if (!callback){
766773
throw err
767-
}else{
774+
} else {
768775
callback(err, null)
769776
return
770777
}
@@ -788,30 +795,32 @@ SignedXml.prototype.computeSignature = function(xml, opts, callback) {
788795
var err = new Error("could not find SignedInfo element in the message")
789796
if (!callback){
790797
throw err
791-
}else{
798+
} else {
792799
callback(err)
793800
return
794801
}
795802
}
796803
signedInfoNode = signedInfoNode[0];
797804

798-
var ret = this.calculateSignatureValue(doc)
799-
if (ret instanceof Promise){
800-
ret.then((asyncSig)=>{
801-
this.signatureValue = asyncSig
802-
803-
signatureDoc.insertBefore(this.createSignature(prefix), signedInfoNode.nextSibling)
804-
this.signatureXml = signatureDoc.toString()
805-
this.signedXml = doc.toString()
806-
807-
if (callback) callback()
808-
}).catch(function(err){
809-
if (callback) callback(err)
810-
})
811-
}else{
805+
if (!callback){
806+
//Synchronous flow
807+
this.calculateSignatureValue(doc)
812808
signatureDoc.insertBefore(this.createSignature(prefix), signedInfoNode.nextSibling)
813809
this.signatureXml = signatureDoc.toString()
814810
this.signedXml = doc.toString()
811+
} else {
812+
//Asynchronous flow
813+
this.calculateSignatureValue(doc, (err, signature) => {
814+
if (err) {
815+
callback(err)
816+
} else {
817+
this.signatureValue = signature
818+
signatureDoc.insertBefore(this.createSignature(prefix), signedInfoNode.nextSibling)
819+
this.signatureXml = signatureDoc.toString()
820+
this.signedXml = doc.toString()
821+
callback()
822+
}
823+
})
815824
}
816825
}
817826

test/signature-unit-tests.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -477,13 +477,12 @@ module.exports = {
477477
"signer creates correct signature values using async callback": function (test) {
478478

479479
function DummySignatureAlgorithm() {
480-
this.getSignature = function (signedInfo, signingKey) {
481-
return new Promise((resolve, reject) => {
482-
var signer = crypto.createSign("RSA-SHA1")
483-
signer.update(signedInfo)
484-
var res = signer.sign(signingKey, 'base64')
485-
resolve(res)
486-
})
480+
this.getSignature = function (signedInfo, signingKey, callback) {
481+
var signer = crypto.createSign("RSA-SHA1")
482+
signer.update(signedInfo)
483+
var res = signer.sign(signingKey, 'base64')
484+
//Do some asynchronous things here
485+
callback(null, res)
487486
}
488487
this.getAlgorithmName = function () {
489488
return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"

0 commit comments

Comments
 (0)