def _gen_ca(): public, private = _gen_key() builder = CertificateBuilder( {"organization_name": "Fake Certificate Authority"}, public) builder.self_signed = True builder.ca = True return (_dump_cert(builder.build(private)), _dump_private(private))
def generate_cert_and_key(cn, filename, keysize, keytype='rsa'): ca_key_name = '%s.key' % filename ca_cert_name = '%s.crt' % filename curdir = pathlib.Path(__file__).parent # Generate and save the key and certificate for the root CA root_ca_public_key, root_ca_private_key = asymmetric.generate_pair( keytype, bit_size=keysize) with open(curdir.joinpath(ca_key_name), 'wb') as f: f.write(asymmetric.dump_private_key(root_ca_private_key, None)) builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': cn, }, root_ca_public_key) builder.self_signed = True builder.ca = True root_ca_certificate = builder.build(root_ca_private_key) with open(curdir.joinpath(ca_cert_name), 'wb') as f: f.write(pem_armor_certificate(root_ca_certificate))
def generate_no_san_cert(domain, base_year, quiet=False): if not quiet: write('Generating domain-match cert ... ', end='') ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': 'no-san.{}'.format(domain), }, public_key ) builder.issuer = ca_cert builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('no-san', certificate) if not quiet: write('done')
def gencert(name): ca_cert_data, ca_private_data = _gen_ca() public_data, private_data = _cert_key() builder = CertificateBuilder({"common_name": name}, _load_public(public_data)) builder.issuer = _load_cert(ca_cert_data) builder.subject_alt_domains = [name] cert = builder.build(_load_private(ca_private_data)) return (_dump_cert(cert), private_data, ca_cert_data)
def generate_self_signed(cls, cn, key_usage, private_key=None): if private_key is None: private_key = cls.generate_pair() builder = CertificateBuilder({ u'common_name': six.text_type(cn), }, private_key.public_key.to_asn1_public_key()) builder.key_usage = key_usage #[u'digital_signature', u'key_encipherment'] builder.self_signed = True certificate = builder.build(private_key.to_asn1_private_key()) return Certificate(certificate=certificate), private_key
def test_build_end_entity_cert(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, public_key ) builder.self_signed = True builder.subject_alt_domains = ['example.com'] certificate = builder.build(private_key) der_bytes = certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual('sha256', new_certificate.hash_algo) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, new_certificate.issuer.native ) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, new_certificate.subject.native ) self.assertEqual('ecdsa', new_certificate.signature_algo) self.assertEqual(set(['key_usage']), new_certificate.critical_extensions) self.assertEqual(set(['digital_signature', 'key_encipherment']), new_certificate.key_usage_value.native) self.assertEqual(['server_auth', 'client_auth'], new_certificate.extended_key_usage_value.native) self.assertEqual(None, new_certificate.authority_key_identifier) self.assertEqual(False, new_certificate.ca) self.assertEqual(True, new_certificate.self_issued) self.assertEqual('yes', new_certificate.self_signed) self.assertEqual(certificate.public_key.sha1, new_certificate.key_identifier) self.assertEqual(['example.com'], new_certificate.valid_domains)
def test_build_ca_cert(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, public_key ) builder.hash_algo = 'sha512' builder.self_signed = True builder.ca = True certificate = builder.build(private_key) der_bytes = certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual('sha512', new_certificate.hash_algo) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, new_certificate.issuer.native ) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, new_certificate.subject.native ) self.assertEqual('ecdsa', new_certificate.signature_algo) self.assertEqual(set(['key_usage', 'basic_constraints']), new_certificate.critical_extensions) self.assertEqual(set(['key_cert_sign', 'crl_sign']), new_certificate.key_usage_value.native) self.assertEqual(None, new_certificate.extended_key_usage_value) self.assertEqual(None, new_certificate.authority_key_identifier) self.assertEqual(True, new_certificate.ca) self.assertEqual(True, new_certificate.self_issued) self.assertEqual('yes', new_certificate.self_signed) self.assertEqual(certificate.public_key.sha1, new_certificate.key_identifier)
def generate_weak_sig_cert(domain, base_year, quiet=False): if not quiet: write('Generating weak-sig cert ... ', end='') full_domain = 'weak-sig.{}'.format(domain) ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': full_domain, }, public_key ) builder.issuer = ca_cert builder.subject_alt_domains = [full_domain] # Hack since API doesn't allow selection of weak algo builder._hash_algo = 'md5' builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('weak-sig', certificate) if not quiet: write('done')
def generate_bad_key_usage_cert(domain, base_year, quiet=False): if not quiet: write('Generating bad-key-usage cert ... ', end='') full_domain = 'bad-key-usage.{}'.format(domain) ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': full_domain, }, public_key ) builder.issuer = ca_cert builder.subject_alt_domains = [full_domain] builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.key_usage = set(['crl_sign']) builder.extended_key_usage = set(['email_protection']) certificate = builder.build(ca_private_key) dump_cert('bad-key-usage', certificate) if not quiet: write('done')
def build_ca(): if not os.path.exists(settings.CA_PATH): os.makedirs(settings.CA_PATH) root_ca_public_key, root_ca_private_key = asymmetric.generate_pair( 'rsa', bit_size=4096) with open(settings.CA_KEY, 'wb') as f: f.write( asymmetric.dump_private_key(root_ca_private_key, settings.CA_KEY_PASSWD)) builder = CertificateBuilder( { 'country_name': 'CR', 'state_or_province_name': 'San Jose', 'locality_name': 'Costa Rica', 'organization_name': 'DFVA Independiente', 'common_name': 'DFVA Root CA 1', }, root_ca_public_key) now = timezone.now() builder.self_signed = True builder.ca = True builder.end_date = now + timedelta(settings.CA_CERT_DURATION * 10) root_ca_certificate = builder.build(root_ca_private_key) with open(settings.CA_CERT, 'wb') as f: f.write(pem_armor_certificate(root_ca_certificate)) builder = CertificateListBuilder('http://crl.dfva.info', root_ca_certificate, 1000) crl_list = builder.build(root_ca_private_key) with open(settings.CA_CRL, 'wb') as f: f.write(crl_list.dump())
def create_certificate_for_client(client_details): # load client public key path_for_client_public_key = PUBLIC_KEY_STORE + file_names.get_public_key_name( client_details['domain_name']) client_public_key = asymmetric.load_public_key\ (get_byte_stream_for_file(path_for_client_public_key)) root_ca_private_key = asymmetric.load_private_key\ (get_byte_stream_for_file(ROOT_CA_PRIVATE_KEY_PATH), ROOT_CA_PRIVATE_KEY_PASSWORD) root_ca_public_key = asymmetric.load_public_key\ (get_byte_stream_for_file(ROOT_CA_PUBLIC_KEY)) root_ca_certificate = asymmetric.load_certificate\ (get_byte_stream_for_file(ROOT_CA_CERTIFICATE)) builder = CertificateBuilder( { u'country_name': client_details['country'], #.decode('utf-8'), u'state_or_province_name': client_details['state'], #.decode('utf-8'), u'locality_name': client_details['city'], #.decode('utf-8'), u'organization_name': client_details['name'], #.decode('utf-8'), u'common_name': get_dns_formatted_name( client_details['domain_name']), #.decode('utf-8'), }, client_public_key) dns_name = [] dns_name.append(u'opengns.com') builder.issuer = root_ca_certificate builder.subject_alt_domains = dns_name #builder.set_extension(u'authority_information_access', u'1.3.6.1.5.5.7.1.1') client_certificate = builder.build(root_ca_private_key) client_certificate_name = file_names.get_certificate_name( client_details['domain_name']) total_path = CERTIFICATE_OUTPUT_DIRECTORY + client_certificate_name with open(total_path, 'wb') as f: f.write(pem_armor_certificate(client_certificate)) return client_certificate_name
def generate_expired_cert(domain, base_year, quiet=False): if not quiet: write('Generating expired cert ... ', end='') full_domain = 'expired.{}'.format(domain) ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': full_domain, }, public_key) builder.issuer = ca_cert builder.subject_alt_domains = [full_domain] builder.begin_date = datetime(base_year - 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('expired', certificate) if not quiet: write('done')
def generate_ca2_cert(base_year, quiet=False): if not quiet: write('Generating ca2 cert ... ', end='') public_key = load_public('ca2') private_key = load_private('ca2') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Good TLS Limited', 'common_name': 'Good TLS Limited RSA CA', }, public_key ) builder.self_signed = True builder.ca = True builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 10, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(private_key) dump_cert('ca2', certificate) if not quiet: write('done')
def retrieve_cert(self, certificate_request): log.debug("Getting certificate status for id %s" % certificate_request.id) time.sleep(0.1) end_entity_public_key, end_entity_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) builder = CertificateBuilder( { 'common_name': certificate_request.common_name, }, end_entity_public_key) root_ca_certificate = asymmetric.load_certificate(ROOT_CA) root_ca_private_key = asymmetric.load_private_key(ROOT_CA_KEY) builder.issuer = root_ca_certificate end_entity_certificate = builder.build(root_ca_private_key) return (pem_armor_certificate(end_entity_certificate).decode())
def create_certificate(): root_ca_public_key, root_ca_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open('root_ca.key', 'wb') as f: f.write(asymmetric.dump_private_key(root_ca_private_key, u'p')) with open('root_ca_public.key', 'wb') as f: f.write(asymmetric.dump_public_key(root_ca_public_key, 'pem')) builder = CertificateBuilder( { u'country_name': u'US', u'state_or_province_name': u'Massachusetts', u'locality_name': u'Amherst', u'organization_name': u'Name Certifying service', u'common_name': u'NCS Root CA', }, root_ca_public_key) builder.self_signed = True builder.ca = True root_ca_certificate = builder.build(root_ca_private_key) with open('root_ca.crt', 'wb') as f: f.write(pem_armor_certificate(root_ca_certificate)) # Generate an end-entity key and certificate, signed by the root end_entity_public_key, end_entity_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open('ramteja_tadishetti_private.key', 'wb') as f: f.write(asymmetric.dump_private_key(end_entity_private_key, u'p')) with open('ramteja_tadishetti_public.key', 'wb') as f: f.write(asymmetric.dump_public_key(end_entity_public_key, 'pem')) builder = CertificateBuilder( { u'country_name': u'US', u'state_or_province_name': u'Massachusetts', u'locality_name': u'Amherst', u'organization_name': u'Ramteja Tadishetti Corp', u'common_name': u'ramtejatadishetti', }, end_entity_public_key) builder.issuer = root_ca_certificate #builder.set_extension( u'1.2.840.113549.1.1.1', 'ramteja', allow_deprecated=False) end_entity_certificate = builder.build(root_ca_private_key) with open('ramteja_tadishetti.crt', 'wb') as f: f.write(pem_armor_certificate(end_entity_certificate))
def test_tsa_certificate_extended_key_usage(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, public_key ) builder.self_signed = True builder.extended_key_usage = set(('time_stamping',)) certificate = builder.build(private_key) der_bytes = certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual(set(['key_usage', 'extended_key_usage']), new_certificate.critical_extensions)
def test_validity_general_times(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, public_key) builder.self_signed = True builder.begin_date = datetime(2050, 1, 1, tzinfo=timezone.utc) builder.end_date = datetime(2052, 1, 1, tzinfo=timezone.utc) certificate = builder.build(private_key) der_bytes = certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual( new_certificate['tbs_certificate']['validity']['not_before'].name, 'general_time') self.assertEqual( new_certificate['tbs_certificate']['validity']['not_after'].name, 'general_time')
def generate_expired_1963_cert(domain, quiet=False): if not quiet: write('Generating expired-1963 cert ... ', end='') full_domain = 'expired-1963.{}'.format(domain) ca_private_key = load_private('ca') ca_cert = load_cert('ca') public_key = load_public('host') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': full_domain, }, public_key ) builder.issuer = ca_cert builder.subject_alt_domains = [full_domain] builder.begin_date = datetime(1962, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(1963, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('expired-1963', certificate) if not quiet: write('done')
def generate_ca_cert(base_year, quiet=False): if not quiet: write('Generating ca cert ... ', end='') public_key = load_public('ca') private_key = load_private('ca') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Bad TLS Limited', 'common_name': 'Bad TLS Limited RSA CA', }, public_key ) builder.self_signed = True builder.ca = True builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 10, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(private_key) dump_cert('ca', certificate) if not quiet: write('done')
def generate_certificate(self, domain, save_model): """This function takes a domain name as a parameter and then creates a certificate and key with the domain name (replacing dots by underscores), finally signing the certificate using specified CA and returns the path of key and cert files. If you are yet to generate a CA then check the top comments""" logger.info("SimpleCA: certificate creation request %s" % (domain,)) ca_private_key = asymmetric.load_private_key( self.ca_key, password=settings.CA_KEY_PASSWD) ca_certificate = asymmetric.load_certificate(self.ca_crt) end_entity_public_key, end_entity_private_key = \ asymmetric.generate_pair('rsa', bit_size=2048) builder = CertificateBuilder( { 'country_name': 'CR', 'state_or_province_name': 'San Jose', 'locality_name': 'Costa Rica', 'organization_name': save_model.name, "organizational_unit_name": save_model.institution_unit, 'common_name': domain, }, end_entity_public_key ) now = timezone.now() builder.issuer = ca_certificate builder.begin_date = now builder.end_date = now+timedelta(settings.CA_CERT_DURATION) builder.key_usage = set(['digital_signature']) end_entity_certificate = builder.build(ca_private_key) # settings.CA_CERT_DURATION server_public_key, server_private_key = \ asymmetric.generate_pair('rsa', bit_size=2048) save_model.private_key = asymmetric.dump_private_key( end_entity_private_key, None) save_model.public_key = asymmetric.dump_public_key( end_entity_public_key) save_model.public_certificate = pem_armor_certificate( end_entity_certificate) save_model.server_sign_key = asymmetric.dump_private_key( server_private_key, None) save_model.server_public_key = asymmetric.dump_public_key( server_public_key) logger.debug("SimpleCA: New certificate for %s is %r" % (domain, save_model.public_certificate)) return save_model
def issue_cert(self, csr: CsrBuilder) -> (PrivateKey, Cert): public_key, private_key = asymmetric.generate_pair('rsa', bit_size=4096) builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, public_key) builder.self_signed = True cert = builder.build(private_key) serial = SerialNumber.from_int(cert.serial_number).as_hex() keypath = self._cert_dir / (serial + '.key') with keypath.open('wb') as f: f.write(asymmetric.dump_private_key(private_key, 'password')) certpath = self._cert_dir / (serial + '.pem') with certpath.open('wb') as f: f.write(pem_armor_certificate(cert))
def test_validity_general_times(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, public_key ) builder.self_signed = True builder.begin_date = datetime(2050, 1, 1, tzinfo=timezone.utc) builder.end_date = datetime(2052, 1, 1, tzinfo=timezone.utc) certificate = builder.build(private_key) der_bytes = certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual(new_certificate['tbs_certificate']['validity']['not_before'].name, 'general_time') self.assertEqual(new_certificate['tbs_certificate']['validity']['not_after'].name, 'general_time')
def create_certificate(): root_ca_public_key, root_ca_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open('root_ca.key', 'wb') as f: f.write(asymmetric.dump_private_key(root_ca_private_key, u'p')) with open('root_ca_public.key', 'wb') as f: f.write(asymmetric.dump_public_key(root_ca_public_key, 'pem')) builder = CertificateBuilder( { u'country_name': u'US', u'state_or_province_name': u'Massachusetts', u'locality_name': u'Amherst', u'organization_name': u'Name Certifying service', u'common_name': u'NCS Root CA', }, root_ca_public_key) builder.self_signed = True builder.ca = True root_ca_certificate = builder.build(root_ca_private_key) with open('root_ca.crt', 'wb') as f: f.write(pem_armor_certificate(root_ca_certificate))
def test_subject_alt_name_shortcuts(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( {'country_name': 'US', 'common_name': 'Test'}, public_key ) builder.self_signed = True self.assertEqual(builder.subject_alt_domains, []) builder.subject_alt_domains = ['example.com', 'example.org'] builder.subject_alt_emails = ['*****@*****.**', '*****@*****.**'] builder.subject_alt_ips = ['127.0.0.1'] builder.subject_alt_uris = ['http://example.com', 'https://bücher.ch'] self.assertEqual(builder.subject_alt_domains, ['example.com', 'example.org']) self.assertEqual(builder.subject_alt_emails, ['*****@*****.**', '*****@*****.**']) self.assertEqual(builder.subject_alt_ips, ['127.0.0.1']) self.assertEqual(builder.subject_alt_uris, ['http://example.com', 'https://bücher.ch']) builder.subject_alt_domains = [] self.assertEqual(builder.subject_alt_domains, []) builder.subject_alt_emails = [] self.assertEqual(builder.subject_alt_emails, []) builder.subject_alt_ips = [] self.assertEqual(builder.subject_alt_ips, []) builder.subject_alt_uris = [] self.assertEqual(builder.subject_alt_uris, []) builder.subject_alt_uris = ['https://bücher.ch'] certificate = builder.build(private_key) self.assertEqual(b'\x86\x18https://xn--bcher-kva.ch', certificate.subject_alt_name_value[0].contents)
def test_build_chain_of_certs(self): ca_public_key, ca_private_key = self.ec_secp521r1 ee_public_key, _ = self.ec_secp256r1 ca_builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Codex Non Sufficit LC - Primary CA', }, ca_public_key ) ca_builder.hash_algo = 'sha512' ca_builder.self_signed = True ca_builder.ca = True ca_certificate = ca_builder.build(ca_private_key) ee_builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, ee_public_key ) ee_builder.issuer = ca_certificate ee_builder.serial_number = 1 ee_certificate = ee_builder.build(ca_private_key) der_bytes = ee_certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual('sha256', new_certificate.hash_algo) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Codex Non Sufficit LC - Primary CA', }, new_certificate.issuer.native ) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, new_certificate.subject.native ) self.assertEqual('ecdsa', new_certificate.signature_algo) self.assertEqual(set(['key_usage']), new_certificate.critical_extensions) self.assertEqual(set(['digital_signature', 'key_encipherment']), new_certificate.key_usage_value.native) self.assertEqual(['server_auth', 'client_auth'], new_certificate.extended_key_usage_value.native) self.assertEqual(ca_certificate.key_identifier, new_certificate.authority_key_identifier) self.assertEqual(False, new_certificate.ca) self.assertEqual(False, new_certificate.self_issued) self.assertEqual('no', new_certificate.self_signed)
def _sign(csr, buf, skip_notify=False, skip_push=False, overwrite=False, profile="default", signer=None): # TODO: CRLDistributionPoints, OCSP URL, Certificate URL if profile not in config.PROFILES: raise ValueError("Invalid profile supplied '%s'" % profile) assert buf.startswith(b"-----BEGIN ") assert isinstance(csr, CertificationRequest) csr_pubkey = asymmetric.load_public_key( csr["certification_request_info"]["subject_pk_info"]) common_name = csr["certification_request_info"]["subject"].native[ "common_name"] cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name) renew = False attachments = [ (buf, "application/x-pem-file", common_name + ".csr"), ] revoked_path = None overwritten = False # Move existing certificate if necessary if os.path.exists(cert_path): with open(cert_path, "rb") as fh: prev_buf = fh.read() header, _, der_bytes = pem.unarmor(prev_buf) prev = x509.Certificate.load(der_bytes) # TODO: assert validity here again? renew = \ asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \ csr_pubkey # BUGBUG: is this enough? if overwrite: # TODO: is this the best approach? prev_serial_hex = "%x" % prev.serial_number revoked_path = os.path.join(config.REVOKED_DIR, "%s.pem" % prev_serial_hex) os.rename(cert_path, revoked_path) attachments += [(prev_buf, "application/x-pem-file", "deprecated.crt" if renew else "overwritten.crt")] overwritten = True else: raise FileExistsError("Will not overwrite existing certificate") # Sign via signer process dn = {u'common_name': common_name} profile_server_flags, lifetime, dn[ "organizational_unit_name"], _ = config.PROFILES[profile] lifetime = int(lifetime) builder = CertificateBuilder(dn, csr_pubkey) builder.serial_number = random.randint( 0x1000000000000000000000000000000000000000, 0x7fffffffffffffffffffffffffffffffffffffff) now = datetime.utcnow() builder.begin_date = now - timedelta(minutes=5) builder.end_date = now + timedelta(days=lifetime) builder.issuer = certificate builder.ca = False builder.key_usage = set(["digital_signature", "key_encipherment"]) # If we have FQDN and profile suggests server flags, enable them if server_flags(common_name) and profile_server_flags: builder.subject_alt_domains = [ common_name ] # OpenVPN uses CN while StrongSwan uses SAN to match hostname of the server builder.extended_key_usage = set( ["server_auth", "1.3.6.1.5.5.8.2.2", "client_auth"]) else: builder.subject_alt_domains = [common_name ] # iOS demands SAN also for clients builder.extended_key_usage = set(["client_auth"]) end_entity_cert = builder.build(private_key) end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert) with open(cert_path + ".part", "wb") as fh: fh.write(end_entity_cert_buf) os.rename(cert_path + ".part", cert_path) attachments.append( (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt")) cert_serial_hex = "%x" % end_entity_cert.serial_number # Create symlink link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR, "%x.pem" % end_entity_cert.serial_number) assert not os.path.exists( link_name ), "Certificate with same serial number already exists: %s" % link_name os.symlink("../%s.pem" % common_name, link_name) # Copy filesystem attributes to newly signed certificate if revoked_path: for key in listxattr(revoked_path): if not key.startswith(b"user."): continue setxattr(cert_path, key, getxattr(revoked_path, key)) # Attach signer username if signer: setxattr(cert_path, "user.signature.username", signer) if not skip_notify: # Send mail if renew: # Same keypair mailer.send("certificate-renewed.md", **locals()) else: # New keypair mailer.send("certificate-signed.md", **locals()) if not skip_push: url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest() click.echo("Publishing certificate at %s ..." % url) requests.post(url, data=end_entity_cert_buf, headers={ "User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert" }) push.publish("request-signed", common_name) return end_entity_cert, end_entity_cert_buf
def _sign(csr, buf, profile, skip_notify=False, skip_push=False, overwrite=False, signer=None): # TODO: CRLDistributionPoints, OCSP URL, Certificate URL assert buf.startswith(b"-----BEGIN ") assert isinstance(csr, CertificationRequest) csr_pubkey = asymmetric.load_public_key( csr["certification_request_info"]["subject_pk_info"]) common_name = csr["certification_request_info"]["subject"].native[ "common_name"] cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name) renew = False attachments = [ (buf, "application/x-pem-file", common_name + ".csr"), ] revoked_path = None overwritten = False # Move existing certificate if necessary if os.path.exists(cert_path): with open(cert_path, "rb") as fh: prev_buf = fh.read() header, _, der_bytes = pem.unarmor(prev_buf) prev = x509.Certificate.load(der_bytes) # TODO: assert validity here again? renew = \ asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \ csr_pubkey # BUGBUG: is this enough? if overwrite: # TODO: is this the best approach? # TODO: why didn't unittest detect bugs here? prev_serial_hex = "%x" % prev.serial_number revoked_path = os.path.join(config.REVOKED_DIR, "%040x.pem" % prev.serial_number) os.rename(cert_path, revoked_path) attachments += [(prev_buf, "application/x-pem-file", "deprecated.crt" if renew else "overwritten.crt")] overwritten = True else: raise FileExistsError("Will not overwrite existing certificate") builder = CertificateBuilder( cn_to_dn(common_name, const.FQDN, o=certificate["tbs_certificate"]["subject"].native.get( "organization_name"), ou=profile.ou), csr_pubkey) builder.serial_number = generate_serial() now = datetime.utcnow() builder.begin_date = now - const.CLOCK_SKEW_TOLERANCE builder.end_date = now + timedelta(days=profile.lifetime) builder.issuer = certificate builder.ca = profile.ca builder.key_usage = profile.key_usage builder.extended_key_usage = profile.extended_key_usage builder.subject_alt_domains = [common_name] builder.ocsp_url = profile.responder_url builder.crl_url = profile.revoked_url end_entity_cert = builder.build(private_key) end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert) with open(cert_path + ".part", "wb") as fh: fh.write(end_entity_cert_buf) os.rename(cert_path + ".part", cert_path) attachments.append( (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt")) cert_serial_hex = "%x" % end_entity_cert.serial_number # Create symlink link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR, "%040x.pem" % end_entity_cert.serial_number) assert not os.path.exists( link_name ), "Certificate with same serial number already exists: %s" % link_name os.symlink("../%s.pem" % common_name, link_name) # Copy filesystem attributes to newly signed certificate if revoked_path: for key in listxattr(revoked_path): if not key.startswith(b"user."): continue setxattr(cert_path, key, getxattr(revoked_path, key)) # Attach signer username if signer: setxattr(cert_path, "user.signature.username", signer) if not skip_notify: # Send mail if renew: # Same keypair mailer.send("certificate-renewed.md", **locals()) else: # New keypair mailer.send("certificate-signed.md", **locals()) if not skip_push: url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest() click.echo("Publishing certificate at %s ..." % url) requests.post(url, data=end_entity_cert_buf, headers={ "User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert" }) if renew: # TODO: certificate-renewed event push.publish("certificate-revoked", common_name) push.publish("request-signed", common_name) else: push.publish("request-signed", common_name) return end_entity_cert, end_entity_cert_buf
def test_build_chain_of_certs(self): ca_public_key, ca_private_key = self.ec_secp521r1 ee_public_key, _ = self.ec_secp256r1 ca_builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Codex Non Sufficit LC - Primary CA', }, ca_public_key) ca_builder.hash_algo = 'sha512' ca_builder.self_signed = True ca_builder.ca = True ca_certificate = ca_builder.build(ca_private_key) ee_builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, ee_public_key) ee_builder.issuer = ca_certificate ee_builder.serial_number = 1 ee_certificate = ee_builder.build(ca_private_key) der_bytes = ee_certificate.dump() new_certificate = asn1crypto.x509.Certificate.load(der_bytes) self.assertEqual('sha256', new_certificate.hash_algo) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Codex Non Sufficit LC - Primary CA', }, new_certificate.issuer.native) self.assertEqual( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'Will Bond', }, new_certificate.subject.native) self.assertEqual('ecdsa', new_certificate.signature_algo) self.assertEqual(set(['key_usage']), new_certificate.critical_extensions) self.assertEqual(set(['digital_signature', 'key_encipherment']), new_certificate.key_usage_value.native) self.assertEqual(['server_auth', 'client_auth'], new_certificate.extended_key_usage_value.native) self.assertEqual(ca_certificate.key_identifier, new_certificate.authority_key_identifier) self.assertEqual(False, new_certificate.ca) self.assertEqual(False, new_certificate.self_issued) self.assertEqual('no', new_certificate.self_signed)
def generate_client_certs(domain, base_year, quiet=False): ca_private_key = load_private('ca') ca_cert = load_cert('ca') ca2_private_key = load_private('ca2') ca2_cert = load_cert('ca2') public_key = load_public('client') crl_url = 'http://crls.{}:9991/client.crl'.format(domain) # Certificate that is valid if not quiet: write('Generating good client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Good TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-good', certificate) if not quiet: write('done') # Certificate that has expired if not quiet: write('Generating expired client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Expired TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year - 1, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-expired', certificate) if not quiet: write('done') # Certificate that is not yet valid if not quiet: write('Generating future client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Future TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 4, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-future', certificate) if not quiet: write('done') # Certificate issued by untrusted CA if not quiet: write('Generating untrusted client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Untrusted TLS Client Certificate', }, public_key) builder.issuer = ca2_cert builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca2_private_key) dump_cert('client-untrusted', certificate) if not quiet: write('done') # Certificate that has a weak signature if not quiet: write('Generating weak client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Weak TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url # Hack since API doesn't allow selection of weak algo builder._hash_algo = 'md5' builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) certificate = builder.build(ca_private_key) dump_cert('client-weak', certificate) if not quiet: write('done') # Certificate that has bad key usage if not quiet: write('Generating bad key usage client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Bad Key Usage TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.key_usage = set(['crl_sign']) builder.extended_key_usage = set(['email_protection']) certificate = builder.build(ca_private_key) dump_cert('client-bad-key-usage', certificate) if not quiet: write('done') # Certificate that has been revoked if not quiet: write('Generating revoked client cert ... ', end='') builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'TLS Client Certificates Limited', 'common_name': 'Revoked TLS Client Certificate', }, public_key) builder.issuer = ca_cert builder.crl_url = crl_url builder.begin_date = datetime(base_year, 1, 1, 0, 0, 0, tzinfo=timezone.utc) builder.end_date = datetime(base_year + 3, 1, 1, 0, 0, 0, tzinfo=timezone.utc) revoked_certificate = builder.build(ca_private_key) dump_cert('client-revoked', revoked_certificate) if not quiet: write('done') crl_number = 1000 crl_builder = CertificateListBuilder(crl_url, ca_cert, crl_number) crl_builder.add_certificate( revoked_certificate.serial_number, datetime(base_year, 1, 2, 0, 0, 0, tzinfo=timezone.utc), 'key_compromise') certificate_list = crl_builder.build(ca_private_key) dump_crl('client', certificate_list)
import json import sys f = open("orqIp.txt", "r") orq_ip = f.read() f.close() keyId = sys.argv[1] r = requests.get("http://" + orq_ip + ":5000/getKey/" + keyId) response = dict(json.loads(r.text)) pub_key = response["pubKey"] asn1PublicKey = core.Asn1Value.load(unhexlify(pub_key)) publicKey = keys.PublicKeyInfo.wrap(asn1PublicKey, u'rsa') builder = CertificateBuilder( { u'country_name': u'SP', u'state_or_province_name': u'Malaga', u'locality_name': u'Malaga', u'organization_name': u'NICS Lab', u'common_name': u'Certificacion Raiz' }, publicKey) builder.self_signed = True builder.ca = True root_ca_certificate = builder.build_mpc(int(keyId), orq_ip, "5000") with open('certificado_raiz.crt', 'wb') as f: f.write(pem_armor_certificate(root_ca_certificate))
fixtures_dir = os.path.join(os.path.dirname(__file__), '..', 'tests', 'fixtures') root_ca_private_key = asymmetric.load_private_key(os.path.join(fixtures_dir, 'test.key')) root_ca_certificate = asymmetric.load_certificate(os.path.join(fixtures_dir, 'test.crt')) root_ocsp_public_key, root_ocsp_private_key = asymmetric.generate_pair('rsa', bit_size=2048) with open(os.path.join(fixtures_dir, 'test-ocsp.key'), 'wb') as f: f.write(asymmetric.dump_private_key(root_ocsp_private_key, 'password', target_ms=20)) builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'organization_unit_name': 'Testing', 'common_name': 'CodexNS OCSP Responder', }, root_ocsp_public_key ) builder.extended_key_usage = set(['ocsp_signing']) builder.issuer = root_ca_certificate root_ocsp_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, 'test-ocsp.crt'), 'wb') as f: f.write(asymmetric.dump_certificate(root_ocsp_certificate))
def test_subject_alt_name_shortcuts(self): public_key, private_key = self.ec_secp256r1 builder = CertificateBuilder( { 'country_name': 'US', 'common_name': 'Test' }, public_key) builder.self_signed = True self.assertEqual(builder.subject_alt_domains, []) builder.subject_alt_domains = ['example.com', 'example.org'] builder.subject_alt_emails = ['*****@*****.**', '*****@*****.**'] builder.subject_alt_ips = ['127.0.0.1'] builder.subject_alt_uris = ['http://example.com', 'https://bücher.ch'] self.assertEqual(builder.subject_alt_domains, ['example.com', 'example.org']) self.assertEqual(builder.subject_alt_emails, ['*****@*****.**', '*****@*****.**']) self.assertEqual(builder.subject_alt_ips, ['127.0.0.1']) self.assertEqual(builder.subject_alt_uris, ['http://example.com', 'https://bücher.ch']) builder.subject_alt_domains = [] self.assertEqual(builder.subject_alt_domains, []) builder.subject_alt_emails = [] self.assertEqual(builder.subject_alt_emails, []) builder.subject_alt_ips = [] self.assertEqual(builder.subject_alt_ips, []) builder.subject_alt_uris = [] self.assertEqual(builder.subject_alt_uris, []) builder.subject_alt_uris = ['https://bücher.ch'] certificate = builder.build(private_key) self.assertEqual(b'\x86\x18https://xn--bcher-kva.ch', certificate.subject_alt_name_value[0].contents)
from oscrypto import asymmetric from certbuilder import CertificateBuilder fixtures_dir = os.path.join(os.path.dirname(__file__), "..", "tests", "fixtures") root_ca_public_key, root_ca_private_key = asymmetric.generate_pair("rsa", bit_size=2048) with open(os.path.join(fixtures_dir, "root.key"), "wb") as f: f.write(asymmetric.dump_private_key(root_ca_private_key, "password123", target_ms=20)) builder = CertificateBuilder( { "country_name": "US", "state_or_province_name": "Massachusetts", "locality_name": "Newbury", "organization_name": "Codex Non Sufficit LC", "common_name": "CodexNS Root CA 1", }, root_ca_public_key, ) builder.self_signed = True builder.end_entity = False root_ca_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, "root.crt"), "wb") as f: f.write(asymmetric.dump_certificate(root_ca_certificate)) root_crl_public_key, root_crl_private_key = asymmetric.generate_pair("rsa", bit_size=2048) with open(os.path.join(fixtures_dir, "crl_issuer.key"), "wb") as f:
fixtures_dir = os.path.join(os.path.dirname(__file__), '..', 'tests', 'fixtures') root_ca_public_key, root_ca_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open(os.path.join(fixtures_dir, 'root.key'), 'wb') as f: f.write( asymmetric.dump_private_key(root_ca_private_key, 'password123', target_ms=20)) builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'common_name': 'CodexNS Root CA 1', }, root_ca_public_key) builder.self_signed = True builder.end_entity = False root_ca_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, 'root.crt'), 'wb') as f: f.write(asymmetric.dump_certificate(root_ca_certificate)) root_crl_public_key, root_crl_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open(os.path.join(fixtures_dir, 'crl_issuer.key'), 'wb') as f: f.write(
root_ca_private_key = asymmetric.load_private_key( os.path.join(fixtures_dir, 'test.key')) root_ca_certificate = asymmetric.load_certificate( os.path.join(fixtures_dir, 'test.crt')) root_ocsp_public_key, root_ocsp_private_key = asymmetric.generate_pair( 'rsa', bit_size=2048) with open(os.path.join(fixtures_dir, 'test-ocsp.key'), 'wb') as f: f.write( asymmetric.dump_private_key(root_ocsp_private_key, 'password', target_ms=20)) builder = CertificateBuilder( { 'country_name': 'US', 'state_or_province_name': 'Massachusetts', 'locality_name': 'Newbury', 'organization_name': 'Codex Non Sufficit LC', 'organization_unit_name': 'Testing', 'common_name': 'CodexNS OCSP Responder', }, root_ocsp_public_key) builder.extended_key_usage = set(['ocsp_signing']) builder.issuer = root_ca_certificate root_ocsp_certificate = builder.build(root_ca_private_key) with open(os.path.join(fixtures_dir, 'test-ocsp.crt'), 'wb') as f: f.write(asymmetric.dump_certificate(root_ocsp_certificate))
def _sign(csr, buf, overwrite=False): # TODO: CRLDistributionPoints, OCSP URL, Certificate URL assert buf.startswith("-----BEGIN CERTIFICATE REQUEST-----\n") assert isinstance(csr, CertificationRequest) csr_pubkey = asymmetric.load_public_key( csr["certification_request_info"]["subject_pk_info"]) common_name = csr["certification_request_info"]["subject"].native[ "common_name"] cert_path = os.path.join(config.SIGNED_DIR, "%s.pem" % common_name) renew = False attachments = [ (buf, "application/x-pem-file", common_name + ".csr"), ] revoked_path = None overwritten = False # Move existing certificate if necessary if os.path.exists(cert_path): with open(cert_path) as fh: prev_buf = fh.read() header, _, der_bytes = pem.unarmor(prev_buf) prev = x509.Certificate.load(der_bytes) # TODO: assert validity here again? renew = \ asymmetric.load_public_key(prev["tbs_certificate"]["subject_public_key_info"]) == \ csr_pubkey # BUGBUG: is this enough? if overwrite: # TODO: is this the best approach? prev_serial_hex = "%x" % prev.serial_number revoked_path = os.path.join(config.REVOKED_DIR, "%s.pem" % prev_serial_hex) os.rename(cert_path, revoked_path) attachments += [(prev_buf, "application/x-pem-file", "deprecated.crt" if renew else "overwritten.crt")] overwritten = True else: raise EnvironmentError("Will not overwrite existing certificate") # Sign via signer process builder = CertificateBuilder({u'common_name': common_name}, csr_pubkey) builder.serial_number = random.randint( 0x1000000000000000000000000000000000000000, 0xffffffffffffffffffffffffffffffffffffffff) now = datetime.utcnow() builder.begin_date = now - timedelta(minutes=5) builder.end_date = now + timedelta( days=config.SERVER_CERTIFICATE_LIFETIME if server_flags(common_name) else config.CLIENT_CERTIFICATE_LIFETIME) builder.issuer = certificate builder.ca = False builder.key_usage = set([u"digital_signature", u"key_encipherment"]) # OpenVPN uses CN while StrongSwan uses SAN if server_flags(common_name): builder.subject_alt_domains = [common_name] builder.extended_key_usage = set( [u"server_auth", u"1.3.6.1.5.5.8.2.2", u"client_auth"]) else: builder.extended_key_usage = set([u"client_auth"]) end_entity_cert = builder.build(private_key) end_entity_cert_buf = asymmetric.dump_certificate(end_entity_cert) with open(cert_path + ".part", "wb") as fh: fh.write(end_entity_cert_buf) os.rename(cert_path + ".part", cert_path) attachments.append( (end_entity_cert_buf, "application/x-pem-file", common_name + ".crt")) cert_serial_hex = "%x" % end_entity_cert.serial_number # Create symlink link_name = os.path.join(config.SIGNED_BY_SERIAL_DIR, "%x.pem" % end_entity_cert.serial_number) assert not os.path.exists( link_name ), "Certificate with same serial number already exists: %s" % link_name os.symlink("../%s.pem" % common_name, link_name) # Copy filesystem attributes to newly signed certificate if revoked_path: for key in listxattr(revoked_path): if not key.startswith("user."): continue setxattr(cert_path, key, getxattr(revoked_path, key)) # Send mail if renew: # Same keypair mailer.send("certificate-renewed.md", **locals()) else: # New keypair mailer.send("certificate-signed.md", **locals()) url = config.LONG_POLL_PUBLISH % hashlib.sha256(buf).hexdigest() click.echo("Publishing certificate at %s ..." % url) requests.post(url, data=end_entity_cert_buf, headers={ "User-Agent": "Certidude API", "Content-Type": "application/x-x509-user-cert" }) push.publish("request-signed", common_name) return end_entity_cert, end_entity_cert_buf