Merge pull request #2274 from esdrubal/udpclientreceive
[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 {
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                 // properties
111
112                 public X509Certificate2Collection Certificates {
113                         get {
114                                 if (list == null)
115                                         list = new X509Certificate2Collection ();
116                                 else if (store == null)
117                                         list.Clear ();
118
119                                 return list;
120                         }
121                 } 
122
123                 public StoreLocation Location {
124                         get { return _location; }
125                 }
126
127                 public string Name {
128                         get { return _name; }
129                 }
130
131                 private MX.X509Stores Factory {
132                         get {
133                                 if (_location == StoreLocation.CurrentUser)
134                                         return MX.X509StoreManager.CurrentUser;
135                                 else
136                                         return MX.X509StoreManager.LocalMachine;
137                         }
138                 }
139
140                 private bool IsOpen {
141                         get { return (store != null); }
142                 }
143
144                 private bool IsReadOnly {
145                         get { return ((_flags & OpenFlags.ReadWrite) == OpenFlags.ReadOnly); }
146                 }
147
148                 internal MX.X509Store Store {
149                         get { return store; }
150                 }
151
152                 [MonoTODO ("Mono's stores are fully managed. Always returns IntPtr.Zero.")]
153                 public IntPtr StoreHandle {
154                         get { return IntPtr.Zero; }
155                 }
156
157                 // methods
158
159                 public void Add (X509Certificate2 certificate)
160                 {
161                         if (certificate == null)
162                                 throw new ArgumentNullException ("certificate");
163                         if (!IsOpen)
164                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
165                         if (IsReadOnly)
166                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
167
168                         if (!Exists (certificate)) {
169                                 try {
170                                         store.Import (new MX.X509Certificate (certificate.RawData));
171                                 }
172                                 finally {
173                                         Certificates.Add (certificate);
174                                 }
175                         }
176                 }
177
178                 [MonoTODO ("Method isn't transactional (like documented)")]
179                 public void AddRange (X509Certificate2Collection certificates)
180                 {
181                         if (certificates == null)
182                                 throw new ArgumentNullException ("certificates");
183
184                         if (certificates.Count == 0)
185                                 return;
186
187                         if (!IsOpen)
188                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
189                         if (IsReadOnly)
190                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
191
192                         foreach (X509Certificate2 certificate in certificates) {
193                                 if (!Exists (certificate)) {
194                                         try {
195                                                 store.Import (new MX.X509Certificate (certificate.RawData));
196                                         }
197                                         finally {
198                                                 Certificates.Add (certificate);
199                                         }
200                                 }
201                         }
202                 }
203
204                 public void Close () 
205                 {
206                         store = null;
207                         if (list != null)
208                                 list.Clear ();
209                 }
210
211                 public void Open (OpenFlags flags)
212                 {
213                         if (String.IsNullOrEmpty (_name))
214                                 throw new CryptographicException (Locale.GetText ("Invalid store name (null or empty)."));
215
216                         /* keep existing Mono installations (pre 2.0) compatible with new stuff */
217                         string name;
218                         switch (_name) {
219                         case "Root":
220                                 name = "Trust";
221                                 break;
222                         default:
223                                 name = _name;
224                                 break;
225                         }
226
227                         bool create = ((flags & OpenFlags.OpenExistingOnly) != OpenFlags.OpenExistingOnly);
228                         store = Factory.Open (name, create);
229                         if (store == null)
230                                 throw new CryptographicException (Locale.GetText ("Store {0} doesn't exists.", _name));
231                         _flags = flags;
232
233                         foreach (MX.X509Certificate x in store.Certificates) {
234                                 var cert2 = new X509Certificate2 (x.RawData);
235                                 cert2.PrivateKey = x.RSA;
236                                 Certificates.Add (cert2);
237                         }
238                 }
239
240                 public void Remove (X509Certificate2 certificate) 
241                 {
242                         if (certificate == null)
243                                 throw new ArgumentNullException ("certificate");
244                         if (!IsOpen)
245                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
246
247                         if (!Exists (certificate))
248                                 return;
249
250                         if (IsReadOnly)
251                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
252
253                         try {
254                                 store.Remove (new MX.X509Certificate (certificate.RawData));
255                         }
256                         finally {
257                                 Certificates.Remove (certificate);
258                         }
259                 }
260
261                 [MonoTODO ("Method isn't transactional (like documented)")]
262                 public void RemoveRange (X509Certificate2Collection certificates) 
263                 {
264                         if (certificates == null)
265                                 throw new ArgumentNullException ("certificates");
266
267                         if (certificates.Count == 0)
268                                 return;
269
270                         if (!IsOpen)
271                                 throw new CryptographicException (Locale.GetText ("Store isn't opened."));
272
273                         bool delete = false;
274                         foreach (X509Certificate2 certificate in certificates) {
275                                 if (Exists (certificate))
276                                         delete = true;
277                         }
278                         if (!delete)
279                                 return;
280
281                         if (IsReadOnly)
282                                 throw new CryptographicException (Locale.GetText ("Store is read-only."));
283
284                         try {
285                                 foreach (X509Certificate2 certificate in certificates)
286                                         store.Remove (new MX.X509Certificate (certificate.RawData));
287                         }
288                         finally {
289                                 Certificates.RemoveRange (certificates);
290                         }
291                 }
292
293                 private bool Exists (X509Certificate2 certificate)
294                 {
295                         if ((store == null) || (list == null) || (certificate == null))
296                                 return false;
297
298                         foreach (X509Certificate2 c in list) {
299                                 if (certificate.Equals (c)) {
300                                         return true;
301                                 }
302                         }
303                         return false;
304                 }
305         }
306 }
307
308 #endif