Add a tool which can sync the Mono cert store from an arbitrary cert bundle (i.e...
authorJo Shields <jo.shields@xamarin.com>
Mon, 22 Sep 2014 12:37:36 +0000 (13:37 +0100)
committerJo Shields <jo.shields@xamarin.com>
Mon, 22 Sep 2014 13:02:03 +0000 (14:02 +0100)
mcs/tools/security/Makefile
mcs/tools/security/cert-sync.cs [new file with mode: 0644]
scripts/Makefile.am

index c9baa67ccfeeb03264046f7da6961b7ffc78692c..ba771b51660dac6eb01f7d228211b65e14f07c5a 100644 (file)
@@ -6,7 +6,7 @@ include ../../build/rules.make
 LOCAL_MCS_FLAGS = /lib:$(topdir)/class/lib/$(PROFILE) -r:Mono.Security.dll
 
 SECURITY_PROGRAMS = secutil.exe cert2spc.exe sn.exe makecert.exe chktrust.exe crlupdate.exe \
-       signcode.exe setreg.exe certmgr.exe caspol.exe permview.exe mozroots.exe
+       signcode.exe setreg.exe certmgr.exe caspol.exe permview.exe mozroots.exe cert-sync.exe
 SECURITY_PROGRAMS_2_0 = httpcfg.exe
 
 HELPER_SOURCES = AssemblyInfo.cs $(topdir)/build/common/Consts.cs
diff --git a/mcs/tools/security/cert-sync.cs b/mcs/tools/security/cert-sync.cs
new file mode 100644 (file)
index 0000000..4428067
--- /dev/null
@@ -0,0 +1,226 @@
+//
+// cert-sync.cs: Import the root certificates from Linux SSL store into Mono
+//
+// Authors:
+//     Sebastien Pouliot <sebastien@ximian.com>
+//     Jo Shields <jo.shields@xamarin.com>
+//
+// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2014 Xamarin, Inc (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+
+using Mono.Security.X509;
+
+[assembly: AssemblyTitle ("Linux Cert Store Sync")]
+[assembly: AssemblyDescription ("Synchronize local certs with certs from local Linux trust store.")]
+
+namespace Mono.Tools
+{
+
+       class CertSync
+       {
+       
+               static string inputFile;
+               static bool quiet;
+
+               static X509Certificate DecodeCertificate (string s)
+               {
+                       byte[] rawdata = Convert.FromBase64String (s);
+                       return new X509Certificate (rawdata);
+               }
+
+               static Stream GetFile ()
+               {
+                       try {
+                               if (inputFile != null) {
+                                       return File.OpenRead (inputFile);
+                               } else {
+                                       return null;
+                               }
+                       } catch {
+                               return null;
+                       }
+               }
+
+               static X509CertificateCollection DecodeCollection ()
+               {
+                       X509CertificateCollection roots = new X509CertificateCollection ();
+                       StringBuilder sb = new StringBuilder ();
+                       bool processing = false;
+
+                       using (Stream s = GetFile ()) {
+                               if (s == null) {
+                                       WriteLine ("Couldn't retrieve the file using the supplied information.");
+                                       return null;
+                               }
+
+                               StreamReader sr = new StreamReader (s);
+                               while (true) {
+                                       string line = sr.ReadLine ();
+                                       if (line == null)
+                                               break;
+
+                                       if (processing) {
+                                               if (line.StartsWith ("-----END CERTIFICATE-----")) {
+                                                       processing = false;
+                                                       X509Certificate root = DecodeCertificate (sb.ToString ());
+                                                       roots.Add (root);
+
+                                                       sb = new StringBuilder ();
+                                                       continue;
+                                               }
+                                               sb.Append (line);
+                                       } else {
+                                               processing = line.StartsWith ("-----BEGIN CERTIFICATE-----");
+                                       }
+                               }
+                               return roots;
+                       }
+               }
+
+               static int Process ()
+               {
+                       X509CertificateCollection roots = DecodeCollection ();
+                       if (roots == null) {
+                               return 1;
+                       } else if (roots.Count == 0) {
+                               WriteLine ("No certificates were found.");
+                               return 0;
+                       }
+                               
+                       X509Stores stores = (X509StoreManager.LocalMachine);
+                       X509CertificateCollection trusted = stores.TrustedRoot.Certificates;
+                       int additions = 0;
+                       WriteLine ("I already trust {0}, your new list has {1}", trusted.Count, roots.Count);
+                       foreach (X509Certificate root in roots) {
+                               if (!trusted.Contains (root)) {
+                                       try {
+                                               stores.TrustedRoot.Import (root);
+                                               WriteLine ("Certificate added: {0}", root.SubjectName);
+                                       } catch {
+                                               WriteLine ("Warning: Could not import {0}");
+                                       }
+                                       additions++;
+                               }
+                       }
+                       if (additions > 0)
+                               WriteLine ("{0} new root certificates were added to your trust store.", additions);
+
+                       X509CertificateCollection removed = new X509CertificateCollection ();
+                       foreach (X509Certificate trust in trusted) {
+                               if (!roots.Contains (trust)) {
+                                       removed.Add (trust);
+                               }
+                       }
+                       if (removed.Count > 0) {
+                               WriteLine ("{0} previously trusted certificates were removed.", removed.Count);
+
+                               foreach (X509Certificate old in removed) {
+                                       stores.TrustedRoot.Remove (old);
+                                       WriteLine ("Certificate removed: {0}", old.SubjectName);
+                               }
+                       }
+                       WriteLine ("Import process completed.");
+                       return 0;
+               }
+
+               static string Thumbprint (string algorithm, X509Certificate certificate)
+               {
+                       HashAlgorithm hash = HashAlgorithm.Create (algorithm);
+                       byte[] digest = hash.ComputeHash (certificate.RawData);
+                       return BitConverter.ToString (digest);
+               }
+
+               static bool ParseOptions (string[] args)
+               {
+                       if (args.Length < 1)
+                               return false;
+
+                       for (int i = 0; i < args.Length - 1; i++) {
+                               switch (args [i]) {
+                               case "--quiet":
+                                       quiet = true;
+                                       break;
+                               default:
+                                       WriteLine ("Unknown option '{0}'.");
+                                       return false;
+                               }
+                       }
+                       inputFile = args [args.Length - 1];
+                       if (!File.Exists (inputFile)) {
+                               WriteLine ("Unknown option or file not found '{0}'.");
+                               return false;
+                       }
+                       return true;
+               }
+
+               static void Header ()
+               {
+                       Console.WriteLine (new AssemblyInfo ().ToString ());
+               }
+
+               static void Help ()
+               {
+                       Console.WriteLine ("Usage: cert-sync [--quiet] system-ca-bundle.crt");
+                       Console.WriteLine ("Where system-ca-bundle.crt is in PEM format");
+               }
+
+               static void WriteLine (string str)
+               {
+                       if (!quiet)
+                               Console.WriteLine (str);
+               }
+
+               static void WriteLine (string format, params object[] args)
+               {
+                       if (!quiet)
+                               Console.WriteLine (format, args);
+               }
+
+               static int Main (string[] args)
+               {
+                       try {
+                               if (!ParseOptions (args)) {
+                                       Header ();
+                                       Help ();
+                                       return 1;
+                               }
+                               if (!quiet) {
+                                       Header ();
+                               }
+                               return Process ();
+                       } catch (Exception e) {
+                               // ignore quiet on exception
+                               Console.WriteLine ("Error: {0}", e);
+                               return 1;
+                       }
+               }
+       }
+}
\ No newline at end of file
index 93adea143ed417dafe5ec142310c3a86b6ca9e54..ac0e3a9a95706952ae1719ba43a001794181e540 100644 (file)
@@ -76,6 +76,7 @@ scripts_4_0 = \
        prj2make$(SCRIPT_SUFFIX)                \
        soapsuds$(SCRIPT_SUFFIX)                \
        caspol$(SCRIPT_SUFFIX)                  \
+       cert-sync$(SCRIPT_SUFFIX)               \
        cert2spc$(SCRIPT_SUFFIX)                \
        certmgr$(SCRIPT_SUFFIX)                 \
        chktrust$(SCRIPT_SUFFIX)                \