Getting Started

HankoXml is a high-performance, strictly secure XML Digital Signature (XML-DSig) library for Ruby. It is backed by a native Rust extension that binds directly to libxmlsec1 using Magnus. It is designed to be completely byte-faithful, blazingly fast, and natively immune to XML Signature Wrapping (XSW) attacks.

It tightly integrates with Nokogiri, allowing you to sign and verify documents directly in memory without fragile re-serialization.

Features

Requirements

Precompiled platform gems are published for x86_64-linux, aarch64-linux, arm64-darwin and x64-mingw-ucrt. They bundle libxmlsec1, libxml2 and OpenSSL, so on those platforms you need nothing else.

Building from source (fallback)

On any other platform RubyGems installs the source gem, which compiles the Rust extension against the local libxmlsec1 (>= 1.2.30, < 1.4). That needs:

Note (macOS): Homebrew’s libxml2 is keg-only. HankoXml’s build.rs automatically works around this by resolving absolute library paths during compilation.

Installation

Add this line to your application’s Gemfile:

gem "hanko_xml"

Then run bundle install, or install it directly with gem install hanko_xml.

Nokogiri is optional. Add gem "nokogiri" for signing and the Nokogiri API; without it, verification still works on a String, a path or an IO, and so does signing a document that already holds its <Signature> template. Building a template raises HankoXml::NokogiriRequired.

Your first signature

The doc.sign! / doc.signature_valid? shorthands below come from the opt-in Nokogiri extension, require "hanko_xml/nokogiri_ext". Without it, use HankoXml.sign! and HankoXml.valid?.

require "nokogiri"
require "hanko_xml"
require "hanko_xml/nokogiri_ext"

doc = Nokogiri::XML(File.read("document.xml"))
private_key = File.read("private.pem")
certificate = File.read("public.crt")

# Sign the document in place
doc.sign!(key: private_key, certificate: certificate)

# Safely serialize without destroying the signature bytes
File.write("signed.xml", doc.to_xml(save_with: Nokogiri::XML::Node::SaveOptions::AS_XML))

# Verify it later
signed_doc = Nokogiri::XML(File.read("signed.xml"))
if signed_doc.signature_valid?(certificate: certificate)
  puts "Signature is valid!"
end

Continue to the Nokogiri API or Module API guides for the full picture, or jump straight to XSW Defense to understand the security model.