Class: Signer
- Inherits:
-
Object
- Object
- Signer
- Defined in:
- lib/signer.rb,
lib/signer/version.rb,
lib/signer/digester.rb
Defined Under Namespace
Classes: Digester
Constant Summary collapse
- WSU_NAMESPACE =
'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'
- VERSION =
"1.3.0"
- DIGEST_ALGORITHMS =
Digest algorithms supported “out of the box”
{ # SHA 1 sha1: { name: 'SHA1', id: 'http://www.w3.org/2000/09/xmldsig#sha1', digester: lambda { OpenSSL::Digest::SHA1.new }, }, # SHA 256 sha256: { name: 'SHA256', id: 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', digester: lambda { OpenSSL::Digest::SHA256.new }, }, # GOST R 34-11 94 gostr3411: { name: 'GOST R 34.11-94', id: 'http://www.w3.org/2001/04/xmldsig-more#gostr3411', digester: lambda { OpenSSL::Engine.load gost_engine = OpenSSL::Engine.by_id('gost') gost_engine.set_default(0xFFFF) gost_engine.digest('md_gost94') }, }, }
Instance Attribute Summary collapse
-
#cert ⇒ Object
Returns the value of attribute cert.
-
#document ⇒ Object
Returns the value of attribute document.
-
#private_key ⇒ Object
Returns the value of attribute private_key.
- #security_node ⇒ Object
- #security_token_id ⇒ Object
-
#signature_algorithm_id ⇒ Object
Returns the value of attribute signature_algorithm_id.
Instance Method Summary collapse
-
#binary_security_token_node ⇒ Object
<o:BinarySecurityToken u:Id=“” ValueType=“docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3” EncodingType=“docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary”> …
- #canonicalize(node = document) ⇒ Object
-
#digest!(target_node, options = {}) ⇒ Object
<Reference URI=“#_0”> <Transforms> <Transform Algorithm=“www.w3.org/2001/10/xml-exc-c14n#”/> </Transforms> <DigestMethod Algorithm=“www.w3.org/2000/09/xmldsig#sha1”/> <DigestValue>aeqXriJuUCk4tPNPAGDXGqHj6ao=</DigestValue> </Reference>.
-
#digest_algorithm ⇒ Object
Return symbol name for supported digest algorithms and string name for custom ones.
-
#digest_algorithm=(algorithm) ⇒ Object
Allows to change algorithm for node digesting (default is SHA1).
-
#initialize(document) ⇒ Signer
constructor
A new instance of Signer.
-
#sign!(options = {}) ⇒ Object
<SignatureValue>…</SignatureValue>.
-
#signature_digest_algorithm ⇒ Object
Return symbol name for supported digest algorithms and string name for custom ones.
-
#signature_digest_algorithm=(algorithm) ⇒ Object
Allows to change digesting algorithm for signature creation.
-
#signature_node ⇒ Object
<Signature xmlns=“www.w3.org/2000/09/xmldsig#”>.
-
#signed_info_node ⇒ Object
<SignedInfo> <CanonicalizationMethod Algorithm=“www.w3.org/2001/10/xml-exc-c14n#”/> <SignatureMethod Algorithm=“www.w3.org/2000/09/xmldsig#rsa-sha1”/> …
- #to_xml ⇒ Object
-
#x509_data_node ⇒ Object
<KeyInfo> <X509Data> <X509IssuerSerial> <X509IssuerName>System.Security.Cryptography.X509Certificates.X500DistinguishedName</X509IssuerName> <X509SerialNumber>13070789</X509SerialNumber> </X509IssuerSerial> <X509Certificate>MIID+jCCAuKgAwIBAgIEAMdxxTANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJTRTEeMBwGA1UEChMVTm9yZGVhIEJhbmsgQUIgKHB1YmwpMScwJQYDVQQDEx5Ob3JkZWEgcm9sZS1jZXJ0aWZpY2F0ZXMgQ0EgMDExFDASBgNVBAUTCzUxNjQwNi0wMTIwMB4XDTA5MDYxMTEyNTAxOVoXDTExMDYxMTEyNTAxOVowcjELMAkGA1UEBhMCU0UxIDAeBgNVBAMMF05vcmRlYSBEZW1vIENlcnRpZmljYXRlMRQwEgYDVQQEDAtDZXJ0aWZpY2F0ZTEUMBIGA1UEKgwLTm9yZGVhIERlbW8xFTATBgNVBAUTDDAwOTU1NzI0Mzc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwcgz5AzbxTbsCE51No7fPnSqmQBIMW9OiPkiHotwYQTl+H9qwDvQRyBqHN26tnw7hNvEShd1ZRGUg4drMEXDV5CmKqsAevs9lauWDaHnGKPNHZJ1hNNYXHwymksEz5zMnG8eqRdhb4vOV2FzreJeYpsgx31Bv0aTofHcHVz4uGcCAwEAAaOCASAwggEcMAkGA1UdEwQCMAAwEQYDVR0OBAoECEj6Y9/vU03WMBMGA1UdIAQMMAowCAYGKoVwRwEDMBMGA1UdIwQMMAqACEIFjfLBeTpRMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aubm9yZGVhLnNlL1JDQTAxMA4GA1UdDwEB/wQEAwIGQDCBiAYDVR0fBIGAMH4wfKB6oHiGdmxkYXA6Ly9sZGFwLm5iLnNlL2NuPU5vcmRlYSUyMHJvbGUtY2VydGlmaWNhdGVzJTIwQ0ElMjAwMSxvPU5vcmRlYSUyMEJhbmslMjBBQiUyMChwdWJsKSxjPVNFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwDQYJKoZIhvcNAQEFBQADggEBAEXUv87VpHk51y3TqkMb1MYDqeKvQRE1cNcvhEJhIzdDpXMA9fG0KqvSTT1e0ZI2r78mXDvtTZnpic44jX2XMSmKO6n+1taAXq940tJUhF4arYMUxwDKOso0Doanogug496gipqMlpLgvIhGt06sWjNrvHzp2eGydUFdCsLr2ULqbDcut7g6eMcmrsnrOntjEU/J3hO8gyCeldJ+fI81qarrK/I0MZLR5LWCyVG/SKduoxHLX7JohsbIGyK1qAh9fi8l6X1Rcu80v5inpu71E/DnjbkAZBo7vsj78zzdk7KNliBIqBcIszdJ3dEHRWSI7FspRxyiR0NDm4lpyLwFtfw=</X509Certificate> </X509Data> </KeyInfo>.
Constructor Details
#initialize(document) ⇒ Signer
Returns a new instance of Signer.
16 17 18 19 20 |
# File 'lib/signer.rb', line 16 def initialize(document) self.document = Nokogiri::XML(document.to_s, &:noblanks) self.digest_algorithm = :sha1 self.set_default_signature_method! end |
Instance Attribute Details
#cert ⇒ Object
Returns the value of attribute cert.
11 12 13 |
# File 'lib/signer.rb', line 11 def cert @cert end |
#document ⇒ Object
Returns the value of attribute document.
10 11 12 |
# File 'lib/signer.rb', line 10 def document @document end |
#private_key ⇒ Object
Returns the value of attribute private_key.
10 11 12 |
# File 'lib/signer.rb', line 10 def private_key @private_key end |
#security_node ⇒ Object
70 71 72 |
# File 'lib/signer.rb', line 70 def security_node @security_node ||= document.xpath("//o:Security", "o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").first end |
#security_token_id ⇒ Object
66 67 68 |
# File 'lib/signer.rb', line 66 def security_token_id @security_token_id ||= "uuid-639b8970-7644-4f9e-9bc4-9c2e367808fc-1" end |
#signature_algorithm_id ⇒ Object
Returns the value of attribute signature_algorithm_id.
10 11 12 |
# File 'lib/signer.rb', line 10 def signature_algorithm_id @signature_algorithm_id end |
Instance Method Details
#binary_security_token_node ⇒ Object
<o:BinarySecurityToken u:Id=“” ValueType=“docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3” EncodingType=“docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary”>
...
</o:BinarySecurityToken> <SignedInfo>
...
</SignedInfo> <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>
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/signer.rb', line 120 def binary_security_token_node node = document.xpath("//o:BinarySecurityToken", "o" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd").first unless node node = Nokogiri::XML::Node.new('BinarySecurityToken', document) node['ValueType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3' node['EncodingType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary' node.content = Base64.encode64(cert.to_der).gsub("\n", '') signature_node.add_previous_sibling(node) wsu_ns = namespace_prefix(node, WSU_NAMESPACE, 'wsu') node["#{wsu_ns}:Id"] = security_token_id key_info_node = Nokogiri::XML::Node.new('KeyInfo', document) security_token_reference_node = Nokogiri::XML::Node.new('o:SecurityTokenReference', document) key_info_node.add_child(security_token_reference_node) reference_node = Nokogiri::XML::Node.new('o:Reference', document) reference_node['ValueType'] = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3' reference_node['URI'] = "##{security_token_id}" security_token_reference_node.add_child(reference_node) signed_info_node.add_next_sibling(key_info_node) end node end |
#canonicalize(node = document) ⇒ Object
74 75 76 |
# File 'lib/signer.rb', line 74 def canonicalize(node = document) node.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0, nil, nil) # The last argument should be exactly +nil+ to remove comments from result end |
#digest!(target_node, options = {}) ⇒ Object
<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>aeqXriJuUCk4tPNPAGDXGqHj6ao=</DigestValue>
</Reference>
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/signer.rb', line 184 def digest!(target_node, = {}) wsu_ns = namespace_prefix(target_node, WSU_NAMESPACE) current_id = target_node["#{wsu_ns}:Id"] if wsu_ns id = [:id] || current_id || "_#{Digest::SHA1.hexdigest(target_node.to_s)}" if id.to_s.size > 0 wsu_ns ||= namespace_prefix(target_node, WSU_NAMESPACE, 'wsu') target_node["#{wsu_ns}:Id"] = id.to_s end target_canon = canonicalize(target_node) target_digest = Base64.encode64(@digester.digest(target_canon)).strip reference_node = Nokogiri::XML::Node.new('Reference', document) reference_node['URI'] = id.to_s.size > 0 ? "##{id}" : "" signed_info_node.add_child(reference_node) transforms_node = Nokogiri::XML::Node.new('Transforms', document) reference_node.add_child(transforms_node) transform_node = Nokogiri::XML::Node.new('Transform', document) if [: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 transforms_node.add_child(transform_node) digest_method_node = Nokogiri::XML::Node.new('DigestMethod', document) digest_method_node['Algorithm'] = @digester.digest_id reference_node.add_child(digest_method_node) digest_value_node = Nokogiri::XML::Node.new('DigestValue', document) digest_value_node.content = target_digest reference_node.add_child(digest_value_node) self end |
#digest_algorithm ⇒ Object
Return symbol name for supported digest algorithms and string name for custom ones.
27 28 29 |
# File 'lib/signer.rb', line 27 def digest_algorithm @digester.symbol || @digester.digest_name end |
#digest_algorithm=(algorithm) ⇒ Object
Allows to change algorithm for node digesting (default is SHA1).
You may pass either a one of :sha1
, :sha256
or :gostr3411
symbols or Hash
with keys :id
with a string, which will denote algorithm in XML Reference tag and :digester
with instance of class with interface compatible with OpenSSL::Digest
class.
36 37 38 |
# File 'lib/signer.rb', line 36 def digest_algorithm=(algorithm) @digester = Signer::Digester.new(algorithm) end |
#sign!(options = {}) ⇒ Object
<SignatureValue>…</SignatureValue>
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/signer.rb', line 221 def sign!( = {}) if [:security_token] binary_security_token_node end if [:issuer_serial] x509_data_node end signed_info_canon = canonicalize(signed_info_node) signature = private_key.sign(@sign_digester.digester, signed_info_canon) signature_value_digest = Base64.encode64(signature).gsub("\n", '') signature_value_node = Nokogiri::XML::Node.new('SignatureValue', document) signature_value_node.content = signature_value_digest signed_info_node.add_next_sibling(signature_value_node) self end |
#signature_digest_algorithm ⇒ Object
Return symbol name for supported digest algorithms and string name for custom ones.
41 42 43 |
# File 'lib/signer.rb', line 41 def signature_digest_algorithm @sign_digester.symbol || @sign_digester.digest_name end |
#signature_digest_algorithm=(algorithm) ⇒ Object
Allows to change digesting algorithm for signature creation. Same as digest_algorithm=
46 47 48 |
# File 'lib/signer.rb', line 46 def signature_digest_algorithm=(algorithm) @sign_digester = Signer::Digester.new(algorithm) end |
#signature_node ⇒ Object
<Signature xmlns=“www.w3.org/2000/09/xmldsig#”>
79 80 81 82 83 84 85 86 87 |
# File 'lib/signer.rb', line 79 def signature_node node = document.xpath("//ds:Signature", "ds" => "http://www.w3.org/2000/09/xmldsig#").first unless node node = Nokogiri::XML::Node.new('Signature', document) node.default_namespace = 'http://www.w3.org/2000/09/xmldsig#' security_node.add_child(node) end node end |
#signed_info_node ⇒ Object
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
...
</SignedInfo>
94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/signer.rb', line 94 def signed_info_node node = signature_node.xpath("//ds:SignedInfo", "ds" => 'http://www.w3.org/2000/09/xmldsig#').first unless node node = Nokogiri::XML::Node.new('SignedInfo', document) signature_node.add_child(node) canonicalization_method_node = Nokogiri::XML::Node.new('CanonicalizationMethod', document) canonicalization_method_node['Algorithm'] = 'http://www.w3.org/2001/10/xml-exc-c14n#' node.add_child(canonicalization_method_node) signature_method_node = Nokogiri::XML::Node.new('SignatureMethod', document) signature_method_node['Algorithm'] = self.signature_algorithm_id node.add_child(signature_method_node) end node end |
#to_xml ⇒ Object
22 23 24 |
# File 'lib/signer.rb', line 22 def to_xml document.to_xml(:save_with => 0) end |
#x509_data_node ⇒ Object
<KeyInfo>
<X509Data>
<X509IssuerSerial>
<X509IssuerName>System.Security.Cryptography.X509Certificates.X500DistinguishedName</X509IssuerName>
<X509SerialNumber>13070789</X509SerialNumber>
</X509IssuerSerial>
<X509Certificate>MIID+jCCAuKgAwIBAgIEAMdxxTANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJTRTEeMBwGA1UEChMVTm9yZGVhIEJhbmsgQUIgKHB1YmwpMScwJQYDVQQDEx5Ob3JkZWEgcm9sZS1jZXJ0aWZpY2F0ZXMgQ0EgMDExFDASBgNVBAUTCzUxNjQwNi0wMTIwMB4XDTA5MDYxMTEyNTAxOVoXDTExMDYxMTEyNTAxOVowcjELMAkGA1UEBhMCU0UxIDAeBgNVBAMMF05vcmRlYSBEZW1vIENlcnRpZmljYXRlMRQwEgYDVQQEDAtDZXJ0aWZpY2F0ZTEUMBIGA1UEKgwLTm9yZGVhIERlbW8xFTATBgNVBAUTDDAwOTU1NzI0Mzc3MjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwcgz5AzbxTbsCE51No7fPnSqmQBIMW9OiPkiHotwYQTl+H9qwDvQRyBqHN26tnw7hNvEShd1ZRGUg4drMEXDV5CmKqsAevs9lauWDaHnGKPNHZJ1hNNYXHwymksEz5zMnG8eqRdhb4vOV2FzreJeYpsgx31Bv0aTofHcHVz4uGcCAwEAAaOCASAwggEcMAkGA1UdEwQCMAAwEQYDVR0OBAoECEj6Y9/vU03WMBMGA1UdIAQMMAowCAYGKoVwRwEDMBMGA1UdIwQMMAqACEIFjfLBeTpRMDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3Aubm9yZGVhLnNlL1JDQTAxMA4GA1UdDwEB/wQEAwIGQDCBiAYDVR0fBIGAMH4wfKB6oHiGdmxkYXA6Ly9sZGFwLm5iLnNlL2NuPU5vcmRlYSUyMHJvbGUtY2VydGlmaWNhdGVzJTIwQ0ElMjAwMSxvPU5vcmRlYSUyMEJhbmslMjBBQiUyMChwdWJsKSxjPVNFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwDQYJKoZIhvcNAQEFBQADggEBAEXUv87VpHk51y3TqkMb1MYDqeKvQRE1cNcvhEJhIzdDpXMA9fG0KqvSTT1e0ZI2r78mXDvtTZnpic44jX2XMSmKO6n+1taAXq940tJUhF4arYMUxwDKOso0Doanogug496gipqMlpLgvIhGt06sWjNrvHzp2eGydUFdCsLr2ULqbDcut7g6eMcmrsnrOntjEU/J3hO8gyCeldJ+fI81qarrK/I0MZLR5LWCyVG/SKduoxHLX7JohsbIGyK1qAh9fi8l6X1Rcu80v5inpu71E/DnjbkAZBo7vsj78zzdk7KNliBIqBcIszdJ3dEHRWSI7FspRxyiR0NDm4lpyLwFtfw=</X509Certificate>
</X509Data>
</KeyInfo>
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/signer.rb', line 151 def x509_data_node issuer_name_node = Nokogiri::XML::Node.new('X509IssuerName', document) issuer_name_node.content = "System.Security.Cryptography.X509Certificates.X500DistinguishedName" issuer_number_node = Nokogiri::XML::Node.new('X509SerialNumber', document) issuer_number_node.content = cert.serial issuer_serial_node = Nokogiri::XML::Node.new('X509IssuerSerial', document) issuer_serial_node.add_child(issuer_name_node) issuer_serial_node.add_child(issuer_number_node) cetificate_node = Nokogiri::XML::Node.new('X509Certificate', document) cetificate_node.content = Base64.encode64(cert.to_der).gsub("\n", '') data_node = Nokogiri::XML::Node.new('X509Data', document) data_node.add_child(issuer_serial_node) data_node.add_child(cetificate_node) key_info_node = Nokogiri::XML::Node.new('KeyInfo', document) key_info_node.add_child(data_node) signed_info_node.add_next_sibling(key_info_node) data_node end |