Git Product home page Git Product logo

signer's Introduction

Signer

Gem Version

WS Security XML Certificate signing for Ruby

Installation

gem install signer

Usage

require "signer"

signer = Signer.new(File.read("example.xml"))
signer.cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
signer.private_key = OpenSSL::PKey::RSA.new(File.read("key.pem"), "password")

signer.document.xpath("//u:Timestamp", { "u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" }).each do |node|
  signer.digest!(node)
end

signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing" }).each do |node|
  signer.digest!(node)
end

signer.sign!(:security_token => true)

signer.to_xml

Usage with Savon

client = Savon::Client.new do |wsdl, http|
  wsdl.document = "..."
  wsdl.endpoint = "..."
end

response = client.request(:search_documents) do
  soap.version = 2
  soap.xml do
    builder = Nokogiri::XML::Builder.new do |xml|
      xml.send("s:Envelope",
        "xmlns:s" => "http://www.w3.org/2003/05/soap-envelope",
        "xmlns:a" => "http://www.w3.org/2005/08/addressing",
        "xmlns:u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
      ) do
        xml.send("s:Header") do
          xml.send("a:Action", "s:mustUnderstand" => "1") do
            xml.text "http://tempuri.org/IDocumentService/SearchDocuments"
          end
          xml.send("a:MessageID") do
            xml.text "urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b"
          end
          xml.send("a:ReplyTo") do
            xml.send("a:Address") do
              xml.text "http://www.w3.org/2005/08/addressing/anonymous"
            end
          end
          xml.send("a:To", "a:mustUnderstand" => "1") do
            xml.text "..."
          end
          xml.send("o:Security",
            "xmlns:o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
            "s:mustUnderstand" => "1"
          ) do
            xml.send("u:Timestamp") do
              time = Time.now.utc
              xml.send("u:Created") do
                xml.text(time.xmlschema)
              end
              xml.send("u:Expires") do
                xml.text((time + 5.minutes).xmlschema)
              end
            end
          end
        end
        xml.send("s:Body") do
          xml.send("SearchDocuments", "xmlns" => "http://tempuri.org/") do
            xml.send("searchCriteria",
              "xmlns:b" => "http://schemas.datacontract.org/2004/07/ZMDVS.BusinessLogic.Data.Documents.Integration",
              "xmlns:i" => "http://www.w3.org/2001/XMLSchema-instance"
            ) do
              xml.send("b:RegistrationNo") do
                xml.text "1"
              end
            end
          end
        end
      end
    end

    signer = Signer.new(builder.to_xml)
    signer.cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
    signer.private_key = OpenSSL::PKey::RSA.new(File.read("key.pem"), "test")

    signer.document.xpath("//u:Timestamp", { "u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" }).each do |node|
      signer.digest!(node)
    end

    signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing" }).each do |node|
      signer.digest!(node)
    end

    signer.sign!

    signer.to_xml
  end
end

Example

Input:

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://tempuri.org/IDocumentService/SearchDocuments</a:Action>
    <a:MessageID>urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <To xmlns="http://www.w3.org/2005/08/addressing" xmlns:a="http://www.w3.org/2003/05/soap-envelope" a:mustUnderstand="1">http://tempuri.org/PublicServices/Test/1.0.12/PublicServices/DocumentService.svc</To>
    <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
      <u:Timestamp>
        <u:Created>2012-05-02T18:17:14.467Z</u:Created>
        <u:Expires>2012-05-02T18:22:14.467Z</u:Expires>
      </u:Timestamp>
    </o:Security>
  </s:Header>
  <s:Body>
    <SearchDocuments xmlns="http://tempuri.org/">
      <searchCriteria xmlns:b="http://schemas.datacontract.org/2004/07/BusinessLogic.Data.Documents.Integration" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <b:RegistrationNo>1</b:RegistrationNo>
      </searchCriteria>
    </SearchDocuments>
  </s:Body>
</s:Envelope>

Output:

<?xml version="1.0"?>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <s:Header>
    <a:Action s:mustUnderstand="1">http://tempuri.org/IDocumentService/SearchDocuments</a:Action>
    <a:MessageID>urn:uuid:30db5d4f-ab84-46be-907c-be690a92979b</a:MessageID>
    <a:ReplyTo>
      <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
    </a:ReplyTo>
    <To xmlns="http://www.w3.org/2005/08/addressing" xmlns:a="http://www.w3.org/2003/05/soap-envelope" a:mustUnderstand="1" u:Id="_7e75a8ded22253b163ca76a40b6cc0c670ed0c33">http://tempuri.org/PublicServices/Test/1.0.12/PublicServices/DocumentService.svc</To>
    <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
      <u:Timestamp u:Id="_23dd13bb673d95ac7c29f0bebcca8268d39675b1">
        <u:Created>2012-05-02T18:17:14.467Z</u:Created>
        <u:Expires>2012-05-02T18:22:14.467Z</u:Expires>
      </u:Timestamp>
      <o:BinarySecurityToken u:Id="uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIICsDCCAhmgAwIBAgIJAOUHvh4oho0tMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwHhcNMTIwNTAzMTMxODIyWhcNMTMwNTAzMTMxODIyWjBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvK5hMPv/R5IFmwWyJOyEaFUrF/ZsmN+Gip8hvR6rLP3YPNx9iFYvPcZllFmuVwyaz7YT2N5BsqTwLdyi5v4HY4fUtuz0p8jIPoSd6dfDvcnSpf4QLTOgOaL3ciPEbgDHH2tnIksukoWzqCYva+qFZ74NFl19swXotW9fA4Jzs4QIDAQABo4GnMIGkMB0GA1UdDgQWBBRU1WEHDnP8Hr7ZulxrSzEwOcYpMzB1BgNVHSMEbjBsgBRU1WEHDnP8Hr7ZulxrSzEwOcYpM6FJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAOUHvh4oho0tMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEASY/9SAOK57q9mGnNJJeyDbmyGrAHSJTod646xTHYkMvhUqwHyk9PTr5bdfmswpmyVn+AQ43U2tU5vnpTBmKpHWD2+HSHgGa92mMLrfBOd8EBZ329NL3N2HDPIaHr4NPGyhNrSK3QVOnAq2D0jlyrGYJlLli1NxHiBz7FCEJaVI8=</o:BinarySecurityToken>
      <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="#_23dd13bb673d95ac7c29f0bebcca8268d39675b1">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>Oz29YgZk14+nchoqv9zGzhJcDUo=</DigestValue>
          </Reference>
          <Reference URI="#_7e75a8ded22253b163ca76a40b6cc0c670ed0c33">
            <Transforms>
              <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            </Transforms>
            <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
            <DigestValue>leV/RNYhwuCuD7/DBzn3IgQzUxI=</DigestValue>
          </Reference>
        </SignedInfo>
        <SignatureValue>en7YYAIn90ofH08aF917jNngMuse+vK6bihF0v6UsXFnGGMOflWfRTZ6mFmC2HwLmb2lSrhZ3eth3cs2fCBlEr/K2ZDMQfJo6CPxmbzfX/fxR/isCTDz+HIJd13J0HK4n+CzkndwplkCmT8SQlduUruUFUUmlQiiZQ7nryR+XyM=</SignatureValue>
        <KeyInfo>
          <o:SecurityTokenReference>
            <o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1"/>
          </o:SecurityTokenReference>
        </KeyInfo>
      </Signature>
    </o:Security>
  </s:Header>
  <s:Body>
    <SearchDocuments xmlns="http://tempuri.org/">
      <searchCriteria xmlns:b="http://schemas.datacontract.org/2004/07/BusinessLogic.Data.Documents.Integration" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <b:RegistrationNo>1</b:RegistrationNo>
      </searchCriteria>
    </SearchDocuments>
  </s:Body>
</s:Envelope>

Different signature and digest algorithms support

You can change digest algorithms used for both node digesting and signing. Default for both is SHA1. Currently SHA1 :sha1, SHA256 :sha256, and GOST R 34.11-94 :gostr3411 are supported out of the box.

signer.digest_algorithm           = :sha256 # Set algorithm for node digesting
signer.signature_digest_algorithm = :sha256 # Set algorithm for message digesting for signing

You can provide you own digest support by passing in these methods a Hash with :id and :digester keys. In :id should be a string for XML //Reference/DigestMethod[Algorithm], in :digester should be a Ruby object, compatible by interface with OpenSSL::Digest class, at least it should respond to digest and reset methods.

Signature algorithm is dependent from keypair used for signing and can't be changed. Usually it's RSA. Currently gem recognizes GOST R 34.10-2001 certificates and sets up a XML identifier for it. If used signature algorithm and signature digest doesn't corresponds with XML identifier, you can change identifier with signature_algorithm_id method.

Please note, that these settings will be changed or reset on certificate assignment, please change them after setting certificate!

NOTE: To sign XMLs with GOST R 34.10-2001, you need to have Ruby compiled with patches from https://bugs.ruby-lang.org/issues/9830 and correctly configured OpenSSL (see https://github.com/openssl/openssl/blob/master/engines/ccgost/README.gost)

Miscellaneous

Every new instance of signer has Nokogiri noblanks set as default in process of parsing xml file. If you need to disable it, pass optional argument noblanks: false.

Signer.new(File.read("example.xml"), noblanks: false)

Available options for the sign! method:

  • [:security_token] - Serializes certificate in DER format, encodes it with Base64 and inserts it within a BinarySecurityToken tag

If you need to digest a BinarySecurityToken tag, you need to construct it yourself before signing.

signer.digest!(signer.binary_security_token_node) # Constructing tag and digesting it
signer.sign! # No need to pass a :security_token option, as we already constructed and inserted this node
  • [:inclusive_namespaces] - Array of namespace prefixes which definitions should be added to signed info node during canonicalization

If you need Signature tags to be in explicit namespace (say, <ds:Signature>) instead of to be in implicit default namespace you can specify next option:

signer.ds_namespace_prefix = 'ds'

If you need to use canonicalization with inclusive namespaces you can pass array of namespace prefixes in :inclusive_namespaces option in both digest! and sign! methods.

  • [:issuer_serial] - flag to include a X509Data node to include information from a X509Certificate
  • [:issuer_in_security_token] - flag to include the X509Data inside a SecurityTokenReference element

signer's People

Contributors

ebeigarts avatar ekzobrain avatar envek avatar flavorjones avatar kunxi-stripe avatar pistachiology avatar tiagocasanovapt 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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

signer's Issues

Ability to change Transform Algorithm and Reference URI

Hi @ebeigarts!

Thank you so much for this gem. It's such a useful gem which helps me a lot in my project.

I'd like to check if is possible to:

  1. Change the Transform Algorithm to a custom value. For example:
<ds:Transform Algorithm="http://docs.oasis-open.org/wss/oasis-wss-SwAProfile-1.1#Attachment-Content-Signature-Transform">
</ds:Transform>
  1. Change the Reference URI to a custom prefix value. Currently, the default prefix value is #, but I need to change it to cid:, for example:
<ds:Reference URI="cid:_4d04c73564c93cd278b27cbaaa1f8339cc899963">
</ds:Reference>

I'd be so happy if I can submit a pull request to help implementing those stuffs. Thank you!

gost2012, ruby > 2.3.1

good day
will you upgrade your gem to provide support for gost2012 and ruby bigger, then 2.3.1?
or there is no hope?)

Convert example to Savon2

Because Savon2 do not have request method (substituted by "call"), can someone update the example in Code tab?

Some support question

I'm trying to connect my app with a provider, in the specs they wrote "In order to warranty the functionality of non repudiation, we use ws-security, specifically XML signature ", Is where "signer" fits?

RequireIssuerSerialReference in the SecurityTokenReference

Hello,
Thanks for putting together a Ruby Implementation for ws-security. It is a great library.

Currently the SecurityTokenReference creates a reference to the Binary Security Token Reference. In the project I am working, the WSDL requires an IssuerSerialReference for the x509 Token:

<sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
    <wsp:Policy>
    <sp:RequireIssuerSerialReference />
    <sp:WssX509V3Token10 />
  </wsp:Policy>

Would it be feasible to update the binary_security_token_node method in signer.rb to optionally include the X509IssuerSerial rather than just a reference. Maybe this could be a config switch?

An example XML snippet is here:

 <wsse:SecurityTokenReference
     xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
     xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
     wsu:Id="STR-c611951a-716b-4679-ad0b-58d07f25d839">
     <ds:X509Data>
         <ds:X509IssuerSerial>
           <ds:X509IssuerName>1.2.840.113549.1.9.1=#161961646d696e6973747261746f72407665726d6f6e742e676f76,CN=someCN,OU=someUR,O=ORG,L=City,ST=State,C=US</ds:X509IssuerName>
             <ds:X509SerialNumber>17878663088277022668</ds:X509SerialNumber>
         </ds:X509IssuerSerial>
     </ds:X509Data>
 </wsse:SecurityTokenReference>

The method x509_data_node does something similar but it includes the x509 data in a different node and not the wsse:SecurityTokenReference.

Thanks!
Yogesh

Output ds:Signature instead of Signature

Hi!

I would like to customize output of signature elements and output it with ds namespace. But I failed. Here is my code:

require 'openssl'
require 'signer'

class MySigner
  def initialize
    @soap_envelope = File.open('./data/soap_envelope.xml') { |f| Nokogiri::XML(f) }
  end

  def sign(xml_to_sign)
    signer = Signer.new(put_in_envelope(xml_to_sign))
    signer.cert = OpenSSL::X509::Certificate.new(File.read("./data/cert.pem"))
    signer.private_key = OpenSSL::PKey.read(File.read("./data/key.pem"), "PASSWORD")
    signer.security_token_id = 'CertId'

    namespaces = {
      'soap' => 'http://schemas.xmlsoap.org/soap/envelope/',
      'ds' => 'http://www.w3.org/2000/09/xmldsig#'
    }

    # Digest soap:Body tag
    signer.document.xpath('//TransferMsg', namespaces).each do |node|
      signer.digest!(node, id: 'body')
    end

    # Sign document itself
    signer.sign!(security_token: true, enveloped: true)

    signer.to_xml
  end

  def put_in_envelope(xml)
    xml_object = Nokogiri::XML(xml)
    valuable_data = xml_object.xpath('/TransferMsg').to_s
    @soap_envelope.xpath('//soap:Body').children.first.add_next_sibling(valuable_data)
    @soap_envelope
  end
end  

soap_envelope.xml:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                   xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
                   xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
  <soap:Header>
    <wsse:Security soap:actor="http://smev.gosuslugi.ru/actors/smev"
                   xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
    </wsse:Security>
  </soap:Header>
  <soap:Body wsu:Id="body">
  </soap:Body>
</soap:Envelope>

xml_to_sign example:

<TransferMsg>
   <DataToDigest>Super Important Data</DataToDigest>
</TransferMsg>

Actual output:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <soap:Header>
        <wsse:Security soap:actor="http://smev.gosuslugi.ru/actors/smev" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:BinarySecurityToken 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">MIIIRzCCB/agAwIBAgIKSchnBgAAAAGKvDAIBgYqhQMCAgMwggFOMRgwFgYFKoUDZAESDTEwMjc3MDcwMTM4MDYxGjAYBggqhQMDgQMBARIMMDA3NzA3MzE0MDI5MTwwOgYDVQQJDDPQkS7QodGD0YXQsNGA0LXQstGB0LrQuNC5INC/0LXRgCzQtDExLNGB0YLRgDEs0L7RhDYxIzAhBgkqhkiG9w0BCQEWFGUtbW9za3ZhQGUtbW9za3ZhLnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMTUwMwYDVQQKDCzQntCQ0J4gItCt0LvQtd=</wsse:BinarySecurityToken>
            <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/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
                </SignedInfo>
                <SignatureValue>vnjz04yWa7DbRtC5vJAt/tsCR5m31i3e8FMxG2eOIo4DtsGhm1FgZ8wKLEEzvbYuolrosc2OKkFafqJinsTWsg==</SignatureValue>
                <KeyInfo>
                    <wsse:SecurityTokenReference>
                        <wsse:Reference URI="#CertId" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </KeyInfo>
            </Signature>
        </wsse:Security>
    </soap:Header>
    <soap:Body wsu:Id="body">
        <soap:TransferMsg>
            <soap:DataToDigest>Super Important Data</soap:DataToDigest>
        </soap:TransferMsg>
    </soap:Body>
</soap:Envelope>

Expected output:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <soap:Header>
        <wsse:Security soap:actor="http://smev.gosuslugi.ru/actors/smev" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <wsse:BinarySecurityToken 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">MIIIRzCCB/agAwIBAgIKSchnBgAAAAGKvDAIBgYqhQMCAgMwggFOMRgwFgYFKoUDZAESDTEwMjc3MDcwMTM4MDYxGjAYBggqhQMDgQMBARIMMDA3NzA3MzE0MDI5MTwwOgYDVQQJDDPQkS7QodGD0YXQsNGA0LXQstGB0LrQuNC5INC/0LXRgCzQtDExLNGB0YLRgDEs0L7RhDYxIzAhBgkqhkiG9w0BCQEWFGUtbW9za3ZhQGUtbW9za3ZhLnJ1MQswCQYDVQQGEwJSVTEcMBoGA1UECAwTNzcg0LMuINCc0L7RgdC60LLQsDEVMBMGA1UEBwwM0JzQvtGB0LrQstCwMTUwMwYDVQQKDCzQntCQ0J4gItCt0LvQtd=</wsse:BinarySecurityToken>
            <ds:Signature>
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#gostr34102001-gostr3411"/>
                </ds:SignedInfo>
                <ds:SignatureValue>vnjz04yWa7DbRtC5vJAt/tsCR5m31i3e8FMxG2eOIo4DtsGhm1FgZ8wKLEEzvbYuolrosc2OKkFafqJinsTWsg==</SignatureValue>
                <ds:KeyInfo>
                    <wsse:SecurityTokenReference>
                        <wsse:Reference URI="#CertId" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </Signature>
        </wsse:Security>
    </soap:Header>
    <soap:Body wsu:Id="body">
        <soap:TransferMsg>
            <soap:DataToDigest>Super Important Data</soap:DataToDigest>
        </soap:TransferMsg>
    </soap:Body>
</soap:Envelope>

Am I missing something?

Should `transform` include both transform for if `option[:enveloped]` is true?

First, thanks for your hard work to address the XML signature pain. I just curious for the logic in transform! method, current implementation only includes one Transform node, such as:

    if options[:enveloped]
      transform_node['Algorithm'] = 'http://www.w3.org/2000/09/xmldsig#enveloped-signature'
    else
      transform_node['Algorithm'] = 'http://www.w3.org/2001/10/xml-exc-c14n#'
    end

I wonder whether the logic should be something like this as the xml-exc-c14n is also a Transform technically:

transform_nodes = [ TransformNode.new('http://www.w3.org/2001/10/xml-exc-c14n#')]
if options[:enveloped]
  transform_nodes.append(TransformNode.new('http://www.w3.org/2000/09/xmldsig#enveloped-signature'))
end

In another word, should we always include xml-exc-c14n# as a Transform?

Getting XMLSEC format with signer

I'm trying to get a xmlsec format with signer but I can´t create this. Any suggestion ?. I'm trying to create this format:

https://gist.github.com/patojimenez/84d22500611620b8b3bebea30243108a

someone has worked with this format ?. I tried with the single format:

signer/spec/signer_spec.rb

Lines 91 to 110 in 01f6527

it "should sign simple XML" do
input_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'input_2.xml')
cert_file = File.join(File.dirname(__FILE__), 'fixtures', 'cert.pem')
private_key_file = File.join(File.dirname(__FILE__), 'fixtures', 'key.pem')
signer = Signer.new(File.read(input_xml_file))
signer.cert = OpenSSL::X509::Certificate.new(File.read(cert_file))
signer.private_key = OpenSSL::PKey::RSA.new(File.read(private_key_file), "test")
signer.security_node = signer.document.root
signer.security_token_id = ""
signer.digest!(signer.document.root, :id => "", :enveloped => true)
signer.sign!(:issuer_serial => true)
# File.open(File.join(File.dirname(__FILE__), 'fixtures', 'output_2.xml'), "w") do |f|
# f.write signer.document.to_s
# end
output_xml_file = File.join(File.dirname(__FILE__), 'fixtures', 'output_2.xml')
signer.to_xml.should == Nokogiri::XML(File.read(output_xml_file), &:noblanks).to_xml(:save_with => 0)
end

but the format is very different.

Any suggestion ?

Removing namespaces and elements

Hi!

Thanks for this gem. I'm using it to sign some XML files here, but our local government has some custom and strict rules for the documents. I'm using this code:

signer  = Signer.new(data)
signer.cert = OpenSSL::X509::Certificate.new(File.read(files[:cert]))
signer.private_key  = OpenSSL::PKey::RSA.new(File.read(files[:key]), File.read(files[:pwd]).chomp)
signer.security_node  = signer.document.root
signer.security_token_id = ""
signer.digest!(signer.document.root, :id => "id", :enveloped => true)
signer.sign!(:issuer_serial => true)
signer.to_xml

And I'd like to check if is possible to:

  1. Remove namespaces. I need xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id" be removed from the main element. They just want their custom namespace.

  2. Remove some elements. To conform to their XSD, I need to remove the elements
    <X509SubjectName>, <X509IssuerSerial>, <KeyValue>, <RSAKeyValue>, <Modulus> and <Exponent>.

  3. Change reference URI. To conform to their XSD, I need to replace the "#id" on Reference URI="#id" to a custom one.

  4. Insert new elements. I need to insert <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> before `' ends.

  5. Remove new lines. They won't allow a new line after <?xml version="1.0"?>, I need the signed result to don't use newline character. I could remove on the result, but seems the sign would be invalid if it was there when signing.

Thanks!

NoMethodError: undefined method `at_xpath' for nil:NilClass

I'm probably missing something.

Assuming I have the file example.xml with the content:

<?xml version="1.0"?>
<tag>test</tag>

Then I followed your example, and executed the code (replacing the cert, key files and password):

require "signer"

signer = Signer.new(File.read("example.xml"))
signer.cert = OpenSSL::X509::Certificate.new(File.read("cert.pem"))
signer.private_key = OpenSSL::PKey::RSA.new(File.read("key.pem"), "password")

signer.document.xpath("//u:Timestamp", { "u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" }).each do |node|
  signer.digest!(node)
end

signer.document.xpath("//a:To", { "a" => "http://www.w3.org/2005/08/addressing" }).each do |node|
  signer.digest!(node)
end

signer.sign!(:security_token => true)

but I get NoMethodError: undefined method 'at_xpath' for nil:NilClass

Not compatible with Nokogiri >= 1.12.0

There is a problem with add_namespace_definition and the Signer in Nokogiri 1.12 and up. I am adding this ticket here so @flavorjones can see see the impact on this gem as he is working on a solution.

See sparklemotion/nokogiri#2317

There are a number of failing tests

Finished in 0.04294 seconds (files took 0.52242 seconds to load)
18 examples, 6 failures

Here is a sample via Nokogiri 1.12.3

node.add_namespace_definition('','wsse')
node.to_xml
=> "<BinarySecurityToken xmlns:=\"wsse\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\" EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">MIICs<<CUT>>>jlyrGYJlLli1NxHiBz7FCEJaVI8=</BinarySecurityToken>"

Here is another sample via Nokogiri 1.11.7

node.add_namespace_definition('','wsse')
node.to_xml
=> "<wsse:BinarySecurityToken xmlns:=\"wsse\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\" EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">MIICs<<CUT>>>jlyrGYJlLli1NxHiBz7FCEJaVI8=</wsse:BinarySecurityToken>"

The difference is the wsse is NOT added to the node in the 1.12.3 version.

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.