def signature(self): sig = self._backend._ffi.new("ASN1_BIT_STRING **") self._backend._lib.X509_REQ_get0_signature( self._x509_req, sig, self._backend._ffi.NULL ) self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) return _asn1_string_to_bytes(self._backend, sig[0])
def _issuer_key_hash(backend, cert_id): key_hash = backend._ffi.new("ASN1_OCTET_STRING **") res = backend._lib.OCSP_id_get0_info(backend._ffi.NULL, backend._ffi.NULL, key_hash, backend._ffi.NULL, cert_id) backend.openssl_assert(res == 1) backend.openssl_assert(key_hash[0] != backend._ffi.NULL) return _asn1_string_to_bytes(backend, key_hash[0])
def get_attribute_for_oid(self, oid: x509.ObjectIdentifier) -> bytes: obj = _txt2obj_gc(self._backend, oid.dotted_string) pos = self._backend._lib.X509_REQ_get_attr_by_OBJ( self._x509_req, obj, -1) if pos == -1: raise x509.AttributeNotFound( "No {} attribute was found".format(oid), oid) attr = self._backend._lib.X509_REQ_get_attr(self._x509_req, pos) self._backend.openssl_assert(attr != self._backend._ffi.NULL) # We don't support multiple valued attributes for now. self._backend.openssl_assert( self._backend._lib.X509_ATTRIBUTE_count(attr) == 1) asn1_type = self._backend._lib.X509_ATTRIBUTE_get0_type(attr, 0) self._backend.openssl_assert(asn1_type != self._backend._ffi.NULL) # We need this to ensure that our C type cast is safe. # Also this should always be a sane string type, but we'll see if # that is true in the real world... if asn1_type.type not in ( _ASN1Type.UTF8String.value, _ASN1Type.PrintableString.value, _ASN1Type.IA5String.value, ): raise ValueError("OID {} has a disallowed ASN.1 type: {}".format( oid, asn1_type.type)) data = self._backend._lib.X509_ATTRIBUTE_get0_data( attr, 0, asn1_type.type, self._backend._ffi.NULL) self._backend.openssl_assert(data != self._backend._ffi.NULL) # This cast is safe iff we assert on the type above to ensure # that it is always a type of ASN1_STRING data = self._backend._ffi.cast("ASN1_STRING *", data) return _asn1_string_to_bytes(self._backend, data)
def responder_key_hash(self) -> typing.Optional[bytes]: self._requires_successful_response() _, asn1_string = self._responder_key_name() if asn1_string == self._backend._ffi.NULL: return None else: return _asn1_string_to_bytes(self._backend, asn1_string)
def _issuer_name_hash(backend, cert_id): name_hash = backend._ffi.new("ASN1_OCTET_STRING **") res = backend._lib.OCSP_id_get0_info( name_hash, backend._ffi.NULL, backend._ffi.NULL, backend._ffi.NULL, cert_id ) backend.openssl_assert(res == 1) backend.openssl_assert(name_hash[0] != backend._ffi.NULL) return _asn1_string_to_bytes(backend, name_hash[0])
def issuer_name_hash(self): name_hash = self._backend._ffi.new("ASN1_OCTET_STRING **") res = self._backend._lib.OCSP_id_get0_info(name_hash, self._backend._ffi.NULL, self._backend._ffi.NULL, self._backend._ffi.NULL, self._cert_id) self._backend.openssl_assert(res == 1) self._backend.openssl_assert(name_hash[0] != self._backend._ffi.NULL) return _asn1_string_to_bytes(self._backend, name_hash[0])
def _patched_asn1_string_to_utf8(backend, asn1_string): buf = backend._ffi.new("unsigned char **") res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) if res == -1: # "Unsupported ASN1 string type. Type: {0}".format(asn1_string.type) # der = backend._lib.ASN1_STRING_data(asn1_string) # print(der) der = _asn1_string_to_bytes(backend, asn1_string) return der.hex() backend.openssl_assert(buf[0] != backend._ffi.NULL) buf = backend._ffi.gc(buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0])) try: return backend._ffi.buffer(buf[0], res)[:].decode('utf8') except UnicodeDecodeError: return backend._ffi.buffer(buf[0], res)[:].decode('latin1')
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 responder_key_hash(self): _, asn1_string = self._responder_key_name() if asn1_string == self._backend._ffi.NULL: return None else: return _asn1_string_to_bytes(self._backend, asn1_string)
def signature(self): sig = self._backend._lib.OCSP_resp_get0_signature(self._basic) self._backend.openssl_assert(sig != self._backend._ffi.NULL) return _asn1_string_to_bytes(self._backend, sig)
def signature(self) -> bytes: self._requires_successful_response() sig = self._backend._lib.OCSP_resp_get0_signature(self._basic) self._backend.openssl_assert(sig != self._backend._ffi.NULL) return _asn1_string_to_bytes(self._backend, sig)
def _patched_decode_general_name(backend, gn): if gn.type == backend._lib.GEN_DNS: # Convert to bytes and then decode to utf8. We don't use # asn1_string_to_utf8 here because it doesn't properly convert # utf8 from ia5strings. name_bytes = _asn1_string_to_bytes(backend, gn.d.dNSName) try: data = name_bytes.decode("utf8") except UnicodeDecodeError: data = name_bytes.hex() # We don't use the constructor for DNSName so we can bypass validation # This allows us to create DNSName objects that have unicode chars # when a certificate (against the RFC) contains them. return x509.DNSName._init_without_validation(data) elif gn.type == backend._lib.GEN_URI: # Convert to bytes and then decode to utf8. We don't use # asn1_string_to_utf8 here because it doesn't properly convert # utf8 from ia5strings. name_bytes = _asn1_string_to_bytes(backend, gn.d.uniformResourceIdentifier) try: data = name_bytes.decode("utf8") except UnicodeDecodeError: # TODO: we could try utf16-be data = name_bytes.hex() # We don't use the constructor for URI so we can bypass validation # This allows us to create URI objects that have unicode chars # when a certificate (against the RFC) contains them. return x509.UniformResourceIdentifier._init_without_validation(data) 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: data = _asn1_string_to_bytes(backend, gn.d.iPAddress) data_len = len(data) if data_len == 8 or data_len == 32: # This is an IPv4 or IPv6 Network and not a single IP. This # type of data appears in Name Constraints. Unfortunately, # ipaddress doesn't support packed bytes + netmask. Additionally, # IPv6Network can only handle CIDR rather than the full 16 byte # netmask. To handle this we convert the netmask to integer, then # find the first 0 bit, which will be the prefix. If another 1 # bit is present after that the netmask is invalid. base = ipaddress.ip_address(data[:data_len // 2]) netmask = ipaddress.ip_address(data[data_len // 2:]) bits = bin(int(netmask))[2:] prefix = bits.find('0') # If no 0 bits are found it is a /32 or /128 if prefix == -1: prefix = len(bits) if "1" in bits[prefix:]: raise ValueError("Invalid netmask") ip = ipaddress.ip_network(base.exploded + u"/{0}".format(prefix)) else: try: ip = ipaddress.ip_address(data) except ValueError: ip = data return x509.IPAddress(ip) elif gn.type == backend._lib.GEN_DIRNAME: return x509.DirectoryName( _decode_x509_name(backend, gn.d.directoryName)) elif gn.type == backend._lib.GEN_EMAIL: # Convert to bytes and then decode to utf8. We don't use # asn1_string_to_utf8 here because it doesn't properly convert # utf8 from ia5strings. data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8") # We don't use the constructor for RFC822Name so we can bypass # validation. This allows us to create RFC822Name objects that have # unicode chars when a certificate (against the RFC) contains them. return x509.RFC822Name._init_without_validation(data) elif gn.type == backend._lib.GEN_OTHERNAME: type_id = _obj2txt(backend, gn.d.otherName.type_id) value = _asn1_to_der(backend, gn.d.otherName.value) return x509.OtherName(x509.ObjectIdentifier(type_id), value) else: # x400Address or ediPartyName raise x509.UnsupportedGeneralNameType( "{0} is not a supported type".format( x509._GENERAL_NAMES.get(gn.type, gn.type)), gn.type)
def signature(self): return _asn1_string_to_bytes(self._backend, self._x509_req.signature)