Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(982)

Side by Side Diff: net/tools/testserver/minica.py

Issue 92443002: Extract Certificate Transparency SCTs from stapled OCSP responses (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@extract_scts
Patch Set: review comments Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698