GithubHelp home page GithubHelp logo

node-saml / xml-crypto Goto Github PK

View Code? Open in Web Editor NEW
195.0 18.0 171.0 2.32 MB

Xml digital signature and encryption library for Node.js

License: MIT License

JavaScript 1.16% C# 7.33% Java 1.99% TypeScript 89.52%

xml-crypto's Introduction

xml-crypto

Build Gitpod Ready-to-Code

An xml digital signature library for node. Xml encryption is coming soon. Written in pure javascript!

For more information visit my blog or my twitter.

Install

Install with npm:

npm install xml-crypto

A pre requisite it to have openssl installed and its /bin to be on the system path. I used version 1.0.1c but it should work on older versions too.

Supported Algorithms

Canonicalization and Transformation Algorithms

Hashing Algorithms

Signature Algorithms

HMAC-SHA1 is also available but it is disabled by default

to enable HMAC-SHA1, call enableHMAC() on your instance of SignedXml.

This will enable HMAC and disable digital signature algorithms. Due to key confusion issues, it is risky to have both HMAC-based and public key digital signature algorithms enabled at same time.

You are able to extend xml-crypto with custom algorithms.

Signing Xml documents

When signing a xml document you can pass the following options to the SignedXml constructor to customize the signature process:

  • privateKey - [required] a Buffer or pem encoded String containing your private key
  • publicCert - [optional] a Buffer or pem encoded String containing your public key
  • signatureAlgorithm - [required] one of the supported signature algorithms. Ex: sign.signatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
  • canonicalizationAlgorithm - [required] one of the supported canonicalization algorithms. Ex: sign.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments"

Use this code:

var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

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

var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") });
sig.addReference({
  xpath: "//*[local-name(.)='book']",
  digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
  transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
sig.computeSignature(xml);
fs.writeFileSync("signed.xml", sig.getSignedXml());

The result will be:

<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>

Note:

If you set the publicCert and the getKeyInfoContent properties, a <KeyInfo></KeyInfo> element with the public certificate will be generated in the signature:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
  <SignedInfo>
    ...[signature info removed]...
  </SignedInfo>
  <SignatureValue>vhWzpQyIYuncHUZV9W...[long base64 removed]...</SignatureValue>
  <KeyInfo>
    <X509Data>
      <X509Certificate>MIIGYjCCBJagACCBN...[long base64 removed]...</X509Certificate>
    </X509Data>
  </KeyInfo>
</Signature>

For getKeyInfoContent, a default implementation SignedXml.getKeyInfoContent is available.

To customize this see customizing algorithms for an example.

Verifying Xml documents

When verifying a xml document you can pass the following options to the SignedXml constructor to customize the verify process:

  • publicCert - [optional] your certificate as a string, a string of multiple certs in PEM format, or a Buffer
  • privateKey - [optional] your private key as a string or a Buffer - used for verifying symmetrical signatures (HMAC)

The certificate that will be used to check the signature will first be determined by calling this.getCertFromKeyInfo(), which function you can customize as you see fit. If that returns null, then publicCert is used. If that is null, then privateKey is used (for symmetrical signing applications).

Example:

new SignedXml({
  publicCert: client_public_pem,
  getCertFromKeyInfo: () => null,
});

You can use any dom parser you want in your code (or none, depending on your usage). This sample uses xmldom, so you should install it first:

npm install @xmldom/xmldom

Example:

var select = require("xml-crypto").xpath,
  dom = require("@xmldom/xmldom").DOMParser,
  SignedXml = require("xml-crypto").SignedXml,
  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({ publicCert: fs.readFileSync("client_public.pem") });
sig.loadSignature(signature);
try {
  var res = sig.checkSignature(xml);
} catch (ex) {
  console.log(ex);
}

In order to protect from some attacks we must check the content we want to use is the one that has been signed:

// Roll your own
const elem = xpath.select("/xpath_to_interesting_element", doc);
const uri = sig.getReferences()[0].uri; // might not be 0; it depends on the document
const id = uri[0] === "#" ? uri.substring(1) : uri;
if (
  elem.getAttribute("ID") != id &&
  elem.getAttribute("Id") != id &&
  elem.getAttribute("id") != id
) {
  throw new Error("The interesting element was not the one verified by the signature");
}

// Get the validated element directly from a reference
const elem = sig.references[0].getValidatedElement(); // might not be 0; it depends on the document
const matchingReference = xpath.select1("/xpath_to_interesting_element", elem);
if (!isDomNode.isNodeLike(matchingReference)) {
  throw new Error("The interesting element was not the one verified by the signature");
}

// Use the built-in method
const elem = xpath.select1("/xpath_to_interesting_element", doc);
try {
  const matchingReference = sig.validateElementAgainstReferences(elem, doc);
} catch {
  throw new Error("The interesting element was not the one verified by the signature");
}

// Use the built-in method with a an xpath expression
try {
  const matchingReference = sig.validateReferenceWithXPath("/xpath_to_interesting_element", doc);
} catch {
  throw new Error("The interesting element was not the one verified by the signature");
}

Note:

The xml-crypto api requires you to supply it separately the xml signature ("<Signature>...</Signature>", in loadSignature) and the signed xml (in checkSignature). The signed xml may or may not contain the signature in it, but you are still required to supply the signature separately.

Caring for Implicit transform

If you fail to verify signed XML, then one possible cause is that there are some hidden implicit transforms(#).
(#) Normalizing XML document to be verified. i.e. remove extra space within a tag, sorting attributes, importing namespace declared in ancestor nodes, etc.

The reason for these implicit transform might come from complex xml signature specification, which makes XML developers confused and then leads to incorrect implementation for signing XML document.

If you keep failing verification, it is worth trying to guess such a hidden transform and specify it to the option as below:

var options = {
  implicitTransforms: ["http://www.w3.org/TR/2001/REC-xml-c14n-20010315"],
  publicCert: fs.readFileSync("client_public.pem"),
};
var sig = new SignedXml(options);
sig.loadSignature(signature);
var res = sig.checkSignature(xml);

You might find it difficult to guess such transforms, but there are typical transforms you can try.

API

xpath

See xpath.js for usage. Note that this is actually using another library as the underlying implementation.

SignedXml

The SignedXml constructor provides an abstraction for sign and verify xml documents. The object is constructed using new SignedXml(options?: SignedXmlOptions) where the possible options are:

  • idMode - default null - if the value of wssecurity is passed it will create/validate id's with the ws-security namespace.
  • idAttribute - string - default Id or ID or id - the name of the attribute that contains the id of the element
  • privateKey - string or Buffer - default null - the private key to use for signing
  • publicCert - string or Buffer - default null - the public certificate to use for verifying
  • signatureAlgorithm - string - the signature algorithm to use
  • canonicalizationAlgorithm - string - default undefined - the canonicalization algorithm to use
  • inclusiveNamespacesPrefixList - string - default null - a list of namespace prefixes to include during canonicalization
  • implicitTransforms - string[] - default [] - a list of implicit transforms to use during verification
  • keyInfoAttributes - object - default {} - a hash of attributes and values attrName: value to add to the KeyInfo node
  • getKeyInfoContent - function - default noop - a function that returns the content of the KeyInfo node
  • getCertFromKeyInfo - function - default SignedXml.getCertFromKeyInfo - a function that returns the certificate from the <KeyInfo /> node

API

A SignedXml object provides the following methods:

To sign xml documents:

  • addReference(xpath, transforms, digestAlgorithm) - adds a reference to a xml element where:
    • xpath - a string containing a XPath expression referencing a xml element
    • transforms - an array of transform algorithms, the referenced element will be transformed for each value in the array
    • digestAlgorithm - one of the supported hashing algorithms
  • computeSignature(xml, [options]) - compute the signature of the given xml where:
    • xml - a string containing a xml document
    • options - an object with the following properties:
      • prefix - adds this value as a prefix for the generated signature tags
      • attrs - a hash of attributes and values attrName: value to add to the signature root node
      • location - customize the location of the signature, pass an object with a reference key which should contain a XPath expression to a reference node, an action key which should contain one of the following values: append, prepend, before, after
      • existingPrefixes - A hash of prefixes and namespaces prefix: namespace that shouldn't be in the signature because they already exist in the xml
  • getSignedXml() - returns the original xml document with the signature in it, must be called only after computeSignature
  • getSignatureXml() - returns just the signature part, must be called only after computeSignature
  • getOriginalXmlWithIds() - returns the original xml with Id attributes added on relevant elements (required for validation), must be called only after computeSignature

To verify xml documents:

  • loadSignature(signatureXml) - loads the signature where:
    • signatureXml - a string or node object (like an xmldom node) containing the xml representation of the signature
  • checkSignature(xml) - validates the given xml document and returns true if the validation was successful

Customizing Algorithms

The following sample shows how to sign a message using custom algorithms.

First import some modules:

var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

Now define the extension point you want to implement. You can choose one or more.

To determine the inclusion and contents of a <KeyInfo /> element, the function this.getKeyInfoContent() is called. There is a default implementation of this. If you wish to change this implementation, provide your own function assigned to the property this.getKeyInfoContent. If you prefer to use the default implementation, assign SignedXml.getKeyInfoContent to this.getKeyInfoContent If there are no attributes and no contents to the <KeyInfo /> element, it won't be included in the generated XML.

To specify custom attributes on <KeyInfo />, add the properties to the .keyInfoAttributes property.

A custom hash algorithm is used to calculate digests. Implement it if you want a hash other than the built-in methods.

function MyDigest() {
  this.getHash = function (xml) {
    return "the base64 hash representation of the given xml string";
  };

  this.getAlgorithmName = function () {
    return "http://myDigestAlgorithm";
  };
}

A custom signing algorithm.

function MySignatureAlgorithm() {
  /*sign the given SignedInfo using the key. return base64 signature value*/
  this.getSignature = function (signedInfo, privateKey) {
    return "signature of signedInfo as base64...";
  };

  this.getAlgorithmName = function () {
    return "http://mySigningAlgorithm";
  };
}

Custom transformation algorithm.

function MyTransformation() {
  /*given a node (from the xmldom module) return its canonical representation (as string)*/
  this.process = function (node) {
    //you should apply your transformation before returning
    return node.toString();
  };

  this.getAlgorithmName = function () {
    return "http://myTransformation";
  };
}

Custom canonicalization is actually the same as custom transformation. It is applied on the SignedInfo rather than on references.

function MyCanonicalization() {
  /*given a node (from the xmldom module) return its canonical representation (as string)*/
  this.process = function (node) {
    //you should apply your transformation before returning
    return "< x/>";
  };

  this.getAlgorithmName = function () {
    return "http://myCanonicalization";
  };
}

Now you need to register the new algorithms:

/*register all the custom algorithms*/

signedXml.CanonicalizationAlgorithms["http://MyTransformation"] = MyTransformation;
signedXml.CanonicalizationAlgorithms["http://MyCanonicalization"] = MyCanonicalization;
signedXml.HashAlgorithms["http://myDigestAlgorithm"] = MyDigest;
signedXml.SignatureAlgorithms["http://mySigningAlgorithm"] = MySignatureAlgorithm;

Now do the signing. Note how we configure the signature to use the above algorithms:

function signXml(xml, xpath, key, dest) {
  var options = {
    publicCert: fs.readFileSync("my_public_cert.pem", "latin1"),
    privateKey: fs.readFileSync(key),
    /*configure the signature object to use the custom algorithms*/
    signatureAlgorithm: "http://mySignatureAlgorithm",
    canonicalizationAlgorithm: "http://MyCanonicalization",
  };

  var sig = new SignedXml(options);

  sig.addReference({
    xpath: "//*[local-name(.)='x']",
    transforms: ["http://MyTransformation"],
    digestAlgorithm: "http://myDigestAlgorithm",
  });

  sig.addReference({
    xpath,
    transforms: ["http://MyTransformation"],
    digestAlgorithm: "http://myDigestAlgorithm",
  });
  sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
  sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
  sig.computeSignature(xml);
  fs.writeFileSync(dest, sig.getSignedXml());
}

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

signXml(xml, "//*[local-name(.)='book']", "client.pem", "result.xml");

You can always look at the actual code as a sample.

Asynchronous signing and verification

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.

function AsyncSignatureAlgorithm() {
  this.getSignature = function (signedInfo, privateKey, callback) {
    var signer = crypto.createSign("RSA-SHA1");
    signer.update(signedInfo);
    var res = signer.sign(privateKey, "base64");
    //Do some asynchronous things here
    callback(null, res);
  };
  this.getAlgorithmName = function () {
    return "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
  };
}

var sig = new SignedXml({ signatureAlgorithm: "http://asyncSignatureAlgorithm" });
sig.SignatureAlgorithms["http://asyncSignatureAlgorithm"] = AsyncSignatureAlgorithm;
sig.signatureAlgorithm = "http://asyncSignatureAlgorithm";
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.computeSignature(xml, opts, function (err) {
  var signedResponse = sig.getSignedXml();
});

The function sig.checkSignature may also use a callback if asynchronous verification is needed.

X.509 / Key formats

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 beginning of the key content is shown):

-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0...
-----END PRIVATE KEY-----

And for verification use key_public.pem:

-----BEGIN CERTIFICATE-----
MIIBxDCCAW6gAwIBAgIQxUSX...
-----END CERTIFICATE-----

Converting .pfx certificates to pem

If you have .pfx certificates you can convert them to .pem using openssl:

openssl pkcs12 -in c:\certs\yourcert.pfx -out c:\certs\cag.pem

Then you could use the result as is for the purpose of signing. For the purpose of validation open the resulting .pem with a text editor and copy from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE----- (including) to a new text file and save it as .pem.

Examples

how to sign a root node (coming soon)

how to add a prefix for the signature

Use the prefix option when calling computeSignature to add a prefix to the signature.

var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

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

var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") });
sig.addReference({
  xpath: "//*[local-name(.)='book']",
  digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
  transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
sig.computeSignature(xml, {
  prefix: "ds",
});

how to specify the location of the signature

Use the location option when calling computeSignature to move the signature around. Set action to one of the following:

  • append(default) - append to the end of the xml document
  • prepend - prepend to the xml document
  • before - prepend to a specific node (use the referenceNode property)
  • after - append to specific node (use the referenceNode property)
var SignedXml = require("xml-crypto").SignedXml,
  fs = require("fs");

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

var sig = new SignedXml({ privateKey: fs.readFileSync("client.pem") });
sig.addReference({
  xpath: "//*[local-name(.)='book']",
  digestAlgorithm: "http://www.w3.org/2000/09/xmldsig#sha1",
  transforms: ["http://www.w3.org/2001/10/xml-exc-c14n#"],
});
sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#";
sig.signatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
sig.computeSignature(xml, {
  location: { reference: "//*[local-name(.)='book']", action: "after" }, //This will place the signature after the book element
});

more examples (coming soon)

Development

The testing framework we use is Mocha with Chai as the assertion framework.

To run tests use:

npm test

More information

Visit my blog or my twitter

Bitdeli Badge

License

This project is licensed under the MIT License. See the LICENSE file for more info.

xml-crypto's People

Contributors

bazzadp avatar bc-m avatar bergie avatar bjrmatos avatar brianhartsock avatar cjbarth avatar danieljoppi avatar dbitting avatar dependabot[bot] avatar drewtunes avatar fcorneli avatar git9527 avatar hinaser avatar hirse avatar ismailkocacan avatar jess-sheneberger avatar larspederamlie avatar lonerifle avatar ma314smith avatar meganmd avatar mthadley avatar ploer avatar shunkica avatar srir avatar tngan avatar troyfactor4 avatar vadimavdeev avatar woloski avatar xdmnl avatar yaronn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xml-crypto's Issues

xmldom version 0.1.2 produces bad xml signature output

With the latest update of xml-crypto to 0.0.7, there was also a change in the dependencies to strictly require xmldom 0.1.2 instead of >=0.1.8. With that change, I found that the signing was producing invalid xml, specifically adding an extra around the beginning xml tag

<?xml version="1.0" encoding="UTF-8"?>

after signing became

<? <?xml version="1.0" encoding="UTF-8"?>?>

If I remove that xml-crypto's [email protected] installation and let it use my main [email protected] installation, it works fine. Perhaps the "0.1.2" in xml-crypto's package.json was a typo of 0.1.12?

Use this.idAttributes[0] when setting id attribute of element?

I noticed here that the id attribute for elements is set. Can we change the hard-coded "Id" to this.idAttributes[0]? That way if one passes in idAttribute as an option to the SignedXml constructor, it will use that instead.

Basically, I'd like to be able to control whether "Id" or "ID" is outputted when I call SignedXml.computeSignature().

(I'm not familiar with xml-crypto, so my apologies if there's a good reason why it's not this way already.)

How to add <SignatureProperties> into signature?

My use case requires me to add a timestamp to the signature within the element. See below for an XML example. Adding additional objects to the signature is foreseen by the standard. But where would be a good place to insert such additional XML-Nodes into the code? This additional node should of course be signed as well, to prove that indeed the signature is from a certain time & date.

Any help appreciated... struggling with this xml mess :-(

Signature
...
    Object Id="SignatureProperties"> <SignatureProperties xmlns="">
        SignatureProperty Target="#PaymentSignature" Id="TimeStamp"> 
            TimeStamp>
                Date>2009-01-22 /Date
                Time>14:59:33.3823239+01:00 /Time
            /TimeStamp>
        /SignatureProperty>
      /SignatureProperties>/Object
/Signature

Generating an enveloped signature for a SAML Request

I have the following SAML request that I want to digitally sign:

<samlp:AuthnRequest Version="2.0" ID="_9FE393FB-1C9C-4EDD-86A5-1AE9F2192A60" IssueInstant="2014-10-22T11:22:56.676Z" Destination="https://idp.ssocircle.com:443/sso/SSOPOST/metaAlias/ssocircle" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
    <saml:Issuer>http://app.localhost</saml:Issuer>
    <samlp:NameIDPolicy AllowCreate="true" />
</samlp:AuthnRequest>

I use the following coffeescript code which relies on the nodejs xmlbuilder and xmlcrypto modules:

request = @xmlbuilder.create
    'samlp:AuthnRequest':
        '@xmlns:samlp':'urn:oasis:names:tc:SAML:2.0:protocol'
        '@xmlns:saml': 'urn:oasis:names:tc:SAML:2.0:assertion'
        '@Version': '2.0'
        '@ID': requestId
        '@IssueInstant': (new Date()).toISOString()
        '@Destination': idpUrl
        'saml:Issuer': '@@spEntityId'
    ,null
    ,headless: true

request.comment 'insert-signature-here'
request.element 'samlp:NameIDPolicy':
                    '@AllowCreate': 'true'
saml = request.end()

@fs.readFile "certs/my-cert.pem", (err, certificate)=>
    return next @errorService.readFileError certFilePath, err if err?
    signer = new @xmlcrypto.SignedXml()
    signer.signingKey = certificate
    signer.addReference "//*[local-name(.)='AuthnRequest']", ['http://www.w3.org/2000/09/xmldsig#enveloped-signature']
    signer.keyInfoProvider = new =>
        getKeyInfo: (key)=>
            public_key = /-----BEGIN CERTIFICATE-----([^-]*)-----END CERTIFICATE-----/g.exec(key)[1].replace /[\r\n|\n]/g, ''
            "<X509Data><X509Certificate>#{public_key}</X509Certificate></X509Data>"
    signer.computeSignature saml
    signature = signer.getSignatureXml()
    signed = saml.replace '<!-- insert-signature-here -->', signature
    console.log signed

Which generates the following digitally signed SAML request:

<samlp:AuthnRequest Version="2.0" ID="_5FEB2162-F4D0-4900-BC28-F2940188E45B" IssueInstant="2014-10-28T13:07:14.007Z" Destination="https://idp.testshib.org/idp/profile/SAML2/Redirect/SSO" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
    <saml:Issuer>http://app.localhost9de83841</saml:Issuer>
    <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="#_5FEB2162-F4D0-4900-BC28-F2940188E45B">
                <Transforms>
                    <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
                </Transforms>
                <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
                <DigestValue>47MSlH9IpJf8vs37T3DnhZMZ7mo=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>T0Uw...KZkm00A==</SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>MIIDg...OgMMxZ</X509Certificate>
            </X509Data>
        </KeyInfo>
    </Signature>
    <samlp:NameIDPolicy AllowCreate="true" />
</samlp:AuthnRequest>

This appears to be valid.

However when I test this with SSOCircle and TestShib they both report that the digest value does not match.

The certificate I am using is a self-signed certificate (pem) with an unencrypted private key.

I have double checked to categorically ensure that the public key supplied in the sp-metadata was taken from the same pem file used to digitally sign the SAML.

Does the private key need to be encrypted?

If not then can you suggest why the signature check should fail?

Thanks.

keyInfoProvider.getKey should be async

(I'm on a roll, I know, but it's a good roll, right?)

The example for getKey in the README is using fs.readFileSync which is nice and all when you can actually use a sync version of a function - what I'm facing right now is a DER encoded key and so far - I haven't found a nice way to convert it to PEM (or use as is in crypto) other than by calling openssl -inform DER -outform PEM and doing that synchronously is really not an option.

Validating with X509 in body

Hi
I'm trying to validate a Signed xml document that has the X509 key base64 encoded in the document itself.

However, no matter what i try i can't get it to validate(not getting the same digest) and I'm having difficulty understanding how to validate the document this way.

I found a KeyInfo implemenentation in #47 but I can't seem to get that to work either.

Anyone able/willing to lay things out for me?

How to include <X509Certificate> in the signature?

I've signed my xml with this code :

var sig = new SignedXml();
sig.addReference("//*[local-name(.)='AuthnRequest']", ["http://www.w3.org/2000/09/xmldsig#enveloped-signature", "http://www.w3.org/2001/10/xml-exc-c14n#"], "http://www.w3.org/2000/09/xmldsig#sha1", "", "", "", true)
 sig.signingKey = fs.readFileSync("./config/saml.key");
sig.computeSignature(xml_authnRequest);
return sig.getSignedXml();

But i don't know how to put the element <keyinfo> and <X509Certificate> in the signature-
Would you please help me?

Exclusive Canonicalization nsCompare is not spec complaint and creates invalid digests

The namespace compare method in exclusive-canonicalization.js is not compliant with the XML Canonicalization specs. The bug in this code is causing the canonical XML to be ordered slightly differently and thus failing signature validation because the digest values are being hashed over malformed canonicalXML.
http://www.w3.org/TR/xml-exc-c14n/ which refers to the rules specified in http://www.ietf.org/rfc/rfc3076.txt .

Specifically, the spec states:
"

  • An element's namespace nodes are sorted lexicographically by
    local name (the default namespace node, if one exists, has no
    local name and is therefore lexicographically least).
  • An element's attribute nodes are sorted lexicographically with
    namespace URI as the primary key and local name as the
    secondary key (an empty namespace URI is lexicographically
    least). "

For the namespace comparison, instead of sorting by just local name (per spec) the code does this instead:
var attr1 = a.prefix+a.namespaceURI;
var attr2 = b.prefix+b.namespaceURI;
if (attr1 == attr2) return 0;
return attr1.localeCompare(attr2);

For clarification, the 'prefix' here is actually the local name.

But the code is incorrect because the namespaceURI should not be a part of the comparison.

What ends up happening is that if you have something like this:
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"

by doing the namespace comparison of the localName appended with the namespaceURI this string comparison will compare 'samlpurn:oasis:names:tc:SAML:2.0:protocol' to 'samlurnoasis:names:tc:SAML:2.0:assertion'
and the resulting canonicalXML will be incorrectly out of order.

EXPECTED (correct) canonical XML:
<Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" Destination....

ACTUAL (incorrect) canonicalXML as a result of the bad namespace comparison:
<Response xmlns="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Destination=....

Verification of the digest value will fail since it is performed on the incorrect canonicalXML.

The namespace comparison should sort based on just the localNames, here as 'saml' to 'samlp'.

The following code snippet shows one way this can be corrected to be spec compliant:
ExclusiveCanonicalization.prototype.nsCompare = function(a,b) {
var attr1 = a.prefix; // don't compare a.namespaceURI;
var attr2 = b.prefix; // don't compare b.namespaceURI;
if (attr1 == attr2) return 0;
return attr1.localeCompare(attr2);
};

While you're in there, you might also want to double check the attribute comparison too to make sure that is spec compliant as well (at a glance I'm not sure if the attribute comparison is correct either because it doesn't look like it's using the namespaceURI as a primary key for sorting first , it looks like it may use the localName if present instead of namespaceURI).

Prepare for 1.0

The plan (discussed here):

  • [deprecate] sig.loadSignature (at least from the public API).
  • [new behaviour] checkSignature(String: xmlDocument, [String: externalSignatureXmlDocument]) will search and validate only the first signature found (a cool feature would be let the user to validate a specific signature, vía a XPath expression).
  • [new feature] checkAllSignatures(String: xmlDocument, [String: externalSignatureXmlDocument]) will validate all signatures found (by default it will search inside the document for all instances of and validate all instances accordingly. if externalSignatureXmlDocument is specified it will search inside the external document).
  • bring it back the condition: //*[local-name(.)='SignedInfo']/*[local-name(.)='Reference' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#'] (removed here) to ensure a well formed xml document.. it will be ok since we have all the information that we need (namespaces) in the xml document node.
  • both checkSignature and checkAllSignatures must support the externalSignatureXmlDocument param for external signatures.
  • [refactor] adapt current tests
  • [fix/improve] travis build (seems like it is broken since some time ago)
  • [add] debug module for logging in development
  • [remove] hacky workaround in this commits if more information is not provided here

🎉 The user wont need to specify the signature manually, xml-crypto will do it and will support multiple signature validation. 🎉

Support for prefixed signature

Hello @yaronn, as discussed here #26 i'm starting to work in a pull request that support generate a prefixed signature. i've cloned the repo and after run npm test i see a failing test, do you have the same result?

image

A typo in README

There is a small typo in README.md.

You can choose one ore more.

allow to use pem with passphrase

currently if a pem requires a passphrase than the user will be prompt to enter it. effectively this means a passphrase is not supported.

solution is to change signer.sign (also verify?) to accept an object as first parameter: https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format

this is not available yet in node 0.10.33 (not sure starting which version it is). when used on non supported node version the object parameter to sign will throw:

crypto.js:429
  var ret = this._binding.sign(toBuf(key));
                      ^
TypeError: Not a buffer
    at Sign.sign (crypto.js:429:27)

support inclusive namespaces

Follow up to #43

A reference like this:

 <ds:Reference URI="...">
          <ds:Transforms>
            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
              <xc14n:InclusiveNamespaces xmlns:xc14n="http://www.w3.org/2001/10/xml-exc-c14n#"  PrefixList="xs saml xsi">
              </xc14n:InclusiveNamespaces>
            </ds:Transform>
          </ds:Transforms>
          <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1">
          </ds:DigestMethod>
          <ds:DigestValue>...</ds:DigestValue>
    </ds:Reference>

means that we need to add definitions for xs, saml and xsi on the canonicalized value of the node we validate. they should be bound to whatever they are bound to in the context of that node.

for example if we need to sign X:

<y xmlns:xs="1" xmlns:saml="2" xmlns:xsi="3">
    <x>
</y>

then X canonical form should be:

<x xmlns:xs="1" xmlns:saml="2" xmlns:xsi="3"></x>

new version?

could you please publish a new version including latest 2 commits?

Thanks!

latest version issues

  • is trying to load ./xpath.js and there is no such file on the folder. And the xpath.js package is not specified on package.json. I assume you wanted to use the installed package.
  • when running the tests it fails on the windows store signature test.

thanks
Matias

How to add signature on AuthnRequest

Hello,
I'm trying to add signature on my AuthnRequest with xml-crypto.
I've tried to add some configuration to SamlStrategy but nothing appens on AuthnRequest XML.

This is the configuration for Strategy :

passport: {
            strategy : 'saml',
            saml : {
                entryPoint : 'https://idp.idp.it/samlsso',
                issuer : 'http://111.111.11.111:8000',
                callbackUrl : 'http://111.111.11.111:8000/login/callback',
                identifierFormat: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient',
                decryptionPvk: fs.readFileSync('./config/saml.key'),
                cert:'MII....Q==',
                validateInResponseTo :true,
                authnContext : 'urn:oasis:names:tc:SAML:2.0:ac:classes:name1',
                protocol: 'http://',
                attributeConsumingServiceIndex:0
            }
        }

This how route the login request, but i don't know how to add signature on it

app.get("/login",
        passport.authenticate(config.passport.strategy,
        {
            successRedirect : "/",
            failureRedirect : "/login",
        })
    );

    app.post('/login/callback',
        passport.authenticate(config.passport.strategy,
            {
                failureRedirect: '/',
                failureFlash: true
            }),
        function(req, res) {
            res.redirect('/');
        }
    );

This is the SAML AuthnRequest xml :

<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                    ID="_6eefdebac845aec3b311"
                    Version="2.0"
                    IssueInstant="2015-03-30T09:47:12.835Z"
                    ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                    AssertionConsumerServiceURL="http://111.111.11.111:8000/login/callback"
                    Destination="https://idp.idp.it/samlsso"
                    >
    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">http://111.111.11.111:8000</saml:Issuer>
    <samlp:NameIDPolicy xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                        Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
                        AllowCreate="true"
                        />
    <samlp:RequestedAuthnContext xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
                                 Comparison="exact"
                                 >
        <saml:AuthnContextClassRef xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:oasis:names:tc:SAML:2.0:ac:classes:name1</saml:AuthnContextClassRef>
    </samlp:RequestedAuthnContext>
</samlp:AuthnRequest>

fix travis builds

hi @yaronn, i noticed some time ago that the travis builds are broken because we are testing against an older version of node (0.6), can i update .travis.yml to test against 0.10 and 0.12?

Support for SHA-512

The library is not supporting SHA-512. I think that it would be a good improvement. Our IdP at SunGard uses SHA-512 for SAML assertion encryption/encoding and we are not able to use passport-saml because this lack of support in sml-crypto. Happily, the changes are pretty straightforward, see the patch pasted below:

--- C:/rajesh/psp/portal/node_modules/passport-saml/node_modules/xml-crypto/lib/signed-xml (2).js Fri Sep 12 16:45:15 2014
+++ C:/rajesh/psp/portal/node_modules/passport-saml/node_modules/xml-crypto/lib/signed-xml.js Mon Sep 22 16:19:20 2014
@@ -126,7 +126,37 @@ function RSASHA256() {

}

+function RSASHA512() {

  • /**
  • * Sign the given string using the given key
  • */
  • this.getSignature = function(signedInfo, signingKey) {
  • var signer = crypto.createSign("RSA-SHA512")
  • signer.update(signedInfo)
  • var res = signer.sign(signingKey, 'base64')
  • return res
  • }
  • /**
  • * Verify the given signature of the given string using key
  • */
  • this.verifySignature = function(str, key, signatureValue) {
  • var verifier = crypto.createVerify("RSA-SHA512")
  • verifier.update(str)
  • var res = verifier.verify(key, signatureValue, 'base64')
  • return res
  • }

+}
+
+
/**

  • Xml signature implementation
    *
    @@ -164,7 +194,8 @@ SignedXml.HashAlgorithms = {

SignedXml.SignatureAlgorithms = {
'http://www.w3.org/2000/09/xmldsig#rsa-sha1': RSASHA1,

Windows Store Receipt doesn't validate

Hi,

Thanks for your library. I'm in a rush and I'd really, really be grateful if you could help me get this working with your library. I want to be able to take one of the XML objects from the Windows store sample code:

Copy and paste one of the 2 <Receipt>...</Receipt> objects from here
http://msdn.microsoft.com/en-us/library/windows/apps/jj649137.aspx

and validate it with the Microsoft store cert here:
https://lic.apps.microsoft.com/licensing/certificateserver/?cid=b809e47cd0110a4db043b3f73e83acd917fe1336

Problem #1:
SignedXml.validateReferences() isn't expecting:

  <Reference URI="">

and is trying to reference a char that doesn't exist:

ref.uri[0]

Problem #2:
If I try hack around that, it still doesn't work. I think the problem is that SignedXml.getCanonXml() is applying all the transforms:

<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />

but I don't see where is applying the overall canonicalization

<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />

which is a different algorithm.

I don't think I'm the only one who would love to be able to use node to work with the Windows store. Getting this to work would be greatly appreciated!

enveloped transformation + exclusive-canonicalization

Can both algorithms work together? I'm getting a digest mismatch error with the following "transforms" element:

<ds:Transforms>
  <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
  <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
    <xc14n:InclusiveNamespaces xmlns:xc14n="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs saml xsi"/>
  </ds:Transform>
 </ds:Transforms>

Thanks

Can't get XML digests to match. Possible canonicalization problem?

I'm having some issues using the passport-saml library, which depends on xml-crypto, in a expressjs application running on a Windows server using the IISNode package. It is failing comparing the digest of an XML document during signature validation. It may not be xml-crypto but my own configuration, but I'm hoping you can take a look at this and tell me what might be going on. After some debugging, I've tried console logging the canonXML in validateReferences and I get this:

<ns2:Assertion xmlns:ns2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_46a4b76336ee613e48253c243a3a0b6ba082" IssueInstant="2015-03-16T23:06:50Z" Version="2.0">&#xD;
        <ns2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">REDACTED</ns2:Issuer>&#xD;
        <ns2:Subject>&#xD;
            <ns2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">REDACTED</ns2:NameID>&#xD;
            <ns2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">&#xD;
                <ns2:SubjectConfirmationData NotOnOrAfter="2015-03-16T23:08:20Z" Recipient="REDACTED"></ns2:SubjectConfirmationData>&#xD;
            </ns2:SubjectConfirmation>&#xD;
        </ns2:Subject>&#xD;
        <ns2:Conditions NotBefore="2015-03-16T23:06:20Z" NotOnOrAfter="2015-03-16T23:08:20Z">&#xD;
            <ns2:AudienceRestriction>&#xD;
                <ns2:Audience>REDACTED</ns2:Audience>&#xD;
            </ns2:AudienceRestriction>&#xD;
        </ns2:Conditions>&#xD;
        <ns2:AuthnStatement AuthnInstant="2015-03-16T23:06:49Z" SessionIndex="B6VBp2KsdceV80qx2kbd6lqKDCI=kgfzlw==" SessionNotOnOrAfter="2015-03-16T23:08:20Z">&#xD;
            <ns2:AuthnContext>&#xD;
                <ns2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</ns2:AuthnContextClassRef>&#xD;
            </ns2:AuthnContext>&#xD;
        </ns2:AuthnStatement>&#xD;
        <ns2:AttributeStatement>&#xD;
            <ns2:Attribute Name="FirstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">&#xD;
                <ns2:AttributeValue>REDACTED</ns2:AttributeValue>&#xD;
            </ns2:Attribute>&#xD;
            <ns2:Attribute Name="LastName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">&#xD;
                <ns2:AttributeValue>REDACTED</ns2:AttributeValue>&#xD;
            </ns2:Attribute>&#xD;
        </ns2:AttributeStatement>&#xD;
    </ns2:Assertion>

It prints out exactly like that in console. I know next to nothing about XML canonicalization. I'm concerned about the &#xD; after each line while other types of whitespace is retained, as I've never seen XML that looks like that.

Provide an option to ignore missing URIs

I'm working on a library to verify ASiC containers - they are essentially a ZIP with a signatures.xml. The signatures.xml contains XAdES which can happily be verified using this library, except that it contains URIs which are outside of the document itself, i.e. the URIs do not reference the IDs inside the XML, but reference the files inside the ZIP. Since URIs with and without the starting # can be treated as reference IDs, I don't see an easy way to automagically determine which is which, therefore I need a way to tell this library to ignore missing elements. I think a good way to achieve that would be to have an option that instead of failing here: https://github.com/yaronn/xml-crypto/blob/master/lib/signed-xml.js#L284 would rather stuff the information into some "missing URIs" property, that can later be used to verify the documents externally.

In short - I'd like to see a way to treat missing URIs as warnings, not as failures.

I'm happy to submit a PR, if we can agree on the contract - where to add the option and how to name the "missing URIs" property. What do you think about options.failOnMissingUris [default: true] and SignedXml.validationWarnings (array of objects with warningType and custom data which differs per type) or a simpler SignedXml.validationMissingUris?

Reference:
ASiC: http://www.etsi.org/deliver/etsi_ts/102900_102999/102918/01.03.01_60/ts_102918v010301p.pdf
XAdES: http://www.etsi.org/deliver/etsi_ts%5C101900_101999%5C101903%5C01.04.02_60%5Cts_101903v010402p.pdf

Is documentation up to date?

Hello, i just find in the source code that a EnvelopedSignature transform is supported, but nothing of this is mentioned in the docs, also there are other things that i think are out-dated too, would you accept a pull request covering this?

inclusiveNamespacesPrefixList doesn't work as expected

My goal is producing C14N canonical form (inclusive canonical form). I tried to do it by adding all namespaces in document to inclusiveNamespacesPrefixList. Instead of extracting all namespace nodes and adding them to list I just simulated such action by small change in code:

if (attr.prefix && prefixesInScope.indexOf(attr.localName) === -1 && inclusiveNamespacesPrefixList.indexOf(attr.localName) >= 0)

became

if (attr.prefix && prefixesInScope.indexOf(attr.localName) === -1 /*&& inclusiveNamespacesPrefixList.indexOf(attr.localName) >= 0*/)

in renderNs function. But I still recieving exclusive canonical form (I'm comparing with Java Apache Canonicalizer).

What I'm doing wrong?

<Reference/> without ID

I think that sign verification is not working when you have just one tag without ID. In this case it should use the whole xml-document excluding Tag. But instead of this, it returns an error.
I paste an ugly patch just to clarification.

/**

  • Overrides method from SignedXML (@see singed-xml.js).
  • Original method do not work for reference with no IDs.
  • @param doc
  • @returns {Boolean}
    */

SignedXml.prototype.validateReferences = function(doc) {
/*
* determines if has been processed a Reference without ID. It can be done
* just one time.
*/
var emptyRef = false;
for ( var r in this.references) {
var ref = this.references[r];

    var uri = ref.uri[0] == "#" ? ref.uri.substring(1) : ref.uri;
    var elem = [];
    for ( var index = 0; index < this.idAttributes.length; index++) {
        elem = select(doc, "//*[@*[local-name(.)='"
                + this.idAttributes[index] + "']='" + uri + "']");
        if (elem.length > 0)
            break;
    }

    if (elem.length == 0 && !emptyRef) {
        emptyRef = true;
        elem = doc.childNodes;
    } else if (elem.length == 0) {
        this.validationErrors
                .push("invalid signature: the signature refernces an element with uri "
                        + ref.uri
                        + " but could not find such element in the xml");
        return false;
    }

    var canonXml = this.getCanonXml(ref.transforms, elem[0]);
    var hash = this.findHashAlgorithm(ref.digestAlgorithm);
    var digest = hash.getHash(canonXml);
    if (digest != ref.digestValue) {
        this.validationErrors.push("invalid signature: for uri " + ref.uri
                + " calculated digest is " + digest
                + " but the xml to validate supplies digest "
                + ref.digestValue);

        return false;
    }
}
return true;

};

Include InclusiveNamespaces in transform tag

Hi
I need to define a reference when signing my xml with a html tag called: InclusiveNamespaces.
Are there any solution for this?

This is what I need to have inside my reference tag:


signed assertion + signed message + "ds" prefix defined only at the root of the XML

Hi guys,

I have a scenario where I need to validate a saml response with the following conditions:

  • Assertion was signed
  • Message (saml response) was signed too
  • The "ds" prefix was defined only at the root of the XML (it's not in the Signature node)

Now, time to validate both signatures with the SignedXml class (sig.checkSignature):

  • For the message signature validation, everything works as expected
  • But for the assertion signature validation, I have the following error:
[ 'invalid signature: for uri #pfxabec2b1c-3915-1115-d115-6003c7afd15e calculated digest is X but the xml to validate supplies digest Y' ]

Do you know if this scenario is supported for your library? I mean signed assertion + signed message + "ds" prefix defined only at the root of the XML

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="http://sp.example.com/demo1/index.php?acs" ID="pfx4b172e4e-9db1-5b0b-01e9-5f50031ab711" IssueInstant="2016-01-29T15:33:31Z" Version="2.0">
   <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://idp.example.com/metadata.php</saml:Issuer><ds:Signature>
  <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
  <ds:Reference URI="#pfx4b172e4e-9db1-5b0b-01e9-5f50031ab711"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>v71AK2FW1QltA8vQ9EJi6OdpqFM=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>nHNUcs5iE1upZT/bB7J08WyiOxsy0T89SBr3VC9r1wuQgvYM1fOXCuyYKgsEAlCunzs+EQBVxP3wdNghmrTwLv+3M3BeMIx3o7dfjNJcr9oL3K6JjtqlPMFuAoaEPyNukcLvXOsDjIj0XtbHuz8zL31fjKMkMYe0lQJolToqPDJVTi03u06Qv+24zAKL3R196p3HQzSvjpKvwQRvsLyn3U6kZe27xvz7dJK0kizbnLJWyaHnmOimuhg6pm9osWUzL3IFwngMXM/6XRNWKJEfRGkToy9FTqXjlgACVXK5NL9iIHlRO0zSbRepRZdpuEqSUg+Q5LuFNDeJWE2DZSV2qg==</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIC7DCCAdSgAwIBAgIJOVW7hb0ZTkGPMA0GCSqGSIb3DQEBBQUAMB0xGzAZBgNVBAMTEmxvZ2luMC5teWF1dGgwLmNvbTAeFw0xNTEyMTEyMTQ5MTVaFw0yOTA4MTkyMDQ5MTVaMB0xGzAZBgNVBAMTEmxvZ2luMC5teWF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvF/7JY9/G6edCE4qi44ODhlWoI71xVWflWNy8cRm8P6Wxgm2Z9AjJYsxsZJG2QecJeciX+WrkJ4nJxvb9CW4IIOhUy/BpMWxCVvSxLqKcvKxt0UI9jCThxTQZW7m0F9lhgXte0hr7Azr52wlUm9a5R2z5b1LtSDsLPQTwEWSCpVV4Hu1jZ5BsTbrF0poA+yMWvNScJjedKrMAG4C60WlqBULAMCO0LnHsGJgm+XFATy+XNRxFUiFJD2HkrhNlwrimx1EuKPqOMxMl+HOQOlMs+LVebvaJ+hZ1Xsi05dOPkSQc5QH8tFXAphecOtvDyZ583/qFgttLBtAK7f0Hn0JsCAwEAAaMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU3vBV4ENIG5bJIdd6dIuYZIUSyMkwDQYJKoZIhvcNAQEFBQADggEBABR47xeLlgmarCYcSFheV5N6DKcJT2grcKRHKUNAwbGnFZ1jmpZG8EYrQPpTRjFy82n1E6cxUlcBLUnlOYWpJ4VhmM1g+PJr+H3nCdcNCRgoPA2NyNqYmV1qr4vQHc3Iyja+UQDdFiWaMM+I11fy1uGKF345tZwBANl2tfENIjNVRXIEiPXr4xlGrZbuAoTHm+gv7GOcyqOikWj7N9smYTUyItwyzN+GO8vZeBmpiA18qQpXNOvXzFyT1/EBdQmIl4MFIUIQudUxObd0/K2IbJd6wXEzOUpfvmNuXmo+XtwLMQ3B7IpK/d/zHk8YMnxqA2fGoqpczNajshZ7gbPLvXM=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
   <samlp:Status>
      <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
   </samlp:Status>
   <saml:Assertion ID="pfxabec2b1c-3915-1115-d115-6003c7afd15e" IssueInstant="2016-01-29T15:33:31Z" Version="2.0">
      <saml:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://idp.example.com/metadata.php</saml:Issuer><ds:Signature>
  <ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
  <ds:Reference URI="#pfxabec2b1c-3915-1115-d115-6003c7afd15e"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>adowtTeoldhOVr2xyRL/wd9GssA=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>Y25O9LZHY8ltQReTNPh9+Vc8tZpPcq/HyCl4a2v9I9D3RBSZEWNbdZXrJ40APm6ph+iGqZFoEw90jZo0S7UpKFB/vLT2rdigulBugQg7BPzgFN4LL690qdegUbApt1FQqnhPlcZQGAzODg6zDAyJ+GzDFxso8oqh6RoaZLWZAEvfnrlWakI2ammrBquI59XGn0mUBrT47K77NA/U6u3AJtACqpFFslcjR6yhjUssW102IRDxfxVy44bHslse0rHp553/DifyDFSc8pNiqtCbfy0XnKqzLY+YEn2h90BlGocI6Fg0tMQUjCc9y/lHoZ5XwKka1l2tVJGOrUPMLgFvBw==</ds:SignatureValue>
<ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIC7DCCAdSgAwIBAgIJOVW7hb0ZTkGPMA0GCSqGSIb3DQEBBQUAMB0xGzAZBgNVBAMTEmxvZ2luMC5teWF1dGgwLmNvbTAeFw0xNTEyMTEyMTQ5MTVaFw0yOTA4MTkyMDQ5MTVaMB0xGzAZBgNVBAMTEmxvZ2luMC5teWF1dGgwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvF/7JY9/G6edCE4qi44ODhlWoI71xVWflWNy8cRm8P6Wxgm2Z9AjJYsxsZJG2QecJeciX+WrkJ4nJxvb9CW4IIOhUy/BpMWxCVvSxLqKcvKxt0UI9jCThxTQZW7m0F9lhgXte0hr7Azr52wlUm9a5R2z5b1LtSDsLPQTwEWSCpVV4Hu1jZ5BsTbrF0poA+yMWvNScJjedKrMAG4C60WlqBULAMCO0LnHsGJgm+XFATy+XNRxFUiFJD2HkrhNlwrimx1EuKPqOMxMl+HOQOlMs+LVebvaJ+hZ1Xsi05dOPkSQc5QH8tFXAphecOtvDyZ583/qFgttLBtAK7f0Hn0JsCAwEAAaMvMC0wDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQU3vBV4ENIG5bJIdd6dIuYZIUSyMkwDQYJKoZIhvcNAQEFBQADggEBABR47xeLlgmarCYcSFheV5N6DKcJT2grcKRHKUNAwbGnFZ1jmpZG8EYrQPpTRjFy82n1E6cxUlcBLUnlOYWpJ4VhmM1g+PJr+H3nCdcNCRgoPA2NyNqYmV1qr4vQHc3Iyja+UQDdFiWaMM+I11fy1uGKF345tZwBANl2tfENIjNVRXIEiPXr4xlGrZbuAoTHm+gv7GOcyqOikWj7N9smYTUyItwyzN+GO8vZeBmpiA18qQpXNOvXzFyT1/EBdQmIl4MFIUIQudUxObd0/K2IbJd6wXEzOUpfvmNuXmo+XtwLMQ3B7IpK/d/zHk8YMnxqA2fGoqpczNajshZ7gbPLvXM=</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature>
      <saml:Subject>
         <saml:NameID Format="urn:ibm:names:ITFIM:5.1:accessmanager">[email protected]</saml:NameID>
         <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
            <saml:SubjectConfirmationData NotOnOrAfter="2016-01-29T15:43:31Z" Recipient="http://sp.example.com/demo1/index.php?acs"/>
         </saml:SubjectConfirmation>
      </saml:Subject>
      <saml:Conditions NotBefore="2016-01-29T15:32:31Z" NotOnOrAfter="2016-01-29T15:43:31Z">
         <saml:AudienceRestriction>
            <saml:Audience>http://sp.example.com/demo1/metadata.php</saml:Audience>
         </saml:AudienceRestriction>
      </saml:Conditions>
      <saml:AuthnStatement AuthnInstant="2016-01-29T15:33:31Z" SessionIndex="_be9967abd904ddcae3c0eb4189adbe3f71e327cf93" SessionNotOnOrAfter="2016-01-30T04:33:30Z">
         <saml:AuthnContext>
            <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
         </saml:AuthnContext>
      </saml:AuthnStatement>
      <saml:AttributeStatement>
         <saml:Attribute Name="EmailAddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
            <saml:AttributeValue xsi:type="xs:string">[email protected]</saml:AttributeValue>
         </saml:Attribute>
         <saml:Attribute Name="UserID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
            <saml:AttributeValue xsi:type="xs:string">4G1441786</saml:AttributeValue>
         </saml:Attribute>
         <saml:Attribute Name="FirstName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
            <saml:AttributeValue xsi:type="xs:string">jon</saml:AttributeValue>
         </saml:Attribute>
         <saml:Attribute Name="LastName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
            <saml:AttributeValue xsi:type="xs:string">doe</saml:AttributeValue>
         </saml:Attribute>
      </saml:AttributeStatement>
   </saml:Assertion>
</samlp:Response>

Thanks!

possibility of removing xmldom-fork-fixed dependency and moving to xmldom 0.1.19

Xmldom clarified its license to a dual MIT/LGPL license several versions ago; however, the version of xmldom used in xml-crypto does not include that clarification.

It would be great to move to the latest xmldom (0.1.19), so that organizations that can't accept a LGPL license can still use xml-crypto. (We use xml-crypto in passport-saml, and this issue comes up there).

I notice that if I remove xmldom-fork-fixed and update xmldom, there is a single test case that starts failing. I haven't found a repository with the xmldom-fork-fixed changes, but it seems like there must be something in there that hasn't been submitted back to xmldom.

Is there anything I could do to help get this fixed?

Signed a particular structure

Hi all,
I need to generate a XML Signature like this:

         <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <Reference URI="">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>puV.............3M=</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>Ghog270A................b1rJCpX3A4=</SignatureValue>
            <KeyInfo>
                <X509Data><X509Certificate>MIIEM..................4EsZ3UGyvLWK+O</X509Certificate>
                </X509Data>
                <KeyValue>
                    <RSAKeyValue>
                        <Modulus>MIGfMA0GCSqGSIb3DQEBAQU..........T/wIDAQAB</Modulus>
                        <Exponent>AQAB</Exponent>
                    </RSAKeyValue>
                </KeyValue>
            </KeyInfo>
        </Signature>

And I have to put it in a specific node <security>.

The final result would be something like that:

<?xml version="1.0" encoding="UTF-8"?>
<SchufaService version="2.0" xmlns="http://www.schufa.de/siml/2.0/final">
    <Security>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <Reference URI="">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue>puVw.......473M=</DigestValue>
                </Reference>
            </SignedInfo>
            <SignatureValue>Ghog2.........X3A4=</SignatureValue>
            <KeyInfo>
                <X509Data>
                    <X509Certificate>MIIEMTCCA.....3UGyvLWK+O</X509Certificate>
                </X509Data>
                <KeyValue>
                    <RSAKeyValue>
                        <Modulus>MIGf..........IDAQAB</Modulus>
                        <Exponent>AQAB</Exponent>
                    </RSAKeyValue>
                </KeyValue>
            </KeyInfo>
        </Signature>
    </Security>
    <Service timestamp="2014-09-04T13:16:46.958Z">
        <Online>
            <Request/>
        </Online>
    </Service>
    <Data language="DEU">
        <Aktion teilnehmerkennung="xxxxxxxxx" teilnehmerkennwort="xxxxxxxxx">
            <AnfrageBonitaetsauskunft version="1.0">
                <Anfragemerkmal merkmalcode="AU"/>
                <Verbraucherdaten>
                    <Vorname>xxxxxxxxxx</Vorname>
                    <Nachname>xxxxxxxxxx</Nachname>
                    <Geschlecht>M</Geschlecht>
                    <Geburtsdatum>xxxxxxxxxx</Geburtsdatum>
                    <AktuelleAdresse>
                        <Strasse>ZUM xxxxxxx 11</Strasse>
                        <PLZ>xxxxxx</PLZ>
                        <Ort>xxxxxxxx</Ort>
                    </AktuelleAdresse>
                </Verbraucherdaten>
            </AnfrageBonitaetsauskunft>
        </Aktion>
    </Data>
</SchufaService>

My solution to do this is:

STEP 1

Create all XML like the example:

<?xml version="1.0" encoding="UTF-8"?>
<SchufaService version="2.0" xmlns="http://www.schufa.de/siml/2.0/final">
    <Security>
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
            <SignedInfo>
                <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
                <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                <Reference URI="">
                    <Transforms>
                        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                    </Transforms>
                    <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                    <DigestValue/>
                </Reference>
            </SignedInfo>
            <SignatureValue/>
            <KeyInfo>
                <X509Data>
                    <X509Certificate>MIIEMTCCA.....3UGyvLWK+O</X509Certificate>
                </X509Data>
                <KeyValue>
                    <RSAKeyValue>
                        <Modulus>MIGf..........IDAQAB</Modulus>
                        <Exponent>AQAB</Exponent>
                    </RSAKeyValue>
                </KeyValue>
            </KeyInfo>
        </Signature>
    </Security>
    <Service timestamp="2014-09-04T13:16:46.958Z">
        <Online>
            <Request/>
        </Online>
    </Service>
    <Data language="DEU">
        <Aktion teilnehmerkennung="xxxxxxxxx" teilnehmerkennwort="xxxxxxxxx">
            <AnfrageBonitaetsauskunft version="1.0">
                <Anfragemerkmal merkmalcode="AU"/>
                <Verbraucherdaten>
                    <Vorname>xxxxxxxxxx</Vorname>
                    <Nachname>xxxxxxxxxx</Nachname>
                    <Geschlecht>M</Geschlecht>
                    <Geburtsdatum>xxxxxxxxxx</Geburtsdatum>
                    <AktuelleAdresse>
                        <Strasse>ZUM xxxxxxx 11</Strasse>
                        <PLZ>xxxxxx</PLZ>
                        <Ort>xxxxxxxx</Ort>
                    </AktuelleAdresse>
                </Verbraucherdaten>
            </AnfrageBonitaetsauskunft>
        </Aktion>
    </Data>
</SchufaService>
STEP 2

Generate a signature getSignatureXml() for the <data> node and extracting the DigestValue and SignatureValue from the result and put these in the relatives nodes of the XML created in the STEP 1.

the function to do that is this:

function getSecurityContent(xml){
    var xml_result = xml.toString();

    SignedXml.CanonicalizationAlgorithms["http://www.w3.org/2000/09/xmldsig#enveloped-signature"] = MyTransformation;
    SignedXml.CanonicalizationAlgorithms["http://www.w3.org/2001/10/xml-exc-c14n#WithComments"] = MyCanonicalization;

    var sig = new SignedXml();
    sig.addReference("//*[local-name(.)='Data']",["http://www.w3.org/2000/09/xmldsig#enveloped-signature"], "http://www.w3.org/2000/09/xmldsig#sha1", "", "", "", true);
    sig.signingKey = fs.readFileSync("routes/pem/RSA_privkey.pem");
    sig.canonicalizationAlgorithm = "http://www.w3.org/2001/10/xml-exc-c14n#WithComments";
    sig.keyInfoProvider = new FileKeyInfo("routes/pem/Cert_public.pem")
    sig.computeSignature(xml_result);

    var signature = sig.getSignatureXml();
    var start_digest = '\<DigestValue>';
    var end_digest = '\</DigestValue>';
    var temp_digest = '\<DigestValue/>';
    var start_signature = '\<SignatureValue>';
    var end_signature = '\</SignatureValue>';
    var temp_signature = '\<SignatureValue/>';
    var real_digest = signature.substring((signature.indexOf(start_digest) + start_digest.length), signature.indexOf(end_digest));
    var real_signature = signature.substring((signature.indexOf(start_signature) + start_signature.length), signature.indexOf(end_signature));

    xml_result = [xml_result.slice(0, xml_result.indexOf(temp_digest)), xml_result.slice(xml_result.indexOf(temp_digest) + temp_digest.length)].join( "<DigestValue>" + real_digest.toString() + "</DigestValue>");
    xml_result = [xml_result.slice(0, xml_result.indexOf(temp_signature)), xml_result.slice(xml_result.indexOf(temp_signature) + temp_signature.length)].join( "<SignatureValue>" + real_signature.toString() + "</SignatureValue>");

    return xml_result.toString();
}
RESULT

SO NOT WORK!!!! :(
When i try to validate it the response is that

invalid data:data and digest do not match

Any Ideas???

Thanks

working with Axis/WSS4J web services

I wanted to see if I can write node.js code to work with a Axis/WSS4J based web services that I maintain. I captured a request and started writing code to analyse it and familiarize myself with xml-crypto.

xml = fs.readFileSync('request.xml', 'ascii', function(err,data) {
            if(err) {
                console.log("Could not open file"+ err);
                process.exit(1);
            }
        });
var sig = new SignedXml();
sig.keyInfoProvider = new FileKeyInfo("service-consumer-20121016-public.pem");
var signature = select(this.doc, "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
console.log(signature.toString());
sig.loadSignature(signature.toString());
var res = sig.checkSignature(xml);

request.xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
soapenv:Header
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" soapenv:mustUnderstand="1">
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-87498914">
wsu:Created2013-01-17T17:20:28.257Z/wsu:Created
wsu:Expires2013-01-17T17:25:28.257Z/wsu:Expires
/wsu:Timestamp
<wsse:BinarySecurityToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="CertId-5762605">MIIDujCCAyOgAwIBAgIJAL4olIXwkZQOMA0GCSqGSIb3DQEBBQUAMIGEMQ0wCwYDVQQKEwRKQ0RYMQwwCgYDVQQLEwNkZXYxHDAaBgkqhkiG9w0BCQEWDWpjZHhAamNkeC5vcmcxEjAQBgNVBAcTCVNhbiBEaWVnbzELMAkGA1UECBMCQ0ExCzAJBgNVBAYTAlVTMRkwFwYDVQQDExBzZXJ2aWNlLWNvbnN1bWVyMB4XDTEyMTAxNjEyNDE1NloXDTIyMDcxNjEyNDE1NlowgYQxDTALBgNVBAoTBEpDRFgxDDAKBgNVBAsTA2RldjEcMBoGCSqGSIb3DQEJARYNamNkeEBqY2R4Lm9yZzESMBAGA1UEBxMJU2FuIERpZWdvMQswCQYDVQQIEwJDQTELMAkGA1UEBhMCVVMxGTAXBgNVBAMTEHNlcnZpY2UtY29uc3VtZXIwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANT5xJoZbag0zGmFk8BSA7aJfkFUBBVw+NiHpm8yRROsRJyKAnbGb8R7Jkyh9pTXXVrcC++qF21ipERJ78UE5fuqgTZbXEqSRhtEW377PEVSP8P9pR4XSpyCYqGs0Z77JAX3EalQmNj1iulGiY9d/22XyZixr4s4K94A3+ru+FONAgMBAAGjggEwMIIBLDAMBgNVHRMEBTADAQH/MB0GA1UdDgQWBBRIB+IzcpVPbP7e4O62u+TxfDxEZzCBuQYDVR0jBIGxMIGugBRIB+IzcpVPbP7e4O62u+TxfDxEZ6GBiqSBhzCBhDENMAsGA1UEChMESkNEWDEMMAoGA1UECxMDZGV2MRwwGgYJKoZIhvcNAQkBFg1qY2R4QGpjZHgub3JnMRIwEAYDVQQHEwlTYW4gRGllZ28xCzAJBgNVBAgTAkNBMQswCQYDVQQGEwJVUzEZMBcGA1UEAxMQc2VydmljZS1jb25zdW1lcoIJAL4olIXwkZQOMDEGA1UdJQQqMCgGCCsGAQUFBwMCBggrBgEFBQcDBAYIKwYBBQUHAwMGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIE8DANBgkqhkiG9w0BAQUFAAOBgQCz5grHrjsd4NFP0sfQEa677uqukB9jj+8gNYD6HqQ7N6D1hWMg81V1Qg6jDTJzjRlXx8Z1pAkbepR2TiPCPhvEjxn5KMT53gNBce8I8pHGUTN4Xev5USW4K+4GJEwly5eXTBAey6Rp7DlpnIvCmr0Xk7qgJZK+lA7NKv5mJV0KLA==/wsse:BinarySecurityToken
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="Signature-791234579">
ds:SignedInfo
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">/ds:CanonicalizationMethod
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1">/ds:SignatureMethod
<ds:Reference URI="#id-2141355741">
ds:Transforms
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">/ds:Transform
/ds:Transforms
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1">/ds:DigestMethod
ds:DigestValueeH8rMl07vI5vfO0jI+riK8x4scc=/ds:DigestValue
/ds:Reference
/ds:SignedInfo
ds:SignatureValueF5vcOJgohQ4qFqOUtYwjOLu47Dtp7BLKqL6ESuOoZ0+/6YZ3kZuDI+/8PKKyzNpIY7ebqg/22qz7S02HbukfjG3VblyZx2qUmIdQJQbYDiqU/yNjoXK9AEH3AhGwpkIOrnh5LGRhedvW4Kd7TBEJF2QMJUalcvXgP3GZJqtxiGY=/ds:SignatureValue
<ds:KeyInfo Id="KeyId-1060827029">
<wsse:SecurityTokenReference xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="STRId-910639009">
<wsse:Reference URI="#CertId-5762605" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">/wsse:Reference
/wsse:SecurityTokenReference
/ds:KeyInfo
/ds:Signature
/wsse:Security
<wsa:MessageID soapenv:mustUnderstand="0">uuid:302caa30-60ca-11e2-8fd5-db8b3dff3bdb/wsa:MessageID
<wsa:To soapenv:mustUnderstand="0">https://172.168.1.101:8443/JWSSMsgService-1.0/services/JWSSMsg/wsa:To
<wsa:Action soapenv:mustUnderstand="0">urn:JWSSMsgService/sendMessage/wsa:Action
<wsa:From soapenv:mustUnderstand="0">
wsa:Addresshttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous/wsa:Address
/wsa:From
/soapenv:Header
<soapenv:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-2141355741">

Wk5SIFVVVVVVDQ0KUCAwMTE2NTBaIEZFQiAxMQ0NCkZNIEpDRFhURVNUDQ0KVE8gSkNEWA0NCkJUDQ0KVU5DTEFTDQ0KTVNHSUQvSkNEWFRFU1QvR09MRC85MC9GRUINDQpDVEMvOTAvQzkwLU45MC8vLy8vVVMvOTAvLy8wMA0NClBPUy8wMTE2NTFaNC9GRUIvMDAwNk42LzAwMDAxRTEvT1RSDQ0KUklHL0dQMS9SQUlTRUQgMS0yLTMvQ1JVSVNFUi9NRktDR01GS0NHTS85OTk5OTkvOTBGVC9DSEsgUklHRklFTERTDQ0KQVJSL0xPUyBBTkdFTEVTL1VTLzA3MTY1OVo4L0FVRy8vDQ0KREVQL1NBTiBESUVHTyBQVC9VUy8wOTIyMzBaNi9BVUcvLw0NCkVOREFUL0RFQ0w6IFgxDQ0KQlQNDQoKCgoKCgpOTk5O



/soapenv:Body
/soapenv:Envelope

When I run the code I get:
[ 'invalid signature: for uri #id-2141355741 calculated digest is sWJn06HNJ9p3TkWxVRWf/BNaqN4= but the xml to validate supplies digest eH8rMl07vI5vfO0jI+riK8x4scc=' ]

So I started looking at how the digest is calculated and that's led to canonicalization. I changed SignedXml to print the result of canonicalization which is:

<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-2141355741">

Wk5SIFVVVVVVDQ0KUCAwMTE2NTBaIEZFQiAxMQ0NCkZNIEpDRFhURVNUDQ0KVE8gSkNEWA0NCkJUDQ0KVU5DTEFTDQ0KTVNHSUQvSkNEWFRFU1QvR09MRC85MC9GRUINDQpDVEMvOTAvQzkwLU45MC8vLy8vVVMvOTAvLy8wMA0NClBPUy8wMTE2NTFaNC9GRUIvMDAwNk42LzAwMDAxRTEvT1RSDQ0KUklHL0dQMS9SQUlTRUQgMS0yLTMvQ1JVSVNFUi9NRktDR01GS0NHTS85OTk5OTkvOTBGVC9DSEsgUklHRklFTERTDQ0KQVJSL0xPUyBBTkdFTEVTL1VTLzA3MTY1OVo4L0FVRy8vDQ0KREVQL1NBTiBESUVHTyBQVC9VUy8wOTIyMzBaNi9BVUcvLw0NCkVOREFUL0RFQ0w6IFgxDQ0KQlQNDQoKCgoKCgpOTk5O



/soapenv:Body

Then I wrote a small java app to see how that compared to the Axis/WSS4J version where I got:

 [java] <soapenv:Body wsu:Id="id-2141355741" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
 [java]     <message xmlns="urn:jwss.jcdx.org">
 [java]       <data>Wk5SIFVVVVVVDQ0KUCAwMTE2NTBaIEZFQiAxMQ0NCkZNIEpDRFhURVNUDQ0KVE8gSkNEWA0NCkJUDQ0KVU5DTEFTDQ0KTVNHSUQvSkNEWFRFU1QvR09MRC85MC9GRUINDQpDVEMvOTAvQzkwLU45MC8vLy8vVVMvOTAvLy8wMA0NClBPUy8wMTE2NTFaNC9GRUIvMDAwNk42LzAwMDAxRTEvT1RSDQ0KUklHL0dQMS9SQUlTRUQgMS0yLTMvQ1JVSVNFUi9NRktDR01GS0NHTS85OTk5OTkvOTBGVC9DSEsgUklHRklFTERTDQ0KQVJSL0xPUyBBTkdFTEVTL1VTLzA3MTY1OVo4L0FVRy8vDQ0KREVQL1NBTiBESUVHTyBQVC9VUy8wOTIyMzBaNi9BVUcvLw0NCkVOREFUL0RFQ0w6IFgxDQ0KQlQNDQoKCgoKCgpOTk5O</data>
 [java]       <dn xsi:nil="true"></dn>
 [java]       <signature xsi:nil="true"></signature>
 [java]     </message>
 [java]   </soapenv:Body>

ignore the [java] that is a by product of running from an ant script.

I'm curious as to why they are different. Which W3C spec did you follow for your implementation? Have you done any interoperability testing with other XML security implementations?

Enveloped Signature

Thanks for the efforts of maintaining this project. Unfortunately I have some issues using your code for my project.

1.Enveloped signature
How can I tell the xml-crypto to generate an enveloped signature? In the XML-Reference of my webservice provider the recommended structure is:

<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="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>b7VS5HX4x89oy7OhxvJ9V4mUFfQ=</DigestValue>
</Reference>
</SignedInfo>

2.Reference
In the XML demos above you can see my second problem the Reference Uri is expected to be empty but xml-crypto always generates a #_0 and inserts an id to the referenced Element. How can i prevent this behaviour?

<Reference URI="">

3.KeyValue missing
In the XML demos of my service provider always occurs a KeyValue-Class with appropriate content. How do i generate it with xml-crypto?

<KeyInfo>
    <X509Data>
        <X509Certificate>...</X509Certificate>
    </X509Data>
    <KeyValue>
        <RSAKeyValue>                   
           <Modulus>nbjs..bBRdU=</Modulus>
           <Exponent>AQAB</Exponent>
        </RSAKeyValue>
    </KeyValue>
</KeyInfo>

Example.js produces invalid xml

When running the example.js produces:
----CODE SNIPPET BEGINS HERE----
'<CanonicalizationM......Reduced for brevity..... Harry Potter'
----CODE SNIPPET ENDS HERE----

The root of the xml doc (library) is appended before book so the document is finished and the book is added to the end. The behavior is different from that in the tutorial

Namespace support for Signature?

Is there a way to specify the namespace for the signature?

For example:

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

Thank you for providing this package!

Use of Releases

Why you don't use a release management provided by github?

Don't you think that Is a better option than to put version just in package.json?

Append signature as last child of node being referenced?

Quoting from the readme:

sig.getSignedXml() returns the original xml document with the signature pushed as the last child of the root node.

Is there any way to customize it so that the signature is pushed as the last child of the node being referenced (instead of always the document root)?

Example:

<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response Version="2.0">
  <saml:Assertion Version="2.0" Id="_0">
    <saml:Subject>
      <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">Test</saml:NameID>
    </saml:Subject>
    <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>...</DigestValue>
        </Reference>
      </SignedInfo>
      <SignatureValue>...</SignatureValue>
    </Signature>
  </saml:Assertion>
</samlp:Response>

This is a valid thing to do, right? I don't know much about XML signatures, but OpenIDP (a SAML 2.0 Identity Provider) seems to sign XML in this manner. So does this Wikipedia example.

using v1.2 node got into issue when run npm test

✖ Exclusive canonicalization works on complex xml
✖ Exclusive canonicalization removes Comments

✖ signer creates correct signature values

Assertion Message: wrong signature format

AssertionError: '

✖ Exclusive canonicalization sorts upper case attributes before lower case

AssertionError: '' == ''

✖ verify valid signature

Assertion Message: expected signature to be valid, but it was reported invalid

FAILURES: 9/128 assertions failed (672ms)
npm ERR! Test failed. See above for more details.

How do I sign a root node?

var SignedXml = require('xml-crypto').SignedXml   
      , fs = require('fs')
var xml = "<library><book><name>Harry Potter</name</book></library>"
var sig = new SignedXml()
sig.addReference("//*[local-name(.)='library']")    
sig.signingKey = fs.readFileSync("my-cert.pem")
sig.computeSignature(xml)
var signed = sig.getSignedXml()

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

The following code above signs some sample xml and then validates the signature. It fails because the digests do not match. Presumably this is because I am attempting to sign the root node.

In your help file you say:

sig.getSignedXml() returns the original xml document with the signature pushed as the last child of
 the root node (as above). This assumes you are not signing the root node but only sub node(s) 
otherwise this is not valid. If you do sign the root node call sig.getSignatureXml() to get just the
 signature part and sig.getOriginalXmlWithIds() to get the original xml with Id attributes added on 
relevant elements (required for validation).

However I am afraid I don't understand what you mean by this. I would be very grateful if you could provide a code example of showing how to sign the root node of the test xml.

In actual fact I am looking to generate an enveloped signature. Is this possible with xml-crypto?

Thanks

xmldom dependency is a git repository

We are having issues with the dependency in the package.json for xmldom being a git repository reference. Which is then published in npm.

We are an enterprise and do not have a direct connection to the internet, so when we use projects that then depend on this project, it cannot resolve the xmldom, as we cannot connect to github from within our enterprise.

We do have an internal npm registry, so if your project actually referenced the xmldom from npm itself, then this would work correctly.

Is it possible that you can release a version of this library using the xmldom package from npm rather than the git repo reference?

Error validation

Hi, I'm validating an XML signed by xml-crypto, but always returns me a invalid message, I've attached the signed xml, the public key, and my coffeescript code to sign and verify

could you help me whit that please?

to sign

sign = new SignedXml()
sign.addReference "//*[local-name(.)='ConsultaSectorPrimario']" , "" , "" , "" , "" , "" , true
sign.keyInfoProvider = new MyKeyInfo( rfc )
sign.signingKey = fs.readFileSync( "./certificados/" + rfc + ".key.pem" )
sign.computeSignature xml
xml = 
[JAEP820923NM9_publicKey.key.pem.txt](https://github.com/yaronn/xml-    crypto/files/44482/JAEP820923NM9_publicKey.key.pem.txt)
[JAEP820923NM9_publicKey.key.pem.txt](https://github.com/yaronn/xml-    crypto/files/44483/JAEP820923NM9_publicKey.key.pem.txt)

[JAEP820923NM9-AOPF580423BIA.txt](https://github.com/yaronn/xml-crypto/files/44484/JAEP820923NM9-AOPF580423BIA.txt)

sign.getSignedXml()

to verify

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

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

sign anf verify in browser

Is there any tutorial to use xml-crypto for signing and verification without Node?

May I verify signed xml without xmldom?

As far as I know, I can clone to local folder and use browserify tool, am I right? I tried to do this, but console says something like XmlSigned object is not defined.

question

i have a question :

i want verify the windows store receipt with x509 ;
the xml is :












cdiU06eD8X/w1aGCHeaGCG9w/kWZ8I099rw4mmPpvdU=


SjRIxS/2r2P6ZdgaR9bwUSa6ZItYYFpKLJZrnAa3zkMylbiWjh9oZGGng2p6/gtBHC2dSTZlLbqnysJjl7mQp/A3wKaIkzjyRXv3kxoVaSV0pkqiPt04cIfFTP0JZkE5QD/vYxiWjeyGp1dThEM2RV811sRWvmEs/hHhVxb32e8xCLtpALYx3a9lW51zRJJN0eNdPAvNoiCJlnogAoTToUQLHs72I1dECnSbeNPXiG7klpy5boKKMCZfnVXXkneWvVFtAA1h2sB7ll40LEHO4oYN6VzD+uKd76QOgGmsu9iGVyRvvmMtahvtL1/pxoxsTRedhKq6zrzCfT8qfh3C1w==

the x509 is :
-----BEGIN CERTIFICATE-----
MIIDyTCCArGgAwIBAgIQNP+YKvSo8IVArhlhpgc/xjANBgkqhkiG9w0BAQsFADCB
jjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1Jl
ZG1vbmQxHjAcBgNVBAoMFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEWMBQGA1UECwwN
V2luZG93cyBTdG9yZTEgMB4GA1UEAwwXV2luZG93cyBTdG9yZSBMaWNlbnNpbmcw
HhcNMTExMTE3MjMwNTAyWhcNMzYxMTEwMjMxMzQ0WjCBjjELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcMB1JlZG1vbmQxHjAcBgNVBAoM
FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEWMBQGA1UECwwNV2luZG93cyBTdG9yZTEg
MB4GA1UEAwwXV2luZG93cyBTdG9yZSBMaWNlbnNpbmcwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQCcr4/vgqZFtzMqy3jO0XHjBUNx6j7ZTXEnNpLl2VSe
zVQA9KK2RlvroXKhYMUUdJpw+txm1mqi/W7D9QOYTq1e83GLhWC9IRh/OSmSYt0e
kgVLB+icyRH3dtpYcJ5sspU2huPf4I/Nc06OuXlMsD9MU4Ug9IBD2HSDBEquhGRo
xV64YuEH4645oB14LlEay0+JZlkKZ/mVhx/sdzSBfrda1X/Ckc7SOgnTSM3d/DnO
5DKwV2WYn+7i/rBqe4/op6IqQMrPpHyem9Sny+i0xiUMA+1IwkX0hs0gvHM6zDww
TMDiTapbCy9LnmMx65oMq56hhsQydLEmquq8lVYUDEzLAgMBAAGjITAfMB0GA1Ud
DgQWBBREzrOBz7zw+HWskxonOXAPMa6+NzANBgkqhkiG9w0BAQsFAAOCAQEAeVtN
4c6muxO6yfht9SaxEfleUBIjGfe0ewLBp00Ix7b7ldJ/lUQcA6y+Drrl7vjmkHQK
OU3uZiFbCxTvgTcoz9o+1rzR/WPXmqH5bqu6ua/UrobGKavAScqqI/G6o56Xmx/y
oErWN0VapN370crKJvNWxh3yw8DCl+W0EcVRiWX5lFsMBNBbVpK4Whp+VhkSJilu
iRpe1B35Q8EqOz/4RQkOpVI0dREnuSYkBy/h2ggCtiQ5yfvH5zCdcfhFednYDevS
axmt3W5WuHz8zglkg+OQ3qpXaXySRlrmLdxEmWu2MOiZbQkU2ZjBSQmvFAOy0dd6
P1YLS4+Eyh5drQJc0Q==
-----END CERTIFICATE-----

how can i use the lib to do the things ?

thanks!

Windows 8 Receipt

Hello,

I am trying to use your library to validate Windows 8 IAP receipts. Check the following examples:
http://msdn.microsoft.com/en-us/library/windows/apps/jj649137.aspx

The required public key can be downloaded here:
https://lic.apps.microsoft.com/licensing/certificateserver/?cid=b809e47cd0110a4db043b3f73e83acd917fe1336

The C# based validation succeeded. Then I wanted to try with this lib. I installed xml-crypro and xmldom with npm and run the provided example code:

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

function validateXml(xml, key)
{
  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(key)
  sig.loadSignature(signature.toString())
  var res = sig.checkSignature(xml)
  if (!res) console.log(sig.validationErrors)
  return res;
}

var signedXml = fs.readFileSync('d:\signed.xml').toString()

if (validateXml(signedXml, 'd:\certificate.pem'))
  console.log("signature is valid")
else
  console.log("signature not valid")

Unfortunately both receipts failed with the following messages respectively:

[ 'invalid signature: for uri  calculated digest is aFhvxdIChqWdWV7k+LcohKo9v7HhFztE2WRgsCJwrfA= but the xml to validate supplies digest cdiU06eD8X/w1aGCHeaGCG9w/kWZ8I099rw4mmPpvdU=' ]
signature not valid

[ 'invalid signature: for uri  calculated digest is nX743QRNHl9BL0/zF4v6lKuaD09FQua0HyiGfBO3J/Y= but the xml to validate supplies digest Uvi8jkTYd3HtpMmAMpOm94fLeqmcQ2KCrV1XmSuY1xI=' ]
signature not valid

I am not a crypto expert, but it seems all the required algorithms are included in the lib. What could be the problem? Am I missing something?

Thank you!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.