• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Copyright 2016 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""
7Given a path to a XXX.pem file, re-generates a CERTIFICATE.
8
9The .pem file is expected to contain comments that resemble:
10
11#-----BEGIN XXX-----
12<ascii-der values in here>
13#-----END XXX-----
14
15These are interpreted as substitutions to make inside of the Certificate
16template (v3_certificate_template.txt)
17"""
18
19import sys
20import os
21import re
22import base64
23import subprocess
24
25
26def read_file_to_string(path):
27  """Reads a file entirely to a string"""
28  with open(path, 'r') as f:
29    return f.read()
30
31
32def write_string_to_file(data, path):
33  """Writes a string to a file"""
34  print "Writing file %s ..." % (path)
35  with open(path, "w") as f:
36    f.write(data)
37
38
39def replace_string(original, start, end, replacement):
40  """Replaces the specified range of |original| with |replacement|"""
41  return original[0:start] + replacement + original[end:]
42
43
44def apply_substitution(template, name, value):
45  """Finds a section named |name| in |template| and replaces it with |value|."""
46  # Find the section |name| in |template|.
47  regex = re.compile(r'#-----BEGIN %s-----(.*?)#-----END %s-----' %
48                    (re.escape(name), re.escape(name)), re.DOTALL)
49  m = regex.search(template)
50  if not m:
51    print "Couldn't find a section named %s in the template" % (name)
52    sys.exit(1)
53
54  return replace_string(template, m.start(1), m.end(1), value)
55
56
57def main():
58  if len(sys.argv) != 2:
59    print 'Usage: %s <PATH_TO_PEM>' % (sys.argv[0])
60    sys.exit(1)
61
62  pem_path = sys.argv[1]
63  orig = read_file_to_string(pem_path)
64
65  cert_ascii = read_file_to_string("v3_certificate_template.txt")
66
67  # Apply all substitutions described by comments in |orig|
68  regex = re.compile(r'#-----BEGIN ([\w ]+)-----(.*?)#-----END \1-----',
69                     re.DOTALL)
70  num_matches = 0
71  for m in regex.finditer(orig):
72    num_matches += 1
73    cert_ascii = apply_substitution(cert_ascii, m.group(1), m.group(2))
74
75  if num_matches == 0:
76    print "Input did not contain any substitutions"
77    sys.exit(1)
78
79  # Convert the ascii-der to actual DER binary.
80  cert_der = None
81  try:
82    p = subprocess.Popen(['ascii2der'], stdout=subprocess.PIPE,
83                         stdin=subprocess.PIPE, stderr=subprocess.STDOUT)
84    cert_der = p.communicate(input=cert_ascii)[0]
85  except OSError as e:
86    print ('ERROR: Failed executing ascii2der.\n'
87           'Make sure this is in your path\n'
88           'Obtain it from https://github.com/google/der-ascii')
89    sys.exit(1)
90
91  # Replace the CERTIFICATE block with the newly generated one.
92  regex = re.compile(r'-----BEGIN CERTIFICATE-----\n(.*?)\n'
93                     '-----END CERTIFICATE-----', re.DOTALL)
94  m = regex.search(orig)
95  if not m:
96    print "ERROR: Cannot find CERTIFICATE block in input"
97    sys.exit(1)
98  modified = replace_string(orig, m.start(1), m.end(1),
99                            base64.b64encode(cert_der))
100
101  # Write back the .pem file.
102  write_string_to_file(modified, pem_path)
103
104main()
105