Skip to content

Releases: litzki-systems/sovp-python

sovp 1.1.1

Choose a tag to compare

@litzki-systems litzki-systems released this 09 Oct 23:16
Immutable release. Only release title and notes can be modified.

Fixes a defect found in an external review of the published surface: the documented live-validation path could not succeed against any real deployment, including this project's own.

validate_domain() rejected correctly signed, unexpired documents. It passed check_timestamp=True unconditionally, which enforced the issuance window of draft Section 9.4 (default W = 600 s) against freshness.created. A statically published .well-known document is re-signed on its validity cycle, not per request, so the window could never be satisfied — validate_domain("litzki-systems.com") returned psi_core = 0. The window is now opt-in:

validate_domain("litzki-systems.com")                       # psi_core 1, reason "ok"
validate_domain("litzki-systems.com", check_timestamp=True) # psi_core 0, reason "issuance_window"

freshness.expiresAt and host binding are still always enforced.

New reason field. validate_domain() now names the first failed check — ok, host_mismatch, signature, freshness_missing, freshness_invalid, created_in_future, expired, issuance_window, no_key — so an expired document is distinguishable from a forged one. Backed by the new verify_identity_detail(), which returns (verified, reason). verify_identity() keeps its boolean contract unchanged.

generate_identity_document() default validity. It defaulted freshness.expiresAt to created + 1 hour, while its own docstring and draft Section 10 both claimed the field was omitted unless supplied. The default is now created + DEFAULT_VALIDITY_DAYS (90 days), matching what the production deployments publish.

Documentation. The README's "Live validation example" pointed at examples/validate_live.py, which the PyPI distribution does not contain, and printed an expected output that was wrong in two fields. It is now a three-line example over the installed API with its real output. Two dead draft cross-references corrected: the issuance window is Section 9.4 (not 7.2, which does not exist in revision 04), the 300-second DNS TTL recommendation is Section 9.3 (not 6.1). requires-python = ">=3.9" is now declared.

No change to the wire format, the schema, the signed scope or the canonicalization. 80 tests pass.

Full detail in CHANGELOG.md.

sovp 1.1.0

Choose a tag to compare

@litzki-systems litzki-systems released this 09 Oct 17:34
Immutable release. Only release title and notes can be modified.

Added

  • sovp/core.py — generate_identity_document() now signs a freshness object (created, nonce, expiresAt) as part of the Ed25519-signed scope; default context_version changed from "v1.4" to "v2.0". Previously these fields lived inside the unsigned integrity_proof and were forgeable without invalidating the signature — same weakness as the already-documented expiresAt forgeability in sovp-engine's scanner. Closes the replay-protection gap described in draft-litzki-sovp-04.
  • tests/test_vectors.py — Test Vector Set 2 (schema v2.0, real generated+verified signatures) covering the new freshness object, including tamper rejection for freshness.created/freshness.expiresAt. Test Vector Set 1 (v1.4, locked) is unchanged.
  • sovp/document_safety.py — parse_unverified_sovp_document(), a minimal JSON parser enforcing draft-litzki-sovp-04's "Resource Limits for Unverified Documents": rejects a document larger than 64 KiB, nested deeper than 16 levels, or containing a duplicate member name in any object, before the document is trusted with any further processing.

Changed

  • pyproject.toml — the cryptography bound stays at >=38.0.0,!=40.0.0,!=40.0.1,<42. It matches the Requires-Dist line of the OS-packaged pyOpenSSL 23.2.0 on Ubuntu 24.04, which certbot imports. A global pip install sovp with a higher bound shadows that version and breaks certificate renewal. The library itself runs on newer cryptography releases; the bound protects the system install.
  • CHANGELOG.md — the 1.0.1 entry referenced a parameter count. It now states that the parameter count references were aligned with the protocol specification.
  • README.md — the introduction names pip install sovp as the normal installation route and keeps the editable clone for development.
  • sovp/core.py — verify_identity()'s check_timestamp path now reads freshness.created first and falls back to the unsigned integrity_proof.created only for documents whose @context predates v2.0; this fallback affects timestamp freshness checking only, never signature verification.
  • README.md — schema example and "Replay protection" table row updated to the v2.0/freshness shape; added an explicit callout that the tamper-resistance guarantee is new as of v2.0 and did not hold under v1.4.
  • README.md — contentAddress example corrected from the stale prefixed "sha256:<hex>" single-field form to the shape generate_identity_document() actually ships: {"alg": "sha256", "digest": "<hex>"}.
  • README.md — removed the parameters (entropy_threshold/determinism_score) field from the schema example; it does not exist in any reference implementation (sovp-python, sovp-engine, or the Cloudflare Worker) and was never anything other than an illustrative artifact. Found while reconciling draft-litzki-sovp-04 against the running implementations — the draft's own schema example had the same field, removed there too.
  • sovp/core.py — Draft 04 host binding is enforced through expected_host; v2.0 freshness remains signed and expiry is always validated. Generated DNS key references use the URL hostname, excluding ports and normalizing trailing dots and case.
  • sovp/resolver.py — DNS TXT parsing now accepts only the exact v=SOVP1; k=<base64> record shape and requires a valid 32-byte Ed25519 public key. Legacy endpoint fallback remains restricted to HTTP 404.
  • examples/ — live validation, end-to-end verification, and the ARD trustManifest example now identify Draft 04 explicitly and demonstrate v2.0 host binding and the current contentAddress shape.
  • workers/sovp-identity/ — the reference worker now serves a publisher-supplied, pre-signed Draft 04 v2.0 document from a Cloudflare secret instead of embedding a stale v1.4 artifact.

Fixed

  • tests/test_vectors.py — contentAddress.digest in Test Vector Set 2 was wrong. The vector shipped 33465a2b…3ae2b5; the correct value over sha256(JCS(signed scope)) is d00c6db5…30b460. No test read the field, so the vector and the specification drifted apart unnoticed.
  • sovp/core.py — verify_identity() no longer fails open when integrity_proof.created is missing; with check_timestamp=True a missing created is now a rejection (Psi_core = 0), closing a replay bypass of draft Section 7.2
  • sovp/core.py — verify_identity() no longer raises AttributeError when integrity_proof is a non-dict value (attacker-controlled since it's excluded from the signed payload); now returns False per the documented bool-only contract
  • sovp/resolver.py — fetch_identity_document() used resp.json() (== json.loads()) to parse a remote, not-yet-signature-checked document, with no size, depth, or duplicate-key limit. Now parses via parse_unverified_sovp_document().

Tests

  • tests/test_vectors.py — two tests now recompute contentAddress.digest from Test Vector Set 2 itself and assert that a change inside the signed scope changes the recomputed digest. This keeps the vector and the specification from drifting apart again.
  • Added Draft 04 conformance coverage for freshness clock-skew boundaries, the 600-second issuance window, signed unknown top-level members, unsigned contentAddress and scan extensions, host normalization, URL ports, and exact DNS TXT syntax.

PyPI: https://pypi.org/project/sovp/1.1.0/

sovp 1.0.5

Choose a tag to compare

@litzki-systems litzki-systems released this 09 Oct 17:44
Immutable release. Only release title and notes can be modified.

Diese Release-Notiz wurde nachträglich angelegt am 09.10.2026. Daher steht sie in der Liste nach v1.1.0, obwohl 1.0.5 die ältere Version ist.

This release note was created retroactively on 2026-10-09. It therefore appears after v1.1.0 in the list although 1.0.5 is the older version.

Fixed

  • pyproject.toml — capped the unpinned cryptography dependency to >=38.0.0,!=40.0.0,!=40.0.1,<42. A global pip install sovp on a server also running certbot/pyOpenSSL (OS-packaged) could pull a cryptography release newer than pyOpenSSL supports, shadow the OS-packaged version, and break certbot with AttributeError: module 'lib' has no attribute 'GEN_EMAIL'. The cap matches the range pyOpenSSL 23.x (Ubuntu 24.04's apt version) actually declares support for.

PyPI: https://pypi.org/project/sovp/1.0.5/

SOVP 1.0.4 — Packaging release

Choose a tag to compare

@litzki-systems litzki-systems released this 24 Aug 04:10
Immutable release. Only release title and notes can be modified.
0c0dc6c

SOVP 1.0.4 — Packaging release

Fixed

sovp-Quellmodule werden jetzt ins gebaute Wheel aufgenommen (packages.find include = ["sovp*"]), sodass pip install sovp die importierbaren Module sovp.core, sovp.cli und sovp.resolver ausliefert.

Protocol specification: draft-litzki-sovp-03