2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / Mono.Security.X509 / X509Store.cs
1 //
2 // X509Store.cs: Handles a X.509 certificates/CRLs store
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // (C) 2004 Novell (http://www.novell.com)
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.Collections;
35 using System.Globalization;
36 using System.IO;
37 using System.Text;
38
39 using Mono.Security.X509.Extensions;
40
41 namespace Mono.Security.X509 {
42
43 #if INSIDE_CORLIB
44         internal
45 #else
46         public 
47 #endif
48         class X509Store {
49
50                 private string _storePath;
51                 private X509CertificateCollection _certificates;
52                 private ArrayList _crls;
53                 private bool _crl;
54                 private string _name;
55
56                 internal X509Store (string path, bool crl) 
57                 {
58                         _storePath = path;
59                         _crl = crl;
60                 }
61
62                 // properties
63
64                 public X509CertificateCollection Certificates {
65                         get { 
66                                 if (_certificates == null) {
67                                         _certificates = BuildCertificatesCollection (_storePath);
68                                 }
69                                 return _certificates; 
70                         }
71                 }
72
73                 public ArrayList Crls {
74                         get {
75                                 // CRL aren't applicable to all stores
76                                 // but returning null is a little rude
77                                 if (!_crl) {
78                                         _crls = new ArrayList ();
79                                 }
80                                 if (_crls == null) {
81                                         _crls = BuildCrlsCollection (_storePath);
82                                 }
83                                 return _crls; 
84                         }
85                 }
86
87                 public string Name {
88                         get {
89                                 if (_name == null) {
90                                         int n = _storePath.LastIndexOf (Path.DirectorySeparatorChar);
91                                         _name = _storePath.Substring (n+1);
92                                 }
93                                 return _name;
94                         }
95                 }
96
97                 // methods
98
99                 public void Clear () 
100                 {
101                         if (_certificates != null)
102                                 _certificates.Clear ();
103                         _certificates = null;
104                         if (_crls != null)
105                                 _crls.Clear ();
106                         _crls = null;
107                 }
108
109                 public void Import (X509Certificate certificate) 
110                 {
111                         if (!Directory.Exists (_storePath)) {
112                                 Directory.CreateDirectory (_storePath);
113                         }
114
115                         string filename = Path.Combine (_storePath, GetUniqueName (certificate));
116                         if (!File.Exists (filename)) {
117                                 using (FileStream fs = File.OpenWrite (filename)) {
118                                         byte[] data = certificate.RawData;
119                                         fs.Write (data, 0, data.Length);
120                                         fs.Close ();
121                                 }
122                         }
123                 }
124
125                 public void Remove (X509Certificate certificate) 
126                 {
127                         string filename = Path.Combine (_storePath, GetUniqueName (certificate));
128                         if (File.Exists (filename)) {
129                                 File.Delete (filename);
130                         }
131                 }
132
133                 // private stuff
134
135                 private string GetUniqueName (X509Certificate certificate) 
136                 {
137                         string method = null;
138                         byte[] name = null;
139
140                         // We prefer Subject Key Identifier as the unique name
141                         // as it will provide faster lookups
142                         X509Extension ext = certificate.Extensions ["2.5.29.14"];
143                         if (ext != null) {
144                                 SubjectKeyIdentifierExtension ski = new SubjectKeyIdentifierExtension (ext);
145                                 name = ski.Identifier;
146                                 method = "ski";
147                         }
148                         else {
149                                 method = "tbp"; // thumbprint
150                                 name = certificate.Hash;
151                         }
152
153                         StringBuilder sb = new StringBuilder (method);
154                         sb.Append ("-");
155                         foreach (byte b in name) {
156                                 sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
157                         }
158                         sb.Append (".cer");
159
160                         return sb.ToString ();
161                 }
162
163                 private byte[] Load (string filename) 
164                 {
165                         byte[] data = null;
166                         using (FileStream fs = File.OpenRead (filename)) {
167                                 data = new byte [fs.Length];
168                                 fs.Read (data, 0, data.Length);
169                                 fs.Close ();
170                         }
171                         return data;
172                 }
173
174                 private X509Certificate LoadCertificate (string filename) 
175                 {
176                         byte[] data = Load (filename);
177                         X509Certificate cert = new X509Certificate (data);
178                         return cert;
179                 }
180
181                 private X509Crl LoadCrl (string filename) 
182                 {
183                         byte[] data = Load (filename);
184                         X509Crl crl = new X509Crl (data);
185                         return crl;
186                 }
187
188                 private X509CertificateCollection BuildCertificatesCollection (string storeName) 
189                 {
190                         string path = Path.Combine (_storePath, storeName);
191                         if (!Directory.Exists (path)) {
192                                 Directory.CreateDirectory (path);
193                         }
194
195                         X509CertificateCollection coll = new X509CertificateCollection ();
196                         string[] files = Directory.GetFiles (path, "*.cer");
197                         if ((files != null) && (files.Length > 0)) {
198                                 foreach (string file in files) {
199                                         try {
200                                                 X509Certificate cert = LoadCertificate (file);
201                                                 coll.Add (cert);
202                                         }
203                                         catch {
204                                                 // in case someone is dumb enough
205                                                 // (like me) to include a base64
206                                                 // encoded certs (or other junk 
207                                                 // into the store).
208                                         }
209                                 }
210                         }
211                         return coll;
212                 }
213
214                 private ArrayList BuildCrlsCollection (string storeName) 
215                 {
216                         ArrayList list = new ArrayList ();
217                         string path = Path.Combine (_storePath, storeName);
218                         string[] files = Directory.GetFiles (path, "*.crl");
219                         if ((files != null) && (files.Length > 0)) {
220                                 foreach (string file in files) {
221                                         try {
222                                                 X509Crl crl = LoadCrl (file);
223                                                 list.Add (crl);
224                                         }
225                                         catch {
226                                                 // junk catcher
227                                         }
228                                 }
229                         }
230                         return list;
231                 }
232         }
233 }