Przewodnik wprowadzający dla rejestratorów weryfikatorów

Przegląd

W tej sekcji opisujemy krok po kroku proces rejestracji w usłudze tożsamości Portfela Google dla rejestratorów weryfikatorów.

Jako rejestrator weryfikujący (np. firma IDV weryfikująca w imieniu innych podmiotów) pełnisz funkcję własnego urzędu certyfikacji, podpisując żądania tożsamości dla podrzędnych podmiotów RP, którymi zarządzasz.

Proces wdrażania

Krok 1. Prześlij formularz zgłoszeniowy, certyfikaty główne i zaakceptuj Warunki korzystania z usługi

Wypełnij i prześlij formularz rejestracyjny weryfikatora. W tym formularzu podasz certyfikaty główne piaskownicy i środowiska produkcyjnego. Przesyłając ten formularz rejestracyjny, formalnie akceptujesz Warunki korzystania z usługi rejestratora Portfela Google Verifier.

Krok 2. Zaufanie i testowanie w piaskownicy

Po przesłaniu formularza Google doda certyfikat główny piaskownicy do magazynu zaufanych certyfikatów piaskownicy Portfela Google i powiadomi Cię o tym. Następnie możesz rozpocząć testowanie integracji w piaskownicy za pomocą certyfikatów podpisanych przez główny certyfikat piaskownicy.

Krok 3. Nagraj film demonstracyjny E2E

Po zakończeniu testowania w środowisku piaskownicy nagraj kompleksowe filmy demonstracyjne przedstawiające proces weryfikacji w przypadku pierwszej (1.) instytucji ufającej i prześlij je do Google.

  • Wymagania dotyczące filmów:
    • Nagrywaj demonstracje zarówno w przypadku przepływów hostowanych przez weryfikatora (hostowanych samodzielnie), jak i hostowanych przez sprzedawcę (hostowanych przez dostawcę tożsamości).
    • W filmach używaj rzeczywistych komponentów wyświetlanych sprzedawcy (nazwa, logo, adres URL Warunków korzystania z usługi) i komponentów wyświetlanych agregatora.
    • Wyraźnie pokaż interfejs i ekrany, które uruchamiają proces weryfikacji.

Krok 4. Zatwierdzenie i zaufanie do głównego certyfikatu produkcyjnego

Po otrzymaniu kompleksowych filmów demonstracyjnych Google rozpoczyna proces sprawdzania i zatwierdzania filmów, a równolegle uruchamia proces zaufania do głównego certyfikatu produkcyjnego. Po zakończeniu i zatwierdzeniu obu procesów możesz rozpocząć wdrażanie usługi dla swoich klientów końcowych.

Krok 5. Ciągłe wdrażanie dostawców tożsamości

W przypadku każdego podmiotu RP, z którym podpiszesz umowę, musisz:

  • Poinformuj Google: użyj formularza rejestracji klienta weryfikatora, aby powiadomić Google o nowym dostawcy tożsamości i jego zamierzonym zastosowaniu.
  • Skonfiguruj metadane: wypełnij informacje wyświetlane przez dostawcę tożsamości (nazwa, logo, adres URL polityki prywatności) i ustaw w certyfikacie globalnie unikalną nazwę wyróżniającą (podmiot).

Specyfikacja techniczna

A. Profil certyfikatu

Żądania muszą być podpisane standardowymi certyfikatami X.509 v3 wygenerowanymi przy użyciu algorytmu P-256 / ECDSA i zawierającymi niestandardowe rozszerzenie Google:

  • Identyfikator obiektu niestandardowego rozszerzenia: 1.3.6.1.4.1.11129.10.1
  • Krytyczność: niekrytyczna.
  • Treść: identyfikator SHA256 elementu RelyingPartyMetadataBytes zakodowany w formacie ASN.1 OCTET STRING.

B. Schemat metadanych (CBOR)

Metadane muszą być zakodowane w formacie CBOR.

; in CDDL for CBOR encoding
; schemaVersion = "v1"

RelyingPartyMetadataBytes = #6.24(bstr .cbor RelyingPartyMetadata)


RelyingPartyMetadata = {
  "schema_version": tstr,
  "display": DisplayInfo,
  "aggregator_info": DisplayInfo  ; Optional: include to show your branding alongside the RP
}

DisplayInfo = {
  "display_name": tstr,
  "logo_uri": tstr,             ; See brand guidelines link in following paragraph
  "privacy_policy_uri": tstr
}

logo_uri musi być zgodny z wytycznymi dotyczącymi marki Portfela Google.

C. Integracja OpenID4VP

Podczas formatowania podpisanego żądania poświadczeń OpenID4VP umieść metadane zakodowane w formacie base64url w polu gw_rp_metadata_bytes w obiekcie client_metadata (jak pokazano w przykładowym kodzie żądania w następnej sekcji).

Zgodność ze standardami i unieważnienie

  • Monitorowanie nadużyć: Google monitoruje złośliwą aktywność w ramach programu RP i powiadamia Cię o wykrytych nadużyciach.
  • Szybkie odwoływanie: musisz szybko odwoływać certyfikaty w przypadku podmiotów RP, które dopuszczają się nadużyć, i publikować zaktualizowaną listę odwołanych certyfikatów (CRL).
  • Audyt: Google prowadzi anonimizowane dzienniki, aby mieć pewność, że żądania RP są zgodne z zarejestrowanymi przypadkami użycia.

Dalsze kroki

Aby rozpocząć proces wdrażania jako rejestrator weryfikujący, wypełnij i prześlij formularz zgłoszenia rejestratora weryfikującego. Aby zarejestrować kolejnych klientów niższego szczebla, użyj formularza rejestracji klienta rejestrującego weryfikatorów.

Odpowiedzi na najczęstsze pytania dotyczące wdrażania i integracji znajdziesz w tym artykule.

Szczegóły integracji rejestratora weryfikatora

W sekcji poniżej znajdziesz szczegóły techniczne integracji rejestratorów weryfikatorów z interfejsem Digital Credentials API (w tym formatowanie żądań, szyfrowanie żądań, wywoływanie interfejsu API, weryfikowanie odpowiedzi i wdrażanie dowodów z zerową wiedzą).

Obsługiwane formaty i możliwości

Portfel Google obsługuje cyfrowe dokumenty tożsamości oparte na ISO mdoc.

Formatowanie żądania

Aby poprosić o dane uwierzytelniające z dowolnego portfela, musisz sformatować żądanie za pomocą OpenID4VP. Możesz poprosić o konkretne dane logowania lub o kilka rodzajów danych logowania w jednym obiekcie dcql_query.

Przykład żądania JSON

Oto przykładowe żądanie mdoc requestJson dotyczące uzyskania dokumentów tożsamości z dowolnego portfela na urządzeniu z Androidem lub w internecie.

{
      "requests" : [
        {
          "protocol": "openid4vp-v1-signed",
          "data": {<signed_credential_request>} // This is an object, shouldn't be a string.
        }
      ]
}

Żądanie szyfrowania

W client_metadata znajduje się publiczny klucz szyfrowania dla każdego żądania. Musisz przechowywać klucze prywatne dla każdego żądania i używać ich do uwierzytelniania i autoryzowania tokena otrzymanego z aplikacji portfela.

Zintegrowane metadane OpenID4VP

Podczas formatowania żądania danych logowania musisz umieścić pole gw_rp_metadata_bytes w obiekcie client_metadata (jak pokazano w przykładowym kodzie żądania poniżej). To pole zawiera metadane podmiotu ufającego zakodowane w formacie Base64URL, które są wymagane przez Portfel Google do weryfikacji Twojej tożsamości i wyświetlania użytkownikowi Twojej marki.

Parametr credential_request w requestJson zawiera te pola:

Określony certyfikat

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "cred1",
        "format": "mso_mdoc",
        "meta": {
          // Use org.iso.18013.5.1.mDL for mDL,
          // com.google.wallet.idcard.1 for ID pass, or
          // org.iso.23220.photoid.1 for ID pass (using photo ID document type)
          "doctype_value": "org.iso.18013.5.1.mDL"
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
  },
  "client_metadata": {
    "jwks": {
      "keys": [ // sample request encryption key
        {
          "kty": "EC",
          "crv": "P-256",
          "x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
          "y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
          "use": "enc",
          "kid" : "1",  // This is required
          "alg" : "ECDH-ES",  // This is required
        }
      ]
    },
    "vp_formats_supported": {
      "mso_mdoc": {
        "deviceauth_alg_values": [
          -7
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Dowolny kwalifikujący się certyfikat

Oto przykładowe żądanie dotyczące mDL, cyfrowego dokumentu tożsamości i cyfrowego dokumentu tożsamości (z użyciem dokumentu tożsamości ze zdjęciem). Użytkownik może skorzystać z jednej z tych opcji.

{
  "response_type": "vp_token",
  "response_mode": "dc_api.jwt", // change this to dc_api if you want to demo with a non encrypted response.
  "nonce": "1234",
  "dcql_query": {
    "credentials": [
      {
        "id": "mdl-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.18013.5.1.mDL"
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      },
      {  // Credential type 2: ID pass
        "id": "id_pass-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "com.google.wallet.idcard.1"
        },
        "claims": [
          {
            "path": [
              "org.iso.18013.5.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.18013.5.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      },
      {  // Credential type 3: ID pass (using photo ID document type)
        "id": "photo_id-request",
        "format": "mso_mdoc",
        "meta": {
          "doctype_value": "org.iso.23220.photoid.1"
        },
        "claims": [
          {
            "path": [
              "org.iso.23220.1",
              "family_name"
            ],
            "intent_to_retain": false // set this to true if you are saving the value of the field
          },
          {
            "path": [
              "org.iso.23220.1",
              "given_name"
            ],
            "intent_to_retain": false
          },
          {
            "path": [
              "org.iso.23220.1",
              "age_over_18"
            ],
            "intent_to_retain": false
          }
        ]
      }
    ]
    credential_sets : [
      {
        "options": [
          [ "mdl-request" ],
          [ "id_pass-request" ],
          [ "photo_id-request" ]
        ]
      }
    ]
  },
  "client_metadata": {
    "jwks": {
      "keys": [ // sample request encryption key
        {
          "kty": "EC",
          "crv": "P-256",
          "x": "pDe667JupOe9pXc8xQyf_H03jsQu24r5qXI25x_n1Zs",
          "y": "w-g0OrRBN7WFLX3zsngfCWD3zfor5-NLHxJPmzsSvqQ",
          "use": "enc",
          "kid" : "1",  // This is required
          "alg" : "ECDH-ES",  // This is required
        }
      ]
    },
    "vp_formats_supported": {
      "mso_mdoc": {
        "deviceauth_alg_values": [
          -7
        ],
        "issuerauth_alg_values": [
          -7
        ]
      }
    },
    "gw_rp_metadata_bytes": "<base64url encoded metadata string>"
  }
}

Możesz poprosić o dowolną liczbę obsługiwanych atrybutów z dowolnego dokumentu tożsamości przechowywanego w Portfelu Google.

Podpisane żądania

Podpisane żądania (żądania autoryzacji zabezpieczone tokenem JWT) zawierają żądanie prezentacji weryfikowalnej w tokenie sieciowym JSON (JWT) podpisanym kryptograficznie przy użyciu infrastruktury PKI. Zapewnia to integralność żądania i potwierdza Twoją tożsamość w Portfelu Google.

Wymagania wstępne

Zanim wprowadzisz zmiany w kodzie w przypadku podpisanych żądań, upewnij się, że masz:

  • Klucz prywatny: do podpisania żądania potrzebujesz klucza prywatnego (np. krzywej eliptycznej ES256), którym zarządzasz na swoim serwerze.
  • Certyfikat: potrzebujesz standardowego certyfikatu X.509 pochodzącego z pary kluczy.
  • Rejestracja: upewnij się, że Twój certyfikat publiczny jest zarejestrowany w Portfelu Google.

Logika tworzenia prośby

Aby utworzyć żądanie, musisz użyć klucza prywatnego i zawinąć ładunek w JWS.

def construct_openid4vp_request(
    doctypes: list[str],
    requested_fields: list[dict],
    nonce_base64: str,
    jwe_encryption_public_jwk: jwk.JWK,
    is_zkp_request: bool,
    is_signed_request: bool,
    state: dict,
    origin: str
) -> dict:

    # ... [Existing logic to build 'presentation_definition' and basic 'request_payload'] ...

    # ------------------------------------------------------------------
    # SIGNED REQUEST IMPLEMENTATION (JAR)
    # ------------------------------------------------------------------
    if is_signed_request:
        try:
            # 1. Load the Verifier's Certificate
            # We must load the PEM string into a cryptography x509 object
            verifier_cert_obj = x509.load_pem_x509_certificate(
                CERTIFICATE.encode('utf-8'),
                backend=default_backend()
            )

            # 2. Calculate Client ID (x509_hash)
            # We calculate the SHA-256 hash of the DER-encoded certificate.
            cert_der = verifier_cert_obj.public_bytes(serialization.Encoding.DER)
            verifier_fingerprint_bytes = hashlib.sha256(cert_der).digest()

            # Create a URL-safe Base64 hash (removing padding '=')
            verifier_fingerprint_b64 = base64.urlsafe_b64encode(verifier_fingerprint_bytes).decode('utf-8').rstrip("=")

            # Format the client_id as required by the spec
            client_id = f'x509_hash:{verifier_fingerprint_b64}'

            # 3. Update Request Payload with JAR specific fields
            request_payload["client_id"] = client_id

            # Explicitly set expected origins to prevent relay attacks
            # Format for android origin: origin = android:apk-key-hash:<base64SHA256_ofAppSigningCert>
            # Format for web origin: origin = <origin_url>
            if origin:
                request_payload["expected_origins"] = [origin]

            # 4. Create Signed JWT (JWS)
            # Load the signing private key
            signing_key = jwk.JWK.from_pem(PRIVATE_KEY.encode('utf-8'))

            # Initialize JWS with the JSON payload
            jws_token = jws.JWS(json.dumps(request_payload).encode('utf-8'))

            # Construct the JOSE Header
            # 'x5c' (X.509 Certificate Chain) is critical: it allows the wallet
            # to validate your key against the one registered in the console.
            x5c_value = base64.b64encode(cert_der).decode('utf-8')

            protected_header = {
                "alg": "ES256",                 # Algorithm (e.g., ES256 or RS256)
                "typ": "oauth-authz-req+jwt",   # Standard type for JAR
                "kid": "1",                     # Key ID
                "x5c": [x5c_value]              # Embed the certificate
            }

            # Sign the token
            jws_token.add_signature(
                key=signing_key,
                alg=None,
                protected=json_encode(protected_header)
            )

            # 5. Return the Request Object
            # Instead of returning the raw JSON, we return the signed JWT string
            # under the 'request' key.
            return {"request": jws_token.serialize(compact=True)}

        except Exception as e:
            print(f"Error signing OpenID4VP request: {e}")
            return None

    # ... [Fallback for unsigned requests] ...
    return request_payload

Wywoływanie interfejsu API

Całe żądanie do interfejsu API powinno być generowane po stronie serwera. W zależności od platformy wygenerowany plik JSON zostanie przekazany do interfejsów API platformy.

W aplikacji (Android)

Aby poprosić o dane logowania w aplikacjach na Androida:

Aktualizowanie zależności

W pliku build.gradle projektu zaktualizuj zależności, aby używać usługi Credential Manager (wersja beta):

dependencies {
    implementation("androidx.credentials:credentials:1.5.0-beta01")
    implementation("androidx.credentials:credentials-play-services-auth:1.5.0-beta01")
}

Konfigurowanie Menedżera danych logowania

Aby skonfigurować i zainicjować obiekt CredentialManager, dodaj logikę podobną do tej:

// Use your app or activity context to instantiate a client instance of CredentialManager.
val credentialManager = CredentialManager.create(context)

Żądanie atrybutów tożsamości

Zamiast określać poszczególne parametry żądań dotyczących tożsamości, aplikacja podaje je wszystkie razem jako ciąg JSON w parametrze CredentialOption. Menedżer danych logowania przekazuje ten ciąg znaków JSON do dostępnych portfeli cyfrowych bez sprawdzania jego zawartości. Każdy portfel jest następnie odpowiedzialny za:<ul><li> parsowanie ciągu JSON w celu zrozumienia żądania tożsamości; – określenie, które z zapisanych danych logowania spełniają żądanie (jeśli takie istnieją);

Zalecamy partnerom tworzenie żądań na serwerze nawet w przypadku integracji z aplikacjami na Androida.

Użyjesz requestJson z sekcji Format żądania jako request w wywołaniu funkcji GetDigitalCredentialOption().

// The request in the JSON format to conform with
// the JSON-ified Digital Credentials API request definition.
val requestJson = generateRequestFromServer()
val digitalCredentialOption =
    GetDigitalCredentialOption(requestJson = requestJson)

// Use the option from the previous step to build the `GetCredentialRequest`.
val getCredRequest = GetCredentialRequest(
    listOf(digitalCredentialOption)
)

coroutineScope.launch {
    try {
        val result = credentialManager.getCredential(
            context = activityContext,
            request = getCredRequest
        )
        verifyResult(result)
    } catch (e : GetCredentialException) {
        handleFailure(e)
    }
}

Obsługa odpowiedzi dotyczącej danych logowania

Gdy otrzymasz odpowiedź z portfela, sprawdź, czy jest ona prawidłowa i zawiera odpowiedź credentialJson.

// Handle the successfully returned credential.
fun verifyResult(result: GetCredentialResponse) {
    val credential = result.credential
    when (credential) {
        is DigitalCredential -> {
            val responseJson = credential.credentialJson
            validateResponseOnServer(responseJson) // make a server call to validate the response
        }
        else -> {
            // Catch any unrecognized credential type here.
            Log.e(TAG, "Unexpected type of credential ${credential.type}")
        }
    }
}

// Handle failure.
fun handleFailure(e: GetCredentialException) {
  when (e) {
        is GetCredentialCancellationException -> {
            // The user intentionally canceled the operation and chose not
            // to share the credential.
        }
        is GetCredentialInterruptedException -> {
            // Retry-able error. Consider retrying the call.
        }
        is NoCredentialException -> {
            // No credential was available.
        }
        else -> Log.w(TAG, "Unexpected exception type ${e::class.java}")
    }
}

Odpowiedź credentialJson zawiera zaszyfrowany identityToken (JWT) zdefiniowany przez W3C. Za przygotowanie tej odpowiedzi odpowiada aplikacja Portfel.

Przykład:

{
  "protocol" : "openid4vp-v1-signed",
  "data" : {
    <encrpted_response>
  }
}

Przekaż tę odpowiedź z powrotem na serwer, aby potwierdzić jej autentyczność. Instrukcje weryfikacji odpowiedzi dotyczącej danych logowania

Sieć

Aby poprosić o dane logowania za pomocą interfejsu Digital Credentials API w Chrome lub innych obsługiwanych przeglądarkach, wyślij to żądanie.

const credentialResponse = await navigator.credentials.get({
          digital : {
          requests : [
            {
              protocol: "openid4vp-v1-signed",
              data: {<credential_request>} // This is an object, shouldn't be a string.
            }
          ]
        }
      })

Wyślij odpowiedź z tego interfejsu API z powrotem na serwer, aby zweryfikować odpowiedź dotyczącą danych logowania.

Weryfikacja odpowiedzi

Gdy portfel zwróci zaszyfrowany token identityToken (JWT), musisz przeprowadzić ścisłą weryfikację po stronie serwera, zanim zaufasz danym.

Odszyfrowanie odpowiedzi

Aby odszyfrować JWE, użyj klucza prywatnego odpowiadającego kluczowi publicznemu wysłanemu w żądaniu client_metadata. Daje to vp_token.

Przykład w Pythonie:

  from jwcrypto import jwe, jwk

  # Retrieve the Private Key from Datastore
  reader_private_jwk = jwk.JWK.from_json(jwe_private_key_json_str)
  # Save public key thumbprint for session transcript
  encryption_public_jwk_thumbprint = reader_private_jwk.thumbprint()


  # Decrypt the JWE encrypted response from Google Wallet
  jwe_object = jwe.JWE()
  jwe_object.deserialize(encrypted_jwe_response_from_wallet)
  jwe_object.decrypt(reader_private_jwk)
  decrypted_payload_bytes = jwe_object.payload
  decrypted_data = json.loads(decrypted_payload_bytes)

decrypted_data spowoduje utworzenie vp_token JSON zawierającego dane logowania.

  {
    "vp_token":
    {
      "cred1": ["<base64UrlNoPadding_encoded_credential>"] // This applies to OpenID4VP 1.0 spec.
    }
  }
  1. Utwórz transkrypcję sesji

    Następnym krokiem jest utworzenie SessionTranscript zgodnie z normą ISO/IEC 18013-5:2021 z strukturą przekazywania specyficzną dla Androida lub internetu:

    SessionTranscript = [
      null,                // DeviceEngagementBytes not available
      null,                // EReaderKeyBytes not available
      [
        "OpenID4VPDCAPIHandover",
        AndroidHandoverDataBytes   // BrowserHandoverDataBytes for Web
      ]
    ]
    

    W przypadku przekazywania w Androidzie i w internecie musisz użyć tej samej liczby jednorazowej, której użyto do wygenerowania parametru credential_request.

    Android Handover

        AndroidHandoverData = [
          origin,             // "android:apk-key-hash:<base64SHA256_ofAppSigningCert>",
          nonce,           // nonce that was used to generate credential request,
          encryption_public_jwk_thumbprint,  // Encryption public key (JWK) Thumbprint
        ]
    
        AndroidHandoverDataBytes = hashlib.sha256(cbor2.dumps(AndroidHandoverData)).digest()
        

    Przekazywanie przeglądarki

        BrowserHandoverData =[
          origin,               // Origin URL
          nonce,               //  nonce that was used to generate credential request
          encryption_public_jwk_thumbprint,  // Encryption public key (JWK) Thumbprint
        ]
    
        BrowserHandoverDataBytes = hashlib.sha256(cbor2.dumps(BrowserHandoverData)).digest()
        

    Za pomocą SessionTranscript należy zweryfikować odpowiedź urządzenia zgodnie z klauzulą 9 normy ISO/IEC 18013-5:2021.

    Weryfikacja obejmuje kilka kroków:

  2. Sprawdź certyfikat wystawcy: wyodrębnij łańcuch certyfikatów podpisu wystawcy z issuerAuth i zweryfikuj go pod kątem zaufanych głównych certyfikatów IACA. Zapoznaj się z obsługiwanymi certyfikatami IACA wydawcy.

  3. Weryfikacja podpisu MSO (18013-5 Section 9.1.2)

  4. Obliczanie i sprawdzanie ValueDigests w przypadku elementów danych (18013-5, sekcja 9.1.2)

  5. Weryfikacja podpisu deviceSignature (sekcja 9.1.3 normy 18013-5)

{
  "version": "1.0",
  "documents": [
    {
      "docType": "org.iso.18013.5.1.mDL",
      "issuerSigned": {
        "nameSpaces": {...}, // contains data elements
        "issuerAuth": [...]  // COSE_Sign1 w/ issuer PK, mso + sig
      },
      "deviceSigned": {
        "nameSpaces": 24(<< {} >>), // empty
        "deviceAuth": {
          "deviceSignature": [...] // COSE_Sign1 w/ device signature
        }
      }
    }
  ],
  "status": 0
}

Weryfikacja wieku z zachowaniem prywatności (ZKP)

Aby obsługiwać dowody zerowej wiedzy (np. weryfikowanie, czy użytkownik ma ukończone 18 lat, bez sprawdzania dokładnej daty urodzenia), zmień format żądania na mso_mdoc_zk i podaj wymaganą konfigurację zk_system_type.

Ogólne omówienie ZKP i jego możliwości znajdziesz w najczęstszych pytaniach.

  ...
  "dcql_query": {
    "credentials": [{
      "id": "cred1",
      "format": "mso_mdoc_zk",
      "meta": {
        "doctype_value": "org.iso.18013.5.1.mDL"
        "zk_system_type": [
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "f88a39e561ec0be02bb3dfe38fb609ad154e98decbbe632887d850fc612fea6f", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 5,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
        {
          "system": "longfellow-libzk-v1",
          "circuit_hash": "137e5a75ce72735a37c8a72da1a8a0a5df8d13365c2ae3d2c2bd6a0e7197c7c6", // This will differ if you need more than 1 attribute.
          "num_attributes": 1, // number of attributes (in claims) this has can support
          "version": 6,
          "block_enc_hash": 4096,
          "block_enc_sig": 2945,
        }
       ],
       "verifier_message": "challenge"
      },
     "claims": [{
         ...
      "client_metadata": {
        "jwks": {
          "keys": [ // sample request encryption key
            {
              ...

Otrzymasz z portfela zaszyfrowany dowód o zerowej wiedzy. Możesz zweryfikować ten dowód na podstawie certyfikatów IACA wydawców za pomocą biblioteki longfellow-zk Google.

verifier-service zawiera gotowy do wdrożenia serwer oparty na Dockerze, który umożliwia weryfikację odpowiedzi na podstawie określonych certyfikatów IACA wystawcy.

Możesz zmodyfikować plik certs.pem, aby zarządzać certyfikatami wystawcy IACA, którym chcesz zaufać.

Materiały i pomoc