Skip to content

Support encode_der for asn1.TLV values#15113

Open
alex wants to merge 2 commits into
mainfrom
claude/cryptography-issue-15109-xfe3hb
Open

Support encode_der for asn1.TLV values#15113
alex wants to merge 2 commits into
mainfrom
claude/cryptography-issue-15109-xfe3hb

Conversation

@alex

@alex alex commented Jun 29, 2026

Copy link
Copy Markdown
Member

Closes #15109.

Previously, calling asn1.encode_der on a value decoded with the asn1.TLV specifier raised NotImplementedError, making it impossible to parse an arbitrary ASN.1 element as a TLV and then serialize just that element back to DER:

from cryptography.hazmat import asn1

tlv_obj = asn1.decode_der(asn1.TLV, asn1.encode_der(1))
asn1.encode_der(tlv_obj)  # previously raised NotImplementedError

Change

Implements the Type::Tlv() arm of the declarative ASN.1 encoder. A TLV's full_data is a complete, already-validated DER element, so encoding re-parses it into an asn1::Tlv and writes it back out verbatim:

  • No annotation (top-level / ANY field) → written as-is.
  • EXPLICIT annotation → re-wrapped in the explicit tag, mirroring the existing decode path.
  • IMPLICIT annotation → still rejected (consistent with decoding, and already rejected at definition time at the Python level).

The re-parse is necessary because the TLV Python object stores the element's raw DER bytes rather than a live asn1::Tlv<'_> (which borrows its input and can't be held in a pyclass); the writer needs an Asn1Writable, and asn1::Tlv has no public constructor, so re-parsing full_data is how we recover one. It only reads the tag/length header and can't fail in practice, since the bytes came from a successful decode.

Tests

  • test_ok_encode_tlv round-trips several elements (INTEGER, BIT STRING, SEQUENCE, NULL) through decode_der(TLV, ...)encode_der.
  • test_ok_encode_tlv_issue_example covers the exact example from the issue.
  • Extended test_sequence_with_tlv_with_explicit_annotation to assert the EXPLICIT-tagged TLV fields re-encode to the original DER.
  • Added a Rust unit test (test_encode_implicit_tlv) covering the defensive implicit-encoding branch, for parity with the decode side.

🤖 Generated with Claude Code


Generated by Claude Code

Previously, calling `asn1.encode_der` on a value decoded with the
`asn1.TLV` specifier raised `NotImplementedError`. This made it
impossible to parse an arbitrary ASN.1 element as a `TLV` and then
serialize just that element back to DER.

A `TLV`'s `full_data` is a complete, already-validated DER element, so
encoding re-parses it and writes it back out verbatim, honoring an
EXPLICIT annotation when present (IMPLICIT annotations on TLV fields
remain rejected at definition time).

Closes #15109

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016iPBDfr6FxfNSm6nzakgwh
Comment thread tests/hazmat/asn1/test_serialization.py Outdated
assert isinstance(tlv, asn1.TLV)
assert asn1.encode_der(tlv) == original

def test_ok_encode_tlv_issue_example(self) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test name (and associated comment) isn't going to age well

Renames `test_ok_encode_tlv_issue_example` to
`test_ok_encode_tlv_roundtrip_from_value` and rewords its comment to
describe the behavior under test rather than referencing the original
feature request, which won't age well.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016iPBDfr6FxfNSm6nzakgwh
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Support asn1.encode_der for asn1.TLV

3 participants