diff --git a/CHANGELOG.md b/CHANGELOG.md index a6e4835..c64460e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Magic method (`__eq__` and `__repr__`) has been added for TimestampResponse + and TimestampRequest ([#48](https://github.com/trailofbits/rfc3161-client/pull/48)) ## [0.0.2] - 2024-10-30 diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 487fd8d..e86ad3e 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -103,6 +103,12 @@ impl TimeStampReq { hasher.finish() } + fn __eq__(&self, py: pyo3::Python<'_>, other: pyo3::PyRef<'_, Self>) -> pyo3::PyResult { + let other_bytes = other.as_bytes(py)?; + let self_bytes = self.as_bytes(py)?; + Ok(other_bytes.eq(&self_bytes.as_bytes())) + } + fn __repr__(&self, py: pyo3::Python<'_>) -> pyo3::PyResult { let version = self.version()?; let nonce_repr = match self.nonce(py)? { @@ -293,6 +299,12 @@ impl TimeStampResp { hasher.finish() } + fn __eq__(&self, other: pyo3::PyRef<'_, Self>) -> pyo3::PyResult { + let other_bytes = asn1::write_single(&other.raw.borrow_dependent()).unwrap(); + let self_bytes = asn1::write_single(&self.raw.borrow_dependent()).unwrap(); + Ok(other_bytes.eq(&self_bytes)) + } + fn __repr__(&self) -> pyo3::PyResult { let status = self.status()?; Ok(format!("")) diff --git a/src/rfc3161_client/tsp.py b/src/rfc3161_client/tsp.py index 70a7f26..8e9de89 100644 --- a/src/rfc3161_client/tsp.py +++ b/src/rfc3161_client/tsp.py @@ -166,7 +166,7 @@ def nonce(self) -> bytes: @property @abc.abstractmethod - def name(self) -> cryptography.x509.Name: + def name(self) -> cryptography.x509.GeneralName: """Returns the name.""" diff --git a/test/fixtures/other_request.der b/test/fixtures/other_request.der new file mode 100644 index 0000000..fae125b Binary files /dev/null and b/test/fixtures/other_request.der differ diff --git a/test/fixtures/other_response.tsr b/test/fixtures/other_response.tsr new file mode 100644 index 0000000..e66f853 Binary files /dev/null and b/test/fixtures/other_response.tsr differ diff --git a/test/test_tsp.py b/test/test_tsp.py new file mode 100644 index 0000000..e71dbcf --- /dev/null +++ b/test/test_tsp.py @@ -0,0 +1,55 @@ +from datetime import datetime, timezone +from pathlib import Path + +from rfc3161_client import TimeStampRequest, decode_timestamp_response +from rfc3161_client._rust import parse_timestamp_request + +_HERE = Path(__file__).parent.resolve() +_FIXTURE = _HERE / "fixtures" + + +class TestTimestampResponse: + def test_parsing_good(self): + timestamp_response = decode_timestamp_response((_FIXTURE / "response.tsr").read_bytes()) + assert timestamp_response.status == 0 + + tst_info = timestamp_response.tst_info + assert tst_info.name.value.rfc4514_string() == "CN=Test TSA Timestamping,O=local" + assert tst_info.nonce == 3937359519792308179 + assert not tst_info.ordering + assert tst_info.policy.dotted_string == "1.3.6.1.4.1.57264.2" + assert tst_info.serial_number == 693290210947147715387173185458430793885588677084 + assert tst_info.version == 1 + assert datetime(2024, 10, 8, 15, 40, 32, tzinfo=timezone.utc) == tst_info.gen_time + assert tst_info.message_imprint.message.hex().startswith("9b71d224bd62f3785d96d") + + assert tst_info.accuracy.seconds == 1 + assert tst_info.accuracy.millis is None + assert tst_info.accuracy.micros is None + + def test_equality(self): + timestamp_response = decode_timestamp_response((_FIXTURE / "response.tsr").read_bytes()) + other_response = decode_timestamp_response((_FIXTURE / "other_response.tsr").read_bytes()) + + assert timestamp_response != other_response + assert decode_timestamp_response( + (_FIXTURE / "response.tsr").read_bytes() + ) == decode_timestamp_response((_FIXTURE / "response.tsr").read_bytes()) + + +class TestTimestampRequest: + def test_parsing_good(self): + timestamp_request: TimeStampRequest = parse_timestamp_request( + (_FIXTURE / "request.der").read_bytes() + ) + assert timestamp_request.version == 1 + assert timestamp_request.cert_req + assert timestamp_request.nonce == 3937359519792308179 + assert timestamp_request.policy is None + assert timestamp_request.message_imprint.message.hex().startswith("9b71d224bd62f3785d96d") + + def test_equality(self): + timestamp_request = parse_timestamp_request((_FIXTURE / "request.der").read_bytes()) + other_request = parse_timestamp_request((_FIXTURE / "other_request.der").read_bytes()) + + assert timestamp_request != other_request