Skip to content

Conversation

@facutuesca
Copy link
Contributor

This adds support for encoding/decoding PrintableString.

here's an example of how it would be used:

@asn1.sequence
class MySeq:
    field: asn1.PrintableString

object = MySeq(field=asn1.PrintableString("A string"))
encoded = encode_der(object)

decoded = decode_der(MySeq, encoded)
assert decoded.field.as_str() == "A string"

A couple of implementation notes:

  • In this comment, I mentioned that the idea was to use typing.NewType to define the PrintableString type. However, I had forgotten that a NewType cannot be told apart from the original type during runtime:

    Note that these checks are enforced only by the static type checker. At runtime, the statement Derived = NewType('Derived', Base) will make Derived a callable that immediately returns whatever parameter you pass it.
    src

    The actual solution was to use a Rust type PrintableString and expose it directly to Python. This type wraps a normal Python string, and can only be used through a restricted API (similar to rust-asn1's):

class PrintableString:
    def __new__(cls, inner: str) -> PrintableString: ...
    def as_str(self) -> str: ...

Part of #12283

@facutuesca facutuesca force-pushed the ft/asn1-printable-string branch from 7aba7ee to 8c1812c Compare September 24, 2025 00:33
Comment on lines 80 to 84
let inner_str: pyo3::pybacked::PyBackedStr = val
.get()
.inner
.extract(py)
.map_err(|_| asn1::WriteError::AllocationError)?;
Copy link
Member

Choose a reason for hiding this comment

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

We shouldn't need a pybacked string, val.get().inner.bind(py) should be all we need.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@facutuesca facutuesca marked this pull request as ready for review September 24, 2025 00:52
@facutuesca facutuesca force-pushed the ft/asn1-printable-string branch from 508abec to 3b22b14 Compare September 25, 2025 22:38
def test_repr_printable_string(self) -> None:
assert (
repr(asn1.PrintableString("MyString"))
== "PrintableString(MyString)"
Copy link
Member

Choose a reason for hiding this comment

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

I think we want PrintableString("MyString") (or single quotes) -- using the repr of the str

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed


class TestPrintableString:
def test_ok_printable_string(self) -> None:
def decoded_eq(a: asn1.PrintableString, b: asn1.PrintableString):
Copy link
Member

Choose a reason for hiding this comment

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

Oh, we should implement __eq__ on asn1.PrintableString.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

Signed-off-by: Facundo Tuesca <[email protected]>
impl PrintableString {
#[new]
#[pyo3(signature = (inner,))]
fn new(inner: pyo3::Py<pyo3::types::PyString>) -> Self {
Copy link
Member

Choose a reason for hiding this comment

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

We should validate that inner is a valid PrintableString, rather than defering that to serialization

Copy link
Contributor Author

@facutuesca facutuesca Sep 25, 2025

Choose a reason for hiding this comment

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

Should I replicate the logic from rust-asn1's PrintableString::verify ? We could also make verify public.

Copy link
Member

Choose a reason for hiding this comment

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

asn1::PrintableString::new(s).is_none() should be enough to check if its invalid

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or call rust-asn1's PrintableString::new and discard the result

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

@alex alex enabled auto-merge (squash) September 25, 2025 23:43
@alex alex merged commit 07f2662 into pyca:main Sep 25, 2025
73 checks passed
@facutuesca facutuesca deleted the ft/asn1-printable-string branch September 25, 2025 23:44
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.

2 participants