Update tools to pick up code signing certs from the Common CA Database:
https://www.ccadb.org/resources Our normal root certs come from mozilla, but mozilla does not evaluate code signing. Currently code signing is only used my Microsoft .net, so we need to get code signing certs from Microsoft's code signing list. The certs in this list will only show up in the code signing lists or in the general list with only code signing set.
This commit is contained in:
parent
17e75b4e10
commit
6d164aedd7
11
fetch.sh
11
fetch.sh
@ -5,8 +5,9 @@
|
||||
#
|
||||
baseurl="https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib"
|
||||
force=0
|
||||
skip_signed_obj=0
|
||||
release_type="RTM"
|
||||
release="3_43"
|
||||
release="3_65"
|
||||
while [ -n "$1" ]; do
|
||||
case $1 in
|
||||
"-d")
|
||||
@ -32,11 +33,15 @@ while [ -n "$1" ]; do
|
||||
"-f")
|
||||
force=1
|
||||
;;
|
||||
"-s")
|
||||
skip_signed_obj=1
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 [-r] [-n release] [-f]"
|
||||
echo "-d use the development tip rather than the latest release"
|
||||
echo "-n release fetch a specific nss release"
|
||||
echo "-f skip the verify check"
|
||||
echo "-s skip fetching signed objects"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@ -108,6 +113,10 @@ if [ $? -ne 0 ]; then
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
if [ ${skip_signed_obj} -eq 0 ]; then
|
||||
./fetch_objsign.sh
|
||||
fi
|
||||
|
||||
# Verify everything is good with the user
|
||||
echo -e "Upgrading ${current_version} -> ${version}:"
|
||||
echo -e "*${log_date} ${name} <$email> ${version}-${release}\n - Update to CKBI ${ckbi_version} from NSS ${nss_version}"
|
||||
|
62
fetch_objsign.sh
Executable file
62
fetch_objsign.sh
Executable file
@ -0,0 +1,62 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# This script fetches the object signing list from the Microsoft list. It then
|
||||
# mergest that list into the fetched certdata.txt.
|
||||
#
|
||||
baseurl="https://ccadb-public.secure.force.com/microsoft/IncludedRootsPEMTxtForMSFT?TrustBitsInclude=Code%20Signing"
|
||||
target="microsoft_code_siging.pem"
|
||||
certdata="./certdata.txt"
|
||||
merge=1
|
||||
diff=0
|
||||
while [ -n "$1" ]; do
|
||||
case $1 in
|
||||
"-u")
|
||||
shift
|
||||
baseurl=$1
|
||||
;;
|
||||
"-o")
|
||||
shift
|
||||
target=$1
|
||||
;;
|
||||
"-c")
|
||||
shift
|
||||
certdata=$1
|
||||
;;
|
||||
"-u")
|
||||
merge=0
|
||||
;;
|
||||
"-d")
|
||||
diff=1
|
||||
difffile=$1
|
||||
;;
|
||||
*)
|
||||
echo "usage: $0 [-u URL] [-o target] [-c certdata] [-n]"
|
||||
echo "-u URL base URL to fetch code signing list"
|
||||
echo "-o target name of the codesigning target"
|
||||
echo "-c certdata patch to certdata.txt to merge with"
|
||||
echo "-d diff optional diff file"
|
||||
echo "-n don't merge"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
|
||||
wget ${baseurl} -O ${target}
|
||||
|
||||
if [ ${merge} -eq 0 ]; then
|
||||
exit 0;
|
||||
fi
|
||||
|
||||
out=${certdata}
|
||||
if [ ${diff} -eq 1]; then
|
||||
out=${certdata}.out
|
||||
fi
|
||||
|
||||
python3 ./mergepem2certdata.py -c "${certdata}" -p "${target}" -o "${out}" -t "CKA_TRUST_CODE_SIGNING" -l "Microsoft Code Signing Only Certificate"
|
||||
|
||||
if [ ${diff} -eq 1 ]; then
|
||||
diff -u ${certdata} ${out} > ${difffile}
|
||||
mv ${out} ${certdata}
|
||||
fi
|
320
mergepem2certdata.py
Normal file
320
mergepem2certdata.py
Normal file
@ -0,0 +1,320 @@
|
||||
#!/usr/bin/python
|
||||
# vim:set et sw=4:
|
||||
#
|
||||
# certdata2pem.py - splits certdata.txt into multiple files
|
||||
#
|
||||
# Copyright (C) 2009 Philipp Kern <pkern@debian.org>
|
||||
# Copyright (C) 2013 Kai Engert <kaie@redhat.com>
|
||||
#
|
||||
# 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 subprocess
|
||||
import getopt
|
||||
import asn1
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
|
||||
objects = []
|
||||
|
||||
pemcerts = []
|
||||
|
||||
certdata='./certdata.txt'
|
||||
pem='./cert.pem'
|
||||
output='./certdata_out.txt'
|
||||
trust='CKA_TRUST_CODE_SIGNING'
|
||||
merge_label="Non-Mozilla Object Signing Only Certificate"
|
||||
|
||||
trust_types = {
|
||||
"CKA_TRUST_SERVER_AUTH",
|
||||
"CKA_TRUST_EMAIL_PROTECTION",
|
||||
"CKA_TRUST_CODE_SIGNING"
|
||||
}
|
||||
|
||||
attribute_types = {
|
||||
"CKA_CLASS" : "CK_OBJECT_CLASS",
|
||||
"CKA_TOKEN" : "CK_BBOOL",
|
||||
"CKA_PRIVATE" : "CK_BBOOL",
|
||||
"CKA_MODIFIABLE" : "CK_BBOOL",
|
||||
"CKA_LABEL" : "UTF8",
|
||||
"CKA_CERTIFICATE_TYPE" : "CK_CERTIFICATE_TYPE",
|
||||
"CKA_SUBJECT" : "MULTILINE_OCTAL",
|
||||
"CKA_ID" : "UTF8",
|
||||
"CKA_CERT_SHA1_HASH" : "MULTILINE_OCTAL",
|
||||
"CKA_CERT_MD5_HASH" : "MULTILINE_OCTAL",
|
||||
"CKA_ISSUER" : "MULTILINE_OCTAL",
|
||||
"CKA_SERIAL_NUMBER" : "MULTILINE_OCTAL",
|
||||
"CKA_VALUE" : "MULTILINE_OCTAL",
|
||||
"CKA_NSS_MOZILLA_CA_POLICY" : "CK_BBOOL",
|
||||
"CKA_NSS_SERVER_DISTRUST_AFTER" : "Distrust",
|
||||
"CKA_NSS_EMAIL_DISTRUST_AFTER" : "Distrust",
|
||||
"CKA_TRUST_SERVER_AUTH" : "CK_TRUST",
|
||||
"CKA_TRUST_EMAIL_PROTECTION" : "CK_TRUST",
|
||||
"CKA_TRUST_CODE_SIGNING" : "CK_TRUST",
|
||||
"CKA_TRUST_STEP_UP_APPROVED" : "CK_BBOOL"
|
||||
}
|
||||
|
||||
def printable_serial(obj):
|
||||
return ".".join([str(x) for x in obj['CKA_SERIAL_NUMBER']])
|
||||
|
||||
def getSerial(cert):
|
||||
encoder = asn1.Encoder()
|
||||
encoder.start()
|
||||
encoder.write(cert.serial_number)
|
||||
return encoder.output()
|
||||
|
||||
def dumpOctal(f,value):
|
||||
for i in range(len(value)) :
|
||||
if i % 16 == 0 :
|
||||
f.write("\n")
|
||||
f.write("\\%03o"%int.from_bytes(value[i:i+1],sys.byteorder))
|
||||
f.write("\nEND\n")
|
||||
|
||||
# in python 3.8 this can be replaces with return byteval.hex(':',1)
|
||||
def formatHex(byteval) :
|
||||
string=byteval.hex()
|
||||
string_out=""
|
||||
for i in range(0,len(string)-2,2) :
|
||||
string_out += string[i:i+2] + ':'
|
||||
string_out += string[-2:]
|
||||
return string_out
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:],"c:o:p:t:l:",)
|
||||
except getopt.GetoptError as err:
|
||||
print(err)
|
||||
print(sys.argv[0] + ' [-c certdata] [-p pem] [-o certdata_target] [-t trustvalue] [-l merge_label]')
|
||||
print('-c certdata certdata file to merge to (default="'+certdata+'")');
|
||||
print('-p pem pem file with CAs to merge from (default="'+pem+'")');
|
||||
print('-o certdata_target resulting output file (default="'+output+'")');
|
||||
print('-t trustvalue what these CAs are trusted for (default="'+trust+'")');
|
||||
print('-l merge_label what label CAs that aren\'t in certdata (default="'+merge_label+'")');
|
||||
sys.exit(2)
|
||||
|
||||
for opt, arg in opts:
|
||||
if opt == '-c' :
|
||||
certdata = arg
|
||||
elif opt == '-p' :
|
||||
pem = arg
|
||||
elif opt == '-o' :
|
||||
output = arg
|
||||
elif opt == '-t' :
|
||||
trust = arg
|
||||
elif opt == '-l' :
|
||||
merge_label = arg
|
||||
|
||||
# read the pem file
|
||||
in_cert, certvalue = False, ""
|
||||
for line in open(pem, 'r'):
|
||||
if not in_cert:
|
||||
if line.find("BEGIN CERTIFICATE") != -1:
|
||||
in_cert = True;
|
||||
continue
|
||||
# Ignore comment lines and blank lines.
|
||||
if line.startswith('#'):
|
||||
continue
|
||||
if len(line.strip()) == 0:
|
||||
continue
|
||||
if line.find("END CERTIFICATE") != -1 :
|
||||
pemcerts.append(certvalue);
|
||||
certvalue = "";
|
||||
in_cert = False;
|
||||
continue
|
||||
certvalue += line;
|
||||
|
||||
|
||||
# read the certdata.txt file
|
||||
in_data, in_multiline, in_obj = False, False, False
|
||||
field, ftype, value, binval, obj = None, None, None, bytearray(), dict()
|
||||
header, comment = "", ""
|
||||
for line in open(certdata, 'r'):
|
||||
# Ignore the file header.
|
||||
if not in_data:
|
||||
header += line
|
||||
if line.startswith('BEGINDATA'):
|
||||
in_data = True
|
||||
continue
|
||||
# Ignore comment lines.
|
||||
if line.startswith('#'):
|
||||
comment += line
|
||||
continue
|
||||
|
||||
# Empty lines are significant if we are inside an object.
|
||||
if in_obj and len(line.strip()) == 0:
|
||||
# collect all the inline comments in this object
|
||||
obj['Comment'] += comment
|
||||
comment = ""
|
||||
objects.append(obj)
|
||||
obj = dict()
|
||||
in_obj = False
|
||||
continue
|
||||
if len(line.strip()) == 0:
|
||||
continue
|
||||
if in_multiline:
|
||||
if not line.startswith('END'):
|
||||
if ftype == 'MULTILINE_OCTAL':
|
||||
line = line.strip()
|
||||
for i in re.finditer(r'\\([0-3][0-7][0-7])', line):
|
||||
integ = int(i.group(1), 8)
|
||||
binval.extend((integ).to_bytes(1, sys.byteorder))
|
||||
obj[field] = binval
|
||||
else:
|
||||
value += line
|
||||
obj[field] = value
|
||||
continue
|
||||
in_multiline = False
|
||||
continue
|
||||
if line.startswith('CKA_CLASS'):
|
||||
in_obj = True
|
||||
obj['Comment'] = comment
|
||||
comment = ""
|
||||
line_parts = line.strip().split(' ', 2)
|
||||
if len(line_parts) > 2:
|
||||
field, ftype = line_parts[0:2]
|
||||
value = ' '.join(line_parts[2:])
|
||||
elif len(line_parts) == 2:
|
||||
field, ftype = line_parts
|
||||
value = None
|
||||
else:
|
||||
raise NotImplementedError('line_parts < 2 not supported.\n' + line)
|
||||
if ftype == 'MULTILINE_OCTAL':
|
||||
in_multiline = True
|
||||
value = ""
|
||||
binval = bytearray()
|
||||
continue
|
||||
obj[field] = value
|
||||
if len(list(obj.items())) > 0:
|
||||
objects.append(obj)
|
||||
|
||||
# now merge the results
|
||||
for certval in pemcerts:
|
||||
certder = base64.b64decode(certval)
|
||||
cert = x509.load_der_x509_certificate(certder)
|
||||
certhashsha1 = cert.fingerprint(hashes.SHA1())
|
||||
certhashmd5 = cert.fingerprint(hashes.MD5())
|
||||
try:
|
||||
label=cert.subject.get_attributes_for_oid(x509.oid.NameOID.COMMON_NAME)[0].value
|
||||
except:
|
||||
try:
|
||||
label=cert.subject.get_attributes_for_oid(x509.oid.NameOID.ORGANIZATION_UNIT_NAME)[0].value
|
||||
except:
|
||||
try:
|
||||
label=cert.subject.get_attributes_for_oid(x509.oid.NameOID.ORGANIZATION_NAME)[0].value
|
||||
except:
|
||||
label="Unknown Certificate"
|
||||
|
||||
|
||||
found = False
|
||||
# see if it exists in certdata.txt
|
||||
for obj in objects:
|
||||
# we only need to check the trust objects, because
|
||||
# that is the object we would modify if it exists
|
||||
if obj['CKA_CLASS'] != 'CKO_NSS_TRUST':
|
||||
continue
|
||||
# explicitly distrusted certs don't have a hash value
|
||||
if not 'CKA_CERT_SHA1_HASH' in obj:
|
||||
continue
|
||||
if obj['CKA_CERT_SHA1_HASH'] != certhashsha1:
|
||||
continue
|
||||
obj[trust] = 'CKT_NSS_TRUSTED_DELEGATOR'
|
||||
found = True
|
||||
print('Found "'+label+'"');
|
||||
break
|
||||
if found :
|
||||
continue
|
||||
# append this certificate
|
||||
obj=dict()
|
||||
time='%a %b %d %H:%M:%S %Y'
|
||||
comment = '# ' + merge_label + '\n# %s "'+label+'"\n'
|
||||
comment += '# Issuer: ' + cert.issuer.rfc4514_string() + '\n'
|
||||
comment += '# Serial Number:'
|
||||
sn=cert.serial_number
|
||||
if sn < 0x100000:
|
||||
comment += ' %d (0x%x)\n'%(sn,sn)
|
||||
else:
|
||||
comment += formatHex(sn.to_bytes((sn.bit_length()+7)//8,"big")) + '\n'
|
||||
comment += '# Subject: ' + cert.subject.rfc4514_string() + '\n'
|
||||
comment += '# Not Valid Before: ' + cert.not_valid_before.strftime(time) + '\n'
|
||||
comment += '# Not Valid After: ' + cert.not_valid_after.strftime(time) + '\n'
|
||||
comment += '# Fingerprint (MD5): ' + formatHex(certhashmd5) + '\n'
|
||||
comment += '# Fingerprint (SHA1): ' + formatHex(certhashsha1) + '\n'
|
||||
obj['Comment']= comment%"Certificate"
|
||||
obj['CKA_CLASS'] = 'CKO_CERTIFICATE'
|
||||
obj['CKA_TOKEN'] = 'CK_TRUE'
|
||||
obj['CKA_PRIVATE'] = 'CK_FALSE'
|
||||
obj['CKA_MODIFIABLE'] = 'CK_FALSE'
|
||||
obj['CKA_LABEL'] = '"' + label + '"'
|
||||
obj['CKA_CERTIFICATE_TYPE'] = 'CKC_X_509'
|
||||
obj['CKA_SUBJECT'] = cert.subject.public_bytes()
|
||||
obj['CKA_ID'] = '"0"'
|
||||
obj['CKA_ISSUER'] = cert.issuer.public_bytes()
|
||||
obj['CKA_SERIAL_NUMBER'] = getSerial(cert)
|
||||
obj['CKA_VALUE'] = certder
|
||||
obj['CKA_NSS_MOZILLA_CA_POLICY'] = 'CK_FALSE'
|
||||
obj['CKA_NSS_SERVER_DISTRUST_AFTER'] = 'CK_FALSE'
|
||||
obj['CKA_NSS_EMAIL_DISTRUST_AFTER'] = 'CK_FALSE'
|
||||
objects.append(obj)
|
||||
|
||||
# append the trust values
|
||||
obj=dict()
|
||||
obj['Comment']= comment%"Trust for"
|
||||
obj['CKA_CLASS'] = 'CKO_TRUST'
|
||||
obj['CKA_TOKEN'] = 'CK_TRUE'
|
||||
obj['CKA_PRIVATE'] = 'CK_FALSE'
|
||||
obj['CKA_MODIFIABLE'] = 'CK_FALSE'
|
||||
obj['CKA_LABEL'] = '"' + label + '"'
|
||||
obj['CKA_CERT_SHA1_HASH'] = certhashsha1
|
||||
obj['CKA_CERT_MD5_HASH'] = certhashmd5
|
||||
obj['CKA_ISSUER'] = cert.issuer.public_bytes()
|
||||
obj['CKA_SERIAL_NUMBER'] = getSerial(cert)
|
||||
for t in list(trust_types):
|
||||
if t == trust:
|
||||
obj[t] = 'CKT_NSS_TRUSTED_DELEGATOR'
|
||||
else:
|
||||
obj[t] = 'CKT_NSS_MUST_VERIFY_TRUST'
|
||||
obj['CKA_TRUST_STEP_UP_APPROVED'] = 'CK_FALSE'
|
||||
objects.append(obj)
|
||||
print('Added "'+label+'"');
|
||||
|
||||
# now dump the results
|
||||
f = open(output, 'w')
|
||||
f.write(header)
|
||||
for obj in objects:
|
||||
if 'Comment' in obj:
|
||||
f.write(obj['Comment'])
|
||||
else:
|
||||
print("Object with no comment!!")
|
||||
print(obj)
|
||||
for field in list(attribute_types.keys()):
|
||||
if not field in obj:
|
||||
continue
|
||||
ftype = attribute_types[field];
|
||||
if ftype == 'Distrust':
|
||||
if obj[field] == 'CK_FALSE':
|
||||
ftype = 'CK_BBOOL'
|
||||
else:
|
||||
ftype = 'MULTILINE_OCTAL'
|
||||
f.write("%s %s"%(field,ftype));
|
||||
if ftype == 'MULTILINE_OCTAL':
|
||||
dumpOctal(f,obj[field])
|
||||
else:
|
||||
f.write(" %s\n"%obj[field])
|
||||
f.write("\n")
|
||||
f.close
|
Loading…
Reference in New Issue
Block a user