agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 1 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
| 5 | import asn1 |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 6 | import datetime |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 7 | import hashlib |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 8 | import itertools |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 9 | import os |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 10 | import time |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 11 | |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 12 | GENERALIZED_TIME_FORMAT = "%Y%m%d%H%M%SZ" |
| 13 | |
| 14 | OCSP_STATE_GOOD = 1 |
| 15 | OCSP_STATE_REVOKED = 2 |
| 16 | OCSP_STATE_INVALID_RESPONSE = 3 |
| 17 | OCSP_STATE_UNAUTHORIZED = 4 |
| 18 | OCSP_STATE_UNKNOWN = 5 |
| 19 | OCSP_STATE_TRY_LATER = 6 |
| 20 | OCSP_STATE_INVALID_RESPONSE_DATA = 7 |
| 21 | OCSP_STATE_MISMATCHED_SERIAL = 8 |
| 22 | |
| 23 | OCSP_DATE_VALID = 1 |
| 24 | OCSP_DATE_OLD = 2 |
| 25 | OCSP_DATE_EARLY = 3 |
| 26 | OCSP_DATE_LONG = 4 |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 27 | OCSP_DATE_LONGER = 5 |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 28 | |
| 29 | OCSP_PRODUCED_VALID = 1 |
| 30 | OCSP_PRODUCED_BEFORE_CERT = 2 |
| 31 | OCSP_PRODUCED_AFTER_CERT = 3 |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 32 | |
| 33 | # This file implements very minimal certificate and OCSP generation. It's |
| 34 | # designed to test revocation checking. |
| 35 | |
| 36 | def RandomNumber(length_in_bytes): |
| 37 | '''RandomNumber returns a random number of length 8*|length_in_bytes| bits''' |
| 38 | rand = os.urandom(length_in_bytes) |
| 39 | n = 0 |
| 40 | for x in rand: |
| 41 | n <<= 8 |
| 42 | n |= ord(x) |
| 43 | return n |
| 44 | |
| 45 | |
| 46 | def ModExp(n, e, p): |
| 47 | '''ModExp returns n^e mod p''' |
| 48 | r = 1 |
| 49 | while e != 0: |
| 50 | if e & 1: |
| 51 | r = (r*n) % p |
| 52 | e >>= 1 |
| 53 | n = (n*n) % p |
| 54 | return r |
| 55 | |
rsleevi | 85d2177 | 2014-08-28 15:46:51 -0700 | [diff] [blame] | 56 | # PKCS1v15_SHA256_PREFIX is the ASN.1 prefix for a SHA256 signature. |
| 57 | PKCS1v15_SHA256_PREFIX = '3031300d060960864801650304020105000420'.decode('hex') |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 58 | |
| 59 | class RSA(object): |
| 60 | def __init__(self, modulus, e, d): |
| 61 | self.m = modulus |
| 62 | self.e = e |
| 63 | self.d = d |
| 64 | |
| 65 | self.modlen = 0 |
| 66 | m = modulus |
| 67 | while m != 0: |
| 68 | self.modlen += 1 |
| 69 | m >>= 8 |
| 70 | |
| 71 | def Sign(self, message): |
rsleevi | 85d2177 | 2014-08-28 15:46:51 -0700 | [diff] [blame] | 72 | digest = hashlib.sha256(message).digest() |
| 73 | prefix = PKCS1v15_SHA256_PREFIX |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 74 | |
| 75 | em = ['\xff'] * (self.modlen - 1 - len(prefix) - len(digest)) |
| 76 | em[0] = '\x00' |
| 77 | em[1] = '\x01' |
| 78 | em += "\x00" + prefix + digest |
| 79 | |
| 80 | n = 0 |
| 81 | for x in em: |
| 82 | n <<= 8 |
| 83 | n |= ord(x) |
| 84 | |
| 85 | s = ModExp(n, self.d, self.m) |
| 86 | out = [] |
| 87 | while s != 0: |
| 88 | out.append(s & 0xff) |
| 89 | s >>= 8 |
| 90 | out.reverse() |
| 91 | return '\x00' * (self.modlen - len(out)) + asn1.ToBytes(out) |
| 92 | |
| 93 | def ToDER(self): |
| 94 | return asn1.ToDER(asn1.SEQUENCE([self.m, self.e])) |
| 95 | |
| 96 | |
Adam Langley | 1b62265 | 2017-12-05 23:57:33 +0000 | [diff] [blame] | 97 | def Name(cn): |
| 98 | return asn1.SEQUENCE([ |
| 99 | asn1.SET([ |
| 100 | asn1.SEQUENCE([ |
| 101 | COMMON_NAME, cn, |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 102 | ]) |
Adam Langley | 1b62265 | 2017-12-05 23:57:33 +0000 | [diff] [blame] | 103 | ]) |
| 104 | ]) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 105 | |
| 106 | |
| 107 | # The private key and root certificate name are hard coded here: |
| 108 | |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 109 | # This is the root private key |
| 110 | ROOT_KEY = RSA(0x00c1541fac63d3b969aa231a02cb2e0d9ee7b26724f136c121b2c28bdae5caa87733cc407ad83842ef20ec67d941b448a1ce3557cf5ddebf3c9bde8f36f253ee73e670d1c4c6631d1ddc0e39cbde09b833f66347ea379c3fa891d61a0ca005b38b0b2cad1058e3589c9f30600be81e4ff4ac220972c17b74f92f03d72b496f643543d0b27a5227f1efee13c138888b23cb101877b3b4dc091f0b3bb6fc3c792187b05ab38e97862f8af6156bcbfbb824385132c6741e6c65cfcd5f13142421a210b95185884c4866f3ea644dfb8006133d14e72a4704f3e700cf827ca5ffd2ef74c2ab6a5259ffff40f0f7f607891388f917fc9fc9e65742df1bfa0b322140bb65, |
| 111 | 65537, |
| 112 | 0x00980f2db66ef249e4954074a5fbdf663135363a3071554ac4d19079661bd5b179c890ffaa5fc4a8c8e3116e81104fd7cd049f2a48dd2165332bb9fad511f6f817cb09b3c45cf1fa25d13e9331099c8578c173c74dae9dc3e83784ba0a7216e9e8144af8786221b741c167d033ad47a245e4da04aa710a44aff5cdc480b48adbba3575d1315555690f081f9f69691e801e34c21240bcd3df9573ec5f9aa290c5ed19404fb911ab28b7680e0be086487273db72da6621f24d8c66197a5f1b7687efe1d9e3b6655af2891d4540482e1246ff5f62ce61b8b5dcb2c66ade6bb41e0bf071445fb8544aa0a489780f770a6f1031ee19347641794f4ad17354d579a9d061) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 113 | |
| 114 | # Root certificate CN |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 115 | ROOT_CN = "Testing CA" |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 116 | |
| 117 | # All certificates are issued under this policy OID, in the Google arc: |
| 118 | CERT_POLICY_OID = asn1.OID([1, 3, 6, 1, 4, 1, 11129, 2, 4, 1]) |
| 119 | |
| 120 | # These result in the following root certificate: |
| 121 | # -----BEGIN CERTIFICATE----- |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 122 | # MIIC1DCCAbygAwIBAgIBATANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwpUZXN0 |
| 123 | # aW5nIENBMB4XDTEwMDEwMTA2MDAwMFoXDTMyMTIwMTA2MDAwMFowFTETMBEGA1UE |
| 124 | # AxMKVGVzdGluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMFU |
| 125 | # H6xj07lpqiMaAssuDZ7nsmck8TbBIbLCi9rlyqh3M8xAetg4Qu8g7GfZQbRIoc41 |
| 126 | # V89d3r88m96PNvJT7nPmcNHExmMdHdwOOcveCbgz9mNH6jecP6iR1hoMoAWziwss |
| 127 | # rRBY41icnzBgC+geT/SsIglywXt0+S8D1ytJb2Q1Q9CyelIn8e/uE8E4iIsjyxAY |
| 128 | # d7O03AkfCzu2/Dx5IYewWrOOl4YvivYVa8v7uCQ4UTLGdB5sZc/NXxMUJCGiELlR |
| 129 | # hYhMSGbz6mRN+4AGEz0U5ypHBPPnAM+CfKX/0u90wqtqUln//0Dw9/YHiROI+Rf8 |
| 130 | # n8nmV0LfG/oLMiFAu2UCAwEAAaMvMC0wEgYDVR0TAQH/BAgwBgEB/wIBATAXBgNV |
| 131 | # HSAEEDAOMAwGCisGAQQB1nkCBAEwDQYJKoZIhvcNAQELBQADggEBADNrvoAyqAVm |
| 132 | # bydPBBfLRqyH4DXt2vuMVmnSdnWnOxYiEezGmNSNiO1k1ZFBwVSsd+JHrT24lax9 |
| 133 | # kvU1yQDW//PBu3ijfZOCaIUleQiGXHMGfV4MjzgYbxpvHOvEUC6IXmYCsIEwcZgK |
| 134 | # lrwnfJQ3MVU4hOgGTlOTWYPtCwvTsBObNRLdIs+ifMQiWmzPBlM8XeX4e5acDjTb |
| 135 | # emcN4szU3EcgmCA0LvBIRI4F6NWpaIJl2WnLyMUDyKq4vjpRJOZkNwAC+525duDr |
| 136 | # JFE4PKR2Lh53nJQIJv6mcTZQkX1mmw0yzqWxcGCoHACma3TgSwOHryvSopL+t26+ |
| 137 | # ZlQvP2ygwqY= |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 138 | # -----END CERTIFICATE----- |
| 139 | |
mattm | adace8e | 2016-10-03 14:07:15 -0700 | [diff] [blame] | 140 | # If you update any of the above, you can generate a new root by running this |
| 141 | # file as a script. |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 142 | |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 143 | INTERMEDIATE_KEY = RSA(0x00c661afcc659f88855a83ade8fb792dc13d0cf388b17bece9149cf0b8556d27b19101d081fb2a842d13a2ac95d8308ddd66783843ecc5806513959eb6b30dd69b2845d97e10d0bbbf653d686dc8828935022cc96f9e030b567157257d3d6526734080bb9727cee0d30f4209d5820e1d662f358fc789c0e9366d84f89adf1beb8d843f74e6f325876ac35d5c11691fcb296967c06edf69450c16bb2314c14599fe90725d5ec90f2db6698afae72bba0cfbf77967c7e8b49f2172f9381827c27ab7f9471c62bd8da4a6c657966ec1385cf41d739449835888f30d64971619dcd380408cd74f25c3be19833a92620c9cf710da67e15ac8cef69bc7e4e5e7f813c1ed, |
| 144 | 65537, |
| 145 | 0x77c5e2edf52d2cafd6c649e9b06aa9455226cfa26805fa337f4e81c7c94bedfb3721715208e2d28aa4a042b2f5a3db03212ad44dae564ffeb6a44efedf7c2b65e21aca056301a3591b36c82600394fbdc16268fc0adaabadb5207871f4ef6d17888a30b84240955cd889768681cf23d0de0fe88f008c8841643e341acd397e2d1104a23242e566088b7617c26ae8b48a85b6c9b7dc64ef1fa5e9b124ff8c1659a82d8225f28a820cc6ca07beff0354364c631a9142309fea1d8b054f6e00e23c54b493a21fcbe89a646b39d1acba5bc2ace9bba0252671d42a15202f3afccc912114d6c20eb3131e74289f2c744c5b39e7d3780fe21402ab1c3ae65854fee401) |
| 146 | |
Matt Mueller | 7586334 | 2018-05-01 22:58:47 +0000 | [diff] [blame] | 147 | # Intermediate certificate CN prefix (random serial number is added to the CN |
| 148 | # in order to avoid caching issues.) |
| 149 | INTERMEDIATE_CN_PREFIX = "Testing Intermediate CA" |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 150 | |
| 151 | LEAF_KEY = RSA(0x00cd12d317b39cfbb160fb1dc9c9f0dc8fef3604dda4d8c557392ce1d616483713f78216cadbefd1c76ea0f3bbbe410e24b233b1b73583922b09314e249b2cfde1be0995e13f160fb630c10d447750da20ffaa4880006717feaa3e4db602e4f511b5cc312f770f44b037784effec62640f948aa189c3769f03bdd0e22a36ecfa5951f5577de195a4fba33c879b657968b79138fd7ab389a9968522f7389c6052be1ff78bc168d3ea961e132a044eba33ac07ead95367c7b815e91eca924d914fd0d811349b8bf500707ba71a43a2901a545f34e1792e72654f6649fab9716f4ba17379ee8042186bbba9b9bac416a60474cc60686f0e6e4b01259cc3cb5873edf9, |
| 152 | 65537, |
| 153 | 0x009c23e81bd4c30314743dded9646b82d408937db2f0afa7d9988be6cba59d886a287aa13605ad9c7117776efc94885de76cd3554da46e301d9a5b331f4613449edb9ddac36cd0345848d8c46c4bd880acbd5cfee48ee9efe813e16a33da124fd213348c8292494ac84d03ca4aabc5e25fc67ea32e0c6845fc884b01d8988768b8b931c41de49708dbcd5fcb61823f9a1f7507c6f364be4cb5a8cf24af4925997030dd4f67a0c9c6813401cc8b2f5d1971ee0022770239b7042fde8228c33942e9c0a0b18854cb1b5542be928338ab33ac936bbba174e55457007b16f36011dbb8f4258abe64e42b1cfa79803d30170b7ecf3e7c595d42003fff72591e07acd9cd) |
| 154 | |
| 155 | LEAF_KEY_PEM = '''-----BEGIN RSA PRIVATE KEY----- |
| 156 | MIIEpQIBAAKCAQEAzRLTF7Oc+7Fg+x3JyfDcj+82BN2k2MVXOSzh1hZINxP3ghbK |
| 157 | 2+/Rx26g87u+QQ4ksjOxtzWDkisJMU4kmyz94b4JleE/Fg+2MMENRHdQ2iD/qkiA |
| 158 | AGcX/qo+TbYC5PURtcwxL3cPRLA3eE7/7GJkD5SKoYnDdp8DvdDiKjbs+llR9Vd9 |
| 159 | 4ZWk+6M8h5tleWi3kTj9erOJqZaFIvc4nGBSvh/3i8Fo0+qWHhMqBE66M6wH6tlT |
| 160 | Z8e4FekeypJNkU/Q2BE0m4v1AHB7pxpDopAaVF804XkucmVPZkn6uXFvS6Fzee6A |
| 161 | Qhhru6m5usQWpgR0zGBobw5uSwElnMPLWHPt+QIDAQABAoIBAQCcI+gb1MMDFHQ9 |
| 162 | 3tlka4LUCJN9svCvp9mYi+bLpZ2Iaih6oTYFrZxxF3du/JSIXeds01VNpG4wHZpb |
| 163 | Mx9GE0Se253aw2zQNFhI2MRsS9iArL1c/uSO6e/oE+FqM9oST9ITNIyCkklKyE0D |
| 164 | ykqrxeJfxn6jLgxoRfyISwHYmIdouLkxxB3klwjbzV/LYYI/mh91B8bzZL5MtajP |
| 165 | JK9JJZlwMN1PZ6DJxoE0AcyLL10Zce4AIncCObcEL96CKMM5QunAoLGIVMsbVUK+ |
| 166 | koM4qzOsk2u7oXTlVFcAexbzYBHbuPQlir5k5Csc+nmAPTAXC37PPnxZXUIAP/9y |
| 167 | WR4HrNnNAoGBAPmOqTe7ntto6rDEsU1cKOJFKIZ7UVcSByyz8aLrvj1Rb2mkrNJU |
| 168 | SdTqJvtqrvDXgO0HuGtFOzsZrRV9+XRPd2P0mP0uhfRiYGWT8hnILGyI2+7zlC/w |
| 169 | HDtLEefelhtdOVKgUaLQXptSn7aGalUHghZKWjRNT5ah+U85MoI2ZkDbAoGBANJe |
| 170 | KvrBBPSFLj+x2rsMhG+ksK0I6tivapVvSTtDV3ME1DvA/4BIMV/nIZyoH4AYI72c |
| 171 | m/vD66+eCqh75cq5BzbVD63tR+ZRi/VdT1HJcl2IFXynk6eaBw8v7gpQyx6t3iSK |
| 172 | lx/dIdpLt1BQuR4qI6x1wYp7Utn98soEkiFXzgq7AoGBAJTLBYPQXvgNBxlcPSaV |
| 173 | 016Nw4rjTe0vN43kwCbWjjf7LQV9BPnm/Zpv/cwboLDCnQE2gDOdNKKZPYS59pjt |
| 174 | pI65UNpr+bxrR3RpEIlku2/+7br8ChfG/t4vdT6djTxFih8ErYf42t+bFNT8Mbv+ |
| 175 | 3QYzULMsgU6bxo0A2meezbrPAoGBAK/IxmtQXP6iRxosWRUSCZxs5sFAgVVdh1el |
| 176 | bXEa/Xj8IQhpZlbgfHmh3oFULzZPdZYcxm7jsQ7HpipRlZwHbtLPyNFSRFFd9PCr |
| 177 | 7vrttSYY77OBKC3V1G5JY8S07HYPXV/1ewDCPGZ3/I8dVQKyvap/n6FDGeFUhctv |
| 178 | dFhuUZq/AoGAWLXlbcIl1cvOhfFJ5owohJhzh9oW9tlCtjV5/dlix2RaE5CtDZWS |
| 179 | oMm4sQu9HiA8jLDP1MEEMRFPrPXdrZnxnSqVd1DgabSegD1/ZCb1QlWwQWkk5QU+ |
| 180 | wotPOMI33L50kZqUaDP+1XSL0Dyfo/pYpm4tYy/5QmP6WKXCtFUXybI= |
| 181 | -----END RSA PRIVATE KEY----- |
| 182 | ''' |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 183 | |
| 184 | # Various OIDs |
| 185 | |
| 186 | AIA_OCSP = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 1]) |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 187 | AIA_CA_ISSUERS = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 2]) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 188 | AUTHORITY_INFORMATION_ACCESS = asn1.OID([1, 3, 6, 1, 5, 5, 7, 1, 1]) |
| 189 | BASIC_CONSTRAINTS = asn1.OID([2, 5, 29, 19]) |
| 190 | CERT_POLICIES = asn1.OID([2, 5, 29, 32]) |
| 191 | COMMON_NAME = asn1.OID([2, 5, 4, 3]) |
| 192 | COUNTRY = asn1.OID([2, 5, 4, 6]) |
| 193 | HASH_SHA1 = asn1.OID([1, 3, 14, 3, 2, 26]) |
| 194 | OCSP_TYPE_BASIC = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 1, 1]) |
| 195 | ORGANIZATION = asn1.OID([2, 5, 4, 10]) |
| 196 | PUBLIC_KEY_RSA = asn1.OID([1, 2, 840, 113549, 1, 1, 1]) |
rsleevi | 85d2177 | 2014-08-28 15:46:51 -0700 | [diff] [blame] | 197 | SHA256_WITH_RSA_ENCRYPTION = asn1.OID([1, 2, 840, 113549, 1, 1, 11]) |
rsleevi | a58a92d | 2017-03-03 19:07:20 -0800 | [diff] [blame] | 198 | SUBJECT_ALTERNATIVE_NAME = asn1.OID([2, 5, 29, 17]) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 199 | |
| 200 | def MakeCertificate( |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 201 | issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None, |
rsleevi | a58a92d | 2017-03-03 19:07:20 -0800 | [diff] [blame] | 202 | ca_issuers_url = None, is_ca=False, path_len=None, ip_sans=None, |
| 203 | dns_sans=None): |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 204 | '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' |
| 205 | extensions = asn1.SEQUENCE([]) |
| 206 | |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 207 | if is_ca: |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 208 | # Root certificate. |
| 209 | c = None |
| 210 | o = None |
| 211 | extensions.children.append( |
| 212 | asn1.SEQUENCE([ |
mattm | adace8e | 2016-10-03 14:07:15 -0700 | [diff] [blame] | 213 | BASIC_CONSTRAINTS, |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 214 | True, |
| 215 | asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([ |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 216 | True, # IsCA |
| 217 | ] + ([path_len] if path_len is not None else []) # Path len |
| 218 | ))), |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 219 | ])) |
rsleevi | a58a92d | 2017-03-03 19:07:20 -0800 | [diff] [blame] | 220 | if ip_sans is not None or dns_sans is not None: |
| 221 | sans = [] |
| 222 | if dns_sans is not None: |
| 223 | for dns_name in dns_sans: |
| 224 | sans.append( |
| 225 | asn1.Raw(asn1.TagAndLength(0x82, len(dns_name)) + dns_name)) |
| 226 | if ip_sans is not None: |
| 227 | for ip_addr in ip_sans: |
| 228 | sans.append( |
| 229 | asn1.Raw(asn1.TagAndLength(0x87, len(ip_addr)) + ip_addr)) |
| 230 | extensions.children.append( |
| 231 | asn1.SEQUENCE([ |
| 232 | SUBJECT_ALTERNATIVE_NAME, |
| 233 | # There is implicitly a critical=False here. Since false is the |
| 234 | # default, encoding the value would be invalid DER. |
| 235 | asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE(sans))) |
| 236 | ])) |
| 237 | |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 238 | if ocsp_url is not None or ca_issuers_url is not None: |
| 239 | aia_entries = [] |
| 240 | if ocsp_url is not None: |
| 241 | aia_entries.append( |
| 242 | asn1.SEQUENCE([ |
| 243 | AIA_OCSP, |
| 244 | asn1.Raw(asn1.TagAndLength(0x86, len(ocsp_url)) + ocsp_url), |
| 245 | ])) |
| 246 | if ca_issuers_url is not None: |
| 247 | aia_entries.append( |
| 248 | asn1.SEQUENCE([ |
| 249 | AIA_CA_ISSUERS, |
| 250 | asn1.Raw(asn1.TagAndLength(0x86, |
| 251 | len(ca_issuers_url)) + ca_issuers_url), |
| 252 | ])) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 253 | extensions.children.append( |
| 254 | asn1.SEQUENCE([ |
| 255 | AUTHORITY_INFORMATION_ACCESS, |
mattm | adace8e | 2016-10-03 14:07:15 -0700 | [diff] [blame] | 256 | # There is implicitly a critical=False here. Since false is the default, |
| 257 | # encoding the value would be invalid DER. |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 258 | asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE(aia_entries))), |
| 259 | ])) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 260 | |
| 261 | extensions.children.append( |
| 262 | asn1.SEQUENCE([ |
| 263 | CERT_POLICIES, |
mattm | adace8e | 2016-10-03 14:07:15 -0700 | [diff] [blame] | 264 | # There is implicitly a critical=False here. Since false is the default, |
| 265 | # encoding the value would be invalid DER. |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 266 | asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([ |
| 267 | asn1.SEQUENCE([ # PolicyInformation |
| 268 | CERT_POLICY_OID, |
| 269 | ]), |
| 270 | ]))), |
| 271 | ]) |
| 272 | ) |
| 273 | |
| 274 | tbsCert = asn1.ToDER(asn1.SEQUENCE([ |
| 275 | asn1.Explicit(0, 2), # Version |
| 276 | serial, |
rsleevi | 85d2177 | 2014-08-28 15:46:51 -0700 | [diff] [blame] | 277 | asn1.SEQUENCE([SHA256_WITH_RSA_ENCRYPTION, None]), # SignatureAlgorithm |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 278 | Name(cn = issuer_cn), # Issuer |
| 279 | asn1.SEQUENCE([ # Validity |
| 280 | asn1.UTCTime("100101060000Z"), # NotBefore |
| 281 | asn1.UTCTime("321201060000Z"), # NotAfter |
| 282 | ]), |
Adam Langley | 1b62265 | 2017-12-05 23:57:33 +0000 | [diff] [blame] | 283 | Name(cn = subject_cn), # Subject |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 284 | asn1.SEQUENCE([ # SubjectPublicKeyInfo |
| 285 | asn1.SEQUENCE([ # Algorithm |
| 286 | PUBLIC_KEY_RSA, |
| 287 | None, |
| 288 | ]), |
| 289 | asn1.BitString(asn1.ToDER(pubkey)), |
| 290 | ]), |
| 291 | asn1.Explicit(3, extensions), |
| 292 | ])) |
| 293 | |
| 294 | return asn1.ToDER(asn1.SEQUENCE([ |
| 295 | asn1.Raw(tbsCert), |
| 296 | asn1.SEQUENCE([ |
rsleevi | 85d2177 | 2014-08-28 15:46:51 -0700 | [diff] [blame] | 297 | SHA256_WITH_RSA_ENCRYPTION, |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 298 | None, |
| 299 | ]), |
| 300 | asn1.BitString(privkey.Sign(tbsCert)), |
| 301 | ])) |
| 302 | |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 303 | def MakeOCSPSingleResponse( |
| 304 | issuer_name_hash, issuer_key_hash, serial, ocsp_state, ocsp_date): |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 305 | cert_status = None |
agl@chromium.org | b5f388a | 2012-06-29 17:54:06 +0000 | [diff] [blame] | 306 | if ocsp_state == OCSP_STATE_REVOKED: |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 307 | cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) |
agl@chromium.org | b5f388a | 2012-06-29 17:54:06 +0000 | [diff] [blame] | 308 | elif ocsp_state == OCSP_STATE_UNKNOWN: |
| 309 | cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) |
| 310 | elif ocsp_state == OCSP_STATE_GOOD: |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 311 | cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 312 | elif ocsp_state == OCSP_STATE_MISMATCHED_SERIAL: |
| 313 | cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) |
| 314 | serial -= 1 |
agl@chromium.org | b5f388a | 2012-06-29 17:54:06 +0000 | [diff] [blame] | 315 | else: |
| 316 | raise ValueError('Bad OCSP state: ' + str(ocsp_state)) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 317 | |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 318 | now = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())) |
| 319 | if ocsp_date == OCSP_DATE_VALID: |
| 320 | thisUpdate = now - datetime.timedelta(days=1) |
| 321 | nextUpdate = thisUpdate + datetime.timedelta(weeks=1) |
| 322 | elif ocsp_date == OCSP_DATE_OLD: |
dadrian | 9a07cc9 | 2016-07-22 10:44:37 -0700 | [diff] [blame] | 323 | thisUpdate = now - datetime.timedelta(days=1, weeks=1) |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 324 | nextUpdate = thisUpdate + datetime.timedelta(weeks=1) |
| 325 | elif ocsp_date == OCSP_DATE_EARLY: |
dadrian | 9a07cc9 | 2016-07-22 10:44:37 -0700 | [diff] [blame] | 326 | thisUpdate = now + datetime.timedelta(days=1) |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 327 | nextUpdate = thisUpdate + datetime.timedelta(weeks=1) |
| 328 | elif ocsp_date == OCSP_DATE_LONG: |
| 329 | thisUpdate = now - datetime.timedelta(days=365) |
dadrian | 9a07cc9 | 2016-07-22 10:44:37 -0700 | [diff] [blame] | 330 | nextUpdate = thisUpdate + datetime.timedelta(days=366) |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 331 | elif ocsp_date == OCSP_DATE_LONGER: |
| 332 | thisUpdate = now - datetime.timedelta(days=367) |
| 333 | nextUpdate = thisUpdate + datetime.timedelta(days=368) |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 334 | else: |
| 335 | raise ValueError('Bad OCSP date: ' + str(ocsp_date)) |
| 336 | |
| 337 | return asn1.SEQUENCE([ # SingleResponse |
| 338 | asn1.SEQUENCE([ # CertID |
| 339 | asn1.SEQUENCE([ # hashAlgorithm |
| 340 | HASH_SHA1, |
| 341 | None, |
| 342 | ]), |
| 343 | issuer_name_hash, |
| 344 | issuer_key_hash, |
| 345 | serial, |
| 346 | ]), |
| 347 | cert_status, |
| 348 | asn1.GeneralizedTime( # thisUpdate |
| 349 | thisUpdate.strftime(GENERALIZED_TIME_FORMAT) |
| 350 | ), |
| 351 | asn1.Explicit( # nextUpdate |
| 352 | 0, |
| 353 | asn1.GeneralizedTime(nextUpdate.strftime(GENERALIZED_TIME_FORMAT)) |
| 354 | ), |
| 355 | ]) |
| 356 | |
| 357 | def MakeOCSPResponse( |
| 358 | issuer_cn, issuer_key, serial, ocsp_states, ocsp_dates, ocsp_produced): |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 359 | if ocsp_states[0] == OCSP_STATE_UNAUTHORIZED: |
| 360 | return unauthorizedDER |
| 361 | elif ocsp_states[0] == OCSP_STATE_INVALID_RESPONSE: |
| 362 | return '3' |
| 363 | elif ocsp_states[0] == OCSP_STATE_TRY_LATER: |
| 364 | resp = asn1.SEQUENCE([ |
| 365 | asn1.ENUMERATED(3), |
| 366 | ]) |
| 367 | return asn1.ToDER(resp) |
| 368 | elif ocsp_states[0] == OCSP_STATE_INVALID_RESPONSE_DATA: |
| 369 | invalid_data = asn1.ToDER(asn1.OCTETSTRING('not ocsp data')) |
| 370 | basic_resp = asn1.SEQUENCE([ |
| 371 | asn1.Raw(invalid_data), |
| 372 | asn1.SEQUENCE([ |
| 373 | SHA256_WITH_RSA_ENCRYPTION, |
| 374 | None, |
| 375 | ]), |
| 376 | asn1.BitString(ROOT_KEY.Sign(invalid_data)), |
| 377 | ]) |
| 378 | resp = asn1.SEQUENCE([ |
| 379 | asn1.ENUMERATED(0), |
| 380 | asn1.Explicit(0, asn1.SEQUENCE([ |
| 381 | OCSP_TYPE_BASIC, |
| 382 | asn1.OCTETSTRING(asn1.ToDER(basic_resp)), |
| 383 | ])), |
| 384 | ]) |
| 385 | return asn1.ToDER(resp) |
| 386 | |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 387 | # https://tools.ietf.org/html/rfc2560 |
| 388 | issuer_name_hash = asn1.OCTETSTRING( |
| 389 | hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) |
| 390 | |
| 391 | issuer_key_hash = asn1.OCTETSTRING( |
| 392 | hashlib.sha1(asn1.ToDER(issuer_key)).digest()) |
| 393 | |
| 394 | now = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())) |
| 395 | if ocsp_produced == OCSP_PRODUCED_VALID: |
| 396 | producedAt = now - datetime.timedelta(days=1) |
| 397 | elif ocsp_produced == OCSP_PRODUCED_BEFORE_CERT: |
| 398 | producedAt = datetime.datetime.strptime( |
| 399 | "19100101050000Z", GENERALIZED_TIME_FORMAT) |
| 400 | elif ocsp_produced == OCSP_PRODUCED_AFTER_CERT: |
| 401 | producedAt = datetime.datetime.strptime( |
| 402 | "20321201070000Z", GENERALIZED_TIME_FORMAT) |
| 403 | else: |
| 404 | raise ValueError('Bad OCSP produced: ' + str(ocsp_produced)) |
| 405 | |
| 406 | single_responses = [ |
| 407 | MakeOCSPSingleResponse(issuer_name_hash, issuer_key_hash, serial, |
| 408 | ocsp_state, ocsp_date) |
| 409 | for ocsp_state, ocsp_date in itertools.izip(ocsp_states, ocsp_dates) |
| 410 | ] |
| 411 | |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 412 | basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([ |
| 413 | asn1.Explicit(2, issuer_key_hash), |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 414 | asn1.GeneralizedTime(producedAt.strftime(GENERALIZED_TIME_FORMAT)), |
| 415 | asn1.SEQUENCE(single_responses), |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 416 | ])) |
| 417 | |
| 418 | basic_resp = asn1.SEQUENCE([ |
| 419 | asn1.Raw(basic_resp_data_der), |
| 420 | asn1.SEQUENCE([ |
rsleevi | 85d2177 | 2014-08-28 15:46:51 -0700 | [diff] [blame] | 421 | SHA256_WITH_RSA_ENCRYPTION, |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 422 | None, |
| 423 | ]), |
| 424 | asn1.BitString(issuer_key.Sign(basic_resp_data_der)), |
| 425 | ]) |
| 426 | |
| 427 | resp = asn1.SEQUENCE([ |
| 428 | asn1.ENUMERATED(0), |
| 429 | asn1.Explicit(0, asn1.SEQUENCE([ |
| 430 | OCSP_TYPE_BASIC, |
| 431 | asn1.OCTETSTRING(asn1.ToDER(basic_resp)), |
| 432 | ])) |
| 433 | ]) |
| 434 | |
| 435 | return asn1.ToDER(resp) |
| 436 | |
| 437 | |
| 438 | def DERToPEM(der): |
| 439 | pem = '-----BEGIN CERTIFICATE-----\n' |
| 440 | pem += der.encode('base64') |
| 441 | pem += '-----END CERTIFICATE-----\n' |
| 442 | return pem |
| 443 | |
agl@chromium.org | b5f388a | 2012-06-29 17:54:06 +0000 | [diff] [blame] | 444 | # unauthorizedDER is an OCSPResponse with a status of 6: |
| 445 | # SEQUENCE { ENUM(6) } |
| 446 | unauthorizedDER = '30030a0106'.decode('hex') |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 447 | |
| 448 | def GenerateCertKeyAndOCSP(subject = "127.0.0.1", |
| 449 | ocsp_url = "http://127.0.0.1", |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 450 | ocsp_states = None, |
| 451 | ocsp_dates = None, |
| 452 | ocsp_produced = OCSP_PRODUCED_VALID, |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 453 | ocsp_intermediate_url = None, |
| 454 | ocsp_intermediate_states = None, |
| 455 | ocsp_intermediate_dates = None, |
| 456 | ocsp_intermediate_produced = OCSP_PRODUCED_VALID, |
rsleevi | a58a92d | 2017-03-03 19:07:20 -0800 | [diff] [blame] | 457 | ip_sans = ["\x7F\x00\x00\x01"], |
| 458 | dns_sans = None, |
agl@chromium.org | df77814 | 2013-07-31 21:57:28 +0000 | [diff] [blame] | 459 | serial = 0): |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 460 | '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, |
| 461 | (ocsp_der, ocsp_intermediate_der)) where: |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 462 | * cert_and_key_pem contains a certificate and private key in PEM format |
| 463 | with the given subject common name and OCSP URL. |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 464 | It also contains the intermediate certificate PEM if |
| 465 | ocsp_intermediate_url is not None. |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 466 | * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 467 | None |
| 468 | * ocsp_intermediate_der contains a DER encoded OCSP response for the |
| 469 | intermediate or None if ocsp_intermediate_url is None''' |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 470 | |
dadrian | 4ccf51c | 2016-07-20 15:36:58 -0700 | [diff] [blame] | 471 | if ocsp_states is None: |
| 472 | ocsp_states = [OCSP_STATE_GOOD] |
| 473 | if ocsp_dates is None: |
| 474 | ocsp_dates = [OCSP_DATE_VALID] |
| 475 | |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 476 | issuer_cn = ROOT_CN |
| 477 | issuer_key = ROOT_KEY |
| 478 | intermediate_pem = '' |
| 479 | intermediate_ocsp_der = None |
| 480 | |
| 481 | if ocsp_intermediate_url is not None: |
| 482 | ocsp_intermediate_url = bytes(ocsp_intermediate_url) |
| 483 | if ocsp_intermediate_states is None: |
| 484 | ocsp_intermediate_states = [OCSP_STATE_GOOD] |
| 485 | if ocsp_intermediate_dates is None: |
| 486 | ocsp_intermediate_dates = [OCSP_DATE_VALID] |
| 487 | intermediate_serial = RandomNumber(16) |
| 488 | intermediate_cn = "%s %X" % (INTERMEDIATE_CN_PREFIX, intermediate_serial) |
| 489 | intermediate_cert_der = MakeCertificate(ROOT_CN, intermediate_cn, |
| 490 | intermediate_serial, |
| 491 | INTERMEDIATE_KEY, ROOT_KEY, |
| 492 | ocsp_intermediate_url, |
| 493 | is_ca=True) |
| 494 | intermediate_pem = DERToPEM(intermediate_cert_der) |
| 495 | issuer_cn = intermediate_cn |
| 496 | issuer_key = INTERMEDIATE_KEY |
| 497 | intermediate_ocsp_der = MakeOCSPResponse( |
| 498 | ROOT_CN, ROOT_KEY, intermediate_serial, ocsp_intermediate_states, |
| 499 | ocsp_intermediate_dates, ocsp_intermediate_produced) |
| 500 | |
agl@chromium.org | df77814 | 2013-07-31 21:57:28 +0000 | [diff] [blame] | 501 | if serial == 0: |
| 502 | serial = RandomNumber(16) |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 503 | if ocsp_url is not None: |
| 504 | ocsp_url = bytes(ocsp_url) |
| 505 | cert_der = MakeCertificate(issuer_cn, bytes(subject), serial, LEAF_KEY, |
| 506 | issuer_key, ocsp_url, ip_sans=ip_sans, |
rsleevi | a58a92d | 2017-03-03 19:07:20 -0800 | [diff] [blame] | 507 | dns_sans=dns_sans) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 508 | cert_pem = DERToPEM(cert_der) |
| 509 | |
| 510 | ocsp_der = None |
| 511 | if ocsp_url is not None: |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 512 | ocsp_der = MakeOCSPResponse( |
| 513 | issuer_cn, issuer_key, serial, ocsp_states, ocsp_dates, ocsp_produced) |
agl@chromium.org | 77a9ad9 | 2012-03-20 15:14:27 +0000 | [diff] [blame] | 514 | |
Matt Mueller | 55aef64 | 2018-05-02 18:53:57 +0000 | [diff] [blame] | 515 | return cert_pem + LEAF_KEY_PEM + intermediate_pem, (ocsp_der, |
| 516 | intermediate_ocsp_der) |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 517 | |
| 518 | |
Ryan Sleevi | 3bfd15d | 2018-01-23 21:12:24 +0000 | [diff] [blame] | 519 | def GenerateCertKeyAndIntermediate(subject, |
| 520 | ca_issuers_url, |
| 521 | ip_sans=None, |
| 522 | dns_sans=None, |
| 523 | serial=0): |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 524 | '''Returns a (cert_and_key_pem, intermediate_cert_pem) where: |
| 525 | * cert_and_key_pem contains a certificate and private key in PEM format |
| 526 | with the given subject common name and caIssuers URL. |
| 527 | * intermediate_cert_pem contains a PEM encoded certificate that signed |
| 528 | cert_and_key_pem and was signed by ocsp-test-root.pem.''' |
| 529 | if serial == 0: |
| 530 | serial = RandomNumber(16) |
Ryan Sleevi | 3bfd15d | 2018-01-23 21:12:24 +0000 | [diff] [blame] | 531 | |
Matt Mueller | 7586334 | 2018-05-01 22:58:47 +0000 | [diff] [blame] | 532 | intermediate_serial = RandomNumber(16) |
| 533 | intermediate_cn = "%s %X" % (INTERMEDIATE_CN_PREFIX, intermediate_serial) |
| 534 | |
| 535 | target_cert_der = MakeCertificate(intermediate_cn, bytes(subject), serial, |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 536 | LEAF_KEY, INTERMEDIATE_KEY, |
Ryan Sleevi | 3bfd15d | 2018-01-23 21:12:24 +0000 | [diff] [blame] | 537 | ip_sans=ip_sans, dns_sans=dns_sans, |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 538 | ca_issuers_url=bytes(ca_issuers_url)) |
| 539 | target_cert_pem = DERToPEM(target_cert_der) |
| 540 | |
Matt Mueller | 7586334 | 2018-05-01 22:58:47 +0000 | [diff] [blame] | 541 | intermediate_cert_der = MakeCertificate(ROOT_CN, intermediate_cn, |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 542 | intermediate_serial, |
| 543 | INTERMEDIATE_KEY, ROOT_KEY, |
| 544 | is_ca=True) |
| 545 | |
| 546 | return target_cert_pem + LEAF_KEY_PEM, intermediate_cert_der |
mattm | adace8e | 2016-10-03 14:07:15 -0700 | [diff] [blame] | 547 | |
| 548 | |
| 549 | if __name__ == '__main__': |
| 550 | def bin_to_array(s): |
| 551 | return ' '.join(['0x%02x,'%ord(c) for c in s]) |
| 552 | |
| 553 | import sys |
| 554 | sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', |
| 555 | '..', 'data', 'ssl', 'scripts')) |
| 556 | import crlsetutil |
| 557 | |
mattm | 10ede84 | 2016-11-29 11:57:16 -0800 | [diff] [blame] | 558 | der_root = MakeCertificate(ROOT_CN, ROOT_CN, 1, ROOT_KEY, ROOT_KEY, |
| 559 | is_ca=True, path_len=1) |
mattm | adace8e | 2016-10-03 14:07:15 -0700 | [diff] [blame] | 560 | print 'ocsp-test-root.pem:' |
| 561 | print DERToPEM(der_root) |
| 562 | |
| 563 | print |
| 564 | print 'kOCSPTestCertFingerprint:' |
| 565 | print bin_to_array(hashlib.sha1(der_root).digest()) |
| 566 | |
| 567 | print |
| 568 | print 'kOCSPTestCertSPKI:' |
| 569 | print bin_to_array(crlsetutil.der_cert_to_spki_hash(der_root)) |