Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / mscorlib / system / security / policy / hashmembershipcondition.cs
blob690034bc65c06827f91625316bbfa83f58eba7f6
1 // ==++==
2 //
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 //
5 // ==--==
6 // <OWNER>Microsoft</OWNER>
7 //
9 //
10 // HashMembershipCondition.cs
12 // Implementation of membership condition for hashes of assemblies.
15 namespace System.Security.Policy {
16 using System.Collections;
17 using System.Runtime.Serialization;
18 using System.Security;
19 using System.Security.Cryptography;
20 using System.Security.Util;
21 using System.Security.Permissions;
22 using System.Threading;
23 using System.Globalization;
24 using System.Diagnostics.Contracts;
26 [Serializable]
27 [System.Runtime.InteropServices.ComVisible(true)]
28 public sealed class HashMembershipCondition : ISerializable, IDeserializationCallback, IMembershipCondition, IReportMatchMembershipCondition {
29 private byte[] m_value = null;
30 private HashAlgorithm m_hashAlg = null;
31 private SecurityElement m_element = null;
33 private object s_InternalSyncObject = null;
34 private object InternalSyncObject {
35 get {
36 if (s_InternalSyncObject == null) {
37 Object o = new Object();
38 Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
40 return s_InternalSyncObject;
44 internal HashMembershipCondition() {}
45 private HashMembershipCondition (SerializationInfo info, StreamingContext context) {
46 m_value = (byte[]) info.GetValue("HashValue", typeof(byte[]));
47 string hashAlgorithm = (string) info.GetValue("HashAlgorithm", typeof(string));
48 if (hashAlgorithm != null)
49 m_hashAlg = HashAlgorithm.Create(hashAlgorithm);
50 else
51 m_hashAlg = new SHA1Managed();
54 public HashMembershipCondition(HashAlgorithm hashAlg, byte[] value) {
55 if (value == null)
56 throw new ArgumentNullException("value");
57 if (hashAlg == null)
58 throw new ArgumentNullException("hashAlg");
59 Contract.EndContractBlock();
61 m_value = new byte[value.Length];
62 Array.Copy(value, m_value, value.Length);
63 m_hashAlg = hashAlg;
66 /// <internalonly/>
67 [System.Security.SecurityCritical]
68 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
70 info.AddValue("HashValue", this.HashValue);
71 info.AddValue("HashAlgorithm", this.HashAlgorithm.ToString());
74 /// <internalonly/>
75 void IDeserializationCallback.OnDeserialization (Object sender) {}
77 public HashAlgorithm HashAlgorithm {
78 set {
79 if (value == null)
80 throw new ArgumentNullException("HashAlgorithm");
81 Contract.EndContractBlock();
82 m_hashAlg = value;
84 get {
85 if (m_hashAlg == null && m_element != null)
86 ParseHashAlgorithm();
87 return m_hashAlg;
91 public byte[] HashValue {
92 set {
93 if (value == null)
94 throw new ArgumentNullException("value");
95 Contract.EndContractBlock();
96 m_value = new byte[value.Length];
97 Array.Copy(value, m_value, value.Length);
99 get {
100 if (m_value == null && m_element != null)
101 ParseHashValue();
102 if (m_value == null)
103 return null;
105 byte[] value = new byte[m_value.Length];
106 Array.Copy(m_value, value, m_value.Length);
107 return value;
111 public bool Check(Evidence evidence) {
112 object usedEvidence = null;
113 return (this as IReportMatchMembershipCondition).Check(evidence, out usedEvidence);
116 bool IReportMatchMembershipCondition.Check(Evidence evidence, out object usedEvidence) {
117 usedEvidence = null;
119 if (evidence == null)
120 return false;
122 Hash hash = evidence.GetHostEvidence<Hash>();
123 if (hash != null) {
124 if (m_value == null && m_element != null)
125 ParseHashValue();
127 if (m_hashAlg == null && m_element != null)
128 ParseHashAlgorithm();
130 byte[] asmHash = null;
131 lock (InternalSyncObject) {
132 asmHash = hash.GenerateHash(m_hashAlg);
135 if (asmHash != null && CompareArrays(asmHash, m_value)) {
136 usedEvidence = hash;
137 return true;
141 return false;
144 public IMembershipCondition Copy() {
145 if (m_value == null && m_element != null)
146 ParseHashValue();
148 if (m_hashAlg == null && m_element != null)
149 ParseHashAlgorithm();
151 return new HashMembershipCondition(m_hashAlg, m_value);
154 public SecurityElement ToXml() {
155 return ToXml(null);
158 public void FromXml(SecurityElement e) {
159 FromXml(e, null);
162 public SecurityElement ToXml(PolicyLevel level) {
163 if (m_value == null && m_element != null)
164 ParseHashValue();
166 if (m_hashAlg == null && m_element != null)
167 ParseHashAlgorithm();
169 SecurityElement root = new SecurityElement("IMembershipCondition");
170 XMLUtil.AddClassAttribute(root, this.GetType(), "System.Security.Policy.HashMembershipCondition");
171 // If you hit this assert then most likely you are trying to change the name of this class.
172 // This is ok as long as you change the hard coded string above and change the assert below.
173 Contract.Assert(this.GetType().FullName.Equals("System.Security.Policy.HashMembershipCondition"), "Class name changed!");
175 root.AddAttribute("version", "1");
176 if (m_value != null)
177 root.AddAttribute(s_tagHashValue, Hex.EncodeHexString(HashValue));
178 if (m_hashAlg != null)
179 root.AddAttribute(s_tagHashAlgorithm, HashAlgorithm.GetType().FullName);
180 return root;
183 public void FromXml(SecurityElement e, PolicyLevel level) {
184 if (e == null)
185 throw new ArgumentNullException("e");
187 if (!e.Tag.Equals("IMembershipCondition"))
188 throw new ArgumentException(Environment.GetResourceString("Argument_MembershipConditionElement"));
189 Contract.EndContractBlock();
191 lock (InternalSyncObject) {
192 m_element = e;
193 m_value = null;
194 m_hashAlg = null;
198 public override bool Equals(Object o) {
199 HashMembershipCondition that = (o as HashMembershipCondition);
200 if (that != null) {
201 if (this.m_hashAlg == null && this.m_element != null)
202 this.ParseHashAlgorithm();
203 if (that.m_hashAlg == null && that.m_element != null)
204 that.ParseHashAlgorithm();
206 if (this.m_hashAlg != null && that.m_hashAlg != null &&
207 this.m_hashAlg.GetType() == that.m_hashAlg.GetType()) {
208 if (this.m_value == null && this.m_element != null)
209 this.ParseHashValue();
210 if (that.m_value == null && that.m_element != null)
211 that.ParseHashValue();
213 if (this.m_value.Length != that.m_value.Length)
214 return false;
216 for (int i = 0; i < m_value.Length; i++) {
217 if (this.m_value[i] != that.m_value[i])
218 return false;
220 return true;
223 return false;
226 public override int GetHashCode() {
227 if (this.m_hashAlg == null && this.m_element != null)
228 this.ParseHashAlgorithm();
230 int accumulator = this.m_hashAlg != null ? this.m_hashAlg.GetType().GetHashCode() : 0;
231 if (this.m_value == null && this.m_element != null)
232 this.ParseHashValue();
234 accumulator = accumulator ^ GetByteArrayHashCode(this.m_value);
235 return accumulator;
238 public override string ToString() {
239 if (m_hashAlg == null)
240 ParseHashAlgorithm();
242 return Environment.GetResourceString("Hash_ToString", m_hashAlg.GetType().AssemblyQualifiedName, Hex.EncodeHexString(HashValue));
245 private const string s_tagHashValue = "HashValue";
246 private const string s_tagHashAlgorithm = "HashAlgorithm";
248 private void ParseHashValue() {
249 lock (InternalSyncObject) {
250 if (m_element == null)
251 return;
253 string elHash = m_element.Attribute(s_tagHashValue);
254 if (elHash != null)
255 m_value = Hex.DecodeHexString(elHash);
256 else
257 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidXMLElement", s_tagHashValue, this.GetType().FullName));
259 if (m_value != null && m_hashAlg != null) {
260 m_element = null;
265 private void ParseHashAlgorithm() {
266 lock (InternalSyncObject) {
267 if (m_element == null)
268 return;
270 string elHashAlg = m_element.Attribute(s_tagHashAlgorithm);
271 if (elHashAlg != null)
272 m_hashAlg = HashAlgorithm.Create(elHashAlg);
273 else
274 m_hashAlg = new SHA1Managed();
276 if (m_value != null && m_hashAlg != null)
277 m_element = null;
281 private static bool CompareArrays(byte[] first, byte[] second) {
282 if (first.Length != second.Length)
283 return false;
285 int count = first.Length;
286 for (int i = 0; i < count; ++i) {
287 if (first[i] != second[i])
288 return false;
291 return true;
294 private static int GetByteArrayHashCode(byte[] baData) {
295 if (baData == null)
296 return 0;
298 int accumulator = 0;
299 for (int i = 0; i < baData.Length; ++i) {
300 accumulator = (accumulator << 8) ^ (int)baData[i] ^ (accumulator >> 24);
302 return accumulator;