src/ail_ref/passport.py
Read-only source from the unchanged 0.3.4 kit. Existing license terms apply.
from __future__ import annotations
import base64
from dataclasses import dataclass
from .ast import Atom, Document, Record, String, Unknown
from .canonical import canonical_value
@dataclass(frozen=True)
class PassportResult:
principal: str | None
claimed_role: str | None
claimed_grant: str | None
status: str
reason: str
def _text(value):
if isinstance(value, Atom):
return value.value
if isinstance(value, String):
return value.value
return None
def _passport_record(document: Document) -> Record:
if len(document.units) != 1:
raise ValueError("a passport document must contain exactly one unit")
value = document.units[0].value
if not isinstance(value, Record) or value.name != "PASSPORT":
raise ValueError("document does not contain a PASSPORT record")
return value
def canonical_signing_payload(record: Record) -> bytes:
fields = tuple((key, value) for key, value in record.fields if key != "signature")
return canonical_value(Record(record.name, fields)).encode("utf-8")
def inspect_passport(document: Document) -> PassportResult:
record = _passport_record(document)
fields = dict(record.fields)
principal = _text(fields.get("principal"))
role = _text(fields.get("role"))
grant = _text(fields.get("grant"))
declared = _text(fields.get("verification"))
signature = fields.get("signature")
if isinstance(signature, Unknown) or signature is None:
if declared == "ail:cryptographically_verified":
return PassportResult(principal, role, grant, "ail:rejected", "passport claims cryptographic verification but has no signature")
return PassportResult(principal, role, grant, "ail:declared", "owner claim is present without independent authentication")
if not isinstance(signature, String):
return PassportResult(principal, role, grant, "ail:rejected", "signature must be a base64 string or unknown")
algorithm = _text(fields.get("algorithm"))
public_key = fields.get("public_key")
if algorithm != "Ed25519" or not isinstance(public_key, String):
return PassportResult(principal, role, grant, "ail:rejected", "signed passport requires Ed25519 and a base64 public key")
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
except ImportError:
return PassportResult(principal, role, grant, "ail:declared", "signature is present but the optional cryptography package is unavailable")
try:
key_bytes = base64.b64decode(public_key.value, validate=True)
signature_bytes = base64.b64decode(signature.value, validate=True)
Ed25519PublicKey.from_public_bytes(key_bytes).verify(signature_bytes, canonical_signing_payload(record))
except Exception as exc:
return PassportResult(principal, role, grant, "ail:rejected", f"signature verification failed: {type(exc).__name__}")
return PassportResult(principal, role, grant, "ail:cryptographically_verified", "Ed25519 signature verified")