Class: WSDL::Security::Verifier

Inherits:
Object
  • Object
show all
Defined in:
lib/wsdl/security/verifier.rb,
lib/wsdl/security/verifier/base.rb,
lib/wsdl/security/verifier/reference_validator.rb,
lib/wsdl/security/verifier/signature_validator.rb,
lib/wsdl/security/verifier/structure_validator.rb,
lib/wsdl/security/verifier/timestamp_validator.rb,
lib/wsdl/security/verifier/certificate_resolver.rb,
lib/wsdl/security/verifier/certificate_validator.rb,
lib/wsdl/security/verifier/element_position_validator.rb

Overview

Verifies XML Digital Signatures and timestamps in SOAP responses.

This class coordinates multiple validation steps to provide comprehensive security verification including:

  • Structural Validation — Detects XML Signature Wrapping (XSW) attacks
  • Certificate Resolution — Extracts or validates signing certificates
  • Certificate Validation — Checks validity period and trust chain
  • Reference Verification — Validates digests of signed elements
  • Signature Verification — Cryptographic validation of SignatureValue
  • Timestamp Validation — Freshness checks to prevent replay attacks

The verification process follows W3C XML Signature Best Practices, running structural checks before expensive cryptographic operations.

Examples:

Basic verification

verifier = Verifier.new(response_xml)
if verifier.valid?
  puts "Signature is valid!"
  puts "Signed elements: #{verifier.signed_elements}"
else
  puts "Signature invalid: #{verifier.errors}"
end

With a provided certificate

verifier = Verifier.new(response_xml, certificate: server_cert)
verifier.valid?

With certificate chain validation

verifier = Verifier.new(response_xml, trust_store: :system)
verifier.valid?

With custom CA certificates

verifier = Verifier.new(response_xml, trust_store: [ca_cert])
verifier.valid?

With timestamp validation (enabled by default)

verifier = Verifier.new(response_xml, clock_skew: 600)
verifier.valid?  # checks signature AND timestamp

Disable timestamp validation

verifier = Verifier.new(response_xml, validate_timestamp: false)
verifier.valid?  # checks signature only

See Also:

Defined Under Namespace

Classes: Base, CertificateResolver, CertificateValidator, ElementPositionValidator, ReferenceValidator, SignatureValidator, StructureValidator, TimestampValidator

Constant Summary collapse

SecurityNS =

Local aliases for namespace constants

Constants::NS::Security
SignatureNS =

Alias for XML Signature namespace constants.

Returns:

  • (Module)
Constants::NS::Signature

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(xml, certificate: nil, trust_store: nil, check_validity: true, validate_timestamp: true, clock_skew: 300) ⇒ Verifier

Creates a new Verifier instance.

rubocop:disable Metrics/ParameterLists

Parameters:

  • xml (String)

    the SOAP response XML

  • certificate (OpenSSL::X509::Certificate, String, nil) (defaults to: nil)

    optional certificate to use for verification instead of extracting from the message

  • trust_store (OpenSSL::X509::Store, Symbol, String, Array, nil) (defaults to: nil)

    trust store for certificate chain validation:

    • :system — Use system default CA certificates
    • String — Path to CA bundle file or directory
    • Array<OpenSSL::X509::Certificate> — Array of trusted CA certificates
    • OpenSSL::X509::Store — Pre-configured certificate store
    • nil — Skip chain validation (default)
  • check_validity (Boolean) (defaults to: true)

    whether to check the certificate's validity period (not_before and not_after). Default: true

  • validate_timestamp (Boolean) (defaults to: true)

    whether to validate timestamp freshness. Default: true. Per WS-Security spec, timestamps are optional, so this only validates when a timestamp is present.

  • clock_skew (Integer) (defaults to: 300)

    acceptable clock skew in seconds for timestamp validation. Default: 300 (5 minutes). Per WS-I BSP guidance.



97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/wsdl/security/verifier.rb', line 97

def initialize(xml, certificate: nil, trust_store: nil, check_validity: true,
               validate_timestamp: true, clock_skew: 300)
  # rubocop:enable Metrics/ParameterLists
  @document = parse_document(xml)
  @provided_certificate = certificate
  @trust_store = trust_store
  @check_validity = check_validity
  @validate_timestamp = validate_timestamp
  @clock_skew = clock_skew
  @errors = []
  @verified = nil
  @certificate = normalize_certificate(certificate) if certificate
end

Instance Attribute Details

#certificateOpenSSL::X509::Certificate? (readonly)

Returns certificate used for verification.

Returns:

  • (OpenSSL::X509::Certificate, nil)

    certificate used for verification



75
76
77
# File 'lib/wsdl/security/verifier.rb', line 75

def certificate
  @certificate
end

#errorsArray<String> (readonly)

Returns errors encountered during verification.

Returns:

  • (Array<String>)

    errors encountered during verification



72
73
74
# File 'lib/wsdl/security/verifier.rb', line 72

def errors
  @errors
end

Instance Method Details

#digest_algorithmString?

Returns the digest algorithm URI from the first reference.

Returns:



161
162
163
# File 'lib/wsdl/security/verifier.rb', line 161

def digest_algorithm
  signed_info_node&.at_xpath('ds:Reference/ds:DigestMethod/@Algorithm', ns)&.value
end

#signature_algorithmString?

Returns the signature algorithm URI.

Returns:



154
155
156
# File 'lib/wsdl/security/verifier.rb', line 154

def signature_algorithm
  signature_validator&.signature_algorithm
end

#signature_present?Boolean

Returns whether a signature is present in the document.

Returns:

  • (Boolean)

    true if a ds:Signature element exists



131
132
133
# File 'lib/wsdl/security/verifier.rb', line 131

def signature_present?
  structure_validator.signature_present?
end

#signed_element_idsArray<String>

Returns the IDs of all signed elements.

Returns:

  • (Array<String>)

    element IDs (without # prefix)



138
139
140
141
142
# File 'lib/wsdl/security/verifier.rb', line 138

def signed_element_ids
  return [] unless signature_present?

  reference_validator.referenced_ids
end

#signed_elementsArray<String>

Returns the names of all signed elements.

Returns:

  • (Array<String>)

    element names (e.g., ['Body', 'Timestamp'])



147
148
149
# File 'lib/wsdl/security/verifier.rb', line 147

def signed_elements
  signed_element_ids.filter_map { |id| safe_find_element_by_id(id)&.name }
end

#timestampHash?

Returns the parsed timestamp information.

Returns:

  • (Hash, nil)

    hash with :created_at and :expires_at keys, or nil if no timestamp present



187
188
189
# File 'lib/wsdl/security/verifier.rb', line 187

def timestamp
  timestamp_validator.timestamp
end

#timestamp_errorsArray<String>

Returns timestamp validation errors.

This exposes timestamp-specific diagnostics from the memoized timestamp validator without rerunning a full verification pipeline.

Returns:

  • (Array<String>)

    timestamp validation errors



197
198
199
200
201
# File 'lib/wsdl/security/verifier.rb', line 197

def timestamp_errors
  validator = timestamp_validator
  validator.valid? if validator.errors.empty?
  validator.errors.dup
end

#timestamp_present?Boolean

Returns whether a timestamp is present in the document.

Returns:

  • (Boolean)

    true if wsu:Timestamp exists in the Security header



168
169
170
# File 'lib/wsdl/security/verifier.rb', line 168

def timestamp_present?
  timestamp_validator.timestamp_present?
end

#timestamp_valid?Boolean

Returns whether the timestamp is valid (fresh).

Returns true if:

  • No timestamp is present (timestamps are optional per spec)
  • Timestamp is present and within acceptable time bounds

Returns:

  • (Boolean)

    true if timestamp is valid or not present



179
180
181
# File 'lib/wsdl/security/verifier.rb', line 179

def timestamp_valid?
  timestamp_validator.valid?
end

#valid?Boolean

Returns whether the signature (and timestamp, if enabled) is valid.

Performs full verification including:

  1. Structural validation (XSW protection)
  2. Certificate resolution
  3. Certificate validation (validity period and chain)
  4. Reference digest verification
  5. Cryptographic signature verification
  6. Timestamp freshness validation (if enabled and timestamp present)

Returns:

  • (Boolean)

    true if signature is present and valid



122
123
124
125
126
# File 'lib/wsdl/security/verifier.rb', line 122

def valid?
  return @verified unless @verified.nil?

  @verified = perform_verification
end