Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate nokogiri-xmlsec into nokogiri #2888

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions dependencies.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ libxslt:
sha256: "1f32450425819a09acaff2ab7a5a7f8a2ec7956e505d7beeb45e843d0e1ecab1"
# sha-256 hash provided in https://download.gnome.org/sources/libxslt/1.1/libxslt-1.1.38.sha256sum

xmlsec1:
version: "1.3.0"
sha256: "df3ad2548288411fc3d44c20879e4c4e90684a1a4fb76a06ae444f957171c9a6"
# TODO hash derivation

zlib:
version: "1.2.13"
sha256: "b3a24de97a8fdbc835b9833169501030b8977031bcb54b3b3ac13740f846ab30"
Expand Down
18 changes: 13 additions & 5 deletions ext/nokogiri/depend
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
# DO NOT DELETE

gumbo.o: $(srcdir)/nokogiri.h
html_document.o: $(srcdir)/nokogiri.h
html_element_description.o: $(srcdir)/nokogiri.h
html_entity_lookup.o: $(srcdir)/nokogiri.h
html_sax_parser_context.o: $(srcdir)/nokogiri.h
html_sax_push_parser.o: $(srcdir)/nokogiri.h
html4_document.o: $(srcdir)/nokogiri.h
html4_element_description.o: $(srcdir)/nokogiri.h
html4_entity_lookup.o: $(srcdir)/nokogiri.h
html4_sax_parser_context.o: $(srcdir)/nokogiri.h
html4_sax_push_parser.o: $(srcdir)/nokogiri.h
libxml2_backwards_compat.o: $(srcdir)/nokogiri.h
nokogiri.o: $(srcdir)/nokogiri.h
test_global_handlers.o: $(srcdir)/nokogiri.h
Expand Down Expand Up @@ -35,4 +35,12 @@ xml_schema.o: $(srcdir)/nokogiri.h
xml_syntax_error.o: $(srcdir)/nokogiri.h
xml_text.o: $(srcdir)/nokogiri.h
xml_xpath_context.o: $(srcdir)/nokogiri.h
xmlsec_decrypt_with_key.o: $(srcdir)/nokogiri.h $(srcdir)/xmlsec_options.h $(srcdir)/xmlsec_util.h
xmlsec_encrypt_with_key.o: $(srcdir)/nokogiri.h $(srcdir)/xmlsec_options.h $(srcdir)/xmlsec_util.h
xmlsec_id_attributes.o: $(srcdir)/nokogiri.h $(srcdir)/xmlsec_util.h
xmlsec_init.o: $(srcdir)/nokogiri.h
xmlsec_options.o: $(srcdir)/nokogiri.h $(srcdir)/xmlsec_options.h
xmlsec_sign.o: $(srcdir)/nokogiri.h $(srcdir)/xmlsec_options.h $(srcdir)/xmlsec_util.h
xmlsec_util.o: $(srcdir)/xmlsec_util.h $(srcdir)/nokogiri.h
xmlsec_verify_with.o: $(srcdir)/nokogiri.h $(srcdir)/xmlsec_util.h
xslt_stylesheet.o: $(srcdir)/nokogiri.h
45 changes: 43 additions & 2 deletions ext/nokogiri/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,13 @@ def needs_darwin_linker_hack
headers: "libexslt/exslt.h",
func: "exsltFuncRegister",
)
ensure_package_configuration(
opt: "xmlsec",
pc: "xmlsec1",
lib: "xmlsec1",
headers: "xmlsec/xmlsec.h",
func: "xmlSecInit",
)

have_libxml_headers?(REQUIRED_LIBXML_VERSION) ||
abort("ERROR: libxml2 version #{REQUIRED_LIBXML_VERSION} or later is required!")
Expand Down Expand Up @@ -963,12 +970,45 @@ def configure
]
end

xmlsec1_recipe = process_recipe("xmlsec1", dependencies["xmlsec1"]["version"], static_p, cross_build_p) do |recipe|
source_dir = arg_config("--with-xmlsec1-source-dir")
if source_dir
recipe.source_directory = source_dir
else
recipe.files = [{
url: "https://www.aleksey.com/xmlsec/download/#{recipe.name}-#{recipe.version}.tar.gz",
sha256: dependencies["xmlsec1"]["sha256"],
}]
end

# Upstream has a missing EOF newline; dont' fail the build
cflags = concat_flags(ENV["CFLAGS"], "-O2", "-U_FORTIFY_SOURCE", "-g", "-Wno-newline-eof")

if darwin? && !cross_build_p
recipe.configure_options += ["RANLIB=/usr/bin/ranlib", "AR=/usr/bin/ar"]
end

if windows?
cflags = concat_flags(cflags, "-UXMLSEC_STATIC", "-DXMLSEC_STATIC")
end

# Use openssl since ruby requires openssl
# TODO how to find the ruby's openssl/find things usefully on macos
recipe.configure_options += [
"--with-debug",
"--with-openssl",
"--with-nss=no",
"--enable-crypto-dl=no",
"CFLAGS=#{cflags}",
]
end

append_cppflags("-DNOKOGIRI_PACKAGED_LIBRARIES")
append_cppflags("-DNOKOGIRI_PRECOMPILED_LIBRARIES") if cross_build_p

$libs = $libs.shellsplit.tap do |libs|
[libxml2_recipe, libxslt_recipe].each do |recipe|
libname = recipe.name[/\Alib(.+)\z/, 1]
[libxml2_recipe, libxslt_recipe, xmlsec1_recipe].each do |recipe|
libname = recipe.name[/\Alib(.+)\z/, 1] || recipe.name
config_basename = "#{libname}-config"
File.join(recipe.path, "bin", config_basename).tap do |config|
# call config scripts explicit with 'sh' for compat with Windows
Expand Down Expand Up @@ -1029,6 +1069,7 @@ def configure
ensure_func("xmlParseDoc", "libxml/parser.h")
ensure_func("xsltParseStylesheetDoc", "libxslt/xslt.h")
ensure_func("exsltFuncRegister", "libexslt/exslt.h")
ensure_func("xmlSecInit", "xmlsec/xmlsec.h")
end

libgumbo_recipe = process_recipe("libgumbo", "1.0.0-nokogiri", static_p, cross_build_p, false) do |recipe|
Expand Down
4 changes: 4 additions & 0 deletions ext/nokogiri/nokogiri.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ VALUE mNokogiriHtml4Sax ;
VALUE mNokogiriHtml5 ;
VALUE mNokogiriXml ;
VALUE mNokogiriXmlSax ;
VALUE mNokogiriXmlsec ;
VALUE mNokogiriXmlXpath ;
VALUE mNokogiriXslt ;

Expand Down Expand Up @@ -47,6 +48,7 @@ void noko_init_html_entity_lookup(void);
void noko_init_html_sax_parser_context(void);
void noko_init_html_sax_push_parser(void);
void noko_init_gumbo(void);
void noko_init_xmlsec(void);
void noko_init_test_global_handlers(void);

static ID id_read, id_write, id_external_encoding;
Expand Down Expand Up @@ -190,6 +192,7 @@ Init_nokogiri(void)
mNokogiriXml = rb_define_module_under(mNokogiri, "XML");
mNokogiriXmlSax = rb_define_module_under(mNokogiriXml, "SAX");
mNokogiriXmlXpath = rb_define_module_under(mNokogiriXml, "XPath");
mNokogiriXmlsec = rb_define_module_under(mNokogiri, "XMLSec");
mNokogiriXslt = rb_define_module_under(mNokogiri, "XSLT");

set_libxml_memory_management(); /* must be before any function calls that might invoke xmlInitParser() */
Expand Down Expand Up @@ -278,6 +281,7 @@ Init_nokogiri(void)
noko_init_xml_document();
noko_init_html_document();
noko_init_gumbo();
noko_init_xmlsec();

noko_init_test_global_handlers();

Expand Down
17 changes: 17 additions & 0 deletions ext/nokogiri/nokogiri.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@

#include <libexslt/exslt.h>

#include <xmlsec/xmlsec.h>
#include <xmlsec/xmltree.h>
#include <xmlsec/xmldsig.h>
#include <xmlsec/xmlenc.h>
#include <xmlsec/templates.h>
#include <xmlsec/crypto.h>
#include <xmlsec/errors.h>

/* libxml2_backwards_compat.c */
#ifndef HAVE_XMLFIRSTELEMENTCHILD
xmlNodePtr xmlFirstElementChild(xmlNodePtr parent);
Expand Down Expand Up @@ -103,6 +111,7 @@ NOKOPUBVAR VALUE mNokogiriHtml4 ;
NOKOPUBVAR VALUE mNokogiriHtml4Sax ;
NOKOPUBVAR VALUE mNokogiriHtml5 ;
NOKOPUBVAR VALUE mNokogiriXml ;
NOKOPUBVAR VALUE mNokogiriXmlsec ;
NOKOPUBVAR VALUE mNokogiriXmlSax ;
NOKOPUBVAR VALUE mNokogiriXmlXpath ;
NOKOPUBVAR VALUE mNokogiriXslt ;
Expand Down Expand Up @@ -138,6 +147,14 @@ NOKOPUBVAR VALUE cNokogiriXmlXpathContext;
NOKOPUBVAR VALUE cNokogiriXmlXpathSyntaxError;
NOKOPUBVAR VALUE cNokogiriXsltStylesheet ;

NOKOPUBVAR VALUE cNokogiriXmlsecDocument;
NOKOPUBVAR VALUE cNokogiriXmlsecNode;
NOKOPUBVAR VALUE cNokogiriXmlsecSigningError;
NOKOPUBVAR VALUE cNokogiriXmlsecVerificationError;
NOKOPUBVAR VALUE cNokogiriXmlsecKeystoreError;
NOKOPUBVAR VALUE cNokogiriXmlsecEncryptionError;
NOKOPUBVAR VALUE cNokogiriXmlsecDecryptionError;

NOKOPUBVAR VALUE cNokogiriHtml4Document ;
NOKOPUBVAR VALUE cNokogiriHtml4SaxPushParser ;
NOKOPUBVAR VALUE cNokogiriHtml4ElementDescription ;
Expand Down
94 changes: 94 additions & 0 deletions ext/nokogiri/xmlsec_decrypt_with_key.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#include <nokogiri.h>
#include <xmlsec_options.h>
#include <xmlsec_util.h>

static VALUE rb_decrypt_with_key(VALUE self, VALUE rb_key_name, VALUE rb_key) {
VALUE rb_exception_result = Qnil;
const char* exception_message = NULL;

xmlNodePtr node = NULL;
xmlSecEncCtxPtr encCtx = NULL;
xmlSecKeysMngrPtr keyManager = NULL;
char *key = NULL;
char *keyName = NULL;
unsigned int keyLength = 0;

resetXmlSecError();

Check_Type(rb_key, T_STRING);
Check_Type(rb_key_name, T_STRING);
Noko_Node_Get_Struct(self, xmlNode, node);
key = RSTRING_PTR(rb_key);
keyLength = RSTRING_LEN(rb_key);
keyName = StringValueCStr(rb_key_name);

keyManager = createKeyManagerWithSingleKey(key, keyLength, keyName,
&rb_exception_result,
&exception_message);
if (keyManager == NULL) {
// Propagate the exception.
goto done;
}

// create encryption context
encCtx = xmlSecEncCtxCreate(keyManager);
if(encCtx == NULL) {
rb_exception_result = cNokogiriXmlsecDecryptionError;
exception_message = "failed to create encryption context";
goto done;
}
// don't let xmlsec free the node we're looking at out from under us
encCtx->flags |= XMLSEC_ENC_RETURN_REPLACED_NODE;

encCtx->keyInfoReadCtx.flags |= XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH;
encCtx->keyInfoWriteCtx.flags |= XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH;

// decrypt the data
if((xmlSecEncCtxDecrypt(encCtx, node) < 0) || (encCtx->result == NULL)) {
rb_exception_result = cNokogiriXmlsecDecryptionError;
exception_message = "decryption failed";
goto done;
}

if(encCtx->resultReplaced == 0) {
rb_exception_result = cNokogiriXmlsecDecryptionError;
exception_message = "Not implemented: don't know how to handle decrypted, non-XML data yet";
goto done;
}

done:
// cleanup
if(encCtx != NULL) {
// the replaced node is orphaned, but not freed; let Nokogiri
// own it now
if(encCtx->replacedNodeList != NULL) {
noko_xml_document_pin_node(encCtx->replacedNodeList);
// no really, please don't free it
encCtx->replacedNodeList = NULL;
}
xmlSecEncCtxDestroy(encCtx);
}

if (keyManager != NULL) {
xmlSecKeysMngrDestroy(keyManager);
}

xmlSecErrorsSetCallback(xmlSecErrorsDefaultCallback);

if(rb_exception_result != Qnil) {
if (hasXmlSecLastError()) {
rb_raise(rb_exception_result, "%s, XmlSec error: %s", exception_message,
getXmlSecLastError());
} else {
rb_raise(rb_exception_result, "%s", exception_message);
}
}

return Qnil;
}

void
noko_xmlsec_init_decrypt_with_key(void)
{
rb_define_method(cNokogiriXmlsecNode, "decrypt_with_key", rb_decrypt_with_key, 2);
}
Loading