15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import asn1
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import hashlib
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import os
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This file implements very minimal certificate and OCSP generation. It's
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# designed to test revocation checking.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RandomNumber(length_in_bytes):
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''RandomNumber returns a random number of length 8*|length_in_bytes| bits'''
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rand = os.urandom(length_in_bytes)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  n = 0
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for x in rand:
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n <<= 8
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n |= ord(x)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return n
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def ModExp(n, e, p):
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''ModExp returns n^e mod p'''
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  r = 1
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while e != 0:
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if e & 1:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      r = (r*n) % p
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    e >>= 1
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n = (n*n) % p
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return r
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci# PKCS1v15_SHA256_PREFIX is the ASN.1 prefix for a SHA256 signature.
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciPKCS1v15_SHA256_PREFIX = '3031300d060960864801650304020105000420'.decode('hex')
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class RSA(object):
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def __init__(self, modulus, e, d):
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.m = modulus
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.e = e
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.d = d
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    self.modlen = 0
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    m = modulus
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while m != 0:
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      self.modlen += 1
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      m >>= 8
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def Sign(self, message):
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    digest = hashlib.sha256(message).digest()
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    prefix = PKCS1v15_SHA256_PREFIX
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    em = ['\xff'] * (self.modlen - 1 - len(prefix) - len(digest))
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    em[0] = '\x00'
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    em[1] = '\x01'
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    em += "\x00" + prefix + digest
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    n = 0
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for x in em:
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      n <<= 8
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      n |= ord(x)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    s = ModExp(n, self.d, self.m)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out = []
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while s != 0:
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      out.append(s & 0xff)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      s >>= 8
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    out.reverse()
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return '\x00' * (self.modlen - len(out)) + asn1.ToBytes(out)
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  def ToDER(self):
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return asn1.ToDER(asn1.SEQUENCE([self.m, self.e]))
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Name(cn = None, c = None, o = None):
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  names = asn1.SEQUENCE([])
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if cn is not None:
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    names.children.append(
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SET([
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.SEQUENCE([
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          COMMON_NAME, cn,
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ])
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ])
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    )
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if c is not None:
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    names.children.append(
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SET([
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.SEQUENCE([
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          COUNTRY, c,
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ])
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ])
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    )
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if o is not None:
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    names.children.append(
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SET([
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.SEQUENCE([
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ORGANIZATION, o,
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ])
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ])
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    )
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return names
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# The private key and root certificate name are hard coded here:
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This is the private key
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)KEY = RSA(0x00a71998f2930bfe73d031a87f133d2f378eeeeed52a77e44d0fc9ff6f07ff32cbf3da999de4ed65832afcb0807f98787506539d258a0ce3c2c77967653099a9034a9b115a876c39a8c4e4ed4acd0c64095946fb39eeeb47a0704dbb018acf48c3a1c4b895fc409fb4a340a986b1afc45519ab9eca47c30185c771c64aa5ecf07d,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          3,
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          0x6f6665f70cb2a9a28acbc5aa0cd374cfb49f49e371a542de0a86aa4a0554cc87f7e71113edf399021ca875aaffbafaf8aee268c3b15ded2c84fb9a4375bbc6011d841e57833bc6f998d25daf6fa7f166b233e3e54a4bae7a5aaaba21431324967d5ff3e1d4f413827994262115ca54396e7068d0afa7af787a5782bc7040e6d3)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# And the same thing in PEM format
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)KEY_PEM = '''-----BEGIN RSA PRIVATE KEY-----
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)MIICXAIBAAKBgQCnGZjykwv+c9AxqH8TPS83ju7u1Sp35E0Pyf9vB/8yy/PamZ3k
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)7WWDKvywgH+YeHUGU50ligzjwsd5Z2UwmakDSpsRWodsOajE5O1KzQxkCVlG+znu
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)60egcE27AYrPSMOhxLiV/ECftKNAqYaxr8RVGaueykfDAYXHccZKpezwfQIBAwKB
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)gG9mZfcMsqmiisvFqgzTdM+0n0njcaVC3gqGqkoFVMyH9+cRE+3zmQIcqHWq/7r6
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)+K7iaMOxXe0shPuaQ3W7xgEdhB5XgzvG+ZjSXa9vp/FmsjPj5UpLrnpaqrohQxMk
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ln1f8+HU9BOCeZQmIRXKVDlucGjQr6eveHpXgrxwQObTAkEA2wBAfuduw5G0/VfN
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Wx66D5fbPccfYFqLM5LuTimLmNqzK2gIKXckB2sm44gJZ6wVlumaB1CSNug2LNYx
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)3cAjUwJBAMNUo1hbI8ugqqwI9kpxv9+2Heea4BlnXbS6tYF8pvkHMoliuxNbXmmB
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)u4zNB5iZ6V0ZZ4nvtUNo2cGr/h/Lcu8CQQCSACr/RPSCYSNTj948vya1D+d+hL+V
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)kbIiYfQ0G7Jl5yIc8AVw+hgE8hntBVuacrkPRmaviwwkms7IjsvpKsI3AkEAgjhs
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)5ZIX3RXHHVtO3EvVP86+mmdAEO+TzdHOVlMZ+1ohsOx8t5I+8QEnszNaZbvw6Lua
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)W/UjgkXmgR1UFTJMnwJBAKErmAw21/g3SST0a4wlyaGT/MbXL8Ouwnb5IOKQVe55
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CZdeVeSh6cJ4hAcQKfr2s1JaZTJFIBPGKAif5HqpydA=
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)-----END RSA PRIVATE KEY-----
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)'''
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Root certificate CN
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ISSUER_CN = "Testing CA"
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# All certificates are issued under this policy OID, in the Google arc:
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CERT_POLICY_OID = asn1.OID([1, 3, 6, 1, 4, 1, 11129, 2, 4, 1])
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# These result in the following root certificate:
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# -----BEGIN CERTIFICATE-----
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# MIIB0TCCATqgAwIBAgIBATANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpUZXN0aW5nIENBMB4X
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# DTEwMDEwMTA2MDAwMFoXDTMyMTIwMTA2MDAwMFowFTETMBEGA1UEAxMKVGVzdGluZyBDQTCBnTAN
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# BgkqhkiG9w0BAQEFAAOBiwAwgYcCgYEApxmY8pML/nPQMah/Ez0vN47u7tUqd+RND8n/bwf/Msvz
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 2pmd5O1lgyr8sIB/mHh1BlOdJYoM48LHeWdlMJmpA0qbEVqHbDmoxOTtSs0MZAlZRvs57utHoHBN
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# uwGKz0jDocS4lfxAn7SjQKmGsa/EVRmrnspHwwGFx3HGSqXs8H0CAQOjMzAxMBIGA1UdEwEB/wQI
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# MAYBAf8CAQAwGwYDVR0gAQEABBEwDzANBgsrBgEEAdZ5AgHODzANBgkqhkiG9w0BAQUFAAOBgQA/
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# STb40A6D+93jMfLGQzXc997IsaJZdoPt7tYa8PqGJBL62EiTj+erd/H5pDZx/2/bcpOG4m9J56yg
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# wOohbllw2TM+oeEd8syzV6X+1SIPnGI56JRrm3UXcHYx1Rq5loM9WKAiz/WmIWmskljsEQ7+542p
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# q0pkHjs8nuXovSkUYA==
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# -----END CERTIFICATE-----
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# If you update any of the above, you can generate a new root with the
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# following line:
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#   print DERToPEM(MakeCertificate(ISSUER_CN, ISSUER_CN, 1, KEY, KEY, None))
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Various OIDs
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AIA_OCSP = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 1])
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AUTHORITY_INFORMATION_ACCESS = asn1.OID([1, 3, 6, 1, 5, 5, 7, 1, 1])
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BASIC_CONSTRAINTS = asn1.OID([2, 5, 29, 19])
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)CERT_POLICIES = asn1.OID([2, 5, 29, 32])
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COMMON_NAME = asn1.OID([2, 5, 4, 3])
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)COUNTRY = asn1.OID([2, 5, 4, 6])
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HASH_SHA1 = asn1.OID([1, 3, 14, 3, 2, 26])
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSP_TYPE_BASIC = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 1, 1])
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ORGANIZATION = asn1.OID([2, 5, 4, 10])
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)PUBLIC_KEY_RSA = asn1.OID([1, 2, 840, 113549, 1, 1, 1])
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciSHA256_WITH_RSA_ENCRYPTION = asn1.OID([1, 2, 840, 113549, 1, 1, 11])
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MakeCertificate(
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None):
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''MakeCertificate returns a DER encoded certificate, signed by privkey.'''
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions = asn1.SEQUENCE([])
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # Default subject name fields
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  c = "XX"
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  o = "Testing Org"
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if issuer_cn == subject_cn:
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    # Root certificate.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    c = None
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    o = None
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions.children.append(
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SEQUENCE([
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        basic_constraints,
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        True,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          True, # IsCA
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          0, # Path len
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ]))),
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]))
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ocsp_url is not None:
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions.children.append(
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SEQUENCE([
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        AUTHORITY_INFORMATION_ACCESS,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        False,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          asn1.SEQUENCE([
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            AIA_OCSP,
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            asn1.Raw(asn1.TagAndLength(0x86, len(ocsp_url)) + ocsp_url),
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ]),
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ]))),
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]))
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions.children.append(
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.SEQUENCE([
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CERT_POLICIES,
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      False,
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.SEQUENCE([ # PolicyInformation
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          CERT_POLICY_OID,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ]),
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]))),
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ])
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  )
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tbsCert = asn1.ToDER(asn1.SEQUENCE([
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.Explicit(0, 2), # Version
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      serial,
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      asn1.SEQUENCE([SHA256_WITH_RSA_ENCRYPTION, None]), # SignatureAlgorithm
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Name(cn = issuer_cn), # Issuer
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SEQUENCE([ # Validity
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.UTCTime("100101060000Z"), # NotBefore
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.UTCTime("321201060000Z"), # NotAfter
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]),
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Name(cn = subject_cn, c = c, o = o), # Subject
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SEQUENCE([ # SubjectPublicKeyInfo
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.SEQUENCE([ # Algorithm
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          PUBLIC_KEY_RSA,
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          None,
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ]),
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.BitString(asn1.ToDER(pubkey)),
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]),
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.Explicit(3, extensions),
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]))
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return asn1.ToDER(asn1.SEQUENCE([
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.Raw(tbsCert),
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.SEQUENCE([
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      SHA256_WITH_RSA_ENCRYPTION,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]),
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.BitString(privkey.Sign(tbsCert)),
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ]))
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state):
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  # https://tools.ietf.org/html/rfc2560
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  issuer_name_hash = asn1.OCTETSTRING(
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest())
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  issuer_key_hash = asn1.OCTETSTRING(
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      hashlib.sha1(asn1.ToDER(issuer_key)).digest())
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cert_status = None
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ocsp_state == OCSP_STATE_REVOKED:
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z"))
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif ocsp_state == OCSP_STATE_UNKNOWN:
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0))
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  elif ocsp_state == OCSP_STATE_GOOD:
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0))
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else:
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    raise ValueError('Bad OCSP state: ' + str(ocsp_state))
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.Explicit(2, issuer_key_hash),
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.GeneralizedTime("20100101060000Z"), # producedAt
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.SEQUENCE([
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.SEQUENCE([ # SingleResponse
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.SEQUENCE([ # CertID
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          asn1.SEQUENCE([ # hashAlgorithm
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            HASH_SHA1,
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            None,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          ]),
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          issuer_name_hash,
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          issuer_key_hash,
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          serial,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ]),
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        cert_status,
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.GeneralizedTime("20100101060000Z"), # thisUpdate
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        asn1.Explicit(0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ]),
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]),
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ]))
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  basic_resp = asn1.SEQUENCE([
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.Raw(basic_resp_data_der),
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.SEQUENCE([
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      SHA256_WITH_RSA_ENCRYPTION,
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      None,
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]),
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.BitString(issuer_key.Sign(basic_resp_data_der)),
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ])
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  resp = asn1.SEQUENCE([
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.ENUMERATED(0),
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    asn1.Explicit(0, asn1.SEQUENCE([
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      OCSP_TYPE_BASIC,
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      asn1.OCTETSTRING(asn1.ToDER(basic_resp)),
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ]))
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ])
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return asn1.ToDER(resp)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def DERToPEM(der):
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pem = '-----BEGIN CERTIFICATE-----\n'
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pem += der.encode('base64')
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pem += '-----END CERTIFICATE-----\n'
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pem
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSP_STATE_GOOD = 1
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSP_STATE_REVOKED = 2
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSP_STATE_INVALID = 3
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSP_STATE_UNAUTHORIZED = 4
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)OCSP_STATE_UNKNOWN = 5
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# unauthorizedDER is an OCSPResponse with a status of 6:
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# SEQUENCE { ENUM(6) }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unauthorizedDER = '30030a0106'.decode('hex')
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GenerateCertKeyAndOCSP(subject = "127.0.0.1",
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ocsp_url = "http://127.0.0.1",
326a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                           ocsp_state = OCSP_STATE_GOOD,
327a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                           serial = 0):
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where:
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       * cert_and_key_pem contains a certificate and private key in PEM format
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         with the given subject common name and OCSP URL.
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         None'''
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
334a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  if serial == 0:
335a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    serial = RandomNumber(16)
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY,
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             bytes(ocsp_url))
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  cert_pem = DERToPEM(cert_der)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ocsp_der = None
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ocsp_url is not None:
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ocsp_state == OCSP_STATE_UNAUTHORIZED:
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ocsp_der = unauthorizedDER
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    elif ocsp_state == OCSP_STATE_INVALID:
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ocsp_der = '3'
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else:
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state)
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (cert_pem + KEY_PEM, ocsp_der)
350