1#!/usr/bin/env python
2# Copyright 2015 The Chromium Authors
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     https://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import base64
17import copy
18import os
19import random
20import subprocess
21import sys
22import tempfile
23
24
25def generate(token, s, out_fn):
26  with tempfile.NamedTemporaryFile() as der_tmpfile:
27    with tempfile.NamedTemporaryFile() as conf_tempfile:
28      conf_tempfile.write(str(s))
29      conf_tempfile.flush()
30      description_tmpfile = tempfile.NamedTemporaryFile()
31      subprocess.check_call(["openssl", "asn1parse", "-genconf",
32                             conf_tempfile.name, "-i", "-out",
33                             der_tmpfile.name],
34                            stdout=description_tmpfile)
35
36    with open(out_fn, "w") as output_file:
37      description_tmpfile.seek(0)
38      output_file.write(description_tmpfile.read())
39      output_file.write("-----BEGIN %s-----\n" % token)
40      output_file.write(base64.encodestring(der_tmpfile.read()))
41      output_file.write("-----END %s-----\n" % token)
42
43
44class CertificatePoliciesGenerator:
45  def __init__(self):
46    self.policies = []
47
48  def generate(self, out_fn):
49    generate("CERTIFICATE POLICIES", self, out_fn)
50
51  def add_policy(self, policy):
52    self.policies.append(policy)
53
54  def __str__(self):
55    s = "asn1 = SEQUENCE:certificatePoliciesSequence\n"
56    s += "[certificatePoliciesSequence]\n"
57    s_suffix = ""
58    for n, policy in enumerate(self.policies):
59      n1, n2 = (str(policy) + "\n").split("\n", 1)
60      if n2:
61        s_suffix += n2 + "\n"
62      s += "%s%s\n" % (n, n1)
63
64    return s + s_suffix
65
66
67def policy_qualifier(qualifier_id, qualifier):
68  i = random.randint(0, sys.maxint)
69  s = "asn1 = SEQUENCE:PolicyQualifierInfoSequence%i\n" % i
70  s += "[PolicyQualifierInfoSequence%i]\n" % i
71  s += "policyQualifierId = %s\n" % qualifier_id
72  s += qualifier
73  return s
74
75
76def cps_uri_qualifier(url):
77  return policy_qualifier("OID:id-qt-cps", "cPSUri = IA5STRING:%s\n" % url)
78
79
80def policy_information(policy_id, qualifiers):
81  i = random.randint(0, sys.maxint)
82  s = "policyInformation = SEQUENCE:PolicyInformationSequence%i\n" % i
83  s += "[PolicyInformationSequence%i]\n" % i
84  s += "policyIdentifier = OID:%s\n" % policy_id
85  s_suffix = ""
86  if qualifiers is not None:
87    s += "policyQualifiers = SEQUENCE:PolicyQualifiersSequence%i\n" % i
88    s += "[PolicyQualifiersSequence%i]\n" % i
89    for n, qualifier in enumerate(qualifiers):
90      n1, n2 = (str(qualifier) + "\n").split("\n", 1)
91      if n2:
92        s_suffix += n2 + "\n"
93      s += "%s%s\n" % (n, n1)
94
95  return s + s_suffix
96
97
98def main():
99  p = CertificatePoliciesGenerator()
100  p.generate("invalid-empty.pem")
101
102  p = CertificatePoliciesGenerator()
103  p.add_policy(policy_information("anyPolicy", None))
104  p.generate("anypolicy.pem")
105
106  p = CertificatePoliciesGenerator()
107  p.add_policy(policy_information("anyPolicy", [
108      cps_uri_qualifier("https://example.com/1_2_3")]))
109  p.generate("anypolicy_with_qualifier.pem")
110
111  p = CertificatePoliciesGenerator()
112  p.add_policy(policy_information("anyPolicy", [
113      policy_qualifier("OID:1.2.3.4", 'foo = UTF8:"hi"')]))
114  p.generate("invalid-anypolicy_with_custom_qualifier.pem")
115
116  p = CertificatePoliciesGenerator()
117  p.add_policy(policy_information("1.2.3", None))
118  p.generate("policy_1_2_3.pem")
119
120  p = CertificatePoliciesGenerator()
121  p.add_policy(policy_information("1.2.3", [
122      cps_uri_qualifier("https://example.com/1_2_3")]))
123  p.generate("policy_1_2_3_with_qualifier.pem")
124
125  p = CertificatePoliciesGenerator()
126  p.add_policy(policy_information("1.2.3", [
127      policy_qualifier("OID:1.2.3.4", 'foo = UTF8:"hi"')]))
128  p.generate("policy_1_2_3_with_custom_qualifier.pem")
129
130  p = CertificatePoliciesGenerator()
131  p.add_policy(policy_information("1.2.3", None))
132  p.add_policy(policy_information("1.2.3", [
133      cps_uri_qualifier("https://example.com/1_2_3")]))
134  p.generate("invalid-policy_1_2_3_dupe.pem")
135
136  p = CertificatePoliciesGenerator()
137  p.add_policy(policy_information("1.2.3", []))
138  p.generate("invalid-policy_1_2_3_with_empty_qualifiers_sequence.pem")
139
140  p = CertificatePoliciesGenerator()
141  p.add_policy(policy_information("1.2.3", None))
142  p.add_policy(policy_information("1.2.4", None))
143  p.generate("policy_1_2_3_and_1_2_4.pem")
144
145  p = CertificatePoliciesGenerator()
146  p.add_policy(policy_information("1.2.3", [
147      cps_uri_qualifier("https://example.com/1_2_3")]))
148  p.add_policy(policy_information("1.2.4", [
149      cps_uri_qualifier("http://example.com/1_2_4")]))
150  p.generate("policy_1_2_3_and_1_2_4_with_qualifiers.pem")
151
152  generate("CERTIFICATE POLICIES",
153           "asn1 = SEQUENCE:certificatePoliciesSequence\n"
154           "[certificatePoliciesSequence]\n"
155           "policyInformation = SEQUENCE:PolicyInformationSequence\n"
156           'extradata = IA5STRING:"unconsumed data"\n'
157           "[PolicyInformationSequence]\n"
158           "policyIdentifier = OID:1.2.3\n",
159           "invalid-policy_1_2_3_policyinformation_unconsumed_data.pem")
160
161  generate("CERTIFICATE POLICIES",
162           "asn1 = SEQUENCE:certificatePoliciesSequence\n"
163           "[certificatePoliciesSequence]\n"
164           "policyInformation = SEQUENCE:PolicyInformationSequence\n"
165           "[PolicyInformationSequence]\n"
166           "policyIdentifier = OID:1.2.3\n"
167           "policyQualifiers = SEQUENCE:PolicyQualifiersSequence\n"
168           "[PolicyQualifiersSequence]\n"
169           "policyQualifierInfo = SEQUENCE:PolicyQualifierInfoSequence\n"
170           "[PolicyQualifierInfoSequence]\n"
171           "policyQualifierId = OID:id-qt-cps\n"
172           "cPSUri = IA5STRING:https://example.com/1_2_3\n"
173           'extradata = IA5STRING:"unconsumed data"\n',
174           "invalid-policy_1_2_3_policyqualifierinfo_unconsumed_data.pem")
175
176  generate("CERTIFICATE POLICIES",
177           "asn1 = SEQUENCE:certificatePoliciesSequence\n"
178           "[certificatePoliciesSequence]\n"
179           "policyInformation = SEQUENCE:PolicyInformationSequence\n"
180           "[PolicyInformationSequence]\n"
181           'policyIdentifier = IA5STRING:"1.2.3"\n',
182           "invalid-policy_identifier_not_oid.pem")
183
184
185if __name__ == "__main__":
186  main()
187