2 // System.Security.Cryptography.X509Certificates.X509Certificate2Collection class
5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Tim Coleman (tim@timcoleman.com)
8 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) Tim Coleman, 2004
10 // Copyright (C) 2005, 2006 Novell Inc. (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #if SECURITY_DEP || MOONLIGHT
34 using System
.Collections
;
35 using System
.Globalization
;
37 namespace System
.Security
.Cryptography
.X509Certificates
{
39 public class X509Certificate2Collection
: X509CertificateCollection
{
43 public X509Certificate2Collection ()
47 public X509Certificate2Collection (X509Certificate2Collection certificates
)
49 AddRange (certificates
);
52 public X509Certificate2Collection (X509Certificate2 certificate
)
57 public X509Certificate2Collection (X509Certificate2
[] certificates
)
59 AddRange (certificates
);
64 public new X509Certificate2
this [int index
] {
67 throw new ArgumentOutOfRangeException ("negative index");
68 if (index
>= InnerList
.Count
)
69 throw new ArgumentOutOfRangeException ("index >= Count");
70 return (X509Certificate2
) InnerList
[index
];
72 set { InnerList [index] = value; }
77 public int Add (X509Certificate2 certificate
)
79 if (certificate
== null)
80 throw new ArgumentNullException ("certificate");
82 return InnerList
.Add (certificate
);
85 [MonoTODO ("Method isn't transactional (like documented)")]
86 public void AddRange (X509Certificate2
[] certificates
)
88 if (certificates
== null)
89 throw new ArgumentNullException ("certificates");
91 for (int i
=0; i
< certificates
.Length
; i
++)
92 InnerList
.Add (certificates
[i
]);
95 [MonoTODO ("Method isn't transactional (like documented)")]
96 public void AddRange (X509Certificate2Collection certificates
)
98 if (certificates
== null)
99 throw new ArgumentNullException ("certificates");
101 InnerList
.AddRange (certificates
);
104 public bool Contains (X509Certificate2 certificate
)
106 if (certificate
== null)
107 throw new ArgumentNullException ("certificate");
109 foreach (X509Certificate2 c
in InnerList
) {
110 if (c
.Equals (certificate
))
116 [MonoTODO ("only support X509ContentType.Cert")]
117 public byte[] Export (X509ContentType contentType
)
119 return Export (contentType
, null);
122 [MonoTODO ("only support X509ContentType.Cert")]
123 public byte[] Export (X509ContentType contentType
, string password
)
125 switch (contentType
) {
126 case X509ContentType
.Cert
:
128 case X509ContentType
.Pfx
: // this includes Pkcs12
129 case X509ContentType
.SerializedCert
:
131 // if multiple certificates are present we only export the last one
133 return this [Count
- 1].Export (contentType
, password
);
136 case X509ContentType
.Pkcs7
:
139 case X509ContentType
.SerializedStore
:
144 // this includes Authenticode, Unknown and bad values
145 string msg
= Locale
.GetText ("Cannot export certificate(s) to the '{0}' format", contentType
);
146 throw new CryptographicException (msg
);
151 static string[] newline_split
= new string[] { Environment.NewLine }
;
153 [MonoTODO ("Does not support X509FindType.FindByTemplateName, FindByApplicationPolicy and FindByCertificatePolicy")]
154 public X509Certificate2Collection
Find (X509FindType findType
, object findValue
, bool validOnly
)
156 if (findValue
== null)
157 throw new ArgumentNullException ("findValue");
159 string str
= String
.Empty
;
160 string oid
= String
.Empty
;
161 X509KeyUsageFlags ku
= X509KeyUsageFlags
.None
;
162 DateTime dt
= DateTime
.MinValue
;
165 case X509FindType
.FindByThumbprint
:
166 case X509FindType
.FindBySubjectName
:
167 case X509FindType
.FindBySubjectDistinguishedName
:
168 case X509FindType
.FindByIssuerName
:
169 case X509FindType
.FindByIssuerDistinguishedName
:
170 case X509FindType
.FindBySerialNumber
:
171 case X509FindType
.FindByTemplateName
:
172 case X509FindType
.FindBySubjectKeyIdentifier
:
174 str
= (string) findValue
;
176 catch (Exception e
) {
177 string msg
= Locale
.GetText ("Invalid find value type '{0}', expected '{1}'.",
178 findValue
.GetType (), "string");
179 throw new CryptographicException (msg
, e
);
182 case X509FindType
.FindByApplicationPolicy
:
183 case X509FindType
.FindByCertificatePolicy
:
184 case X509FindType
.FindByExtension
:
186 oid
= (string) findValue
;
188 catch (Exception e
) {
189 string msg
= Locale
.GetText ("Invalid find value type '{0}', expected '{1}'.",
190 findValue
.GetType (), "X509KeyUsageFlags");
191 throw new CryptographicException (msg
, e
);
195 CryptoConfig
.EncodeOID (oid
);
197 catch (CryptographicUnexpectedOperationException
) {
198 string msg
= Locale
.GetText ("Invalid OID value '{0}'.", oid
);
199 throw new ArgumentException ("findValue", msg
);
202 case X509FindType
.FindByKeyUsage
:
204 ku
= (X509KeyUsageFlags
) findValue
;
206 catch (Exception e
) {
207 string msg
= Locale
.GetText ("Invalid find value type '{0}', expected '{1}'.",
208 findValue
.GetType (), "X509KeyUsageFlags");
209 throw new CryptographicException (msg
, e
);
212 case X509FindType
.FindByTimeValid
:
213 case X509FindType
.FindByTimeNotYetValid
:
214 case X509FindType
.FindByTimeExpired
:
216 dt
= (DateTime
) findValue
;
218 catch (Exception e
) {
219 string msg
= Locale
.GetText ("Invalid find value type '{0}', expected '{1}'.",
220 findValue
.GetType (), "X509DateTime");
221 throw new CryptographicException (msg
,e
);
226 string msg
= Locale
.GetText ("Invalid find type '{0}'.", findType
);
227 throw new CryptographicException (msg
);
231 CultureInfo cinv
= CultureInfo
.InvariantCulture
;
232 X509Certificate2Collection results
= new X509Certificate2Collection ();
233 foreach (X509Certificate2 x
in InnerList
) {
234 bool value_match
= false;
237 case X509FindType
.FindByThumbprint
:
238 // works with Thumbprint, GetCertHashString in both normal (upper) and lower case
239 value_match
= ((String
.Compare (str
, x
.Thumbprint
, true, cinv
) == 0) ||
240 (String
.Compare (str
, x
.GetCertHashString (), true, cinv
) == 0));
242 case X509FindType
.FindBySubjectName
:
243 string [] names
= x
.SubjectName
.Format (true).Split (newline_split
, StringSplitOptions
.RemoveEmptyEntries
);
244 foreach (string name
in names
) {
245 int pos
= name
.IndexOf ('=');
246 value_match
= (name
.IndexOf (str
, pos
, StringComparison
.InvariantCultureIgnoreCase
) >= 0);
251 case X509FindType
.FindBySubjectDistinguishedName
:
252 value_match
= (String
.Compare (str
, x
.Subject
, true, cinv
) == 0);
254 case X509FindType
.FindByIssuerName
:
255 string iname
= x
.GetNameInfo (X509NameType
.SimpleName
, true);
256 value_match
= (iname
.IndexOf (str
, StringComparison
.InvariantCultureIgnoreCase
) >= 0);
258 case X509FindType
.FindByIssuerDistinguishedName
:
259 value_match
= (String
.Compare (str
, x
.Issuer
, true, cinv
) == 0);
261 case X509FindType
.FindBySerialNumber
:
262 value_match
= (String
.Compare (str
, x
.SerialNumber
, true, cinv
) == 0);
264 case X509FindType
.FindByTemplateName
:
265 // TODO - find a valid test case
267 case X509FindType
.FindBySubjectKeyIdentifier
:
268 X509SubjectKeyIdentifierExtension ski
= (x
.Extensions
["2.5.29.14"] as X509SubjectKeyIdentifierExtension
);
270 value_match
= (String
.Compare (str
, ski
.SubjectKeyIdentifier
, true, cinv
) == 0);
273 case X509FindType
.FindByApplicationPolicy
:
274 // note: include when no extensions are present (even if v3)
275 value_match
= (x
.Extensions
.Count
== 0);
276 // TODO - find test case with extension
278 case X509FindType
.FindByCertificatePolicy
:
279 // TODO - find test case with extension
281 case X509FindType
.FindByExtension
:
282 value_match
= (x
.Extensions
[oid
] != null);
284 case X509FindType
.FindByKeyUsage
:
285 X509KeyUsageExtension kue
= (x
.Extensions
["2.5.29.15"] as X509KeyUsageExtension
);
287 // key doesn't have any hard coded limitations
288 // note: MS doesn't check for ExtendedKeyUsage
291 value_match
= ((kue
.KeyUsages
& ku
) == ku
);
294 case X509FindType
.FindByTimeValid
:
295 value_match
= ((dt
>= x
.NotBefore
) && (dt
<= x
.NotAfter
));
297 case X509FindType
.FindByTimeNotYetValid
:
298 value_match
= (dt
< x
.NotBefore
);
300 case X509FindType
.FindByTimeExpired
:
301 value_match
= (dt
> x
.NotAfter
);
322 public new X509Certificate2Enumerator
GetEnumerator ()
324 return new X509Certificate2Enumerator (this);
327 [MonoTODO ("same limitations as X509Certificate2.Import")]
328 public void Import (byte[] rawData
)
330 // FIXME: can it import multiple certificates, e.g. a pkcs7 file ?
331 X509Certificate2 cert
= new X509Certificate2 ();
332 cert
.Import (rawData
);
336 [MonoTODO ("same limitations as X509Certificate2.Import")]
337 public void Import (byte[] rawData
, string password
, X509KeyStorageFlags keyStorageFlags
)
339 // FIXME: can it import multiple certificates, e.g. a pkcs7 file ?
340 X509Certificate2 cert
= new X509Certificate2 ();
341 cert
.Import (rawData
, password
, keyStorageFlags
);
345 [MonoTODO ("same limitations as X509Certificate2.Import")]
346 public void Import (string fileName
)
348 // FIXME: can it import multiple certificates, e.g. a pkcs7 file ?
349 X509Certificate2 cert
= new X509Certificate2 ();
350 cert
.Import (fileName
);
354 [MonoTODO ("same limitations as X509Certificate2.Import")]
355 public void Import (string fileName
, string password
, X509KeyStorageFlags keyStorageFlags
)
357 // FIXME: can it import multiple certificates, e.g. a pkcs7 file ?
358 X509Certificate2 cert
= new X509Certificate2 ();
359 cert
.Import (fileName
, password
, keyStorageFlags
);
363 public void Insert (int index
, X509Certificate2 certificate
)
365 if (certificate
== null)
366 throw new ArgumentNullException ("certificate");
368 throw new ArgumentOutOfRangeException ("negative index");
369 if (index
>= InnerList
.Count
)
370 throw new ArgumentOutOfRangeException ("index >= Count");
372 InnerList
.Insert (index
, certificate
);
375 public void Remove (X509Certificate2 certificate
)
377 if (certificate
== null)
378 throw new ArgumentNullException ("certificate");
380 for (int i
=0; i
< InnerList
.Count
; i
++) {
381 X509Certificate c
= (X509Certificate
) InnerList
[i
];
382 if (c
.Equals (certificate
)) {
383 InnerList
.RemoveAt (i
);
384 // only first instance is removed
390 [MonoTODO ("Method isn't transactional (like documented)")]
391 public void RemoveRange (X509Certificate2
[] certificates
)
393 if (certificates
== null)
394 throw new ArgumentNullException ("certificate");
396 foreach (X509Certificate2 x
in certificates
)
400 [MonoTODO ("Method isn't transactional (like documented)")]
401 public void RemoveRange (X509Certificate2Collection certificates
)
403 if (certificates
== null)
404 throw new ArgumentNullException ("certificate");
406 foreach (X509Certificate2 x
in certificates
)