From 3432b108f15257f937279dd33cbb3e18e469e0d44085159c9370eca200668123 Mon Sep 17 00:00:00 2001 From: Stephan Kulow Date: Thu, 16 Sep 2010 10:18:50 +0000 Subject: [PATCH] OBS-URL: https://build.opensuse.org/package/show/Base:System/ca-certificates?expand=0&rev=17 --- ca-certificates.changes | 11 ++ ca-certificates.spec | 65 ++++++++++- java.run | 85 +++++++++++++++ keystore.java | 235 ++++++++++++++++++++++++++++++++++++++++ update-ca-certificates | 23 ++-- 5 files changed, 405 insertions(+), 14 deletions(-) create mode 100644 java.run create mode 100644 keystore.java diff --git a/ca-certificates.changes b/ca-certificates.changes index a1bdbb3..75e3ca7 100644 --- a/ca-certificates.changes +++ b/ca-certificates.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Fri May 21 12:46:55 UTC 2010 - mvyskocil@suse.cz + +* Use the gcc-java and fastjar for build to avoid dependency problems +* build keystore.class only to allow noarch package + +------------------------------------------------------------------- +Wed May 19 09:57:41 UTC 2010 - lnussel@suse.de + +- create java bundles + ------------------------------------------------------------------- Tue Apr 27 14:17:24 UTC 2010 - lnussel@suse.de diff --git a/ca-certificates.spec b/ca-certificates.spec index 62490c0..f00b532 100644 --- a/ca-certificates.spec +++ b/ca-certificates.spec @@ -17,7 +17,13 @@ # norootforbuild +%bcond_without java + BuildRequires: openssl +%if %{with java} +BuildRequires: gcc-java +BuildRequires: fastjar +%endif Name: ca-certificates %define ssletcdir %{_sysconfdir}/ssl @@ -27,14 +33,15 @@ Name: ca-certificates License: GPLv2+ Group: Productivity/Networking/Security Version: 1 -Release: 4 +Release: 5 Summary: Utilities for system wide CA certificate installation Source0: update-ca-certificates Source1: update-ca-certificates.8 Source2: GPL-2.0.txt Source3: certbundle.run +Source4: keystore.java +Source5: java.run BuildRoot: %{_tmppath}/%{name}-%{version}-build -BuildArch: noarch Url: http://gitorious.org/opensuse/ca-certificates # Requires: openssl @@ -43,10 +50,29 @@ Recommends: ca-certificates-mozilla # gone when a package providing actual certificates gets # installed (bnc#594434). Obsoletes: openssl-certs < 0.9.9 +BuildArch: noarch + +%if %{with java} + +%package -n java-ca-certificates +License: GPLv2+ +Group: Productivity/Networking/Security +Summary: Utilities CA certificate import to gcj +Requires(post): ca-certificates +Supplements: packageand(gcj-compat:ca-certificates) +Supplements: packageand(java-1_6_0-openjdk:ca-certificates) +Supplements: packageand(java-1_6_0-sun:ca-certificates) +%endif %description Utilities for system wide CA certificate installation +%if %{with java} + +%description -n java-ca-certificates +Utilities for CA certificate installation for gcj and openjdk Java +%endif + %prep %setup -qcT install -m 755 %{SOURCE0} . @@ -54,6 +80,16 @@ install -m 644 %{SOURCE1} . install -m 644 %{SOURCE2} COPYING %build +%if %{with java} +gcj -C %SOURCE4 -d . +# emulate -e option of jar for fastjar +cat < MANIFEST.MF +Manifest-Version: 1.0 +Created-By: 0.98 +Main-Class: keystore +EOF +fastjar cfm keystore.jar MANIFEST.MF keystore*.class +%endif %install mkdir -p %{buildroot}/%{etccadir} @@ -65,10 +101,18 @@ mkdir -p %{buildroot}%{_prefix}/lib/ca-certificates/update.d install -D -m 644 /dev/null %{buildroot}/%{cabundle} install -m 644 /dev/null %{buildroot}/etc/ca-certificates.conf install -m 755 %{SOURCE3} %{buildroot}%{_prefix}/lib/ca-certificates/update.d +install -m 755 %{SOURCE5} %{buildroot}%{_prefix}/lib/ca-certificates/update.d ln -s %{cabundle} %{buildroot}%{ssletcdir}/ca-bundle.pem install -m 755 update-ca-certificates %{buildroot}/%{_sbindir} install -m 644 update-ca-certificates.8 %{buildroot}/%{_mandir}/man8 +install -m 644 /dev/null %{buildroot}/var/lib/ca-certificates/ca-bundle.pem +%if %{with java} +mkdir -p %{buildroot}%{_prefix}/lib/ca-certificates/java +install -m 644 keystore.jar %{buildroot}%{_prefix}/lib/ca-certificates/java +install -m 644 /dev/null %{buildroot}/var/lib/ca-certificates/java-cacerts +install -m 644 /dev/null %{buildroot}/var/lib/ca-certificates/gcj-cacerts +%endif %post # this is just needed for those updating Factory, @@ -81,6 +125,12 @@ fi # as openssl changed the hash format between 0.9.8 and 1.0 update-ca-certificates -f || true +%if %{with java} + +%post -n java-ca-certificates +update-ca-certificates || true +%endif + %clean rm -rf %{buildroot} @@ -100,5 +150,16 @@ rm -rf %{buildroot} %{_prefix}/lib/ca-certificates/update.d/* %{_sbindir}/update-ca-certificates %{_mandir}/man8/update-ca-certificates.8* +%ghost /var/lib/ca-certificates/ca-bundle.pem + +%if %{with java} + +%files -n java-ca-certificates +%defattr(-, root, root) +%dir %{_prefix}/lib/ca-certificates/java +%{_prefix}/lib/ca-certificates/java/keystore.jar +%ghost /var/lib/ca-certificates/java-cacerts +%ghost /var/lib/ca-certificates/gcj-cacerts +%endif %changelog diff --git a/java.run b/java.run new file mode 100644 index 0000000..29f6963 --- /dev/null +++ b/java.run @@ -0,0 +1,85 @@ +#!/bin/bash + +unset ${!LC_*} ${!RC_LC_*} LANGUAGE RC_LANG +export LANG=en_US + +set -e + +libexecdir="/usr/lib/ca-certificates/java/" +cafile="/var/lib/ca-certificates/java-cacerts" +cafile_gcj="/var/lib/ca-certificates/gcj-cacerts" +cadir="/etc/ssl/certs" + +tmppem="$cafile.tmp" + +cleanup() +{ + rm -rf "$tmppem" +} +trap cleanup EXIT + +for i in "$@"; do + if [ "$i" = "-f" ]; then + fresh=1 + elif [ "$i" = "-v" ]; then + verbose=1 + fi +done + +umask 0022 + +if [ -z "$JAVA_HOME" -a -r /etc/profile.d/alljava.sh ]; then + . /etc/profile.d/alljava.sh +fi + +if [ -n "$JAVA_HOME" ]; then + java="$JAVA_HOME/bin/java" +else + java=`which java` +fi + +if [[ $(readlink -f "${java}") =~ gij ]]; then + java="" +fi + +if [ ! -e "$libexecdir"/keystore.jar ]; then + # nothing to do + exit 0 +fi + +mustrun= +if [ -n "$fresh" ]; then + mustrun=1 +fi +if [ -e "$libexecdir"/keystore.jar -a "$cadir" -nt "$cafile" ]; then + mustrun=1 +fi + +[ -n "$mustrun" ] || exit 0 + +mkdir -p ${cafile%/*} +mkdir -p "$tmppem" +for i in "$cadir"/*.pem; do + # only include certificates trusted for server auth + if grep -q "BEGIN TRUSTED CERTIFICATE" "$i"; then + trust=`sed -n '/^# openssl-trust=/{s/^.*=//;p;q;}' "$i"` + case "$trust" in + *serverAuth*) ;; + *) [ -z "$verbose" ] || echo "skipping $i" >&2; continue ;; + esac + openssl x509 -in "$i" -out "$tmppem/${i##*/}" + else + ln -s "$i" "$tmppem" + fi +done + +if [ -x "$java" ]; then + echo "creating $cafile ..." + $java -jar $libexecdir/keystore.jar -keystore "$cafile" -cadir "$cadir" "$@" +fi +if [ -x "/usr/bin/gij" ]; then + echo "creating $cafile_gcj ..." + /usr/bin/gij -jar $libexecdir/keystore.jar -keystore "$cafile_gcj" -cadir "$cadir" "$@" +fi + +# vim: syntax=sh diff --git a/keystore.java b/keystore.java new file mode 100644 index 0000000..34ca526 --- /dev/null +++ b/keystore.java @@ -0,0 +1,235 @@ +/* + * Import system SSL certificates to java keystore + * Copyright (C) 2010 SUSE LINUX Products GmbH + * + * Author: Ludwig Nussel + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +import java.security.KeyStore; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.BufferedInputStream; +import java.io.FilenameFilter; +import java.util.HashSet; +import java.util.Enumeration; +import java.util.Iterator; + +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +public class keystore +{ + static HashSet blacklist; + + public static void usage() { + System.err.println("Usage: java keystore -keystore -cadir [-storepass |-f|-v]"); + System.err.println(""); + System.err.println(" -keystore \tname of final keystore (required)"); + System.err.println(" -cadir \t\tdirectory contains certificates (required)"); + System.err.println(" -storepass \tthe password"); + System.err.println(" -f\t\t\t\tfresh existing keystore"); + System.err.println(" -v\t\t\t\tbe verbose"); + System.err.println(" -h/--help\t\t\tshow this help"); + } + + public static void main(String[] args) + throws java.security.KeyStoreException, + java.security.NoSuchAlgorithmException, + java.security.cert.CertificateException, + java.io.FileNotFoundException, + java.io.IOException + { + char[] password = null; + String ksfilename = null; + String cadirname = null; + boolean verbose = false; + boolean fresh = false; + + if (args.length == 0) { + usage(); + System.exit(1); + } + + + if (!System.getProperty("java.vendor").equals("Free Software Foundation, Inc.")) { + password = "changeit".toCharArray(); + } + + for (int i = 0; i < args.length; ++i) { + if (args[i].equals("-keystore")) { + ksfilename = args[++i]; + } else if (args[i].equals("-cadir")) { + cadirname = args[++i]; + } else if (args[i].equals("-storepass")) { + password = args[++i].toCharArray(); + } else if (args[i].equals("-v")) { + verbose = true; + } else if (args[i].equals("-f")) { + fresh = true; + } else if (args[i].equals("-h") || args[i].equals("--help")) { + usage(); + System.exit(1); + } else { + System.err.println("invalid argument: " + args[i]); + System.err.println("type -h/--help for help"); + System.exit(1); + } + } + + if (ksfilename == null) { + System.err.println("must specify -keystore"); + return; + } + + if (cadirname == null) { + System.err.println("must specify -cadir"); + return; + } + + File cadir = new File(cadirname); + if (!cadir.isDirectory()) { + System.err.println("cadir is not a directory"); + return; + } + + blacklist = new HashSet(); + // XXX: make a file +// blacklist.add("foo"); + + String certs[] = cadir.list(new FilenameFilter(){ + public boolean accept(File dir, String name) + { + if (!name.endsWith(".pem")) { + return false; + } + if (blacklist.contains(name)) { + return false; + } + return true; + } + }); + + KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); + + FileInputStream storein = null; + try { + File f = new File(ksfilename); + if (!fresh && f.exists()) { + storein = new FileInputStream(ksfilename); + } + ks.load(storein, password); + } finally { + if (storein != null) { + storein.close(); + } + } + + HashSet known = new HashSet(); + for (Enumeration a = ks.aliases(); a.hasMoreElements();) { + known.add(a.nextElement()); + } + + CertificateFactory cf = CertificateFactory.getInstance("X509"); + int added = 0; + int removed = 0; + + for (int i = 0; i < certs.length; ++i) { + BufferedInputStream f = new BufferedInputStream(new FileInputStream(cadirname+"/"+certs[i])); + String marker = "-----BEGIN CERTIFICATE-----"; + boolean found = false; + + f.mark(80); + String line; + String alias = null; + // we need to parse and skip the "header" + while((line = readline(f)) != null) { + if (line.equals(marker)) { + f.reset(); + found = true; + break; + } else if (line.startsWith("# alias=")) { + // FIXME: somehow UTF-8 encoding must be enforced here + alias = line.substring(8); + } + f.mark(80); + } + if (found) { + if (alias == null) { + alias = certs[i].substring(0, certs[i].length()-4); // without .pem + } + alias = alias.toLowerCase(); + try { + X509Certificate cert = (X509Certificate)cf.generateCertificate(f); + if (known.contains(alias)) { + if (verbose) + System.out.println("already known: " + alias); + known.remove(alias); + } else { + if (verbose) + System.out.println("adding " + alias); + ks.setCertificateEntry(alias, cert); + ++added; + } + } catch (java.security.cert.CertificateException ex) { + System.err.println("imporing " + certs[i] + " failed: " + ex.getCause()); + } + } else { + System.out.println("skipping file with unrecognized format: " + certs[i]); + } + } + + if (!known.isEmpty()) { + for (Iterator it = known.iterator(); it.hasNext();) { + String alias = it.next(); + if (verbose) + System.out.println("removing " + alias); + ks.deleteEntry(alias); + ++removed; + } + } + + if (added != 0 || removed != 0) { + FileOutputStream storeout = new FileOutputStream(ksfilename); + ks.store(storeout, password); + storeout.close(); + } + + System.out.println(added + " added, " + removed + " removed."); + } + + public static String readline(BufferedInputStream in) + throws java.io.IOException + { + StringBuffer buf = new StringBuffer(80); + int c = in.read(); + while(c != -1 && c != '\n' && c != '\r') { + buf.append((char)c); + c = in.read(); + } + if (c == '\r') { + in.mark(1); + c = in.read(); + if (c != '\n') + in.reset(); + } + if (buf.length() == 0) + return null; + + return buf.toString(); + } +} diff --git a/update-ca-certificates b/update-ca-certificates index 2279c2a..76b0091 100644 --- a/update-ca-certificates +++ b/update-ca-certificates @@ -107,8 +107,6 @@ if (open(F, '<', $certsconf)) { close F; } -print "Updating certificates in $etccertsdir...\n"; - if ($opt_fresh || %whitelist) { for my $f (glob "$etccertsdir/*" ) { next unless -l $f; @@ -160,19 +158,20 @@ for my $f (glob "$etccertsdir/*.pem") { } } +chdir $etccertsdir || die "$!"; if (%added || %removed || $opt_fresh) { - chdir $etccertsdir || die "$!"; + print "Updating certificates in $etccertsdir...\n"; my $redir = ($opt_verbose?'':'> /dev/null'); system("c_rehash . $redir"); - my @args; - push @args, '-f' if $opt_fresh; - push @args, '-v' if $opt_verbose; - for my $f (glob("$hooksdir2/*.run"), glob("$hooksdir1/*.run")) { - system($f, @args); - } + printf("%d added, %d removed.\n", + (%added?(scalar keys %added):0), + (%removed?(scalar keys %removed):0)); } -printf("%d added, %d removed.\n", - (%added?(scalar keys %added):0), - (%removed?(scalar keys %removed):0)); +my @args; +push @args, '-f' if $opt_fresh; +push @args, '-v' if $opt_verbose; +for my $f (glob("$hooksdir2/*.run"), glob("$hooksdir1/*.run")) { + system($f, @args); +}