Merge pull request #5198 from BrzVlad/fix-binprot-stats
[mono.git] / mcs / class / System / Test / System.Security.Cryptography.X509Certificates / X509ChainTest.cs
1 //
2 // X509ChainTest.cs - NUnit tests for X509Chain
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2006 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30
31 using NUnit.Framework;
32
33 using System;
34 using System.Security.Cryptography;
35 using System.Security.Cryptography.X509Certificates;
36 using System.Text;
37
38 namespace MonoTests.System.Security.Cryptography.X509Certificates {
39
40         [TestFixture]
41         public class X509ChainTest {
42
43                 //private X509Certificate2Collection empty;
44                 private X509Certificate2Collection collection;
45
46                 private X509Certificate2 cert_empty;
47                 private X509Certificate2 cert1;
48                 private X509Certificate2 cert2;
49                 private X509Certificate2 cert3;
50
51                 [TestFixtureSetUp]
52                 public void FixtureSetUp ()
53                 {
54                         cert_empty = new X509Certificate2 ();
55                         cert1 = new X509Certificate2 (X509Certificate2Test.farscape_pfx, "farscape", X509KeyStorageFlags.Exportable);
56                         cert2 = new X509Certificate2 (Encoding.ASCII.GetBytes (X509Certificate2Test.base64_cert));
57
58                         //empty = new X509Certificate2Collection ();
59                         collection = new X509Certificate2Collection ();
60                         collection.Add (cert1);
61                         collection.Add (cert2);
62                 }
63
64                 // this method avoid having a dependance on the order of status
65                 public void CheckChainStatus (X509ChainStatusFlags expected, X509ChainStatus[] status, string msg)
66                 {
67                         if ((expected == X509ChainStatusFlags.NoError) && (status.Length == 0))
68                                 return;
69
70                         X509ChainStatusFlags actual = X509ChainStatusFlags.NoError;
71                         foreach (X509ChainStatus s in status) {
72                                 actual |= s.Status;
73                         }
74                         Assert.AreEqual (expected, actual, msg);
75                 }
76
77                 private void CheckDefaultChain (X509Chain c)
78                 {
79                         Assert.AreEqual (0, c.ChainElements.Count, "ChainElements");
80                         Assert.IsNotNull (c.ChainPolicy, "ChainPolicy");
81                         Assert.AreEqual (0, c.ChainStatus.Length, "ChainStatus");
82                         // check default policy
83                         CheckDefaultPolicy (c.ChainPolicy);
84                 }
85
86                 private void CheckDefaultPolicy (X509ChainPolicy p)
87                 {
88                         Assert.AreEqual (0, p.ApplicationPolicy.Count, "ApplicationPolicy");
89                         Assert.AreEqual (0, p.CertificatePolicy.Count, "CertificatePolicy");
90                         Assert.AreEqual (0, p.ExtraStore.Count, "ExtraStore");
91                         Assert.AreEqual (X509RevocationFlag.ExcludeRoot, p.RevocationFlag, "RevocationFlag");
92                         Assert.AreEqual (X509RevocationMode.Online, p.RevocationMode, "RevocationMode");
93                         Assert.AreEqual (0, p.UrlRetrievalTimeout.Ticks, "UrlRetrievalTimeout");
94                         Assert.AreEqual (X509VerificationFlags.NoFlag, p.VerificationFlags, "VerificationFlags");
95                         Assert.IsTrue (p.VerificationTime <= DateTime.Now, "VerificationTime");
96                 }
97
98                 [Test]
99                 public void ConstructorEmpty () 
100                 {
101                         X509Chain c = new X509Chain ();
102                         CheckDefaultChain (c);
103                 }
104
105                 [Test]
106                 public void ConstructorMachineContextFalse () 
107                 {
108                         X509Chain c = new X509Chain (false);
109                         CheckDefaultChain (c);
110                 }
111
112                 [Test]
113                 public void ConstructorMachineContextTrue () 
114                 {
115                         X509Chain c = new X509Chain (true);
116                         CheckDefaultChain (c);
117                 }
118
119                 [Test]
120                 [ExpectedException (typeof (ArgumentException))]
121                 public void Build_Null ()
122                 {
123                         X509Chain c = new X509Chain ();
124                         c.Build (null);
125                 }
126
127                 [Test]
128                 [ExpectedException (typeof (ArgumentException))]
129                 public void Build_Empty ()
130                 {
131                         X509Chain c = new X509Chain ();
132                         c.Build (cert_empty);
133                 }
134
135                 [Test]
136                 public void Build_Twice_SameCertificate ()
137                 {
138                         X509Chain c = new X509Chain ();
139                         Assert.IsFalse (c.Build (cert1), "Build-1a");
140                         Assert.IsFalse (c.Build (cert1), "Build-2a");
141                 }
142
143                 [Test]
144                 public void Build_Twice_DifferentCertificate ()
145                 {
146                         X509Chain c = new X509Chain ();
147                         Assert.IsFalse (c.Build (cert1), "Build-1");
148                         Assert.IsFalse (c.Build (cert2), "Build-2");
149                 }
150
151                 [Test]
152                 public void Build_Twice_WithReset ()
153                 {
154                         X509Chain c = new X509Chain ();
155                         Assert.IsFalse (c.Build (cert1), "Build-1");
156                         c.Reset ();
157                         Assert.IsFalse (c.Build (cert2), "Build-2");
158                         c.Reset ();
159                         CheckDefaultChain (c);
160                 }
161
162                 private void CheckCert1 (X509Chain c)
163                 {
164                         X509VerificationFlags success_mask;
165
166                         switch (c.ChainPolicy.RevocationMode) {
167                         case X509RevocationMode.Offline:
168                         case X509RevocationMode.Online:
169                                 success_mask = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.AllowUnknownCertificateAuthority;
170                                 break;
171                         case X509RevocationMode.NoCheck:
172                         default:
173                                 success_mask = X509VerificationFlags.AllowUnknownCertificateAuthority;
174                                 break;
175                         }
176
177                         Assert.AreEqual (((c.ChainPolicy.VerificationFlags & success_mask) == success_mask), c.Build (cert1), "Build");
178                         Assert.AreEqual (1, c.ChainElements.Count, "ChainElements");
179                         Assert.AreEqual (String.Empty, c.ChainElements[0].Information, "ChainElements[0].Information");
180                         Assert.AreEqual (cert1, c.ChainElements[0].Certificate, "ChainElements[0].Certificate");
181
182                         switch (c.ChainPolicy.RevocationMode) {
183                         case X509RevocationMode.Offline:
184                         case X509RevocationMode.Online:
185                                 CheckChainStatus (X509ChainStatusFlags.PartialChain | X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation, c.ChainStatus, "c.ChainStatus");
186                                 CheckChainStatus (X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation, c.ChainElements[0].ChainElementStatus, "c.ChainElements[0].ChainElementStatus");
187                                 break;
188                         case X509RevocationMode.NoCheck:
189                                 CheckChainStatus (X509ChainStatusFlags.PartialChain, c.ChainStatus, "c.ChainStatus");
190                                 CheckChainStatus (X509ChainStatusFlags.NoError, c.ChainElements[0].ChainElementStatus, "c.ChainElements[0].ChainElementStatus");
191                                 break;
192                         }
193                 }
194
195                 [Test]
196                 public void Build_Cert1_X509RevocationMode_Offline ()
197                 {
198                         X509Chain c = new X509Chain ();
199                         c.ChainPolicy.RevocationMode = X509RevocationMode.Offline; // default
200                         foreach (X509VerificationFlags vf in Enum.GetValues (typeof (X509VerificationFlags))) {
201                                 c.ChainPolicy.VerificationFlags = vf;
202                                 CheckCert1 (c);
203                                 c.Reset ();
204                         }
205                 }
206
207                 [Test]
208                 public void Build_Cert1_X509RevocationMode_Online ()
209                 {
210                         X509Chain c = new X509Chain ();
211                         c.ChainPolicy.RevocationMode = X509RevocationMode.Online;
212                         foreach (X509VerificationFlags vf in Enum.GetValues (typeof (X509VerificationFlags))) {
213                                 c.ChainPolicy.VerificationFlags = vf;
214                                 CheckCert1 (c);
215                                 c.Reset ();
216                         }
217                 }
218
219                 [Test]
220                 public void Build_Cert1_X509RevocationMode_NoCheck ()
221                 {
222                         X509Chain c = new X509Chain ();
223                         c.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
224                         foreach (X509VerificationFlags vf in Enum.GetValues (typeof (X509VerificationFlags))) {
225                                 c.ChainPolicy.VerificationFlags = vf;
226                                 CheckCert1 (c);
227                                 c.Reset ();
228                         }
229                 }
230
231                 private void CheckCert2 (X509Chain c)
232                 {
233                         X509VerificationFlags success_mask = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.AllowUnknownCertificateAuthority;
234                         Assert.AreEqual (((c.ChainPolicy.VerificationFlags & success_mask) == success_mask), c.Build (cert2), "Build");
235                         Assert.AreEqual (1, c.ChainElements.Count, "ChainElements");
236                         Assert.AreEqual (String.Empty, c.ChainElements[0].Information, "ChainElements[0].Information");
237                         Assert.AreEqual (cert2, c.ChainElements[0].Certificate, "ChainElements[0].Certificate");
238
239                         CheckChainStatus (X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.NotTimeValid, c.ChainStatus, "c.ChainStatus");
240                         CheckChainStatus (X509ChainStatusFlags.UntrustedRoot | X509ChainStatusFlags.NotTimeValid, c.ChainElements[0].ChainElementStatus, "c.ChainElements[0].ChainElementStatus");
241                 }
242
243                 [Test]
244                 public void Build_Cert2 ()
245                 {
246                         X509Chain c = new X509Chain ();
247                         foreach (X509VerificationFlags vf in Enum.GetValues (typeof (X509VerificationFlags))) {
248                                 c.ChainPolicy.VerificationFlags = vf;
249                                 CheckCert2 (c);
250                                 c.Reset ();
251                         }
252                         // minimal criteria for success
253                         c.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreNotTimeValid | X509VerificationFlags.AllowUnknownCertificateAuthority;
254                         CheckCert2 (c);
255                 }
256
257                 [Test]
258                 public void Reset ()
259                 {
260                         X509Chain c = new X509Chain ();
261                         c.ChainPolicy.ApplicationPolicy.Add (new Oid ("1.2.3"));
262                         c.ChainPolicy.CertificatePolicy.Add (new Oid ("1.2.4"));
263                         c.ChainPolicy.ExtraStore.AddRange (collection);
264                         c.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
265                         c.ChainPolicy.RevocationMode = X509RevocationMode.Offline;
266                         c.ChainPolicy.UrlRetrievalTimeout = new TimeSpan (1000);
267                         c.ChainPolicy.VerificationFlags = X509VerificationFlags.IgnoreWrongUsage;
268                         c.ChainPolicy.VerificationTime = DateTime.MinValue;
269                         c.Reset ();
270                         // resetting the chain doesn't reset the policy
271                         Assert.AreEqual (1, c.ChainPolicy.ApplicationPolicy.Count, "ApplicationPolicy");
272                         Assert.AreEqual (1, c.ChainPolicy.CertificatePolicy.Count, "CertificatePolicy");
273                         Assert.AreEqual (2, c.ChainPolicy.ExtraStore.Count, "ExtraStore");
274                         Assert.AreEqual (X509RevocationFlag.EntireChain, c.ChainPolicy.RevocationFlag, "RevocationFlag");
275                         Assert.AreEqual (X509RevocationMode.Offline, c.ChainPolicy.RevocationMode, "RevocationMode");
276                         Assert.AreEqual (1000, c.ChainPolicy.UrlRetrievalTimeout.Ticks, "UrlRetrievalTimeout");
277                         Assert.AreEqual (X509VerificationFlags.IgnoreWrongUsage, c.ChainPolicy.VerificationFlags, "VerificationFlags");
278                         Assert.AreEqual (DateTime.MinValue, c.ChainPolicy.VerificationTime, "VerificationTime");
279                 }
280
281                 [Test]
282                 public void StaticCreation () 
283                 {
284                         X509Chain c = X509Chain.Create ();
285                         CheckDefaultChain (c);
286                 }
287
288                 [Test]
289                 public void CreateViaCryptoConfig ()
290                 {
291                         // X509Chain can be changed using CryptoConfig
292                         Assert.AreEqual (typeof (X509Chain), CryptoConfig.CreateFromName ("X509Chain").GetType (), "X509Chain");
293                         Assert.IsNull (CryptoConfig.CreateFromName ("System.Security.Cryptography.X509Certificates.X509Chain"), "System.Security.Cryptography.X509Certificates.X509Chain");
294                 }
295         }
296 }
297