moxml 0.1.25 → 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.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +9 -0
- data/README.adoc +64 -0
- data/docs/signature/algorithms.md +108 -0
- data/docs/signature/architecture.md +148 -0
- data/docs/signature/c14n.md +110 -0
- data/docs/signature/examples.md +109 -0
- data/docs/signature/flows.md +132 -0
- data/docs/signature/quick-reference.md +115 -0
- data/docs/signature/security.md +143 -0
- data/examples/signature/auto_key_extraction.rb +24 -0
- data/examples/signature/enveloped_rsa.rb +45 -0
- data/examples/signature/hmac.rb +33 -0
- data/lib/moxml/c14n/attribute_handler.rb +71 -0
- data/lib/moxml/c14n/character_encoder.rb +29 -0
- data/lib/moxml/c14n/data_model.rb +145 -0
- data/lib/moxml/c14n/exclusive.rb +188 -0
- data/lib/moxml/c14n/inclusive_10.rb +42 -0
- data/lib/moxml/c14n/inclusive_11.rb +21 -0
- data/lib/moxml/c14n/namespace_context.rb +68 -0
- data/lib/moxml/c14n/namespace_handler.rb +71 -0
- data/lib/moxml/c14n/node.rb +42 -0
- data/lib/moxml/c14n/nodes/attribute_node.rb +50 -0
- data/lib/moxml/c14n/nodes/comment_node.rb +29 -0
- data/lib/moxml/c14n/nodes/element_node.rb +62 -0
- data/lib/moxml/c14n/nodes/namespace_node.rb +41 -0
- data/lib/moxml/c14n/nodes/processing_instruction_node.rb +30 -0
- data/lib/moxml/c14n/nodes/root_node.rb +22 -0
- data/lib/moxml/c14n/nodes/text_node.rb +29 -0
- data/lib/moxml/c14n/nodes.rb +17 -0
- data/lib/moxml/c14n/processor.rb +118 -0
- data/lib/moxml/c14n/writer.rb +121 -0
- data/lib/moxml/c14n/xml_base_handler.rb +140 -0
- data/lib/moxml/c14n.rb +96 -0
- data/lib/moxml/signature/algorithms/base64_transform.rb +40 -0
- data/lib/moxml/signature/algorithms/canonicalization_base.rb +87 -0
- data/lib/moxml/signature/algorithms/digest_base.rb +51 -0
- data/lib/moxml/signature/algorithms/dsa_sha.rb +107 -0
- data/lib/moxml/signature/algorithms/ecdsa_sha.rb +125 -0
- data/lib/moxml/signature/algorithms/enveloped_signature_transform.rb +79 -0
- data/lib/moxml/signature/algorithms/exc_c14n_10.rb +23 -0
- data/lib/moxml/signature/algorithms/hmac_sha.rb +117 -0
- data/lib/moxml/signature/algorithms/inclusive_c14n_10.rb +21 -0
- data/lib/moxml/signature/algorithms/inclusive_c14n_11.rb +23 -0
- data/lib/moxml/signature/algorithms/rsa_pkcs1_sha.rb +56 -0
- data/lib/moxml/signature/algorithms/sha1.rb +13 -0
- data/lib/moxml/signature/algorithms/sha224.rb +13 -0
- data/lib/moxml/signature/algorithms/sha256.rb +13 -0
- data/lib/moxml/signature/algorithms/sha384.rb +13 -0
- data/lib/moxml/signature/algorithms/sha512.rb +13 -0
- data/lib/moxml/signature/algorithms/signature_method_base.rb +58 -0
- data/lib/moxml/signature/algorithms/transform_base.rb +40 -0
- data/lib/moxml/signature/algorithms.rb +113 -0
- data/lib/moxml/signature/errors.rb +99 -0
- data/lib/moxml/signature/key_extractor.rb +172 -0
- data/lib/moxml/signature/model/algorithm_method.rb +18 -0
- data/lib/moxml/signature/model/digest_method.rb +15 -0
- data/lib/moxml/signature/model/key/dsa_key_value.rb +29 -0
- data/lib/moxml/signature/model/key/ec_key_value.rb +22 -0
- data/lib/moxml/signature/model/key/rsa_key_value.rb +19 -0
- data/lib/moxml/signature/model/key/x509_data.rb +32 -0
- data/lib/moxml/signature/model/key/x509_digest.rb +19 -0
- data/lib/moxml/signature/model/key/x509_issuer_serial.rb +19 -0
- data/lib/moxml/signature/model/key_info.rb +21 -0
- data/lib/moxml/signature/model/key_value.rb +20 -0
- data/lib/moxml/signature/model/object_element.rb +18 -0
- data/lib/moxml/signature/model/reference.rb +22 -0
- data/lib/moxml/signature/model/signature.rb +21 -0
- data/lib/moxml/signature/model/signature_value.rb +16 -0
- data/lib/moxml/signature/model/signed_info.rb +20 -0
- data/lib/moxml/signature/model/transform.rb +16 -0
- data/lib/moxml/signature/model/transforms.rb +36 -0
- data/lib/moxml/signature/model.rb +35 -0
- data/lib/moxml/signature/parser.rb +270 -0
- data/lib/moxml/signature/reference_resolver.rb +79 -0
- data/lib/moxml/signature/reference_result.rb +22 -0
- data/lib/moxml/signature/serializer.rb +163 -0
- data/lib/moxml/signature/signer.rb +73 -0
- data/lib/moxml/signature/single_verification_result.rb +31 -0
- data/lib/moxml/signature/transform_pipeline.rb +106 -0
- data/lib/moxml/signature/verification_result.rb +27 -0
- data/lib/moxml/signature/verifier.rb +129 -0
- data/lib/moxml/signature.rb +94 -0
- data/lib/moxml/version.rb +1 -1
- data/lib/moxml.rb +2 -0
- data/reference-docs/w3c-xmldsig-bestpractices.md +216 -0
- data/reference-docs/w3c-xmldsig-core.md +400 -0
- data/spec/fixtures/xmldsig/keys/rsa_private.pem +28 -0
- data/spec/fixtures/xmldsig/keys/rsa_public.pem +9 -0
- data/spec/fixtures/xmldsig/keys/rsa_ref.pem +15 -0
- data/spec/fixtures/xmldsig/keys/rsa_ref.pub +6 -0
- data/spec/fixtures/xmldsig/sign2-doc.xml +6 -0
- data/spec/fixtures/xmldsig/sign2-result.xml +25 -0
- data/spec/fixtures/xmldsig/sign3-result.xml +39 -0
- data/spec/moxml/c14n/api_spec.rb +117 -0
- data/spec/moxml/c14n/c14n_spec.rb +88 -0
- data/spec/moxml/c14n/comments_pis_spec.rb +65 -0
- data/spec/moxml/c14n/inclusive10_spec.rb +60 -0
- data/spec/moxml/c14n/namespace_edge_cases_spec.rb +88 -0
- data/spec/moxml/c14n/xml_attributes_spec.rb +54 -0
- data/spec/moxml/signature/algorithms/base64_transform_spec.rb +26 -0
- data/spec/moxml/signature/algorithms/digest_base_spec.rb +72 -0
- data/spec/moxml/signature/algorithms/dsa_sha_spec.rb +46 -0
- data/spec/moxml/signature/algorithms/ecdsa_sha_spec.rb +72 -0
- data/spec/moxml/signature/algorithms/enveloped_signature_transform_spec.rb +40 -0
- data/spec/moxml/signature/algorithms/hmac_sha_spec.rb +71 -0
- data/spec/moxml/signature/algorithms/rsa_pkcs1_sha_spec.rb +55 -0
- data/spec/moxml/signature/algorithms_spec.rb +76 -0
- data/spec/moxml/signature/cross_verify_spec.rb +64 -0
- data/spec/moxml/signature/edge_cases_spec.rb +284 -0
- data/spec/moxml/signature/fixtures_spec.rb +80 -0
- data/spec/moxml/signature/key_extractor_spec.rb +96 -0
- data/spec/moxml/signature/model_spec.rb +54 -0
- data/spec/moxml/signature/round_trip_spec.rb +113 -0
- metadata +111 -2
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
module Key
|
|
7
|
+
# dsig11:ECKeyValue — NamedCurve URI + PublicKey octets, or
|
|
8
|
+
# explicit ECParameters.
|
|
9
|
+
class ECKeyValue
|
|
10
|
+
attr_accessor :named_curve_uri, :public_key, :ec_parameters
|
|
11
|
+
|
|
12
|
+
def initialize(named_curve_uri: nil, public_key: nil,
|
|
13
|
+
ec_parameters: nil)
|
|
14
|
+
@named_curve_uri = named_curve_uri
|
|
15
|
+
@public_key = public_key
|
|
16
|
+
@ec_parameters = ec_parameters
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
module Key
|
|
7
|
+
# ds:RSAKeyValue — base64-encoded CryptoBinary Modulus + Exponent.
|
|
8
|
+
class RSAKeyValue
|
|
9
|
+
attr_accessor :modulus, :exponent
|
|
10
|
+
|
|
11
|
+
def initialize(modulus:, exponent:)
|
|
12
|
+
@modulus = modulus
|
|
13
|
+
@exponent = exponent
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
module Key
|
|
7
|
+
# ds:X509Data (spec §4.5.4) — container for certificate identifiers.
|
|
8
|
+
# May carry X509IssuerSerial, X509SubjectName, X509SKI, X509Certificate,
|
|
9
|
+
# X509CRL, and dsig11:X509Digest children, all describing the same key.
|
|
10
|
+
class X509Data
|
|
11
|
+
attr_accessor :issuer_serial, :subject_name, :subject_key_id,
|
|
12
|
+
:certificates, :crls, :digests
|
|
13
|
+
|
|
14
|
+
def initialize(issuer_serial: nil, subject_name: nil,
|
|
15
|
+
subject_key_id: nil, certificates: [],
|
|
16
|
+
crls: [], digests: [])
|
|
17
|
+
@issuer_serial = issuer_serial
|
|
18
|
+
@subject_name = subject_name
|
|
19
|
+
@subject_key_id = subject_key_id
|
|
20
|
+
@certificates = Array(certificates)
|
|
21
|
+
@crls = Array(crls)
|
|
22
|
+
@digests = Array(digests)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def first_certificate
|
|
26
|
+
certificates.first
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
module Key
|
|
7
|
+
# dsig11:X509Digest — algorithm URI + base64 digest of a cert.
|
|
8
|
+
class X509Digest
|
|
9
|
+
attr_accessor :algorithm, :digest
|
|
10
|
+
|
|
11
|
+
def initialize(algorithm:, digest:)
|
|
12
|
+
@algorithm = algorithm
|
|
13
|
+
@digest = digest
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
module Key
|
|
7
|
+
# ds:X509IssuerSerial — deprecated in favor of X509Digest.
|
|
8
|
+
class X509IssuerSerial
|
|
9
|
+
attr_accessor :issuer_name, :serial_number
|
|
10
|
+
|
|
11
|
+
def initialize(issuer_name:, serial_number:)
|
|
12
|
+
@issuer_name = issuer_name
|
|
13
|
+
@serial_number = serial_number
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class KeyInfo
|
|
7
|
+
attr_accessor :id, :key_name, :key_value, :x509_data,
|
|
8
|
+
:raw_elements
|
|
9
|
+
|
|
10
|
+
def initialize(id: nil, key_name: nil, key_value: nil,
|
|
11
|
+
x509_data: nil, raw_elements: [])
|
|
12
|
+
@id = id
|
|
13
|
+
@key_name = key_name
|
|
14
|
+
@key_value = key_value
|
|
15
|
+
@x509_data = x509_data
|
|
16
|
+
@raw_elements = raw_elements
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class KeyValue
|
|
7
|
+
attr_accessor :rsa_key_value, :dsa_key_value, :ec_key_value,
|
|
8
|
+
:raw_element
|
|
9
|
+
|
|
10
|
+
def initialize(rsa_key_value: nil, dsa_key_value: nil,
|
|
11
|
+
ec_key_value: nil, raw_element: nil)
|
|
12
|
+
@rsa_key_value = rsa_key_value
|
|
13
|
+
@dsa_key_value = dsa_key_value
|
|
14
|
+
@ec_key_value = ec_key_value
|
|
15
|
+
@raw_element = raw_element
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class ObjectElement
|
|
7
|
+
attr_accessor :id, :mime_type, :encoding, :content
|
|
8
|
+
|
|
9
|
+
def initialize(id: nil, mime_type: nil, encoding: nil, content: nil)
|
|
10
|
+
@id = id
|
|
11
|
+
@mime_type = mime_type
|
|
12
|
+
@encoding = encoding
|
|
13
|
+
@content = content
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class Reference
|
|
7
|
+
attr_accessor :id, :uri, :type, :transforms, :digest_method,
|
|
8
|
+
:digest_value
|
|
9
|
+
|
|
10
|
+
def initialize(id: nil, uri: nil, type: nil, transforms: nil,
|
|
11
|
+
digest_method: nil, digest_value: nil)
|
|
12
|
+
@id = id
|
|
13
|
+
@uri = uri
|
|
14
|
+
@type = type
|
|
15
|
+
@transforms = transforms
|
|
16
|
+
@digest_method = digest_method
|
|
17
|
+
@digest_value = digest_value
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class Signature
|
|
7
|
+
attr_accessor :id, :signed_info, :signature_value,
|
|
8
|
+
:key_info, :objects
|
|
9
|
+
|
|
10
|
+
def initialize(id: nil, signed_info: nil, signature_value: nil,
|
|
11
|
+
key_info: nil, objects: [])
|
|
12
|
+
@id = id
|
|
13
|
+
@signed_info = signed_info
|
|
14
|
+
@signature_value = signature_value
|
|
15
|
+
@key_info = key_info
|
|
16
|
+
@objects = objects
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class SignedInfo
|
|
7
|
+
attr_accessor :id, :canonicalization_method, :signature_method,
|
|
8
|
+
:references
|
|
9
|
+
|
|
10
|
+
def initialize(id: nil, canonicalization_method: nil,
|
|
11
|
+
signature_method: nil, references: [])
|
|
12
|
+
@id = id
|
|
13
|
+
@canonicalization_method = canonicalization_method
|
|
14
|
+
@signature_method = signature_method
|
|
15
|
+
@references = references
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class Transform
|
|
7
|
+
attr_accessor :algorithm, :parameters
|
|
8
|
+
|
|
9
|
+
def initialize(algorithm:, parameters: {})
|
|
10
|
+
@algorithm = algorithm
|
|
11
|
+
@parameters = parameters
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
module Model
|
|
6
|
+
class Transforms
|
|
7
|
+
attr_accessor :transforms
|
|
8
|
+
|
|
9
|
+
def initialize(transforms: [])
|
|
10
|
+
@transforms = Array(transforms)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def <<(transform)
|
|
14
|
+
@transforms << transform
|
|
15
|
+
self
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def each(&block)
|
|
19
|
+
@transforms.each(&block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def empty?
|
|
23
|
+
@transforms.empty?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def size
|
|
27
|
+
@transforms.size
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def length
|
|
31
|
+
@transforms.size
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Moxml
|
|
4
|
+
module Signature
|
|
5
|
+
# Plain-Ruby-Object model of the W3C ds:Signature schema.
|
|
6
|
+
#
|
|
7
|
+
# Models carry data; they do not (de)serialize themselves. The Serializer
|
|
8
|
+
# walks a model and emits a Moxml document; the Parser walks a Moxml
|
|
9
|
+
# document and constructs a model. This separation keeps the data shape
|
|
10
|
+
# and the wire shape independent.
|
|
11
|
+
module Model
|
|
12
|
+
autoload :Signature, "moxml/signature/model/signature"
|
|
13
|
+
autoload :SignedInfo, "moxml/signature/model/signed_info"
|
|
14
|
+
autoload :Reference, "moxml/signature/model/reference"
|
|
15
|
+
autoload :Transforms, "moxml/signature/model/transforms"
|
|
16
|
+
autoload :Transform, "moxml/signature/model/transform"
|
|
17
|
+
autoload :DigestMethod, "moxml/signature/model/digest_method"
|
|
18
|
+
autoload :AlgorithmMethod, "moxml/signature/model/algorithm_method"
|
|
19
|
+
autoload :SignatureValue, "moxml/signature/model/signature_value"
|
|
20
|
+
autoload :KeyInfo, "moxml/signature/model/key_info"
|
|
21
|
+
autoload :KeyValue, "moxml/signature/model/key_value"
|
|
22
|
+
autoload :ObjectElement, "moxml/signature/model/object_element"
|
|
23
|
+
|
|
24
|
+
module Key
|
|
25
|
+
autoload :X509Data, "moxml/signature/model/key/x509_data"
|
|
26
|
+
autoload :X509IssuerSerial,
|
|
27
|
+
"moxml/signature/model/key/x509_issuer_serial"
|
|
28
|
+
autoload :X509Digest, "moxml/signature/model/key/x509_digest"
|
|
29
|
+
autoload :RSAKeyValue, "moxml/signature/model/key/rsa_key_value"
|
|
30
|
+
autoload :DSAKeyValue, "moxml/signature/model/key/dsa_key_value"
|
|
31
|
+
autoload :ECKeyValue, "moxml/signature/model/key/ec_key_value"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
|
|
5
|
+
module Moxml
|
|
6
|
+
module Signature
|
|
7
|
+
# Translates a Moxml::Document containing ds:Signature into a Model::Signature.
|
|
8
|
+
#
|
|
9
|
+
# Robust against namespace prefix variations (ds:, dsig:, default ns).
|
|
10
|
+
class Parser
|
|
11
|
+
DS = { "ds" => DSIG_NS }.freeze
|
|
12
|
+
|
|
13
|
+
attr_reader :context
|
|
14
|
+
|
|
15
|
+
def initialize(context:)
|
|
16
|
+
@context = context
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# `signature_element`: a Moxml::Element whose name is Signature in the
|
|
20
|
+
# xmldsig# namespace.
|
|
21
|
+
def parse(signature_element)
|
|
22
|
+
Model::Signature.new(
|
|
23
|
+
id: signature_element["Id"],
|
|
24
|
+
signed_info: parse_signed_info(at_child(signature_element, "SignedInfo")),
|
|
25
|
+
signature_value: parse_signature_value(at_child(signature_element, "SignatureValue")),
|
|
26
|
+
key_info: parse_key_info(at_child(signature_element, "KeyInfo")),
|
|
27
|
+
objects: [],
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def parse_signed_info(elem)
|
|
34
|
+
return nil unless elem
|
|
35
|
+
|
|
36
|
+
Model::SignedInfo.new(
|
|
37
|
+
id: elem["Id"],
|
|
38
|
+
canonicalization_method: parse_algorithm_method(at_child(elem, "CanonicalizationMethod")),
|
|
39
|
+
signature_method: parse_algorithm_method(at_child(elem, "SignatureMethod")),
|
|
40
|
+
references: at_children(elem, "Reference").map { |r| parse_reference(r) },
|
|
41
|
+
)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def parse_algorithm_method(elem)
|
|
45
|
+
return nil unless elem
|
|
46
|
+
|
|
47
|
+
parameters = {}
|
|
48
|
+
hmac_len = at_child(elem, "HMACOutputLength")
|
|
49
|
+
if hmac_len
|
|
50
|
+
length = begin
|
|
51
|
+
Integer(hmac_len.text.strip)
|
|
52
|
+
rescue StandardError
|
|
53
|
+
nil
|
|
54
|
+
end
|
|
55
|
+
parameters[:hmac_output_length] = length if length
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
Model::AlgorithmMethod.new(
|
|
59
|
+
algorithm: elem["Algorithm"],
|
|
60
|
+
parameters: parameters,
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def parse_reference(elem)
|
|
65
|
+
return nil unless elem
|
|
66
|
+
|
|
67
|
+
transforms_elem = at_child(elem, "Transforms")
|
|
68
|
+
Model::Reference.new(
|
|
69
|
+
id: elem["Id"],
|
|
70
|
+
uri: elem["URI"],
|
|
71
|
+
type: elem["Type"],
|
|
72
|
+
transforms: parse_transforms(transforms_elem),
|
|
73
|
+
digest_method: parse_digest_method(at_child(elem, "DigestMethod")),
|
|
74
|
+
digest_value: at_child(elem, "DigestValue")&.text || "",
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def parse_transforms(elem)
|
|
79
|
+
return nil unless elem
|
|
80
|
+
|
|
81
|
+
transforms = at_children(elem, "Transform").map do |t|
|
|
82
|
+
xpath_children = at_children(t, "XPath").map(&:text)
|
|
83
|
+
Model::Transform.new(
|
|
84
|
+
algorithm: t["Algorithm"],
|
|
85
|
+
parameters: xpath_children.empty? ? {} : { xpaths: xpath_children },
|
|
86
|
+
)
|
|
87
|
+
end
|
|
88
|
+
Model::Transforms.new(transforms: transforms)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def parse_digest_method(elem)
|
|
92
|
+
return nil unless elem
|
|
93
|
+
|
|
94
|
+
Model::DigestMethod.new(algorithm: elem["Algorithm"])
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def parse_signature_value(elem)
|
|
98
|
+
return nil unless elem
|
|
99
|
+
|
|
100
|
+
text = (elem.text || "").gsub(/\s+/, "")
|
|
101
|
+
value = text.empty? ? nil : Base64.strict_decode64(text)
|
|
102
|
+
Model::SignatureValue.new(id: elem["Id"], value: value)
|
|
103
|
+
rescue ArgumentError => e
|
|
104
|
+
raise MalformedSignatureError.new(
|
|
105
|
+
"SignatureValue is not valid base64: #{e.message}",
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def parse_key_info(elem)
|
|
110
|
+
return nil unless elem
|
|
111
|
+
|
|
112
|
+
key_name_el = at_child(elem, "KeyName")
|
|
113
|
+
x509_data_el = at_child(elem, "X509Data")
|
|
114
|
+
key_value_el = at_child(elem, "KeyValue")
|
|
115
|
+
|
|
116
|
+
Model::KeyInfo.new(
|
|
117
|
+
id: elem["Id"],
|
|
118
|
+
key_name: key_name_el&.text,
|
|
119
|
+
x509_data: parse_x509_data(x509_data_el),
|
|
120
|
+
key_value: parse_key_value(key_value_el),
|
|
121
|
+
raw_elements: raw_key_info_children(elem),
|
|
122
|
+
)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def parse_x509_data(elem)
|
|
126
|
+
return nil unless elem
|
|
127
|
+
|
|
128
|
+
certificates = at_children(elem, "X509Certificate").map do |cert_el|
|
|
129
|
+
strip_base64(cert_el.text)
|
|
130
|
+
end
|
|
131
|
+
issuer_serial_el = at_child(elem, "X509IssuerSerial")
|
|
132
|
+
subject_name_el = at_child(elem, "X509SubjectName")
|
|
133
|
+
ski_el = at_child(elem, "X509SKI")
|
|
134
|
+
crl_els = at_children(elem, "X509CRL")
|
|
135
|
+
# dsig11:X509Digest is in a different namespace; look it up loosely.
|
|
136
|
+
digest_els = elem.children.select do |c|
|
|
137
|
+
c.is_a?(::Moxml::Element) &&
|
|
138
|
+
c.name == "X509Digest" &&
|
|
139
|
+
c.namespace_uri == DSIG11_NS
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
Model::Key::X509Data.new(
|
|
143
|
+
issuer_serial: parse_x509_issuer_serial(issuer_serial_el),
|
|
144
|
+
subject_name: subject_name_el&.text,
|
|
145
|
+
subject_key_id: strip_base64(ski_el&.text),
|
|
146
|
+
certificates: certificates,
|
|
147
|
+
crls: crl_els.map { |e| strip_base64(e.text) },
|
|
148
|
+
digests: digest_els.map { |e| parse_x509_digest(e) },
|
|
149
|
+
)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def parse_x509_issuer_serial(elem)
|
|
153
|
+
return nil unless elem
|
|
154
|
+
|
|
155
|
+
issuer = at_child(elem, "X509IssuerName")
|
|
156
|
+
serial = at_child(elem, "X509SerialNumber")
|
|
157
|
+
return nil unless issuer && serial
|
|
158
|
+
|
|
159
|
+
Model::Key::X509IssuerSerial.new(
|
|
160
|
+
issuer_name: issuer.text,
|
|
161
|
+
serial_number: serial.text,
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def parse_x509_digest(elem)
|
|
166
|
+
return nil unless elem
|
|
167
|
+
|
|
168
|
+
Model::Key::X509Digest.new(
|
|
169
|
+
algorithm: elem["Algorithm"],
|
|
170
|
+
digest: strip_base64(elem.text),
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def parse_key_value(elem)
|
|
175
|
+
return nil unless elem
|
|
176
|
+
|
|
177
|
+
rsa_el = at_child(elem, "RSAKeyValue")
|
|
178
|
+
dsa_el = at_child(elem, "DSAKeyValue")
|
|
179
|
+
ec_el = elem.children.find do |c|
|
|
180
|
+
c.is_a?(::Moxml::Element) &&
|
|
181
|
+
c.name == "ECKeyValue" &&
|
|
182
|
+
c.namespace_uri == DSIG11_NS
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
Model::KeyValue.new(
|
|
186
|
+
rsa_key_value: parse_rsa_key_value(rsa_el),
|
|
187
|
+
dsa_key_value: parse_dsa_key_value(dsa_el),
|
|
188
|
+
ec_key_value: parse_ec_key_value(ec_el),
|
|
189
|
+
)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def parse_rsa_key_value(elem)
|
|
193
|
+
return nil unless elem
|
|
194
|
+
|
|
195
|
+
Model::Key::RSAKeyValue.new(
|
|
196
|
+
modulus: text_of(elem, "Modulus"),
|
|
197
|
+
exponent: text_of(elem, "Exponent"),
|
|
198
|
+
)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def parse_dsa_key_value(elem)
|
|
202
|
+
return nil unless elem
|
|
203
|
+
|
|
204
|
+
Model::Key::DSAKeyValue.new(
|
|
205
|
+
p: text_of(elem, "P"),
|
|
206
|
+
q: text_of(elem, "Q"),
|
|
207
|
+
g: text_of(elem, "G"),
|
|
208
|
+
y: text_of(elem, "Y"),
|
|
209
|
+
j: text_of(elem, "J"),
|
|
210
|
+
seed: text_of(elem, "Seed"),
|
|
211
|
+
pgen_counter: text_of(elem, "PgenCounter"),
|
|
212
|
+
)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def parse_ec_key_value(elem)
|
|
216
|
+
return nil unless elem
|
|
217
|
+
|
|
218
|
+
named_curve_el = elem.children.find do |c|
|
|
219
|
+
c.is_a?(::Moxml::Element) &&
|
|
220
|
+
c.name == "NamedCurve" &&
|
|
221
|
+
c.namespace_uri == DSIG11_NS
|
|
222
|
+
end
|
|
223
|
+
public_key_el = elem.children.find do |c|
|
|
224
|
+
c.is_a?(::Moxml::Element) &&
|
|
225
|
+
c.name == "PublicKey" &&
|
|
226
|
+
c.namespace_uri == DSIG11_NS
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
Model::Key::ECKeyValue.new(
|
|
230
|
+
named_curve_uri: named_curve_el&.[]("URI"),
|
|
231
|
+
public_key: strip_base64(public_key_el&.text),
|
|
232
|
+
)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def text_of(parent, local_name)
|
|
236
|
+
elem = at_child(parent, local_name)
|
|
237
|
+
elem&.text
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def strip_base64(text)
|
|
241
|
+
return nil if text.nil?
|
|
242
|
+
|
|
243
|
+
text.to_s.gsub(/\s+/, "")
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def raw_key_info_children(elem)
|
|
247
|
+
# Children we don't model explicitly are preserved for round-trip
|
|
248
|
+
# fidelity (PGPData, SPKIData, MgmtData, dsig11:KeyInfoReference,
|
|
249
|
+
# dsig11:DEREncodedKeyValue, xenc:*).
|
|
250
|
+
elem.children.grep(::Moxml::Element).to_a
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def at_child(parent, local_name)
|
|
254
|
+
parent.children.find do |c|
|
|
255
|
+
c.is_a?(::Moxml::Element) &&
|
|
256
|
+
c.name == local_name &&
|
|
257
|
+
c.namespace_uri == DSIG_NS
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def at_children(parent, local_name)
|
|
262
|
+
parent.children.select do |c|
|
|
263
|
+
c.is_a?(::Moxml::Element) &&
|
|
264
|
+
c.name == local_name &&
|
|
265
|
+
c.namespace_uri == DSIG_NS
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|