87144d3da4820d17cc5af73eaed58f27e46cbcfb
[mono.git] / mcs / class / corlib / Test / System.Security / SecureStringTest.cs
1 //
2 // SecureStringTest.cs - Unit tests for System.Security.SecureString
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 #if NET_2_0
30
31 using System;
32 using System.Security;
33 using System.Runtime.InteropServices;
34
35 using NUnit.Framework;
36
37 namespace MonoTests.System.Security {
38
39         [TestFixture]
40         public class SecureStringTest {
41
42                 private const string NotSupported = "Not supported before Windows 2000 Service Pack 3";
43
44                 [Test]
45                 public void DefaultConstructor ()
46                 {
47                         try {
48                                 SecureString ss = new SecureString ();
49                                 Assert.IsFalse (ss.IsReadOnly (), "IsReadOnly");
50                                 Assert.AreEqual (0, ss.Length, "0");
51                                 ss.AppendChar ('a');
52                                 Assert.AreEqual (1, ss.Length, "1");
53                                 ss.Clear ();
54                                 Assert.AreEqual (0, ss.Length, "0b");
55                                 ss.InsertAt (0, 'b');
56                                 Assert.AreEqual (1, ss.Length, "1b");
57                                 ss.SetAt (0, 'c');
58                                 Assert.AreEqual (1, ss.Length, "1c");
59                                 Assert.AreEqual ("System.Security.SecureString", ss.ToString (), "ToString");
60                                 ss.RemoveAt (0);
61                                 Assert.AreEqual (0, ss.Length, "0c");
62                                 ss.Dispose ();
63                         }
64                         catch (NotSupportedException) {
65                                 Assert.Ignore (NotSupported);
66                         }
67                 }
68 #if !TARGET_JVM
69                 [Test]
70                 public unsafe void UnsafeConstructor ()
71                 {
72                         try {
73                                 SecureString ss = null;
74                                 char[] data = new char[] { 'a', 'b', 'c' };
75                                 fixed (char* p = &data[0]) {
76                                         ss = new SecureString (p, data.Length);
77                                 }
78                                 Assert.IsFalse (ss.IsReadOnly (), "IsReadOnly");
79                                 Assert.AreEqual (3, ss.Length, "3");
80                                 ss.AppendChar ('a');
81                                 Assert.AreEqual (4, ss.Length, "4");
82                                 ss.Clear ();
83                                 Assert.AreEqual (0, ss.Length, "0b");
84                                 ss.InsertAt (0, 'b');
85                                 Assert.AreEqual (1, ss.Length, "1b");
86                                 ss.SetAt (0, 'c');
87                                 Assert.AreEqual (1, ss.Length, "1c");
88                                 ss.RemoveAt (0);
89                                 Assert.AreEqual (0, ss.Length, "0c");
90                                 ss.Dispose ();
91                         }
92                         catch (NotSupportedException) {
93                                 Assert.Ignore (NotSupported);
94                         }
95                 }
96
97                 [Test]
98                 [ExpectedException (typeof (ArgumentNullException))]
99                 public unsafe void UnsafeConstructor_Null ()
100                 {
101                         new SecureString (null, 0);
102                 }
103
104                 [Test]
105                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
106                 public unsafe void UnsafeConstructor_Negative ()
107                 {
108                         char[] data = new char[] { 'a', 'b', 'c' };
109                         fixed (char* p = &data[0]) {
110                                 new SecureString (p, -1);
111                         }
112                 }
113
114                 [Test]
115                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
116                 public unsafe void UnsafeConstructor_BiggerThanMax ()
117                 {
118                         char[] data = new char[] { 'a', 'b', 'c' };
119                         fixed (char* p = &data[0]) {
120                                 new SecureString (p, UInt16.MaxValue + 2);
121                         }
122                 }
123
124                 private SecureString max;
125
126                 private unsafe SecureString GetMaxLength ()
127                 {
128                         if (max == null) {
129                                 int maxlength =  UInt16.MaxValue + 1;
130                                 char[] data = new char[maxlength];
131                                 fixed (char* p = &data[0]) {
132                                         max = new SecureString (p, maxlength);
133                                 }
134                                 // note: don't try a loop of AppendChar with that size ;-)
135                         }
136                         return max;
137                 }
138
139                 [Test]
140                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
141                 public void AppendChar_BiggerThanMax ()
142                 {
143                         SecureString ss = GetMaxLength ();
144                         ss.AppendChar ('a');
145                 }
146 #endif
147                 [Test]
148                 public void Copy_Empty ()
149                 {
150                         SecureString empty = new SecureString ();
151                         Assert.AreEqual (0, empty.Length, "Empty.Length");
152                         SecureString empty_copy = empty.Copy ();
153                         Assert.AreEqual (0, empty_copy.Length, "EmptyCopy.Length");
154                 }
155
156                 [Test]
157                 public void Copy ()
158                 {
159                         SecureString ss = new SecureString ();
160                         ss.AppendChar ('a');
161                         Assert.AreEqual (1, ss.Length, "Length");
162
163                         SecureString ss2 = ss.Copy();
164                         Assert.AreEqual (1, ss2.Length, "Copy.Length");
165                         Assert.IsFalse (ss2.IsReadOnly (), "Copy.IsReadOnly");
166                         ss2.MakeReadOnly ();
167                         Assert.IsTrue (ss2.IsReadOnly (), "Copy.IsReadOnly-2");
168
169                         SecureString ss3 = ss2.Copy ();
170                         Assert.IsFalse (ss3.IsReadOnly (), "Copy.IsReadOnly-3");
171                 }
172
173                 [Test]
174                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
175                 public void InsertAt_Negative ()
176                 {
177                         SecureString ss = new SecureString ();
178                         ss.InsertAt (-1, 'a');
179                 }
180
181                 [Test]
182                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
183                 public void InsertAt_BiggerThanLength ()
184                 {
185                         SecureString ss = new SecureString ();
186                         ss.InsertAt (1, 'a');
187                 }
188
189                 [Test]
190                 public void InsertAt_UsedLikeAppendChar () // #350820
191                 {
192                         SecureString ss = new SecureString ();
193                         ss.AppendChar ('T');
194                         Assert.AreEqual (1, ss.Length, "AppendChar");
195                         ss.InsertAt (1, 'e');
196                         Assert.AreEqual (2, ss.Length, "InsertAt");
197                 }
198
199                 [Test]
200                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
201                 public void SetAt_Negative ()
202                 {
203                         SecureString ss = new SecureString ();
204                         ss.SetAt (-1, 'a');
205                 }
206
207                 [Test]
208                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
209                 public void SetAt_BiggerThanLength ()
210                 {
211                         SecureString ss = new SecureString ();
212                         ss.SetAt (1, 'a');
213                 }
214
215                 [Test]
216                 public void RemoveAt ()
217                 {
218                         string test_string = "test string";
219                         string expected, actual;
220                         SecureString ss = new SecureString ();
221                         foreach (char c in test_string) {
222                                 ss.AppendChar (c);
223                         }
224
225                         ss.RemoveAt (0);
226                         expected = "est string";
227                         actual = ReadSecureString (ss);
228                         Assert.AreEqual (expected, actual, "RemoveAt begining");
229
230                         ss.RemoveAt (4);
231                         expected = "est tring";
232                         actual = ReadSecureString (ss);
233                         Assert.AreEqual (expected, actual, "RemoveAt middle");
234
235                         ss.RemoveAt (8);
236                         expected = "est trin";
237                         actual = ReadSecureString (ss);
238                         Assert.AreEqual (expected, actual, "RemoveAt end");
239                 }
240
241                 [Test]
242                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
243                 public void RemoveAt_Negative ()
244                 {
245                         SecureString ss = new SecureString ();
246                         ss.RemoveAt (-1);
247                 }
248
249                 [Test]
250                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
251                 public void RemoveAt_BiggerThanLength ()
252                 {
253                         SecureString ss = new SecureString ();
254                         ss.RemoveAt (1);
255                 }
256 #if !TARGET_JVM
257                 [Test]
258                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
259                 public void InsertAt_BiggerThanMax ()
260                 {
261                         SecureString ss = GetMaxLength ();
262                         ss.InsertAt (ss.Length, 'a');
263                 }
264 #endif
265                 private SecureString GetReadOnly ()
266                 {
267                         SecureString ss = new SecureString ();
268                         ss.MakeReadOnly ();
269                         return ss;
270                 }
271
272                 [Test]
273                 public void ReadOnly ()
274                 {
275                         try {
276                                 SecureString ss = GetReadOnly ();
277                                 Assert.IsTrue (ss.IsReadOnly (), "IsReadOnly");
278                                 Assert.AreEqual (0, ss.Length, "0");
279                                 ss.Dispose ();
280                         }
281                         catch (NotSupportedException) {
282                                 Assert.Ignore (NotSupported);
283                         }
284                 }
285
286                 [Test]
287                 [ExpectedException (typeof (InvalidOperationException))]
288                 public void ReadOnly_AppendChar ()
289                 {
290                         SecureString ss = GetReadOnly ();
291                         ss.AppendChar ('a');
292                 }
293
294                 [Test]
295                 [ExpectedException (typeof (InvalidOperationException))]
296                 public void ReadOnly_Clear ()
297                 {
298                         SecureString ss = GetReadOnly ();
299                         ss.Clear ();
300                 }
301
302                 [Test]
303                 [ExpectedException (typeof (InvalidOperationException))]
304                 public void ReadOnly_InsertAt ()
305                 {
306                         SecureString ss = GetReadOnly ();
307                         ss.InsertAt (0, 'a');
308                 }
309
310                 [Test]
311                 [ExpectedException (typeof (InvalidOperationException))]
312                 public void ReadOnly_SetAt ()
313                 {
314                         SecureString ss = GetReadOnly ();
315                         ss.SetAt (0, 'a');
316                 }
317
318                 [Test]
319                 [ExpectedException (typeof (InvalidOperationException))]
320                 public void ReadOnly_RemoveAt ()
321                 {
322                         SecureString ss = GetReadOnly ();
323                         ss.RemoveAt (0);
324                 }
325
326                 private SecureString GetDisposed ()
327                 {
328                         SecureString ss = new SecureString ();
329                         ss.Dispose ();
330                         return ss;
331                 }
332
333                 [Test]
334                 public void Disposed ()
335                 {
336                         try {
337                                 SecureString ss = GetDisposed ();
338                                 ss.Dispose ();
339                         }
340                         catch (NotSupportedException) {
341                                 Assert.Ignore (NotSupported);
342                         }
343                 }
344
345                 [Test]
346                 [ExpectedException (typeof (ObjectDisposedException))]
347                 public void Disposed_AppendChar ()
348                 {
349                         SecureString ss = GetDisposed ();
350                         ss.AppendChar ('a');
351                 }
352
353                 [Test]
354                 [ExpectedException (typeof (ObjectDisposedException))]
355                 public void Disposed_Clear ()
356                 {
357                         SecureString ss = GetDisposed ();
358                         ss.Clear ();
359                 }
360
361                 [Test]
362                 [ExpectedException (typeof (ObjectDisposedException))]
363                 public void Disposed_InsertAt ()
364                 {
365                         SecureString ss = GetDisposed ();
366                         ss.InsertAt (0, 'a');
367                 }
368
369                 [Test]
370                 [ExpectedException (typeof (ObjectDisposedException))]
371                 public void Disposed_IsReadOnly ()
372                 {
373                         SecureString ss = GetDisposed ();
374                         Assert.IsFalse (ss.IsReadOnly (), "IsReadOnly");
375                 }
376
377                 [Test]
378                 [ExpectedException (typeof (ObjectDisposedException))]
379                 public void Disposed_Length ()
380                 {
381                         SecureString ss = GetDisposed ();
382                         Assert.AreEqual (0, ss.Length, "Length");
383                 }
384
385                 [Test]
386                 [ExpectedException (typeof (ObjectDisposedException))]
387                 public void Disposed_SetAt ()
388                 {
389                         SecureString ss = GetDisposed ();
390                         ss.SetAt (0, 'a');
391                 }
392
393                 [Test]
394                 [ExpectedException (typeof (ObjectDisposedException))]
395                 public void Disposed_RemoveAt ()
396                 {
397                         SecureString ss = GetDisposed ();
398                         ss.RemoveAt (0);
399                 }
400
401                 // helper function
402                 private static string ReadSecureString(SecureString aSecureString)
403                 {
404                         var strPtr = Marshal.SecureStringToGlobalAllocUnicode (aSecureString);
405                         var str = Marshal.PtrToStringUni(strPtr);
406                         Marshal.ZeroFreeGlobalAllocUnicode (strPtr);
407                         return str;
408                 }
409         }
410 }
411
412 #endif