TracePass
Справочник

Проверка на подписан цифров паспорт

Изтеглете подписания W3C verifiable credential на паспорт, разрешете ключа did:web и проверете ES256 подписа сами, с curl, Node или Python.

Всяка версия на публикуван цифров продуктов паспорт в TracePass се издава като подписан W3C verifiable credential във формата UNTP 0.7.0. Можете да проверите, че данните на паспорта идват от TracePass и не са променени, без акаунт и без да се обръщате към нас. Тази страница показва как, с публичния демо паспорт.

1. Изтеглете credential

bash
curl --http2 -H "Accept: application/vc+jwt" \
  https://id.tracepass.eu/01/99999999999997/21/6B27A0000001 \
  -o credential.jwt

Самият адрес на паспорта връща credential, когато поискате application/vc+jwt. Адресите на паспортите изискват HTTP/2 (EN 18216), затова инструменти, които говорят само HTTP/1.1, получават 505. Заглавката Link на отговора, linkset на паспорта и заглавната част на HTML страницата обявяват credential. Паспорт без подписана текуща версия отговаря с 406, а спрян, изтекъл или архивиран паспорт не връща credential.

2. Прочетете заглавката

Credential е компактен JWS. Защитената му заглавка показва как е подписан:

json
{
  "alg": "ES256",
  "typ": "vc+jwt",
  "cty": "vc",
  "kid": "did:web:www.tracepass.eu#key-1"
}

Полезният товар е самият credential (VC-JOSE-COSE), а не claim vc от VC 1.1. kid посочва издателя и ключа, с който е подписан.

3. Разрешете ключа на издателя

Издателят е did:web:www.tracepass.eu. Идентификатор did:web се разрешава до документ на този домейн, тук https://www.tracepass.eu/.well-known/did.json, който публикува публичния ключ под kid от заглавката. Подписът свързва credential с контрола върху домейна.

4. Проверете подписа

Всеки от тези примери изтегля ключа и проверява подписа ES256:

javascript
// npm install jose
import { readFileSync } from "node:fs";
import { decodeProtectedHeader, importJWK, jwtVerify } from "jose";

const jws = readFileSync("credential.jwt", "utf8").trim();
const { kid } = decodeProtectedHeader(jws); // did:web:www.tracepass.eu#key-1
const did = kid.split("#")[0];
// did:web:<host> resolves to https://<host>/.well-known/did.json
const doc = await (await fetch(`https://${did.slice("did:web:".length)}/.well-known/did.json`)).json();
const method = doc.verificationMethod.find((m) => m.id === kid);
const { payload } = await jwtVerify(jws, await importJWK(method.publicKeyJwk, "ES256"), { typ: "vc+jwt" });
console.log("Verified. Issuer:", payload.issuer.id, "Product:", payload.credentialSubject.id);
python
# pip install "pyjwt[crypto]" requests
import jwt, requests

token = open("credential.jwt").read().strip()
kid = jwt.get_unverified_header(token)["kid"]  # did:web:www.tracepass.eu#key-1
did = kid.split("#")[0]
# did:web:<host> resolves to https://<host>/.well-known/did.json
doc = requests.get(f"https://{did.removeprefix('did:web:')}/.well-known/did.json").json()
jwk = next(m["publicKeyJwk"] for m in doc["verificationMethod"] if m["id"] == kid)
claims = jwt.decode(token, jwt.PyJWK(jwk).key, algorithms=["ES256"])
print("Verified. Issuer:", claims["issuer"]["id"], "Product:", claims["credentialSubject"]["id"])

Credential, променен след подписването дори с един символ, не минава проверката на подписа.

5. Проверете формата (по избор)

За да потвърдите, че credential следва UNTP 0.7.0, валидирайте го спрямо официалната схема на UNTP:

python
# pip install jsonschema requests "pyjwt[crypto]"
import jwt, requests
from jsonschema import Draft202012Validator

token = open("credential.jwt").read().strip()
credential = jwt.decode(token, options={"verify_signature": False})  # verify first, as above
for claim in ("iss", "sub", "iat"):
    credential.pop(claim, None)  # JWT claims, not part of the credential
schema = requests.get("https://untp.unece.org/artefacts/schema/v0.7.0/dpp/DigitalProductPassport.json").json()
errors = [e.message for e in Draft202012Validator(schema).iter_errors(credential)]
print("UNTP 0.7.0 schema errors:", errors or "none")

UNTP изисква и идентификатора на производственото съоръжение и държавата на производство. Credential ги съдържа, когато паспортът ги записва, и иначе ги пропуска, така че е напълно валиден спрямо схемата на UNTP само за такива паспорти. Демо паспортът се валидира без грешки.

Какво доказва валидният подпис

Че TracePass е издал точно тези данни за тази версия на паспорта и никой не ги е променил оттогава. Това е подпис did:web: той доказва контрол върху tracepass.eu, толкова силно, колкото HTTPS. Не е квалифициран електронен печат по eIDAS.

Обхваща само публичния изглед на паспорта, никога полета с ограничен или служебен достъп, затова не е пълният правен запис. Списък за отмяна още няма: копие, което някой вече притежава, продължава да се проверява успешно и след спиране на паспорта, затова проверявайте текущия статус в живия паспорт.