[w32file] Move MonoIO.Find{First,Next,Close} to managed
[mono.git] / mcs / tools / security / certmgr.cs
1 //
2 // CertMgr.cs: Certificate Manager clone tool (CLI version)
3 //
4 // Author:
5 //      Sebastien Pouliot  <sebastien@ximian.com>
6 //
7 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
8 //
9
10 using System;
11 using System.Collections;
12 using System.Globalization;
13 using System.IO;
14 using System.Net;
15 using System.Net.Sockets;
16 using System.Reflection;
17 using System.Security.Cryptography;
18 using SSCX = System.Security.Cryptography.X509Certificates;
19 using System.Text;
20
21 using Mono.Security.Authenticode;
22 using Mono.Security.Cryptography;
23 using Mono.Security.X509;
24 using Mono.Security.Protocol.Tls;
25
26 [assembly: AssemblyTitle ("Mono Certificate Manager")]
27 [assembly: AssemblyDescription ("Manage X.509 certificates and CRL from stores.")]
28
29 namespace Mono.Tools {
30
31         class CertificateManager {
32
33                 static private void Header () 
34                 {
35                         Console.WriteLine (new AssemblyInfo ().ToString ());
36                 }
37
38                 static private void Help () 
39                 {
40                         Console.WriteLine ("Usage: certmgr [action] [object-type] [options] store [filename]");
41                         Console.WriteLine ("   or: certmgr -list object-type [options] store");
42                         Console.WriteLine ("   or: certmgr -del object-type [options] store certhash");
43                         Console.WriteLine ("   or: certmgr -ssl [options] url");
44                         Console.WriteLine ("   or: certmgr -put object-type [options] store certfile");
45                         Console.WriteLine ("   or: certmgr -importKey [options] store pkcs12file");
46                         Console.WriteLine ();
47                         Console.WriteLine ("actions");
48                         Console.WriteLine ("\t-add\t\tAdd a certificate, CRL or CTL to specified store");
49                         Console.WriteLine ("\t-del\t\tRemove a certificate, CRL or CTL to specified store");
50                         Console.WriteLine ("\t-put\t\tCopy a certificate, CRL or CTL from a store to a file");
51                         Console.WriteLine ("\t-list\t\tList certificates, CRL or CTL in the specified store.");
52                         Console.WriteLine ("\t-ssl\t\tDownload and add certificates from an SSL session");
53                         Console.WriteLine ("\t-importKey\tImport PKCS12 privateKey to keypair store.");
54                         Console.WriteLine ("object types");
55                         Console.WriteLine ("\t-c\t\tadd/del/put certificates");
56                         Console.WriteLine ("\t-crl\t\tadd/del/put certificate revocation lists");
57                         Console.WriteLine ("\t-ctl\t\tadd/del/put certificate trust lists [unsupported]");
58                         Console.WriteLine ("other options");
59                         Console.WriteLine ("\t-m\t\tuse the machine certificate store (default to user)");
60                         Console.WriteLine ("\t-v\t\tverbose mode (display status for every steps)");
61                         Console.WriteLine ("\t-p [password]\tPassword used to decrypt PKCS12");
62                         Console.WriteLine ("\t-pem\t\tPut certificate in Base-64 encoded format (default DER encoded)");
63                         Console.WriteLine ("\t-?\t\th[elp]\tDisplay this help message");
64                         Console.WriteLine ();
65                 }
66
67                 static string GetCommand (string arg) 
68                 {
69                         if ((arg == null) || (arg.Length < 1))
70                                 return null;
71
72                         switch (arg [0]) {
73                                 case '/':
74                                         return arg.Substring (1).ToUpper ();
75                                 case '-':
76                                         if (arg.Length < 2)
77                                                 return null;
78                                         int n = ((arg [1] == '-') ? 2 : 1);
79                                         return arg.Substring (n).ToUpper ();
80                                 default:
81                                         return arg;
82                         }
83                 }
84
85                 enum Action {
86                         None,
87                         Add,
88                         Delete,
89                         Put,
90                         List,
91                         Ssl,
92                         ImportKey
93                 }
94
95                 static Action GetAction (string arg) 
96                 {
97                         Action action = Action.None;
98                         switch (GetCommand (arg)) {
99                                 case "ADD":
100                                         action = Action.Add;
101                                         break;
102                                 case "DEL":
103                                 case "DELETE":
104                                         action = Action.Delete;
105                                         break;
106                                 case "PUT":
107                                         action = Action.Put;
108                                         break;
109                                 case "LST":
110                                 case "LIST":
111                                         action = Action.List;
112                                         break;
113                                 case "SSL":
114                                 case "TLS":
115                                         action = Action.Ssl;
116                                         break;
117                                 case "IMPORTKEY":
118                                         action = Action.ImportKey;
119                                         break;
120                         }
121                         return action;
122                 }
123
124                 enum ObjectType {
125                         None,
126                         Certificate,
127                         CRL,
128                         CTL
129                 }
130
131                 static ObjectType GetObjectType (string arg) 
132                 {
133                         ObjectType type = ObjectType.None;
134                         switch (GetCommand (arg)) {
135                                 case "C":
136                                 case "CERT":
137                                 case "CERTIFICATE":
138                                         type = ObjectType.Certificate;
139                                         break;
140                                 case "CRL":
141                                         type = ObjectType.CRL;
142                                         break;
143                                 case "CTL":
144                                         type = ObjectType.CTL;
145                                         break;
146                         }
147                         return type;
148                 }
149
150                 static X509Store GetStoreFromName (string storeName, bool machine) 
151                 {
152                         X509Stores stores = ((machine) ? X509StoreManager.LocalMachine : X509StoreManager.CurrentUser);
153                         X509Store store = null;
154                         switch (storeName) {
155                                 case X509Stores.Names.Personal:
156                                         return stores.Personal;
157                                 case X509Stores.Names.OtherPeople:
158                                         return stores.OtherPeople;
159                                 case X509Stores.Names.IntermediateCA:
160                                         return stores.IntermediateCA;
161                                 case "Root": // special case (same as trusted root)
162                                 case X509Stores.Names.TrustedRoot:
163                                         return stores.TrustedRoot;
164                                 case X509Stores.Names.Untrusted:
165                                         return stores.Untrusted;
166                         }
167                         return store;
168                 }
169
170                 static byte[] PEM (string type, byte[] data) 
171                 {
172                         string pem = Encoding.ASCII.GetString (data);
173                         string header = String.Format ("-----BEGIN {0}-----", type);
174                         string footer = String.Format ("-----END {0}-----", type);
175                         int start = pem.IndexOf (header) + header.Length;
176                         int end = pem.IndexOf (footer, start);
177                         string base64 = pem.Substring (start, (end - start));
178                         return Convert.FromBase64String (base64);
179                 }
180                 
181                 static byte[] ToPEM (string type, byte[] data)
182                 {
183                         string header = String.Format ("-----BEGIN {0}-----", type);
184                         string footer = String.Format ("-----END {0}-----", type);
185                         
186                         string encodedString = Convert.ToBase64String (data);
187
188                         StringBuilder sb = new StringBuilder ();
189                         int remaining = encodedString.Length;
190                         sb.AppendLine (header);
191                         for (int i = 0; i <= encodedString.Length; i += 64) {
192                                 if (remaining >= 64) {
193                                         sb.AppendLine (encodedString.Substring (i, 64));
194                                 } else {
195                                         sb.AppendLine (encodedString.Substring (i, remaining));
196                                 }
197                                 remaining -= 64;
198                         }
199                         sb.AppendLine (footer);
200                         return Encoding.ASCII.GetBytes (sb.ToString ());
201                 }
202
203                 static X509CertificateCollection LoadCertificates (string filename, string password, bool verbose) 
204                 {
205                         X509Certificate x509 = null;
206                         X509CertificateCollection coll = new X509CertificateCollection ();
207                         switch (Path.GetExtension (filename).ToUpper ()) {
208                                 case ".P7B":
209                                 case ".SPC":
210                                         SoftwarePublisherCertificate spc = SoftwarePublisherCertificate.CreateFromFile (filename);
211                                         coll.AddRange (spc.Certificates);
212                                         spc = null;
213                                         break;
214                                 case ".CER":
215                                 case ".CRT":
216                                         using (FileStream fs = File.OpenRead (filename)) {
217                                                 byte[] data = new byte [fs.Length];
218                                                 fs.Read (data, 0, data.Length);
219                                                 if (data [0] != 0x30) {
220                                                         // maybe it's ASCII PEM base64 encoded ?
221                                                         data = PEM ("CERTIFICATE", data);
222                                                 }
223                                                 if (data != null)
224                                                         x509 = new X509Certificate (data);
225                                         }
226                                         if (x509 != null)
227                                                 coll.Add (x509);
228                                         break;
229                                 case ".P12":
230                                 case ".PFX":
231                                         PKCS12 p12 = password == null ? PKCS12.LoadFromFile (filename)
232                                                 : PKCS12.LoadFromFile (filename, password);
233                                         X509CertificateCollection tmp = new X509CertificateCollection (p12.Certificates);
234
235                                         for (int i = 0; i != p12.Keys.Count; i++) {
236                                                 X509Certificate cert = p12.Certificates[i];
237                                                 RSACryptoServiceProvider pk = p12.Keys[i] as RSACryptoServiceProvider;
238
239                                                 if (pk == null || pk.PublicOnly)
240                                                         continue;
241
242                                                 if (verbose)
243                                                         Console.WriteLine ("Found key for certificate: {0}", cert.SubjectName);
244
245                                                 tmp[0].RSA = pk;
246                                         }
247                                         coll.AddRange(tmp);
248                                         p12 = null;
249                                         break;
250                                 default:
251                                         Console.WriteLine ("Unknown file extension: {0}", 
252                                                 Path.GetExtension (filename));
253                                         break;
254                         }
255                         return coll;
256                 }
257
258                 static ArrayList LoadCRLs (string filename) 
259                 {
260                         X509Crl crl = null;
261                         ArrayList list = new ArrayList ();
262                         switch (Path.GetExtension (filename).ToUpper ()) {
263                                 case ".P7B":
264                                 case ".SPC":
265                                         SoftwarePublisherCertificate spc = SoftwarePublisherCertificate.CreateFromFile (filename);
266                                         list.AddRange (spc.Crls);
267                                         spc = null;
268                                         break;
269                                 case ".CRL":
270                                         using (FileStream fs = File.OpenRead (filename)) {
271                                                 byte[] data = new byte [fs.Length];
272                                                 fs.Read (data, 0, data.Length);
273                                                 crl = new X509Crl (data);
274                                         }
275                                         list.Add (crl);
276                                         break;
277                                 default:
278                                         Console.WriteLine ("Unknown file extension: {0}", 
279                                                 Path.GetExtension (filename));
280                                         break;
281                         }
282                         return list;
283                 }
284
285                 static void Add (ObjectType type, X509Store store, string file, string password, bool verbose) 
286                 {
287                         switch (type) {
288                                 case ObjectType.Certificate:
289                                         X509CertificateCollection coll = LoadCertificates (file, password, verbose);
290                                         foreach (X509Certificate x509 in coll) {
291                                                 store.Import (x509);
292                                         }
293                                         Console.WriteLine ("{0} certificate(s) added to store {1}.", 
294                                                 coll.Count, store.Name);
295                                         break;
296                                 case ObjectType.CRL:
297                                         ArrayList list = LoadCRLs (file);
298                                         foreach (X509Crl crl in list) {
299                                                 store.Import (crl);
300                                         }
301                                         Console.WriteLine ("{0} CRL(s) added to store {1}.", 
302                                                 list.Count, store.Name);
303                                         break;
304                                 default:
305                                         throw new NotSupportedException (type.ToString ());
306                         }
307                 }
308
309                 static void Delete (ObjectType type, X509Store store, string hash, bool verbose) 
310                 {
311                         switch (type) {
312                                 case ObjectType.Certificate:
313                                         foreach (X509Certificate x509 in store.Certificates) {
314                                                 if (hash == CryptoConvert.ToHex (x509.Hash)) {
315                                                         store.Remove (x509);
316                                                         Console.WriteLine ("Certificate removed from store.");
317                                                         return;
318                                                 }
319                                         }
320                                         break;
321                                 case ObjectType.CRL:
322                                         foreach (X509Crl crl in store.Crls) {
323                                                 if (hash == CryptoConvert.ToHex (crl.Hash)) {
324                                                         store.Remove (crl);
325                                                         Console.WriteLine ("CRL removed from store.");
326                                                         return;
327                                                 }
328                                         }
329                                         break;
330                                 default:
331                                         throw new NotSupportedException (type.ToString ());
332                         }
333                 }
334
335                 static void Put (ObjectType type, X509Store store, string file, bool machine, bool pem, bool verbose) 
336                 {
337                         if (String.IsNullOrEmpty (file)) {
338                                 Console.Error.WriteLine("error: no filename provided to put the certificate.");
339                                 Help();
340                                 return;
341                         }
342
343                         switch (type) {
344                         case ObjectType.Certificate:
345                                 for(int i = 0; i < store.Certificates.Count; i++) {
346                                         Console.WriteLine ("==============Certificate # {0} ==========", i + 1);
347                                         DisplayCertificate (store.Certificates[i], machine, verbose);
348                                 }
349                                 int selection;
350                                 Console.Write("Enter cert # from the above list to put-->");
351                                 if (!int.TryParse(Console.ReadLine(), out selection) || selection > store.Certificates.Count) {
352                                         Console.Error.WriteLine ("error: invalid selection.");
353                                         return;
354                                 }
355                         
356                                 SSCX.X509Certificate2 cert = new SSCX.X509Certificate2 (store.Certificates[selection-1].RawData);
357                                 byte[] data = null;
358                                 if(pem) {
359                                         data = ToPEM ("CERTIFICATE", cert.Export (SSCX.X509ContentType.Cert));
360                                 } else {
361                                         data = cert.Export (SSCX.X509ContentType.Cert);
362                                 }
363                                 
364                                 using (FileStream fs = File.Create (file)) {
365                                         fs.Write(data, 0, data.Length);
366                                 }
367                                 
368                                 Console.WriteLine ("Certificate put to {0}.", file);
369                                 break;
370                         default:
371                                 throw new NotSupportedException ("Put " + type + " not supported yet");
372                         }
373                 }
374
375                 static void DisplayCertificate (X509Certificate x509, bool machine, bool verbose)
376                 {
377                         Console.WriteLine ("{0}X.509 v{1} Certificate", (x509.IsSelfSigned ? "Self-signed " : String.Empty), x509.Version);
378                         Console.WriteLine ("  Serial Number: {0}", CryptoConvert.ToHex (x509.SerialNumber));
379                         Console.WriteLine ("  Issuer Name:   {0}", x509.IssuerName);
380                         Console.WriteLine ("  Subject Name:  {0}", x509.SubjectName);
381                         Console.WriteLine ("  Valid From:    {0}", x509.ValidFrom);
382                         Console.WriteLine ("  Valid Until:   {0}", x509.ValidUntil);
383                         Console.WriteLine ("  Unique Hash:   {0}", CryptoConvert.ToHex (x509.Hash));
384                         if (verbose) {
385                                 Console.WriteLine ("  Key Algorithm:        {0}", x509.KeyAlgorithm);
386                                 Console.WriteLine ("  Algorithm Parameters: {0}", (x509.KeyAlgorithmParameters == null) ? "None" :
387                                         CryptoConvert.ToHex (x509.KeyAlgorithmParameters));
388                                 Console.WriteLine ("  Public Key:           {0}", CryptoConvert.ToHex (x509.PublicKey));
389                                 Console.WriteLine ("  Signature Algorithm:  {0}", x509.SignatureAlgorithm);
390                                 Console.WriteLine ("  Algorithm Parameters: {0}", (x509.SignatureAlgorithmParameters == null) ? "None" :
391                                         CryptoConvert.ToHex (x509.SignatureAlgorithmParameters));
392                                 Console.WriteLine ("  Signature:            {0}", CryptoConvert.ToHex (x509.Signature));
393                                 RSACryptoServiceProvider rsaCsp = x509.RSA as RSACryptoServiceProvider;
394                                 RSAManaged rsaManaged = x509.RSA as RSAManaged;
395                                 Console.WriteLine ("  Private Key:                      {0}", ((rsaCsp != null && !rsaCsp.PublicOnly) 
396                                         || (rsaManaged != null && !rsaManaged.PublicOnly)));
397                                 CspParameters cspParams = new CspParameters ();
398                                 cspParams.KeyContainerName = CryptoConvert.ToHex (x509.Hash);
399                                 cspParams.Flags = machine ? CspProviderFlags.UseMachineKeyStore : 0;
400                                 KeyPairPersistence kpp = new KeyPairPersistence (cspParams);
401                                 Console.WriteLine ("  KeyPair Key:                      {0}", kpp.Load ());
402                         }
403                         Console.WriteLine ();
404                 }
405
406                 static void DisplayCrl (X509Crl crl, bool machine, bool verbose)
407                 {
408                         Console.WriteLine ("X.509 v{0} CRL", crl.Version);
409                         Console.WriteLine ("  Issuer Name:   {0}", crl.IssuerName);
410                         Console.WriteLine ("  This Update:   {0}", crl.ThisUpdate);
411                         Console.WriteLine ("  Next Update:   {0} {1}", crl.NextUpdate, crl.IsCurrent ? String.Empty : "update overdue!");
412                         Console.WriteLine ("  Unique Hash:   {0}", CryptoConvert.ToHex (crl.Hash));
413                         if (verbose) {
414                                 Console.WriteLine ("  Signature Algorithm:  {0}", crl.SignatureAlgorithm);
415                                 Console.WriteLine ("  Signature:            {0}", CryptoConvert.ToHex (crl.Signature));
416                                 int n = 0;
417                                 foreach (X509Crl.X509CrlEntry entry in crl.Entries) {
418                                         Console.WriteLine ("    #{0}: Serial: {1} revoked on {2}",
419                                                 ++n, CryptoConvert.ToHex (entry.SerialNumber), entry.RevocationDate);
420                                 }
421                         }
422                 }
423
424                 static void List (ObjectType type, X509Store store, bool machine, string file, bool verbose) 
425                 {
426                         switch (type) {
427                                 case ObjectType.Certificate:
428                                         foreach (X509Certificate x509 in store.Certificates) {
429                                                 DisplayCertificate (x509, machine, verbose);
430                                         }
431                                         break;
432                                 case ObjectType.CRL:
433                                         foreach (X509Crl crl in store.Crls) {
434                                                 DisplayCrl (crl, machine, verbose);
435                                         }
436                                         break;
437                                 default:
438                                         throw new NotSupportedException (type.ToString ());
439                         }
440                 }
441
442                 static X509CertificateCollection GetCertificatesFromSslSession (string url) 
443                 {
444                         Uri uri = new Uri (url);
445                         IPHostEntry host = Dns.Resolve (uri.Host);
446                         IPAddress ip = host.AddressList [0];
447                         Socket socket = new Socket (ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
448                         socket.Connect (new IPEndPoint (ip, uri.Port));
449                         NetworkStream ns = new NetworkStream (socket, false);
450                         SslClientStream ssl = new SslClientStream (ns, uri.Host, false, Mono.Security.Protocol.Tls.SecurityProtocolType.Default, null);
451                         ssl.ServerCertValidationDelegate += new CertificateValidationCallback (CertificateValidation);
452
453                         try {
454                                 // we don't really want to write to the server (as we don't know
455                                 // the protocol it using) but we must send something to be sure the
456                                 // SSL handshake is done (so we receive the X.509 certificates).
457                                 StreamWriter sw = new StreamWriter (ssl);
458                                 sw.WriteLine (Environment.NewLine);
459                                 sw.Flush ();
460                                 socket.Poll (30000, SelectMode.SelectRead);
461                         }
462                         finally {
463                                 socket.Close ();
464                         }
465
466                         // we need a little reflection magic to get this information
467                         PropertyInfo pi = typeof (SslStreamBase).GetProperty ("ServerCertificates", BindingFlags.Instance | BindingFlags.NonPublic);
468                         if (pi == null) {
469                                 Console.WriteLine ("Sorry but you need a newer version of Mono.Security.dll to use this feature.");
470                                 return null;
471                         }
472                         return (X509CertificateCollection) pi.GetValue (ssl, null);
473                 }
474
475                 static bool CertificateValidation (SSCX.X509Certificate certificate, int[] certificateErrors)
476                 {
477                         // the main reason to download it is that it's not trusted
478                         return true;
479                         // OTOH we ask user confirmation before adding certificates into the stores
480                 }
481
482                 static void Ssl (string host, bool machine, bool verbose) 
483                 {
484                         if (verbose) {
485                                 Console.WriteLine ("Importing certificates from '{0}' into the {1} stores.",
486                                         host, machine ? "machine" : "user");
487                         }
488                         int n=0;
489
490                         X509CertificateCollection coll = GetCertificatesFromSslSession (host);
491                         if (coll != null) {
492                                 X509Store store = null;
493                                 // start by the end (root) so we can stop adding them anytime afterward
494                                 for (int i = coll.Count - 1; i >= 0; i--) {
495                                         X509Certificate x509 = coll [i];
496                                         bool selfsign = false;
497                                         bool failed = false;
498                                         try {
499                                                 selfsign = x509.IsSelfSigned;
500                                         }
501                                         catch {
502                                                 // sadly it's hard to interpret old certificates with MD2
503                                                 // without manually changing the machine.config file
504                                                 failed = true;
505                                         }
506
507                                         if (selfsign) {
508                                                 // this is a root
509                                                 store = GetStoreFromName (X509Stores.Names.TrustedRoot, machine);
510                                         } else if (i == 0) {
511                                                 // server certificate isn't (generally) an intermediate CA
512                                                 store = GetStoreFromName (X509Stores.Names.OtherPeople, machine);
513                                         } else {
514                                                 // all other certificates should be intermediate CA
515                                                 store = GetStoreFromName (X509Stores.Names.IntermediateCA, machine);
516                                         }
517
518                                         Console.WriteLine ("{0}{1}X.509 Certificate v{2}",      
519                                                 Environment.NewLine,
520                                                 selfsign ? "Self-signed " : String.Empty,
521                                                 x509.Version);
522                                         Console.WriteLine ("   Issued from: {0}", x509.IssuerName);
523                                         Console.WriteLine ("   Issued to:   {0}", x509.SubjectName);
524                                         Console.WriteLine ("   Valid from:  {0}", x509.ValidFrom);
525                                         Console.WriteLine ("   Valid until: {0}", x509.ValidUntil);
526
527                                         if (!x509.IsCurrent)
528                                                 Console.WriteLine ("   *** WARNING: Certificate isn't current ***");
529                                         if ((i > 0) && !selfsign) {
530                                                 X509Certificate signer = coll [i-1];
531                                                 bool signed = false;
532                                                 try {
533                                                         if (signer.RSA != null) {
534                                                                 signed = x509.VerifySignature (signer.RSA);
535                                                         } else if (signer.DSA != null) {
536                                                                 signed = x509.VerifySignature (signer.DSA);
537                                                         } else {
538                                                                 Console.WriteLine ("   *** WARNING: Couldn't not find who signed this certificate ***");
539                                                                 signed = true; // skip next warning
540                                                         }
541
542                                                         if (!signed)
543                                                                 Console.WriteLine ("   *** WARNING: Certificate signature is INVALID ***");
544                                                 }
545                                                 catch {
546                                                         failed = true;
547                                                 }
548                                         }
549                                         if (failed) {
550                                                 Console.WriteLine ("   *** ERROR: Couldn't decode certificate properly ***");
551                                                 Console.WriteLine ("   *** try 'man certmgr' for additional help or report to bugzilla.novell.com ***");
552                                                 break;
553                                         }
554
555                                         if (store.Certificates.Contains (x509)) {
556                                                 Console.WriteLine ("This certificate is already in the {0} store.", store.Name);
557                                         } else {
558                                                 Console.Write ("Import this certificate into the {0} store ?", store.Name);
559                                                 string answer = Console.ReadLine ().ToUpper ();
560                                                 if ((answer == "YES") || (answer == "Y")) {
561                                                         store.Import (x509);
562                                                         n++;
563                                                 } else {
564                                                         if (verbose) {
565                                                                 Console.WriteLine ("Certificate not imported into store {0}.", 
566                                                                         store.Name);
567                                                         }
568                                                         break;
569                                                 }
570                                         }
571                                 }
572                         }
573
574                         Console.WriteLine ();
575                         if (n == 0) {
576                                 Console.WriteLine ("No certificate were added to the stores.");
577                         } else {
578                                 Console.WriteLine ("{0} certificate{1} added to the stores.", 
579                                         n, (n == 1) ? String.Empty : "s");
580                         }
581                 }
582
583                 static void ImportKey (ObjectType type, bool machine, string file, string password, bool verbose)
584                 {
585                         switch (type) {
586                                 case ObjectType.Certificate:
587                                         X509CertificateCollection coll = LoadCertificates (file, password, verbose);
588                                         int count = 0;
589
590                                         foreach (X509Certificate x509 in coll) {
591                                                 RSACryptoServiceProvider pk = x509.RSA as RSACryptoServiceProvider;
592
593                                                 if (pk == null || pk.PublicOnly)
594                                                         continue;
595
596                                                 CspParameters csp = new CspParameters ();
597                                                 csp.KeyContainerName = CryptoConvert.ToHex (x509.Hash);
598                                                 csp.Flags = machine ? CspProviderFlags.UseMachineKeyStore : 0;
599                                                 RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (csp);
600                                                 rsa.ImportParameters (pk.ExportParameters (true));
601                                                 rsa.PersistKeyInCsp = true;
602                                                 count++;
603                                         }
604                                         Console.WriteLine ("{0} keys(s) imported to KeyPair {1} persister.", 
605                                                 count, machine ? "LocalMachine" : "CurrentUser");
606                                         break;
607                                 default:
608                                         throw new NotSupportedException (type.ToString ());
609                         }
610                 }
611
612                 [STAThread]
613                 static void Main (string[] args)
614                 {
615                         string password = null;
616                         bool verbose = false;
617                         bool pem = false;
618                         bool machine = false;
619
620                         Header ();
621                         if (args.Length < 2) {
622                                 Help ();
623                                 return;
624                         }
625
626                         Action action = GetAction (args [0]);
627                         ObjectType type = ObjectType.None;
628
629                         int n = 1;
630                         if (action != Action.Ssl) {
631                                 type = GetObjectType (args [n]);
632                                 if (type != ObjectType.None)
633                                         n++;
634                         }
635                         
636                         for (int i = n; i < args.Length; i++) {
637                                 switch (GetCommand (args[i])) {
638                                 case "V":
639                                         verbose = true;
640                                         n++;
641                                         break;
642                                 case "M":
643                                         machine = true;
644                                         n++;
645                                         break;
646                                 case "P":
647                                         password = args[++n];
648                                         n++;
649                                         break;
650                                 case "PEM":
651                                         pem = true;
652                                         n++;
653                                         break;
654                                 }
655                         }
656                         
657                         X509Store store = null;
658                         string storeName = null;
659                         if (action != Action.Ssl) {
660                                 if ((action == Action.None) || (type == ObjectType.None)) {
661                                         Help ();
662                                         return;
663                                 }
664                                 if (type == ObjectType.CTL) {
665                                         Console.WriteLine ("CTL are not supported");
666                                         return;
667                                 }
668
669                                 storeName = args [n++];
670                                 store = GetStoreFromName (storeName, machine);
671                                 if (store == null) {
672                                         Console.WriteLine ("Invalid Store: {0}", storeName);
673                                         Console.WriteLine ("Valid stores are: {0}, {1}, {2}, {3} and {4}",
674                                                 X509Stores.Names.Personal,
675                                                 X509Stores.Names.OtherPeople, 
676                                                 X509Stores.Names.IntermediateCA, 
677                                                 X509Stores.Names.TrustedRoot, 
678                                                 X509Stores.Names.Untrusted);
679                                         return;
680                                 }
681                         }
682
683                         string file = (n < args.Length) ? args [n] : null;
684
685                         // now action!
686                         try {
687                                 switch (action) {
688                                 case Action.Add:
689                                         Add (type, store, file, password, verbose);
690                                         break;
691                                 case Action.Delete:
692                                         Delete (type, store, file, verbose);
693                                         break;
694                                 case Action.Put:
695                                         Put (type, store, file, machine, pem, verbose);
696                                         break;
697                                 case Action.List:
698                                         List (type, store, machine, file, verbose);
699                                         break;
700                                 case Action.Ssl:
701                                         Ssl (file, machine, verbose);
702                                         break;
703                                 case Action.ImportKey:
704                                         ImportKey (type, machine, file, password, verbose);
705                                         break;
706                                 default:
707                                         throw new NotSupportedException (action.ToString ());
708                                 }
709                         }
710                         catch (UnauthorizedAccessException uae) {
711                                 Console.WriteLine ("Access to the {0} '{1}' certificate store has been denied.", 
712                                         (machine ? "machine" : "user"), storeName);
713                                 if (verbose) {
714                                         Console.WriteLine (uae);
715                                 }
716                         }
717                 }
718         }
719 }