New test.
[mono.git] / mcs / class / Mono.Security / Test / Mono.Security.Authenticode / PrivateKeyTest.cs
1 //
2 // PrivateKeyTest.cs - NUnit Test Cases for Private Key File
3 //
4 // Author:
5 //      Sebastien Pouliot (sebastien@ximian.com)
6 //      Bernie Solomon
7 //
8 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) 2004 Novell (http://www.novell.com)
10 //
11
12 using System;
13 using System.IO;
14 using System.Security.Cryptography;
15 using System.Text;
16
17 using Mono.Security.Authenticode;
18 using NUnit.Framework;
19
20 namespace MonoTests.Mono.Security.Authenticode {
21
22         // partial copy of /mcs/class/Mono.Security/Mono.Security/BitConverterLE.cs
23         internal sealed class BitConverterLE {
24
25                 private BitConverterLE ()
26                 {
27                 }
28
29                 unsafe private static byte[] GetUIntBytes (byte *bytes)
30                 {
31                         if (BitConverter.IsLittleEndian)
32                                 return new byte [] { bytes [0], bytes [1], bytes [2], bytes [3] };
33                         else
34                                 return new byte [] { bytes [3], bytes [2], bytes [1], bytes [0] };
35                 }
36
37                 unsafe internal static byte[] GetBytes (int value)
38                 {
39                         return GetUIntBytes ((byte *) &value);
40                 }
41
42                 unsafe private static void UIntFromBytes (byte *dst, byte[] src, int startIndex)
43                 {
44                         if (BitConverter.IsLittleEndian) {
45                                 dst [0] = src [startIndex];
46                                 dst [1] = src [startIndex + 1];
47                                 dst [2] = src [startIndex + 2];
48                                 dst [3] = src [startIndex + 3];
49                         } else {
50                                 dst [0] = src [startIndex + 3];
51                                 dst [1] = src [startIndex + 2];
52                                 dst [2] = src [startIndex + 1];
53                                 dst [3] = src [startIndex];
54                         }
55                 }
56
57                 unsafe internal static int ToInt32 (byte[] value, int startIndex)
58                 {
59                         int ret;
60
61                         UIntFromBytes ((byte *) &ret, value, startIndex);
62
63                         return ret;
64                 }
65         }
66
67 // HOWTO create a PVK file (on Windows using MS tools)
68 // makecert -n "CN=PVK1" -sv 1.pvk 1.cer
69
70 [TestFixture]
71 public class PrivateKeyTest : Assertion {
72
73         // because most crypto stuff works with byte[] buffers
74         static public void AssertEquals (string msg, byte[] array1, byte[] array2) 
75         {
76                 if ((array1 == null) && (array2 == null))
77                         return;
78                 if (array1 == null)
79                         Fail (msg + " -> First array is NULL");
80                 if (array2 == null)
81                         Fail (msg + " -> Second array is NULL");
82
83                 bool a = (array1.Length == array2.Length);
84                 if (a) {
85                         for (int i = 0; i < array1.Length; i++) {
86                                 if (array1 [i] != array2 [i]) {
87                                         a = false;
88                                         break;
89                                 }
90                         }
91                 }
92                 if (array1.Length > 0) {
93                         msg += " -> Expected " + BitConverter.ToString (array1, 0);
94                         msg += " is different than " + BitConverter.ToString (array2, 0);
95                 }
96                 Assert (msg, a);
97         }
98
99         private const string testfile = "test.pvk";
100
101         [TearDown]
102         public void TearDown () 
103         {
104                 File.Delete (testfile);
105         }
106
107         private void WriteBuffer (byte[] buffer) 
108         {
109                 FileStream fs = File.Create (testfile);
110                 fs.Write (buffer, 0, buffer.Length);
111                 fs.Close ();
112         }
113
114         static byte[] nopwd = { 
115         0x1E, 0xF1, 0xB5, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
116         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 
117         0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 
118         0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xDB, 0x27, 0x34, 0xCB, 
119         0x3D, 0x27, 0xA0, 0x4F, 0x50, 0x68, 0xC7, 0x95, 0x4B, 0x7B, 0x69, 0xD1, 
120         0xFD, 0x30, 0x58, 0x72, 0x6B, 0xFF, 0x77, 0x64, 0x96, 0x35, 0x72, 0x36, 
121         0x98, 0xCE, 0x56, 0xDD, 0x94, 0x43, 0x7C, 0x0D, 0x61, 0x5C, 0x3A, 0xD6, 
122         0x1E, 0xD1, 0x89, 0x6C, 0xD5, 0x9B, 0x3E, 0xD3, 0x60, 0x3E, 0x28, 0x3F, 
123         0xC6, 0x51, 0x35, 0x0D, 0x4F, 0x7E, 0x79, 0xE6, 0xAE, 0xE4, 0xC8, 0xE9, 
124         0xA9, 0x14, 0x6E, 0xD2, 0xBD, 0x42, 0xB2, 0x14, 0x82, 0xEE, 0x26, 0x8F, 
125         0x21, 0x33, 0x1A, 0xD5, 0xD7, 0x6D, 0x90, 0xED, 0xC1, 0xA4, 0x1C, 0x84, 
126         0x3F, 0xA3, 0x8A, 0xFB, 0x33, 0x30, 0x32, 0xF6, 0xE3, 0xE6, 0xC8, 0x81, 
127         0x54, 0x88, 0x1A, 0x92, 0xF0, 0xBA, 0xB8, 0x4F, 0x52, 0x8D, 0xBD, 0x04, 
128         0x47, 0xBC, 0x55, 0xBC, 0xD0, 0x3D, 0x2C, 0x7F, 0x4F, 0xAB, 0x99, 0xDC, 
129         0xFB, 0x2D, 0x18, 0xF3, 0x99, 0x77, 0x10, 0x82, 0x48, 0xF3, 0xDE, 0x36, 
130         0xD7, 0x62, 0xA9, 0xCB, 0x58, 0x01, 0x97, 0x79, 0x66, 0x0D, 0x01, 0x1F, 
131         0xCC, 0x0B, 0xAB, 0x02, 0xA9, 0xE3, 0xF5, 0x85, 0xA8, 0x52, 0xBC, 0x10, 
132         0xD7, 0x90, 0x60, 0x60, 0x50, 0xB1, 0x08, 0x01, 0x85, 0x52, 0xAC, 0x05, 
133         0xF1, 0xCE, 0xF9, 0xE7, 0xBE, 0xDE, 0x46, 0x64, 0x40, 0xE5, 0x07, 0x82, 
134         0x20, 0xDD, 0x48, 0xF1, 0xE1, 0x85, 0x29, 0x8C, 0xFE, 0x57, 0x7C, 0x65, 
135         0xF5, 0x5C, 0x51, 0x9F, 0x63, 0xDE, 0xFC, 0x9C, 0xF9, 0x3F, 0x3D, 0xF2, 
136         0xDC, 0x9F, 0x65, 0x27, 0xEC, 0x50, 0x54, 0xB9, 0xCE, 0xF2, 0xC3, 0x10, 
137         0x93, 0x8B, 0xBE, 0x6A, 0xC1, 0x35, 0x19, 0xBB, 0x66, 0xA5, 0x5E, 0xEA, 
138         0x91, 0x1D, 0xFB, 0x26, 0xF8, 0x0F, 0x5C, 0x13, 0x73, 0xCC, 0x9A, 0x68, 
139         0x4C, 0x08, 0x9C, 0x02, 0xE5, 0xD5, 0x91, 0x37, 0x13, 0x68, 0x3D, 0xFC, 
140         0x3E, 0xA7, 0x43, 0x94, 0xBC, 0xFC, 0x4F, 0xB1, 0x8E, 0xC5, 0x5F, 0x24, 
141         0x9A, 0x6C, 0xDB, 0xC2, 0x49, 0x91, 0xEC, 0x2B, 0xB9, 0x3D, 0x2B, 0x96, 
142         0xA3, 0x60, 0xE3, 0xA8, 0x8C, 0x28, 0xB7, 0x53 };
143
144         [Test]
145         public void MSNoPassword ()
146         {
147                 WriteBuffer (nopwd);
148                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile);
149                 AssertNotNull ("msnopwd.RSA", pvk.RSA);
150                 Assert ("msnopwd.Encrypted", !pvk.Encrypted);
151                 Assert ("msnopwd.Weak", pvk.Weak);
152                 AssertEquals ("msnopwd.KeyType", 2, pvk.KeyType);
153         }
154
155         // this will convert a PVK file without a password to a PVK file
156         // with a password (weak)
157         [Test]
158         public void ConvertToPasswordWeak () 
159         {
160                 WriteBuffer (nopwd);
161                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile);
162                 string rsa1 = pvk.RSA.ToXmlString (true);
163                 pvk.Save (testfile, "password");
164                 pvk = PrivateKey.CreateFromFile (testfile, "password");
165                 AssertNotNull ("topwd.RSA", pvk.RSA);
166                 string rsa2 = pvk.RSA.ToXmlString (true);
167                 AssertEquals ("topwd.RSA identical", rsa1, rsa2);
168                 Assert ("topwd.Encrypted", pvk.Encrypted);
169                 Assert ("topwd.Weak", pvk.Weak);
170         }
171
172         // this will convert a PVK file without a password to a PVK file
173         // with a password (strong)
174         [Test]
175         public void ConvertToPasswordStrong () 
176         {
177                 WriteBuffer (nopwd);
178                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile);
179                 string rsa1 = pvk.RSA.ToXmlString (true);
180                 pvk.Weak = false; // we want strong crypto
181                 pvk.Save (testfile, "password");
182                 pvk = PrivateKey.CreateFromFile (testfile, "password");
183                 AssertNotNull ("topwd.RSA", pvk.RSA);
184                 string rsa2 = pvk.RSA.ToXmlString (true);
185                 AssertEquals ("topwd.RSA identical", rsa1, rsa2);
186                 Assert ("topwd.Encrypted", pvk.Encrypted);
187                 Assert ("topwd.Weak", !pvk.Weak);
188         }
189
190         static byte[] pwd = { 
191         0x1E, 0xF1, 0xB5, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 
192         0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 
193         0x37, 0x53, 0x7C, 0x99, 0x01, 0xB5, 0x50, 0xF3, 0x79, 0x6E, 0xDE, 0xD5, 
194         0x8A, 0x1B, 0xED, 0x05, 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 
195         0x33, 0x98, 0xE8, 0x81, 0xA2, 0x9A, 0xEB, 0x36, 0xEF, 0x1B, 0x52, 0xFD, 
196         0xC3, 0x9B, 0xB7, 0x32, 0x02, 0xC0, 0x9F, 0xE0, 0x6A, 0x50, 0x81, 0x61, 
197         0x37, 0xBE, 0xEC, 0x1B, 0xC3, 0x34, 0x7B, 0x03, 0x0B, 0xC8, 0x31, 0x7B, 
198         0x0D, 0xA6, 0x7A, 0x05, 0xEA, 0xD1, 0xCA, 0x9A, 0xF3, 0x71, 0x84, 0x77, 
199         0x9E, 0x6F, 0xD1, 0xD0, 0xA0, 0x62, 0xFF, 0x3D, 0x24, 0x31, 0x01, 0xD7, 
200         0x02, 0x38, 0x11, 0xB6, 0x5E, 0x4A, 0xCC, 0x33, 0xF0, 0xEB, 0x0B, 0x38, 
201         0x51, 0x27, 0xCF, 0xAD, 0x20, 0x20, 0x9A, 0x80, 0x80, 0x37, 0xBE, 0x4C, 
202         0xBC, 0xA4, 0xC8, 0xE1, 0x5B, 0x57, 0x02, 0xC9, 0x04, 0x53, 0x82, 0x6E, 
203         0x0B, 0x06, 0x94, 0xCF, 0xC2, 0xEF, 0x1A, 0x6C, 0xC8, 0x78, 0x41, 0xB1, 
204         0x63, 0xBD, 0x52, 0x1C, 0x05, 0x2C, 0x97, 0x83, 0x10, 0xD0, 0xFE, 0x22, 
205         0x2F, 0x29, 0xAF, 0xC0, 0xCA, 0xC7, 0x96, 0x0A, 0x9A, 0xC8, 0x69, 0x58, 
206         0xBF, 0xA9, 0xDD, 0x75, 0xE4, 0xAB, 0xC8, 0xFE, 0xF5, 0xFE, 0xC5, 0x18, 
207         0x2B, 0x93, 0xC0, 0x67, 0xFF, 0xDC, 0xE3, 0xAF, 0xAC, 0x5F, 0x7E, 0x5F, 
208         0x0D, 0xEA, 0x41, 0xEB, 0x57, 0x1A, 0x4D, 0xB3, 0x10, 0x07, 0x09, 0xDC, 
209         0x3F, 0xC1, 0xB7, 0x9F, 0xC5, 0x79, 0xCD, 0x6E, 0x79, 0x48, 0x4F, 0x51, 
210         0xD8, 0x4B, 0x3A, 0x32, 0x40, 0x05, 0x6B, 0x74, 0xC9, 0xF4, 0xD9, 0x67, 
211         0x9D, 0x65, 0xFF, 0x4C, 0x4E, 0xAB, 0xC0, 0xC5, 0x65, 0x49, 0xEB, 0x6D, 
212         0xAB, 0xB9, 0x30, 0x5A, 0xFC, 0x5D, 0xD4, 0xE7, 0xB5, 0xDB, 0xD3, 0xF1, 
213         0xBF, 0x6F, 0xD4, 0x18, 0xD6, 0xE7, 0x76, 0x12, 0xCE, 0x57, 0xDF, 0x63, 
214         0x2C, 0x88, 0x2F, 0x0F, 0x31, 0x3A, 0x78, 0xA0, 0xB9, 0x5A, 0x11, 0x50, 
215         0x18, 0x98, 0xA4, 0xA3, 0x9D, 0xC7, 0xC4, 0x5C, 0xE7, 0xDF, 0xFD, 0x4B, 
216         0x96, 0x84, 0x27, 0x4C, 0x84, 0x92, 0xE9, 0x5E, 0x93, 0x65, 0x0C, 0xC9, 
217         0xB4, 0x5B, 0xE7, 0xC0, 0x26, 0x66, 0x36, 0x7A, 0x36, 0x56, 0xB0, 0xC8, 
218         0x34, 0xBB, 0x4F, 0xBD, 0x0E, 0xDA, 0x04, 0x82, 0x74, 0x07, 0x3D, 0xD3, 
219         0x1D, 0x8F, 0x9B, 0x34, 0x4F, 0xA8, 0xD5, 0x58, 0x12, 0xE8, 0x96, 0x20 };
220
221         [Test]
222         public void MSPasswordWeak () 
223         {
224                 WriteBuffer (pwd);
225                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile, "password");
226                 AssertNotNull ("mspwd.RSA", pvk.RSA);
227                 Assert ("mspwd.Encrypted", pvk.Encrypted);
228                 Assert ("mspwd.Weak", pvk.Weak);
229         }
230
231         // this will convert a PVK file with a password to a PVK file
232         // without a password
233         [Test]
234         public void RemovePassword () 
235         {
236                 WriteBuffer (nopwd);
237                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile, "password");
238                 string rsa1 = pvk.RSA.ToXmlString (true);
239                 pvk.Save (testfile);
240                 pvk = PrivateKey.CreateFromFile (testfile);
241                 AssertNotNull ("nomorepwd.RSA", pvk.RSA);
242                 string rsa2 = pvk.RSA.ToXmlString (true);
243                 AssertEquals ("nomorepwd.RSA identical", rsa1, rsa2);
244                 Assert ("nomorepwd.Encrypted", !pvk.Encrypted);
245                 Assert ("nomorepwd.Weak", pvk.Weak);
246         }
247         
248         [Test]
249         public void CreatePVK () 
250         {
251                 PrivateKey pvk = new PrivateKey ();
252                 pvk.KeyType = 2;
253                 pvk.RSA = RSA.Create ();
254                 string rsa1 = pvk.RSA.ToXmlString (true);
255                 pvk.Save (testfile, "mono");
256
257                 pvk = PrivateKey.CreateFromFile (testfile, "mono");
258                 AssertNotNull ("new.RSA", pvk.RSA);
259                 string rsa2 = pvk.RSA.ToXmlString (true);
260                 AssertEquals ("new.RSA identical", rsa1, rsa2);
261                 Assert ("new.Encrypted", pvk.Encrypted);
262                 Assert ("new.Weak", !pvk.Weak);
263         }
264
265         [Test]
266         [ExpectedException (typeof (ArgumentNullException))]
267         public void Save_Null () 
268         {
269                 PrivateKey pvk = new PrivateKey ();
270                 pvk.Save (null, "mono");
271         }
272         
273         [Test]
274         [ExpectedException (typeof (CryptographicException))]
275         public void BadMagic () 
276         {
277                 byte[] bad = (byte[]) nopwd.Clone ();
278                 bad [0] = 0x00;
279                 WriteBuffer (bad);
280                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile, null);
281         }
282         
283         [Test]
284         [ExpectedException (typeof (CryptographicException))]
285         public void BadHeader () 
286         {
287                 byte[] bad = (byte[]) nopwd.Clone ();
288                 bad [4] = 0x01;
289                 WriteBuffer (bad);
290                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile, null);
291         }
292
293         [Test]
294         [ExpectedException (typeof (CryptographicException))]
295         public void SaltWithoutPassword () 
296         {
297                 byte[] bad = (byte[]) nopwd.Clone ();
298                 int saltlen = BitConverterLE.ToInt32 (bad, 16);
299                 int keylen = BitConverterLE.ToInt32 (bad, 20);
300                 // preserve total length
301                 saltlen += 8;
302                 keylen -= 8;
303                 // modify blob
304                 byte[] data = BitConverterLE.GetBytes (saltlen);
305                 Buffer.BlockCopy (data, 0, bad, 16, data.Length); 
306                 data = BitConverterLE.GetBytes (keylen);
307                 Buffer.BlockCopy (data, 0, bad, 20, data.Length); 
308                 // save-n-load          
309                 WriteBuffer (bad);
310                 PrivateKey pvk = PrivateKey.CreateFromFile (testfile, null);
311         }
312         
313         [Test]
314         [ExpectedException (typeof (ArgumentNullException))]
315         public void CreateFromFile_Null () 
316         {
317                 PrivateKey pvk = PrivateKey.CreateFromFile (null, "password");
318         }
319
320         [Test]
321         [ExpectedException (typeof (ArgumentNullException))]
322         public void Constructor_Null () 
323         {
324                 PrivateKey pvk = new PrivateKey (null, "password");
325         }
326 }
327
328 }