CRIT-1: Add post-issuance OID verification in CaService.issueCert() — parses
the returned cert with @peculiar/x509 and validates that OIDs 1.3.6.1.4.1.99999.1
(mosaic_grant_id) and 1.3.6.1.4.1.99999.2 (mosaic_subject_user_id) are present
and match the request values. Throws CaServiceError on mismatch or absence.
CRIT-2: Guard grant activation in the redeem() transaction with
WHERE status='pending' (RETURNING to detect no-op). Throw ConflictException
if the grant was already activated. Also add WHERE state='pending' guard on
the federationPeers UPDATE.
HIGH-2: Remove 90-day silent fallback in extractCertNotAfter() — an unparseable
cert now propagates as a 500 error rather than silently setting a wrong expiry.
HIGH-4: Log only the first 8 hex chars of the enrollment token in the issueCert
failure error log — never log the full 64-char token.
HIGH-5: Wrap redeem() body in try/catch; write a best-effort failure audit row
(outside transaction, .catch(() => {}) guarded) on any error path so all
enrollment attempts are audited regardless of outcome.
MED-3: Verify grantId ↔ peerId binding in createToken() before inserting the
token — prevents cross-wiring a grant to an attacker-controlled peer.
Closes#461
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>