Add new crlupdate tool
authorSebastien Pouliot <sebastien@ximian.com>
Sun, 27 Mar 2011 20:59:26 +0000 (16:59 -0400)
committerSebastien Pouliot <sebastien@ximian.com>
Sun, 27 Mar 2011 20:59:26 +0000 (16:59 -0400)
* man/Makefile.am:
* man/crlupdate.1:
* man/man.xml:
Add new manual page for crlupdate

* mcs/tools/security/Makefile:
* mcs/tools/security/crlupdate.cs:
Add new crlupdate tool

* scripts/Makefile.am:
Generate script wrapper for crlupdate

man/Makefile.am
man/crlupdate.1 [new file with mode: 0644]
man/man.xml
mcs/tools/security/Makefile
mcs/tools/security/crlupdate.cs [new file with mode: 0644]
scripts/Makefile.am

index 4b1810c61686bc62dc6435f13907f037fced72a3..3e4dab73b73266dab13aa570be9ab798648407fa 100644 (file)
@@ -4,6 +4,7 @@ man_MANS = \
        certmgr.1             \
        chktrust.1            \
        cilc.1                \
+       crlupdate.1           \
        csharp.1              \
        disco.1               \
        dtd2xsd.1             \
diff --git a/man/crlupdate.1 b/man/crlupdate.1
new file mode 100644 (file)
index 0000000..8e20437
--- /dev/null
@@ -0,0 +1,56 @@
+.\" 
+.\" crlupdate manual page.
+.\" 
+.\" Author:
+.\"   Sebastien Pouliot  <sebastien@ximian.com>
+.\" 
+.\" Copyright (C) 2011 Novell, Inc (http://www.novell.com)
+.\"
+.TH Mono "crlupdate"
+.SH NAME
+crlupdate \- Mono Certficate Revocation List Downloader and Updater
+.SH SYNOPSIS
+.PP
+.B crlupdate [-m] [-v] [-f]
+.SH DESCRIPTION
+This tool allows the download of new, or update of existing, Certficate 
+Revocation List (CRL) associated with the certificates present in the 
+user (default) or machine stores. The CRL present in the stores are used
+to determine the validity of unexpired, trusted X.509 certificates.
+To ensure CRL are always fresh consider automating the updates using the
+\fIat\fR (or similar) command(s).
+.SH OPTIONS
+.TP
+.I "-m"
+Update CRL associated with certificates in the machine store. By default
+the tool works on the user store.
+.TP
+.I "-v"
+Verbose mode. Display extra information while downloading and updating
+the CRL.
+.TP
+.I "-f"
+Force the download of all CRL even if they are not normally due to be 
+updated (i.e. nextUpdate is still in the future).
+
+.SH EXAMPLES
+.TP
+.B mono crlupdate.exe
+Download (if missing) or update (if existing and past due date) all CRL
+associated with certificates present in user store.
+.TP
+.B mono crlupdate.exe -f -m
+Force the download of every CRL associated with certificates present in
+the machine store. Note that the user running this needs read/write 
+access to the machine store or not update will occur.
+
+.SH AUTHOR
+Written by Sebastien Pouliot
+.SH COPYRIGHT
+Copyright (C) 2011 Novell.
+.SH MAILING LISTS
+Visit http://lists.ximian.com/mailman/listinfo/mono-list for details.
+.SH WEB SITE
+Visit http://www.mono-project.com for details
+.SH SEE ALSO
+.BR certmgr(1), at(1)
index 9146c90d928297d048a900be4a4bc5cf4e15b5bb..fec5271105c79560dde6d72f7fa93696e4d1a190 100644 (file)
@@ -19,6 +19,7 @@
 <manpage name="soapsuds" page="soapsuds.1" />
 <manpage name="setreg" page="setreg.1" />
 <manpage name="certmgr" page="certmgr.1" />
+<manpage name="crlupdate" page="crlupdate.1" />
 <manpage name="xsd" page="xsd.1" />
 <manpage name="caspol" page="caspol.1" />
 <manpage name="al" page="al.1" />
index 9a3ed28fa713ca23e63a9215c60ed7a2431d3448..bb248e32b01c890ae2ca1ff628ae9c0f72fecc12 100644 (file)
@@ -5,7 +5,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 \
+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
 SECURITY_PROGRAMS_2_0 = httpcfg.exe
 
diff --git a/mcs/tools/security/crlupdate.cs b/mcs/tools/security/crlupdate.cs
new file mode 100644 (file)
index 0000000..872b9b8
--- /dev/null
@@ -0,0 +1,203 @@
+//
+// crlupdate.cs: CRL downloader / updater
+//
+// Author:
+//     Sebastien Pouliot  <sebastien@ximian.com>
+//
+// Copyright (C) 2011 Novell, Inc (http://www.novell.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.Net;
+using System.Reflection;
+
+using Mono.Security.X509;
+using Mono.Security.X509.Extensions;
+
+[assembly: AssemblyTitle ("Mono CRL Updater")]
+[assembly: AssemblyDescription ("Download and update X.509 certificate revocation lists from your stores.")]
+
+namespace Mono.Tools {
+
+       class CrlUpdater {
+
+               static private void Header ()
+               {
+                       Console.WriteLine (new AssemblyInfo ().ToString ());
+               }
+
+               static private void Help ()
+               {
+                       Console.WriteLine ("Usage: crlupdate [-m] [-v] [-f] [-?]");
+                       Console.WriteLine ();
+                       Console.WriteLine ("\t-m\tuse the machine certificate store (default to user)");
+                       Console.WriteLine ("\t-v\tverbose mode (display status for every steps)");
+                       Console.WriteLine ("\t-f\tforce download (and replace existing CRL)");
+                       Console.WriteLine ("\t-?\tDisplay this help message");
+                       Console.WriteLine ();
+               }
+
+               static void Download (string url, X509Store store)
+               {
+                       if (verbose)
+                               Console.WriteLine ("Downloading: {0}", url);
+
+                       WebClient wc = new WebClient ();
+                       string error = "download";
+                       try {
+                               byte [] data = wc.DownloadData (url);
+                               error = "decode";
+                               X509Crl crl = new X509Crl (data);
+                               error = "import";
+                               store.Import (crl);
+                       }
+                       catch (Exception e) {
+                               Console.WriteLine ("ERROR: could not {0}: {1}", error, url);
+                               if (verbose) {
+                                       Console.WriteLine (e);
+                                       Console.WriteLine ();
+                               }
+                       }
+               }
+
+               static byte [] GetAuthorityKeyIdentifier (X509Extension ext)
+               {
+                       if (ext == null)
+                               return null;
+
+                       AuthorityKeyIdentifierExtension aki = new AuthorityKeyIdentifierExtension (ext);
+                       return aki.Identifier;
+               }
+
+               static byte [] GetSubjectKeyIdentifier (X509Extension ext)
+               {
+                       if (ext == null)
+                               return null;
+
+                       SubjectKeyIdentifierExtension ski = new SubjectKeyIdentifierExtension (ext);
+                       return ski.Identifier;
+               }
+
+               static bool Compare (byte [] a, byte [] b)
+               {
+                       if (a == null)
+                               return (b == null);
+                       else if (b == null)
+                               return false;
+
+                       if (a.Length != b.Length)
+                               return false;
+
+                       for (int i = 0; i < a.Length; i++) {
+                               if (a [i] != b [i])
+                                       return false;
+                       }
+                       return true;
+               }
+
+               static X509Crl FindCrl (X509Certificate cert, X509Store store)
+               {
+                       string name = cert.SubjectName;
+                       byte [] ski = GetSubjectKeyIdentifier (cert.Extensions ["2.5.29.14"]);
+                       foreach (X509Crl crl in store.Crls) {
+                               if (crl.IssuerName != cert.SubjectName)
+                                       continue;
+                               if ((ski == null) || Compare (ski, GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"])))
+                                       return crl;
+                       }
+                       return null;
+               }
+
+               static void UpdateStore (X509Store store)
+               {
+                       // for each certificate
+                       foreach (X509Certificate cert in store.Certificates) {
+
+                               // do we already have a matching CRL ? (or are we forced to download?)
+                               X509Crl crl = force ? null : FindCrl (cert, store);
+                               // without a CRL (or with a CRL in need of updating)
+                               if ((crl == null) || !crl.IsCurrent) {
+                                       X509Extension ext = cert.Extensions ["2.5.29.31"];
+                                       if (ext == null) {
+                                               if (verbose)
+                                                       Console.WriteLine ("WARNING: No cRL distribution point found for '{0}'", cert.SubjectName);
+                                               continue;
+                                       }
+
+                                       CRLDistributionPointsExtension crlDP = new CRLDistributionPointsExtension (ext);
+                                       foreach (var dp in crlDP.DistributionPoints) {
+                                               string name = dp.Name.Trim ();
+                                               if (name.StartsWith ("URL="))
+                                                       Download (name.Substring (4), store);
+                                               else if (verbose)
+                                                       Console.WriteLine ("WARNING: Unsupported distribution point: '{0}'", name);
+                                       }
+                               }
+                       }
+               }
+
+               static bool verbose = false;
+               static bool force = false;
+
+               static int Main (string [] args)
+               {
+                       bool machine = false;
+
+                       for (int i = 0; i < args.Length; i++) {
+                               switch (args [i]) {
+                               case "-m":
+                               case "--m":
+                                       machine = true;
+                                       break;
+                               case "-v":
+                               case "--v":
+                                       verbose = true;
+                                       break;
+                               case "-f":
+                               case "--f":
+                                       force = true;
+                                       break;
+                               case "-help":
+                               case "--help":
+                               case "-?":
+                               case "--?":
+                                       Help ();
+                                       return 0;
+                               }
+                       }
+
+                       try {
+                               X509Stores stores = ((machine) ? X509StoreManager.LocalMachine : X509StoreManager.CurrentUser);
+                               // for all store (expect Untrusted)
+                               UpdateStore (stores.TrustedRoot);
+                               UpdateStore (stores.IntermediateCA);
+                               UpdateStore (stores.Personal);
+                               UpdateStore (stores.OtherPeople);
+                               return 0;
+                       }
+                       catch (Exception e) {
+                               Console.WriteLine ("ERROR: Unexpected exception: {0}", e);
+                               return 1;
+                       }
+               }
+       }
+}
index 1ffeee3e6e33388c62271d8d34e2d6b896d86053..96df495dd9d1a020e2732c451fdcef13bc08655c 100644 (file)
@@ -75,6 +75,7 @@ scripts_4_0 = \
        cert2spc$(SCRIPT_SUFFIX)                \
        certmgr$(SCRIPT_SUFFIX)                 \
        chktrust$(SCRIPT_SUFFIX)                \
+       crlupdate$(SCRIPT_SUFFIX)               \
        csharp$(SCRIPT_SUFFIX)                  \
        httpcfg$(SCRIPT_SUFFIX)                 \
        lc$(SCRIPT_SUFFIX)                      \