[System.Runtime.Serialization] Static writer fix.
[mono.git] / mcs / class / System / System.Security.Cryptography.X509Certificates / X509Store.cs
1 //
2 // System.Security.Cryptography.X509Certificates.X509Store class
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
8 // Copyright (C) 2004-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 #if SECURITY_DEP
31
32 #if MONO_SECURITY_ALIAS
33 extern alias MonoSecurity;
34 using MX = MonoSecurity::Mono.Security.X509;
35 #else
36 using MX = Mono.Security.X509;
37 #endif
38
39 using System.Security.Permissions;
40
41 namespace System.Security.Cryptography.X509Certificates {
42
43         public sealed class X509Store : IDisposable {
44
45                 private string _name;
46                 private StoreLocation _location;
47                 private X509Certificate2Collection list;
48                 private OpenFlags _flags;
49                 private MX.X509Store store;
50
51                 // constructors
52
53                 // BUG: MY when using this constructor - My when using StoreName.My
54                 public X509Store () 
55                         : this ("MY", StoreLocation.CurrentUser) 
56                 {
57                 }
58
59                 public X509Store (string storeName) 
60                         : this (storeName, StoreLocation.CurrentUser) 
61                 {
62                 }
63
64                 public X509Store (StoreName storeName) 
65                         : this (storeName, StoreLocation.CurrentUser)
66                 {
67                 }
68
69                 public X509Store (StoreLocation storeLocation) 
70                         : this ("MY", storeLocation)
71                 {
72                 }
73
74                 public X509Store (StoreName storeName, StoreLocation storeLocation)
75                 {
76                         if ((storeName < StoreName.AddressBook) || (storeName > StoreName.TrustedPublisher))
77                                 throw new ArgumentException ("storeName");
78                         if ((storeLocation < StoreLocation.CurrentUser) || (storeLocation > StoreLocation.LocalMachine))
79                                 throw new ArgumentException ("storeLocation");
80
81                         switch (storeName) {
82                         case StoreName.CertificateAuthority:
83                                 _name = "CA";
84                                 break;
85                         default:
86                                 _name = storeName.ToString ();
87                                 break;
88                         }
89                         _location = storeLocation;
90                 }
91
92                 [MonoTODO ("Mono's stores are fully managed. All handles are invalid.")]
93                 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
94                 public X509Store (IntPtr storeHandle)
95                 {
96                         if (storeHandle == IntPtr.Zero)
97                                 throw new ArgumentNullException ("storeHandle");
98                         throw new CryptographicException ("Invalid handle.");
99                 }
100
101                 public X509Store (string storeName, StoreLocation storeLocation)
102                 {
103                         if ((storeLocation < StoreLocation.CurrentUser) || (storeLocation > StoreLocation.LocalMachine))
104                                 throw new ArgumentException ("storeLocation");
105
106                         _name = storeName;
107                         _location = storeLocation;
108                 }
109
110                 public void Dispose ()
111                 {
112                 }
113
114                 // properties
115
116                 public X509Certificate2Collection Certificates {
117                         get {
118                                 if (list == null)
119                                         list = new X509Certificate2Collection ();
120                                 else if (store == null)
121                                         list.Clear ();
122
123                                 return list;
124                         }
125                 } 
126
127                 public StoreLocation Location {
128                         get { return _location; }
129                 }
130
131                 public string Name {
132                         get { return _name; }
133                 }
134
135                 private MX.X509Stores Factory {
136                         get {
137                                 if (_location == StoreLocation.CurrentUser)
138                                         return MX.X509StoreManager.CurrentUser;
139                                 else
140                                         return MX.X509StoreManager.LocalMachine;
141                         }
142                 }
143
144                 private bool IsOpen {
145                         get { return (store != null); }
146                 }
147
148                 private bool IsReadOnly {
149                         get { return ((_flags & OpenFlags.ReadWrite) == OpenFlags.ReadOnly); }
150                 }
151
152                 internal MX.X509Store Store {
153                         get { return store; }
154                 }
155
156                 [MonoTODO ("Mono's stores are fully managed. Always returns IntPtr.Zero.")]
157                 public IntPtr StoreHandle {
158                         get { return IntPtr.Zero; }
159                 }
160
161                 // methods
162
163                 public void Add (X509Certificate2 certificate)
164                 {
165                         if (certificate == null)
166                                 throw new ArgumentNullException ("certificate");
167                         if (!IsOpen)
168                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
169                         if (IsReadOnly)
170                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
171
172                         if (!Exists (certificate)) {
173                                 try {
174                                         store.Import (new MX.X509Certificate (certificate.RawData));
175                                 }
176                                 finally {
177                                         Certificates.Add (certificate);
178                                 }
179                         }
180                 }
181
182                 [MonoTODO ("Method isn't transactional (like documented)")]
183                 public void AddRange (X509Certificate2Collection certificates)
184                 {
185                         if (certificates == null)
186                                 throw new ArgumentNullException ("certificates");
187
188                         if (certificates.Count == 0)
189                                 return;
190
191                         if (!IsOpen)
192                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
193                         if (IsReadOnly)
194                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
195
196                         foreach (X509Certificate2 certificate in certificates) {
197                                 if (!Exists (certificate)) {
198                                         try {
199                                                 store.Import (new MX.X509Certificate (certificate.RawData));
200                                         }
201                                         finally {
202                                                 Certificates.Add (certificate);
203                                         }
204                                 }
205                         }
206                 }
207
208                 public void Close () 
209                 {
210                         store = null;
211                         if (list != null)
212                                 list.Clear ();
213                 }
214
215                 public void Open (OpenFlags flags)
216                 {
217                         if (String.IsNullOrEmpty (_name))
218                                 throw new CryptographicException (Locale.GetText ("Invalid store name (null or empty)."));
219
220                         /* keep existing Mono installations (pre 2.0) compatible with new stuff */
221                         string name;
222                         switch (_name) {
223                         case "Root":
224                                 name = "Trust";
225                                 break;
226                         default:
227                                 name = _name;
228                                 break;
229                         }
230
231                         bool create = ((flags & OpenFlags.OpenExistingOnly) != OpenFlags.OpenExistingOnly);
232                         store = Factory.Open (name, create);
233                         if (store == null)
234                                 throw new CryptographicException (Locale.GetText ("Store {0} doesn't exists.", _name));
235                         _flags = flags;
236
237                         foreach (MX.X509Certificate x in store.Certificates) {
238                                 var cert2 = new X509Certificate2 (x.RawData);
239                                 cert2.PrivateKey = x.RSA;
240                                 Certificates.Add (cert2);
241                         }
242                 }
243
244                 public void Remove (X509Certificate2 certificate) 
245                 {
246                         if (certificate == null)
247                                 throw new ArgumentNullException ("certificate");
248                         if (!IsOpen)
249                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
250
251                         if (!Exists (certificate))
252                                 return;
253
254                         if (IsReadOnly)
255                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
256
257                         try {
258                                 store.Remove (new MX.X509Certificate (certificate.RawData));
259                         }
260                         finally {
261                                 Certificates.Remove (certificate);
262                         }
263                 }
264
265                 [MonoTODO ("Method isn't transactional (like documented)")]
266                 public void RemoveRange (X509Certificate2Collection certificates) 
267                 {
268                         if (certificates == null)
269                                 throw new ArgumentNullException ("certificates");
270
271                         if (certificates.Count == 0)
272                                 return;
273
274                         if (!IsOpen)
275                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
276
277                         bool delete = false;
278                         foreach (X509Certificate2 certificate in certificates) {
279                                 if (Exists (certificate))
280                                         delete = true;
281                         }
282                         if (!delete)
283                                 return;
284
285                         if (IsReadOnly)
286                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
287
288                         try {
289                                 foreach (X509Certificate2 certificate in certificates)
290                                         store.Remove (new MX.X509Certificate (certificate.RawData));
291                         }
292                         finally {
293                                 Certificates.RemoveRange (certificates);
294                         }
295                 }
296
297                 private bool Exists (X509Certificate2 certificate)
298                 {
299                         if ((store == null) || (list == null) || (certificate == null))
300                                 return false;
301
302                         foreach (X509Certificate2 c in list) {
303                                 if (certificate.Equals (c)) {
304                                         return true;
305                                 }
306                         }
307                         return false;
308                 }
309         }
310 }
311
312 #endif