1#!/bin/bash 2 3# This script fetches the current list of trusted CAs blessed by Mozilla 4# for web tls validation, and processes it into two outputs 5# 6# - ./trust/webroot/* consisting of ./_trust/webroot/der a static, serveable set 7# of trusted DER certs, with symlinks in ./_trust/webroot/by-skid and 8# ./_trust/webroot/by-iss allowing serving the DER matching a given 9# SubjectKeyIdentifier or Issuer + serial combination (suitably encoded) 10# 11# - ./_trust/blob-XXXX.bin a single blob containing indexes and DER CA certs 12# 13# - ./_trust/trust_blob.h a C uint8_t array formatted copy of blob-XXXX.bin 14 15# The trust blob layout is currently 16# 17# 54 42 4c 42 Magic "TBLB" 18# 00 01 MSB-first trust blob layout version 19# XX XX MSB-first count of certificates 20# XX XX XX XX MSB-first trust blob generation unix time 21# XX XX XX XX MSB-first offset of cert length table (MSB-first 16-bit length-per-cert) 22# XX XX XX XX MSB-first offset of SKID length table (8-bit length-per-cert) 23# XX XX XX XX MSB-first offset of SKID table 24# XX XX XX XX MSB-first total blob length 25# 26# XX .. XX DER certs (start at +0x1c) 27# XX .. XX DER cert length table (MSB-first 16-bit per cert) 28# XX .. XX SKID length table (8-bit per cert) 29# XX .. XX SKID table (variable per cert) 30# 31 32echo "Mozilla trust bundle for TLS validation processing Andy Green <[email protected]>" 33echo 34 35rm -rf _trust 36mkdir _trust 37 38wget -O _trust/trusted.txt "https://ccadb-public.secure.force.com/mozilla/IncludedRootsPEMTxt?TrustBitsInclude=Websites" 39#cp ~/Downloads/IncludedRootsPEM.txt _trust/trusted.txt 40 41if [ $? -ne 0 ]; then 42 echo "Failed to get current website trust bundle" 43 exit 1 44fi 45 46mkdir -p _trust/webroot/by-skid _trust/webroot/by-iss _trust/webroot/der 47 48echo 0 > _trust/ofs 49echo 0 > _trust/count 50echo 0 > _trust/skidtab 51 52GT=`date +%s` 53BN=_trust/blob-$GT.bin 54 55cat _trust/trusted.txt | while read _line ; do 56 line=`echo -n $_line | sed 's/\r$//g'` 57 if [ "$line" == "-----BEGIN CERTIFICATE-----" ] ; then 58 echo $line > _trust/single 59 else 60 echo $line >> _trust/single 61 62 if [ "$line" == "-----END CERTIFICATE-----" ] ; then 63 openssl x509 -in _trust/single -text -noout > _trust/c1 64 if [ $? -ne 0 ] ; then 65 echo "FAILED" 66 exit 1 67 fi 68 69 ISS=`cat _trust/c1 | grep Issuer: | sed "s/.*://g" | sed "s/^\ *//g"` 70 SER=`cat _trust/c1 | grep "Serial Number:" | sed "s/.*://g" | sed "s/^\ *//g" | sed "s/\ .*//g"` 71 if [ -z "$SER" ] ; then 72 SER=`cat _trust/c1 | sed -e "1,/.*Serial Number:/ d" | head -n 1 | sed "s/^\ *//g" | sed "s/\ .*//g"` 73 fi 74 SKID=`cat _trust/c1 | sed -e '1,/.*X509v3 Subject Key Identifier:/ d' | sed -n '/Signature.*/q;p' | \ 75 grep ':' | grep -v ': ' | grep -v ':$' | grep -v U | grep -v k | grep -v T | grep -v "i" | \ 76 grep -v "S" | grep -v "V" | sed "s/^\ *//g"` 77 SKID_NO_COLONS=`echo -n $SKID | sed "s/://g"` 78 79 na=`cat _trust/c1 | grep "Not\ After\ :" | sed "s/.*\ :\ //g"` 80 ct=`date +%s` 81 ts=`date --date="$na" +%s` 82 life_days=`echo -n "$(( ( $ts - $ct ) / 86400 ))"` 83 84 echo "$life_days $safe" >> _trust/life 85 if [ $life_days -lt 1095 ] ; then 86 echo "$life_days $safe" >> _trust/life_lt_3y 87 fi 88 89 echo "issuer=\"$ISS\", serial=\"${SER^^}\", skid=\"${SKID_NO_COLONS^^}\", life_days=\"${life_days}\"" 90 91 issname=`echo -n "$ISS"_"$SER" | tr -cd '[a-zA-Z0-9]_'` 92 skidname=`echo -n "$SKID_NO_COLONS" | tr -cd '[a-zA-Z0-9]_'` 93 safe=$issname"_"$skidname 94 95 cat _trust/single | grep -v -- '---' | base64 -d > _trust/webroot/der/$safe 96 cd _trust/webroot/by-skid 97 ln -sf ../der/$safe $SKID_NO_COLONS 98 cd ../../.. 99 cd _trust/webroot/by-iss 100 ln -sf ../der/$safe $issname 101 cd ../../.. 102 103 DERSIZ=`cat _trust/single | grep -v -- '---' | base64 -d | wc -c | cut -d' ' -f1` 104 105 cat _trust/single | grep -v -- '---' | base64 -d | hexdump -C | tr -s ' ' | sed 's/\ $//g' | \ 106 cut -d' ' -f 2-17 | cut -d'|' -f1 | grep -v 000 | sed "s/\ //g" | sed ':a;N;$!ba;s/\n//g' | xxd -r -p >> _trust/_ders 107 108 printf "%04x" $DERSIZ | xxd -r -p >> _trust/_derlens 109 110echo $SKID 111 112 if [ ! -z "$SKID" ] ; then 113 echo -n "$SKID_NO_COLONS" | xxd -r -p >> _trust/_skid 114 fi 115 SKIDSIZ=`echo -n $SKID_NO_COLONS | xxd -r -p | wc -c | cut -d' ' -f1` 116 printf "%02x" $SKIDSIZ | xxd -r -p >> _trust/_skidlens 117 118 OFS=`cat _trust/ofs` 119 echo -n $(( $OFS + $DERSIZ )) > _trust/ofs 120 COUNT=`cat _trust/count` 121 echo -n $(( $COUNT +1 )) > _trust/count 122 ST=`cat _trust/skidtab` 123 echo -n $(( $ST + ( `echo -n $skidname | wc -c | cut -d' ' -f1` / 2 ) )) > _trust/skidtab 124 125 rm -f _trust/single 126 127 fi 128 fi 129 130done 131 132 COUNT=`cat _trust/count` 133 OFS=`cat _trust/ofs` 134 ST=`cat _trust/skidtab` 135 136 # everything in the layout framing is MSB-first 137 138 # magic 139 echo -n "TBLB" > $BN 140 # blob layout version 141 echo -n 0001 | xxd -r -p >> $BN 142 # number of certs in the blob 143 printf "%04x" $COUNT | xxd -r -p >> $BN 144 # unix time blob was created 145 printf "%08x" $GT | xxd -r -p >> $BN 146 147 POS=28 148 POS=$(( $POS + `cat _trust/_ders | wc -c | cut -d' ' -f1` )) 149 150 # blob offset of start of cert length table 151 printf "%08x" $POS | xxd -r -p >> $BN 152 153 POS=$(( $POS + `cat _trust/_derlens | wc -c | cut -d' ' -f1` )) 154 155 # blob offset of start of SKID length table 156 printf "%08x" $POS | xxd -r -p >> $BN 157 158 POS=$(( $POS + `cat _trust/_skidlens | wc -c | cut -d' ' -f1` )) 159 160 # blob offset of start of SKID table 161 printf "%08x" $POS | xxd -r -p >> $BN 162 163 POS=$(( $POS + `cat _trust/_skid | wc -c | cut -d' ' -f1` )) 164 165 # blob total length 166 printf "%08x" $POS | xxd -r -p >> $BN 167 168 169 # the DER table, start at +0x1c 170 cat _trust/_ders >> $BN 171 # the DER length table 172 cat _trust/_derlens >> $BN 173 # the SKID length table 174 cat _trust/_skidlens >> $BN 175 # the SKID table 176 cat _trust/_skid >> $BN 177 178# produce a C-friendly version of the blob 179 180 cat $BN | hexdump -v -C | tr -s ' ' | sed 's/\ $//g' | \ 181 cut -d' ' -f 2-17 | cut -d'|' -f1 | grep -v 000 | sed "s/\ /,\ 0x/g" | sed "s/^/0x/g" | \ 182 sed 's/\, 0x$//g' | sed 's/$/,/g' >> _trust/trust_blob.h 183 184 185 echo 186 echo "$COUNT CA certs, $POS byte blob" 187 echo 188 echo "CAs expiring in less than 3 years (days left):" 189 sort -h _trust/life_lt_3y 190 191 rm -f _trust/count _trust/_idx _trust/_idx_skid _trust/ofs _trust/_skid _trust/skidtab _trust/life _trust/life_lt_3y _trust/c1 _trust/single _trust/_derlens _trust/_ders _trust/_skid _trust/_skidlens 192 193exit 0 194 195