Skip to content

Commit 474107c

Browse files
JoTiTukenkosmowski
andauthored
init vp_format support (#252)
* vp_formats support Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> --------- Signed-off-by: Johannes Tuerk <johannes.tuerk@lissi.id> Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> Co-authored-by: kenkosmowski <ken.kosmowski@gmx.de>
1 parent 2b5bc2f commit 474107c

File tree

14 files changed

+149
-96
lines changed

14 files changed

+149
-96
lines changed

.github/workflows/publish-nuget.yaml

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ env:
1717
jobs:
1818
build:
1919

20-
runs-on: ubuntu-latest
20+
runs-on: ubuntu-22.04
2121

2222
steps:
2323
- uses: actions/checkout@v2
@@ -37,14 +37,6 @@ jobs:
3737
fi
3838
echo "APP_VERSION=$VERSION$SUFFIX" >> $GITHUB_ENV
3939
40-
- name: Setup NuGet
41-
uses: NuGet/setup-nuget@v2
42-
with:
43-
nuget-version: 6.10.2
44-
45-
- name: Restore dependencies
46-
run: nuget restore $SOLUTION
47-
4840
- name: Setup .NET
4941
uses: actions/setup-dotnet@v3
5042
with:
@@ -57,6 +49,9 @@ jobs:
5749
# sudo apt-get update \
5850
# apt-get install -y libindy
5951

52+
- name: Restore dependencies
53+
run: dotnet restore $SOLUTION
54+
6055
- name: Build
6156
run: dotnet build $SOLUTION --configuration $BUILD_CONFIG -p:Version=$APP_VERSION
6257

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ public record ClientMetadata
5454
/// </summary>
5555
[JsonProperty("tos_uri")]
5656
public string? TosUri { get; }
57+
58+
/// <summary>
59+
/// The URI to a human-readable terms of service document for the client (verifier).
60+
/// </summary>
61+
[JsonProperty("vp_formats")]
62+
public Formats Formats { get; }
5763

5864
public ClientMetadata(
5965
string? clientName,
@@ -63,7 +69,8 @@ public ClientMetadata(
6369
string? policyUri,
6470
string? tosUri,
6571
string[] redirectUris,
66-
List<JsonWebKey> jwks)
72+
List<JsonWebKey> jwks,
73+
Formats formats)
6774
{
6875
ClientName = clientName;
6976
ClientUri = clientUri;
@@ -73,5 +80,6 @@ public ClientMetadata(
7380
TosUri = tosUri;
7481
RedirectUris = redirectUris;
7582
Jwks = jwks;
83+
Formats = formats;
7684
}
7785
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Newtonsoft.Json;
2+
3+
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
4+
5+
public record Formats
6+
{
7+
[JsonProperty("vc+sd-jwt")]
8+
public SdJwtFormat? SdJwtFormat { get; init; }
9+
10+
[JsonProperty("mso_mdoc")]
11+
public MDocFormat? MDocFormat { get; init; }
12+
}

src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Models/Format.cs renamed to src/WalletFramework.Oid4Vc/Oid4Vp/Models/MDocFormat.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using Newtonsoft.Json;
22

3-
namespace WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models;
3+
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
44

55
/// <summary>
66
/// Represents the claim format, encapsulating supported algorithms.
77
/// </summary>
8-
public class Format
8+
public class MDocFormat
99
{
1010
/// <summary>
1111
/// Gets the names of supported algorithms.
@@ -18,4 +18,4 @@ public class Format
1818
/// </summary>
1919
[JsonProperty("proof_type")]
2020
public string[] ProofTypes { get; private set; } = null!;
21-
}
21+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Newtonsoft.Json;
2+
3+
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
4+
5+
public record SdJwtFormat
6+
{
7+
[JsonProperty("sd-jwt_alg_values")]
8+
public List<string>? IssuerSignedJwtAlgValues { get; init; }
9+
10+
[JsonProperty("kb-jwt_alg_values")]
11+
public List<string>? KeyBindingJwtAlgValues { get; init; }
12+
};

src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Models/InputDescriptor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Newtonsoft.Json;
2+
using WalletFramework.Oid4Vc.Oid4Vp.Models;
23

34
namespace WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models;
45

@@ -20,7 +21,7 @@ public class InputDescriptor
2021
/// This property is optional.
2122
/// </summary>
2223
[JsonProperty("format")]
23-
public Dictionary<string, Format> Formats { get; private set; } = null!;
24+
public Formats? Formats { get; private set; }
2425

2526
/// <summary>
2627
/// Gets or sets the unique identifier for the input descriptor.

src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Models/PresentationDefinition.cs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@ namespace WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models;
77
/// </summary>
88
public class PresentationDefinition
99
{
10-
/// <summary>
11-
/// Gets or sets the format of the presentation definition
12-
/// This property is optional.
13-
/// </summary>
14-
[JsonProperty("format")]
15-
public Dictionary<string, Format> Formats { get; }
16-
1710
/// <summary>
1811
/// Represents a collection of input descriptors.
1912
/// </summary>
@@ -24,7 +17,7 @@ public class PresentationDefinition
2417
/// This MUST be a string. The string SHOULD provide a unique ID for the desired context.
2518
/// </summary>
2619
[JsonProperty("id", Required = Required.Always)]
27-
public string Id { get; }
20+
public string Id { get; }
2821

2922
/// <summary>
3023
/// This SHOULD be a human-friendly string intended to constitute a distinctive designation of the Presentation
@@ -47,14 +40,12 @@ public class PresentationDefinition
4740

4841
[JsonConstructor]
4942
private PresentationDefinition(
50-
Dictionary<string, Format> formats,
5143
InputDescriptor[] inputDescriptors,
5244
string id,
5345
string? name,
5446
string? purpose,
5547
SubmissionRequirement[] submissionRequirements)
5648
{
57-
Formats = formats;
5849
InputDescriptors = inputDescriptors;
5950
Id = id;
6051
Name = name;

src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Services/IPexService.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using LanguageExt;
12
using WalletFramework.Oid4Vc.Oid4Vp.Models;
23
using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models;
34

@@ -17,11 +18,12 @@ public interface IPexService
1718
/// A task representing the asynchronous operation. The task result contains the Presentation Submission.
1819
/// </returns>
1920
Task<PresentationSubmission> CreatePresentationSubmission(PresentationDefinition presentationDefinition, DescriptorMap[] descriptorMaps);
20-
21+
2122
/// <summary>
2223
/// Finds the credential candidates based on the provided credentials and input descriptors.
2324
/// </summary>
2425
/// <param name="inputDescriptors">An array of input descriptors to be satisfied.</param>
26+
/// <param name="supportedFormatSigningAlgorithms">An array of input descriptors to be satisfied.</param>
2527
/// <returns>An array of credential candidates, each containing a list of credentials that match the input descriptors.</returns>
26-
Task<PresentationCandidates[]> FindCredentialCandidates(IEnumerable<InputDescriptor> inputDescriptors);
28+
Task<PresentationCandidates[]> FindCredentialCandidates(IEnumerable<InputDescriptor> inputDescriptors, Option<Formats> supportedFormatSigningAlgorithms);
2729
}

src/WalletFramework.Oid4Vc/Oid4Vp/PresentationExchange/Services/PexService.cs

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
using System.IdentityModel.Tokens.Jwt;
12
using Hyperledger.Aries.Agents;
3+
using LanguageExt;
24
using Newtonsoft.Json.Linq;
35
using SD_JWT.Models;
46
using WalletFramework.Core.Credentials.Abstractions;
57
using WalletFramework.Core.Functional;
68
using WalletFramework.MdocLib.Issuer;
9+
using WalletFramework.MdocLib.Security.Cose;
710
using WalletFramework.Oid4Vc.Oid4Vci.Abstractions;
811
using WalletFramework.Oid4Vc.Oid4Vp.Models;
912
using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models;
@@ -40,23 +43,19 @@ public Task<PresentationSubmission> CreatePresentationSubmission(
4043
}
4144

4245
/// <inheritdoc />
43-
public virtual async Task<PresentationCandidates[]> FindCredentialCandidates(IEnumerable<InputDescriptor> inputDescriptors)
46+
public virtual async Task<PresentationCandidates[]> FindCredentialCandidates(
47+
IEnumerable<InputDescriptor> inputDescriptors, Option<Formats> supportedFormatSigningAlgorithms)
4448
{
4549
var result = new List<PresentationCandidates>();
4650

4751
foreach (var inputDescriptor in inputDescriptors)
4852
{
49-
if (!(inputDescriptor.Formats.Keys.Contains("vc+sd-jwt") || inputDescriptor.Formats.Keys.Contains("mso_mdoc")))
50-
{
51-
throw new NotSupportedException("Only vc+sd-jwt or mso_mdoc format are supported");
52-
}
53-
5453
if (inputDescriptor.Constraints.Fields == null || inputDescriptor.Constraints.Fields.Length == 0)
5554
{
5655
throw new InvalidOperationException("Fields cannot be null or empty");
5756
}
5857

59-
var matchingCredentials = await GetMatchingCredentials(inputDescriptor);
58+
var matchingCredentials = await GetMatchingCredentials(inputDescriptor, supportedFormatSigningAlgorithms);
6059

6160
if (matchingCredentials.Count == 0)
6261
continue;
@@ -83,7 +82,7 @@ public virtual async Task<PresentationCandidates[]> FindCredentialCandidates(IEn
8382
return result.ToArray();
8483
}
8584

86-
private async Task<List<ICredential>> GetMatchingCredentials(InputDescriptor inputDescriptor)
85+
private async Task<List<ICredential>> GetMatchingCredentials(InputDescriptor inputDescriptor, Option<Formats> supportedFormatSigningAlgorithms)
8786
{
8887
var context = await agentProvider.GetContextAsync();
8988

@@ -93,7 +92,15 @@ private async Task<List<ICredential>> GetMatchingCredentials(InputDescriptor inp
9392
var filteredSdJwtRecords = sdJwtRecords.Where(record =>
9493
{
9594
var doc = _toSdJwtDoc(record);
96-
return inputDescriptor.Formats.ContainsKey("vc+sd-jwt") && inputDescriptor.Constraints.Fields!.All(field =>
95+
96+
var handler = new JwtSecurityTokenHandler();
97+
var issuerSignedJwt = handler.ReadJwtToken(doc.IssuerSignedJwt);
98+
99+
return issuerSignedJwt.Header.TryGetValue("alg", out var alg)
100+
&& supportedFormatSigningAlgorithms.Match(
101+
formats => formats.SdJwtFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString()) ?? true,
102+
() => inputDescriptor.Formats?.SdJwtFormat?.IssuerSignedJwtAlgValues?.Contains(alg.ToString()) ?? true)
103+
&& inputDescriptor.Constraints.Fields!.All(field =>
97104
{
98105
try
99106
{
@@ -115,27 +122,34 @@ private async Task<List<ICredential>> GetMatchingCredentials(InputDescriptor inp
115122
}).Cast<ICredential>().AsOption();
116123

117124
var filteredMdocRecords = mdocRecords.OnSome(records => records
118-
.Where(record => inputDescriptor.Formats.ContainsKey("mso_mdoc") && inputDescriptor.Constraints.Fields!.All(field =>
125+
.Where(record =>
119126
{
120-
try
127+
return record.Mdoc.IssuerSigned.IssuerAuth.ProtectedHeaders.Value.TryGetValue(new CoseLabel(1), out var alg)
128+
&& supportedFormatSigningAlgorithms.Match(
129+
formats => formats.MDocFormat?.Alg.Contains(alg.ToString()) ?? true,
130+
() => inputDescriptor.Formats?.MDocFormat?.Alg.Contains(alg.ToString()) ?? true)
131+
&& inputDescriptor.Constraints.Fields!.All(field =>
121132
{
122-
var jObj = record.Mdoc.IssuerSigned.IssuerNameSpaces.ToJObject();
123-
124-
if (jObj.SelectToken(field.Path.First(), true) is not JValue value)
125-
return false;
126-
127-
if (field.Filter?.Const != null)
133+
try
128134
{
129-
return field.Filter?.Const == value.Value?.ToString();
130-
}
135+
var jObj = record.Mdoc.IssuerSigned.IssuerNameSpaces.ToJObject();
131136

132-
return true;
133-
}
134-
catch (Exception)
135-
{
136-
return false;
137-
}
138-
}))
137+
if (jObj.SelectToken(field.Path.First(), true) is not JValue value)
138+
return false;
139+
140+
if (field.Filter?.Const != null)
141+
{
142+
return field.Filter?.Const == value.Value?.ToString();
143+
}
144+
145+
return true;
146+
}
147+
catch (Exception)
148+
{
149+
return false;
150+
}
151+
});
152+
})
139153
.Cast<ICredential>()
140154
.AsOption());
141155

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models;
22
using WalletFramework.Oid4Vc.Oid4Vp.Models;
3+
using Format = WalletFramework.Oid4Vc.Oid4Vci.CredConfiguration.Models.Format;
34

45
namespace WalletFramework.Oid4Vc.Oid4Vp.Services;
56

0 commit comments

Comments
 (0)