def load_gnames(self, gname_list): """Converts list of prefixed strings to GeneralName list. """ gnames = [] for alt in gname_list: if ':' not in alt: die("Invalid gname: %s", alt) t, val = alt.split(':', 1) t = t.lower().strip() val = val.strip() if t == 'dn': gn = x509.DirectoryName(self.load_name(parse_dn(val))) elif t == 'dns': gn = x509.DNSName(val) elif t == 'email': gn = x509.RFC822Name(val) elif t == 'uri': gn = x509.UniformResourceIdentifier(val) elif t == 'ip': if val.find(':') >= 0: gn = x509.IPAddress(ipaddress.IPv6Address(val)) else: gn = x509.IPAddress(ipaddress.IPv4Address(val)) elif t == 'dn': gn = x509.DirectoryName(self.load_name(parse_dn(val))) elif t == 'net': if val.find(':') >= 0: gn = x509.IPAddress(ipaddress.IPv6Network(val)) else: gn = x509.IPAddress(ipaddress.IPv4Network(val)) else: raise Exception('Invalid GeneralName: ' + alt) gnames.append(gn) return gnames
def make_cert(cacert: Cert): private_key = make_key() builder = ( x509.CertificateSigningRequestBuilder().subject_name( x509.Name([x509.NameAttribute( NameOID.COMMON_NAME, "localhost")])).add_extension( x509.SubjectAlternativeName([ # Describe what sites we want this certificate for. x509.DNSName("localhost"), x509.IPAddress(ipaddress.IPv4Address("127.0.0.1")), x509.IPAddress(ipaddress.IPv6Address("::1")), ]), critical=False, )) csr = builder.sign(private_key, hashes.SHA256(), default_backend()) assert csr.is_signature_valid cert_builder = (x509.CertificateBuilder().subject_name( csr.subject).issuer_name(cacert.cert.subject).not_valid_before( datetime.today() - one_day).not_valid_after(datetime.today() + one_day).serial_number( int(uuid.uuid4())).public_key(csr.public_key())) for extension in csr.extensions: cert_builder = cert_builder.add_extension(extension.value, critical=extension.critical) certificate = cert_builder.sign(private_key=cacert.key, algorithm=hashes.SHA256(), backend=default_backend()) return Cert(certificate, private_key)
def generate_selfsigned_cert( name, key, valid_until, other_ips: Optional[List] = None) -> x509.Certificate: subject = issuer = x509.Name( [x509.NameAttribute(NameOID.COMMON_NAME, name)]) # Add common SAN for localhost san_names = [ x509.DNSName("localhost"), x509.DNSName("localhost.localdomain"), x509.IPAddress(IPv4Address("127.0.0.1")), x509.IPAddress(IPv6Address("::1")), ] if other_ips: for ip in other_ips: san_names.append(x509.IPAddress(ip_address(ip))) cert = (x509.CertificateBuilder().subject_name(subject).add_extension( x509.SubjectAlternativeName(san_names), critical=False).issuer_name(issuer).public_key( key.public_key()).serial_number( x509.random_serial_number()).not_valid_before( datetime.datetime.utcnow()).not_valid_after( valid_until).sign(key, hashes.SHA256(), backend=default_backend())) return cert
def cryptography_get_name(name, what='Subject Alternative Name'): ''' Given a name string, returns a cryptography x509.GeneralName object. Raises an OpenSSLObjectError if the name is unknown or cannot be parsed. ''' try: if name.startswith('DNS:'): return x509.DNSName(to_text(name[4:])) if name.startswith('IP:'): address = to_text(name[3:]) if '/' in address: return x509.IPAddress(ipaddress.ip_network(address)) return x509.IPAddress(ipaddress.ip_address(address)) if name.startswith('email:'): return x509.RFC822Name(to_text(name[6:])) if name.startswith('URI:'): return x509.UniformResourceIdentifier(to_text(name[4:])) if name.startswith('RID:'): m = re.match(r'^([0-9]+(?:\.[0-9]+)*)$', to_text(name[4:])) if not m: raise OpenSSLObjectError('Cannot parse {what} "{name}"'.format( name=name, what=what)) return x509.RegisteredID(x509.oid.ObjectIdentifier(m.group(1))) if name.startswith('otherName:'): # otherName can either be a raw ASN.1 hex string or in the format that OpenSSL works with. m = re.match( r'^([0-9]+(?:\.[0-9]+)*);([0-9a-fA-F]{1,2}(?::[0-9a-fA-F]{1,2})*)$', to_text(name[10:])) if m: return x509.OtherName(x509.oid.ObjectIdentifier(m.group(1)), _parse_hex(m.group(2))) # See https://www.openssl.org/docs/man1.0.2/man5/x509v3_config.html - Subject Alternative Name for more # defailts on the format expected. name = to_text(name[10:], errors='surrogate_or_strict') if ';' not in name: raise OpenSSLObjectError( 'Cannot parse {what} otherName "{name}", must be in the ' 'format "otherName:<OID>;<ASN.1 OpenSSL Encoded String>" or ' '"otherName:<OID>;<hex string>"'.format(name=name, what=what)) oid, value = name.split(';', 1) b_value = serialize_asn1_string_as_der(value) return x509.OtherName(x509.ObjectIdentifier(oid), b_value) if name.startswith('dirName:'): return x509.DirectoryName(x509.Name(_parse_dn(to_text(name[8:])))) except Exception as e: raise OpenSSLObjectError( 'Cannot parse {what} "{name}": {error}'.format(name=name, what=what, error=e)) if ':' not in name: raise OpenSSLObjectError( 'Cannot parse {what} "{name}" (forgot "DNS:" prefix?)'.format( name=name, what=what)) raise OpenSSLObjectError( 'Cannot parse {what} "{name}" (potentially unsupported by cryptography backend)' .format(name=name, what=what))
def generate_cert(self, addr: str = '') -> Tuple[str, str]: have_ip = True if addr: try: ip = x509.IPAddress(ipaddress.IPv4Address(addr)) except Exception: try: ip = x509.IPAddress(ipaddress.IPv6Address(addr)) except Exception: have_ip = False pass else: ip = x509.IPAddress(ipaddress.IPv4Address(self.mgr.get_mgr_ip())) private_key = rsa.generate_private_key(public_exponent=65537, key_size=4096, backend=default_backend()) public_key = private_key.public_key() builder = x509.CertificateBuilder() builder = builder.subject_name( x509.Name([ x509.NameAttribute( NameOID.COMMON_NAME, addr if addr else str(self.mgr.get_mgr_ip())), ])) builder = builder.issuer_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, u'cephadm-root'), ])) builder = builder.not_valid_before(datetime.now()) builder = builder.not_valid_after(datetime.now() + timedelta(days=(365 * 10 + 3))) builder = builder.serial_number(x509.random_serial_number()) builder = builder.public_key(public_key) if have_ip: builder = builder.add_extension(x509.SubjectAlternativeName([ip]), critical=False) builder = builder.add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True, ) cert = builder.sign(private_key=self.root_key, algorithm=hashes.SHA256(), backend=default_backend()) cert_str = crypto.dump_certificate(crypto.FILETYPE_PEM, cert).decode('utf-8') key_str = private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()).decode('utf-8') return (cert_str, key_str)
def _deserialize(self, value, attr, data): general_names = [] for name in value: if name['nameType'] == 'DNSName': validators.sensitive_domain(name['value']) general_names.append(x509.DNSName(name['value'])) elif name['nameType'] == 'IPAddress': general_names.append(x509.IPAddress(ipaddress.ip_address(name['value']))) elif name['nameType'] == 'IPNetwork': general_names.append(x509.IPAddress(ipaddress.ip_network(name['value']))) elif name['nameType'] == 'uniformResourceIdentifier': general_names.append(x509.UniformResourceIdentifier(name['value'])) elif name['nameType'] == 'directoryName': # TODO: Need to parse a string in name['value'] like: # 'CN=Common Name, O=Org Name, OU=OrgUnit Name, C=US, ST=ST, L=City/[email protected]' # or # 'CN=Common Name/O=Org Name/OU=OrgUnit Name/C=US/ST=NH/L=City/[email protected]' # and turn it into something like: # x509.Name([ # x509.NameAttribute(x509.OID_COMMON_NAME, "Common Name"), # x509.NameAttribute(x509.OID_ORGANIZATION_NAME, "Org Name"), # x509.NameAttribute(x509.OID_ORGANIZATIONAL_UNIT_NAME, "OrgUnit Name"), # x509.NameAttribute(x509.OID_COUNTRY_NAME, "US"), # x509.NameAttribute(x509.OID_STATE_OR_PROVINCE_NAME, "NH"), # x509.NameAttribute(x509.OID_LOCALITY_NAME, "City"), # x509.NameAttribute(x509.OID_EMAIL_ADDRESS, "*****@*****.**") # ] # general_names.append(x509.DirectoryName(x509.Name(BLAH)))) pass elif name['nameType'] == 'rfc822Name': general_names.append(x509.RFC822Name(name['value'])) elif name['nameType'] == 'registeredID': general_names.append(x509.RegisteredID(x509.ObjectIdentifier(name['value']))) elif name['nameType'] == 'otherName': # This has two inputs (type and value), so it doesn't fit the mold of the rest of these GeneralName entities. # general_names.append(x509.OtherName(name['type'], bytes(name['value']), 'utf-8')) pass elif name['nameType'] == 'x400Address': # The Python Cryptography library doesn't support x400Address types (yet?) pass elif name['nameType'] == 'EDIPartyName': # The Python Cryptography library doesn't support EDIPartyName types (yet?) pass else: current_app.logger.warning('Unable to deserialize SubAltName with type: {name_type}'.format(name_type=name['nameType'])) return x509.SubjectAlternativeName(general_names)
def generate_local_cert(private_key, days_valid=3650, output_file='server.crt', loc_name=None, org_name=None): def_name = u'SickGear' # Various details about who we are. For a self-signed certificate the # subject and issuer are always the same. subject = issuer = x509.Name([ x509.NameAttribute(NameOID.LOCALITY_NAME, loc_name or def_name), x509.NameAttribute(NameOID.ORGANIZATION_NAME, org_name or def_name) ]) # build Subject Alternate Names (aka SAN) list # First the host names, add with x509.DNSName(): san_list = [x509.DNSName(u'localhost')] try: thishostname = text_type(socket.gethostname()) san_list.append(x509.DNSName(thishostname)) except (BaseException, Exception): pass # Then the host IP addresses, add with x509.IPAddress() # Inside a try-except, just to be sure try: # noinspection PyCompatibility from ipaddress import IPv4Address, IPv6Address san_list.append(x509.IPAddress(IPv4Address(u'127.0.0.1'))) san_list.append(x509.IPAddress(IPv6Address(u'::1'))) # append local v4 ip mylocalipv4 = localipv4() if mylocalipv4: san_list.append(x509.IPAddress(IPv4Address(u'' + mylocalipv4))) except (ImportError, Exception): pass cert = x509.CertificateBuilder() \ .subject_name(subject) \ .issuer_name(issuer) \ .public_key(private_key.public_key()) \ .not_valid_before(datetime.datetime.utcnow()) \ .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=days_valid)) \ .serial_number(random_serial_number()) \ .add_extension(x509.SubjectAlternativeName(san_list), critical=True) \ .sign(private_key, hashes.SHA256(), default_backend()) # Write the certificate out to disk. with open(output_file, 'wb') as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) return cert
def generate_local_cert(private_key, days_valid=3560, output_file="cert.cert", LN="SABnzbd", ON="SABnzbd"): """Generate a certificate, using basic information. Ported from cryptography docs/x509/tutorial.rst """ # Various details about who we are. For a self-signed certificate the # subject and issuer are always the same. subject = issuer = x509.Name([ x509.NameAttribute(NameOID.LOCALITY_NAME, LN), x509.NameAttribute(NameOID.ORGANIZATION_NAME, ON), # x509.NameAttribute(NameOID.COMMON_NAME, CN), ]) # build Subject Alternate Names (aka SAN) list # First the host names, add with x509.DNSName(): san_list = [ x509.DNSName("localhost"), x509.DNSName(str(socket.gethostname())) ] # Then the host IP addresses, add with x509.IPAddress() # Inside a try-except, just to be sure try: import ipaddress san_list.append(x509.IPAddress(ipaddress.IPv4Address("127.0.0.1"))) san_list.append(x509.IPAddress(ipaddress.IPv6Address("::1"))) # append local v4 ip mylocalipv4 = localipv4() if mylocalipv4: san_list.append( x509.IPAddress(ipaddress.IPv4Address(str(mylocalipv4)))) except: pass cert = (x509.CertificateBuilder().subject_name(subject).issuer_name( issuer).public_key(private_key.public_key()).not_valid_before( datetime.datetime.utcnow()).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=days_valid)).serial_number( x509.random_serial_number()).add_extension( x509.SubjectAlternativeName(san_list), critical=True).sign(private_key, hashes.SHA256(), default_backend())) # Write our certificate out to disk. with open(output_file, "wb") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) return cert
def get_certificate(): private_key = ec.generate_private_key(ec.SECP384R1, default_backend()) public_key = private_key.public_key() host = '127.0.0.1' now = datetime.datetime.utcnow() fields = [ x509.NameAttribute(NameOID.COMMON_NAME, host), ] subject = issuer = x509.Name(fields) cert = x509.CertificateBuilder().subject_name(subject) cert = cert.issuer_name(issuer) cert = cert.public_key(public_key) cert = cert.serial_number(x509.random_serial_number()) cert = cert.not_valid_before(now) cert = cert.not_valid_after(now + datetime.timedelta(days=1)) cert = cert.add_extension(x509.SubjectAlternativeName( [x509.IPAddress(IPv4Address(host))]), critical=False) cert = cert.sign(private_key, hashes.SHA512(), default_backend()) return cert, private_key
def generate_server_cert(name, passphrase): """ """ key = rsa.generate_private_key( public_exponent=65537, key_size=2048, ) cert = base_cert(name, key).add_extension( x509.SubjectAlternativeName([x509.IPAddress(IPv4Address("127.0.0.1")) ]), critical=False).add_extension( x509.ExtendedKeyUsage([ ExtendedKeyUsageOID.SERVER_AUTH, ]), critical=True, ).sign(key, hashes.SHA256()) return ( cert.public_bytes(serialization.Encoding.PEM), key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption( passphrase.encode('utf-8'))), )
def server_certificate(ip, issuer, issuer_key): server_cert_filepath, server_key_filepath = get_filepaths( ip, SERVER_DIRNAME) server_key = get_persistent_key(server_key_filepath) subject = x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, "AU"), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "NSW"), x509.NameAttribute(NameOID.LOCALITY_NAME, "Wagga Wagga"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Quarc"), x509.NameAttribute(NameOID.COMMON_NAME, "quarc.internal") ]) if not os.path.exists(server_cert_filepath): cert = x509.CertificateBuilder().subject_name(subject).issuer_name( issuer).public_key(server_key.public_key()).serial_number( x509.random_serial_number()).not_valid_before( datetime.datetime.utcnow()).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=3650)).add_extension( x509.SubjectAlternativeName( [x509.IPAddress(ipaddress.ip_address(ip))]), critical=True, ).sign(issuer_key, hashes.SHA256(), default_backend()) with open(server_cert_filepath, 'wb') as file: file.write(cert.public_bytes(serialization.Encoding.PEM)) return server_cert_filepath, server_key_filepath
def _generate_pem_cert_and_key(cn='127.0.0.1', alt_ip='127.0.0.1'): import datetime import ipaddress from cryptography import x509 from cryptography.x509.oid import NameOID from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import rsa key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, cn)]) now = datetime.datetime.utcnow() cert_builder = (x509.CertificateBuilder().subject_name( name).issuer_name(name).public_key( key.public_key()).serial_number(1000).not_valid_before( now).not_valid_after(now + datetime.timedelta(days=1))) if alt_ip is not None: cert_builder = cert_builder.add_extension( x509.SubjectAlternativeName([ x509.DNSName(cn), x509.IPAddress(ipaddress.IPv4Address(alt_ip)) ]), critical=False) cert = cert_builder.sign(key, hashes.SHA256(), default_backend()) cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM) key_pem = key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption()) return cert_pem, key_pem
def _encode_host(name): """Encode a host principal as a DNS name or IP address""" try: return x509.IPAddress(ip_address(name)) except ValueError: return x509.DNSName(name)
def user_input_alt_name(): data = [] count = 0 common_name = "" print( "Please enter the domain or ip address you want to create in the cert") print("Enter 1 domain or IP address each time, press ENTER to end") while True: input_data = input() if count == 0: common_name = input_data # use first domain or ip address as cert CN count = count + 1 if input_data == "": break if check_is_ip(input_data): try: data.append(x509.IPAddress(IPv4Address(input_data))) except ValueError: print("Illegal IP address! Please try again") else: try: data.append(x509.DNSName(input_data)) except ValueError: print( "IDN current not supported!, please convert to punycode first" ) print("current domain or ipaddress:", end="") print(data) common_name = common_name.replace("*", "_") return common_name, data
def selfSignedCert(ip: str) -> typing.Tuple[str, str, str]: key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend(), ) # Create a random password for private key password = secrets.token_urlsafe(32) name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, ip)]) san = x509.SubjectAlternativeName( [x509.IPAddress(ipaddress.ip_address(ip))]) basic_contraints = x509.BasicConstraints(ca=True, path_length=0) now = datetime.utcnow() cert = ( x509.CertificateBuilder().subject_name(name).issuer_name( name) # self signed, its Issuer DN must match its Subject DN. .public_key(key.public_key()).serial_number( random.SystemRandom().randint(0, 1 << 64)).not_valid_before(now). not_valid_after(now + timedelta(days=10 * 365)).add_extension( basic_contraints, False).add_extension(san, False).sign(key, hashes.SHA256(), default_backend())) return (key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.BestAvailableEncryption( password.encode())).decode(), cert.public_bytes(encoding=serialization.Encoding.PEM).decode(), password)
def build_name(key, value): key = key.lower() if key == "dns": return x509.DNSName(str(value)) if key == "email": return x509.RFC822Name(str(value)) if key == "uri": return x509.UniformResourceIdentifier(str(value)) if key == "dirname": return x509.DirectoryName(str(value)) if key in ("ip", "ip address"): import ipaddress try: value = ipaddress.ip_address(str(value)) except ValueError: value = ipaddress.ip_network(str(value)) return x509.IPAddress(value) raise ValueError(f"Unsupported alternative name: {key}")
def generate_self_signed_certificate( host: str, checksum_address: str, curve: EllipticCurve, private_key: _EllipticCurvePrivateKey = None, days_valid: int = 365) -> Tuple[Certificate, _EllipticCurvePrivateKey]: if not private_key: private_key = ec.generate_private_key(curve, default_backend()) public_key = private_key.public_key() now = datetime.datetime.utcnow() subject = issuer = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, host), x509.NameAttribute(NameOID.PSEUDONYM, checksum_address) ]) cert = x509.CertificateBuilder().subject_name(subject) cert = cert.issuer_name(issuer) cert = cert.public_key(public_key) cert = cert.serial_number(x509.random_serial_number()) cert = cert.not_valid_before(now) cert = cert.not_valid_after(now + datetime.timedelta(days=days_valid)) cert = cert.add_extension(x509.SubjectAlternativeName( [x509.IPAddress(IPv4Address(host))]), critical=False) cert = cert.sign(private_key, hashes.SHA512(), default_backend()) return cert, private_key
def generate_self_signed_certificate( host: str, private_key: SecretKey = None, days_valid: int = 365, curve: ClassVar[EllipticCurve] = _TLS_CURVE, ) -> Tuple[Certificate, _EllipticCurvePrivateKey]: if private_key: private_bn = int.from_bytes(private_key.to_secret_bytes(), 'big') private_key = ec.derive_private_key(private_value=private_bn, curve=curve()) else: private_key = ec.generate_private_key(curve(), default_backend()) public_key = private_key.public_key() now = datetime.datetime.utcnow() fields = [x509.NameAttribute(NameOID.COMMON_NAME, host)] subject = issuer = x509.Name(fields) cert = x509.CertificateBuilder().subject_name(subject) cert = cert.issuer_name(issuer) cert = cert.public_key(public_key) cert = cert.serial_number(x509.random_serial_number()) cert = cert.not_valid_before(now) cert = cert.not_valid_after(now + datetime.timedelta(days=days_valid)) cert = cert.add_extension(x509.SubjectAlternativeName( [x509.IPAddress(IPv4Address(host))]), critical=False) cert = cert.sign(private_key, hashes.SHA512(), default_backend()) return cert, private_key
def generate_device_cert(hostname: str, ipv4_address: IPv4Address): apidata = get_apidata() try: if not os.path.isfile(apidata['cafile']): raise Exception("Specified cafile is not a file: {}".format( apidata['cafile'])) except KeyError: raise Exception("No cafile specified in api.yml") try: if not os.path.isfile(apidata['cakeyfile']): raise Exception("Specified cakeyfile is not a file: {}".format( apidata['cakeyfile'])) except KeyError: raise Exception("No cakeyfile specified in api.yml") try: if not os.path.isdir(apidata['certpath']): raise Exception("Specified certpath is not a directory") except KeyError: raise Exception("No certpath found in api.yml settings") with open(apidata['cakeyfile'], "rb") as cakeyfile: root_key = serialization.load_pem_private_key( cakeyfile.read(), password=None, ) with open(apidata['cafile'], "rb") as cafile: root_cert = x509.load_pem_x509_certificate(cafile.read()) cert_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) new_subject = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, hostname), ]) cert = (x509.CertificateBuilder().subject_name(new_subject).issuer_name( root_cert.issuer).public_key(cert_key.public_key()).serial_number( x509.random_serial_number()).not_valid_before( datetime.datetime.utcnow()).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=7300)).add_extension( x509.SubjectAlternativeName( [x509.IPAddress(ipv4_address)]), critical=False, ).sign(root_key, hashes.SHA256(), default_backend())) with open(os.path.join(apidata['certpath'], "{}.crt".format(hostname)), "wb") as f: f.write(cert.public_bytes(serialization.Encoding.PEM)) with open(os.path.join(apidata['certpath'], "{}.key".format(hostname)), "wb") as f: f.write( cert_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ))
def _get_alt_name(self, alt_name): """Get instances of X509 Names according to their type""" try: socket.inet_pton(socket.AF_INET, alt_name) except socket.error: return x509.DNSName(unicode(alt_name)) else: return x509.IPAddress(ipaddress.IPv4Address(unicode(alt_name)))
def generate_selfsigned_cert(hostname, public_ip, private_ip): import datetime import ipaddress from cryptography import x509 from cryptography.x509.oid import NameOID from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa # Generate our key key = rsa.generate_private_key(public_exponent=65537, key_size=1024, backend=default_backend()) name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, hostname)]) alt_names = x509.SubjectAlternativeName([ # best practice seem to be to include the hostname in the SAN, which *SHOULD* mean COMMON_NAME is ignored. x509.DNSName(hostname), # allow addressing by IP, for when you don't have real DNS (common in most testing scenarios) # openssl wants DNSnames for ips... x509.DNSName(public_ip), x509.DNSName(private_ip), # ... whereas golang's crypto/tls is stricter, and needs IPAddresses x509.IPAddress(ipaddress.ip_address(public_ip)), x509.IPAddress(ipaddress.ip_address(private_ip)), ]) # path_len=0 means this cert can only sign itself, not other certs. basic_constraints = x509.BasicConstraints(ca=True, path_length=0) now = datetime.datetime.utcnow() cert = (x509.CertificateBuilder().subject_name(name).issuer_name( name).public_key( key.public_key()).serial_number(1000).not_valid_before(now). not_valid_after(now + datetime.timedelta(days=100 * 365)).add_extension( basic_constraints, False).add_extension(alt_names, False).sign( key, hashes.SHA256(), default_backend())) cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM) key_pem = key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ) return cert_pem, key_pem
def test_basic(self): # duplication of doctests, but those are not run for every version self.assertEqual(format_general_name(x509.DNSName('example.com')), 'DNS:example.com') self.assertEqual( format_general_name( x509.IPAddress(ipaddress.IPv4Address('127.0.0.1'))), 'IP:127.0.0.1')
def _create_server_certificate(self, cert: Certificate_model, private_key: Key, issuer_key: Key) -> x509.Certificate: # TODO implement checks # countryName = match # stateOrProvinceName = match # localityName = match # organizationName = match # organizationalUnitName = optional # commonName = supplied # emailAddress = optional if cert.parent.type != CertificateTypes.INTERMEDIATE and cert.parent.type != CertificateTypes.ROOT: raise RuntimeError("A root or intermediate parent is expected ") self._builder = x509.CertificateBuilder() self._set_basic(cert, private_key, issuer_key) self._builder = self._builder.add_extension( x509.KeyUsage(digital_signature=True, content_commitment=False, key_encipherment=True, data_encipherment=False, key_agreement=False, key_cert_sign=False, crl_sign=False, encipher_only=False, decipher_only=False), critical=True, ) self._builder = self._builder.add_extension( x509.ExtendedKeyUsage([ExtendedKeyUsageOID.SERVER_AUTH]), critical=False, ) if cert.dn.subjectAltNames: alts = [] for altname in cert.dn.subjectAltNames: try: alt = x509.IPAddress(ipaddress.ip_address(altname)) alts.append(alt) continue except: pass try: alt = x509.DNSName(altname) alts.append(alt) continue except: pass self._builder = self._builder.add_extension( x509.SubjectAlternativeName(alts), critical=False, ) return self._sign_certificate(issuer_key)
def create_cert(ca_crt, ca_key, common_name, subjectAltNames, filename): logger.info('Create certificate for %s with sans %s', common_name, ','.join(subjectAltNames)) one_day = datetime.timedelta(1, 0, 0) issuer_name = ca_crt.issuer.get_attributes_for_oid( x509.name.NameOID.COMMON_NAME)[0].value private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048, backend=default_backend()) public_key = private_key.public_key() builder = x509.CertificateBuilder() builder = builder.subject_name( x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, common_name), ])) builder = builder.issuer_name( x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, issuer_name)])) builder = builder.not_valid_before(datetime.datetime.today() - one_day) builder = builder.not_valid_after(datetime.datetime.today() + one_day * 365 * 1) builder = builder.serial_number(int(x509.random_serial_number())) builder = builder.public_key(public_key) builder = builder.add_extension( x509.BasicConstraints(ca=False, path_length=None), critical=True, ) builder = builder.add_extension(x509.SubjectAlternativeName( [x509.DNSName(name) for name in subjectAltNames] + [x509.IPAddress(ipaddress.IPv4Address('127.0.0.1'))]), critical=True) builder = builder.add_extension(x509.ExtendedKeyUsage([ x509.oid.ExtendedKeyUsageOID.CLIENT_AUTH, x509.oid.ExtendedKeyUsageOID.SERVER_AUTH, ]), critical=False) certificate = builder.sign(private_key=ca_key, algorithm=hashes.SHA256(), backend=default_backend()) ca_key_filename = filename + '-key.pem' ca_crt_filename = filename + '-crt.pem' logger.info('Write %s certificate and key in %s %s', common_name, ca_crt_filename, ca_key_filename) with open(ca_key_filename, 'wb') as f: f.write( private_key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption())) with open(ca_crt_filename, 'wb') as f: f.write(certificate.public_bytes(encoding=serialization.Encoding.PEM)) return certificate, private_key
def build_csr(self): if not self.private_key: if self.key_type == KeyTypes.RSA: self.private_key = rsa.generate_private_key( public_exponent=65537, key_size=self.key_length, backend=default_backend()) elif self.key_type == KeyTypes.ECDSA: if self.key_curve == "P521": curve = ec.SECP521R1() elif self.key_curve == "P384": curve = ec.SECP384R1() elif self.key_curve == "P256": curve = ec.SECP256R1() elif self.key_curve == "P224": curve = ec.SECP224R1() else: curve = ec.SECP521R1() self.private_key = ec.generate_private_key( curve, default_backend()) else: raise ClientBadData self.public_key_from_private() csr_builder = x509.CertificateSigningRequestBuilder() subject = [ x509.NameAttribute( NameOID.COMMON_NAME, self.common_name, ) ] csr_builder = csr_builder.subject_name(x509.Name(subject)) alt_names = [] if self.ip_addresses: for ip in self.ip_addresses: alt_names.append(x509.IPAddress(ipaddress.IPv4Address(ip))) if self.san_dns: for ns in self.san_dns: alt_names.append(x509.DNSName(ns)) if self.email_addresses: for mail in self.email_addresses: alt_names.append(x509.RFC822Name(mail)) csr_builder = csr_builder.add_extension( x509.SubjectAlternativeName(alt_names), critical=False, ) csr_builder = csr_builder.sign(self.private_key, hashes.SHA256(), default_backend()) self.csr = csr_builder.public_bytes( serialization.Encoding.PEM).decode() return
def generate_selfsigned_cert(hostname, ip_addresses=None, key=None): """Generates self signed certificate for a hostname, and optional IP addresses.""" from cryptography import x509 from cryptography.x509.oid import NameOID from cryptography.hazmat.primitives import hashes from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric import rsa # Generate our key if key is None: key = rsa.generate_private_key( public_exponent=65537, key_size=2048, backend=default_backend(), ) name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, hostname)]) # best practice seem to be to include the hostname in the SAN, which # *SHOULD* mean COMMON_NAME is ignored. alt_names = [x509.DNSName(hostname)] # allow addressing by IP, for when you don't have real DNS (common in # most testing scenarios if ip_addresses: for addr in ip_addresses: # openssl wants DNSnames for ips... alt_names.append(x509.DNSName(addr)) # whereas golang's crypto/tls is stricter, and needs IPAddresses # note: older versions of cryptography do not understand # ip_address objects alt_names.append(x509.IPAddress(ipaddress.ip_address(addr))) san = x509.SubjectAlternativeName(alt_names) # path_len=0 means this cert can only sign itself, not other certs. basic_contraints = x509.BasicConstraints(ca=True, path_length=0) now = datetime.utcnow() cert = (x509.CertificateBuilder().subject_name(name).issuer_name( name).public_key(key.public_key()).serial_number( x509.random_serial_number()).not_valid_before(now).not_valid_after( now + timedelta(days=2 * 365)).add_extension( basic_contraints, False).add_extension(san, False).sign(key, hashes.SHA256(), default_backend())) cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM) key_pem = key.private_bytes( encoding=serialization.Encoding.PEM, format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ) return key_pem, cert_pem
def authority_certificate(ip): auth_cert_filepath, _ = get_filepaths(ip, AUTHORITY_DIRNAME) auth_key = make_key() issuer = subject = x509.Name([ x509.NameAttribute(NameOID.COUNTRY_NAME, "AU"), x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "NSW"), x509.NameAttribute(NameOID.LOCALITY_NAME, "Wagga Wagga"), x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Quarc"), x509.NameAttribute(NameOID.COMMON_NAME, "quarc.services") ]) if os.path.exists(auth_cert_filepath): # print( # "\nTLS authority certificate:\n" # " {}\n".format(auth_cert_filepath)) pass else: # Uses name constraints # https://nameconstraints.bettertls.com/ cert = x509.CertificateBuilder().subject_name(subject).issuer_name( issuer).public_key(auth_key.public_key()).serial_number( x509.random_serial_number()).not_valid_before( datetime.datetime.utcnow()).not_valid_after( datetime.datetime.utcnow() + datetime.timedelta(days=3650)).add_extension( x509.NameConstraints( [x509.IPAddress(ipaddress.ip_network(ip))], None), critical=True, ).sign(auth_key, hashes.SHA256(), default_backend()) with open(auth_cert_filepath, 'wb') as file: file.write(cert.public_bytes(serialization.Encoding.PEM)) print( "\n" "=================================================================" "===============" "\n\n" " A TLS certificate for your current IP address has been created at:\n\n" " {}\n\n" " This certificate is to be installed as a certificate authority\n" " on each client that needs access to this server. This certificate\n" " will only allow authentication for servers hosted at the followng\n" " address:\n\n" " https://{}:PORT\n\n" " This is achieved by implementing the Name Constraints extension\n" " and by not storing the certificate authority private key to disk.\n\n" "=================================================================" "===============" "\n".format(auth_cert_filepath, ip)) return auth_cert_filepath, subject, auth_key
def _build_general_name(backend, gn): if gn.type == backend._lib.GEN_DNS: data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:] return x509.DNSName(idna.decode(data)) elif gn.type == backend._lib.GEN_URI: data = backend._ffi.buffer( gn.d.uniformResourceIdentifier.data, gn.d.uniformResourceIdentifier.length)[:].decode("ascii") parsed = urllib_parse.urlparse(data) hostname = idna.decode(parsed.hostname) if parsed.port: netloc = hostname + u":" + six.text_type(parsed.port) else: netloc = hostname # Note that building a URL in this fashion means it should be # semantically indistinguishable from the original but is not # guaranteed to be exactly the same. uri = urllib_parse.urlunparse( (parsed.scheme, netloc, parsed.path, parsed.params, parsed.query, parsed.fragment)) return x509.UniformResourceIdentifier(uri) elif gn.type == backend._lib.GEN_RID: oid = _obj2txt(backend, gn.d.registeredID) return x509.RegisteredID(x509.ObjectIdentifier(oid)) elif gn.type == backend._lib.GEN_IPADD: return x509.IPAddress( ipaddress.ip_address( backend._ffi.buffer(gn.d.iPAddress.data, gn.d.iPAddress.length)[:])) elif gn.type == backend._lib.GEN_DIRNAME: return x509.DirectoryName(_build_x509_name(backend, gn.d.directoryName)) elif gn.type == backend._lib.GEN_EMAIL: data = backend._ffi.buffer(gn.d.rfc822Name.data, gn.d.rfc822Name.length)[:].decode("ascii") name, address = parseaddr(data) parts = address.split(u"@") if name or len(parts) > 2 or not address: # parseaddr has found a name (e.g. Name <email>) or the split # has found more than 2 parts (which means more than one @ sign) # or the entire value is an empty string. raise ValueError("Invalid rfc822name value") elif len(parts) == 1: # Single label email name. This is valid for local delivery. No # IDNA decoding can be done since there is no domain component. return x509.RFC822Name(address) else: # A normal email of the form [email protected]. Let's attempt to # decode the domain component and return the entire address. return x509.RFC822Name(parts[0] + u"@" + idna.decode(parts[1])) else: # otherName, x400Address or ediPartyName raise x509.UnsupportedGeneralNameType( "{0} is not a supported type".format( x509._GENERAL_NAMES.get(gn.type, gn.type)), gn.type)
def gen_alt_name(list): alt_name_objs = [] for name in list: try: addr = IPv4Address(name) alt_name_objs.append(x509.IPAddress(addr)) continue except AddressValueError: pass try: addr = IPv6Address(name) alt_name_objs.append(x509.IPAddress(addr)) continue except AddressValueError: pass alt_name_objs.append(x509.DNSName(name)) return x509.SubjectAlternativeName(alt_name_objs)
def dummy_cert( privkey: rsa.RSAPrivateKey, cacert: x509.Certificate, commonname: Optional[str], sans: List[str], organization: Optional[str] = None, ) -> Cert: """ Generates a dummy certificate. privkey: CA private key cacert: CA certificate commonname: Common name for the generated certificate. sans: A list of Subject Alternate Names. organization: Organization name for the generated certificate. Returns cert if operation succeeded, None if not. """ builder = x509.CertificateBuilder() builder = builder.issuer_name(cacert.subject) builder = builder.add_extension(x509.ExtendedKeyUsage( [ExtendedKeyUsageOID.SERVER_AUTH]), critical=False) builder = builder.public_key(cacert.public_key()) now = datetime.datetime.now() builder = builder.not_valid_before(now - datetime.timedelta(days=2)) builder = builder.not_valid_after(now + CERT_EXPIRY) subject = [] is_valid_commonname = (commonname is not None and len(commonname) < 64) if is_valid_commonname: assert commonname is not None subject.append(x509.NameAttribute(NameOID.COMMON_NAME, commonname)) if organization is not None: assert organization is not None subject.append( x509.NameAttribute(NameOID.ORGANIZATION_NAME, organization)) builder = builder.subject_name(x509.Name(subject)) builder = builder.serial_number(x509.random_serial_number()) ss: List[x509.GeneralName] = [] for x in sans: try: ip = ipaddress.ip_address(x) except ValueError: ss.append(x509.DNSName(x)) else: ss.append(x509.IPAddress(ip)) # RFC 5280 ยง4.2.1.6: subjectAltName is critical if subject is empty. builder = builder.add_extension(x509.SubjectAlternativeName(ss), critical=not is_valid_commonname) cert = builder.sign(private_key=privkey, algorithm=hashes.SHA256()) # type: ignore return Cert(cert)