Skip to content

Commit 5d65949

Browse files
authored
Align mdoc response with oid4vp1.0 (#394) (#426)
* Introduce the new mDoc presentation structure * Remove Test Dependencies from SdJwtLib * change target framework of core project to net8 * change target framework of mdocLib project to net8 * clean * implemented requested changes * xml comment indendation * move handover types to constants file * revert the Handover union type * fix requested nit --------- (cherry picked from commit bfeaf9b) Signed-off-by: Johannes Tuerk <[email protected]>
1 parent 480c568 commit 5d65949

File tree

9 files changed

+204
-106
lines changed

9 files changed

+204
-106
lines changed

src/WalletFramework.Oid4Vc/Oid4Vci/CredRequest/Implementations/CredentialRequestService.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Text;
22
using LanguageExt;
3+
using Microsoft.IdentityModel.Tokens;
34
using OneOf;
45
using WalletFramework.Core.Cryptography.Abstractions;
56
using WalletFramework.Core.Cryptography.Models;
@@ -69,8 +70,13 @@ await authorizationRequest.Match(
6970
Some: _ =>
7071
{
7172
if (format == Constants.MdocFormat)
72-
sessionTranscript = authorizationRequest.UnwrapOrThrow(new Exception()).ToVpHandover()
73-
.ToSessionTranscript();
73+
{
74+
var handover = OpenId4VpHandover.FromAuthorizationRequest(
75+
authorizationRequest.UnwrapOrThrow(new Exception()),
76+
Option<JsonWebKey>.None);
77+
sessionTranscript = handover.ToSessionTranscript();
78+
}
79+
7480
return Task.CompletedTask;
7581
},
7682
None: async () => await keyId.IfSomeAsync(async id =>

src/WalletFramework.Oid4Vc/Oid4Vp/DcApi/Models/OpenId4VpDcApiHandover.cs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,38 @@
11
using LanguageExt;
2+
using Microsoft.IdentityModel.Tokens;
23
using PeterO.Cbor;
34
using WalletFramework.Core.Cryptography.Models;
5+
using WalletFramework.Core.Functional;
46
using WalletFramework.MdocLib.Device;
57
using WalletFramework.MdocLib.Security;
68
using WalletFramework.MdocLib.Security.Abstractions;
9+
using WalletFramework.Oid4Vc.Oid4Vp.Jwk;
710
using WalletFramework.Oid4Vc.Oid4Vp.Models;
811
using static WalletFramework.Oid4Vc.Oid4Vp.Models.Nonce;
912

1013
namespace WalletFramework.Oid4Vc.Oid4Vp.DcApi.Models;
1114

1215
/// <summary>
13-
/// Represents OpenID4VPDCAPIHandover according to the OpenID4VP specification.
14-
/// Contains a fixed identifier and the SHA-256 hash of OpenID4VPDCAPIHandoverInfo
15-
/// Structure: ["OpenID4VPDCAPIHandover", OpenID4VPDCAPIHandoverInfoHash]
16+
/// Represents OpenID4VPDCAPIHandover according to the OpenID4VP specification.
17+
/// Contains a fixed identifier and the SHA-256 hash of OpenID4VPDCAPIHandoverInfo
18+
/// Structure: ["OpenID4VPDCAPIHandover", OpenID4VPDCAPIHandoverInfoHash]
1619
/// </summary>
1720
public record OpenId4VpDcApiHandover(OpenId4VpDcApiHandoverInfo HandoverInfo) : IHandover
1821
{
1922
/// <summary>
20-
/// Mdoc generated nonce created during handover initialization
23+
/// Mdoc generated nonce created during handover initialization
2124
/// </summary>
2225
public Nonce MdocGeneratedNonce { get; } = GenerateNonce();
23-
24-
/// <summary>
25-
/// Fixed identifier for this handover type
26-
/// </summary>
27-
public const string HandoverTypeIdentifier = "OpenID4VPDCAPIHandover";
2826

2927
/// <summary>
30-
/// Converts the handover to CBOR representation as an array
28+
/// Converts the handover to CBOR representation as an array
3129
/// </summary>
3230
/// <returns>CBOR array containing [identifier, hash]</returns>
3331
public CBORObject ToCbor()
3432
{
3533
var result = CBORObject.NewArray();
36-
37-
result.Add(HandoverTypeIdentifier);
34+
35+
result.Add(HandoverConstants.DcApiHandoverTypeIdentifier);
3836
result.Add(HandoverInfo.ToHash().AsBytes);
3937

4038
return result;
@@ -55,4 +53,16 @@ public SessionTranscript ToSessionTranscript()
5553
);
5654
}
5755

56+
public static OpenId4VpDcApiHandover FromAuthorizationRequest(AuthorizationRequest request, Origin origin, Option<JsonWebKey> verifierPublicKey)
57+
{
58+
var encryptionKey = verifierPublicKey.OnSome(JwkFun.GetThumbprint);
59+
60+
var handoverInfo = new OpenId4VpDcApiHandoverInfo(
61+
origin,
62+
request.Nonce,
63+
encryptionKey
64+
);
65+
66+
return new OpenId4VpDcApiHandover(handoverInfo);
67+
}
5868
}

src/WalletFramework.Oid4Vc/Oid4Vp/DcApi/Models/OpenId4VpDcApiHandoverInfo.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
namespace WalletFramework.Oid4Vc.Oid4Vp.DcApi.Models;
66

77
/// <summary>
8-
/// Represents OpenID4VPDCAPIHandoverInfo according to the OpenID4VP specification.
9-
/// Contains the handover parameters as a CBOR array: [origin, nonce, jwkThumbprint]
8+
/// Represents OpenID4VPDCAPIHandoverInfo according to the OpenID4VP specification.
9+
/// Contains the handover parameters as a CBOR array: [origin, nonce, jwkThumbprint]
1010
/// </summary>
1111
public record OpenId4VpDcApiHandoverInfo(
1212
Origin Origin,
1313
string Nonce,
1414
Option<byte[]> JwkThumbprint)
1515
{
1616
/// <summary>
17-
/// Converts the handover info to CBOR representation as an array
17+
/// Converts the handover info to CBOR representation as an array
1818
/// </summary>
1919
/// <returns>CBOR array containing [origin, nonce, jwkThumbprint]</returns>
2020
public CBORObject ToCbor()
@@ -33,13 +33,13 @@ public CBORObject ToCbor()
3333
}
3434

3535
/// <summary>
36-
/// Encodes the handover info as CBOR bytes
36+
/// Encodes the handover info as CBOR bytes
3737
/// </summary>
3838
/// <returns>CBOR-encoded bytes of the handover info</returns>
3939
public byte[] ToCborBytes() => ToCbor().EncodeToBytes();
4040

4141
/// <summary>
42-
/// Computes the SHA-256 hash of the handover info CBOR bytes
42+
/// Computes the SHA-256 hash of the handover info CBOR bytes
4343
/// </summary>
4444
/// <returns>SHA-256 hash of the CBOR-encoded handover info</returns>
4545
public Sha256Hash ToHash()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace WalletFramework.Oid4Vc.Oid4Vp;
2+
3+
public static class HandoverConstants
4+
{
5+
public const string BasicHandoverTypeIdentifier = "OpenID4VPHandover";
6+
7+
public const string DcApiHandoverTypeIdentifier = "OpenID4VPDCAPIHandover";
8+
}

src/WalletFramework.Oid4Vc/Oid4Vp/Models/Oid4VpHandover.cs

Lines changed: 0 additions & 62 deletions
This file was deleted.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using LanguageExt;
2+
using Microsoft.IdentityModel.Tokens;
3+
using PeterO.Cbor;
4+
using WalletFramework.Core.Cryptography.Models;
5+
using WalletFramework.Core.Functional;
6+
using WalletFramework.MdocLib.Device;
7+
using WalletFramework.MdocLib.Security;
8+
using WalletFramework.MdocLib.Security.Abstractions;
9+
using WalletFramework.Oid4Vc.Oid4Vp.Jwk;
10+
using static WalletFramework.Oid4Vc.Oid4Vp.Models.Nonce;
11+
12+
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
13+
14+
/// <summary>
15+
/// Represents OpenID4VPHandover according to the OpenID4VP specification.
16+
/// Contains a fixed identifier and the SHA-256 hash of OpenID4VPDCAPIHandoverInfo
17+
/// Structure: ["OpenID4VPHandover", OpenID4VPHandoverInfoHash]
18+
/// </summary>
19+
public record OpenId4VpHandover(OpenId4VpHandoverInfo HandoverInfo) : IHandover
20+
{
21+
/// <summary>
22+
/// Mdoc generated nonce created during handover initialization
23+
/// </summary>
24+
public Nonce MdocGeneratedNonce { get; } = GenerateNonce();
25+
26+
/// <summary>
27+
/// Converts the handover to CBOR representation as an array
28+
/// </summary>
29+
/// <returns>CBOR array containing [identifier, hash]</returns>
30+
public CBORObject ToCbor()
31+
{
32+
var result = CBORObject.NewArray();
33+
34+
result.Add(HandoverConstants.BasicHandoverTypeIdentifier);
35+
result.Add(HandoverInfo.ToHash().AsBytes);
36+
37+
return result;
38+
}
39+
40+
/// <summary>
41+
/// Encodes the handover as CBOR bytes
42+
/// </summary>
43+
/// <returns>CBOR-encoded bytes of the handover</returns>
44+
public byte[] ToCborBytes() => ToCbor().EncodeToBytes();
45+
46+
public SessionTranscript ToSessionTranscript()
47+
{
48+
return new SessionTranscript(
49+
Option<DeviceEngagement>.None,
50+
Option<PublicKey>.None,
51+
this
52+
);
53+
}
54+
55+
public static OpenId4VpHandover FromAuthorizationRequest(AuthorizationRequest request, Option<JsonWebKey> verifierPublicKey)
56+
{
57+
var encryptionKey = verifierPublicKey.OnSome(JwkFun.GetThumbprint);
58+
59+
var handoverInfo = new OpenId4VpHandoverInfo(
60+
request.ClientIdScheme != null
61+
? $"{request.ClientIdScheme.AsString()}:{request.ClientId}"
62+
: request.ClientId!,
63+
request.Nonce,
64+
request.ResponseUri,
65+
encryptionKey
66+
);
67+
68+
return new OpenId4VpHandover(handoverInfo);
69+
}
70+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using LanguageExt;
2+
using PeterO.Cbor;
3+
using WalletFramework.Core.Encoding;
4+
using WalletFramework.Oid4Vc.Oid4Vp.DcApi.Models;
5+
6+
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
7+
8+
/// <summary>
9+
/// Represents OpenID4VPDCAPIHandoverInfo according to the OpenID4VP specification.
10+
/// Contains the handover parameters as a CBOR array: [origin, nonce, jwkThumbprint]
11+
/// </summary>
12+
public record OpenId4VpHandoverInfo(
13+
string ClientId,
14+
string Nonce,
15+
string ResponseUri,
16+
Option<byte[]> JwkThumbprint)
17+
{
18+
/// <summary>
19+
/// Converts the handover info to CBOR representation as an array
20+
/// </summary>
21+
/// <returns>CBOR array containing [origin, nonce, jwkThumbprint]</returns>
22+
public CBORObject ToCbor()
23+
{
24+
var result = CBORObject.NewArray();
25+
26+
result.Add(ClientId);
27+
result.Add(Nonce);
28+
29+
JwkThumbprint.Match(
30+
thumbprint => result.Add(thumbprint),
31+
() => result.Add(CBORObject.Null)
32+
);
33+
34+
result.Add(ResponseUri);
35+
36+
return result;
37+
}
38+
39+
/// <summary>
40+
/// Encodes the handover info as CBOR bytes
41+
/// </summary>
42+
/// <returns>CBOR-encoded bytes of the handover info</returns>
43+
public byte[] ToCborBytes() => ToCbor().EncodeToBytes();
44+
45+
/// <summary>
46+
/// Computes the SHA-256 hash of the handover info CBOR bytes
47+
/// </summary>
48+
/// <returns>SHA-256 hash of the CBOR-encoded handover info</returns>
49+
public Sha256Hash ToHash()
50+
{
51+
var handoverInfoBytes = ToCborBytes();
52+
return Sha256Hash.ComputeHash(handoverInfoBytes);
53+
}
54+
}

src/WalletFramework.Oid4Vc/Oid4Vp/Services/Oid4VpClientService.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ public Oid4VpClientService(
7575
IOid4VpHaipClient oid4VpHaipClient,
7676
IOid4VpRecordService oid4VpRecordService,
7777
IPresentationService presentationService,
78+
IVerifierKeyService verifierKeyService,
7879
ISdJwtVcHolderService sdJwtVcHolderService)
7980
{
8081
_agentProvider = agentProvider;
@@ -89,6 +90,7 @@ public Oid4VpClientService(
8990
_oid4VpHaipClient = oid4VpHaipClient;
9091
_oid4VpRecordService = oid4VpRecordService;
9192
_presentationService = presentationService;
93+
_verifierKeyService = verifierKeyService;
9294
_sdJwtVcHolderService = sdJwtVcHolderService;
9395
}
9496

@@ -104,6 +106,7 @@ public Oid4VpClientService(
104106
private readonly IOid4VpHaipClient _oid4VpHaipClient;
105107
private readonly IOid4VpRecordService _oid4VpRecordService;
106108
private readonly IPresentationService _presentationService;
109+
private readonly IVerifierKeyService _verifierKeyService;
107110
private readonly ISdJwtVcHolderService _sdJwtVcHolderService;
108111

109112
public async Task<Option<Uri>> AbortAuthorizationRequest(AuthorizationRequestCancellation cancellation)
@@ -221,7 +224,7 @@ await credentialSetMdocRecords.Match(
221224

222225
switch (presentation.PresentedCredential)
223226
{
224-
case SdJwtRecord sdJwtRecord:
227+
case SdJwtRecord sdJwtRecord:
225228
var issuanceSdJwtDoc = sdJwtRecord.ToSdJwtDoc();
226229
var sdJwtDoc = new SdJwtDoc(presentation.PresentationMap.Presentation);
227230

@@ -239,7 +242,7 @@ from claim in sdJwtRecord.Claims
239242
key = claim.Key,
240243
value = new PresentedClaim { Value = claim.Value }
241244
};
242-
245+
243246
result = new PresentedCredentialSet
244247
{
245248
SdJwtCredentialType = Vct.ValidVct(sdJwtRecord.Vct).UnwrapOrThrow(),
@@ -408,7 +411,14 @@ public async Task<Option<Uri>> AcceptOnDemandRequest(
408411

409412
var mdoc = mdocRecord.Mdoc.SelectivelyDisclose(toDisclose);
410413

411-
var handover = authorizationRequest.ToVpHandover();
414+
var responseEncryptionKey = authorizationRequest.ResponseMode == AuthorizationRequest.DirectPostJwt
415+
? await _verifierKeyService.GetPublicKey(authorizationRequest)
416+
: Option<JsonWebKey>.None;
417+
418+
var handover = OpenId4VpHandover.FromAuthorizationRequest(
419+
authorizationRequest,
420+
responseEncryptionKey);
421+
412422
mdocNonce = handover.MdocGeneratedNonce;
413423
var sessionTranscript = handover.ToSessionTranscript();
414424

0 commit comments

Comments
 (0)