You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
90 lines
3.1 KiB
90 lines
3.1 KiB
7 months ago
|
#!/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()
|