-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
XmlDsigEnvelopedSignatureTransform.cs
196 lines (175 loc) · 7.5 KB
/
XmlDsigEnvelopedSignatureTransform.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.IO;
using System.Xml;
namespace System.Security.Cryptography.Xml
{
public class XmlDsigEnvelopedSignatureTransform : Transform
{
private readonly Type[] _inputTypes = { typeof(Stream), typeof(XmlNodeList), typeof(XmlDocument) };
private readonly Type[] _outputTypes = { typeof(XmlNodeList), typeof(XmlDocument) };
private XmlNodeList? _inputNodeList;
private readonly bool _includeComments;
private XmlNamespaceManager? _nsm;
private XmlDocument? _containingDocument;
private int _signaturePosition;
internal int SignaturePosition
{
set { _signaturePosition = value; }
}
public XmlDsigEnvelopedSignatureTransform()
{
Algorithm = SignedXml.XmlDsigEnvelopedSignatureTransformUrl;
}
/// <internalonly/>
public XmlDsigEnvelopedSignatureTransform(bool includeComments)
{
_includeComments = includeComments;
Algorithm = SignedXml.XmlDsigEnvelopedSignatureTransformUrl;
}
public override Type[] InputTypes
{
get { return _inputTypes; }
}
public override Type[] OutputTypes
{
get { return _outputTypes; }
}
// An enveloped signature has no inner XML elements
public override void LoadInnerXml(XmlNodeList nodeList)
{
if (nodeList != null && nodeList.Count > 0)
throw new CryptographicException(SR.Cryptography_Xml_UnknownTransform);
}
// An enveloped signature has no inner XML elements
protected override XmlNodeList? GetInnerXml()
{
return null;
}
public override void LoadInput(object obj)
{
if (obj is Stream)
{
LoadStreamInput((Stream)obj);
return;
}
if (obj is XmlNodeList)
{
LoadXmlNodeListInput((XmlNodeList)obj);
return;
}
if (obj is XmlDocument)
{
LoadXmlDocumentInput((XmlDocument)obj);
return;
}
}
private void LoadStreamInput(Stream stream)
{
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
XmlResolver resolver = ResolverSet ? _xmlResolver : XmlResolverHelper.GetThrowingResolver();
XmlReader xmlReader = Utils.PreProcessStreamInput(stream, resolver, BaseURI!);
doc.Load(xmlReader);
_containingDocument = doc;
if (_containingDocument == null)
throw new CryptographicException(SR.Cryptography_Xml_EnvelopedSignatureRequiresContext);
_nsm = new XmlNamespaceManager(_containingDocument.NameTable);
_nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
}
private void LoadXmlNodeListInput(XmlNodeList nodeList)
{
if (nodeList is null)
{
throw new ArgumentNullException(nameof(nodeList));
}
_containingDocument = Utils.GetOwnerDocument(nodeList);
if (_containingDocument == null)
throw new CryptographicException(SR.Cryptography_Xml_EnvelopedSignatureRequiresContext);
_nsm = new XmlNamespaceManager(_containingDocument.NameTable);
_nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
_inputNodeList = nodeList;
}
private void LoadXmlDocumentInput(XmlDocument doc)
{
if (doc is null)
{
throw new ArgumentNullException(nameof(doc));
}
_containingDocument = doc;
_nsm = new XmlNamespaceManager(_containingDocument.NameTable);
_nsm.AddNamespace("dsig", SignedXml.XmlDsigNamespaceUrl);
}
public override object GetOutput()
{
if (_containingDocument == null)
throw new CryptographicException(SR.Cryptography_Xml_EnvelopedSignatureRequiresContext);
// If we have received an XmlNodeList as input
if (_inputNodeList != null)
{
// If the position has not been set, then we don't want to remove any signature tags
if (_signaturePosition == 0) return _inputNodeList;
XmlNodeList? signatureList = _containingDocument.SelectNodes("//dsig:Signature", _nsm!);
if (signatureList == null) return _inputNodeList;
CanonicalXmlNodeList resultNodeList = new CanonicalXmlNodeList();
foreach (XmlNode? node in _inputNodeList)
{
if (node == null) continue;
// keep namespaces
if (Utils.IsXmlNamespaceNode(node) || Utils.IsNamespaceNode(node))
{
resultNodeList.Add(node);
}
else
{
// SelectSingleNode throws an exception for xmldecl PI for example, so we will just ignore those exceptions
try
{
// Find the nearest signature ancestor tag
XmlNode result = node.SelectSingleNode("ancestor-or-self::dsig:Signature[1]", _nsm!)!;
int position = 0;
foreach (XmlNode node1 in signatureList)
{
position++;
if (node1 == result) break;
}
if (result == null || position != _signaturePosition)
{
resultNodeList.Add(node);
}
}
catch { }
}
}
return resultNodeList;
}
// Else we have received either a stream or a document as input
else
{
XmlNodeList? signatureList = _containingDocument.SelectNodes("//dsig:Signature", _nsm!);
if (signatureList == null) return _containingDocument;
if (signatureList.Count < _signaturePosition || _signaturePosition <= 0) return _containingDocument;
// Remove the signature node with all its children nodes
signatureList[_signaturePosition - 1]!.ParentNode!.RemoveChild(signatureList[_signaturePosition - 1]!);
return _containingDocument;
}
}
public override object GetOutput(Type type)
{
if (type == typeof(XmlNodeList) || type.IsSubclassOf(typeof(XmlNodeList)))
{
_inputNodeList ??= Utils.AllDescendantNodes(_containingDocument!, true);
return (XmlNodeList)GetOutput();
}
else if (type == typeof(XmlDocument) || type.IsSubclassOf(typeof(XmlDocument)))
{
if (_inputNodeList != null) throw new ArgumentException(SR.Cryptography_Xml_TransformIncorrectInputType, nameof(type));
return (XmlDocument)GetOutput();
}
else
{
throw new ArgumentException(SR.Cryptography_Xml_TransformIncorrectInputType, nameof(type));
}
}
}
}