diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt index 5d19de146..897317d3b 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/DocumentType.kt @@ -243,7 +243,7 @@ class DocumentType private constructor( } list } - VcRequest(claims) + VcRequest(vcBuilder!!.type, claims) } sampleRequests.add(DocumentWellKnownRequest(id, displayName, mdocRequest, vcRequest)) } diff --git a/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcRequest.kt b/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcRequest.kt index 273ab7b46..e5fd31c93 100644 --- a/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcRequest.kt +++ b/identity/src/commonMain/kotlin/com/android/identity/documenttype/VcRequest.kt @@ -3,8 +3,12 @@ package com.android.identity.documenttype /** * A class representing a request for claims. * + * @param vct the verifiable credential type, as defined in section 3.2.2.1.1. + * "Verifiable Credential Type - vct Claim" of IETF + * [SD-JWT-based Verifiable Credentials (SD-JWT VC)](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-sd-jwt-vc-05) * @param claimsToRequest the claims to request. */ data class VcRequest( + val vct: String, val claimsToRequest: List ) diff --git a/server/src/main/java/com/android/identity/wallet/server/VerifierServlet.kt b/server/src/main/java/com/android/identity/wallet/server/VerifierServlet.kt index 9a8df11f4..1da6290ec 100644 --- a/server/src/main/java/com/android/identity/wallet/server/VerifierServlet.kt +++ b/server/src/main/java/com/android/identity/wallet/server/VerifierServlet.kt @@ -1382,6 +1382,14 @@ private fun sdjwtCalcPresentationDefinition( format.put("jwt_vc", algContainer) val fields = JSONArray() + val vctArray = JSONArray() + vctArray.add("\$.vct") + val vctFilter = JSONObject() + vctFilter.put("const", request.vcRequest!!.vct) + val vctField = JSONObject() + vctField.put("path", vctArray) + vctField.put("filter", vctFilter) + fields.add(vctField) for (claim in request.vcRequest!!.claimsToRequest) { var array = JSONArray() array.add("\$.${claim.identifier}") diff --git a/wallet/src/main/java/com/android/identity_credential/wallet/presentation/OpenID4VPPresentationActivity.kt b/wallet/src/main/java/com/android/identity_credential/wallet/presentation/OpenID4VPPresentationActivity.kt index e23e986b7..ec70e8505 100644 --- a/wallet/src/main/java/com/android/identity_credential/wallet/presentation/OpenID4VPPresentationActivity.kt +++ b/wallet/src/main/java/com/android/identity_credential/wallet/presentation/OpenID4VPPresentationActivity.kt @@ -343,7 +343,12 @@ class OpenID4VPPresentationActivity : FragmentActivity() { val documentConfiguration = document.documentConfiguration return when (credentialFormat) { CredentialFormat.MDOC_MSO -> documentConfiguration.mdocConfiguration?.docType == docType - CredentialFormat.SD_JWT_VC -> documentConfiguration.sdJwtVcDocumentConfiguration != null + CredentialFormat.SD_JWT_VC -> + if (docType == "") { + documentConfiguration.sdJwtVcDocumentConfiguration != null + } else { + documentConfiguration.sdJwtVcDocumentConfiguration?.vct == docType + } } } @@ -479,7 +484,25 @@ class OpenID4VPPresentationActivity : FragmentActivity() { // https://identity.foundation/presentation-exchange/spec/v2.0.0/#input-descriptor // val inputDescriptorObj = inputDescriptors[0].jsonObject - val docType = inputDescriptorObj["id"]!!.toString().run { substring(1, this.length - 1) } + val docType = if (credentialFormat == CredentialFormat.MDOC_MSO) { + inputDescriptorObj["id"]!!.toString().run { substring(1, this.length - 1) } + } else { + try { + var vct = "" + val constraints = inputDescriptorObj["constraints"]!!.jsonObject + for (field in constraints["fields"]!!.jsonArray) { + if (field.jsonObject["path"]!!.jsonArray[0].toString() == "\"\$.vct\"") { + val vctField = field.jsonObject + val filter = vctField["filter"]!!.jsonObject + vct = filter["const"]!!.toString().run { substring(1, this.length - 1) } + } + } + vct + } catch (e: NullPointerException) { + Logger.d(TAG, "Error: Could not find const filter field: ${e.message}") + "" + } + } val documentRequest = formatAsDocumentRequest(inputDescriptorObj) val document = firstMatchingDocument(credentialFormat, docType)