Class: OpenID::SimpleSign
- Inherits:
-
Object
- Object
- OpenID::SimpleSign
- Defined in:
- lib/gapps_openid.rb
Overview
Basic implementation of the XML Simple Sign algorithm. Currently only supports RSA-SHA1
Constant Summary collapse
- C14N_RAW_OCTETS =
'http://docs.oasis-open.org/xri/xrd/2009/01#canonicalize-raw-octets'
- SIGN_RSA_SHA1 =
'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
- NAMESPACES =
{ 'ds' => 'http://www.w3.org/2000/09/xmldsig#', 'xrds' => 'xri://xrds' }
- @@store =
nil
Class Method Summary collapse
-
.parse_certificates(doc) ⇒ Object
Extracts the signer’s certificates from the XML.
-
.store ⇒ Object
Initialize the store.
-
.valid_chain?(chain) ⇒ Boolean
Verifies the chain of trust for the signing certificates.
-
.verify(xml, signature_value) ⇒ Object
Verifies the signature of the doc, returning the CN of the signer if valid.
Class Method Details
.parse_certificates(doc) ⇒ Object
Extracts the signer’s certificates from the XML
264 265 266 267 268 269 270 271 272 273 |
# File 'lib/gapps_openid.rb', line 264 def self.parse_certificates(doc) certs = [] REXML::XPath.each(doc, "//ds:Signature/ds:KeyInfo/ds:X509Data/ds:X509Certificate", NAMESPACES ) { | encoded | encoded = encoded.text.strip.scan(/.{1,64}/).join("\n") encoded = "-----BEGIN CERTIFICATE-----\n#{encoded}\n-----END CERTIFICATE-----\n" cert = OpenSSL::X509::Certificate.new(encoded) certs << cert } return certs end |
.store ⇒ Object
Initialize the store
252 253 254 255 256 257 258 259 260 261 |
# File 'lib/gapps_openid.rb', line 252 def self.store if @@store.nil? OpenID.logger.info("Initializing CA bundle") unless OpenID.logger.nil? ca_bundle_path = File.join(File.dirname(__FILE__), 'ca-bundle.crt') @@store = OpenSSL::X509::Store.new @@store.set_default_paths @@store.add_file(ca_bundle_path) end return @@store end |
.valid_chain?(chain) ⇒ Boolean
Verifies the chain of trust for the signing certificates
276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/gapps_openid.rb', line 276 def self.valid_chain?(chain) if chain.nil? or chain.empty? return false end cert = chain.shift if self.store.verify(cert) return true end if chain.empty? or not cert.verify(chain.first.public_key) return false end return self.valid_chain?(chain) end |
.verify(xml, signature_value) ⇒ Object
Verifies the signature of the doc, returning the CN of the signer if valid
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
# File 'lib/gapps_openid.rb', line 291 def self.verify(xml, signature_value) doc = REXML::Document.new(xml) return nil if REXML::XPath.first(doc, "//ds:Signature").nil? and signature_value.nil? decoded_sig = Base64.decode64(signature_value) certs = self.parse_certificates(doc) raise "No signature in document" if certs.nil? or certs.empty? raise "Missing signature value" if signature_value.nil? signing_certificate = certs.first raise "Invalid signature" if !signing_certificate.public_key.verify(OpenSSL::Digest::SHA1.new, decoded_sig, xml) raise "Certificate chain not valid" if !self.valid_chain?(certs) # Signature is valid, return CN of the subject subject = signing_certificate.subject.to_a signed_by = subject.last[1] return signed_by end |