From c8d346e1ec7890036206c257f95ceab1a2176eaaa49a4878d0ab0ee04305b274 Mon Sep 17 00:00:00 2001 From: Ludwig Nussel Date: Tue, 2 Jul 2013 13:57:37 +0000 Subject: [PATCH] Accepting request 181763 from home:lnussel:branches:Base:System - use certdata2pem.py from Fedora to extract all certs OBS-URL: https://build.opensuse.org/request/show/181763 OBS-URL: https://build.opensuse.org/package/show/Base:System/ca-certificates-mozilla?expand=0&rev=37 --- ca-certificates-mozilla.changes | 5 + ca-certificates-mozilla.spec | 40 +++--- certdata2pem.py | 199 ++++++++++++++++++++++++++++ compareoldnew | 18 +-- extractcerts.pl | 224 -------------------------------- 5 files changed, 231 insertions(+), 255 deletions(-) create mode 100644 certdata2pem.py delete mode 100644 extractcerts.pl diff --git a/ca-certificates-mozilla.changes b/ca-certificates-mozilla.changes index 784898e..0b76653 100644 --- a/ca-certificates-mozilla.changes +++ b/ca-certificates-mozilla.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Thu Jun 27 16:03:05 UTC 2013 - lnussel@suse.de + +- use certdata2pem.py from Fedora to extract all certs + ------------------------------------------------------------------- Fri Jun 21 12:59:53 UTC 2013 - lnussel@suse.de diff --git a/ca-certificates-mozilla.spec b/ca-certificates-mozilla.spec index e132ef4..fcd9004 100644 --- a/ca-certificates-mozilla.spec +++ b/ca-certificates-mozilla.spec @@ -16,17 +16,12 @@ # -%if 0%{?suse_version} < 1310 -%bcond_with trustedcerts -%define certdir %{_datadir}/ca-certificates/mozilla -%else -%bcond_without trustedcerts -%define certdir %{trustdir_static}/anchors +%define certdir %{trustdir_static} BuildRequires: p11-kit-devel -%endif BuildRequires: ca-certificates BuildRequires: openssl +BuildRequires: python Name: ca-certificates-mozilla Version: 1.85 @@ -48,7 +43,7 @@ Url: http://www.mozilla.org # - Watch out that blacklisted or untrusted certificates are not # accidentally included! Source: certdata.txt -Source1: extractcerts.pl +Source1: certdata2pem.py Source2: %{name}.COPYING Source3: compareoldnew BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -69,35 +64,36 @@ from MozillaFirefox %prep %setup -qcT /bin/cp %{SOURCE0} . -install -m 644 %{S:1} COPYING +install -m 644 %{SOURCE2} COPYING %build -perl %{SOURCE1} --trustbits < certdata.txt +python %{SOURCE1} %install -mkdir -p %{buildroot}/%{certdir} +mkdir -p %{buildroot}/%{trustdir_static}/anchors set +x -for i in *.pem; do +for i in *.crt; do args=() trust=`sed -n '/^# openssl-trust=/{s/^.*=//;p;q;}' "$i"` + distrust=`sed -n '/^# openssl-distrust=/{s/^.*=//;p;q;}' "$i"` alias=`sed -n '/^# alias=/{s/^.*=//;p;q;}' "$i"` -%if %{with trustedcerts} args+=('-trustout') for t in $trust; do args+=("-addtrust" "$t") done + for t in $distrust; do + args+=("-addreject" "$t") + done [ -z "$alias" ] || args+=('-setalias' "$alias") -%else - case "$trust" in - *serverAuth*) ;; - *) echo "skipping $i, not trusted for serverAuth"; continue ;; - esac -%endif - echo "$i" + + echo "$i ${args[*]}" { grep '^#' "$i" openssl x509 -in "$i" "${args[@]}" - } > "%{buildroot}/%{certdir}/$i" + } > "%{buildroot}/%{trustdir_static}$d/${i%%:*}.pem" +done +for i in *.p11-kit; do + install -m 644 "$i" "%{buildroot}/%{trustdir_static}" done set -x @@ -110,6 +106,6 @@ update-ca-certificates || true %files %defattr(-, root, root) %doc COPYING -%{certdir} +%{trustdir_static} %changelog diff --git a/certdata2pem.py b/certdata2pem.py new file mode 100644 index 0000000..ccaac69 --- /dev/null +++ b/certdata2pem.py @@ -0,0 +1,199 @@ +#!/usr/bin/python +# vim:set et sw=4: +# +# certdata2pem.py - splits certdata.txt into multiple files +# +# Copyright (C) 2009 Philipp Kern +# Copyright (C) 2013 Kai Engert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, +# USA. + +import base64 +import os.path +import re +import sys +import textwrap +import urllib + +objects = [] + +def printable_serial(obj): + return ".".join(map(lambda x:str(ord(x)), obj['CKA_SERIAL_NUMBER'])) + +# Dirty file parser. +in_data, in_multiline, in_obj = False, False, False +field, type, value, obj = None, None, None, dict() +for line in open('certdata.txt', 'r'): + # Ignore the file header. + if not in_data: + if line.startswith('BEGINDATA'): + in_data = True + continue + # Ignore comment lines. + if line.startswith('#'): + continue + # Empty lines are significant if we are inside an object. + if in_obj and len(line.strip()) == 0: + objects.append(obj) + obj = dict() + in_obj = False + continue + if len(line.strip()) == 0: + continue + if in_multiline: + if not line.startswith('END'): + if type == 'MULTILINE_OCTAL': + line = line.strip() + for i in re.finditer(r'\\([0-3][0-7][0-7])', line): + value += chr(int(i.group(1), 8)) + else: + value += line + continue + obj[field] = value + in_multiline = False + continue + if line.startswith('CKA_CLASS'): + in_obj = True + line_parts = line.strip().split(' ', 2) + if len(line_parts) > 2: + field, type = line_parts[0:2] + value = ' '.join(line_parts[2:]) + elif len(line_parts) == 2: + field, type = line_parts + value = None + else: + raise NotImplementedError, 'line_parts < 2 not supported.\n' + line + if type == 'MULTILINE_OCTAL': + in_multiline = True + value = "" + continue + obj[field] = value +if len(obj.items()) > 0: + objects.append(obj) + +# Build up trust database. +trustmap = dict() +for obj in objects: + if obj['CKA_CLASS'] != 'CKO_NSS_TRUST': + continue + key = obj['CKA_LABEL'] + printable_serial(obj) + trustmap[key] = obj + print " added trust", key + +# Build up cert database. +certmap = dict() +for obj in objects: + if obj['CKA_CLASS'] != 'CKO_CERTIFICATE': + continue + key = obj['CKA_LABEL'] + printable_serial(obj) + certmap[key] = obj + print " added cert", key + +def obj_to_filename(obj): + label = obj['CKA_LABEL'][1:-1] + label = label.replace('/', '_')\ + .replace(' ', '_')\ + .replace('(', '=')\ + .replace(')', '=')\ + .replace(',', '_') + label = re.sub(r'\\x[0-9a-fA-F]{2}', lambda m:chr(int(m.group(0)[2:], 16)), label) + serial = printable_serial(obj) + return label + ":" + serial + +trust_types = { + "CKA_TRUST_DIGITAL_SIGNATURE": "digital-signature", + "CKA_TRUST_NON_REPUDIATION": "non-repudiation", + "CKA_TRUST_KEY_ENCIPHERMENT": "key-encipherment", + "CKA_TRUST_DATA_ENCIPHERMENT": "data-encipherment", + "CKA_TRUST_KEY_AGREEMENT": "key-agreement", + "CKA_TRUST_KEY_CERT_SIGN": "cert-sign", + "CKA_TRUST_CRL_SIGN": "crl-sign", + "CKA_TRUST_SERVER_AUTH": "server-auth", + "CKA_TRUST_CLIENT_AUTH": "client-auth", + "CKA_TRUST_CODE_SIGNING": "code-signing", + "CKA_TRUST_EMAIL_PROTECTION": "email-protection", + "CKA_TRUST_IPSEC_END_SYSTEM": "ipsec-end-system", + "CKA_TRUST_IPSEC_TUNNEL": "ipsec-tunnel", + "CKA_TRUST_IPSEC_USER": "ipsec-user", + "CKA_TRUST_TIME_STAMPING": "time-stamping", + "CKA_TRUST_STEP_UP_APPROVED": "step-up-approved", +} + +openssl_trust = { + "CKA_TRUST_SERVER_AUTH": "serverAuth", + "CKA_TRUST_CLIENT_AUTH": "clientAuth", + "CKA_TRUST_CODE_SIGNING": "codeSigning", + "CKA_TRUST_EMAIL_PROTECTION": "emailProtection", +} + +for tobj in objects: + if tobj['CKA_CLASS'] == 'CKO_NSS_TRUST': + key = tobj['CKA_LABEL'] + printable_serial(tobj) + print "producing trust for " + key + trustbits = [] + distrustbits = [] + openssl_trustflags = [] + openssl_distrustflags = [] + for t in trust_types.keys(): + if tobj.has_key(t) and tobj[t] == 'CKT_NSS_TRUSTED_DELEGATOR': + trustbits.append(t) + if t in openssl_trust: + openssl_trustflags.append(openssl_trust[t]) + if tobj.has_key(t) and tobj[t] == 'CKT_NSS_NOT_TRUSTED': + distrustbits.append(t) + if t in openssl_trust: + openssl_distrustflags.append(openssl_trust[t]) + + fname = obj_to_filename(tobj) + try: + obj = certmap[key] + except: + obj = None + + if obj != None: + fname += ".crt" + else: + fname += ".p11-kit" + + f = open(fname, 'w') + if obj != None: + f.write("# alias=%s\n"%tobj['CKA_LABEL']) + f.write("# trust=" + " ".join(trustbits) + "\n") + f.write("# distrust=" + " ".join(distrustbits) + "\n") + if openssl_trustflags: + f.write("# openssl-trust=" + " ".join(openssl_trustflags) + "\n") + if openssl_distrustflags: + f.write("# openssl-distrust=" + " ".join(openssl_distrustflags) + "\n") + f.write("-----BEGIN CERTIFICATE-----\n") + f.write("\n".join(textwrap.wrap(base64.b64encode(obj['CKA_VALUE']), 64))) + f.write("\n-----END CERTIFICATE-----\n") + else: + f.write("[p11-kit-object-v1]\n") + f.write("label: "); + f.write(tobj['CKA_LABEL']); + f.write("\n") + f.write("class: certificate\n") + f.write("certificate-type: x-509\n") + f.write("issuer: \""); + f.write(urllib.quote(tobj['CKA_ISSUER'])); + f.write("\"\n") + f.write("serial-number: \""); + f.write(urllib.quote(tobj['CKA_SERIAL_NUMBER'])); + f.write("\"\n") + if (tobj['CKA_TRUST_SERVER_AUTH'] == 'CKT_NSS_NOT_TRUSTED') or (tobj['CKA_TRUST_EMAIL_PROTECTION'] == 'CKT_NSS_NOT_TRUSTED') or (tobj['CKA_TRUST_CODE_SIGNING'] == 'CKT_NSS_NOT_TRUSTED'): + f.write("x-distrusted: true\n") + f.write("\n\n") + print " -> written as '%s', trust = %s, openssl-trust = %s, distrust = %s, openssl-distrust = %s" % (fname, trustbits, openssl_trustflags, distrustbits, openssl_distrustflags) diff --git a/compareoldnew b/compareoldnew index a4e42d6..01ba64b 100644 --- a/compareoldnew +++ b/compareoldnew @@ -15,15 +15,15 @@ trap cleanup EXIT mkdir old new cd old echo old... -VERBOSE=1 ../extractcerts.pl --trustbits < ../.osc/certdata.txt > tmp -sort < tmp > ../old.files -rm -f tmp +ln -s ../.osc/certdata.txt +python ../certdata2pem.py > stdout 2> stderr +ls -1 *.crt | sort > ../old.files cd .. cd new echo new... -VERBOSE=1 ../extractcerts.pl --trustbits < ../certdata.txt > tmp -sort < tmp > ../new.files -rm -f tmp +ln -s ../certdata.txt +python ../certdata2pem.py > stdout 2> stderr +ls -1 *.crt | sort > ../new.files cd .. echo '----------------------------' while read line; do @@ -32,13 +32,13 @@ while read line; do new="$2" common="$3" if [ -n "$old" ]; then - echo "! removed: $old" + echo "> removed: $old" showcert old/$old elif [ -n "$new" ]; then - echo "! new: $new" + echo "> new: $new" showcert new/$new elif ! cmp "old/$common" "new/$common"; then - echo "! diff: $common" + echo "> changed: $common" showcert old/$common showcert new/$common diff -u old/$common new/$common || true diff --git a/extractcerts.pl b/extractcerts.pl deleted file mode 100644 index c09e0cc..0000000 --- a/extractcerts.pl +++ /dev/null @@ -1,224 +0,0 @@ -#!/usr/bin/perl -w -# -# ***** BEGIN LICENSE BLOCK ***** -# Version: MPL 1.1/GPL 2.0/LGPL 2.1 -# -# The contents of this file are subject to the Mozilla Public License Version -# 1.1 (the "License"); you may not use this file except in compliance with -# the License. You may obtain a copy of the License at -# http://www.mozilla.org/MPL/ -# -# Software distributed under the License is distributed on an "AS IS" basis, -# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License -# for the specific language governing rights and limitations under the -# License. -# -# The Original Code is the Netscape security libraries. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1994-2000 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# -# Alternatively, the contents of this file may be used under the terms of -# either the GNU General Public License Version 2 or later (the "GPL"), or -# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), -# in which case the provisions of the GPL or the LGPL are applicable instead -# of those above. If you wish to allow use of your version of this file only -# under the terms of either the GPL or the LGPL, and not to allow others to -# use your version of this file under the terms of the MPL, indicate your -# decision by deleting the provisions above and replace them with the notice -# and other provisions required by the GPL or the LGPL. If you do not delete -# the provisions above, a recipient may use your version of this file under -# the terms of any one of the MPL, the GPL or the LGPL. -# -# ***** END LICENSE BLOCK ***** -use strict; -use Encode; - -my $count = 0; -my @certificates = (); -my %trusts = (); -my $object = undef; -my $output_trustbits; - -my %trust_types = ( - "CKA_TRUST_DIGITAL_SIGNATURE" => "digital-signature", - "CKA_TRUST_NON_REPUDIATION" => "non-repudiation", - "CKA_TRUST_KEY_ENCIPHERMENT" => "key-encipherment", - "CKA_TRUST_DATA_ENCIPHERMENT" => "data-encipherment", - "CKA_TRUST_KEY_AGREEMENT" => "key-agreement", - "CKA_TRUST_KEY_CERT_SIGN" => "cert-sign", - "CKA_TRUST_CRL_SIGN" => "crl-sign", - "CKA_TRUST_SERVER_AUTH" => "server-auth", - "CKA_TRUST_CLIENT_AUTH" => "client-auth", - "CKA_TRUST_CODE_SIGNING" => "code-signing", - "CKA_TRUST_EMAIL_PROTECTION" => "email-protection", - "CKA_TRUST_IPSEC_END_SYSTEM" => "ipsec-end-system", - "CKA_TRUST_IPSEC_TUNNEL" => "ipsec-tunnel", - "CKA_TRUST_IPSEC_USER" => "ipsec-user", - "CKA_TRUST_TIME_STAMPING" => "time-stamping", - "CKA_TRUST_STEP_UP_APPROVED" => "step-up-approved", -); - -my %openssl_trust = ( - CKA_TRUST_SERVER_AUTH => 'serverAuth', - CKA_TRUST_CLIENT_AUTH => 'clientAuth', - CKA_TRUST_EMAIL_PROTECTION => 'emailProtection', - CKA_TRUST_CODE_SIGNING => 'codeSigning', -); - -if (@ARGV && $ARGV[0] eq '--trustbits') { - shift @ARGV; - $output_trustbits = 1; -} - -sub colonhex -{ - return join(':', unpack("(H2)*", $_[0])); -} - -sub handle_object($) -{ - my $object = shift; - return unless $object; - ### convert old tags to be able to compare pre 1.74 files - $object->{'CKA_CLASS'} =~ s/^CKO_NETSCAPE/CKO_NSS/; - for my $type (keys %trust_types) { - next unless (exists $object->{$type}); - $object->{$type} =~ s/^CKT_NETSCAPE/CKT_NSS/; - } - #### - if($object->{'CKA_CLASS'} eq 'CKO_CERTIFICATE' && $object->{'CKA_CERTIFICATE_TYPE'} eq 'CKC_X_509') { - push @certificates, $object; - } elsif ($object->{'CKA_CLASS'} eq 'CKO_NSS_TRUST') { - my $label = $object->{'CKA_LABEL'}; - my $serial = colonhex($object->{'CKA_SERIAL_NUMBER'}); - die "$label exists ($serial)" if exists($trusts{$label.$serial}); - $trusts{$label.$serial} = $object; - } elsif ($object->{'CKA_CLASS'} eq 'CKO_NSS_BUILTIN_ROOT_LIST') { - # ignore - } else { - print STDERR "class ", $object->{'CKA_CLASS'} ," not handled\n"; - } -} - -while(<>) { - my @fields = (); - - s/^((?:[^"#]+|"[^"]*")*)(\s*#.*$)/$1/; - next if (/^\s*$/); - - if( /(^CVS_ID\s+)(.*)/ ) { - next; - } - - # This was taken from the perl faq #4. - my $text = $_; - push(@fields, $+) while $text =~ m{ - "([^\"\\]*(?:\\.[^\"\\]*)*)"\s? # groups the phrase inside the quotes - | ([^\s]+)\s? - | \s - }gx; - push(@fields, undef) if substr($text,-1,1) eq '\s'; - - if( $fields[0] =~ /BEGINDATA/ ) { - next; - } - - if( $fields[1] =~ /MULTILINE/ ) { - die "expected MULTILINE_OCTAL" unless $fields[1] eq 'MULTILINE_OCTAL'; - $fields[2] = ""; - while(<>) { - last if /END/; - chomp; - $fields[2] .= pack("C", oct($+)) while $_ =~ /\G\\([0-3][0-7][0-7])/g; - } - } - - if( $fields[0] =~ /CKA_CLASS/ ) { - $count++; - handle_object($object); - $object = {}; - } - - $object->{$fields[0]} = $fields[2]; -} -handle_object($object); -undef $object; - -use MIME::Base64; -for my $cert (@certificates) { - my $alias = $cert->{'CKA_LABEL'}; - my $serial = colonhex($cert->{'CKA_SERIAL_NUMBER'}); - if(!exists($trusts{$alias.$serial})) { - print STDERR "NO TRUST: $alias\n"; - next; - } - # check trust. We only include certificates that are trusted for identifying - # web sites - my $trust = $trusts{$alias.$serial}; - my @addtrust; - my @addtrust_openssl; - my $trusted; - if ($output_trustbits) { - for my $type (keys %trust_types) { - if (exists $trust->{$type} - && $trust->{$type} eq 'CKT_NSS_TRUSTED_DELEGATOR') { - push @addtrust, $trust_types{$type}; - if (exists $openssl_trust{$type}) { - push @addtrust_openssl, $openssl_trust{$type}; - } - $trusted = 1; - } - } - } else { - if($trust->{'CKA_TRUST_SERVER_AUTH'} eq 'CKT_NSS_TRUSTED_DELEGATOR') { - $trusted = 1; - } - } - - if (!$trusted) { - my $t = $trust->{'CKA_TRUST_SERVER_AUTH'}; - $t =~ s/CKT_NSS_//; - print STDERR "$t: $alias\n"; - next; - } - - if ($alias =~ /\\x[0-9a-fA-F]{2}/) { - $alias =~ s/\\x([0-9a-fA-F]{2})/chr(hex($1))/ge; # thanks mls! - $alias = Encode::decode("UTF-8", $alias); - } - my $file = $alias; - $alias =~ s/'/-/g; - $file =~ s/[^[:alnum:]\\]+/_/g; - $file = Encode::encode("UTF-8", $file); - if (-e $file.'.pem') { - my $i = 1; - while (-e $file.".$i.pem") { - ++$i; - } - $file .= ".$i.pem"; - } else { - $file .= '.pem'; - } - if (!open(O, '>', $file)) { - print STDERR "$file: $!\n"; - next; - } - print "$file\n" if $ENV{'VERBOSE'}; - my $value = $cert->{'CKA_VALUE'}; - if ($output_trustbits) { - print O "# alias=",Encode::encode("UTF-8", $alias),"\n"; - print O "# trust=",join(" ", @addtrust),"\n"; - if (@addtrust_openssl) { - print O "# openssl-trust=",join(" ", @addtrust_openssl),"\n"; - } - } - print O "-----BEGIN CERTIFICATE-----\n"; - print O encode_base64($value); - print O "-----END CERTIFICATE-----\n"; - close O; -}