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 datetime | |
| 6 import hashlib | 7 import hashlib |
| 7 import os | 8 import os |
| 9 import time | |
| 8 | 10 |
| 11 GENERALIZED_TIME_FORMAT = "%Y%m%d%H%M%SZ" | |
| 12 | |
| 13 OCSP_STATE_GOOD = 1 | |
| 14 OCSP_STATE_REVOKED = 2 | |
| 15 OCSP_STATE_INVALID = 3 | |
| 16 OCSP_STATE_UNAUTHORIZED = 4 | |
| 17 OCSP_STATE_UNKNOWN = 5 | |
| 18 | |
| 19 OCSP_DATE_VALID = 1 | |
| 20 OCSP_DATE_OLD = 2 | |
| 21 OCSP_DATE_YOUNG = 3 | |
| 22 OCSP_DATE_LONG = 4 | |
| 9 | 23 |
| 10 # This file implements very minimal certificate and OCSP generation. It's | 24 # This file implements very minimal certificate and OCSP generation. It's |
| 11 # designed to test revocation checking. | 25 # designed to test revocation checking. |
| 12 | 26 |
| 13 def RandomNumber(length_in_bytes): | 27 def RandomNumber(length_in_bytes): |
| 14 '''RandomNumber returns a random number of length 8*|length_in_bytes| bits''' | 28 '''RandomNumber returns a random number of length 8*|length_in_bytes| bits''' |
| 15 rand = os.urandom(length_in_bytes) | 29 rand = os.urandom(length_in_bytes) |
| 16 n = 0 | 30 n = 0 |
| 17 for x in rand: | 31 for x in rand: |
| 18 n <<= 8 | 32 n <<= 8 |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 238 | 252 |
| 239 return asn1.ToDER(asn1.SEQUENCE([ | 253 return asn1.ToDER(asn1.SEQUENCE([ |
| 240 asn1.Raw(tbsCert), | 254 asn1.Raw(tbsCert), |
| 241 asn1.SEQUENCE([ | 255 asn1.SEQUENCE([ |
| 242 SHA256_WITH_RSA_ENCRYPTION, | 256 SHA256_WITH_RSA_ENCRYPTION, |
| 243 None, | 257 None, |
| 244 ]), | 258 ]), |
| 245 asn1.BitString(privkey.Sign(tbsCert)), | 259 asn1.BitString(privkey.Sign(tbsCert)), |
| 246 ])) | 260 ])) |
| 247 | 261 |
| 248 | 262 def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state, ocsp_date): |
| 249 def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state): | |
| 250 # https://tools.ietf.org/html/rfc2560 | 263 # https://tools.ietf.org/html/rfc2560 |
| 251 issuer_name_hash = asn1.OCTETSTRING( | 264 issuer_name_hash = asn1.OCTETSTRING( |
| 252 hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) | 265 hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) |
| 253 | 266 |
| 254 issuer_key_hash = asn1.OCTETSTRING( | 267 issuer_key_hash = asn1.OCTETSTRING( |
| 255 hashlib.sha1(asn1.ToDER(issuer_key)).digest()) | 268 hashlib.sha1(asn1.ToDER(issuer_key)).digest()) |
| 256 | 269 |
| 257 cert_status = None | 270 cert_status = None |
| 258 if ocsp_state == OCSP_STATE_REVOKED: | 271 if ocsp_state == OCSP_STATE_REVOKED: |
| 259 cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) | 272 cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) |
| 260 elif ocsp_state == OCSP_STATE_UNKNOWN: | 273 elif ocsp_state == OCSP_STATE_UNKNOWN: |
| 261 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) | 274 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) |
| 262 elif ocsp_state == OCSP_STATE_GOOD: | 275 elif ocsp_state == OCSP_STATE_GOOD: |
| 263 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) | 276 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) |
| 264 else: | 277 else: |
| 265 raise ValueError('Bad OCSP state: ' + str(ocsp_state)) | 278 raise ValueError('Bad OCSP state: ' + str(ocsp_state)) |
| 266 | 279 |
| 280 now = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())) | |
| 281 if ocsp_date == OCSP_DATE_VALID: | |
| 282 thisUpdate = now - datetime.timedelta(hours=1) | |
| 283 nextUpdate = thisUpdate + datetime.timedelta(weeks=1) | |
| 284 elif ocsp_date == OCSP_DATE_OLD: | |
| 285 thisUpdate = now - datetime.timedelta(hours=1, weeks=1) | |
| 286 nextUpdate = thisUpdate + datetime.timedelta(weeks=1) | |
| 287 elif ocsp_date == OCSP_DATE_YOUNG: | |
|
svaldez
2016/06/23 14:03:16
EARLY?
| |
| 288 thisUpdate = now + datetime.timedelta(hours=1) | |
| 289 nextUpdate = thisUpdate + datetime.timedelta(weeks=1) | |
| 290 elif ocsp_date == OCSP_DATE_LONG: | |
| 291 thisUpdate = now - datetime.timedelta(days=365) | |
| 292 nextUpdate = thisUpdate + datetime.timedelta(hours=1, days=365) | |
| 293 else: | |
| 294 raise ValueError('Bad OCSP date: ' + str(ocsp_date)) | |
| 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([ |
| 271 asn1.SEQUENCE([ # SingleResponse | 300 asn1.SEQUENCE([ # SingleResponse |
| 272 asn1.SEQUENCE([ # CertID | 301 asn1.SEQUENCE([ # CertID |
| 273 asn1.SEQUENCE([ # hashAlgorithm | 302 asn1.SEQUENCE([ # hashAlgorithm |
| 274 HASH_SHA1, | 303 HASH_SHA1, |
| 275 None, | 304 None, |
| 276 ]), | 305 ]), |
| 277 issuer_name_hash, | 306 issuer_name_hash, |
| 278 issuer_key_hash, | 307 issuer_key_hash, |
| 279 serial, | 308 serial, |
| 280 ]), | 309 ]), |
| 281 cert_status, | 310 cert_status, |
| 282 asn1.GeneralizedTime("20100101060000Z"), # thisUpdate | 311 asn1.GeneralizedTime( # thisUpdate, 1 hour ago |
| 283 asn1.Explicit(0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate | 312 thisUpdate.strftime(GENERALIZED_TIME_FORMAT) |
| 313 ), | |
| 314 asn1.Explicit( # nextUpdate, 7 days later | |
| 315 0, | |
| 316 asn1.GeneralizedTime(nextUpdate.strftime(GENERALIZED_TIME_FORMAT)) | |
| 317 ), | |
| 284 ]), | 318 ]), |
| 285 ]), | 319 ]), |
| 286 ])) | 320 ])) |
| 287 | 321 |
| 288 basic_resp = asn1.SEQUENCE([ | 322 basic_resp = asn1.SEQUENCE([ |
| 289 asn1.Raw(basic_resp_data_der), | 323 asn1.Raw(basic_resp_data_der), |
| 290 asn1.SEQUENCE([ | 324 asn1.SEQUENCE([ |
| 291 SHA256_WITH_RSA_ENCRYPTION, | 325 SHA256_WITH_RSA_ENCRYPTION, |
| 292 None, | 326 None, |
| 293 ]), | 327 ]), |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 304 | 338 |
| 305 return asn1.ToDER(resp) | 339 return asn1.ToDER(resp) |
| 306 | 340 |
| 307 | 341 |
| 308 def DERToPEM(der): | 342 def DERToPEM(der): |
| 309 pem = '-----BEGIN CERTIFICATE-----\n' | 343 pem = '-----BEGIN CERTIFICATE-----\n' |
| 310 pem += der.encode('base64') | 344 pem += der.encode('base64') |
| 311 pem += '-----END CERTIFICATE-----\n' | 345 pem += '-----END CERTIFICATE-----\n' |
| 312 return pem | 346 return pem |
| 313 | 347 |
| 314 OCSP_STATE_GOOD = 1 | |
| 315 OCSP_STATE_REVOKED = 2 | |
| 316 OCSP_STATE_INVALID = 3 | |
| 317 OCSP_STATE_UNAUTHORIZED = 4 | |
| 318 OCSP_STATE_UNKNOWN = 5 | |
| 319 | |
| 320 # unauthorizedDER is an OCSPResponse with a status of 6: | 348 # unauthorizedDER is an OCSPResponse with a status of 6: |
| 321 # SEQUENCE { ENUM(6) } | 349 # SEQUENCE { ENUM(6) } |
| 322 unauthorizedDER = '30030a0106'.decode('hex') | 350 unauthorizedDER = '30030a0106'.decode('hex') |
| 323 | 351 |
| 324 def GenerateCertKeyAndOCSP(subject = "127.0.0.1", | 352 def GenerateCertKeyAndOCSP(subject = "127.0.0.1", |
| 325 ocsp_url = "http://127.0.0.1", | 353 ocsp_url = "http://127.0.0.1", |
| 326 ocsp_state = OCSP_STATE_GOOD, | 354 ocsp_state = OCSP_STATE_GOOD, |
| 355 ocsp_date = OCSP_DATE_VALID, | |
| 327 serial = 0): | 356 serial = 0): |
| 328 '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where: | 357 '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where: |
| 329 * cert_and_key_pem contains a certificate and private key in PEM format | 358 * cert_and_key_pem contains a certificate and private key in PEM format |
| 330 with the given subject common name and OCSP URL. | 359 with the given subject common name and OCSP URL. |
| 331 * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is | 360 * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is |
| 332 None''' | 361 None''' |
| 333 | 362 |
| 334 if serial == 0: | 363 if serial == 0: |
| 335 serial = RandomNumber(16) | 364 serial = RandomNumber(16) |
| 336 cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY, | 365 cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY, |
| 337 bytes(ocsp_url)) | 366 bytes(ocsp_url)) |
| 338 cert_pem = DERToPEM(cert_der) | 367 cert_pem = DERToPEM(cert_der) |
| 339 | 368 |
| 340 ocsp_der = None | 369 ocsp_der = None |
| 341 if ocsp_url is not None: | 370 if ocsp_url is not None: |
| 342 if ocsp_state == OCSP_STATE_UNAUTHORIZED: | 371 if ocsp_state == OCSP_STATE_UNAUTHORIZED: |
| 343 ocsp_der = unauthorizedDER | 372 ocsp_der = unauthorizedDER |
| 344 elif ocsp_state == OCSP_STATE_INVALID: | 373 elif ocsp_state == OCSP_STATE_INVALID: |
| 345 ocsp_der = '3' | 374 ocsp_der = '3' |
| 346 else: | 375 else: |
| 347 ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state) | 376 ocsp_der = MakeOCSPResponse( |
| 377 ISSUER_CN, KEY, serial, ocsp_state, ocsp_date) | |
| 348 | 378 |
| 349 return (cert_pem + KEY_PEM, ocsp_der) | 379 return (cert_pem + KEY_PEM, ocsp_der) |
| OLD | NEW |