Skip to content

Commit adf9aa5

Browse files
authored
Add C'' (#169)
* c'' interfaces Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * issuance + wip presentation Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * apply merge changes to current state Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * c'' vp and fix encryptedAuthResponse alg Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * clean code + fix test Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> * fix test Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> --------- Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id>
1 parent 49afecf commit adf9aa5

File tree

20 files changed

+544
-36
lines changed

20 files changed

+544
-36
lines changed

src/WalletFramework.Oid4Vc/Oid4Vci/Abstractions/IOid4VciClientService.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
using OneOf;
44
using WalletFramework.Core.Functional;
55
using WalletFramework.Core.Localization;
6+
using WalletFramework.MdocLib;
67
using WalletFramework.MdocVc;
78
using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models;
9+
using WalletFramework.Oid4Vc.Oid4Vp.Models;
10+
using WalletFramework.SdJwtVc.Models;
811
using WalletFramework.SdJwtVc.Models.Records;
912

1013
namespace WalletFramework.Oid4Vc.Oid4Vci.Abstractions;
@@ -40,6 +43,17 @@ public interface IOid4VciClientService
4043
/// </returns>
4144
Task<Validation<List<OneOf<SdJwtRecord, MdocRecord>>>> RequestCredential(IssuanceSession issuanceSession);
4245

46+
/// <summary>
47+
/// Requests a verifiable credential using the authorization code flow and C''.
48+
/// </summary>
49+
/// <param name="issuanceSession">Holds authorization session relevant information.</param>
50+
/// <param name="authorizationRequest">The AuthorizationRequest that is associated witht the ad-hoc crednetial issuance</param>
51+
/// <param name="credentialType">Specifies whether Sd-Jwt or MDoc should be issued</param>
52+
/// <returns>
53+
/// A list of credentials.
54+
/// </returns>
55+
Task<Validation<List<OneOf<SdJwtRecord, MdocRecord>>>> RequestOnDemandCredential(IssuanceSession issuanceSession, AuthorizationRequest authorizationRequest, OneOf<Vct, DocType> credentialType);
56+
4357
/// <summary>
4458
/// Processes a credential offer
4559
/// </summary>

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Abstractions/IAuthFlowSessionStorage.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ public interface IAuthFlowSessionStorage
2525
/// <param name="authFlowSessionState">Session State Identifier of a Authorization Code Flow session</param>
2626
/// <returns></returns>
2727
Task<AuthFlowSessionRecord> GetAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState);
28+
29+
/// <summary>
30+
/// Updates the authorization session record by the session identifier.
31+
/// </summary>
32+
/// <param name="context">Agent Context</param>
33+
/// <param name="record">the updated Authorization Session Record</param>
34+
/// <returns></returns>
35+
Task UpdateAsync(IAgentContext context, AuthFlowSessionRecord record);
2836

2937
/// <summary>
3038
/// Stores the authorization session record.

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Implementations/AuthFlowSessionStorage.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,8 @@ public async Task<AuthFlowSessionRecord> GetAsync(IAgentContext context, AuthFlo
4848
/// <inheritdoc />
4949
public async Task<bool> DeleteAsync(IAgentContext context, AuthFlowSessionState authFlowSessionState) =>
5050
await _recordService.DeleteAsync<AuthFlowSessionRecord>(context.Wallet, authFlowSessionState);
51+
52+
/// <inheritdoc />
53+
public async Task UpdateAsync(IAgentContext context, AuthFlowSessionRecord record) =>
54+
await _recordService.UpdateAsync(context.Wallet, record);
5155
}

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Models/AuthorizationData.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Globalization;
2+
using LanguageExt;
23
using Newtonsoft.Json.Linq;
34
using WalletFramework.Core.Functional;
45
using WalletFramework.Oid4Vc.Oid4Vci.Authorization.Models;
@@ -11,13 +12,15 @@ public record AuthorizationData(
1112
ClientOptions ClientOptions,
1213
IssuerMetadata IssuerMetadata,
1314
AuthorizationServerMetadata AuthorizationServerMetadata,
15+
Option<OAuthToken> OAuthToken,
1416
List<CredentialConfigurationId> CredentialConfigurationIds);
1517

1618
public static class AuthorizationDataFun
1719
{
1820
private const string ClientOptionsJsonKey = "client_options";
1921
private const string IssuerMetadataJsonKey = "issuer_metadata";
2022
private const string AuthorizationServerMetadataJsonKey = "authorization_server_metadata";
23+
private const string CredentialOAuthToken = "credential_oauth_token";
2124
private const string CredentialConfigurationIdsJsonKey = "credential_configuration_ids";
2225

2326
public static JObject EncodeToJson(this AuthorizationData data)
@@ -27,6 +30,10 @@ public static JObject EncodeToJson(this AuthorizationData data)
2730
var issuerMetadata = data.IssuerMetadata.EncodeToJson();
2831

2932
var authServerMetadata = JObject.FromObject(data.AuthorizationServerMetadata);
33+
34+
var oAuthToken = data.OAuthToken.MatchUnsafe(
35+
Some: JObject.FromObject,
36+
None: () => null);
3037

3138
var ids = data.CredentialConfigurationIds.Select(id => id.ToString());
3239
var idsArray = new JArray(ids);
@@ -36,6 +43,7 @@ public static JObject EncodeToJson(this AuthorizationData data)
3643
{ ClientOptionsJsonKey, clientOptions },
3744
{ IssuerMetadataJsonKey, issuerMetadata },
3845
{ AuthorizationServerMetadataJsonKey, authServerMetadata },
46+
{ CredentialOAuthToken, oAuthToken },
3947
{ CredentialConfigurationIdsJsonKey, idsArray }
4048
};
4149
}
@@ -50,6 +58,8 @@ public static AuthorizationData DecodeFromJson(JObject json)
5058

5159
var authServerMetadata = json[AuthorizationServerMetadataJsonKey]!.ToObject<AuthorizationServerMetadata>()!;
5260

61+
var credentialOAuthToken = json[CredentialOAuthToken]!.ToObject<OAuthToken>()!;
62+
5363
var configIds = json[CredentialConfigurationIdsJsonKey]!.Cast<JValue>().Select(value =>
5464
{
5565
var str = value.ToString(CultureInfo.InvariantCulture);
@@ -59,6 +69,6 @@ public static AuthorizationData DecodeFromJson(JObject json)
5969

6070
}).ToList();
6171

62-
return new AuthorizationData(clientOptions, issuerMetadata, authServerMetadata, configIds);
72+
return new AuthorizationData(clientOptions, issuerMetadata, authServerMetadata, credentialOAuthToken, configIds);
6373
}
6474
}

src/WalletFramework.Oid4Vc/Oid4Vci/AuthFlow/Records/AuthFlowSessionRecord.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public AuthFlowSessionState AuthFlowSessionState
3131
/// <summary>
3232
/// The authorization data.
3333
/// </summary>
34-
public AuthorizationData AuthorizationData { get; }
34+
public AuthorizationData AuthorizationData { get; set; }
3535

3636
/// <summary>
3737
/// The parameters for the 'authorization_code' grant type.

src/WalletFramework.Oid4Vc/Oid4Vci/CredRequest/Abstractions/ICredentialRequestService.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.SdJwt;
99
using WalletFramework.Oid4Vc.Oid4Vci.CredResponse;
1010
using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Models;
11+
using WalletFramework.Oid4Vc.Oid4Vp.Models;
1112

1213
namespace WalletFramework.Oid4Vc.Oid4Vci.CredRequest.Abstractions;
1314

@@ -17,5 +18,6 @@ public Task<Validation<CredentialResponse>> RequestCredentials(
1718
OneOf<SdJwtConfiguration, MdocConfiguration> configuration,
1819
IssuerMetadata issuerMetadata,
1920
OneOf<OAuthToken, DPopToken> token,
20-
Option<ClientOptions> clientOptions);
21+
Option<ClientOptions> clientOptions,
22+
Option<AuthorizationRequest> authorizationRequest);
2123
}

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

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using WalletFramework.Core.Functional;
77
using WalletFramework.Core.Json;
88
using WalletFramework.Core.Uri;
9+
using WalletFramework.MdocLib.Security;
910
using WalletFramework.Oid4Vc.Oid4Vci.AuthFlow.Models;
1011
using WalletFramework.Oid4Vc.Oid4Vci.Authorization.DPop.Abstractions;
1112
using WalletFramework.Oid4Vc.Oid4Vci.Authorization.DPop.Models;
@@ -20,6 +21,7 @@
2021
using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Models;
2122
using WalletFramework.Oid4Vc.Oid4Vci.CredRequest.Models.SdJwt;
2223
using WalletFramework.Oid4Vc.Oid4Vci.CredResponse;
24+
using WalletFramework.Oid4Vc.Oid4Vp.Models;
2325
using WalletFramework.SdJwtVc.Services.SdJwtVcHolderService;
2426

2527
namespace WalletFramework.Oid4Vc.Oid4Vci.CredRequest.Implementations;
@@ -46,9 +48,10 @@ public CredentialRequestService(
4648
private async Task<CredentialRequest> CreateCredentialRequest(
4749
KeyId keyId,
4850
Format format,
49-
IssuerMetadata issuerMetadata,
5051
OneOf<OAuthToken, DPopToken> token,
51-
Option<ClientOptions> clientOptions)
52+
IssuerMetadata issuerMetadata,
53+
Option<ClientOptions> clientOptions,
54+
Option<AuthorizationRequest> authorizationRequest)
5255
{
5356
var cNonce = token.Match(
5457
oauthToken => oauthToken.CNonce,
@@ -61,21 +64,34 @@ private async Task<CredentialRequest> CreateCredentialRequest(
6164
"openid4vci-proof+jwt",
6265
null,
6366
clientOptions.ToNullable()?.ClientId);
67+
68+
var proof = Option<ProofOfPossession>.None;
69+
var sessionTranscript = Option<SessionTranscript>.None;
6470

65-
var proof = new ProofOfPossession
66-
{
67-
ProofType = "jwt",
68-
Jwt = keyBindingJwt
69-
};
71+
authorizationRequest.Match(
72+
Some: _ =>
73+
{
74+
if (format == "mso_mdoc")
75+
sessionTranscript = authorizationRequest.UnwrapOrThrow(new Exception()).ToVpHandover().ToSessionTranscript();
76+
},
77+
None: () =>
78+
{
79+
proof = new ProofOfPossession
80+
{
81+
ProofType = "jwt",
82+
Jwt = keyBindingJwt
83+
};
84+
});
7085

71-
return new CredentialRequest(proof, format);
86+
return new CredentialRequest(format, proof, sessionTranscript);
7287
}
7388

7489
async Task<Validation<CredentialResponse>> ICredentialRequestService.RequestCredentials(
7590
OneOf<SdJwtConfiguration, MdocConfiguration> configuration,
7691
IssuerMetadata issuerMetadata,
7792
OneOf<OAuthToken, DPopToken> token,
78-
Option<ClientOptions> clientOptions)
93+
Option<ClientOptions> clientOptions,
94+
Option<AuthorizationRequest> authorizationRequest)
7995
{
8096
var keyId = await _keyStore.GenerateKey();
8197

@@ -85,9 +101,10 @@ async Task<Validation<CredentialResponse>> ICredentialRequestService.RequestCred
85101
var vciRequest = await CreateCredentialRequest(
86102
keyId,
87103
sdJwt.Format,
88-
issuerMetadata,
89104
token,
90-
clientOptions);
105+
issuerMetadata,
106+
clientOptions,
107+
authorizationRequest);
91108

92109
var result = new SdJwtCredentialRequest(vciRequest, sdJwt.Vct);
93110
return result.EncodeToJson();
@@ -97,9 +114,10 @@ async Task<Validation<CredentialResponse>> ICredentialRequestService.RequestCred
97114
var vciRequest = await CreateCredentialRequest(
98115
keyId,
99116
mdoc.Format,
100-
issuerMetadata,
101117
token,
102-
clientOptions);
118+
issuerMetadata,
119+
clientOptions,
120+
authorizationRequest);
103121

104122
var result = new MdocCredentialRequest(vciRequest, mdoc);
105123
return result.EncodeToJson();

src/WalletFramework.Oid4Vc/Oid4Vci/CredRequest/Models/CredentialRequest.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
using LanguageExt;
22
using Newtonsoft.Json.Linq;
3+
using WalletFramework.Core.Base64Url;
4+
using WalletFramework.MdocLib.Security;
35
using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models;
46

57
namespace WalletFramework.Oid4Vc.Oid4Vci.CredRequest.Models;
@@ -9,7 +11,7 @@ namespace WalletFramework.Oid4Vc.Oid4Vci.CredRequest.Models;
911
/// This request contains the format of the credential, the type of credential,
1012
/// and a proof of possession of the key material the issued credential shall be bound to.
1113
/// </summary>
12-
public record CredentialRequest(Option<ProofOfPossession> Proof, Format Format)
14+
public record CredentialRequest(Format Format, Option<ProofOfPossession> Proof, Option<SessionTranscript> SessionTranscript)
1315
{
1416
/// <summary>
1517
/// Gets the proof of possession of the key material the issued credential shall be bound to.
@@ -20,12 +22,15 @@ public record CredentialRequest(Option<ProofOfPossession> Proof, Format Format)
2022
/// Gets the format of the credential to be issued.
2123
/// </summary>
2224
public Format Format { get; } = Format;
25+
26+
public Option<SessionTranscript> SessionTranscript { get; } = SessionTranscript;
2327
}
2428

2529
public static class CredentialRequestFun
2630
{
2731
private const string ProofJsonKey = "proof";
2832
private const string FormatJsonKey = "format";
33+
private const string SessionTranscriptKey = "session_transcript";
2934

3035
public static JObject EncodeToJson(this CredentialRequest request)
3136
{
@@ -36,6 +41,11 @@ public static JObject EncodeToJson(this CredentialRequest request)
3641
result.Add(ProofJsonKey, JObject.FromObject(proof));
3742
});
3843

44+
request.SessionTranscript.IfSome(sessionTranscript =>
45+
{
46+
result.Add(SessionTranscriptKey, Base64UrlString.CreateBase64UrlString(sessionTranscript.ToCbor().ToJSONBytes()).ToString());
47+
});
48+
3949
result.Add(FormatJsonKey, request.Format.ToString());
4050

4151
return result;

0 commit comments

Comments
 (0)