moxml 0.1.24 → 0.1.26

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 (133) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/docs.yml +1 -1
  3. data/.github/workflows/opal.yml +18 -1
  4. data/.github/workflows/rake.yml +32 -3
  5. data/.github/workflows/release.yml +9 -0
  6. data/.github/workflows/round-trip.yml +72 -9
  7. data/.gitmodules +6 -0
  8. data/.rubocop_todo.yml +2 -0
  9. data/Gemfile +9 -1
  10. data/README.adoc +188 -0
  11. data/Rakefile +116 -4
  12. data/docs/signature/algorithms.md +108 -0
  13. data/docs/signature/architecture.md +148 -0
  14. data/docs/signature/c14n.md +110 -0
  15. data/docs/signature/examples.md +109 -0
  16. data/docs/signature/flows.md +132 -0
  17. data/docs/signature/quick-reference.md +115 -0
  18. data/docs/signature/security.md +143 -0
  19. data/examples/signature/auto_key_extraction.rb +24 -0
  20. data/examples/signature/enveloped_rsa.rb +45 -0
  21. data/examples/signature/hmac.rb +33 -0
  22. data/lib/compat/opal/moxml_boot.rb +4 -0
  23. data/lib/moxml/adapter.rb +5 -3
  24. data/lib/moxml/c14n/attribute_handler.rb +71 -0
  25. data/lib/moxml/c14n/character_encoder.rb +29 -0
  26. data/lib/moxml/c14n/data_model.rb +145 -0
  27. data/lib/moxml/c14n/exclusive.rb +188 -0
  28. data/lib/moxml/c14n/inclusive_10.rb +42 -0
  29. data/lib/moxml/c14n/inclusive_11.rb +21 -0
  30. data/lib/moxml/c14n/namespace_context.rb +68 -0
  31. data/lib/moxml/c14n/namespace_handler.rb +71 -0
  32. data/lib/moxml/c14n/node.rb +42 -0
  33. data/lib/moxml/c14n/nodes/attribute_node.rb +50 -0
  34. data/lib/moxml/c14n/nodes/comment_node.rb +29 -0
  35. data/lib/moxml/c14n/nodes/element_node.rb +62 -0
  36. data/lib/moxml/c14n/nodes/namespace_node.rb +41 -0
  37. data/lib/moxml/c14n/nodes/processing_instruction_node.rb +30 -0
  38. data/lib/moxml/c14n/nodes/root_node.rb +22 -0
  39. data/lib/moxml/c14n/nodes/text_node.rb +29 -0
  40. data/lib/moxml/c14n/nodes.rb +17 -0
  41. data/lib/moxml/c14n/processor.rb +118 -0
  42. data/lib/moxml/c14n/writer.rb +121 -0
  43. data/lib/moxml/c14n/xml_base_handler.rb +140 -0
  44. data/lib/moxml/c14n.rb +96 -0
  45. data/lib/moxml/config.rb +1 -1
  46. data/lib/moxml/signature/algorithms/base64_transform.rb +40 -0
  47. data/lib/moxml/signature/algorithms/canonicalization_base.rb +87 -0
  48. data/lib/moxml/signature/algorithms/digest_base.rb +51 -0
  49. data/lib/moxml/signature/algorithms/dsa_sha.rb +107 -0
  50. data/lib/moxml/signature/algorithms/ecdsa_sha.rb +125 -0
  51. data/lib/moxml/signature/algorithms/enveloped_signature_transform.rb +79 -0
  52. data/lib/moxml/signature/algorithms/exc_c14n_10.rb +23 -0
  53. data/lib/moxml/signature/algorithms/hmac_sha.rb +117 -0
  54. data/lib/moxml/signature/algorithms/inclusive_c14n_10.rb +21 -0
  55. data/lib/moxml/signature/algorithms/inclusive_c14n_11.rb +23 -0
  56. data/lib/moxml/signature/algorithms/rsa_pkcs1_sha.rb +56 -0
  57. data/lib/moxml/signature/algorithms/sha1.rb +13 -0
  58. data/lib/moxml/signature/algorithms/sha224.rb +13 -0
  59. data/lib/moxml/signature/algorithms/sha256.rb +13 -0
  60. data/lib/moxml/signature/algorithms/sha384.rb +13 -0
  61. data/lib/moxml/signature/algorithms/sha512.rb +13 -0
  62. data/lib/moxml/signature/algorithms/signature_method_base.rb +58 -0
  63. data/lib/moxml/signature/algorithms/transform_base.rb +40 -0
  64. data/lib/moxml/signature/algorithms.rb +113 -0
  65. data/lib/moxml/signature/errors.rb +99 -0
  66. data/lib/moxml/signature/key_extractor.rb +172 -0
  67. data/lib/moxml/signature/model/algorithm_method.rb +18 -0
  68. data/lib/moxml/signature/model/digest_method.rb +15 -0
  69. data/lib/moxml/signature/model/key/dsa_key_value.rb +29 -0
  70. data/lib/moxml/signature/model/key/ec_key_value.rb +22 -0
  71. data/lib/moxml/signature/model/key/rsa_key_value.rb +19 -0
  72. data/lib/moxml/signature/model/key/x509_data.rb +32 -0
  73. data/lib/moxml/signature/model/key/x509_digest.rb +19 -0
  74. data/lib/moxml/signature/model/key/x509_issuer_serial.rb +19 -0
  75. data/lib/moxml/signature/model/key_info.rb +21 -0
  76. data/lib/moxml/signature/model/key_value.rb +20 -0
  77. data/lib/moxml/signature/model/object_element.rb +18 -0
  78. data/lib/moxml/signature/model/reference.rb +22 -0
  79. data/lib/moxml/signature/model/signature.rb +21 -0
  80. data/lib/moxml/signature/model/signature_value.rb +16 -0
  81. data/lib/moxml/signature/model/signed_info.rb +20 -0
  82. data/lib/moxml/signature/model/transform.rb +16 -0
  83. data/lib/moxml/signature/model/transforms.rb +36 -0
  84. data/lib/moxml/signature/model.rb +35 -0
  85. data/lib/moxml/signature/parser.rb +270 -0
  86. data/lib/moxml/signature/reference_resolver.rb +79 -0
  87. data/lib/moxml/signature/reference_result.rb +22 -0
  88. data/lib/moxml/signature/serializer.rb +163 -0
  89. data/lib/moxml/signature/signer.rb +73 -0
  90. data/lib/moxml/signature/single_verification_result.rb +31 -0
  91. data/lib/moxml/signature/transform_pipeline.rb +106 -0
  92. data/lib/moxml/signature/verification_result.rb +27 -0
  93. data/lib/moxml/signature/verifier.rb +129 -0
  94. data/lib/moxml/signature.rb +94 -0
  95. data/lib/moxml/version.rb +1 -1
  96. data/lib/moxml.rb +2 -0
  97. data/moxml.gemspec +1 -1
  98. data/reference-docs/w3c-xmldsig-bestpractices.md +216 -0
  99. data/reference-docs/w3c-xmldsig-core.md +400 -0
  100. data/spec/fixtures/xmldsig/keys/rsa_private.pem +28 -0
  101. data/spec/fixtures/xmldsig/keys/rsa_public.pem +9 -0
  102. data/spec/fixtures/xmldsig/keys/rsa_ref.pem +15 -0
  103. data/spec/fixtures/xmldsig/keys/rsa_ref.pub +6 -0
  104. data/spec/fixtures/xmldsig/sign2-doc.xml +6 -0
  105. data/spec/fixtures/xmldsig/sign2-result.xml +25 -0
  106. data/spec/fixtures/xmldsig/sign3-result.xml +39 -0
  107. data/spec/moxml/adapter/platform_spec.rb +64 -46
  108. data/spec/moxml/c14n/api_spec.rb +117 -0
  109. data/spec/moxml/c14n/c14n_spec.rb +88 -0
  110. data/spec/moxml/c14n/comments_pis_spec.rb +65 -0
  111. data/spec/moxml/c14n/inclusive10_spec.rb +60 -0
  112. data/spec/moxml/c14n/namespace_edge_cases_spec.rb +88 -0
  113. data/spec/moxml/c14n/xml_attributes_spec.rb +54 -0
  114. data/spec/moxml/opal_oga_adapter_spec.rb +14 -0
  115. data/spec/moxml/opal_oga_features_spec.rb +212 -0
  116. data/spec/moxml/opal_oga_smoke_spec.rb +35 -0
  117. data/spec/moxml/signature/algorithms/base64_transform_spec.rb +26 -0
  118. data/spec/moxml/signature/algorithms/digest_base_spec.rb +72 -0
  119. data/spec/moxml/signature/algorithms/dsa_sha_spec.rb +46 -0
  120. data/spec/moxml/signature/algorithms/ecdsa_sha_spec.rb +72 -0
  121. data/spec/moxml/signature/algorithms/enveloped_signature_transform_spec.rb +40 -0
  122. data/spec/moxml/signature/algorithms/hmac_sha_spec.rb +71 -0
  123. data/spec/moxml/signature/algorithms/rsa_pkcs1_sha_spec.rb +55 -0
  124. data/spec/moxml/signature/algorithms_spec.rb +76 -0
  125. data/spec/moxml/signature/cross_verify_spec.rb +64 -0
  126. data/spec/moxml/signature/edge_cases_spec.rb +284 -0
  127. data/spec/moxml/signature/fixtures_spec.rb +80 -0
  128. data/spec/moxml/signature/key_extractor_spec.rb +96 -0
  129. data/spec/moxml/signature/model_spec.rb +54 -0
  130. data/spec/moxml/signature/round_trip_spec.rb +113 -0
  131. data/spec/moxml/xpath/functions/node_functions_spec.rb +1 -1
  132. data/spec/spec_helper.rb +1 -1
  133. metadata +115 -2
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Signature
5
+ # Reference generation + SignatureValue computation per spec §3.1.
6
+ #
7
+ # Flow:
8
+ # 1. For each Reference in signed_info.references:
9
+ # a. Resolve URI (same-document or octet).
10
+ # b. Apply each Transform in order.
11
+ # c. Compute digest via DigestMethod.
12
+ # d. Store base64 digest on Reference#digest_value.
13
+ # 2. Serialize SignedInfo.
14
+ # 3. Canonicalize per CanonicalizationMethod.
15
+ # 4. Sign via SignatureMethod#sign(canonical_octets, key).
16
+ # 5. Set signature.signature_value.
17
+ class Signer
18
+ attr_reader :context, :signature, :document, :key
19
+
20
+ def initialize(context:, signature:, document:, key:)
21
+ @context = context
22
+ @signature = signature
23
+ @document = document
24
+ @key = key
25
+ end
26
+
27
+ def sign
28
+ Algorithms.load_builtins!
29
+
30
+ signature.signed_info.references.each do |ref|
31
+ digest = compute_reference_digest(ref)
32
+ ref.digest_value = digest
33
+ end
34
+
35
+ signature.signature_value = Model::SignatureValue.new(
36
+ value: compute_signature_value,
37
+ )
38
+ signature
39
+ end
40
+
41
+ private
42
+
43
+ def compute_reference_digest(reference)
44
+ resolver = ReferenceResolver.new(context: context, document: document)
45
+ input = resolver.resolve(reference.uri)
46
+ pipeline = TransformPipeline.new(context: context, signature_element: nil)
47
+ transformed = pipeline.apply(input, reference.transforms)
48
+ canonical = pipeline.to_octets(transformed, reference)
49
+ digest_algo = Algorithms.lookup(:digest, reference.digest_method.algorithm).new
50
+ digest_algo.digest_base64(canonical)
51
+ end
52
+
53
+ def compute_signature_value
54
+ signed_info = signature.signed_info
55
+ serializer = Serializer.new(context: context)
56
+ signed_info_doc = serializer.serialize_signed_info(signed_info)
57
+
58
+ c14n_uri = signed_info.canonicalization_method.algorithm
59
+ c14n_klass = Algorithms.lookup(:canonicalization, c14n_uri)
60
+ c14n = c14n_klass.new(identifier_uri: c14n_uri)
61
+ canonical_octets = c14n.canonicalize(signed_info_doc.root)
62
+
63
+ sm_uri = signed_info.signature_method.algorithm
64
+ sm_klass = Algorithms.lookup(:signature_method, sm_uri)
65
+ sm = sm_klass.new(
66
+ identifier_uri: sm_uri,
67
+ parameters: signed_info.signature_method.parameters,
68
+ )
69
+ sm.sign(canonical_octets, key)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Signature
5
+ # Verification outcome for a single Signature element. Carries the
6
+ # cryptographic-result boolean, per-reference results, and (when
7
+ # applicable) the error that caused failure.
8
+ class SingleVerificationResult
9
+ attr_reader :signature_id, :references, :error
10
+
11
+ def initialize(signature_id:, signature_valid:, references:, error: nil)
12
+ @signature_id = signature_id
13
+ @signature_valid = signature_valid
14
+ @references = references
15
+ @error = error
16
+ end
17
+
18
+ def signature_valid?
19
+ @signature_valid
20
+ end
21
+
22
+ def valid?
23
+ @signature_valid && references.all?(&:valid?)
24
+ end
25
+
26
+ def failing_references
27
+ references.reject(&:valid?)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Signature
5
+ # Shared transform-pipeline logic used by both Signer (signing flow,
6
+ # signature_element: nil) and Verifier (verification flow, with the
7
+ # containing Signature element so the Enveloped Signature transform
8
+ # can remove it from the digest input).
9
+ #
10
+ # Each Transform in the chain is looked up via Algorithms.lookup(:transform, uri),
11
+ # with a fallback to Algorithms.lookup(:canonicalization, uri) per
12
+ # spec §6.6.1 (any canonicalization algorithm can be used as a transform).
13
+ #
14
+ # Type coercion matches spec §4.4.3.2 reference processing model:
15
+ # - octets → nodeset: parse as XML
16
+ # - nodeset → octets: apply inclusive C14N 1.0
17
+ class TransformPipeline
18
+ attr_reader :context, :signature_element
19
+
20
+ def initialize(context:, signature_element: nil)
21
+ @context = context
22
+ @signature_element = signature_element
23
+ end
24
+
25
+ def apply(input, transforms_model)
26
+ current = input
27
+ current_type = type_of(current)
28
+ transforms = transforms_from(transforms_model)
29
+
30
+ transforms.each do |transform_model|
31
+ algo_class = lookup(transform_model.algorithm)
32
+ transform = algo_class.new(
33
+ parameters: transform_model.parameters,
34
+ context: context,
35
+ signature_element: signature_element,
36
+ )
37
+ current_type, current = coerce(current, current_type,
38
+ algo_class.input_type)
39
+ current = transform.transform(current)
40
+ current_type = algo_class.output_type
41
+ end
42
+
43
+ current
44
+ end
45
+
46
+ # Final step: convert the pipeline output (which may still be a node)
47
+ # to octets suitable for digesting. Uses inclusive C14N 1.0 as the
48
+ # default mapping per spec §4.4.3.2.
49
+ def to_octets(value, reference = nil)
50
+ return value if value.is_a?(String)
51
+
52
+ c14n_uri = canonicalization_from(reference) || DEFAULT_OCTET_C14N
53
+ klass = Algorithms.lookup(:canonicalization, c14n_uri)
54
+ klass.new(identifier_uri: c14n_uri).canonicalize(value)
55
+ end
56
+
57
+ DEFAULT_OCTET_C14N = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
58
+
59
+ private_constant :DEFAULT_OCTET_C14N
60
+
61
+ private
62
+
63
+ def transforms_from(transforms_model)
64
+ return [] unless transforms_model
65
+
66
+ transforms_model.transforms
67
+ end
68
+
69
+ def lookup(uri)
70
+ Algorithms.lookup(:transform, uri)
71
+ rescue UnknownAlgorithm
72
+ Algorithms.lookup(:canonicalization, uri)
73
+ end
74
+
75
+ def type_of(value)
76
+ case value
77
+ when ::Moxml::Node, Array then :nodeset
78
+ else :octets
79
+ end
80
+ end
81
+
82
+ def coerce(input, from, to)
83
+ return [to, input] if from == to
84
+
85
+ case [from, to]
86
+ when %i[octets nodeset]
87
+ parsed = context.parse(input.to_s)
88
+ [:nodeset, parsed.root]
89
+ when %i[nodeset octets]
90
+ octets = C14n::Inclusive10.new.canonicalize(input)
91
+ [:octets, octets]
92
+ else
93
+ raise TransformError, "cannot coerce #{from} to #{to}"
94
+ end
95
+ end
96
+
97
+ def canonicalization_from(reference)
98
+ return nil unless reference&.transforms
99
+
100
+ reference.transforms.transforms.reverse_each.find do |t|
101
+ Algorithms.registered?(:canonicalization, t.algorithm)
102
+ end&.algorithm
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Signature
5
+ # Aggregated verification result for a document. A document may
6
+ # contain multiple Signature elements; this result wraps them all.
7
+ class VerificationResult
8
+ attr_reader :results
9
+
10
+ def initialize(results:)
11
+ @results = results
12
+ end
13
+
14
+ def valid?
15
+ results.all?(&:valid?)
16
+ end
17
+
18
+ def signature_count
19
+ results.size
20
+ end
21
+
22
+ def failing
23
+ results.reject(&:valid?)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Moxml
4
+ module Signature
5
+ # Core Validation per spec §3.2, with the safe ordering prescribed by
6
+ # Best Practice 1: verify SignatureValue BEFORE running any reference
7
+ # transforms (which could be hostile).
8
+ class Verifier
9
+ attr_reader :context, :document, :key, :key_map
10
+
11
+ def initialize(context:, document:, key: nil, key_map: {}, **_options)
12
+ @context = context
13
+ @document = document
14
+ @key = key
15
+ @key_map = key_map || {}
16
+ end
17
+
18
+ def verify
19
+ Algorithms.load_builtins!
20
+ signatures = find_signatures
21
+
22
+ results = signatures.map { |sig_elem| verify_one(sig_elem) }
23
+ VerificationResult.new(results: results)
24
+ end
25
+
26
+ private
27
+
28
+ def find_signatures
29
+ document.xpath("//ds:Signature", "ds" => DSIG_NS)
30
+ .grep(::Moxml::Element)
31
+ end
32
+
33
+ def verify_one(signature_element)
34
+ signature = Parser.new(context: context).parse(signature_element)
35
+ signature_value_ok, error = verify_signature_value(signature, signature_element)
36
+ reference_results = if signature_value_ok
37
+ verify_references(signature, signature_element)
38
+ else
39
+ []
40
+ end
41
+
42
+ SingleVerificationResult.new(
43
+ signature_id: signature.id,
44
+ signature_valid: signature_value_ok,
45
+ references: reference_results,
46
+ error: error,
47
+ )
48
+ end
49
+
50
+ # Returns [Boolean, ErrorOrNil] so the caller can attach the error
51
+ # to the result for debugging. The error is never raised — Best
52
+ # Practice 1 says authenticate first; surfacing why auth failed is
53
+ # an application concern, not a panic.
54
+ def verify_signature_value(signature, signature_element)
55
+ return [false, nil] if signature.signature_value.nil?
56
+ return [false, nil] if signature.signature_value.value.nil?
57
+
58
+ signed_info_elem = signature_element.at_xpath(
59
+ "./ds:SignedInfo", "ds" => DSIG_NS
60
+ )
61
+ return [false, nil] if signed_info_elem.nil?
62
+
63
+ c14n_uri = signature.signed_info.canonicalization_method&.algorithm
64
+ return [false, nil] if c14n_uri.nil?
65
+
66
+ canonical = canonicalize_signed_info(c14n_uri, signed_info_elem)
67
+ sm_uri = signature.signed_info.signature_method.algorithm
68
+ sm = Algorithms.lookup(:signature_method, sm_uri).new(
69
+ identifier_uri: sm_uri,
70
+ parameters: signature.signed_info.signature_method.parameters,
71
+ )
72
+ verification_key = resolve_key(signature)
73
+ return [false, nil] if verification_key.nil?
74
+
75
+ ok = sm.verify(canonical, verification_key, signature.signature_value.value)
76
+ [ok, nil]
77
+ rescue VerificationError, UnknownAlgorithm => e
78
+ [false, e]
79
+ end
80
+
81
+ # Canonicalize the original SignedInfo element as it appears in the
82
+ # document. Re-serializing the parsed model would change namespace
83
+ # prefixes (e.g. SignedInfo → ds:SignedInfo) and break byte-exact
84
+ # verification.
85
+ def canonicalize_signed_info(c14n_uri, signed_info_elem)
86
+ Algorithms.lookup(:canonicalization, c14n_uri)
87
+ .new(identifier_uri: c14n_uri)
88
+ .canonicalize(signed_info_elem)
89
+ end
90
+
91
+ def resolve_key(signature)
92
+ return key if key
93
+ return nil unless signature.key_info
94
+
95
+ KeyExtractor.new(key_map: key_map).extract(signature.key_info)
96
+ end
97
+
98
+ def verify_references(signature, signature_element)
99
+ signature.signed_info.references.map do |ref|
100
+ verify_reference(ref, signature_element)
101
+ end
102
+ end
103
+
104
+ def verify_reference(reference, signature_element)
105
+ resolver = ReferenceResolver.new(context: context, document: document)
106
+ input = resolver.resolve(reference.uri)
107
+ pipeline = TransformPipeline.new(
108
+ context: context,
109
+ signature_element: signature_element,
110
+ )
111
+ transformed = pipeline.apply(input, reference.transforms)
112
+ canonical = pipeline.to_octets(transformed, reference)
113
+
114
+ digest_algo = Algorithms.lookup(
115
+ :digest, reference.digest_method.algorithm
116
+ ).new
117
+ computed = digest_algo.digest_base64(canonical)
118
+ expected = (reference.digest_value || "").strip
119
+
120
+ ReferenceResult.new(
121
+ uri: reference.uri,
122
+ digest_method: reference.digest_method.algorithm,
123
+ expected: expected,
124
+ computed: computed,
125
+ )
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+ require "base64"
5
+
6
+ module Moxml
7
+ # W3C XML Signature (xmldsig-core-1.1) processing for any moxml adapter.
8
+ #
9
+ # All XML operations flow through Moxml::Document / Moxml::Element; the
10
+ # signature module never touches the underlying adapter (Nokogiri, Oga,
11
+ # REXML, Ox, LibXML) directly.
12
+ module Signature
13
+ DSIG_NS = "http://www.w3.org/2000/09/xmldsig#"
14
+ DSIG11_NS = "http://www.w3.org/2009/xmldsig11#"
15
+ DSIG_MORE_NS = "http://www.w3.org/2001/04/xmldsig-more#"
16
+
17
+ autoload :Error, "moxml/signature/errors"
18
+ autoload :SignatureError, "moxml/signature/errors"
19
+ autoload :UnknownAlgorithm, "moxml/signature/errors"
20
+ autoload :DuplicateAlgorithm, "moxml/signature/errors"
21
+ autoload :SigningError, "moxml/signature/errors"
22
+ autoload :VerificationError, "moxml/signature/errors"
23
+ autoload :ReferenceDigestMismatch, "moxml/signature/errors"
24
+ autoload :SignatureValueMismatch, "moxml/signature/errors"
25
+ autoload :TransformError, "moxml/signature/errors"
26
+ autoload :CanonicalizationError, "moxml/signature/errors"
27
+ autoload :MalformedSignatureError, "moxml/signature/errors"
28
+ autoload :SignatureKeyError, "moxml/signature/errors"
29
+
30
+ autoload :Algorithms, "moxml/signature/algorithms"
31
+ autoload :C14n, "moxml/c14n"
32
+ autoload :Model, "moxml/signature/model"
33
+ autoload :Serializer, "moxml/signature/serializer"
34
+ autoload :Parser, "moxml/signature/parser"
35
+ autoload :ReferenceResolver, "moxml/signature/reference_resolver"
36
+ autoload :Signer, "moxml/signature/signer"
37
+ autoload :Verifier, "moxml/signature/verifier"
38
+ autoload :KeyExtractor, "moxml/signature/key_extractor"
39
+ autoload :TransformPipeline, "moxml/signature/transform_pipeline"
40
+ autoload :VerificationResult, "moxml/signature/verification_result"
41
+ autoload :SingleVerificationResult,
42
+ "moxml/signature/single_verification_result"
43
+ autoload :ReferenceResult, "moxml/signature/reference_result"
44
+
45
+ class << self
46
+ def sign(context:, document:, key:, **options)
47
+ signature = build_signature(context: context, document: document, **options)
48
+ Signer.new(
49
+ context: context,
50
+ signature: signature,
51
+ document: document,
52
+ key: key,
53
+ ).sign
54
+ signature
55
+ end
56
+
57
+ def verify(context:, document:, key: nil, **options)
58
+ Verifier.new(context: context, document: document, key: key, **options).verify
59
+ end
60
+
61
+ private
62
+
63
+ def build_signature(**opts)
64
+ _context = opts[:context]
65
+ _document = opts[:document]
66
+ signed_info = Model::SignedInfo.new(
67
+ canonicalization_method: Model::AlgorithmMethod.new(
68
+ algorithm: opts[:canonicalization_method],
69
+ ),
70
+ signature_method: Model::AlgorithmMethod.new(
71
+ algorithm: opts[:signature_method],
72
+ ),
73
+ references: [
74
+ Model::Reference.new(
75
+ uri: opts[:reference_uri],
76
+ transforms: Model::Transforms.new(
77
+ transforms: opts[:transforms].map do |transform|
78
+ Model::Transform.new(algorithm: transform)
79
+ end,
80
+ ),
81
+ digest_method: Model::DigestMethod.new(algorithm: opts[:digest_method]),
82
+ ),
83
+ ],
84
+ )
85
+
86
+ Model::Signature.new(
87
+ id: opts[:signature_id],
88
+ signed_info: signed_info,
89
+ key_info: opts[:key_info],
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
data/lib/moxml/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Moxml
4
- VERSION = "0.1.24"
4
+ VERSION = "0.1.26"
5
5
  end
data/lib/moxml.rb CHANGED
@@ -89,6 +89,8 @@ module Moxml
89
89
  autoload :Adapter, "moxml/adapter"
90
90
  autoload :XPath, "moxml/xpath"
91
91
  autoload :SAX, "moxml/sax"
92
+ autoload :Signature, "moxml/signature"
93
+ autoload :C14n, "moxml/c14n"
92
94
 
93
95
  # Error hierarchy — each subclass autoloads from the same file
94
96
  autoload :Error, "moxml/error"
data/moxml.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
27
27
  # RubyGem that have been added into git.
28
28
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
29
29
  `git ls-files -z`.split("\x0").reject do |f|
30
- f.match(%r{^(test|features)/})
30
+ f.match(%r{^(test|features|vendor/)})
31
31
  end
32
32
  end
33
33
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }