Skip to content

Commit 49afecf

Browse files
authored
Encrypted Authorization response (#170)
* encryption Signed-off-by: Kevin <kevin.dinh@lissi.id> * fix build Signed-off-by: Kevin <kevin.dinh@lissi.id> --------- Signed-off-by: Kevin <kevin.dinh@lissi.id>
1 parent ba3c20a commit 49afecf

File tree

13 files changed

+173
-38
lines changed

13 files changed

+173
-38
lines changed

src/WalletFramework.Core/Base64Url/Base64UrlString.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ namespace WalletFramework.Core.Base64Url;
55
public readonly struct Base64UrlString
66
{
77
private string Value { get; }
8-
8+
99
public byte[] AsByteArray => Base64UrlEncoder.DecodeBytes(Value);
1010

11+
public string AsString => Value;
12+
1113
private Base64UrlString(string value)
1214
{
1315
Value = value;

src/WalletFramework.Core/WalletFramework.Core.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<Nullable>enable</Nullable>
66
</PropertyGroup>
77
<ItemGroup>
8+
<PackageReference Include="jose-jwt" Version="5.0.0" />
89
<PackageReference Include="LanguageExt.Core" Version="4.4.9" />
910
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.0.1" />
1011
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />

src/WalletFramework.MdocLib/Mdoc.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,10 @@ public static Validation<Mdoc> FromIssuerSigned(string base64UrlencodedCborByteS
104104
});
105105

106106
var validateIntegrity = new List<Validator<Mdoc>>
107-
{
108-
MdocFun.DocTypeMatches,
109-
MdocFun.DigestsMatch
110-
}
111-
.AggregateValidators();
107+
{
108+
MdocFun.DocTypeMatches,
109+
MdocFun.DigestsMatch
110+
}.AggregateValidators();
112111

113112
return
114113
from bytes in decodeBase64Url(base64UrlencodedCborByteString)

src/WalletFramework.Oid4Vc/Oid4Vci/Implementations/Oid4VciClientService.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,7 @@ from issState in code.IssuerState
136136
null,
137137
null);
138138

139-
var authServerMetadata =
140-
await FetchAuthorizationServerMetadataAsync(issuerMetadata);
139+
var authServerMetadata = await FetchAuthorizationServerMetadataAsync(issuerMetadata);
141140

142141
_httpClient.DefaultRequestHeaders.Clear();
143142
var response = await _httpClient.PostAsync(
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using Hyperledger.Aries.Extensions;
2+
using Jose;
3+
using LanguageExt;
4+
using WalletFramework.Oid4Vc.Oid4Vp.Jwk;
5+
using WalletFramework.Oid4Vc.Oid4Vp.Models;
6+
7+
namespace WalletFramework.Oid4Vc.Oid4Vp.AuthResponse.Encryption;
8+
9+
public record EncryptedAuthorizationResponse(string Jwe)
10+
{
11+
public override string ToString() => Jwe;
12+
}
13+
14+
public static class EncryptedAuthorizationResponseFun
15+
{
16+
public static FormUrlEncodedContent ToFormUrl(this EncryptedAuthorizationResponse response)
17+
{
18+
var content = new Dictionary<string, string>
19+
{
20+
{ "response", response.ToString() },
21+
};
22+
23+
return new FormUrlEncodedContent(content);
24+
}
25+
26+
public static EncryptedAuthorizationResponse Encrypt(
27+
this AuthorizationResponse response,
28+
AuthorizationRequest authorizationRequest,
29+
Option<Nonce> mdocNonce)
30+
{
31+
var verifierPubKey = authorizationRequest.ClientMetadata!.Jwks.First();
32+
33+
var headers = new Dictionary<string, object>
34+
{
35+
{ "apv", authorizationRequest.Nonce },
36+
{ "kid", verifierPubKey.Kid }
37+
};
38+
39+
mdocNonce.IfSome(nonce => headers.Add("apu", nonce.AsBase64Url.ToString()));
40+
41+
var jwe = JWE.EncryptBytes(
42+
response.ToJson().GetUTF8Bytes(),
43+
new [] { new JweRecipient(JweAlgorithm.ECDH_ES, verifierPubKey.ToEcdh()) },
44+
JweEncryption.A256GCM,
45+
mode: SerializationMode.Compact,
46+
extraProtectedHeaders: headers);
47+
48+
return new EncryptedAuthorizationResponse(jwe);
49+
}
50+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System.Security.Cryptography;
2+
using Microsoft.IdentityModel.Tokens;
3+
4+
namespace WalletFramework.Oid4Vc.Oid4Vp.Jwk;
5+
6+
public static class JwkFun
7+
{
8+
public static ECDiffieHellman ToEcdh(this JsonWebKey jwk)
9+
{
10+
var ecParameters = new ECParameters
11+
{
12+
Q =
13+
{
14+
X = Base64UrlEncoder.DecodeBytes(jwk.X),
15+
Y = Base64UrlEncoder.DecodeBytes(jwk.Y)
16+
},
17+
// TODO: Map curve from jwk
18+
Curve = ECCurve.NamedCurves.nistP256
19+
};
20+
21+
return ECDiffieHellman.Create(ecParameters);
22+
}
23+
}

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
1111
/// </summary>
1212
public record AuthorizationRequest
1313
{
14-
private const string DirectPost = "direct_post";
15-
private const string DirectPostJwt = "direct_post.jwt";
14+
public const string DirectPost = "direct_post";
15+
public const string DirectPostJwt = "direct_post.jwt";
1616

1717
private const string VpToken = "vp_token";
1818

@@ -45,6 +45,9 @@ public record AuthorizationRequest
4545
/// </summary>
4646
[JsonProperty("response_uri")]
4747
public string ResponseUri { get; }
48+
49+
[JsonProperty("response_mode")]
50+
public string ResponseMode { get; }
4851

4952
/// <summary>
5053
/// Gets the client metadata. Contains the Verifier metadata.
@@ -89,6 +92,7 @@ private AuthorizationRequest(
8992
string clientId,
9093
string nonce,
9194
string responseUri,
95+
string responseMode,
9296
ClientMetadata? clientMetadata,
9397
string? clientMetadataUri,
9498
string? scope,
@@ -101,6 +105,7 @@ private AuthorizationRequest(
101105
Nonce = nonce;
102106
PresentationDefinition = presentationDefinition;
103107
ResponseUri = responseUri;
108+
ResponseMode = responseMode;
104109
Scope = scope;
105110
State = state;
106111
}
Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Newtonsoft.Json;
2+
using WalletFramework.Oid4Vc.Oid4Vp.PresentationExchange.Models;
23

34
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
45

@@ -10,18 +11,30 @@ public class AuthorizationResponse
1011
/// <summary>
1112
/// Gets or sets the VP Token.
1213
/// </summary>
13-
[JsonProperty ("vp_token")]
14+
[JsonProperty("vp_token")]
1415
public string VpToken { get; set; } = null!;
1516

1617
/// <summary>
1718
/// Gets or sets the Presentation Submission.
1819
/// </summary>
19-
[JsonProperty ("presentation_submission")]
20-
public string PresentationSubmission { get; set; } = null!;
20+
[JsonProperty("presentation_submission")]
21+
public PresentationSubmission PresentationSubmission { get; set; } = null!;
2122

2223
/// <summary>
2324
/// Gets or sets the State.
2425
/// </summary>
25-
[JsonProperty ("state", NullValueHandling = NullValueHandling.Ignore)]
26-
public string? State { get; set; } = null!;
26+
[JsonProperty("state", NullValueHandling = NullValueHandling.Ignore)]
27+
public string? State { get; set; }
28+
}
29+
30+
public static class AuthorizationResponseFun
31+
{
32+
public static FormUrlEncodedContent ToFormUrl(this AuthorizationResponse authorizationResponse)
33+
{
34+
var json = JsonConvert.SerializeObject(authorizationResponse);
35+
var nameValueCollection =
36+
JsonConvert.DeserializeObject<Dictionary<string, string>>(json)!.ToList();
37+
38+
return new FormUrlEncodedContent(nameValueCollection);
39+
}
2740
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using Microsoft.IdentityModel.Tokens;
2+
using Newtonsoft.Json;
3+
using Newtonsoft.Json.Linq;
4+
using WalletFramework.Core.Functional;
5+
using WalletFramework.Core.Json;
6+
7+
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
8+
9+
public class ClientJwksConverter : JsonConverter<List<JsonWebKey>>
10+
{
11+
public override bool CanRead => true;
12+
13+
public override bool CanWrite => false;
14+
15+
public override void WriteJson(JsonWriter writer, List<JsonWebKey>? value, JsonSerializer serializer)
16+
{
17+
throw new NotImplementedException();
18+
}
19+
20+
public override List<JsonWebKey> ReadJson(
21+
JsonReader reader,
22+
Type objectType,
23+
List<JsonWebKey>? existingValue,
24+
bool hasExistingValue,
25+
JsonSerializer serializer)
26+
{
27+
var json = JObject.Load(reader);
28+
var validKeysArray =
29+
from keys in json.GetByKey("keys")
30+
from keysArray in keys.ToJArray()
31+
select keysArray;
32+
33+
var result = validKeysArray.OnSuccess(keysArray =>
34+
{
35+
return keysArray.Select(keyToken => JsonWebKey.Create(keyToken.ToString())).ToList();
36+
}).UnwrapOrThrow();
37+
38+
return result;
39+
}
40+
}

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1+
using Microsoft.IdentityModel.Tokens;
12
using Newtonsoft.Json;
23

34
namespace WalletFramework.Oid4Vc.Oid4Vp.Models;
45

56
/// <summary>
67
/// Represents the metadata of a client (verifier).
78
/// </summary>
8-
// TODO: Rename this to VerifierMetadata
99
public record ClientMetadata
1010
{
1111
/// <summary>
@@ -38,8 +38,9 @@ public record ClientMetadata
3838
[JsonProperty("logo_uri")]
3939
public string? LogoUri { get; }
4040

41-
// TODO: JWKs of the verifier
42-
// public List<JWK> PublicKeys { get; }
41+
[JsonProperty("jwks")]
42+
[JsonConverter(typeof(ClientJwksConverter))]
43+
public List<JsonWebKey> Jwks { get; }
4344

4445
/// <summary>
4546
/// The URI to a human-readable privacy policy document for the client (verifier).
@@ -54,7 +55,15 @@ public record ClientMetadata
5455
public string? TosUri { get; }
5556

5657
[JsonConstructor]
57-
private ClientMetadata(string? clientName, string? clientUri, string[]? contacts, string? logoUri, string? policyUri, string? tosUri, string[] redirectUris)
58+
private ClientMetadata(
59+
string? clientName,
60+
string? clientUri,
61+
string[]? contacts,
62+
string? logoUri,
63+
string? policyUri,
64+
string? tosUri,
65+
string[] redirectUris,
66+
List<JsonWebKey> jwks)
5867
{
5968
ClientName = clientName;
6069
ClientUri = clientUri;
@@ -63,5 +72,6 @@ private ClientMetadata(string? clientName, string? clientUri, string[]? contacts
6372
PolicyUri = policyUri;
6473
TosUri = tosUri;
6574
RedirectUris = redirectUris;
75+
Jwks = jwks;
6676
}
6777
}

0 commit comments

Comments
 (0)