Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 import asn1 | 5 import asn1 |
| 6 import hashlib | 6 import hashlib |
| 7 import os | 7 import os |
| 8 | 8 |
| 9 | 9 |
| 10 # This file implements very minimal certificate and OCSP generation. It's | 10 # This file implements very minimal certificate and OCSP generation. It's |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 159 AUTHORITY_INFORMATION_ACCESS = asn1.OID([1, 3, 6, 1, 5, 5, 7, 1, 1]) | 159 AUTHORITY_INFORMATION_ACCESS = asn1.OID([1, 3, 6, 1, 5, 5, 7, 1, 1]) |
| 160 BASIC_CONSTRAINTS = asn1.OID([2, 5, 29, 19]) | 160 BASIC_CONSTRAINTS = asn1.OID([2, 5, 29, 19]) |
| 161 CERT_POLICIES = asn1.OID([2, 5, 29, 32]) | 161 CERT_POLICIES = asn1.OID([2, 5, 29, 32]) |
| 162 COMMON_NAME = asn1.OID([2, 5, 4, 3]) | 162 COMMON_NAME = asn1.OID([2, 5, 4, 3]) |
| 163 COUNTRY = asn1.OID([2, 5, 4, 6]) | 163 COUNTRY = asn1.OID([2, 5, 4, 6]) |
| 164 HASH_SHA1 = asn1.OID([1, 3, 14, 3, 2, 26]) | 164 HASH_SHA1 = asn1.OID([1, 3, 14, 3, 2, 26]) |
| 165 OCSP_TYPE_BASIC = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 1, 1]) | 165 OCSP_TYPE_BASIC = asn1.OID([1, 3, 6, 1, 5, 5, 7, 48, 1, 1]) |
| 166 ORGANIZATION = asn1.OID([2, 5, 4, 10]) | 166 ORGANIZATION = asn1.OID([2, 5, 4, 10]) |
| 167 PUBLIC_KEY_RSA = asn1.OID([1, 2, 840, 113549, 1, 1, 1]) | 167 PUBLIC_KEY_RSA = asn1.OID([1, 2, 840, 113549, 1, 1, 1]) |
| 168 SHA1_WITH_RSA_ENCRYPTION = asn1.OID([1, 2, 840, 113549, 1, 1, 5]) | 168 SHA1_WITH_RSA_ENCRYPTION = asn1.OID([1, 2, 840, 113549, 1, 1, 5]) |
| 169 # SignedCertificateTimestampList (RFC 6962) | |
|
wtc
2013/12/03 21:04:25
Nit: the comment should mention this OID is used w
| |
| 170 SCT_LIST_OCSP = asn1.OID([1, 3, 6, 1, 4, 1, 11129, 2, 4, 5]) | |
| 169 | 171 |
| 170 | 172 |
| 171 def MakeCertificate( | 173 def MakeCertificate( |
| 172 issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None): | 174 issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None): |
| 173 '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' | 175 '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' |
| 174 extensions = asn1.SEQUENCE([]) | 176 extensions = asn1.SEQUENCE([]) |
| 175 | 177 |
| 176 # Default subject name fields | 178 # Default subject name fields |
| 177 c = "XX" | 179 c = "XX" |
| 178 o = "Testing Org" | 180 o = "Testing Org" |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 239 return asn1.ToDER(asn1.SEQUENCE([ | 241 return asn1.ToDER(asn1.SEQUENCE([ |
| 240 asn1.Raw(tbsCert), | 242 asn1.Raw(tbsCert), |
| 241 asn1.SEQUENCE([ | 243 asn1.SEQUENCE([ |
| 242 SHA1_WITH_RSA_ENCRYPTION, | 244 SHA1_WITH_RSA_ENCRYPTION, |
| 243 None, | 245 None, |
| 244 ]), | 246 ]), |
| 245 asn1.BitString(privkey.Sign(tbsCert)), | 247 asn1.BitString(privkey.Sign(tbsCert)), |
| 246 ])) | 248 ])) |
| 247 | 249 |
| 248 | 250 |
| 249 def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state): | 251 def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state, sct_extension): |
| 250 # https://tools.ietf.org/html/rfc2560 | 252 # https://tools.ietf.org/html/rfc2560 |
| 251 issuer_name_hash = asn1.OCTETSTRING( | 253 issuer_name_hash = asn1.OCTETSTRING( |
| 252 hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) | 254 hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) |
| 253 | 255 |
| 254 issuer_key_hash = asn1.OCTETSTRING( | 256 issuer_key_hash = asn1.OCTETSTRING( |
| 255 hashlib.sha1(asn1.ToDER(issuer_key)).digest()) | 257 hashlib.sha1(asn1.ToDER(issuer_key)).digest()) |
| 256 | 258 |
| 257 cert_status = None | 259 cert_status = None |
| 258 if ocsp_state == OCSP_STATE_REVOKED: | 260 if ocsp_state == OCSP_STATE_REVOKED: |
| 259 cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) | 261 cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) |
| 260 elif ocsp_state == OCSP_STATE_UNKNOWN: | 262 elif ocsp_state == OCSP_STATE_UNKNOWN: |
| 261 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) | 263 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) |
| 262 elif ocsp_state == OCSP_STATE_GOOD: | 264 elif ocsp_state == OCSP_STATE_GOOD: |
| 263 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) | 265 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) |
| 264 else: | 266 else: |
| 265 raise ValueError('Bad OCSP state: ' + str(ocsp_state)) | 267 raise ValueError('Bad OCSP state: ' + str(ocsp_state)) |
| 266 | 268 |
| 269 single_response_sequence = [ # SingleResponse | |
| 270 asn1.SEQUENCE([ # CertID | |
| 271 asn1.SEQUENCE([ # hashAlgorithm | |
| 272 HASH_SHA1, | |
| 273 None, | |
| 274 ]), | |
| 275 issuer_name_hash, | |
| 276 issuer_key_hash, | |
| 277 serial, | |
| 278 ]), | |
| 279 cert_status, | |
| 280 asn1.GeneralizedTime("20100101060000Z"), # thisUpdate | |
| 281 asn1.Explicit(0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate | |
| 282 ] | |
| 283 | |
| 284 if sct_extension: | |
| 285 single_extension = asn1.SEQUENCE([ | |
| 286 SCT_LIST_OCSP, # exntID | |
| 287 False, # critical | |
| 288 asn1.OCTETSTRING(asn1.ToDER(asn1.OCTETSTRING(sct_extension))) | |
| 289 ]) | |
| 290 | |
| 291 single_extensions = asn1.SEQUENCE([single_extension]) | |
| 292 single_response_sequence.append(asn1.Explicit(1, single_extensions)) | |
| 293 | |
| 294 single_response = asn1.SEQUENCE(single_response_sequence) | |
| 295 | |
| 267 basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([ | 296 basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([ |
| 268 asn1.Explicit(2, issuer_key_hash), | 297 asn1.Explicit(2, issuer_key_hash), |
| 269 asn1.GeneralizedTime("20100101060000Z"), # producedAt | 298 asn1.GeneralizedTime("20100101060000Z"), # producedAt |
| 270 asn1.SEQUENCE([ | 299 asn1.SEQUENCE([single_response]), |
| 271 asn1.SEQUENCE([ # SingleResponse | 300 ])) |
|
wtc
2013/12/03 21:04:25
Nit: the original code indents this line with two
| |
| 272 asn1.SEQUENCE([ # CertID | |
| 273 asn1.SEQUENCE([ # hashAlgorithm | |
| 274 HASH_SHA1, | |
| 275 None, | |
| 276 ]), | |
| 277 issuer_name_hash, | |
| 278 issuer_key_hash, | |
| 279 serial, | |
| 280 ]), | |
| 281 cert_status, | |
| 282 asn1.GeneralizedTime("20100101060000Z"), # thisUpdate | |
| 283 asn1.Explicit(0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate | |
| 284 ]), | |
| 285 ]), | |
| 286 ])) | |
| 287 | 301 |
| 288 basic_resp = asn1.SEQUENCE([ | 302 basic_resp = asn1.SEQUENCE([ |
| 289 asn1.Raw(basic_resp_data_der), | 303 asn1.Raw(basic_resp_data_der), |
| 290 asn1.SEQUENCE([ | 304 asn1.SEQUENCE([ |
| 291 SHA1_WITH_RSA_ENCRYPTION, | 305 SHA1_WITH_RSA_ENCRYPTION, |
| 292 None, | 306 None, |
| 293 ]), | 307 ]), |
| 294 asn1.BitString(issuer_key.Sign(basic_resp_data_der)), | 308 asn1.BitString(issuer_key.Sign(basic_resp_data_der)), |
| 295 ]) | 309 ]) |
| 296 | 310 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 317 OCSP_STATE_UNAUTHORIZED = 4 | 331 OCSP_STATE_UNAUTHORIZED = 4 |
| 318 OCSP_STATE_UNKNOWN = 5 | 332 OCSP_STATE_UNKNOWN = 5 |
| 319 | 333 |
| 320 # unauthorizedDER is an OCSPResponse with a status of 6: | 334 # unauthorizedDER is an OCSPResponse with a status of 6: |
| 321 # SEQUENCE { ENUM(6) } | 335 # SEQUENCE { ENUM(6) } |
| 322 unauthorizedDER = '30030a0106'.decode('hex') | 336 unauthorizedDER = '30030a0106'.decode('hex') |
| 323 | 337 |
| 324 def GenerateCertKeyAndOCSP(subject = "127.0.0.1", | 338 def GenerateCertKeyAndOCSP(subject = "127.0.0.1", |
| 325 ocsp_url = "http://127.0.0.1", | 339 ocsp_url = "http://127.0.0.1", |
| 326 ocsp_state = OCSP_STATE_GOOD, | 340 ocsp_state = OCSP_STATE_GOOD, |
| 327 serial = 0): | 341 serial = 0, |
| 342 sct_extension = None): | |
| 328 '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where: | 343 '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where: |
| 329 * cert_and_key_pem contains a certificate and private key in PEM format | 344 * cert_and_key_pem contains a certificate and private key in PEM format |
| 330 with the given subject common name and OCSP URL. | 345 with the given subject common name and OCSP URL. |
| 331 * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is | 346 * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is |
| 332 None''' | 347 None''' |
| 333 | 348 |
| 334 if serial == 0: | 349 if serial == 0: |
| 335 serial = RandomNumber(16) | 350 serial = RandomNumber(16) |
| 336 cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY, | 351 cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY, |
| 337 bytes(ocsp_url)) | 352 bytes(ocsp_url)) |
| 338 cert_pem = DERToPEM(cert_der) | 353 cert_pem = DERToPEM(cert_der) |
| 339 | 354 |
| 340 ocsp_der = None | 355 ocsp_der = None |
| 341 if ocsp_url is not None: | 356 if ocsp_url is not None: |
| 342 if ocsp_state == OCSP_STATE_UNAUTHORIZED: | 357 if ocsp_state == OCSP_STATE_UNAUTHORIZED: |
| 343 ocsp_der = unauthorizedDER | 358 ocsp_der = unauthorizedDER |
| 344 elif ocsp_state == OCSP_STATE_INVALID: | 359 elif ocsp_state == OCSP_STATE_INVALID: |
| 345 ocsp_der = '3' | 360 ocsp_der = '3' |
| 346 else: | 361 else: |
| 347 ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state) | 362 ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state, |
| 363 sct_extension) | |
| 348 | 364 |
| 349 return (cert_pem + KEY_PEM, ocsp_der) | 365 return (cert_pem + KEY_PEM, ocsp_der) |
| OLD | NEW |