1 #!/usr/bin/python 2 3 """Extract certificates from a multi-certificate pem file. 4 5 Each certificate in the file is extracted into a format appropriate for use with 6 Brillo or Android. On success, the contents of the output directory match the 7 input file exactly. Existing files in the output directory will be deleted. 8 9 The current date will be written into the timestamp file, './TIMESTAMP' by 10 default. 11 12 Typical usage (extracting from ./roots.pem and output into ./files): 13 > ./extract_from_pem.py 14 """ 15 16 import argparse 17 import datetime 18 import os 19 import re 20 21 import M2Crypto # sudo apt-get install python-m2crypto 22 23 24 def WriteCertificateFile(content, base_name, output_dir): 25 """Writes a certificate file to the output directory. 26 27 Args: 28 content: The file content to write. 29 base_name: The file name will be base_name.n where n is the first available 30 non-negative integer. Ex. if myfile.0 exists and has different 31 content, the output file will be myfile.1. 32 output_dir: The output directory. 33 """ 34 i = 0 35 file_path = os.path.join(output_dir, '%s.%d' % (base_name, i)) 36 while os.path.exists(file_path): 37 with open(file_path) as existing_file: 38 if content == existing_file.read(): 39 # Ignore identical duplicate. 40 return 41 i += 1 42 file_path = os.path.join(output_dir, '%s.%d' % (base_name, i)) 43 with open(file_path, 'w') as new_file: 44 new_file.write(content) 45 46 47 def GetFingerprintString(x509): 48 """Computes a fingerprint string as output by 'openssl x509 -fingerprint'. 49 50 Args: 51 x509: A M2Crypto.X509.X509 object. 52 53 Returns: 54 The fingerprint as a string. 55 """ 56 # Zero filled and with ':' between bytes. 57 return ':'.join(re.findall(r'..', x509.get_fingerprint('sha1').zfill(40))) 58 59 60 def main(): 61 parser = argparse.ArgumentParser(description='PEM Certificate Importer') 62 parser.add_argument('--pem_file', nargs='?', default='roots.pem') 63 parser.add_argument('--output_dir', nargs='?', default='files') 64 parser.add_argument('--timestamp_file', nargs='?', default='TIMESTAMP') 65 args = parser.parse_args() 66 assert os.path.isdir(args.output_dir) and os.path.isfile(args.pem_file) 67 if 'y' != raw_input('All files in \'%s\' will be deleted. Proceed? [y,N]: ' % 68 args.output_dir): 69 print 'Aborted.' 70 return 71 for existing_file in os.listdir(args.output_dir): 72 os.remove(os.path.join(args.output_dir, existing_file)) 73 with open(args.pem_file) as pem_file: 74 pattern = r'-----BEGIN CERTIFICATE-----[^-]*-----END CERTIFICATE-----' 75 pem_certs = re.findall(pattern, pem_file.read()) 76 for pem_cert in pem_certs: 77 x509 = M2Crypto.X509.load_cert_string(pem_cert) 78 content = '%s%sSHA1 Fingerprint=%s\n' % (x509.as_pem(), 79 x509.as_text(), 80 GetFingerprintString(x509)) 81 base_name = '%08x' % x509.get_subject().as_hash() 82 WriteCertificateFile(content, base_name, args.output_dir) 83 with open(args.timestamp_file, 'w') as timestamp_file: 84 timestamp_file.write('Last Update (YYYY-MM-DD): %s\n' % 85 datetime.date.today().isoformat()) 86 87 88 if __name__ == '__main__': 89 main() 90