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,400 @@
|
|
|
1
|
+
# XML Signature Syntax and Processing Version 1.1 (W3C Recommendation, 11 April 2013)
|
|
2
|
+
|
|
3
|
+
Curated implementation-focused extract. Source: https://www.w3.org/TR/xmldsig-core/
|
|
4
|
+
|
|
5
|
+
Editors: Donald Eastlake, Joseph Reagle, David Solo, Frederick Hirsch, Magnus Nyström, Thomas Roessler, Kelvin Yiu.
|
|
6
|
+
|
|
7
|
+
## Abstract
|
|
8
|
+
|
|
9
|
+
XML Signatures provide integrity, message authentication, and/or signer
|
|
10
|
+
authentication services for data of any type, whether located within the XML
|
|
11
|
+
that includes the signature or elsewhere.
|
|
12
|
+
|
|
13
|
+
## Namespaces
|
|
14
|
+
|
|
15
|
+
| URI | prefix |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| `http://www.w3.org/2000/09/xmldsig#` | `ds:` / `dsig:` |
|
|
18
|
+
| `http://www.w3.org/2009/xmldsig11#` | `dsig11:` |
|
|
19
|
+
|
|
20
|
+
Algorithm identifiers in the `http://www.w3.org/2001/04/xmldsig-more#` namespace
|
|
21
|
+
are defined by RFC 6931.
|
|
22
|
+
|
|
23
|
+
## Signature Structure
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
<Signature ID?>
|
|
27
|
+
<SignedInfo>
|
|
28
|
+
<CanonicalizationMethod />
|
|
29
|
+
<SignatureMethod />
|
|
30
|
+
(<Reference URI? >
|
|
31
|
+
(<Transforms>)?
|
|
32
|
+
<DigestMethod>
|
|
33
|
+
<DigestValue>
|
|
34
|
+
</Reference>)+
|
|
35
|
+
</SignedInfo>
|
|
36
|
+
<SignatureValue>
|
|
37
|
+
(<KeyInfo>)?
|
|
38
|
+
(<Object ID?>)*
|
|
39
|
+
</Signature>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Processing Rules
|
|
43
|
+
|
|
44
|
+
### 3.1 Signature Generation
|
|
45
|
+
|
|
46
|
+
#### 3.1.1 Reference Generation
|
|
47
|
+
|
|
48
|
+
For each data object being signed:
|
|
49
|
+
|
|
50
|
+
1. Apply the `Transforms`, as determined by the application, to the data object.
|
|
51
|
+
2. Calculate the digest value over the resulting data object.
|
|
52
|
+
3. Create a `Reference` element, including the (optional) identification of the
|
|
53
|
+
data object, any (optional) transform elements, the digest algorithm and the
|
|
54
|
+
`DigestValue`.
|
|
55
|
+
|
|
56
|
+
#### 3.1.2 Signature Generation
|
|
57
|
+
|
|
58
|
+
1. Create `SignedInfo` element with `SignatureMethod`, `CanonicalizationMethod`
|
|
59
|
+
and `Reference`(s).
|
|
60
|
+
2. Canonicalize and then calculate the `SignatureValue` over `SignedInfo` based
|
|
61
|
+
on algorithms specified in `SignedInfo`.
|
|
62
|
+
3. Construct the `Signature` element that includes `SignedInfo`, `Object`(s),
|
|
63
|
+
`KeyInfo` (if required), and `SignatureValue`.
|
|
64
|
+
|
|
65
|
+
### 3.2 Core Validation
|
|
66
|
+
|
|
67
|
+
The required steps of core validation include:
|
|
68
|
+
|
|
69
|
+
1. **Reference validation** — verification of the digest contained in each
|
|
70
|
+
`Reference` in `SignedInfo`.
|
|
71
|
+
2. **Signature validation** — cryptographic signature validation of the signature
|
|
72
|
+
calculated over `SignedInfo`.
|
|
73
|
+
|
|
74
|
+
Comparison of each value is over the numeric (integer) or decoded octet sequence
|
|
75
|
+
of the value.
|
|
76
|
+
|
|
77
|
+
#### 3.2.1 Reference Validation
|
|
78
|
+
|
|
79
|
+
1. Canonicalize the `SignedInfo` element based on the `CanonicalizationMethod`.
|
|
80
|
+
2. For each `Reference` in `SignedInfo`:
|
|
81
|
+
1. Obtain the data object (dereference `URI`, execute `Transforms`, or fetch
|
|
82
|
+
from local cache).
|
|
83
|
+
2. Digest using the `DigestMethod`.
|
|
84
|
+
3. Compare against `DigestValue`; mismatch ⇒ validation fails.
|
|
85
|
+
|
|
86
|
+
#### 3.2.2 Signature Validation
|
|
87
|
+
|
|
88
|
+
1. Obtain the keying information from `KeyInfo` or external source.
|
|
89
|
+
2. Obtain the canonical form of `SignedInfo` using `CanonicalizationMethod` and
|
|
90
|
+
confirm the `SignatureValue` over `SignedInfo`.
|
|
91
|
+
|
|
92
|
+
## Schema
|
|
93
|
+
|
|
94
|
+
### `ds:CryptoBinary`
|
|
95
|
+
|
|
96
|
+
Integer-to-octet conversion equivalent to IEEE 1363 I2OSP with minimal length,
|
|
97
|
+
then base64-encoded.
|
|
98
|
+
|
|
99
|
+
### 4.2 `Signature`
|
|
100
|
+
|
|
101
|
+
```xml
|
|
102
|
+
<element name="Signature" type="ds:SignatureType"/>
|
|
103
|
+
<complexType name="SignatureType">
|
|
104
|
+
<sequence>
|
|
105
|
+
<element ref="ds:SignedInfo"/>
|
|
106
|
+
<element ref="ds:SignatureValue"/>
|
|
107
|
+
<element ref="ds:KeyInfo" minOccurs="0"/>
|
|
108
|
+
<element ref="ds:Object" minOccurs="0" maxOccurs="unbounded"/>
|
|
109
|
+
</sequence>
|
|
110
|
+
<attribute name="Id" type="ID" use="optional"/>
|
|
111
|
+
</complexType>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 4.3 `SignatureValue`
|
|
115
|
+
|
|
116
|
+
```xml
|
|
117
|
+
<complexType name="SignatureValueType">
|
|
118
|
+
<simpleContent>
|
|
119
|
+
<extension base="base64Binary">
|
|
120
|
+
<attribute name="Id" type="ID" use="optional"/>
|
|
121
|
+
</extension>
|
|
122
|
+
</simpleContent>
|
|
123
|
+
</complexType>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 4.4 `SignedInfo`
|
|
127
|
+
|
|
128
|
+
```xml
|
|
129
|
+
<complexType name="SignedInfoType">
|
|
130
|
+
<sequence>
|
|
131
|
+
<element ref="ds:CanonicalizationMethod"/>
|
|
132
|
+
<element ref="ds:SignatureMethod"/>
|
|
133
|
+
<element ref="ds:Reference" maxOccurs="unbounded"/>
|
|
134
|
+
</sequence>
|
|
135
|
+
<attribute name="Id" type="ID" use="optional"/>
|
|
136
|
+
</complexType>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 4.4.1 `CanonicalizationMethod`
|
|
140
|
+
|
|
141
|
+
```xml
|
|
142
|
+
<complexType name="CanonicalizationMethodType" mixed="true">
|
|
143
|
+
<sequence>
|
|
144
|
+
<any namespace="##any" minOccurs="0" maxOccurs="unbounded"/>
|
|
145
|
+
</sequence>
|
|
146
|
+
<attribute name="Algorithm" type="anyURI" use="required"/>
|
|
147
|
+
</complexType>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### 4.4.2 `SignatureMethod`
|
|
151
|
+
|
|
152
|
+
```xml
|
|
153
|
+
<complexType name="SignatureMethodType" mixed="true">
|
|
154
|
+
<sequence>
|
|
155
|
+
<element name="HMACOutputLength" minOccurs="0" type="ds:HMACOutputLengthType"/>
|
|
156
|
+
<any namespace="##other" minOccurs="0" maxOccurs="unbounded"/>
|
|
157
|
+
</sequence>
|
|
158
|
+
<attribute name="Algorithm" type="anyURI" use="required"/>
|
|
159
|
+
</complexType>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Signatures MUST be deemed invalid if the HMAC truncation length is below the
|
|
163
|
+
larger of (a) half the underlying hash output length, and (b) 80 bits.
|
|
164
|
+
|
|
165
|
+
### 4.4.3 `Reference`
|
|
166
|
+
|
|
167
|
+
```xml
|
|
168
|
+
<complexType name="ReferenceType">
|
|
169
|
+
<sequence>
|
|
170
|
+
<element ref="ds:Transforms" minOccurs="0"/>
|
|
171
|
+
<element ref="ds:DigestMethod"/>
|
|
172
|
+
<element ref="ds:DigestValue"/>
|
|
173
|
+
</sequence>
|
|
174
|
+
<attribute name="Id" type="ID" use="optional"/>
|
|
175
|
+
<attribute name="URI" type="anyURI" use="optional"/>
|
|
176
|
+
<attribute name="Type" type="anyURI" use="optional"/>
|
|
177
|
+
</complexType>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
#### 4.4.3.2 Reference Processing Model
|
|
181
|
+
|
|
182
|
+
Result of URI dereferencing or transforms is either octet stream or XPath node-set.
|
|
183
|
+
|
|
184
|
+
Defaults:
|
|
185
|
+
- octet stream + node-set transform expected ⇒ parse octets as XML.
|
|
186
|
+
- node-set + octet transform expected ⇒ canonicalize via C14N.
|
|
187
|
+
|
|
188
|
+
A **same-document reference** is a URI-Reference that consists of `#` followed by
|
|
189
|
+
a fragment, or an empty URI.
|
|
190
|
+
|
|
191
|
+
- `URI=""` ⇒ node-set (minus comments) of the entire document.
|
|
192
|
+
- `URI="#id"` ⇒ node-set of the element with that ID + descendants + in-scope
|
|
193
|
+
namespaces/attributes, no comments.
|
|
194
|
+
- `#xpointer(/)` retains comments at root.
|
|
195
|
+
- `#xpointer(id('ID'))` retains comments for the element.
|
|
196
|
+
|
|
197
|
+
### 4.4.3.4 `Transforms`
|
|
198
|
+
|
|
199
|
+
```xml
|
|
200
|
+
<complexType name="TransformsType">
|
|
201
|
+
<sequence>
|
|
202
|
+
<element ref="ds:Transform" maxOccurs="unbounded"/>
|
|
203
|
+
</sequence>
|
|
204
|
+
</complexType>
|
|
205
|
+
|
|
206
|
+
<complexType name="TransformType" mixed="true">
|
|
207
|
+
<choice minOccurs="0" maxOccurs="unbounded">
|
|
208
|
+
<any namespace="##other" processContents="lax"/>
|
|
209
|
+
<element name="XPath" type="string"/>
|
|
210
|
+
</choice>
|
|
211
|
+
<attribute name="Algorithm" type="anyURI" use="required"/>
|
|
212
|
+
</complexType>
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### 4.5 `KeyInfo`
|
|
216
|
+
|
|
217
|
+
```xml
|
|
218
|
+
<complexType name="KeyInfoType" mixed="true">
|
|
219
|
+
<choice maxOccurs="unbounded">
|
|
220
|
+
<element ref="ds:KeyName"/>
|
|
221
|
+
<element ref="ds:KeyValue"/>
|
|
222
|
+
<element ref="ds:RetrievalMethod"/>
|
|
223
|
+
<element ref="ds:X509Data"/>
|
|
224
|
+
<element ref="ds:PGPData"/>
|
|
225
|
+
<element ref="ds:SPKIData"/>
|
|
226
|
+
<element ref="ds:MgmtData"/>
|
|
227
|
+
<any processContents="lax" namespace="##other"/>
|
|
228
|
+
</choice>
|
|
229
|
+
<attribute name="Id" type="ID" use="optional"/>
|
|
230
|
+
</complexType>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
`KeyValue` contains one of `DSAKeyValue`, `RSAKeyValue`, or (1.1) `ECKeyValue`.
|
|
234
|
+
|
|
235
|
+
X509Data child elements: `X509IssuerSerial` (deprecated), `X509SKI`,
|
|
236
|
+
`X509SubjectName`, `X509Certificate`, `X509CRL`, `dsig11:X509Digest`.
|
|
237
|
+
|
|
238
|
+
### 4.6 `Object`
|
|
239
|
+
|
|
240
|
+
Optional element for including data objects. Has `Id`, `MimeType`, `Encoding`
|
|
241
|
+
attributes.
|
|
242
|
+
|
|
243
|
+
## Additional Syntax
|
|
244
|
+
|
|
245
|
+
### 5.1 `Manifest`
|
|
246
|
+
|
|
247
|
+
A list of `Reference`s where digest checking is application-defined (not core).
|
|
248
|
+
|
|
249
|
+
### 5.2 `SignatureProperties`
|
|
250
|
+
|
|
251
|
+
For signature-time, hardware serial, etc. `SignatureProperty` has required
|
|
252
|
+
`Target` attribute referencing the `Signature` element.
|
|
253
|
+
|
|
254
|
+
### 5.3 PIs and 5.4 Comments
|
|
255
|
+
|
|
256
|
+
Unless `CanonicalizationMethod` strips comments or PIs, they are signed.
|
|
257
|
+
|
|
258
|
+
## Algorithms
|
|
259
|
+
|
|
260
|
+
### Mandatory & Recommended URIs
|
|
261
|
+
|
|
262
|
+
**Digest**:
|
|
263
|
+
- Required: SHA1 `http://www.w3.org/2000/09/xmldsig#sha1` (discouraged); SHA256
|
|
264
|
+
`http://www.w3.org/2001/04/xmlenc#sha256`
|
|
265
|
+
- Optional: SHA224 `…xmldsig-more#sha224`; SHA384 `…xmldsig-more#sha384`; SHA512
|
|
266
|
+
`…xmlenc#sha512`
|
|
267
|
+
|
|
268
|
+
**MAC**:
|
|
269
|
+
- Required: HMAC-SHA1 `…xmldsig#hmac-sha1` (discouraged); HMAC-SHA256
|
|
270
|
+
`…xmldsig-more#hmac-sha256`
|
|
271
|
+
- Recommended: HMAC-SHA384, HMAC-SHA512
|
|
272
|
+
|
|
273
|
+
**Signature**:
|
|
274
|
+
- Required: RSA-SHA256 `…xmldsig-more#rsa-sha256`; ECDSA-SHA256
|
|
275
|
+
`…xmldsig-more#ecdsa-sha256`; DSA-SHA1 (verification only) `…xmldsig#dsa-sha1`
|
|
276
|
+
- Recommended: RSA-SHA1 (verification; discouraged for generation)
|
|
277
|
+
- Optional: RSA-{SHA224,SHA384,SHA512}; ECDSA-{SHA1,SHA224,SHA384,SHA512};
|
|
278
|
+
DSA-SHA256 `…xmldsig11#dsa-sha256`
|
|
279
|
+
|
|
280
|
+
**Canonicalization**:
|
|
281
|
+
- Required:
|
|
282
|
+
- Canonical XML 1.0 (omit comments): `http://www.w3.org/TR/2001/REC-xml-c14n-20010315`
|
|
283
|
+
- Canonical XML 1.1 (omit comments): `http://www.w3.org/2006/12/xml-c14n11`
|
|
284
|
+
- Exclusive XML Canonicalization 1.0 (omit comments): `http://www.w3.org/2001/10/xml-exc-c14n#`
|
|
285
|
+
- Recommended variants append `#WithComments`
|
|
286
|
+
|
|
287
|
+
**Transform**:
|
|
288
|
+
- Required: base64 `…xmldsig#base64`; Enveloped Signature
|
|
289
|
+
`…xmldsig#enveloped-signature`
|
|
290
|
+
- Recommended: XPath `…REC-xpath-19991116`; XPath Filter 2.0
|
|
291
|
+
`…2002/06/xmldsig-filter2`
|
|
292
|
+
- Optional: XSLT `…REC-xslt-19991116`
|
|
293
|
+
|
|
294
|
+
### Digest Algorithms
|
|
295
|
+
|
|
296
|
+
- SHA-1: 160-bit / 20 octets, base64-encoded.
|
|
297
|
+
- SHA-256: 256-bit / 32 octets.
|
|
298
|
+
- SHA-384: 384-bit / 48 octets.
|
|
299
|
+
- SHA-512: 512-bit / 64 octets.
|
|
300
|
+
|
|
301
|
+
### HMAC
|
|
302
|
+
|
|
303
|
+
Identifier family: `…xmldsig#hmac-sha1`, `…xmldsig-more#hmac-{sha224,sha256,sha384,sha512}`.
|
|
304
|
+
Truncation length (`HMACOutputLength`) MUST be a multiple of 8 bits. If below
|
|
305
|
+
half the hash output length, signature MUST be deemed invalid.
|
|
306
|
+
|
|
307
|
+
### DSA
|
|
308
|
+
|
|
309
|
+
Identifier: `…xmldsig#dsa-sha1` (1024/160), `…xmldsig11#dsa-sha256` (2048/256 or
|
|
310
|
+
3072/256).
|
|
311
|
+
|
|
312
|
+
Output (r, s): base64-encoded concatenation of two octet streams using I2OSP with
|
|
313
|
+
length parameter 20 (for SHA-1) or `N` (for SHA-256 with N=|q|).
|
|
314
|
+
|
|
315
|
+
### RSA (PKCS#1 v1.5)
|
|
316
|
+
|
|
317
|
+
Identifiers: `…xmldsig#rsa-sha1`, `…xmldsig-more#rsa-{sha224,sha256,sha384,sha512}`.
|
|
318
|
+
RSASSA-PKCS1-v1_5 per RFC 3447 §8.2.1.
|
|
319
|
+
|
|
320
|
+
### ECDSA
|
|
321
|
+
|
|
322
|
+
Identifiers: `…xmldsig-more#ecdsa-{sha1,sha224,sha256,sha384,sha512}`.
|
|
323
|
+
Output (r, s): base64-encoded concatenation of I2OSP of r and s, each of length
|
|
324
|
+
equal to the base point order in bytes (32 for P-256, 66 for P-521).
|
|
325
|
+
|
|
326
|
+
Required curve: P-256 (FIPS 186-3 §D.2.3). Recommended: P-384, P-521.
|
|
327
|
+
|
|
328
|
+
### Canonicalization
|
|
329
|
+
|
|
330
|
+
All algorithms take octet-stream or node-set, produce octet-stream output.
|
|
331
|
+
Output is UTF-8 (no BOM), NFC. See [XML-C14N], [XML-C14N11], [XML-EXC-C14N].
|
|
332
|
+
|
|
333
|
+
### Transforms
|
|
334
|
+
|
|
335
|
+
- **base64** (octet→octet, node-set→octet): decodes base64. For node-set input,
|
|
336
|
+
logically applies `self::text()`, sorts by document order, concatenates.
|
|
337
|
+
- **XPath Filtering** (octet|node-set → node-set): evaluates XPath per node,
|
|
338
|
+
includes nodes where boolean result is true. Includes `here()` function.
|
|
339
|
+
- **Enveloped Signature**: removes the containing `Signature` element from
|
|
340
|
+
digest calculation. Equivalent to specific XPath.
|
|
341
|
+
- **XSLT**: octet-stream → octet-stream via XSL stylesheet (sole child).
|
|
342
|
+
|
|
343
|
+
## XML Canonicalization Considerations
|
|
344
|
+
|
|
345
|
+
Signatures only work if verification uses the same bits as signing. XML surface
|
|
346
|
+
forms vary, so canonicalization standardizes before signing/verification.
|
|
347
|
+
|
|
348
|
+
Categories of change to canonicalize:
|
|
349
|
+
1. XML 1.0 syntax (line endings, attribute defaults, entity refs, attribute
|
|
350
|
+
normalization).
|
|
351
|
+
2. DOM/SAX information loss (attribute order, insignificant whitespace, namespace
|
|
352
|
+
declaration locations).
|
|
353
|
+
3. Charset conversion.
|
|
354
|
+
4. Namespace inheritance/context.
|
|
355
|
+
|
|
356
|
+
All canonicalization algorithms identified use UTF-8 (no BOM) and do not perform
|
|
357
|
+
character normalization. Applications SHOULD produce content in NFC.
|
|
358
|
+
|
|
359
|
+
### Namespace Context and Portable Signatures
|
|
360
|
+
|
|
361
|
+
Inclusive canonicalization "attracts" ancestor namespace context, breaking
|
|
362
|
+
signatures when subdocuments are moved. Exclusive canonicalization "repels"
|
|
363
|
+
ancestor context, preserving portability.
|
|
364
|
+
|
|
365
|
+
## Security Considerations
|
|
366
|
+
|
|
367
|
+
### 8.1 Transforms
|
|
368
|
+
|
|
369
|
+
- Only what is signed is secure.
|
|
370
|
+
- Only what is "seen" should be signed.
|
|
371
|
+
- "See" what is signed (operate over canonicalized form).
|
|
372
|
+
|
|
373
|
+
### 8.2 Security Models
|
|
374
|
+
|
|
375
|
+
Public-key signatures vs keyed-hash MACs have different trust models. Public
|
|
376
|
+
keys verify; only private-key holders can sign. MAC keys are shared; any
|
|
377
|
+
verifier can forge.
|
|
378
|
+
|
|
379
|
+
### 8.3 Algorithms, Key Lengths, Certificates
|
|
380
|
+
|
|
381
|
+
Conforming implementations MUST support RSA signature generation and
|
|
382
|
+
verification with public keys at least 2048 bits. 3072-bit recommended for
|
|
383
|
+
signatures verified beyond 2030.
|
|
384
|
+
|
|
385
|
+
### 8.4 Error Messages
|
|
386
|
+
|
|
387
|
+
Generic error responses; avoid leaking specifics about algorithm processing.
|
|
388
|
+
|
|
389
|
+
## References
|
|
390
|
+
|
|
391
|
+
- [XML-C14N] Canonical XML 1.0
|
|
392
|
+
- [XML-C14N11] Canonical XML 1.1
|
|
393
|
+
- [XML-EXC-C14N] Exclusive XML Canonicalization 1.0
|
|
394
|
+
- [PKCS1] RFC 3447 (RSA Cryptography Specifications v2.1)
|
|
395
|
+
- [FIPS-186-3] Digital Signature Standard
|
|
396
|
+
- [FIPS-180-3] Secure Hash Standard
|
|
397
|
+
- [HMAC] RFC 2104
|
|
398
|
+
- [RFC6931] Additional XML Security URIs
|
|
399
|
+
- [XPATH] XML Path Language 1.0
|
|
400
|
+
- [XMLDSIG-BESTPRACTICES] XML Signature Best Practices
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8F3ut738mezjz
|
|
3
|
+
Wg6J11OJCe28lyJXHcb6PbMJVm9NUC3MeMr27PI9s7ildxEodm9bOkXTIGD1ev4Y
|
|
4
|
+
4p69cjMeyn1vFoxUyE+IN9+0pSVs/ABf19/349MFMTC1mpWlBvRtOKyCkLObQ0hn
|
|
5
|
+
i+lMd4mQ+Ht+6+ZQNpNGIE0HcUUTH/r13AkmYLGYjlf2BwiqLP5MaxsdARormXwJ
|
|
6
|
+
wsJD92us5MHN2P4Pew+J+TyCMdM94h7TCR4vmhZrX7EQcbIfsIEYpfRs3IeORW90
|
|
7
|
+
CoXt7AgLmC+myMt8N/VF6OTKzXrShjGGeF88sikG0GSsIVWy7+tReqe4rfx/iavd
|
|
8
|
+
da0LhPJVAgMBAAECggEAMSugaPmFj11CJ5fg2hcA3v/J9vW5g/WkWTG89pFyek8e
|
|
9
|
+
Eeh4ArIxp4Cuog7s3NuNQ9eJfmZmAnZ7K60+mz7Z71A3F03ZNKbC59TXdeWAUavV
|
|
10
|
+
Ozj3c1nLBf30gl0dhq05Q74/lshWM54UtQEF5bgQLeZPfoATzt9dg8UY7ful95f/
|
|
11
|
+
StU1jJB16r7l8Oy1KyJE094ZL+dYSAaJaG/kb/hq857UJxU/9mmnqq0AsAseXrHm
|
|
12
|
+
9T4AR5vJjhh71+3BHsQNxP6oO2ErV+Bd4MddMRYZbyo7jVIN6t6nti+uB+reKAi0
|
|
13
|
+
FdcKNL+zldxPyKzt/dXh43M1Y60aFJ9jre/x+aqW9wKBgQDmGrguBixFJiBYdJXw
|
|
14
|
+
NXyIDKDYPRlP3+B28piybne3JVvnyZQ+v5KmDCAtE4i/hIkX9/pdyXAoAfsEI8dc
|
|
15
|
+
sarcFPynMjl+BpBxRKiMgIJvAsRh83HfrkewUTk9uhD3hqW4RlKZZIRlsPuEhIcG
|
|
16
|
+
2oWJzwuDlRsZyrlqLef94O59FwKBgQDRQmJgZm0faJfIFkmy17iCSmpLCHsef3iJ
|
|
17
|
+
gKr2yQBxOJMwConPauZEQ+YdTjk2XPo81TNpjWyBKZD+1RPPpJ5sFzUAfAqCfsxY
|
|
18
|
+
EZWCzuZKntiegwOsdRrp5FdAFrFCmttW0p5AnTH23PMKxT+7fMDmuwq1X3pS712X
|
|
19
|
+
hGujrnXncwKBgDKKrefWDUVHAZXMTd7MMMVFWNMGYJftycT2tlmC8CK3Pv+jhD9g
|
|
20
|
+
HtsAENU11DSU7PPp0QFmrI7tGHCpVzHiCHB8353t5zjqQjHO7eKmm3+8sNv++AU0
|
|
21
|
+
p6Rvws3vH6ju11mpgJ0WugoIHMbXwTzdJLXHV3UYfDJnF+DdonZeQKQTAoGAIo7K
|
|
22
|
+
/k6MAN7eCg4cN6vGbcXqTd/lrUCx4EtecIj7SLdmH03uOlHWGzn3W6maay7pqHgx
|
|
23
|
+
GGJho+cAagU4U1dFTmZ6u0zA05IrHvQwc7zFbVdUQME0LxvbyPqLqirVNUGrrWf0
|
|
24
|
+
+Ii9Qp50iLfQcZ8FoFUNTKyq391l4Gre99YM5J8CgYEA2EsA5AVf3Q4hkY5ImWN9
|
|
25
|
+
hWgcvKaa1Fw8n59iGExgoh1Zr4p9SWxaNxa/iY3q0wdiQBMihEgFdc3JMBiS3RSe
|
|
26
|
+
KZCpPAFeNW9RnXIQwnW06oyaiZkymLq96cYT5ToSLEoFl9/Z+ulMAYrfRJGszyR+
|
|
27
|
+
hJAW5QUsrp1RKksKftYOAlA=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
|
2
|
+
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvBd7re9/Jns481oOiddT
|
|
3
|
+
iQntvJciVx3G+j2zCVZvTVAtzHjK9uzyPbO4pXcRKHZvWzpF0yBg9Xr+GOKevXIz
|
|
4
|
+
Hsp9bxaMVMhPiDfftKUlbPwAX9ff9+PTBTEwtZqVpQb0bTisgpCzm0NIZ4vpTHeJ
|
|
5
|
+
kPh7fuvmUDaTRiBNB3FFEx/69dwJJmCxmI5X9gcIqiz+TGsbHQEaK5l8CcLCQ/dr
|
|
6
|
+
rOTBzdj+D3sPifk8gjHTPeIe0wkeL5oWa1+xEHGyH7CBGKX0bNyHjkVvdAqF7ewI
|
|
7
|
+
C5gvpsjLfDf1Rejkys160oYxhnhfPLIpBtBkrCFVsu/rUXqnuK38f4mr3XWtC4Ty
|
|
8
|
+
VQIDAQAB
|
|
9
|
+
-----END PUBLIC KEY-----
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
+
MIICXgIBAAKBgQC15La+LSmHNUs/yqzSuzKdBUED1OfaOZpBp8zxAAQy7VlTrqRh
|
|
3
|
+
/eiJH3VSeRRZEygORvtLgi/teF2P+z/mfJ6IHIdCdkn8MF4CCCQKkjm7JKRrKfK5
|
|
4
|
+
fOUp1NZF22oP8x0L4j67NYCtR9F6KIkV5A6FPAZGI8nsHnyJzRwqmG2xbQIDAQAB
|
|
5
|
+
AoGBAJDT2UW3g/dqUc4rPExWTUiFJG0+mpVBhDd+ukmyL6W1Iojk53I2z25PJAVU
|
|
6
|
+
7wS1ohEsJ27J7Aty6Vx5Ozn0Q+zYVaKRSxcazNeGbwS0UaGrN0lMvWDs7RmVGCdx
|
|
7
|
+
bI2LUTQ88Bl94dW4QObAub+wMOL6xmVEVrJssZnm+CIqS2UBAkEA49QDNB//oHmi
|
|
8
|
+
iqD4SFotE8Lz80qBGHN15YIm80TKUR2k1LusZl6R5+2nYTF2vPsG+HGXPbkGhqTn
|
|
9
|
+
JL9GMBv7TQJBAMxinne8+bKTvOl/hhdAohFs7aHUBZhZOEuXIf1jYENASk2weYC6
|
|
10
|
+
95SlHvWcwPHfqVbpwt83sGL8aDm8CCPYPqECQQDEFRQQx72GC0oG0FYAR4RmbrLx
|
|
11
|
+
YN1NAwqkVmlZlIogWEgmQ8Q0cw5Ws+cMMrtEGTU9nN4TZGymc8TwjqNFAsA9AkEA
|
|
12
|
+
ol8Cp/uQn6cxIIt4Gsb1OkTAcJ0BKOxQhfT2QtiNJEBSB3BYxsVCZWvcsaGrwzw9
|
|
13
|
+
yteBQlZ6odkGcD+Kc/eaoQJAH+0a7jlHDu2VCHI63OiNZQJ8J9oxaPvWZyKYSaCO
|
|
14
|
+
iGvon/Z6KGQhXMedPDaCH7UjeMle5AVhjSrSvF6OglgZ9g==
|
|
15
|
+
-----END RSA PRIVATE KEY-----
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
-----BEGIN PUBLIC KEY-----
|
|
2
|
+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC15La+LSmHNUs/yqzSuzKdBUED
|
|
3
|
+
1OfaOZpBp8zxAAQy7VlTrqRh/eiJH3VSeRRZEygORvtLgi/teF2P+z/mfJ6IHIdC
|
|
4
|
+
dkn8MF4CCCQKkjm7JKRrKfK5fOUp1NZF22oP8x0L4j67NYCtR9F6KIkV5A6FPAZG
|
|
5
|
+
I8nsHnyJzRwqmG2xbQIDAQAB
|
|
6
|
+
-----END PUBLIC KEY-----
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<Envelope xmlns="urn:envelope">
|
|
3
|
+
<Data>
|
|
4
|
+
Hello, World!
|
|
5
|
+
</Data>
|
|
6
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
7
|
+
<SignedInfo>
|
|
8
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
9
|
+
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
|
10
|
+
<Reference>
|
|
11
|
+
<Transforms>
|
|
12
|
+
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
13
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
14
|
+
</Transforms>
|
|
15
|
+
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
|
16
|
+
<DigestValue>Gx8CGUsbi2qvBLd15VCmwELbDMND8F4vY3jPOc7/FJ0=</DigestValue>
|
|
17
|
+
</Reference>
|
|
18
|
+
</SignedInfo>
|
|
19
|
+
<SignatureValue>T2c7nqOw55P8hcP1qhvfPCwOSEAuo8HstZf9shlrggcarxfgWTKhA6UdrF4McfrS
|
|
20
|
+
XtcgHA7zy0Yzd2cgeGkKA2jgI+9QRhoQsifOMuI55sE5r+fpBs+goaxC57gmcBXj
|
|
21
|
+
XnuwIiWf7nfpF4hYZ841HzYd2HcpQKPTdbhvZUprvx8=</SignatureValue>
|
|
22
|
+
<KeyInfo>
|
|
23
|
+
<KeyName>test</KeyName>
|
|
24
|
+
</KeyInfo>
|
|
25
|
+
</Signature></Envelope>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<?xml version="1.0"?>
|
|
2
|
+
<Envelope xmlns="urn:envelope">
|
|
3
|
+
<Data>
|
|
4
|
+
Hello, World!
|
|
5
|
+
</Data>
|
|
6
|
+
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
|
7
|
+
<SignedInfo>
|
|
8
|
+
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
9
|
+
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
|
10
|
+
<Reference>
|
|
11
|
+
<Transforms>
|
|
12
|
+
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
|
13
|
+
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
|
14
|
+
</Transforms>
|
|
15
|
+
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
|
16
|
+
<DigestValue>Gx8CGUsbi2qvBLd15VCmwELbDMND8F4vY3jPOc7/FJ0=</DigestValue>
|
|
17
|
+
</Reference>
|
|
18
|
+
</SignedInfo>
|
|
19
|
+
<SignatureValue>TGJ9fCzjppp3LgG4fiBJx+0R34wRa7il9XKKZ+kkOAdKkcW0PIAYKmjn0Tn8krGd
|
|
20
|
+
Gw6qtFFqjdohXfhkKmajXAFunEtd3J0kHFkf3obIwRB1qdsYmKXVFxUx3GqcIlph
|
|
21
|
+
vt9v/9FC12JAxwAiJXHuY2xN5uo3xSDER4+tCCy3/AI=</SignatureValue>
|
|
22
|
+
<KeyInfo>
|
|
23
|
+
<X509Data>
|
|
24
|
+
<X509Certificate>MIICLzCCAZgCCQCVuhhQ38rw0TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJV
|
|
25
|
+
UzEQMA4GA1UECAwHR2VvcmdpYTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
|
|
26
|
+
dHkgTHRkMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTAgFw0xMzA1MjUxODQwMDRa
|
|
27
|
+
GA8zMDEyMDkyNTE4NDAwNFowWzELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0dlb3Jn
|
|
28
|
+
aWExITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEXMBUGA1UEAwwO
|
|
29
|
+
d3d3Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALE4oSql
|
|
30
|
+
eymfHtzOeY86WyvfsjZmaz2XnIo9dzZsK71yMEKkgvXQnnYy9pK0NaYcG0B0hcii
|
|
31
|
+
3fqGBiHMkZY2BOGWwCC/wOmJCzLq9q6caPWUs71Zko+h59LaqV93vzDmZaXYfFoQ
|
|
32
|
+
gSVEWpEpCSo560x0mSuLnJYdQQzZ/L6xvxZ1AgMBAAEwDQYJKoZIhvcNAQEFBQAD
|
|
33
|
+
gYEATyK/RlfpohUVimgFkycTF2hyusjctseXoZDCctgg/STMsL8iA0P9YB6k91GC
|
|
34
|
+
kWpwevuiwarD1MfSUV6goPINFkIBvfK+5R9lpHaTqqs615z8T9R5VJgaLcFe3tWd
|
|
35
|
+
7oq3V2q5Nl6MrZfXj2N07qe6/9zfdauxYO26vAEKCvIkbMo=
|
|
36
|
+
</X509Certificate>
|
|
37
|
+
</X509Data>
|
|
38
|
+
</KeyInfo>
|
|
39
|
+
</Signature></Envelope>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "moxml/c14n"
|
|
5
|
+
|
|
6
|
+
RSpec.describe "Moxml::C14n API" do
|
|
7
|
+
let(:ctx) { Moxml.new(:nokogiri) }
|
|
8
|
+
|
|
9
|
+
describe ".canonicalize (algorithm selector)" do
|
|
10
|
+
it "defaults to inclusive C14N 1.0" do
|
|
11
|
+
doc = ctx.parse("<root xmlns:foo='urn:foo'><foo:a/></root>")
|
|
12
|
+
default_result = Moxml::C14n.canonicalize(doc.root)
|
|
13
|
+
incl10_result = Moxml::C14n.canonicalize(doc.root, algorithm: :inclusive10)
|
|
14
|
+
expect(default_result).to eq(incl10_result)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "raises ArgumentError for unknown algorithm" do
|
|
18
|
+
expect do
|
|
19
|
+
Moxml::C14n.canonicalize("<x/>", algorithm: :bogus)
|
|
20
|
+
end.to raise_error(ArgumentError, /unknown C14N algorithm/)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "accepts inclusive_11 algorithm" do
|
|
24
|
+
doc = ctx.parse("<root/>")
|
|
25
|
+
result = Moxml::C14n.canonicalize(doc.root, algorithm: :inclusive11)
|
|
26
|
+
expect(result).to eq("<root></root>")
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "accepts exclusive_10 algorithm" do
|
|
30
|
+
doc = ctx.parse("<root xmlns:foo='urn:foo'><foo:a/></root>")
|
|
31
|
+
result = Moxml::C14n.canonicalize(doc.root, algorithm: :exclusive10)
|
|
32
|
+
# Exclusive renders ns where visibly used (on foo:a), not on root
|
|
33
|
+
expect(result).to include('<foo:a xmlns:foo="urn:foo">')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe ".equivalent?" do
|
|
38
|
+
it "returns true for byte-identical inputs" do
|
|
39
|
+
expect(Moxml::C14n).to be_equivalent("<root>x</root>", "<root>x</root>")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "returns true when only attribute whitespace differs" do
|
|
43
|
+
# Whitespace inside the tag is not significant — both parse identically.
|
|
44
|
+
a = %(<root attr="value"/>)
|
|
45
|
+
b = %(<root attr="value" />)
|
|
46
|
+
expect(Moxml::C14n).to be_equivalent(a, b)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "returns false when text whitespace differs (text IS significant)" do
|
|
50
|
+
a = "<root><child>a</child> </root>"
|
|
51
|
+
b = "<root> <child>a</child></root>"
|
|
52
|
+
expect(Moxml::C14n).not_to be_equivalent(a, b)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "returns true when only attribute order differs" do
|
|
56
|
+
a = %(<root a="1" b="2"/>)
|
|
57
|
+
b = %(<root b="2" a="1"/>)
|
|
58
|
+
expect(Moxml::C14n).to be_equivalent(a, b)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "returns true when only namespace prefix differs" do
|
|
62
|
+
a = "<root xmlns:foo='urn:foo'><foo:a/></root>"
|
|
63
|
+
b = "<root xmlns:bar='urn:foo'><bar:a/></root>"
|
|
64
|
+
# Inclusive canonical form: prefix is part of qname → not equivalent
|
|
65
|
+
expect(Moxml::C14n).not_to be_equivalent(a, b)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "returns false for different content" do
|
|
69
|
+
expect(Moxml::C14n).not_to be_equivalent("<root>a</root>", "<root>b</root>")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "respects algorithm argument" do
|
|
73
|
+
a = "<root xmlns:foo='urn:foo'><foo:a/></root>"
|
|
74
|
+
b = "<root><a xmlns:foo='urn:foo'/></root>"
|
|
75
|
+
# Inclusive: ns on root vs on child → different
|
|
76
|
+
expect(Moxml::C14n).not_to be_equivalent(a, b, algorithm: :inclusive10)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "accepts Moxml::Node inputs" do
|
|
80
|
+
doc1 = ctx.parse("<root/>")
|
|
81
|
+
doc2 = ctx.parse("<root></root>")
|
|
82
|
+
expect(Moxml::C14n).to be_equivalent(doc1.root, doc2.root)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe "convenience methods" do
|
|
87
|
+
it ".canonicalize_inclusive10 matches default" do
|
|
88
|
+
doc = ctx.parse("<root/>")
|
|
89
|
+
expect(Moxml::C14n.canonicalize_inclusive10(doc.root))
|
|
90
|
+
.to eq(Moxml::C14n.canonicalize(doc.root))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it ".canonicalize_inclusive11 produces output" do
|
|
94
|
+
doc = ctx.parse("<root/>")
|
|
95
|
+
expect(Moxml::C14n.canonicalize_inclusive11(doc.root)).to eq("<root></root>")
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it ".canonicalize_exclusive accepts inclusive_namespaces" do
|
|
99
|
+
doc = ctx.parse("<root xmlns:foo='urn:foo'/>")
|
|
100
|
+
result = Moxml::C14n.canonicalize_exclusive(doc.root, inclusive_namespaces: ["foo"])
|
|
101
|
+
# Even though foo is not visibly used, inclusive list forces render
|
|
102
|
+
expect(result).to include('xmlns:foo="urn:foo"')
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
describe "escape helpers (backward compat)" do
|
|
107
|
+
it ".escape_text escapes & < >" do
|
|
108
|
+
expect(Moxml::C14n.escape_text("a & b < c > d"))
|
|
109
|
+
.to eq("a & b < c > d")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it ".escape_attribute escapes quotes and whitespace" do
|
|
113
|
+
expect(Moxml::C14n.escape_attribute(%(a"b\tc\nd)))
|
|
114
|
+
.to eq(%(a"b	c
d))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|