@@ -25,6 +25,7 @@ import id.walt.oid4vc.data.OpenId4VPProfile
25
25
import id.walt.oid4vc.data.ProofType
26
26
import id.walt.sdjwt.SDField
27
27
import id.walt.sdjwt.SDMap
28
+ import id.walt.sdjwt.SDisclosure
28
29
import id.walt.sdjwt.utils.Base64Utils.encodeToBase64Url
29
30
import id.walt.verifier.oidc.RequestedCredential
30
31
import id.walt.webwallet.db.models.WalletCredential
@@ -49,6 +50,9 @@ import kotlinx.coroutines.runBlocking
49
50
import kotlinx.serialization.ExperimentalSerializationApi
50
51
import kotlinx.serialization.decodeFromByteArray
51
52
import kotlinx.serialization.json.*
53
+ import sun.font.StrikeCache
54
+ import kotlin.io.encoding.Base64
55
+ import kotlin.io.encoding.ExperimentalEncodingApi
52
56
import kotlin.test.assertEquals
53
57
import kotlin.test.assertNotEquals
54
58
import kotlin.test.assertNotNull
@@ -326,6 +330,7 @@ class ExchangeExternalSignatures {
326
330
)
327
331
testOID4VP(openbadgeSdJwtPresentationRequest)
328
332
testOID4VP(openbadgeSdJwtPresentationRequest, true )
333
+ testOID4VP(openbadgeSdJwtPresentationRequest, true , true )
329
334
clearWalletCredentials()
330
335
}
331
336
@@ -338,6 +343,7 @@ class ExchangeExternalSignatures {
338
343
)
339
344
testOID4VPSdJwtVc()
340
345
testOID4VPSdJwtVc(true )
346
+ testOID4VPSdJwtVc(true , true )
341
347
clearWalletCredentials()
342
348
testPreAuthorizedOID4VCI(
343
349
useOptionalParameters = false ,
@@ -490,6 +496,7 @@ class ExchangeExternalSignatures {
490
496
private suspend fun testOID4VP (
491
497
presentationRequest : String ,
492
498
addDisclosures : Boolean = false,
499
+ forgeDisclosures : Boolean = false,
493
500
) {
494
501
lateinit var presentationRequestURL: String
495
502
lateinit var verificationID: String
@@ -522,18 +529,22 @@ class ExchangeExternalSignatures {
522
529
presentationRequest = presentationRequestURL,
523
530
selectedCredentialIdList = matchedCredentialList.map { it.id },
524
531
disclosures = if (addDisclosures) matchedCredentialList.filter { it.disclosures != null }.associate {
525
- Pair (it.id, listOf (it.disclosures!! ))
532
+ Pair (it.id, listOf (
533
+ if (forgeDisclosures) forgeSDisclosureString(it.disclosures!! ) else it.disclosures!!
534
+ ))
526
535
} else null ,
527
536
)
528
537
println (prepareRequest)
529
538
response = client.post(" /wallet-api/wallet/$walletId /exchange/external_signatures/presentation/prepare" ) {
530
539
setBody(prepareRequest)
531
540
}.expectSuccess()
532
541
val prepareResponse = response.body<PrepareOID4VPResponse >()
533
- client.post(" /wallet-api/wallet/$walletId /exchange/external_signatures/presentation/submit" ) {
542
+ val submitResponse = client.post(" /wallet-api/wallet/$walletId /exchange/external_signatures/presentation/submit" ) {
534
543
setBody(SubmitOID4VPRequest .build(prepareResponse,
535
544
disclosures = if (addDisclosures) matchedCredentialList.filter { it.disclosures != null }.associate {
536
- Pair (it.id, listOf (it.disclosures!! ))
545
+ Pair (it.id, listOf (
546
+ if (forgeDisclosures) forgeSDisclosureString(it.disclosures!! ) else it.disclosures!!
547
+ ))
537
548
} else null ,
538
549
w3cJwtVpProof = prepareResponse.w3CJwtVpProofParameters?.let { params ->
539
550
holderKey.signJws(
@@ -550,12 +561,16 @@ class ExchangeExternalSignatures {
550
561
)
551
562
})
552
563
)
553
- }.expectSuccess()
564
+ }
565
+ if (! forgeDisclosures)
566
+ submitResponse.expectSuccess()
567
+ else
568
+ submitResponse.expectFailure()
554
569
verifierSessionApi.get(verificationID) { sessionInfo ->
555
570
assert (sessionInfo.tokenResponse?.vpToken?.jsonPrimitive?.contentOrNull?.expectLooksLikeJwt() != null ) { " Received no valid token response!" }
556
571
assert (sessionInfo.tokenResponse?.presentationSubmission != null ) { " should have a presentation submission after submission" }
557
572
558
- assert (sessionInfo.verificationResult == true ) { " overall verification should be valid " }
573
+ assert (sessionInfo.verificationResult == ! forgeDisclosures ) { " overall verification should be ${ ! forgeDisclosures} " }
559
574
sessionInfo.policyResults.let {
560
575
require(it != null ) { " policyResults should be available after running policies" }
561
576
assert (it.size > 1 ) { " no policies have run" }
@@ -565,6 +580,7 @@ class ExchangeExternalSignatures {
565
580
566
581
private suspend fun testOID4VPSdJwtVc (
567
582
addDisclosures : Boolean = false,
583
+ forgeDisclosures : Boolean = false,
568
584
) {
569
585
lateinit var presentationRequestURL: String
570
586
lateinit var resolvedPresentationRequestURL: String
@@ -611,18 +627,22 @@ class ExchangeExternalSignatures {
611
627
presentationRequest = presentationRequestURL,
612
628
selectedCredentialIdList = matchedCredentialList.map { it.id },
613
629
disclosures = if (addDisclosures) matchedCredentialList.filter { it.disclosures != null }.associate {
614
- Pair (it.id, listOf (it.disclosures!! ))
630
+ Pair (it.id, listOf (
631
+ if (forgeDisclosures) forgeSDisclosureString(it.disclosures!! ) else it.disclosures!!
632
+ ))
615
633
} else null ,
616
634
)
617
635
println (prepareRequest)
618
636
response = client.post(" /wallet-api/wallet/$walletId /exchange/external_signatures/presentation/prepare" ) {
619
637
setBody(prepareRequest)
620
638
}.expectSuccess()
621
639
val prepareResponse = response.body<PrepareOID4VPResponse >()
622
- client.post(" /wallet-api/wallet/$walletId /exchange/external_signatures/presentation/submit" ) {
640
+ val submitResponse = client.post(" /wallet-api/wallet/$walletId /exchange/external_signatures/presentation/submit" ) {
623
641
setBody(SubmitOID4VPRequest .build(prepareResponse,
624
642
disclosures = if (addDisclosures) matchedCredentialList.filter { it.disclosures != null }.associate {
625
- Pair (it.id, listOf (it.disclosures!! ))
643
+ Pair (it.id, listOf (
644
+ if (forgeDisclosures) forgeSDisclosureString(it.disclosures!! ) else it.disclosures!!
645
+ ))
626
646
} else null ,
627
647
w3cJwtVpProof = prepareResponse.w3CJwtVpProofParameters?.let { params ->
628
648
holderKey.signJws(
@@ -639,12 +659,16 @@ class ExchangeExternalSignatures {
639
659
)
640
660
})
641
661
)
642
- }.expectSuccess()
662
+ }
663
+ if (! forgeDisclosures)
664
+ submitResponse.expectSuccess()
665
+ else
666
+ submitResponse.expectFailure()
643
667
verifierSessionApi.get(verificationID) { sessionInfo ->
644
668
// assert(sessionInfo.tokenResponse?.vpToken?.jsonPrimitive?.contentOrNull?.expectLooksLikeJwt() != null) { "Received no valid token response!" }
645
669
assert (sessionInfo.tokenResponse?.presentationSubmission != null ) { " should have a presentation submission after submission" }
646
670
647
- assert (sessionInfo.verificationResult == true ) { " overall verification should be valid " }
671
+ assert (sessionInfo.verificationResult == ! forgeDisclosures ) { " overall verification should be ${ ! forgeDisclosures} " }
648
672
sessionInfo.policyResults.let {
649
673
require(it != null ) { " policyResults should be available after running policies" }
650
674
assert (it.size > 1 ) { " no policies have run" }
@@ -748,4 +772,15 @@ class ExchangeExternalSignatures {
748
772
}
749
773
}
750
774
}
775
+
776
+ @OptIn(ExperimentalEncodingApi ::class )
777
+ fun forgeSDisclosureString (disclosures : String ): String {
778
+ return disclosures.split(" ~" ).filter { it.isNotEmpty() }.map { SDisclosure .parse(it) }.map { disclosure ->
779
+ Base64 .UrlSafe .encode(buildJsonArray {
780
+ add(disclosure.salt)
781
+ add(disclosure.key)
782
+ add(JsonPrimitive (" <forged>" ))
783
+ }.toString().encodeToByteArray()).trimEnd(' =' )
784
+ }.joinToString(" ~" )
785
+ }
751
786
}
0 commit comments