Skip to content

Verify signatures of several passports

Check the Ed25519 signatures of a list of public passports offline, loading the key set once, and print one result per passport.

The script takes passport UUIDs (the part after urn:dpp:) as arguments, loads the key set from /.well-known/batterypass/keys.json once, and checks each passport as described in Verify a passport signature offline: canonicalise document with RFC 8785, compare the SHA-256 with verification.hash, verify the Ed25519 signature with the key named by verification.key_id. It needs no API key. It exits with status 1 if any passport is not valid, so it fits a monitoring job or an incoming-goods check.

The cURL tab uses verifyPassport instead: the server checks the signatures for you, which is quick but relies on the server's answer.

#!/usr/bin/env bash
# verify-many.sh <passport-uuid>...: the server-side check with verifyPassport (needs curl and jq)
for id in "$@"; do
  curl -sS "$BATTERYPASS_URL/api/v1/public/passports/$id/verify" |
    jq -r --arg id "$id" '"\($id)\t\(if .valid == true then "valid (version \(.version_no))" elif .code then .code else "INVALID" end)"'
done
Output
0192f0c4-7d1e-7a3b-9c55-2f1e8d4a6b10	valid
0192f0c4-7d1e-7a3b-9c55-2f1e8d4a6b11	not checked (qr_locked)
0192f0c4-7d1e-7a3b-9c55-2f1e8d4a6b12	error 404

not checked means the passport is not public right now (its status is shown), so there is no signed document. Public reads are limited to 300 requests per minute per client address; for long lists, add a pause or handle 429 as in Handle errors and retries. To verify passports of another manufacturer, set BATTERYPASS_URL to the address their passports come from.