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) | |
170 SCT_LIST_OCSP = asn1.OID([1, 3, 6, 1, 4, 1, 11129, 2, 4, 5]) | |
171 | |
wtc
2013/12/03 01:18:06
Nit: don't add this blank line.
ekasper
2013/12/03 13:50:51
Done.
| |
169 | 172 |
170 | 173 |
171 def MakeCertificate( | 174 def MakeCertificate( |
172 issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None): | 175 issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None): |
173 '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' | 176 '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' |
174 extensions = asn1.SEQUENCE([]) | 177 extensions = asn1.SEQUENCE([]) |
175 | 178 |
176 # Default subject name fields | 179 # Default subject name fields |
177 c = "XX" | 180 c = "XX" |
178 o = "Testing Org" | 181 o = "Testing Org" |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 return asn1.ToDER(asn1.SEQUENCE([ | 242 return asn1.ToDER(asn1.SEQUENCE([ |
240 asn1.Raw(tbsCert), | 243 asn1.Raw(tbsCert), |
241 asn1.SEQUENCE([ | 244 asn1.SEQUENCE([ |
242 SHA1_WITH_RSA_ENCRYPTION, | 245 SHA1_WITH_RSA_ENCRYPTION, |
243 None, | 246 None, |
244 ]), | 247 ]), |
245 asn1.BitString(privkey.Sign(tbsCert)), | 248 asn1.BitString(privkey.Sign(tbsCert)), |
246 ])) | 249 ])) |
247 | 250 |
248 | 251 |
249 def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state): | 252 def MakeOCSPResponse(issuer_cn, issuer_key, serial, ocsp_state, sct_extension): |
250 # https://tools.ietf.org/html/rfc2560 | 253 # https://tools.ietf.org/html/rfc2560 |
251 issuer_name_hash = asn1.OCTETSTRING( | 254 issuer_name_hash = asn1.OCTETSTRING( |
252 hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) | 255 hashlib.sha1(asn1.ToDER(Name(cn = issuer_cn))).digest()) |
253 | 256 |
254 issuer_key_hash = asn1.OCTETSTRING( | 257 issuer_key_hash = asn1.OCTETSTRING( |
255 hashlib.sha1(asn1.ToDER(issuer_key)).digest()) | 258 hashlib.sha1(asn1.ToDER(issuer_key)).digest()) |
256 | 259 |
257 cert_status = None | 260 cert_status = None |
258 if ocsp_state == OCSP_STATE_REVOKED: | 261 if ocsp_state == OCSP_STATE_REVOKED: |
259 cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) | 262 cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) |
260 elif ocsp_state == OCSP_STATE_UNKNOWN: | 263 elif ocsp_state == OCSP_STATE_UNKNOWN: |
261 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) | 264 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) |
262 elif ocsp_state == OCSP_STATE_GOOD: | 265 elif ocsp_state == OCSP_STATE_GOOD: |
263 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) | 266 cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) |
264 else: | 267 else: |
265 raise ValueError('Bad OCSP state: ' + str(ocsp_state)) | 268 raise ValueError('Bad OCSP state: ' + str(ocsp_state)) |
266 | 269 |
270 single_response_sequence = [ # SingleResponse | |
271 asn1.SEQUENCE([ # CertID | |
272 asn1.SEQUENCE([ # hashAlgorithm | |
273 HASH_SHA1, | |
274 None, | |
275 ]), | |
276 issuer_name_hash, | |
277 issuer_key_hash, | |
278 serial, | |
279 ]), | |
280 cert_status, | |
281 asn1.GeneralizedTime("20100101060000Z"), # thisUpdate | |
282 asn1.Explicit(0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate | |
283 ] | |
284 | |
285 if sct_extension: | |
286 single_extension = asn1.SEQUENCE([ | |
287 SCT_LIST_OCSP, # exntID | |
288 False, # critical | |
289 asn1.OCTETSTRING(asn1.ToDER(asn1.OCTETSTRING(sct_extension))) | |
290 ]) | |
291 | |
292 single_extensions = asn1.SEQUENCE([single_extension]) | |
293 single_response_sequence.append(asn1.Explicit(1, single_extensions)) | |
294 | |
295 single_response = asn1.SEQUENCE(single_response_sequence) | |
296 | |
267 basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([ | 297 basic_resp_data_der = asn1.ToDER(asn1.SEQUENCE([ |
268 asn1.Explicit(2, issuer_key_hash), | 298 asn1.Explicit(2, issuer_key_hash), |
269 asn1.GeneralizedTime("20100101060000Z"), # producedAt | 299 asn1.GeneralizedTime("20100101060000Z"), # producedAt |
270 asn1.SEQUENCE([ | 300 asn1.SEQUENCE([single_response]), |
271 asn1.SEQUENCE([ # SingleResponse | 301 ])) |
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 | 302 |
288 basic_resp = asn1.SEQUENCE([ | 303 basic_resp = asn1.SEQUENCE([ |
289 asn1.Raw(basic_resp_data_der), | 304 asn1.Raw(basic_resp_data_der), |
290 asn1.SEQUENCE([ | 305 asn1.SEQUENCE([ |
291 SHA1_WITH_RSA_ENCRYPTION, | 306 SHA1_WITH_RSA_ENCRYPTION, |
292 None, | 307 None, |
293 ]), | 308 ]), |
294 asn1.BitString(issuer_key.Sign(basic_resp_data_der)), | 309 asn1.BitString(issuer_key.Sign(basic_resp_data_der)), |
295 ]) | 310 ]) |
296 | 311 |
(...skipping 20 matching lines...) Expand all Loading... | |
317 OCSP_STATE_UNAUTHORIZED = 4 | 332 OCSP_STATE_UNAUTHORIZED = 4 |
318 OCSP_STATE_UNKNOWN = 5 | 333 OCSP_STATE_UNKNOWN = 5 |
319 | 334 |
320 # unauthorizedDER is an OCSPResponse with a status of 6: | 335 # unauthorizedDER is an OCSPResponse with a status of 6: |
321 # SEQUENCE { ENUM(6) } | 336 # SEQUENCE { ENUM(6) } |
322 unauthorizedDER = '30030a0106'.decode('hex') | 337 unauthorizedDER = '30030a0106'.decode('hex') |
323 | 338 |
324 def GenerateCertKeyAndOCSP(subject = "127.0.0.1", | 339 def GenerateCertKeyAndOCSP(subject = "127.0.0.1", |
325 ocsp_url = "http://127.0.0.1", | 340 ocsp_url = "http://127.0.0.1", |
326 ocsp_state = OCSP_STATE_GOOD, | 341 ocsp_state = OCSP_STATE_GOOD, |
327 serial = 0): | 342 serial = 0, |
343 sct_extension = None): | |
328 '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where: | 344 '''GenerateCertKeyAndOCSP returns a (cert_and_key_pem, ocsp_der) where: |
329 * cert_and_key_pem contains a certificate and private key in PEM format | 345 * cert_and_key_pem contains a certificate and private key in PEM format |
330 with the given subject common name and OCSP URL. | 346 with the given subject common name and OCSP URL. |
331 * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is | 347 * ocsp_der contains a DER encoded OCSP response or None if ocsp_url is |
332 None''' | 348 None''' |
333 | 349 |
334 if serial == 0: | 350 if serial == 0: |
335 serial = RandomNumber(16) | 351 serial = RandomNumber(16) |
336 cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY, | 352 cert_der = MakeCertificate(ISSUER_CN, bytes(subject), serial, KEY, KEY, |
337 bytes(ocsp_url)) | 353 bytes(ocsp_url)) |
338 cert_pem = DERToPEM(cert_der) | 354 cert_pem = DERToPEM(cert_der) |
339 | 355 |
340 ocsp_der = None | 356 ocsp_der = None |
341 if ocsp_url is not None: | 357 if ocsp_url is not None: |
342 if ocsp_state == OCSP_STATE_UNAUTHORIZED: | 358 if ocsp_state == OCSP_STATE_UNAUTHORIZED: |
343 ocsp_der = unauthorizedDER | 359 ocsp_der = unauthorizedDER |
344 elif ocsp_state == OCSP_STATE_INVALID: | 360 elif ocsp_state == OCSP_STATE_INVALID: |
345 ocsp_der = '3' | 361 ocsp_der = '3' |
346 else: | 362 else: |
347 ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state) | 363 ocsp_der = MakeOCSPResponse(ISSUER_CN, KEY, serial, ocsp_state, |
364 sct_extension) | |
348 | 365 |
349 return (cert_pem + KEY_PEM, ocsp_der) | 366 return (cert_pem + KEY_PEM, ocsp_der) |
OLD | NEW |