hanko_xml 0.1.0-x64-mingw-ucrt

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +44 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +222 -0
  5. data/THIRD_PARTY_LICENSES.md +392 -0
  6. data/dependencies.yml +87 -0
  7. data/lib/hanko_xml/3.1/hanko_xml.so +0 -0
  8. data/lib/hanko_xml/3.2/hanko_xml.so +0 -0
  9. data/lib/hanko_xml/3.3/hanko_xml.so +0 -0
  10. data/lib/hanko_xml/3.4/hanko_xml.so +0 -0
  11. data/lib/hanko_xml/algorithms.rb +228 -0
  12. data/lib/hanko_xml/dom.rb +137 -0
  13. data/lib/hanko_xml/errors.rb +132 -0
  14. data/lib/hanko_xml/exc-c14n.xsd +26 -0
  15. data/lib/hanko_xml/input.rb +50 -0
  16. data/lib/hanko_xml/key.rb +213 -0
  17. data/lib/hanko_xml/key_info.rb +67 -0
  18. data/lib/hanko_xml/native_version.rb +75 -0
  19. data/lib/hanko_xml/nokogiri_ext.rb +34 -0
  20. data/lib/hanko_xml/placement.rb +127 -0
  21. data/lib/hanko_xml/policy.rb +502 -0
  22. data/lib/hanko_xml/reference.rb +49 -0
  23. data/lib/hanko_xml/signature_info.rb +134 -0
  24. data/lib/hanko_xml/signed_document.rb +155 -0
  25. data/lib/hanko_xml/signer.rb +572 -0
  26. data/lib/hanko_xml/template.rb +150 -0
  27. data/lib/hanko_xml/transform.rb +87 -0
  28. data/lib/hanko_xml/verification.rb +377 -0
  29. data/lib/hanko_xml/verifier.rb +694 -0
  30. data/lib/hanko_xml/version.rb +5 -0
  31. data/lib/hanko_xml/xades/verifier.rb +319 -0
  32. data/lib/hanko_xml/xades.rb +287 -0
  33. data/lib/hanko_xml/xml.rb +93 -0
  34. data/lib/hanko_xml/xmldsig-core-schema.xsd +332 -0
  35. data/lib/hanko_xml.rb +122 -0
  36. data/sig/hanko_xml/key.rbs +48 -0
  37. data/sig/hanko_xml/native.rbs +12 -0
  38. data/sig/hanko_xml/native_version.rbs +13 -0
  39. data/sig/hanko_xml/nokogiri_ext.rbs +23 -0
  40. data/sig/hanko_xml/placement.rbs +27 -0
  41. data/sig/hanko_xml/policy.rbs +83 -0
  42. data/sig/hanko_xml/reference.rbs +36 -0
  43. data/sig/hanko_xml/signed_document.rbs +66 -0
  44. data/sig/hanko_xml/signer.rbs +50 -0
  45. data/sig/hanko_xml/template.rbs +41 -0
  46. data/sig/hanko_xml/verification.rbs +100 -0
  47. data/sig/hanko_xml/verifier.rbs +45 -0
  48. data/sig/hanko_xml/xades.rbs +70 -0
  49. data/sig/hanko_xml.rbs +62 -0
  50. metadata +104 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b68f0b8bc0036b66446e0b446868aac77a51a831b94a289b73269e195c5854a3
4
+ data.tar.gz: 7365f7d8fc3d9f6bf7d95940f9d688097472319f1be604462c16703c21abcc0c
5
+ SHA512:
6
+ metadata.gz: 516d1c6461fd81c4cf0c285c68d1f43e733df9aa27cf6931ff7348c307fe08dd2b727baa7fb8b93891f58498d74cf6096f79e505ecab8574fd5d6189c9acf26c
7
+ data.tar.gz: 6c2da420c829d81e914c855e039cb4603889701f2f502ff264c4c654d269b29bb7e02ab54cbbae6a1dd7ce1b489e8990081c30b4e46143b6ac802a48301d0549
data/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the gem version
5
+ follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html) **over the
6
+ Ruby API only** — the libxmlsec1 version the extension is built against is
7
+ tracked separately, and is reported by `HankoXml::NativeVersion.build_versions`.
8
+
9
+ ## [Unreleased]
10
+
11
+ ## [0.1.0] - 2026-10-15
12
+
13
+ First release.
14
+
15
+ - **XML-DSig signing and verification** of enveloped, enveloping and detached
16
+ signatures, through libxmlsec1: canonicalization, digests, signature math and
17
+ reference resolution all happen in xmlsec, never in Ruby.
18
+ - **Secure by default.** `Policy.strict` denies SHA-1, HMAC, XSLT, XPath and
19
+ external references, requires 2048-bit RSA and DSA and 256-bit EC keys, and
20
+ checks the signing certificate's key usage. Opt-in presets cover other needs:
21
+ `Policy.fragment` (SAML-style signed fragments), `Policy.legacy_sha1`,
22
+ `Policy.xades` (RSA-PSS, SHA-3, ECDSA-SHA3) and `Policy.interop` for older
23
+ signatures.
24
+ - **The caller chooses the key.** Verification uses the certificate, key or
25
+ `OpenSSL::X509::Store` you pass, never one selected by the document's
26
+ `<KeyInfo>`, and `Verification` reports which references were signed, so
27
+ XML Signature Wrapping is caught.
28
+ - **XAdES-B** signing (`Xades::Signer`) and verification (`Xades::Verifier`),
29
+ including XAdES 1.2.2 and 1.1.1 signed properties, tested against SignXML
30
+ and the EU DSS corpus.
31
+ - **Works without Nokogiri.** Signing and verification run on Strings, files
32
+ and IOs. With Nokogiri, the documents you already hold can be signed in
33
+ place, and `require "hanko_xml/nokogiri_ext"` adds `doc.sign!` and
34
+ `doc.signature_valid?`.
35
+ - **Detailed results.** `Verification` exposes the certificate chain,
36
+ `SignedInfo`, `KeyInfo` and per-reference status, with
37
+ `Verifier.without_trust_verification` for integrity-only checks.
38
+ - **External references** are served only from `referenced_documents:`: the
39
+ library never reads files or opens network connections.
40
+ - **Precompiled gems** for `x86_64-linux`, `aarch64-linux`, `arm64-darwin` and
41
+ `x64-mingw-ucrt`, with libxml2 2.15.4, xmlsec1 1.3.12 and OpenSSL 3.5.9
42
+ statically linked and isolated from Nokogiri's libxml2. Other platforms build
43
+ the source gem against the system libraries (libxmlsec1 `>= 1.2.30, < 1.4`).
44
+ - **Ruby 3.1 to 3.4**, with RBS signatures in `sig/`.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Danimar Ribeiro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,222 @@
1
+ <p align="center">
2
+ <img src="assets/hanko-mark.png" alt="HankoXml" width="120" height="120">
3
+ </p>
4
+
5
+ <h1 align="center">HankoXml</h1>
6
+
7
+ <p align="center">
8
+ A high-performance, strictly secure XML Digital Signature (XML-DSig) library for Ruby.
9
+ </p>
10
+
11
+ ---
12
+
13
+ HankoXml is backed by a native Rust extension that binds directly to [libxmlsec1](https://www.aleksey.com/xmlsec/) using [Magnus](https://github.com/matsadler/magnus). It is designed to be completely byte-faithful, blazingly fast, and natively immune to XML Signature Wrapping (XSW) attacks.
14
+
15
+ It works nicely with Nokogiri, signing and verifying the documents you already hold without fragile re-serialization, and it works without Nokogiri too: verification runs on plain bytes.
16
+
17
+ ## Features
18
+ - **Full XML-DSig Support:** Sign and verify Enveloped, Enveloping, and Detached signatures.
19
+ - **Nokogiri Native, Nokogiri Optional:** Signs and verifies the Nokogiri documents you already hold, with opt-in `doc.sign!` / `doc.signature_valid?` shorthands (`require "hanko_xml/nokogiri_ext"`), and verifies Strings, files and IOs without Nokogiri.
20
+ - **XSW Defense:** Provides a robust `Policy` engine and structural `signed?(node)` checks to defeat XML Signature Wrapping (XSW) attacks.
21
+ - **Rust-Backed:** Memory-safe FFI boundaries, zero shell-outs to CLI binaries, and massive performance gains over pure-Ruby cryptography.
22
+
23
+ A feature and security comparison with Python [SignXML](https://pypi.org/project/signxml/), including a plan to close the remaining gaps (XAdES first), lives in [`docs/src/content/guide/comparison-signxml.md`](docs/src/content/guide/comparison-signxml.md).
24
+
25
+ ## Requirements
26
+
27
+ Most users install a precompiled platform gem and do **not** need a local build
28
+ toolchain.
29
+
30
+ - Ruby 3.1+
31
+
32
+ Precompiled gems are published for:
33
+
34
+ - `x86_64-linux`
35
+ - `aarch64-linux`
36
+ - `arm64-darwin`
37
+ - `x64-mingw-ucrt`
38
+
39
+ ### Building from source (fallback)
40
+
41
+ If RubyGems falls back to the source gem for your platform, HankoXml compiles
42
+ its Rust extension against the local `libxmlsec1`, so the build toolchain has
43
+ to be present:
44
+
45
+ - Rust toolchain (stable)
46
+ - `libxmlsec1` and `libxml2` development headers, `pkg-config`, and libclang
47
+ (bindgen generates the FFI bindings during the build):
48
+ - **macOS:** `brew install libxmlsec1 libxml2 pkg-config`
49
+ - **Debian/Ubuntu:** `apt install libxmlsec1-dev libxml2-dev pkg-config libclang-dev`
50
+
51
+ Supported libxmlsec1: `>= 1.2.30, < 1.4`.
52
+
53
+ *(Note for macOS: Homebrew's `libxml2` is keg-only. HankoXml's `build.rs` automatically works around this by resolving absolute library paths during compilation.)*
54
+
55
+ ### Version safety
56
+
57
+ bindgen bakes xmlsec's and libxml2's struct layouts into the compiled
58
+ extension, and a later mismatch is invisible to the dynamic linker — every
59
+ symbol still resolves, and a field is then read at the wrong offset. HankoXml
60
+ checks for this when it loads and raises `HankoXml::NativeVersionMismatch`
61
+ rather than returning a wrong answer from `verify!`:
62
+
63
+ ```ruby
64
+ HankoXml::NativeVersion.build_versions
65
+ # => { xmlsec: "1.3.12", libxml2: "2.15.3", crypto: "openssl" }
66
+ ```
67
+
68
+ If you installed from source and later upgrade libxmlsec1 through your OS
69
+ package manager, rebuild the extension with `gem pristine hanko_xml`.
70
+
71
+ ## Installation
72
+
73
+ Add this line to your application's Gemfile:
74
+
75
+ ```ruby
76
+ gem "hanko_xml"
77
+ ```
78
+
79
+ Nokogiri is optional, and `hanko_xml` does not depend on it or load it. Pick
80
+ the setup that fits:
81
+
82
+ - **With Nokogiri** (most projects already have it): add `gem "nokogiri"` and
83
+ `require "nokogiri"`. Everything is available, including signing, the
84
+ Nokogiri API below, and node-level `signed?` checks.
85
+ - **Bytes only**: leave Nokogiri out. Verification works on a String, a path
86
+ or an IO, with the same policy, schema and structural checks. Signing works
87
+ when the document already holds the `<Signature>` template. Building one, and
88
+ the DOM features, raise `HankoXml::NokogiriRequired`, naming what needs
89
+ Nokogiri.
90
+
91
+ | Capability | With Nokogiri | Bytes only |
92
+ |---|---|---|
93
+ | `valid?`, `verify!`, `Verifier`, `signature_present?` | yes | yes |
94
+ | `sign` into a template the document already holds | yes | yes, one template per call |
95
+ | `sign` that builds the template, `sign!`, `Signer#template` | yes | raises `NokogiriRequired` |
96
+ | `Verification#signed?`, `#at_signed`, `#signed_nodes` | yes | raises; `#covers_root?` still answers |
97
+ | Custom `Nokogiri::XML::Schema`, `signature:` XPath, `resolver:`, XAdES | yes | raises `NokogiriRequired` |
98
+
99
+ `HankoXml.capabilities` reports the same thing at runtime. On Linux with
100
+ system libraries, whichever of hanko_xml and Nokogiri loads first decides which
101
+ libxml2 the other runs on, so HankoXml leaves the load order to you.
102
+
103
+ ## Usage
104
+
105
+ ### 1. The Nokogiri API (Recommended)
106
+
107
+ HankoXml can extend Nokogiri directly, making signing and verifying incredibly
108
+ ergonomic. The extension is opt-in: `require "hanko_xml"` alone does not touch
109
+ Nokogiri's classes, and `require "hanko_xml/nokogiri_ext"` adds `#sign`,
110
+ `#sign!`, `#signature_valid?`, `#signatures` and `#signature_present?` to
111
+ `Nokogiri::XML::Document` and `Node`.
112
+
113
+ ```ruby
114
+ require "nokogiri"
115
+ require "hanko_xml"
116
+ require "hanko_xml/nokogiri_ext"
117
+
118
+ doc = Nokogiri::XML(File.read("document.xml"))
119
+ private_key = File.read("private.pem")
120
+ certificate = File.read("public.crt")
121
+
122
+ # Sign the document in place
123
+ doc.sign!(key: private_key, certificate: certificate)
124
+
125
+ # Safely serialize without destroying the signature bytes
126
+ File.write("signed.xml", doc.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML))
127
+
128
+ # Verify it later
129
+ signed_doc = Nokogiri::XML(File.read("signed.xml"))
130
+ if signed_doc.signature_valid?(certificate: certificate)
131
+ puts "Signature is valid!"
132
+ end
133
+ ```
134
+
135
+ ### 2. The Module API
136
+
137
+ If you prefer not to load the Nokogiri extension, use the top-level module:
138
+
139
+ #### Verification
140
+
141
+ This works with or without Nokogiri:
142
+
143
+ ```ruby
144
+ require "hanko_xml"
145
+ require "pathname"
146
+
147
+ xml = File.read("signed.xml")
148
+
149
+ # Raises HankoXml::VerificationError if the signature is invalid or tampered with
150
+ result = HankoXml.verify!(xml, certificate: Pathname("public.crt"))
151
+
152
+ puts result.valid? # => true
153
+ ```
154
+
155
+ #### Signing (Immutable)
156
+ ```ruby
157
+ # Returns a safe `SignedDocument` wrapper without mutating the original
158
+ # A String is PEM content, not a filename: pass files as Pathname (or File.read them).
159
+ signed_doc = HankoXml.sign(xml, key: Pathname("private.pem"), certificate: Pathname("public.crt"))
160
+
161
+ puts signed_doc.to_s
162
+ ```
163
+
164
+ ### Defending against XML Signature Wrapping (XSW)
165
+
166
+ A signature is only secure if it actually signed the data you are looking at. Attackers often wrap or move the `<Signature>` block to trick naive verifiers. HankoXml provides a structural `signed?` check on the verification result to prove a specific node was cryptographically covered by the digest.
167
+
168
+ ```ruby
169
+ result = HankoXml.verify!(doc, certificate: cert)
170
+
171
+ # Find the critical data in your document
172
+ payload = doc.at_xpath("//Invoice")
173
+
174
+ # Ensure the attacker didn't move it outside the signed block
175
+ unless result.signed?(payload)
176
+ raise "XSW Attack Detected: The invoice was tampered with!"
177
+ end
178
+ ```
179
+
180
+ ### Trust Anchors & Verification Options
181
+
182
+ You can verify signatures against multiple certificates, strict schemas, or specific validation times.
183
+
184
+ ```ruby
185
+ HankoXml.verify!(
186
+ doc,
187
+ # Pass a single cert, an array of certs, an OpenSSL::X509::Store, or a mapping of <KeyName>s
188
+ store: my_trusted_ca_store,
189
+
190
+ # Ensure the certificate was valid at a specific time
191
+ verification_time: Time.parse("2023-01-01"),
192
+
193
+ # Pre-validate the <Signature> structure against the W3C XSD to prevent parser exploits
194
+ schema: :default,
195
+
196
+ # Enforce strict security policies (no SHA-1, no external references)
197
+ policy: HankoXml::Policy.strict
198
+ )
199
+ ```
200
+
201
+ ## Contributing
202
+
203
+ Bug reports and pull requests are welcome on GitHub at https://github.com/danimaribeiro/HankoXml.
204
+
205
+ `bundle exec rake compile spec` by default builds the Rust extension against
206
+ your system's `libxmlsec1` (see "Building from source" above), which is fine
207
+ for day-to-day development. But the system library's build configuration can
208
+ differ from the pinned, vendored `libxmlsec1` that CI and the released gem
209
+ actually use — on macOS with Homebrew's `libxmlsec1`, this has been observed
210
+ to make some native URI-restriction and `KeyValue` specs fail or hang. Before
211
+ relying on a full local `bundle exec rspec` run (e.g. to validate a security
212
+ fix), rebuild against the vendored library instead:
213
+
214
+ ```sh
215
+ HANKO_XML_VENDOR=1 bundle exec rake compile spec
216
+ ```
217
+
218
+ See [VENDORING.md](VENDORING.md) for details on what gets vendored and why.
219
+
220
+ ## License
221
+
222
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).