2004-04-28 Sebastien Pouliot <sebastien@ximian.com>
[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 using System;
11 using System.Collections;
12 using System.Globalization;
13 using System.IO;
14 using System.Text;
15
16 using Mono.Security.X509.Extensions;
17
18 namespace Mono.Security.X509 {
19
20 #if INSIDE_CORLIB
21         internal
22 #else
23         public 
24 #endif
25         class X509Store {
26
27                 private string _storePath;
28                 private X509CertificateCollection _certificates;
29                 private ArrayList _crls;
30                 private bool _crl;
31                 private string _name;
32
33                 internal X509Store (string path, bool crl) 
34                 {
35                         _storePath = path;
36                         _crl = crl;
37                 }
38
39                 // properties
40
41                 public X509CertificateCollection Certificates {
42                         get { 
43                                 if (_certificates == null) {
44                                         _certificates = BuildCertificatesCollection (_storePath);
45                                 }
46                                 return _certificates; 
47                         }
48                 }
49
50                 public ArrayList Crls {
51                         get {
52                                 // CRL aren't applicable to all stores
53                                 // but returning null is a little rude
54                                 if (!_crl) {
55                                         _crls = new ArrayList ();
56                                 }
57                                 if (_crls == null) {
58                                         _crls = BuildCrlsCollection (_storePath);
59                                 }
60                                 return _crls; 
61                         }
62                 }
63
64                 public string Name {
65                         get {
66                                 if (_name == null) {
67                                         int n = _storePath.LastIndexOf (Path.DirectorySeparatorChar);
68                                         _name = _storePath.Substring (n+1);
69                                 }
70                                 return _name;
71                         }
72                 }
73
74                 // methods
75
76                 public void Clear () 
77                 {
78                         if (_certificates != null)
79                                 _certificates.Clear ();
80                         _certificates = null;
81                         if (_crls != null)
82                                 _crls.Clear ();
83                         _crls = null;
84                 }
85
86                 public void Import (X509Certificate certificate) 
87                 {
88                         if (!Directory.Exists (_storePath)) {
89                                 Directory.CreateDirectory (_storePath);
90                         }
91
92                         string filename = Path.Combine (_storePath, GetUniqueName (certificate));
93                         if (!File.Exists (filename)) {
94                                 using (FileStream fs = File.OpenWrite (filename)) {
95                                         byte[] data = certificate.RawData;
96                                         fs.Write (data, 0, data.Length);
97                                         fs.Close ();
98                                 }
99                         }
100                 }
101
102                 public void Remove (X509Certificate certificate) 
103                 {
104                         string filename = Path.Combine (_storePath, GetUniqueName (certificate));
105                         if (File.Exists (filename)) {
106                                 File.Delete (filename);
107                         }
108                 }
109
110                 // private stuff
111
112                 private string GetUniqueName (X509Certificate certificate) 
113                 {
114                         string method = null;
115                         byte[] name = null;
116
117                         // We prefer Subject Key Identifier as the unique name
118                         // as it will provide faster lookups
119                         X509Extension ext = certificate.Extensions ["2.5.29.14"];
120                         if (ext != null) {
121                                 SubjectKeyIdentifierExtension ski = new SubjectKeyIdentifierExtension (ext);
122                                 name = ski.Identifier;
123                                 method = "ski";
124                         }
125                         else {
126                                 method = "tbp"; // thumbprint
127                                 name = certificate.Hash;
128                         }
129
130                         StringBuilder sb = new StringBuilder (method);
131                         sb.Append ("-");
132                         foreach (byte b in name) {
133                                 sb.Append (b.ToString ("X2", CultureInfo.InvariantCulture));
134                         }
135                         sb.Append (".cer");
136
137                         return sb.ToString ();
138                 }
139
140                 private byte[] Load (string filename) 
141                 {
142                         byte[] data = null;
143                         using (FileStream fs = File.OpenRead (filename)) {
144                                 data = new byte [fs.Length];
145                                 fs.Read (data, 0, data.Length);
146                                 fs.Close ();
147                         }
148                         return data;
149                 }
150
151                 private X509Certificate LoadCertificate (string filename) 
152                 {
153                         byte[] data = Load (filename);
154                         X509Certificate cert = new X509Certificate (data);
155                         return cert;
156                 }
157
158                 private X509Crl LoadCrl (string filename) 
159                 {
160                         byte[] data = Load (filename);
161                         X509Crl crl = new X509Crl (data);
162                         return crl;
163                 }
164
165                 private X509CertificateCollection BuildCertificatesCollection (string storeName) 
166                 {
167                         string path = Path.Combine (_storePath, storeName);
168                         if (!Directory.Exists (path)) {
169                                 Directory.CreateDirectory (path);
170                         }
171
172                         X509CertificateCollection coll = new X509CertificateCollection ();
173                         string[] files = Directory.GetFiles (path, "*.cer");
174                         if ((files != null) && (files.Length > 0)) {
175                                 foreach (string file in files) {
176                                         try {
177                                                 X509Certificate cert = LoadCertificate (file);
178                                                 coll.Add (cert);
179                                         }
180                                         catch {
181                                                 // in case someone is dumb enough
182                                                 // (like me) to include a base64
183                                                 // encoded certs (or other junk 
184                                                 // into the store).
185                                         }
186                                 }
187                         }
188                         return coll;
189                 }
190
191                 private ArrayList BuildCrlsCollection (string storeName) 
192                 {
193                         ArrayList list = new ArrayList ();
194                         string path = Path.Combine (_storePath, storeName);
195                         string[] files = Directory.GetFiles (path, "*.crl");
196                         if ((files != null) && (files.Length > 0)) {
197                                 foreach (string file in files) {
198                                         try {
199                                                 X509Crl crl = LoadCrl (file);
200                                                 list.Add (crl);
201                                         }
202                                         catch {
203                                                 // junk catcher
204                                         }
205                                 }
206                         }
207                         return list;
208                 }
209         }
210 }