def test_der_lengths(selenium): from cryptography.hazmat._der import OCTET_STRING, DERReader, encode_der for [length, header] in [ # Single-byte lengths. (0, b"\x04\x00"), (1, b"\x04\x01"), (2, b"\x04\x02"), (127, b"\x04\x7f"), # Long-form lengths. (128, b"\x04\x81\x80"), (129, b"\x04\x81\x81"), (255, b"\x04\x81\xff"), (0x100, b"\x04\x82\x01\x00"), (0x101, b"\x04\x82\x01\x01"), (0xFFFF, b"\x04\x82\xff\xff"), (0x10000, b"\x04\x83\x01\x00\x00"), ]: body = length * b"a" der = header + body reader = DERReader(der) element = reader.read_element(OCTET_STRING) reader.check_empty() assert element.data.tobytes() == body assert encode_der(OCTET_STRING, body) == der
def test_der_lengths(length, header): body = length * b"a" der = header + body reader = DERReader(der) element = reader.read_element(OCTET_STRING) reader.check_empty() assert element.data.tobytes() == body assert encode_der(OCTET_STRING, body) == der
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 test_der(): # This input is the following structure, using # https://github.com/google/der-ascii # # SEQUENCE { # SEQUENCE { # NULL {} # INTEGER { 42 } # OCTET_STRING { "hello" } # } # } der = b"\x30\x0e\x30\x0c\x05\x00\x02\x01\x2a\x04\x05\x68\x65\x6c\x6c\x6f" reader = DERReader(der) with pytest.raises(ValueError): reader.check_empty() with pytest.raises(ValueError): with reader: pass with pytest.raises(ZeroDivisionError): with DERReader(der): raise ZeroDivisionError # Parse the outer element. outer = reader.read_element(SEQUENCE) reader.check_empty() assert outer.data.tobytes() == der[2:] # Parse the outer element with read_any_element. reader = DERReader(der) tag, outer2 = reader.read_any_element() reader.check_empty() assert tag == SEQUENCE assert outer2.data.tobytes() == der[2:] # Parse the outer element with read_single_element. outer3 = DERReader(der).read_single_element(SEQUENCE) assert outer3.data.tobytes() == der[2:] # read_single_element rejects trailing data. with pytest.raises(ValueError): DERReader(der + der).read_single_element(SEQUENCE) # Continue parsing the structure. inner = outer.read_element(SEQUENCE) outer.check_empty() # Parsing a missing optional element should work. assert inner.read_optional_element(INTEGER) is None null = inner.read_element(NULL) null.check_empty() # Parsing a present optional element should work. integer = inner.read_optional_element(INTEGER) assert integer is not None assert integer.as_integer() == 42 octet_string = inner.read_element(OCTET_STRING) assert octet_string.data.tobytes() == b"hello" # Parsing a missing optional element should work when the input is empty. inner.check_empty() assert inner.read_optional_element(INTEGER) is None # Re-encode the same structure. der2 = encode_der( SEQUENCE, encode_der( SEQUENCE, encode_der(NULL), encode_der(INTEGER, encode_der_integer(42)), encode_der(OCTET_STRING, b"hello"), ), ) assert der2 == der
def test_der_reader_wrong_tag(): reader = DERReader(b"\x04\x00") with pytest.raises(ValueError): reader.read_element(SEQUENCE)
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)