Home | History | Annotate | Download | only in google
      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