Coder Social home page Coder Social logo

xml-crypto's Introduction

Node SAML

Build Status npm version code style: prettier codecov DeepScan grade

NPM

This is a SAML 2.0 authentication provider for Node.js.

Sponsors

We gratefully acknowledge support from our sponsors:

If your company benefits from node-saml being secure and up-to-date, consider asking them to sponsor the project at $25/month. See the Github Sponsors page for more sponsorship levels. It's easy to do, appearing as another line-item on the Github bill they already have.

Installation

npm install @node-saml/node-saml

Usage

The examples utilize the Feide OpenIdp identity provider. You need an account there to log in with this. You also need to register your site as a service provider.

Configure strategy

The SAML identity provider will redirect you to the URL provided by the path configuration.

const { SAML } = require("@node-saml/node-saml");

const options = {};
const saml = new SAML(options);

Config parameter details

  • Core

  • callbackUrl: full callbackUrl

  • entryPoint: identity provider entrypoint (is required to be spec-compliant when the request is signed)

  • issuer: issuer string to supply to identity provider

  • audience: expected saml response Audience, defaults to value of Issuer (if false, Audience won't be verified)

  • idpCert: the IDP's public signing certificate used to validate the signatures of the incoming SAML Responses, see Security and signatures

  • privateKey: see Security and signatures.

  • publicCert: the service provider's public signing certificate used to embed in AuthnRequest in order for the IDP to validate the signatures of the incoming SAML Request, see Security and signatures

  • decryptionPvk: optional private key that will be used to attempt to decrypt any encrypted assertions that are received

  • signatureAlgorithm: valid values are 'sha1', 'sha256', or 'sha512'

  • digestAlgorithm: optionally set the digest algorithm used to provide a digest for the signed data object, valid values are 'sha1' (default), 'sha256', or 'sha512'

  • xmlSignatureTransforms: optionally set an array of signature transforms to be used in HTTP-POST signatures. By default this is [ 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#' ]

  • Additional SAML behaviors

  • additionalParams: dictionary of additional query params to add to all requests; if an object with this key is passed to authenticate, the dictionary of additional query params will be appended to those present on the returned URL, overriding any specified by initialization options' additional parameters (additionalParams, additionalAuthorizeParams, and additionalLogoutParams)

  • additionalAuthorizeParams: dictionary of additional query params to add to 'authorize' requests

  • identifierFormat: optional name identifier format to request from identity provider (default: urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress)

  • allowCreate: grants permission to the identity provider to create a new subject identifier (default: true)

  • spNameQualifier: optionally specifies that the assertion subject's identifier be returned (or created) in the namespace of another service provider, or in the namespace of an affiliation of service providers

  • wantAssertionsSigned: if true, add WantAssertionsSigned="true" to the metadata, to specify that the IdP should always sign the assertions. It is on by default. Note: either the response or the assertion must be signed even if both are turned off.

  • wantAuthnResponseSigned: if true, require that all incoming authentication response messages be signed at the top level, not just at the assertions. It is on by default. Note: either the response or the assertion must be signed even if both are turned off.

  • acceptedClockSkewMs: Time in milliseconds of skew that is acceptable between client and server when checking OnBefore and NotOnOrAfter assertion condition validity timestamps. Setting to -1 will disable checking these conditions entirely. Default is 0.

  • maxAssertionAgeMs: Amount of time after which the framework should consider an assertion expired. If the limit imposed by this variable is stricter than the limit imposed by NotOnOrAfter, this limit will be used when determining if an assertion is expired.

  • attributeConsumingServiceIndex: optional AttributeConsumingServiceIndex attribute to add to AuthnRequest to instruct the IDP which attribute set to attach to the response (link)

  • disableRequestedAuthnContext: if truthy, do not request a specific authentication context.

  • authnContext: if truthy, name identifier format to request auth context (default: urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport); array of values is also supported

  • racComparison: Requested Authentication Context comparison type. Possible values are 'exact','minimum','maximum','better'. Default is 'exact'.

  • forceAuthn: if set to true, the initial SAML request from the service provider specifies that the IdP should force re-authentication of the user, even if they possess a valid session.

  • passive: if set to true, specifies that the IdP must not visibly take control of the user interface and interact with the user.

  • providerName: optional human-readable name of the requester for use by the presenter's user agent or the identity provider

  • skipRequestCompression: if set to true, the SAML request from the service provider won't be compressed.

  • authnRequestBinding: if set to HTTP-POST, will request authentication from IDP via HTTP POST binding, otherwise defaults to HTTP Redirect

  • disableRequestAcsUrl: if truthy, SAML AuthnRequest from the service provider will not include the optional AssertionConsumerServiceURL. Default is falsy so it is automatically included.

  • generateUniqueId: optional function which will be called to generate unique IDs for SAML requests.

  • scoping: An optional configuration which implements the functionality explained in the SAML spec paragraph "3.4.1.2 Element ". The config object is structured as following:

  • signMetadata: if true, adds a signature to the generated Service Provider metadata. privateKey must be set to use this option.

{
  idpList: [ // optional
    {
      entries: [ // required
        {
          providerId: 'yourProviderId', // required for each entry
          name: 'yourName', // optional
          loc: 'yourLoc', // optional
        }
      ],
      getComplete: 'URI to your complete IDP list', // optional
    },
  ],
  proxyCount: 2, // optional
  requesterId: 'requesterId', // optional
}
  • InResponseTo Validation

  • validateInResponseTo:

    • if "always", then InResponseTo will be validated from incoming SAML responses
    • if "never", then InResponseTo won't be validated
    • if "ifPresent", then InResponseTo will only be validated if present in the incoming SAML response
  • requestIdExpirationPeriodMs: Defines the expiration time when a Request ID generated for a SAML request will not be valid if seen in a SAML response in the InResponseTo field. Default is 8 hours.

  • cacheProvider: Defines the implementation for a cache provider used to store request Ids generated in SAML requests as part of InResponseTo validation. Default is a built-in in-memory cache provider. For details see the 'Cache Provider' section.

  • Issuer Validation

  • idpIssuer: if provided, then the IdP issuer will be validated for incoming Logout Requests/Responses. For ADFS this looks like https://acme_tools.windows.net/deadbeef

  • Passport

  • passReqToCallback: if truthy, req will be passed as the first argument to the verify callback (default: false)

  • name: Optionally, provide a custom name. (default: saml). Useful If you want to instantiate the strategy multiple times with different configurations, allowing users to authenticate against multiple different SAML targets from the same site. You'll need to use a unique set of URLs for each target, and use this custom name when calling passport.authenticate() as well.

  • Logout

  • logoutUrl: base address to call with logout requests (default: entryPoint)

  • additionalLogoutParams: dictionary of additional query params to add to 'logout' requests

  • logoutCallbackUrl: The value with which to populate the Location attribute in the SingleLogoutService elements in the generated service provider metadata.

  • SAML Authn Request Extensions

  • samlAuthnRequestExtensions: Optional, The SAML extension provides a more flexible structure for expressing which combination of Attributes are requested by service providers in comparison to the existing mechanisms, More about extensions. There are many possible values for the samlAuthnRequestExtensions element. It accepts fully customize XMLBuilder type.

// Example
samlAuthnRequestExtensions: {
  "md:RequestedAttribute": {
    "@isRequired": "true",
    "@Name": "LastName",
    "@xmlns:md": "urn:oasis:names:tc:SAML:2.0:metadata"
  },
  vetuma: {
    "@xmlns": "urn:vetuma:SAML:2.0:extensions",
    LG: {
      "#text": "sv",
    },
  },
},
  • SAML Logout Request Extensions
  • samlLogoutRequestExtensions: Optional, The SAML extension provides a more flexible structure for expressing which combination of Attributes are requested by service providers in comparison to the existing mechanisms, More about extensions. There are many possible values for the samlLogoutRequestExtensions element. It accepts fully customize XMLBuilder type.
// Example
samlLogoutRequestExtensions: {
  vetuma: {
    "@xmlns": "urn:vetuma:SAML:2.0:extensions",
    LG: {
      "#text": "sv",
    },
  },
},
  • SAML metadata Extensions
  • metadataContactPerson: Optional, this parameters can be used to include more metadata in the XML generated by generateServiceProviderMetadata. There are many possible values for the metadataContactPerson element. You can check the type definitions for help.
  • metadataOrganization: Optional, this parameters can be used to include more metadata in the XML generated by generateServiceProviderMetadata. There are many possible values for the metadataOrganization element. You can check the type definitions for help.
// Example for metadataContactPerson
metadataContactPerson:  [{
  "@contactType": "support",
  "GivenName": "test",
  "EmailAddress": "test@node-saml",
}],
// ContactPerson is an array because there can be multiple ContactPerson fields

generateServiceProviderMetadata( decryptionCert, publicCert )

As a convenience, the strategy object exposes a generateServiceProviderMetadata method which will generate a service provider metadata document suitable for supplying to an identity provider.

The decryptionCert argument should be a public certificate matching the decryptionPvk and is required if the strategy is configured with a decryptionPvk.

The publicCert argument should be a public certificate matching the privateKey and is required if the strategy is configured with a privateKey. An array of certificates can be provided to support certificate rotation. When supplying an array of certificates, the first entry in the array should match the current privateKey. Additional entries in the array can be used to publish upcoming certificates to IdPs before changing the privateKey.

generateServiceProviderMetadata( params )

The underlying generateServiceProviderMetadata function is also exported directly. This is useful if you want to generate metadata without creating a strategy object.

const { generateServiceProviderMetadata } = require("@node-saml/node-saml");

const metadata = generateServiceProviderMetadata({
  issuer: "https://example.com",
  callbackUrl: "https://example.com/callback",
});

Security and signatures

Node-SAML uses the HTTP Redirect Binding for its AuthnRequests (unless overridden with the authnRequestBinding parameter), and expects to receive the messages back via the HTTP POST binding.

Configuration option signatureAlgorithm

Authentication requests sent by Node-SAML can be signed using RSA signature with SHA1, SHA256 or SHA512 hashing algorithms.

To select hashing algorithm, use:

signatureAlgorithm: 'sha1' // (default, but not recommended anymore these days)
signatureAlgorithm: 'sha256', // (preferred - your IDP should support it, otherwise think about upgrading it)
signatureAlgorithm: 'sha512' // (most secure - check if your IDP supports it)

Configuration option privateKey

To sign authentication requests, private key needs to be provide in the PEM format via the privateKey configuration property. Node-SAML is enforcing RFC7468 stricttextualmsg format for PEM files.

Add it to strategy options like this:

privateKey: fs.readFileSync("./privateKey.pem", "latin1");

Example formats for privateKey field are,

  1. RFC7468 stricttextualmsg formatted PEM:
-----BEGIN PRIVATE KEY-----
<private key contents here delimited at 64 characters per row>
-----END PRIVATE KEY-----

or

-----BEGIN RSA PRIVATE KEY-----
<private key contents here delimited at 64 characters per row>
-----END RSA PRIVATE KEY-----
  1. Alternatively, a single-line or multi-line private key in Base64 format. See example from tests of single line private key.

Configuration option idpCert

It is important to validate the signatures of the incoming SAML Responses. For this, provide the Identity Provider's public X.509 signing certificate(s) or public key(s) in RFC7468 stricttextualmsg PEM format via the idpCert configuration property.

Important, provided public key MUST always be in PEM format!

Add it to options like this:

idpCert: "MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W==";

or

If the Identity Provider has multiple signing certificates or public keys that are valid then the idpCert configuration property can be an array. This can be the case during the rolling from an old key to a new key and responses signed with either key are valid:

idpCert: ["MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W==", "MIIEOTCCAyGgAwIBAgIJAKZgJdKdCdL6M ... g="];

or

The idpCert configuration property can also be a function that receives a callback as argument calls back a possible error and a certificate or array of certificates or a public key or array of public keys. This allows the Identity Provider to be polled for valid certificates or public keys and the new certificate or public key can be used if it is changed:

idpCert: (callback) => {
  callback(null, polledCertificates);
};

Example formats for idpCert field are,

  1. RFC7468 stricttextualmsg formatted PEM:
-----BEGIN CERTIFICATE-----
<certificate contents here delimited at 64 characters per row>
-----END CERTIFICATE-----

or

-----BEGIN PUBLIC KEY-----
<public key contents here delimited at 64 characters per row>
-----END PUBLIC KEY-----
  1. Alternatively, a single-line or multi-line certificate in Base64 format.

TIP: If the certificate is in the binary DER encoding

Convert it to the necessary PEM encoding like this:

openssl x509 -inform der -in my_certificate.cer -out my_certificate.pem

Some identity providers require that the public signing certificate be embedded in AuthnRequest in order for the IDP to verify the request as well as match the subject DN and confirm if the certificate was signed. This can be achieved by passing service provider's public signing certificate in PEM format via the publicCert configuration key. The publicCert should be a public certificate matching the privateKey.

-----BEGIN CERTIFICATE-----
<X.509 certificate contents here delimited at 64 characters per row>
-----END CERTIFICATE-----

Alternativelly a single line X.509 certificate without start/end lines where all rows are joined into single line can be passed:

publicCert: "MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W==";

SAML Response Validation - NotBefore and NotOnOrAfter

If the NotBefore or the NotOnOrAfter attributes are returned in the SAML response, Node-SAML will validate them against the current time +/- a configurable clock skew value. The default for the skew is 0s. This is to account for differences between the clock time on the client (Node server with Node-SAML) and the server (Identity provider).

NotBefore and NotOnOrAfter can be part of either the SubjectConfirmation element, or within in the Assertion/Conditions element in the SAML response.

Subject confirmation validation

When configured (turn validateInResponseTo to always in the Node-SAML config), the InResponseTo attribute will be validated. Validation will succeed if Node-SAML previously generated a SAML request with an id that matches the value of InResponseTo.

Also note that InResponseTo is validated as an attribute of the top level Response element in the SAML response, as well as part of the SubjectConfirmation element.

Previous request id's generated for SAML requests will eventually expire. This is controlled with the requestIdExpirationPeriodMs option passed into the Node-SAML config. The default is 28,800,000 ms (8 hours). Once expired, a subsequent SAML response received with an InResponseTo equal to the expired id will not validate and an error will be returned.

Cache Provider

When InResponseTo validation is turned on, Node SAML will store generated request ids used in SAML requests to the IdP. The implementation of how things are stored, checked to see if they exist, and eventually removed is handled by the configured CacheProvider.

The default implementation is a simple in-memory cache provider. For multiple server/process scenarios, this will not be sufficient as the server/process that generated the request id and stored in memory could be different than the server/process handling the SAML response. The InResponseTo could fail in this case erroneously.

To support this scenario you can create a cache provider that implements the following interface:

interface CacheProvider {
  // Store an item in the cache, using the specified key and value.
  saveAsync(key: string, value: string): Promise<CacheItem | null>;
  // Returns the value of the specified key in the cache
  getAsync(key: string): Promise<string | null>;
  // Removes an item from the cache if the key exists
  removeAsync(key: string): Promise<string | null>;
}

SLO (single logout)

Node-SAML has built in support for SLO including

  • Signature validation
  • IdP initiated and SP initiated logouts
  • Decryption of encrypted name identifiers in IdP initiated logout
  • Redirect and POST SAML Protocol Bindings

ChangeLog

See Changelog

FAQ

Node Support Policy

We only support Long-Term Support versions of Node.

We specifically limit our support to LTS versions of Node, not because this package won't work on other versions, but because we have a limited amount of time, and supporting LTS offers the greatest return on that investment.

It's possible this package will work correctly on newer versions of Node. It may even be possible to use this package on older versions of Node, though that's more unlikely as we'll make every effort to take advantage of features available in the oldest LTS version we support.

As each Node LTS version reaches its end-of-life we will remove that version from the node engines property of our package's package.json file. Removing a Node version is considered a breaking change and will entail the publishing of a new major version of this package. We will not accept any requests to support an end-of-life version of Node. Any merge requests or issues supporting an end-of-life version of Node will be closed.

We will accept code that allows this package to run on newer, non-LTS, versions of Node.

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

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. ๐ŸŽ‰

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.

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.

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

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.

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

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>

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!

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.

new version?

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

Thanks!

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

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

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

};

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

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.

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

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?

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?

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!

A typo in README

There is a small typo in README.md.

You can choose one ore more.

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?

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.

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

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,

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!

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!

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?

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?

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?

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>

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

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

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?

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?

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>

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

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?

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!

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)

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

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:


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.