2 // X509Store.cs: Handles a X.509 certificates/CRLs store
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System
.Collections
;
31 using System
.Globalization
;
35 using Mono
.Security
.X509
.Extensions
;
37 namespace Mono
.Security
.X509
{
46 private string _storePath
;
47 private X509CertificateCollection _certificates
;
48 private ArrayList _crls
;
52 internal X509Store (string path
, bool crl
)
60 public X509CertificateCollection Certificates
{
62 if (_certificates
== null) {
63 _certificates
= BuildCertificatesCollection (_storePath
);
69 public ArrayList Crls
{
71 // CRL aren't applicable to all stores
72 // but returning null is a little rude
74 _crls
= new ArrayList ();
77 _crls
= BuildCrlsCollection (_storePath
);
86 int n
= _storePath
.LastIndexOf (Path
.DirectorySeparatorChar
);
87 _name
= _storePath
.Substring (n
+1);
97 if (_certificates
!= null)
98 _certificates
.Clear ();
105 public void Import (X509Certificate certificate
)
107 CheckStore (_storePath
, true);
109 string filename
= Path
.Combine (_storePath
, GetUniqueName (certificate
));
110 if (!File
.Exists (filename
)) {
111 using (FileStream fs
= File
.Create (filename
)) {
112 byte[] data
= certificate
.RawData
;
113 fs
.Write (data
, 0, data
.Length
);
119 public void Import (X509Crl crl
)
121 CheckStore (_storePath
, true);
123 string filename
= Path
.Combine (_storePath
, GetUniqueName (crl
));
124 if (!File
.Exists (filename
)) {
125 using (FileStream fs
= File
.Create (filename
)) {
126 byte[] data
= crl
.RawData
;
127 fs
.Write (data
, 0, data
.Length
);
132 public void Remove (X509Certificate certificate
)
134 string filename
= Path
.Combine (_storePath
, GetUniqueName (certificate
));
135 if (File
.Exists (filename
)) {
136 File
.Delete (filename
);
140 public void Remove (X509Crl crl
)
142 string filename
= Path
.Combine (_storePath
, GetUniqueName (crl
));
143 if (File
.Exists (filename
)) {
144 File
.Delete (filename
);
150 private string GetUniqueName (X509Certificate certificate
)
153 byte[] name
= GetUniqueName (certificate
.Extensions
);
155 method
= "tbp"; // thumbprint
156 name
= certificate
.Hash
;
160 return GetUniqueName (method
, name
, ".cer");
163 private string GetUniqueName (X509Crl crl
)
166 byte[] name
= GetUniqueName (crl
.Extensions
);
168 method
= "tbp"; // thumbprint
173 return GetUniqueName (method
, name
, ".crl");
176 private byte[] GetUniqueName (X509ExtensionCollection extensions
)
178 // We prefer Subject Key Identifier as the unique name
179 // as it will provide faster lookups
180 X509Extension ext
= extensions
["2.5.29.14"];
184 SubjectKeyIdentifierExtension ski
= new SubjectKeyIdentifierExtension (ext
);
185 return ski
.Identifier
;
188 private string GetUniqueName (string method
, byte[] name
, string fileExtension
)
190 StringBuilder sb
= new StringBuilder (method
);
192 foreach (byte b
in name
) {
193 sb
.Append (b
.ToString ("X2", CultureInfo
.InvariantCulture
));
195 sb
.Append (fileExtension
);
197 return sb
.ToString ();
200 private byte[] Load (string filename
)
203 using (FileStream fs
= File
.OpenRead (filename
)) {
204 data
= new byte [fs
.Length
];
205 fs
.Read (data
, 0, data
.Length
);
211 private X509Certificate
LoadCertificate (string filename
)
213 byte[] data
= Load (filename
);
214 X509Certificate cert
= new X509Certificate (data
);
218 private X509Crl
LoadCrl (string filename
)
220 byte[] data
= Load (filename
);
221 X509Crl crl
= new X509Crl (data
);
225 private bool CheckStore (string path
, bool throwException
)
228 if (Directory
.Exists (path
))
230 Directory
.CreateDirectory (path
);
231 return Directory
.Exists (path
);
240 private X509CertificateCollection
BuildCertificatesCollection (string storeName
)
242 X509CertificateCollection coll
= new X509CertificateCollection ();
243 string path
= Path
.Combine (_storePath
, storeName
);
244 if (!CheckStore (path
, false))
245 return coll
; // empty collection
247 string[] files
= Directory
.GetFiles (path
, "*.cer");
248 if ((files
!= null) && (files
.Length
> 0)) {
249 foreach (string file
in files
) {
251 X509Certificate cert
= LoadCertificate (file
);
255 // in case someone is dumb enough
256 // (like me) to include a base64
257 // encoded certs (or other junk
265 private ArrayList
BuildCrlsCollection (string storeName
)
267 ArrayList list
= new ArrayList ();
268 string path
= Path
.Combine (_storePath
, storeName
);
269 if (!CheckStore (path
, false))
270 return list
; // empty list
272 string[] files
= Directory
.GetFiles (path
, "*.crl");
273 if ((files
!= null) && (files
.Length
> 0)) {
274 foreach (string file
in files
) {
276 X509Crl crl
= LoadCrl (file
);