Module: HankoXml
- Defined in:
- lib/hanko_xml.rb,
lib/hanko_xml/dom.rb,
lib/hanko_xml/key.rb,
lib/hanko_xml/xml.rb,
lib/hanko_xml/input.rb,
lib/hanko_xml/xades.rb,
lib/hanko_xml/errors.rb,
lib/hanko_xml/policy.rb,
lib/hanko_xml/signer.rb,
lib/hanko_xml/version.rb,
lib/hanko_xml/key_info.rb,
lib/hanko_xml/template.rb,
lib/hanko_xml/verifier.rb,
lib/hanko_xml/placement.rb,
lib/hanko_xml/reference.rb,
lib/hanko_xml/transform.rb,
lib/hanko_xml/algorithms.rb,
lib/hanko_xml/nokogiri_ext.rb,
lib/hanko_xml/verification.rb,
lib/hanko_xml/xades/locator.rb,
lib/hanko_xml/native_version.rb,
lib/hanko_xml/signature_info.rb,
lib/hanko_xml/xades/verifier.rb,
lib/hanko_xml/signed_document.rb,
lib/hanko_xml/xades/augmenter.rb,
lib/hanko_xml/xades/long_term.rb,
lib/hanko_xml/xades/timestamp.rb,
lib/hanko_xml/xades/timestamp.rb,
lib/hanko_xml/xades/validation_data.rb
Overview
Core extensions for Nokogiri::XML::Document and Nokogiri::XML::Node to support direct #sign, #sign!, #signature_valid?, #signatures, and #signed? See API_CONTRACT.md §6.6.
Defined Under Namespace
Modules: Algorithms, Dom, KeyInfo, NativeVersion, NokogiriExt, Xades Classes: CertificateExpired, ConfigurationError, DigestMismatch, Error, FrozenSignatureError, Input, Key, KeyLoadError, MultipleSignatures, NativeError, NativeVersionMismatch, NokogiriRequired, NotSignedError, ParseError, Placement, PlacementError, Policy, PolicyError, Reference, ReferenceError, ResolutionMismatch, SchemaError, SignatureInfo, SignatureInvalid, SignatureMissing, SignedDocument, Signer, SigningError, Template, Transform, UntrustedCertificate, Verification, VerificationError, Verifier, XadesError
Constant Summary collapse
- NS =
XML-DSig namespace prefixes used in every XPath this library runs internally -- never //Signature, never local-name(). See API_CONTRACT.md §6.8.
{ "ds" => "http://www.w3.org/2000/09/xmldsig#", "ds11" => "http://www.w3.org/2009/xmldsig11#", "ec" => "http://www.w3.org/2001/10/xml-exc-c14n#" }.freeze
- VERSION =
"0.2.0"
Class Method Summary collapse
-
.capabilities ⇒ Object
Which capabilities are available given whether Nokogiri is loaded.
-
.coerce_document(input, policy: nil) ⇒ Object
private
Coerces any of the accepted document input shapes (§6.2) into a Nokogiri::XML::Document: an existing Document as-is, a Node via its #document, a String of markup, a path-like object, or anything responding to #read.
-
.nokogiri? ⇒ Boolean
True when Nokogiri is loaded.
-
.parse(source) ⇒ Object
Parses
source(a String, IO, or path-like object) the one way that does not break XML-DSig: strict (no RECOVER), nonet, never NOBLANKS, never NOENT, never HUGE. -
.parse_error(errors) ⇒ Object
libxml2's diagnostics can quote the document (tag names, text), so they go in #xmlsec_errors, never in #message (#96, API_CONTRACT.md §5.10).
-
.read_source(input, policy: nil) ⇒ Object
private
Reads unparsed input (§6.2) without parsing it: a String as-is, a path-like object's file, or anything responding to #read.
-
.serialize(doc) ⇒ Object
Byte-faithful serialization: AS_XML only, never FORMAT (which reindents the tree and invalidates any signature over it).
-
.sign(doc_or_xml, **kwargs) ⇒ HankoXml::SignedDocument
Signs an XML document, returning a safely-serializable
SignedDocumentwrapper. -
.sign!(doc, **kwargs) ⇒ Nokogiri::XML::Node, Nokogiri::XML::Document
Signs a Nokogiri XML document in place.
-
.signature_present?(xml) ⇒ Boolean
Checks whether the document contains at least one populated ds:Signature.
-
.valid?(xml, **kwargs) ⇒ Boolean
Verifies an XML signature and answers with a plain boolean, so it is safe directly in a conditional.
-
.verify!(xml, **kwargs) ⇒ HankoXml::Verification
Verifies an XML signature, raising an exception if invalid.
-
.zero_copy_available? ⇒ Boolean
Returns whether zero-copy DOM verification is available on this platform.
Class Method Details
.capabilities ⇒ Object
Which capabilities are available given whether Nokogiri is loaded. See §6.1.
49 50 51 |
# File 'lib/hanko_xml.rb', line 49 def capabilities Dom.capabilities end |
.coerce_document(input, policy: nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Coerces any of the accepted document input shapes (§6.2) into a Nokogiri::XML::Document: an existing Document as-is, a Node via its #document, a String of markup, a path-like object, or anything responding to #read.
policy, when given, applies its max_document_size to unparsed
input before it is read or parsed (S-12): see #read_source. An
existing Document/Node is not checked here; Signer/Verifier check its
serialized form before any native call.
57 58 59 60 61 62 |
# File 'lib/hanko_xml/xml.rb', line 57 def coerce_document(input, policy: nil) return input if Dom.document?(input) return input.document if Dom.node?(input) parse(read_source(input, policy: policy)) end |
.nokogiri? ⇒ Boolean
True when Nokogiri is loaded. See §6.1.
43 44 45 |
# File 'lib/hanko_xml.rb', line 43 def nokogiri? Dom.available? end |
.parse(source) ⇒ Object
Parses source (a String, IO, or path-like object) the one way that
does not break XML-DSig: strict (no RECOVER), nonet, never NOBLANKS,
never NOENT, never HUGE. See API_CONTRACT.md §6.3.
Raises HankoXml::NokogiriRequired without Nokogiri, HankoXml::ParseError on malformed input.
21 22 23 24 25 26 27 28 |
# File 'lib/hanko_xml/xml.rb', line 21 def parse(source) Dom.require!("HankoXml.parse") doc, errors = Dom.parse(source) raise parse_error(errors) if errors.any? doc end |
.parse_error(errors) ⇒ Object
libxml2's diagnostics can quote the document (tag names, text), so they go in #xmlsec_errors, never in #message (#96, API_CONTRACT.md §5.10).
32 33 34 |
# File 'lib/hanko_xml/xml.rb', line 32 def parse_error(errors) HankoXml::ParseError.new("the document is not well-formed XML", xmlsec_errors: errors.map(&:message)) end |
.read_source(input, policy: nil) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Reads unparsed input (§6.2) without parsing it: a String as-is, a
path-like object's file, or anything responding to #read. +policy+'s
max_document_size applies before the input is read (S-12): a String
by #bytesize, a path by File.size, an IO by reading at most one byte
past the limit.
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/hanko_xml/xml.rb', line 71 def read_source(input, policy: nil) limit = policy&.max_document_size limit = nil unless limit&.finite? case input when String policy&.enforce_document_size!(input.bytesize) input when ->(obj) { obj.respond_to?(:to_path) } policy&.enforce_document_size!(::File.size(input.to_path)) ::File.binread(input.to_path) when ->(obj) { obj.respond_to?(:read) } source = limit ? input.read(limit + 1) : input.read policy&.enforce_document_size!(source.to_s.bytesize) source.to_s else raise ArgumentError, "expected a Nokogiri::XML::Document/Node, an XML String, a path-like object " \ "(Pathname/File), or an IO, got #{input.class}" end end |
.serialize(doc) ⇒ Object
Byte-faithful serialization: AS_XML only, never FORMAT (which reindents the tree and invalidates any signature over it). See API_CONTRACT.md §6.3.
40 41 42 43 44 |
# File 'lib/hanko_xml/xml.rb', line 40 def serialize(doc) Dom.require!("HankoXml.serialize") Dom.to_xml(doc) end |
.sign(doc_or_xml, **kwargs) ⇒ HankoXml::SignedDocument
Signs an XML document, returning a safely-serializable SignedDocument wrapper.
This is a convenience shortcut that creates a Signer and calls #sign.
The original document is not modified (a deep clone is created).
60 61 62 |
# File 'lib/hanko_xml.rb', line 60 def sign(doc_or_xml, **kwargs) HankoXml::Signer.new(**kwargs).sign(doc_or_xml) end |
.sign!(doc, **kwargs) ⇒ Nokogiri::XML::Node, Nokogiri::XML::Document
Signs a Nokogiri XML document in place.
This is a convenience shortcut that creates a Signer and calls #sign!.
70 71 72 |
# File 'lib/hanko_xml.rb', line 70 def sign!(doc, **kwargs) HankoXml::Signer.new(**kwargs).sign!(doc) end |
.signature_present?(xml) ⇒ Boolean
Checks whether the document contains at least one populated ds:Signature. Does NOT verify the signature's cryptographic validity.
108 109 110 111 |
# File 'lib/hanko_xml.rb', line 108 def signature_present?(xml) # Structural, from the native parse; needs no DOM (#102). HankoXml::Input.read(xml).scan([])[:signature_values].any? end |
.valid?(xml, **kwargs) ⇒ Boolean
Verifies an XML signature and answers with a plain boolean, so it is safe
directly in a conditional. This is a convenience shortcut that creates a
Verifier and calls #valid?.
There is deliberately no HankoXml.verify: a Verification is always
truthy, so if HankoXml.verify(doc, ...) would be a security bug that reads
like correct code (API_CONTRACT §5.1). For the rich object use verify! or
HankoXml::Verifier#verify.
87 88 89 |
# File 'lib/hanko_xml.rb', line 87 def valid?(xml, **kwargs) HankoXml::Verifier.new(**kwargs).valid?(xml) end |
.verify!(xml, **kwargs) ⇒ HankoXml::Verification
Verifies an XML signature, raising an exception if invalid.
This is a convenience shortcut that creates a Verifier and calls #verify!.
99 100 101 |
# File 'lib/hanko_xml.rb', line 99 def verify!(xml, **kwargs) HankoXml::Verifier.new(**kwargs).verify!(xml) end |
.zero_copy_available? ⇒ Boolean
Returns whether zero-copy DOM verification is available on this platform.
116 117 118 |
# File 'lib/hanko_xml.rb', line 116 def zero_copy_available? false end |