普通文本  |  90行  |  3.14 KB

#!/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()