def parse(self, backend, x509_obj): extensions = [] seen_oids = set() for i in range(self.ext_count(backend, x509_obj)): ext = self.get_ext(backend, x509_obj, i) backend.openssl_assert(ext != backend._ffi.NULL) crit = backend._lib.X509_EXTENSION_get_critical(ext) critical = crit == 1 oid = x509.ObjectIdentifier( _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))) if oid in seen_oids: raise x509.DuplicateExtension( "Duplicate {} extension found".format(oid), oid) # These OIDs are only supported in OpenSSL 1.1.0+ but we want # to support them in all versions of OpenSSL so we decode them # ourselves. if oid == ExtensionOID.TLS_FEATURE: data = backend._lib.X509_EXTENSION_get_data(ext) parsed = _Integers.load(_asn1_string_to_bytes(backend, data)) value = x509.TLSFeature( [_TLS_FEATURE_TYPE_TO_ENUM[x.native] for x in parsed]) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: data = backend._lib.X509_EXTENSION_get_data(ext) parsed = asn1crypto.core.Null.load( _asn1_string_to_bytes(backend, data)) assert parsed == asn1crypto.core.Null() extensions.append( x509.Extension(oid, critical, x509.PrecertPoison())) seen_oids.add(oid) continue try: handler = self.handlers[oid] except KeyError: # Dump the DER payload into an UnrecognizedExtension object data = backend._lib.X509_EXTENSION_get_data(ext) backend.openssl_assert(data != backend._ffi.NULL) der = backend._ffi.buffer(data.data, data.length)[:] unrecognized = x509.UnrecognizedExtension(oid, der) extensions.append(x509.Extension(oid, critical, unrecognized)) else: ext_data = backend._lib.X509V3_EXT_d2i(ext) if ext_data == backend._ffi.NULL: backend._consume_errors() raise ValueError( "The {} extension is invalid and can't be " "parsed".format(oid)) value = handler(backend, ext_data) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) return x509.Extensions(extensions)
def new_cert_request(names, key, must_staple=False): primary_name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, names[0].decode('utf-8') if getattr(names[0], 'decode', None) else names[0])]) all_names = x509.SubjectAlternativeName( [x509.DNSName(name.decode('utf-8') if getattr(name, 'decode', None) else name) for name in names]) req = x509.CertificateSigningRequestBuilder() req = req.subject_name(primary_name) req = req.add_extension(all_names, critical=False) if must_staple: if getattr(x509, 'TLSFeature', None): req = req.add_extension(x509.TLSFeature(features=[x509.TLSFeatureType.status_request]), critical=False) else: log('OCSP must-staple ignored as current version of cryptography does not support the flag.', warning=True) req = req.sign(key, hashes.SHA256(), default_backend()) return req
def create_csr(key, domains, must_staple=False): """ Creates a CSR in DER format for the specified key and domain names. """ assert domains name = x509.Name([ x509.NameAttribute(NameOID.COMMON_NAME, domains[0]), ]) san = x509.SubjectAlternativeName( [x509.DNSName(domain) for domain in domains]) csr = (x509.CertificateSigningRequestBuilder().subject_name( name).add_extension(san, critical=False)) if must_staple: ocsp_must_staple = x509.TLSFeature( features=[x509.TLSFeatureType.status_request]) csr = csr.add_extension(ocsp_must_staple, critical=False) return csr.sign(key, hashes.SHA256(), default_backend())
def _xep_patched_parse(self, backend, x509_obj): extensions = [] seen_oids = set() for i in range(self.ext_count(backend, x509_obj)): ext = self.get_ext(backend, x509_obj, i) backend.openssl_assert(ext != backend._ffi.NULL) crit = backend._lib.X509_EXTENSION_get_critical(ext) critical = crit == 1 oid = x509.ObjectIdentifier( _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))) # This OID is only supported in OpenSSL 1.1.0+ but we want # to support it in all versions of OpenSSL so we decode it # ourselves. if oid == ExtensionOID.TLS_FEATURE: data = backend._lib.X509_EXTENSION_get_data(ext) parsed = _Integers.load(_asn1_string_to_bytes(backend, data)) value = x509.TLSFeature( [_TLS_FEATURE_TYPE_TO_ENUM[x.native] for x in parsed]) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue try: handler = self.handlers[oid] except KeyError: # Dump the DER payload into an UnrecognizedExtension object der = dump_der(ext, backend) unrecognized = x509.UnrecognizedExtension(oid, der) extensions.append(x509.Extension(oid, critical, unrecognized)) else: ext_data = backend._lib.X509V3_EXT_d2i(ext) if ext_data == backend._ffi.NULL: backend._consume_errors() der = dump_der(ext, backend) unrecognized = x509.UnrecognizedExtension(oid, der) extensions.append(x509.Extension(oid, critical, unrecognized)) else: value = handler(backend, ext_data) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) return x509.Extensions(extensions)
def create_csr(self, common_name: str, alt_names: Iterable[str] = (), must_staple=False) -> x509.CertificateSigningRequest: subject = [ # letencrypt ignores all other fields. x509.NameAttribute(x509.NameOID.COMMON_NAME, common_name) ] req = x509.CertificateSigningRequestBuilder(x509.Name(subject)) if alt_names: req = req.add_extension(x509.SubjectAlternativeName( general_names=(x509.DNSName(name) for name in alt_names)), critical=True) if must_staple: req = req.add_extension(x509.TLSFeature( [x509.TLSFeatureType.status_request]), critical=False) return req.sign(self._key, hashes.SHA256(), default_backend())
def parse(self, x509_obj): extensions = [] seen_oids = set() for i in range(self.ext_count(x509_obj)): ext = self.get_ext(x509_obj, i) self._backend.openssl_assert(ext != self._backend._ffi.NULL) crit = self._backend._lib.X509_EXTENSION_get_critical(ext) critical = crit == 1 oid = x509.ObjectIdentifier( _obj2txt(self._backend, self._backend._lib.X509_EXTENSION_get_object(ext))) if oid in seen_oids: raise x509.DuplicateExtension( "Duplicate {} extension found".format(oid), oid) # These OIDs are only supported in OpenSSL 1.1.0+ but we want # to support them in all versions of OpenSSL so we decode them # ourselves. if oid == ExtensionOID.TLS_FEATURE: # The extension contents are a SEQUENCE OF INTEGERs. data = self._backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(self._backend, data) features = DERReader(data_bytes).read_single_element(SEQUENCE) parsed = [] while not features.is_empty(): parsed.append(features.read_element(INTEGER).as_integer()) # Map the features to their enum value. value = x509.TLSFeature( [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed]) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: data = self._backend._lib.X509_EXTENSION_get_data(ext) # The contents of the extension must be an ASN.1 NULL. reader = DERReader(_asn1_string_to_bytes(self._backend, data)) reader.read_single_element(NULL).check_empty() extensions.append( x509.Extension(oid, critical, x509.PrecertPoison())) seen_oids.add(oid) continue try: handler = self.handlers[oid] except KeyError: # Dump the DER payload into an UnrecognizedExtension object data = self._backend._lib.X509_EXTENSION_get_data(ext) self._backend.openssl_assert(data != self._backend._ffi.NULL) der = self._backend._ffi.buffer(data.data, data.length)[:] unrecognized = x509.UnrecognizedExtension(oid, der) extensions.append(x509.Extension(oid, critical, unrecognized)) else: ext_data = self._backend._lib.X509V3_EXT_d2i(ext) if ext_data == self._backend._ffi.NULL: self._backend._consume_errors() raise ValueError( "The {} extension is invalid and can't be " "parsed".format(oid)) value = handler(self._backend, ext_data) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) return x509.Extensions(extensions)
def install_extensions(self, builder): """Add common extensions to Cert- or CSR builder. """ # BasicConstraints, critical if self.ca: ext = x509.BasicConstraints(ca=True, path_length=self.path_length) else: ext = x509.BasicConstraints(ca=False, path_length=None) builder = builder.add_extension(ext, critical=True) # KeyUsage, critical ku_args = {k: k in self.usage for k in KU_FIELDS} if self.ca: ku_args.update(CA_DEFAULTS) elif not self.usage: ku_args.update(NONCA_DEFAULTS) for k in XKU_DEFAULTS: if k in self.usage: for k2 in XKU_DEFAULTS[k]: ku_args[k2] = True ext = make_key_usage(**ku_args) builder = builder.add_extension(ext, critical=True) # ExtendedKeyUsage, critical xku = [x for x in self.usage if x not in KU_FIELDS] xku_bad = [x for x in xku if x not in XKU_CODE_TO_OID] if xku_bad: raise InvalidCertificate("Unknown usage keywords: %s" % (','.join(xku_bad),)) if xku: xku_oids = [XKU_CODE_TO_OID[x] for x in xku] ext = x509.ExtendedKeyUsage(xku_oids) builder = builder.add_extension(ext, critical=True) # NameConstraints, critical if (self.exclude_subtrees or self.permit_subtrees) and self.ca: allow = self.load_gnames(self.permit_subtrees) or None disallow = self.load_gnames(self.exclude_subtrees) or None ext = x509.NameConstraints(allow, disallow) builder = builder.add_extension(ext, critical=True) # SubjectAlternativeName if self.san: ext = x509.SubjectAlternativeName(self.get_san_gnames()) builder = builder.add_extension(ext, critical=False) # CRLDistributionPoints if self.crl_urls: full_names = self.get_crl_gnames() reasons = None crl_issuer = None point = x509.DistributionPoint(full_names, None, reasons, crl_issuer) ext = x509.CRLDistributionPoints([point]) builder = builder.add_extension(ext, critical=False) # AuthorityInformationAccess if self.ocsp_urls or self.issuer_urls: oid = AuthorityInformationAccessOID.OCSP ocsp_list = [x509.AccessDescription(oid, gn) for gn in self.get_ocsp_gnames()] oid = AuthorityInformationAccessOID.CA_ISSUERS ca_list = [x509.AccessDescription(oid, gn) for gn in self.get_issuer_urls_gnames()] ext = x509.AuthorityInformationAccess(ocsp_list + ca_list) builder = builder.add_extension(ext, critical=False) # OCSPNoCheck if self.ocsp_nocheck: ext = x509.OCSPNoCheck() builder = builder.add_extension(ext, critical=False) # TLSFeature: status_request, status_request_v2 tls_features = self.get_tls_features() if tls_features: ext = x509.TLSFeature(tls_features) builder = builder.add_extension(ext, critical=False) # configured builder return builder
def extension_type(self) -> x509.TLSFeature: # call serialize_item() to ensure consistent sort order return x509.TLSFeature(sorted(self.value, key=self.serialize_item))
def create_csr(csr_config, private_key=None): """ Given a list of domains create the appropriate csr for those domains :param csr_config: """ if not private_key: private_key = generate_rsa_key(4096) builder = x509.CertificateSigningRequestBuilder() name_list = [x509.NameAttribute( x509.OID_COMMON_NAME, csr_config["domains"][0])] name_list.append( x509.NameAttribute(x509.OID_EMAIL_ADDRESS, csr_config["owner"]) ) if "organization" in csr_config and csr_config["organization"].strip(): name_list.append( x509.NameAttribute(x509.OID_ORGANIZATION_NAME, csr_config["organization"]) ) if ( "organizational_unit" in csr_config and csr_config["organizational_unit"].strip() ): name_list.append( x509.NameAttribute( x509.OID_ORGANIZATIONAL_UNIT_NAME, csr_config["organizational_unit"] ) ) if "country" in csr_config and csr_config["country"].strip(): name_list.append( x509.NameAttribute(x509.OID_COUNTRY_NAME, csr_config["country"]) ) if "state" in csr_config and csr_config["state"].strip(): name_list.append( x509.NameAttribute( x509.OID_STATE_OR_PROVINCE_NAME, csr_config["state"]) ) if "location" in csr_config and csr_config["location"].strip(): name_list.append( x509.NameAttribute(x509.OID_LOCALITY_NAME, csr_config["location"]) ) if "domains" in csr_config: san = x509.SubjectAlternativeName( [x509.DNSName(domain) for domain in csr_config["domains"]]) builder.add_extension(san, critical=True) builder = builder.subject_name( x509.Name(name_list)).add_extension(san, critical=False) if csr_config.get("must_staple", False): ocsp_must_staple = x509.TLSFeature( features=[x509.TLSFeatureType.status_request]) builder.add_extension(ocsp_must_staple, critical=False) extensions = csr_config.get("extensions", {}) critical_extensions = ["basic_constraints", "sub_alt_names", "key_usage"] noncritical_extensions = ["extended_key_usage"] for k, v in extensions.items(): if v: if k in critical_extensions: logger.debug( "Adding Critical Extension: {0} {1}".format(k, v) ) if k == "sub_alt_names": if v["names"]: builder = builder.add_extension( v["names"], critical=True) else: builder = builder.add_extension(v, critical=True) if k in noncritical_extensions: logger.debug("Adding Extension: {0} {1}".format(k, v)) builder = builder.add_extension(v, critical=False) ski = extensions.get("subject_key_identifier", {}) if ski.get("include_ski", False): builder = builder.add_extension( x509.SubjectKeyIdentifier.from_public_key( private_key.public_key()), critical=False, ) request = builder.sign(private_key, hashes.SHA256(), default_backend()) # serialize our private key and CSR private_key = private_key.private_bytes( encoding=serialization.Encoding.PEM, # would like to use PKCS8 but AWS ELBs don't like it format=serialization.PrivateFormat.TraditionalOpenSSL, encryption_algorithm=serialization.NoEncryption(), ).decode("utf-8") csr = request.public_bytes( encoding=serialization.Encoding.PEM).decode("utf-8") return csr, private_key
def parse(self, backend, x509_obj): extensions = [] seen_oids = set() for i in range(self.ext_count(backend, x509_obj)): ext = self.get_ext(backend, x509_obj, i) backend.openssl_assert(ext != backend._ffi.NULL) crit = backend._lib.X509_EXTENSION_get_critical(ext) critical = crit == 1 oid = x509.ObjectIdentifier( _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext)) ) if oid in seen_oids: raise x509.DuplicateExtension( "Duplicate {} extension found".format(oid), oid ) if oid == ExtensionOID.TLS_FEATURE: data = backend._lib.X509_EXTENSION_get_data(ext) data_bytes = _asn1_string_to_bytes(backend, data) features = DERReader(data_bytes).read_single_element(SEQUENCE) parsed = [] while not features.is_empty(): parsed.append(features.read_element(INTEGER).as_integer()) value = x509.TLSFeature( [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed] ) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POSION: data = backend._lib.X509_EXTENSION_get_data(ext) reader = DERReader(_asn1_string_to_bytes(backend, data)) reader.read_single_element(NULL).check_empty() extensions.append(x509.Extension( oid, critical, x509.PrecertPoison() )) seen_oids.add(oid) continue elif oid == ExtensionOID.PRECERT_POISON: data = backend._lib.X509_EXTENSION_get_data(ext) reader = DERReader(_asn1_string_to_bytes(backend, data)) reader.read_single_element(NULL).check_empty() extensions.append(x509.Extension( oid, critical, x509.PrecertPoison() )) seen_oids.add(oid) continue try: handler = self.handlers[oid] except KeyError: data = backend._lib.X509_EXTENSION_get_data(ext) backend.openssl_assert(data != backend._ffi.NULL) der = backend._ffi.buffer(data.data, data.length)[:] unrecognized = x509.UnrecognizedExtension(oid, der) extensions.append( x509.Extension(oid, critical, unrecognized) ) else: ext_data = backend._lib.X509V3_EXT_d2i(ext) if ext_data == backend._ffi.NULL: backend._consume_errors() raise ValueError( "The {} extension is invalid and can't be " "parsed".format(oid) ) value = handler(backend, ext_data) extensions.append(x509.Extension(oid, critical, value)) seen_oids.add(oid) return x509.Extensions(extenions)