{"id":9413,"library":"x690","title":"x690","description":"x690 is a pure Python library that implements the X.690 standard for Basic Encoding Rules (BER) encoding and decoding of ASN.1 data structures. It provides functionalities to encode Python objects into BER-encoded bytes and decode BER-encoded bytes back into Python objects. The current version is 1.0.0.post1, with the last update in September 2022, suggesting a stable but infrequently updated codebase.","status":"active","version":"1.0.0.post1","language":"en","source_language":"en","source_url":"https://github.com/dgorissen/x690","tags":["x690","asn.1","ber","encoding","decoding","serialization","pure-python"],"install":[{"cmd":"pip install x690","lang":"bash","label":"Install stable version"}],"dependencies":[],"imports":[{"note":"The primary function for decoding BER bytes.","symbol":"decode","correct":"from x690 import decode"},{"note":"Provides access to standard X.690 types like Integer, Sequence, OctetString.","symbol":"types","correct":"import x690.types as t"},{"note":"Contains custom exceptions like IncompleteDecoding and UnexpectedType.","symbol":"exc","correct":"from x690 import exc"},{"note":"Base class for defining custom X.690 types. When subclassing, ensure the new type is imported for registration.","symbol":"Type","correct":"from x690.types import Type"}],"quickstart":{"code":"import x690.types as t\nfrom x690 import decode\n\n# 1. Encoding a value\nmy_integer = t.Integer(123)\nencoded_bytes = bytes(my_integer)\nprint(f\"Encoded Integer: {encoded_bytes.hex()}\")\n\n# 2. Encoding a composite value (Sequence)\nmy_sequence = t.Sequence([t.Integer(1), t.OctetString(b'hello')])\nencoded_sequence_bytes = bytes(my_sequence)\nprint(f\"Encoded Sequence: {encoded_sequence_bytes.hex()}\")\n\n# 3. Decoding bytes\ndecoded_value, next_offset = decode(encoded_bytes)\nprint(f\"Decoded value: {decoded_value.pyvalue} (Type: {type(decoded_value).__name__})\")\n\n# 4. Decoding a sequence (multiple values)\ndata_to_decode = b'0\\x06\\x02\\x01\\x01\\x04\\x01a'\ndecoded_obj_1, offset_1 = decode(data_to_decode)\ndecoded_obj_2, offset_2 = decode(data_to_decode, offset_1)\nprint(f\"Decoded obj 1: {decoded_obj_1.pretty()}\")\nprint(f\"Decoded obj 2: {decoded_obj_2.pretty()}\")\n\n# 5. Decoding with an expected type (optional but good for type checking)\n# This helps ensure the decoded type matches expectations and aids type checkers.\nfrom x690.exc import UnexpectedType\ntry:\n    expected_int_value, _ = decode(encoded_bytes, expected_type=t.Integer)\n    print(f\"Decoded with expected type: {expected_int_value.pyvalue}\")\n    # This would raise UnexpectedType if encoded_bytes was not an Integer\n    # decode(encoded_bytes, expected_type=t.OctetString) \nexcept UnexpectedType as e:\n    print(f\"Error decoding with unexpected type: {e}\")\n","lang":"python","description":"This quickstart demonstrates how to encode basic X.690 types like Integer and Sequence into bytes, and how to decode BER-encoded bytes back into Python objects using the `decode` function. It also shows how to use `pretty()` for human-readable output and how to leverage `expected_type` for type validation during decoding."},"warnings":[{"fix":"Always check the `next_offset` value and pass it for subsequent `decode` calls. If you expect only one object, use `strict=True` to catch remaining bytes as an error.","message":"When decoding, the `decode` function returns a tuple: `(decoded_object, next_offset)`. It does not automatically consume all bytes if there are multiple BER-encoded objects concatenated. You must loop and pass `next_offset` to decode subsequent objects.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Review the GitHub repository for any unreleased fixes or forks if critical updates are needed. Consider vendor-specific or more actively maintained ASN.1 libraries if advanced features or aggressive maintenance is required.","message":"The library's last update was in September 2022. While functional for X.690 BER, it may not actively incorporate new Python language features or security patches. Users should be aware of this if integrating into highly active or security-sensitive projects.","severity":"breaking","affected_versions":"1.0.0.post1 and earlier"},{"fix":"Ensure that the module containing your custom `x690.types.Type` subclass is imported at runtime before any decoding operations that might encounter that type.","message":"To support custom X.690 types not defined in the standard, you must subclass `x690.types.Type` and define `TYPECLASS`, `NATURE`, and `TAG`. Crucially, this custom type *must be imported* somewhere in your application code for the library to automatically register it for decoding. If not imported, it will be treated as an `UnknownType`.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-16T00:00:00.000Z","next_check":"2026-07-15T00:00:00.000Z","problems":[{"fix":"If you expect multiple objects, remove `strict=True` and loop through the data, passing the `next_offset` returned by `decode` to subsequent calls. If you genuinely expect only one object and this is an error, check your input data for unexpected trailing bytes.","cause":"This error occurs when `x690.decode` is called with `strict=True`, but the input `bytes` object contains more BER-encoded data after the first object has been successfully decoded. It indicates that the entire byte stream was not consumed by a single decoding operation.","error":"x690.exc.IncompleteDecoding: Strict decoding still had X remaining bytes!"},{"fix":"Verify that the `expected_type` passed to `decode` accurately reflects the type of the BER object you are trying to parse. If the type is unknown or can vary, omit `expected_type` and check the type of the returned object dynamically.","cause":"This error is raised when `x690.decode` is called with the `expected_type` argument, and the actual BER-encoded object's type identifier (tag) does not match the provided `expected_type`.","error":"x690.exc.UnexpectedType: Expected type 'Integer' but got 'OctetString'"},{"fix":"Ensure that the Python module where your custom `x690.types.Type` subclass is defined is imported somewhere in your application's startup code. This allows the class to be registered with the `x690` library.","cause":"This typically happens when you define a custom X.690 type (by subclassing `x690.types.Type`) but fail to import the module where it's defined before attempting to decode data containing that type. The library defaults to `UnknownType` if it can't find a registered class for the tag.","error":"AttributeError: 'UnknownType' object has no attribute 'my_custom_field'"}]}