#!/usr/bin/python
"""Extract certificates from a multi-certificate pem file.
Each certificate in the file is extracted into a format appropriate for use with
Brillo or Android. On success, the contents of the output directory match the
input file exactly. Existing files in the output directory will be deleted.
The current date will be written into the timestamp file, './TIMESTAMP' by
default.
Typical usage (extracting from ./roots.pem and output into ./files):
> ./extract_from_pem.py
"""
import argparse
import datetime
import os
import re
import M2Crypto # sudo apt-get install python-m2crypto
def WriteCertificateFile(content, base_name, output_dir):
"""Writes a certificate file to the output directory.
Args:
content: The file content to write.
base_name: The file name will be base_name.n where n is the first available
non-negative integer. Ex. if myfile.0 exists and has different
content, the output file will be myfile.1.
output_dir: The output directory.
"""
i = 0
file_path = os.path.join(output_dir, '%s.%d' % (base_name, i))
while os.path.exists(file_path):
with open(file_path) as existing_file:
if content == existing_file.read():
# Ignore identical duplicate.
return
i += 1
file_path = os.path.join(output_dir, '%s.%d' % (base_name, i))
with open(file_path, 'w') as new_file:
new_file.write(content)
def GetFingerprintString(x509):
"""Computes a fingerprint string as output by 'openssl x509 -fingerprint'.
Args:
x509: A M2Crypto.X509.X509 object.
Returns:
The fingerprint as a string.
"""
# Zero filled and with ':' between bytes.
return ':'.join(re.findall(r'..', x509.get_fingerprint('sha1').zfill(40)))
def main():
parser = argparse.ArgumentParser(description='PEM Certificate Importer')
parser.add_argument('--pem_file', nargs='?', default='roots.pem')
parser.add_argument('--output_dir', nargs='?', default='files')
parser.add_argument('--timestamp_file', nargs='?', default='TIMESTAMP')
args = parser.parse_args()
assert os.path.isdir(args.output_dir) and os.path.isfile(args.pem_file)
if 'y' != raw_input('All files in \'%s\' will be deleted. Proceed? [y,N]: ' %
args.output_dir):
print 'Aborted.'
return
for existing_file in os.listdir(args.output_dir):
os.remove(os.path.join(args.output_dir, existing_file))
with open(args.pem_file) as pem_file:
pattern = r'-----BEGIN CERTIFICATE-----[^-]*-----END CERTIFICATE-----'
pem_certs = re.findall(pattern, pem_file.read())
for pem_cert in pem_certs:
x509 = M2Crypto.X509.load_cert_string(pem_cert)
content = '%s%sSHA1 Fingerprint=%s\n' % (x509.as_pem(),
x509.as_text(),
GetFingerprintString(x509))
base_name = '%08x' % x509.get_subject().as_hash()
WriteCertificateFile(content, base_name, args.output_dir)
with open(args.timestamp_file, 'w') as timestamp_file:
timestamp_file.write('Last Update (YYYY-MM-DD): %s\n' %
datetime.date.today().isoformat())
if __name__ == '__main__':
main()