def test_invalid(self, subtests): for value in [ "C=US,CN=Joe , Smith,DC=example", ",C=US,CN=Joe , Smith,DC=example", "C=US,UNKNOWN=Joe , Smith,DC=example", "C=US,CN,DC=example", "C=US,FOOBAR=example", ]: with subtests.test(): with pytest.raises(ValueError): Name.from_rfc4514_string(value)
def generate_keys(): folder = os.path.dirname(__file__) key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend(), ) with open(os.path.join(folder, 'localhost.key'), "wb") as f: f.write( key.private_bytes( encoding=Encoding.PEM, format=PrivateFormat.TraditionalOpenSSL, encryption_algorithm=NoEncryption(), )) subject = issuer = Name([ NameAttribute(NameOID.COUNTRY_NAME, "IE"), NameAttribute(NameOID.ORGANIZATION_NAME, "Scrapy"), NameAttribute(NameOID.COMMON_NAME, "localhost"), ]) cert = (CertificateBuilder().subject_name(subject).issuer_name( issuer).public_key(key.public_key()).serial_number( random_serial_number()).not_valid_before( datetime.utcnow()).not_valid_after( datetime.utcnow() + timedelta(days=10)).add_extension( SubjectAlternativeName([DNSName("localhost")]), critical=False, ).sign(key, SHA256(), default_backend())) with open(os.path.join(folder, 'localhost.crt'), "wb") as f: f.write(cert.public_bytes(Encoding.PEM))
def selfsigned(key, common_name, san): subject = issuer = Name([ NameAttribute(NameOID.COMMON_NAME, common_name), NameAttribute(NameOID.ORGANIZATION_NAME, "Sanic Org"), ]) cert = (CertificateBuilder().subject_name(subject).issuer_name( issuer).public_key(key.public_key()).serial_number( random_serial_number()).not_valid_before( datetime.utcnow()).not_valid_after( datetime.utcnow() + timedelta(days=365.25 * 8)).add_extension( KeyUsage(True, False, False, False, False, False, False, False, False), critical=True, ).add_extension( ExtendedKeyUsage([ ExtendedKeyUsageOID.SERVER_AUTH, ExtendedKeyUsageOID.CLIENT_AUTH, ]), critical=False, ).add_extension( BasicConstraints(ca=True, path_length=None), critical=True, ).add_extension( SubjectAlternativeName([ IPAddress(ip_address(n)) if n[0].isdigit() or ":" in n else DNSName(n) for n in san ]), critical=False, ).sign(key, hashes.SHA256())) return cert
def _make_subject_name(cn: str) -> Name: return Name([ NameAttribute( NameOID.COMMON_NAME, cn, ), ])
def _validate_issuer(self): expected_issuer = Name([ NameAttribute(oid=cryptography_name_to_oid(iss[0]), value=to_text(iss[1])) for iss in self.issuer ]) cert_issuer = self.existing_certificate.issuer if not compare_sets(expected_issuer, cert_issuer, self.issuer_strict): return self.issuer, cert_issuer
def _validate_subject(self): expected_subject = Name([ NameAttribute(oid=cryptography_name_to_oid(sub[0]), value=to_text(sub[1])) for sub in self.subject ]) cert_subject = self.existing_certificate.subject if not compare_sets(expected_subject, cert_subject, self.subject_strict): return expected_subject, cert_subject
def x509_name_to_json(name: x509.Name) -> Dict[str, Any]: attributes = [] for attr in name: attributes.append( _X509NameAttributeAsJson(oid=attr.oid, value=attr.value, rfc4514_string=attr.rfc4514_string()) ) x509name_as_json = _X509NameAsJson(rfc4514_string=name.rfc4514_string(), attributes=attributes) return asdict(x509name_as_json)
def _get_name_as_short_text(name_field: x509.Name) -> str: """Convert a name field returned by the cryptography module to a string suitable for displaying it to the user.""" # Name_field is supposed to be a Subject or an Issuer; print the CN if there is one common_names = get_common_names(name_field) if common_names: # We don't support certs with multiple CNs return common_names[0] else: # Otherwise show the whole field return name_field.rfc4514_string()
def cert(issuer, subject, pubkey, privkey, ca): builder = CertificateBuilder().issuer_name( Name([NameAttribute(NameOID.COMMON_NAME, issuer)]), ).subject_name( Name([NameAttribute(NameOID.COMMON_NAME, subject)]), ).add_extension( SubjectAlternativeName([DNSName(subject)]), critical=False, ) if ca: builder = builder.add_extension( BasicConstraints(True, None), critical=True, ) return builder.public_key( pubkey, ).serial_number(random_serial_number(), ).not_valid_before( datetime.utcnow(), ).not_valid_after( datetime.utcnow() + timedelta(seconds=1), ).sign( privkey, SHA256(), default_backend(), )
def generate_tls_keys(): """ Creates a TLS private key (RSA, 4096 bits, PEM format) and certificate signing request (CSR). """ # Query the user for CSR attributes country = input("Country: ") state = input("State or province: ") locality = input("Locality: ") organization = input("Organization: ") organizational_unit = input("Organizational unit: ") email = input("Email: ") common_name = input("Common name: ") print("Enter any subject alternative names (SANs) you wish to attach to the certificate. Leave blank to continue.") sans = [] while True: san = input("Subject alternative name: ") if san == '': break sans.append(DNSName(san)) # Make sure we can open the output files first private_key_file = open("private.key", "wb") csr_file = open("certificate_signing_request", "wb") # Generate the private key key = generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) attributes = [ NameAttribute(NameOID.COUNTRY_NAME, country), NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, state), NameAttribute(NameOID.LOCALITY_NAME, locality), NameAttribute(NameOID.ORGANIZATION_NAME, organization), NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, organizational_unit), NameAttribute(NameOID.EMAIL_ADDRESS, email), NameAttribute(NameOID.COMMON_NAME, common_name), ] # Generate the CSR and sign it with the private key csr = CertificateSigningRequestBuilder().subject_name(Name(attributes)) if sans: csr = csr.add_extension(SubjectAlternativeName(sans), critical=False) csr = csr.sign(key, SHA256(), default_backend()) # Write the private key and CSR to disk private_key_file.write(key.private_bytes(encoding=Encoding.PEM, format=PrivateFormat.TraditionalOpenSSL, encryption_algorithm=NoEncryption())) csr_file.write(csr.public_bytes(Encoding.PEM)) private_key_file.close() csr_file.close() # Success! print("Successfully generated a private key and certificate signing request.")
def parse_certificate_object_identifier_name(certificate: x509.Name, oid: x509.ObjectIdentifier) -> Optional[List[str]]: """ Get attribute from decoded certificate. Args: certificate: Certificate as x509.Certificate . oid: Enum value from x509.NameOID . Returns: list: Decoded values. """ attributes = [attr.value for attr in certificate.get_attributes_for_oid(oid)] return attributes if attributes else None
def server_cert(server_key, backend): """Generate server certificate.""" subject = issuer = Name([ NameAttribute(NameOID.COMMON_NAME, six.u('localhost')), NameAttribute(NameOID.ORGANIZATION_NAME, six.u('Bob B. Server')) ]) return CertificateBuilder().subject_name(subject).issuer_name( issuer).serial_number(random_serial_number()).public_key( server_key.public_key()).not_valid_before(datetime( 2008, 1, 1)).not_valid_after(datetime(3020, 1, 1)).add_extension( SubjectAlternativeName([DNSName(six.u('localhost'))]), critical=False).sign(server_key, SHA256(), backend)
def client_cert(client_key, backend): """Generate client certificate.""" subject = issuer = Name([ NameAttribute(NameOID.COMMON_NAME, six.u('example.org')), NameAttribute(NameOID.ORGANIZATION_NAME, six.u('Alice A. Client')) ]) return CertificateBuilder().subject_name(subject).issuer_name( issuer).serial_number(random_serial_number()).public_key( client_key.public_key()).not_valid_before(datetime( 3019, 1, 1)).not_valid_after(datetime(3019, 1, 10)).add_extension( SubjectAlternativeName([DNSName(six.u('localhost'))]), critical=False).sign(client_key, SHA256(), backend)
def _generate_crl(self): backend = default_backend() crl = CertificateRevocationListBuilder() try: crl = crl.issuer_name( Name([ NameAttribute(cryptography_name_to_oid(entry[0]), to_text(entry[1])) for entry in self.issuer ])) except ValueError as e: raise CRLError(e) crl = crl.last_update(self.last_update) crl = crl.next_update(self.next_update) if self.update and self.crl: new_entries = set([ self._compress_entry(entry) for entry in self.revoked_certificates ]) for entry in self.crl: decoded_entry = self._compress_entry( cryptography_decode_revoked_certificate(entry)) if decoded_entry not in new_entries: crl = crl.add_revoked_certificate(entry) for entry in self.revoked_certificates: revoked_cert = RevokedCertificateBuilder() revoked_cert = revoked_cert.serial_number(entry['serial_number']) revoked_cert = revoked_cert.revocation_date( entry['revocation_date']) if entry['issuer'] is not None: revoked_cert = revoked_cert.add_extension( x509.CertificateIssuer([ cryptography_get_name(name, 'issuer') for name in entry['issuer'] ]), entry['issuer_critical']) if entry['reason'] is not None: revoked_cert = revoked_cert.add_extension( x509.CRLReason(entry['reason']), entry['reason_critical']) if entry['invalidity_date'] is not None: revoked_cert = revoked_cert.add_extension( x509.InvalidityDate(entry['invalidity_date']), entry['invalidity_date_critical']) crl = crl.add_revoked_certificate(revoked_cert.build(backend)) self.crl = crl.sign(self.privatekey, self.digest, backend=backend) if self.format == 'pem': return self.crl.public_bytes(Encoding.PEM) else: return self.crl.public_bytes(Encoding.DER)
def _generate_certs(path: Union[Path, str], days: int = 3652, key_size: int = 2048, separate_key: bool = False) -> None: # DO NOT USE THIS FOR ANYTHING PRODUCTION RELATED, EVER! # Generate private key # 2048 is the minimum that works as of 3.9 key = rsa.generate_private_key(public_exponent=65537, key_size=key_size) key_file = "key.pem" if separate_key else "cert.pem" key_path = Path(path).joinpath(key_file) with open(key_path, "ab") as f: f.write(key.private_bytes( encoding=serialization.Encoding.PEM, encryption_algorithm=serialization.NoEncryption(), format=serialization.PrivateFormat.TraditionalOpenSSL )) log.debug("Private key generated") # Generate public certificate hostname = socket.gethostname() ip = socket.gethostbyname(hostname) subject = Name([NameAttribute(NameOID.COMMON_NAME, "smtpdfix_cert")]) alt_names = [ DNSName("localhost"), DNSName("localhost.localdomain"), DNSName(hostname), IPAddress(ip_address("127.0.0.1")), IPAddress(ip_address("0.0.0.1")), IPAddress(ip_address("::1")), IPAddress(ip_address(ip)), ] # Set it so the certificate can be a root certificate with # ca=true, path_length=0 means it can only sign itself. constraints = BasicConstraints(ca=True, path_length=0) cert = (CertificateBuilder() .issuer_name(subject) .subject_name(subject) .serial_number(random_serial_number()) .not_valid_before(datetime.utcnow()) .not_valid_after(datetime.utcnow() + timedelta(days=days)) .add_extension(SubjectAlternativeName(alt_names), critical=False) .public_key(key.public_key()) .add_extension(constraints, critical=False) .sign(private_key=key, algorithm=hashes.SHA256())) cert_path = Path(path).joinpath("cert.pem") with open(cert_path, "ab") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) log.debug("Certificate generated")
def generate(identifier, path): debug("Generating private key") key = generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) with open(join(path, Certificate.PRIVATE_KEY_FILE), "wb+") as pem: pem.write(key.private_bytes(Encoding.PEM, PrivateFormat.TraditionalOpenSSL, NoEncryption())) name = Name([ NameAttribute(NameOID.COMMON_NAME, identifier), NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "KDE Connect"), NameAttribute(NameOID.ORGANIZATION_NAME, "KDE"), ]) before = datetime.utcnow() - timedelta(days=365) after = before + timedelta(days=3650) debug("Generating certificate") cert = CertificateBuilder().subject_name(name).issuer_name(name).\ public_key(key.public_key()).serial_number(1).not_valid_before(before).\ not_valid_after(after).sign(key, SHA256(), default_backend()) with open(join(path, Certificate.CERTIFICATE_FILE), "wb+") as pem: pem.write(cert.public_bytes(Encoding.PEM))
def _get_names_with_oid(name_field: Name, name_oid: NameOID) -> List[str]: return [cn.value for cn in name_field.get_attributes_for_oid(name_oid)]
def get_common_names(name_field: x509.Name) -> List[str]: return [cn.value for cn in name_field.get_attributes_for_oid(NameOID.COMMON_NAME)] # type: ignore
def get_common_name(name_field: x509.Name) -> str: try: return get_common_names(name_field)[0] except IndexError: return name_field.rfc4514_string()
def self_signed_certificate(*hostname, **oid): """ Generates a self signed ssl_cert_key. Args: hostname (str): host name or IP address. oid (str): Object Identifiers. See "cryptography.x509.oid.NameOID" Returns: tuple of bytes: certificate and private key in PEM format. """ # Python 2: Unicode are required if version_info[0] == 2: oid = {key: unicode(value) for key, value in oid.items()} hostname = [unicode(value) for value in hostname] # Requester information name = Name([ NameAttribute(getattr(NameOID, key.upper()), value) for key, value in oid.items() ]) # IP addresses alternatives_names = [] for host in hostname: # DNS host name alternatives_names.append(DNSName(host)) # Host IP address try: alternatives_names.append(IPAddress(ip_address(host))) except ValueError: pass # Validity start date valid_from = datetime.utcnow() # Generates private RSA key private_key = generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) # Generates ssl_cert_key certificate = ( CertificateBuilder() # Requester information # Subject = Issuer on self signed certificates .subject_name(name).issuer_name(name) # Public key and serial number .public_key(private_key.public_key()).serial_number( random_serial_number()) # Validity .not_valid_before(valid_from).not_valid_after(valid_from + timedelta(days=VALIDITY)) # This ssl_cert_key can only sign itself .add_extension(BasicConstraints(ca=True, path_length=0), critical=False) # IP addresses .add_extension(SubjectAlternativeName(alternatives_names), critical=False) # Sign ssl_cert_key with private key .sign(private_key, SHA256(), default_backend())) # Generates public ssl_cert_key file certificate_bytes = certificate.public_bytes(encoding=Encoding.PEM) # Generates private key file private_key_bytes = private_key.private_bytes( encoding=Encoding.PEM, format=PrivateFormat.TraditionalOpenSSL, encryption_algorithm=NoEncryption()) return certificate_bytes, private_key_bytes
def test_valid(self, subtests): for value, expected in [ ( r"CN=James \"Jim\" Smith\, III", Name([ NameAttribute(NameOID.COMMON_NAME, 'James "Jim" Smith, III') ]), ), ( r"UID=\# escape\+\,\;\00this\ ", Name([NameAttribute(NameOID.USER_ID, "# escape+,;\0this ")]), ), ( r"2.5.4.3=James \"Jim\" Smith\, III", Name([ NameAttribute(NameOID.COMMON_NAME, 'James "Jim" Smith, III') ]), ), ("ST=", Name([NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "")])), ( "OU=Sales+CN=J. Smith,DC=example,DC=net", Name([ RelativeDistinguishedName([ NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, "Sales"), NameAttribute(NameOID.COMMON_NAME, "J. Smith"), ]), RelativeDistinguishedName( [NameAttribute(NameOID.DOMAIN_COMPONENT, "example")]), RelativeDistinguishedName( [NameAttribute(NameOID.DOMAIN_COMPONENT, "net")]), ]), ), ( "CN=cryptography.io,O=PyCA,L=,ST=,C=US", Name([ NameAttribute(NameOID.COMMON_NAME, "cryptography.io"), NameAttribute(NameOID.ORGANIZATION_NAME, "PyCA"), NameAttribute(NameOID.LOCALITY_NAME, ""), NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, ""), NameAttribute(NameOID.COUNTRY_NAME, "US"), ]), ), ( r"C=US,CN=Joe \, Smith,DC=example", Name([ NameAttribute(NameOID.COUNTRY_NAME, "US"), NameAttribute(NameOID.COMMON_NAME, "Joe , Smith"), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), ]), ), ( r"C=US,CN=Jane \"J\,S\" Smith,DC=example", Name([ NameAttribute(NameOID.COUNTRY_NAME, "US"), NameAttribute(NameOID.COMMON_NAME, 'Jane "J,S" Smith'), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), ]), ), ( 'C=US,CN=\\"Jane J\\,S Smith\\",DC=example', Name([ NameAttribute(NameOID.COUNTRY_NAME, "US"), NameAttribute(NameOID.COMMON_NAME, '"Jane J,S Smith"'), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), ]), ), ( 'C=US,CN=\\"Jane \\"J\\,S\\" Smith\\",DC=example', Name([ NameAttribute(NameOID.COUNTRY_NAME, "US"), NameAttribute(NameOID.COMMON_NAME, '"Jane "J,S" Smith"'), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), ]), ), ( r"C=US,CN=Jane=Smith,DC=example", Name([ NameAttribute(NameOID.COUNTRY_NAME, "US"), NameAttribute(NameOID.COMMON_NAME, "Jane=Smith"), NameAttribute(NameOID.DOMAIN_COMPONENT, "example"), ]), ), (r"CN=#616263", Name([NameAttribute(NameOID.COMMON_NAME, "abc")])), (r"CN=👍", Name([NameAttribute(NameOID.COMMON_NAME, "👍")])), ( "CN=\\\\123", Name([NameAttribute(NameOID.COMMON_NAME, "\\123")]), ), ("CN=\\\\\\;", Name([NameAttribute(NameOID.COMMON_NAME, "\\;")])), ( "CN=\\\\#123", Name([NameAttribute(NameOID.COMMON_NAME, "\\#123")]), ), ( "2.5.4.10=abc", Name([NameAttribute(NameOID.ORGANIZATION_NAME, "abc")]), ), ]: with subtests.test(): result = Name.from_rfc4514_string(value) assert result == expected