blob: 1f1cfe70283326e952e788120e4371264952d0be [file] [log] [blame]
#!/usr/bin/python3
# Copyright 2019 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Extract individual root cert pem files from bundle.
We expect the bundle is downloaded from https://pki.goog/roots.pem and contains
leading comment lines.
This script reads the specified ROOTS_PEM, parses header comments, and extracts
individual certs into .pem files with human-readable names (based on "Label").
"""
import argparse
import os
import re
import sys
class ExtractedCert:
"""This class represents a cert extracted from a PEM bundle."""
def __init__(self, lines, prefix=''):
self.lines = lines
self.prefix = prefix
def get_label(self):
for line in self.lines:
if line.startswith('# Label:'):
m = re.search('# Label: "([^"]+)"', line)
label = m.group(1)
return label
def get_filename(self):
"""Construct path to write to, based on "Label" comment."""
label_underscores = self.get_label().replace(' ', '_')
filename = '%s.pem' % label_underscores
path = os.path.join(self.prefix, filename)
return path
def write(self):
cert_file = self.get_filename()
parent_dir = os.path.dirname(cert_file)
if not os.path.exists(parent_dir):
os.makedirs(parent_dir)
with open(cert_file, 'w') as f:
f.writelines(self.lines)
def lex_pem_file(roots_pem):
"""Generator that splits lines from |roots_pem| on cert boundaries."""
with open(roots_pem) as f:
lines = f.readlines()
cert_lines = []
for line in lines:
cert_lines.append(line)
if line.startswith('-----END CERTIFICATE-----'):
yield cert_lines
cert_lines = []
def extract_certs(roots_pem, extract_to):
"""Extracts all certs as individual pem files.
Args:
roots_pem: Path to bundle file that is a concatenation of certs.
extract_to: Directory where extracted certs are written. When None,
extracted certs will not be written to disk.
"""
for line_list in lex_pem_file(roots_pem):
cert = ExtractedCert(line_list, prefix=extract_to)
if extract_to:
cert.write()
def main(argv):
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--roots-pem', help='File containing many certs.',
required=True)
parser.add_argument('--extract-to', default='',
help='Where to place extracted certs. If not specified,'
' files will not be written.')
opts = parser.parse_args(argv)
extract_certs(opts.roots_pem, opts.extract_to)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))