1#!/usr/bin/env python
2# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
3# vim: set filetype=python
4
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
9# This file generates the certspec files for test_cert_version.js. The naming
10# convention for those files is generally of the form
11# "<subject-description>_<issuer-description>.pem.certspec". End-entity
12# certificates are generally called "ee". Intermediates are called
13# "int". The root CA is called "ca" and self-signed certificates are called
14# "ss".
15# In the case that the subject and issuer are the same, the redundant part is
16# not repeated.
17# If there is nothing particularly special about a certificate, it has no
18# description ("nothing particularly special" meaning the certificate is X509v3
19# and has or does not have the basic constraints extension as expected by where
20# it is in the hierarchy). Otherwise, the description includes its version and
21# details about the extension. If the extension is not present, the string
22# "noBC" is used. If it is present but the cA bit is not asserted, the string
23# "BC-not-cA" is used. If it is present with the cA bit asserted, the string
24# "BC-cA" is used.
25# For example, a v1 intermediate that does not have the extension that was
26# issued by the root CA has the name "int-v1-noBC_ca.pem.certspec".
27# A v4 end-entity that does have the extension but does not assert the cA bit
28# that was issued by the root CA has the name
29# "ee-v4-BC-not-cA_ca.pem.certspec".
30# An end-entity issued by a v3 intermediate with the extension that asserts the
31# cA bit has the name "ee_int-v3-BC-cA.pem.certspec".
32
33versions = {
34    'v1': 1,
35    'v2': 2,
36    'v3': 3,
37    'v4': 4
38}
39
40basicConstraintsTypes = {
41    'noBC': '',
42    'BC-not-cA': 'extension:basicConstraints:,',
43    'BC-cA': 'extension:basicConstraints:cA,'
44}
45
46def writeCertspec(issuer, subject, fields):
47    filename = '%s_%s.pem.certspec' % (subject, issuer)
48    if issuer == subject:
49        filename = '%s.pem.certspec' % subject
50    with open(filename, 'w') as f:
51        f.write('issuer:%s\n' % issuer)
52        f.write('subject:%s\n' % subject)
53        for field in fields:
54            if len(field) > 0:
55                f.write('%s\n' % field)
56
57
58keyUsage = 'extension:keyUsage:keyCertSign,cRLSign'
59basicConstraintsCA = 'extension:basicConstraints:cA,'
60
61writeCertspec('ca', 'ca', [keyUsage, basicConstraintsCA])
62
63for versionStr, versionVal in versions.iteritems():
64    # intermediates
65    versionText = 'version:%s' % versionVal
66    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
67        intermediateName = 'int-%s-%s' % (versionStr, basicConstraintsType)
68        writeCertspec('ca', intermediateName,
69                      [keyUsage, versionText, basicConstraintsExtension])
70        writeCertspec(intermediateName, 'ee', [])
71
72    # end-entities
73    versionText = 'version:%s' % versionVal
74    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
75        writeCertspec('ca', 'ee-%s-%s' % (versionStr, basicConstraintsType),
76                      [versionText, basicConstraintsExtension])
77
78    # self-signed certificates
79    versionText = 'version:%s' % versionVal
80    for basicConstraintsType, basicConstraintsExtension in basicConstraintsTypes.iteritems():
81        selfSignedName = 'ss-%s-%s' % (versionStr, basicConstraintsType)
82        writeCertspec(selfSignedName, selfSignedName,
83                      [versionText, basicConstraintsExtension])
84