def MakeOCSPSingleResponse(issuer_name_hash, issuer_key_hash, serial, ocsp_state, ocsp_date): cert_status = None if ocsp_state == OCSP_STATE_REVOKED: cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) elif ocsp_state == OCSP_STATE_UNKNOWN: cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 2, 0)) elif ocsp_state == OCSP_STATE_GOOD: cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) elif ocsp_state == OCSP_STATE_MISMATCHED_SERIAL: cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) serial -= 1 else: raise ValueError('Bad OCSP state: ' + str(ocsp_state)) now = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())) if ocsp_date == OCSP_DATE_VALID: thisUpdate = now - datetime.timedelta(days=1) nextUpdate = thisUpdate + datetime.timedelta(weeks=1) elif ocsp_date == OCSP_DATE_OLD: thisUpdate = now - datetime.timedelta(days=1, weeks=1) nextUpdate = thisUpdate + datetime.timedelta(weeks=1) elif ocsp_date == OCSP_DATE_EARLY: thisUpdate = now + datetime.timedelta(days=1) nextUpdate = thisUpdate + datetime.timedelta(weeks=1) elif ocsp_date == OCSP_DATE_LONG: thisUpdate = now - datetime.timedelta(days=365) nextUpdate = thisUpdate + datetime.timedelta(days=366) elif ocsp_date == OCSP_DATE_LONGER: thisUpdate = now - datetime.timedelta(days=367) nextUpdate = thisUpdate + datetime.timedelta(days=368) else: raise ValueError('Bad OCSP date: ' + str(ocsp_date)) return asn1.SEQUENCE([ # SingleResponse asn1.SEQUENCE([ # CertID asn1.SEQUENCE([ # hashAlgorithm HASH_SHA1, None, ]), issuer_name_hash, issuer_key_hash, serial, ]), cert_status, asn1.GeneralizedTime( # thisUpdate thisUpdate.strftime(GENERALIZED_TIME_FORMAT)), asn1.Explicit( # nextUpdate 0, asn1.GeneralizedTime( nextUpdate.strftime(GENERALIZED_TIME_FORMAT))), ])
def MakeOCSPResponse(issuer_cn, issuer_key, serial, revoked): # https://tools.ietf.org/html/rfc2560 issuer_name_hash = asn1.OCTETSTRING( hashlib.sha1(asn1.ToDER(Name(cn=issuer_cn))).digest()) issuer_key_hash = asn1.OCTETSTRING( hashlib.sha1(asn1.ToDER(issuer_key)).digest()) cert_status = None if revoked: cert_status = asn1.Explicit(1, asn1.GeneralizedTime("20100101060000Z")) else: cert_status = asn1.Raw(asn1.TagAndLength(0x80 | 0, 0)) basic_resp_data_der = asn1.ToDER( asn1.SEQUENCE([ asn1.Explicit(2, issuer_key_hash), asn1.GeneralizedTime("20100101060000Z"), # producedAt asn1.SEQUENCE([ asn1.SEQUENCE([ # SingleResponse asn1.SEQUENCE([ # CertID asn1.SEQUENCE([ # hashAlgorithm HASH_SHA1, None, ]), issuer_name_hash, issuer_key_hash, serial, ]), cert_status, asn1.GeneralizedTime("20100101060000Z"), # thisUpdate asn1.Explicit( 0, asn1.GeneralizedTime("20300101060000Z")), # nextUpdate ]), ]), ])) basic_resp = asn1.SEQUENCE([ asn1.Raw(basic_resp_data_der), asn1.SEQUENCE([ SHA1_WITH_RSA_ENCRYPTION, None, ]), asn1.BitString(issuer_key.Sign(basic_resp_data_der)), ]) resp = asn1.SEQUENCE([ asn1.ENUMERATED(0), asn1.Explicit( 0, asn1.SEQUENCE([ OCSP_TYPE_BASIC, asn1.OCTETSTRING(asn1.ToDER(basic_resp)), ])) ]) return asn1.ToDER(resp)
def MakeCertificate( issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url = None, ca_issuers_url = None, is_ca=False, path_len=None, ip_sans=None, dns_sans=None): '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' extensions = asn1.SEQUENCE([]) # Default subject name fields c = "XX" o = "Testing Org" if is_ca: # Root certificate. c = None o = None extensions.children.append( asn1.SEQUENCE([ BASIC_CONSTRAINTS, True, asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([ True, # IsCA ] + ([path_len] if path_len is not None else []) # Path len ))), ])) if ip_sans is not None or dns_sans is not None: sans = [] if dns_sans is not None: for dns_name in dns_sans: sans.append( asn1.Raw(asn1.TagAndLength(0x82, len(dns_name)) + dns_name)) if ip_sans is not None: for ip_addr in ip_sans: sans.append( asn1.Raw(asn1.TagAndLength(0x87, len(ip_addr)) + ip_addr)) extensions.children.append( asn1.SEQUENCE([ SUBJECT_ALTERNATIVE_NAME, # There is implicitly a critical=False here. Since false is the # default, encoding the value would be invalid DER. asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE(sans))) ])) if ocsp_url is not None or ca_issuers_url is not None: aia_entries = [] if ocsp_url is not None: aia_entries.append( asn1.SEQUENCE([ AIA_OCSP, asn1.Raw(asn1.TagAndLength(0x86, len(ocsp_url)) + ocsp_url), ])) if ca_issuers_url is not None: aia_entries.append( asn1.SEQUENCE([ AIA_CA_ISSUERS, asn1.Raw(asn1.TagAndLength(0x86, len(ca_issuers_url)) + ca_issuers_url), ])) extensions.children.append( asn1.SEQUENCE([ AUTHORITY_INFORMATION_ACCESS, # There is implicitly a critical=False here. Since false is the default, # encoding the value would be invalid DER. asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE(aia_entries))), ])) extensions.children.append( asn1.SEQUENCE([ CERT_POLICIES, # There is implicitly a critical=False here. Since false is the default, # encoding the value would be invalid DER. asn1.OCTETSTRING(asn1.ToDER(asn1.SEQUENCE([ asn1.SEQUENCE([ # PolicyInformation CERT_POLICY_OID, ]), ]))), ]) ) tbsCert = asn1.ToDER(asn1.SEQUENCE([ asn1.Explicit(0, 2), # Version serial, asn1.SEQUENCE([SHA256_WITH_RSA_ENCRYPTION, None]), # SignatureAlgorithm Name(cn = issuer_cn), # Issuer asn1.SEQUENCE([ # Validity asn1.UTCTime("100101060000Z"), # NotBefore asn1.UTCTime("321201060000Z"), # NotAfter ]), Name(cn = subject_cn, c = c, o = o), # Subject asn1.SEQUENCE([ # SubjectPublicKeyInfo asn1.SEQUENCE([ # Algorithm PUBLIC_KEY_RSA, None, ]), asn1.BitString(asn1.ToDER(pubkey)), ]), asn1.Explicit(3, extensions), ])) return asn1.ToDER(asn1.SEQUENCE([ asn1.Raw(tbsCert), asn1.SEQUENCE([ SHA256_WITH_RSA_ENCRYPTION, None, ]), asn1.BitString(privkey.Sign(tbsCert)), ]))
def MakeCertificate(issuer_cn, subject_cn, serial, pubkey, privkey, ocsp_url=None): '''MakeCertificate returns a DER encoded certificate, signed by privkey.''' extensions = asn1.SEQUENCE([]) # Default subject name fields c = "XX" o = "Testing Org" if issuer_cn == subject_cn: # Root certificate. c = None o = None extensions.children.append( asn1.SEQUENCE([ BASIC_CONSTRAINTS, True, asn1.OCTETSTRING( asn1.ToDER(asn1.SEQUENCE([ True, # IsCA 0, # Path len ]))), ])) if ocsp_url is not None: extensions.children.append( asn1.SEQUENCE([ AUTHORITY_INFORMATION_ACCESS, # There is implicitly a critical=False here. Since false is the default, # encoding the value would be invalid DER. asn1.OCTETSTRING( asn1.ToDER( asn1.SEQUENCE([ asn1.SEQUENCE([ AIA_OCSP, asn1.Raw( asn1.TagAndLength(0x86, len(ocsp_url)) + ocsp_url), ]), ]))), ])) extensions.children.append( asn1.SEQUENCE([ CERT_POLICIES, # There is implicitly a critical=False here. Since false is the default, # encoding the value would be invalid DER. asn1.OCTETSTRING( asn1.ToDER( asn1.SEQUENCE([ asn1.SEQUENCE([ # PolicyInformation CERT_POLICY_OID, ]), ]))), ])) tbsCert = asn1.ToDER( asn1.SEQUENCE([ asn1.Explicit(0, 2), # Version serial, asn1.SEQUENCE([SHA256_WITH_RSA_ENCRYPTION, None]), # SignatureAlgorithm Name(cn=issuer_cn), # Issuer asn1.SEQUENCE([ # Validity asn1.UTCTime("100101060000Z"), # NotBefore asn1.UTCTime("321201060000Z"), # NotAfter ]), Name(cn=subject_cn, c=c, o=o), # Subject asn1.SEQUENCE([ # SubjectPublicKeyInfo asn1.SEQUENCE([ # Algorithm PUBLIC_KEY_RSA, None, ]), asn1.BitString(asn1.ToDER(pubkey)), ]), asn1.Explicit(3, extensions), ])) return asn1.ToDER( asn1.SEQUENCE([ asn1.Raw(tbsCert), asn1.SEQUENCE([ SHA256_WITH_RSA_ENCRYPTION, None, ]), asn1.BitString(privkey.Sign(tbsCert)), ]))