PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/tools/security/certmgr.cs

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