Skip to content

Commit cca9fda

Browse files
Implement RP authentication (#323)
* add decoding of registration certificate Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * parse registration certificate attachments in authorization request Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * parse x5c in auth request attachment Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * adjust parsing of registration certificate Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * validate registration certificate Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * use new registration certificate format Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * add tests for registration certificate validation Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> * implement rp auth Signed-off-by: Kevin <kevin.dinh@lissi.id> --------- Signed-off-by: kenkosmowski <ken.kosmowski@gmx.de> Signed-off-by: Kevin <kevin.dinh@lissi.id> Co-authored-by: kenkosmowski <ken.kosmowski@gmx.de>
1 parent 9e50e99 commit cca9fda

File tree

79 files changed

+2443
-405
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+2443
-405
lines changed

test/WalletFramework.SdJwtVc.Tests/StatusListTests.cs renamed to src/WalletFramework.Core.Tests/StatusList/StatusListTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
using Moq;
33
using Moq.Protected;
44
using WalletFramework.Core.Credentials;
5-
using WalletFramework.SdJwtVc.Models.StatusList;
6-
using WalletFramework.SdJwtVc.Services;
5+
using WalletFramework.Core.StatusList;
6+
using Xunit;
77

8-
namespace WalletFramework.SdJwtVc.Tests;
8+
namespace WalletFramework.Core.Tests.StatusList;
99

1010
public class StatusListTests
1111
{

src/WalletFramework.Core.Tests/WalletFramework.Core.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
<ItemGroup>
1212
<PackageReference Include="FluentAssertions" Version="6.12.0" />
1313
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0"/>
14+
<PackageReference Include="Moq" Version="$(MoqVersion)" />
1415
<PackageReference Include="xunit" Version="2.9.0" />
1516
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
1617
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

src/WalletFramework.SdJwtVc/Services/IStatusListService.cs renamed to src/WalletFramework.Core/StatusList/IStatusListService.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
using LanguageExt;
22
using WalletFramework.Core.Credentials;
3-
using WalletFramework.SdJwtVc.Models.StatusList;
43

5-
namespace WalletFramework.SdJwtVc.Services;
4+
namespace WalletFramework.Core.StatusList;
65

76
public interface IStatusListService
87
{
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Newtonsoft.Json.Linq;
2+
using WalletFramework.Core.Functional;
3+
using WalletFramework.Core.Functional.Errors;
4+
using WalletFramework.Core.Json;
5+
using static WalletFramework.Core.StatusList.StatusListEntryFun;
6+
7+
namespace WalletFramework.Core.StatusList;
8+
9+
public record StatusListEntry(int Idx, string Uri)
10+
{
11+
public static Validation<StatusListEntry> FromJObject(JObject json)
12+
{
13+
var idx = json.GetByKey(IdxJsonKey)
14+
.OnSuccess(token => token.ToJValue())
15+
.OnSuccess(jValue =>
16+
{
17+
var value = jValue.Value?.ToString();
18+
if (string.IsNullOrWhiteSpace(value) || !int.TryParse(value, out var idx))
19+
{
20+
return new StringIsNullOrWhitespaceError<StatusListEntry>();
21+
}
22+
23+
return ValidationFun.Valid(idx);
24+
});
25+
26+
var uri = json.GetByKey(UriJsonKey)
27+
.OnSuccess(token => token.ToJValue())
28+
.OnSuccess(value =>
29+
{
30+
if (string.IsNullOrWhiteSpace(value.Value?.ToString()))
31+
{
32+
return new StringIsNullOrWhitespaceError<StatusListEntry>();
33+
}
34+
35+
return ValidationFun.Valid(value.Value.ToString());;
36+
});
37+
38+
return ValidationFun.Valid(Create)
39+
.Apply(idx)
40+
.Apply(uri);
41+
}
42+
43+
private static StatusListEntry Create(
44+
int idx,
45+
string uri) =>
46+
new(idx, uri);
47+
}
48+
49+
public static class StatusListEntryFun
50+
{
51+
public const string IdxJsonKey = "idx";
52+
public const string UriJsonKey = "uri";
53+
}

src/WalletFramework.SdJwtVc/Services/StatusListService.cs renamed to src/WalletFramework.Core/StatusList/StatusListService.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
using WalletFramework.Core.Credentials;
88
using WalletFramework.Core.Functional;
99
using WalletFramework.Core.Json;
10-
using WalletFramework.SdJwtVc.Models.StatusList;
1110

12-
namespace WalletFramework.SdJwtVc.Services;
11+
namespace WalletFramework.Core.StatusList;
1312

1413
public class StatusListService(IHttpClientFactory httpClientFactory) : IStatusListService
1514
{

src/WalletFramework.Core/WalletFramework.Core.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77
<ItemGroup>
88
<PackageReference Include="jose-jwt" Version="5.0.0" />
99
<PackageReference Include="LanguageExt.Core" Version="4.4.9" />
10+
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.5" />
1011
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.0.1" />
1112
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
1213
<PackageReference Include="OneOf" Version="3.0.271" />
1314
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
15+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.2" />
1416
</ItemGroup>
1517
</Project>

src/WalletFramework.Core/X509/X509CertificateExtensions.cs

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Security.Cryptography.X509Certificates;
2+
using Org.BouncyCastle.Asn1;
23
using Org.BouncyCastle.Pkix;
34
using Org.BouncyCastle.Utilities.Collections;
45
using Org.BouncyCastle.X509;
@@ -12,28 +13,57 @@ namespace WalletFramework.Core.X509;
1213
/// </summary>
1314
public static class X509CertificateExtensions
1415
{
16+
public static string? GetAuthorityKeyId(this X509Certificate2 cert)
17+
{
18+
var authorityKeyIdentifier = cert.Extensions["2.5.29.35"];
19+
if (authorityKeyIdentifier == null)
20+
return null;
21+
22+
var asn1Object = new Asn1InputStream(authorityKeyIdentifier.RawData).ReadObject() as DerSequence;
23+
var derTaggedObject = asn1Object?[0] as DerTaggedObject;
24+
var hex = derTaggedObject?.GetObject().ToString().Trim('#');
25+
return hex;
26+
}
27+
28+
public static string? GetSubjectKeyId(this X509Certificate2 cert)
29+
{
30+
const string subjectKeyIdentifierOid = "2.5.29.14";
31+
32+
var ext = cert.Extensions[subjectKeyIdentifierOid] as X509SubjectKeyIdentifierExtension;
33+
return ext?.SubjectKeyIdentifier;
34+
}
35+
36+
public static bool IsSelfSigned(this X509Certificate certificate) =>
37+
certificate.IssuerDN.Equivalent(certificate.SubjectDN);
38+
1539
/// <summary>
1640
/// Validates the trust chain of the certificate.
1741
/// </summary>
1842
/// <param name="trustChain">The trust chain to validate.</param>
1943
/// <returns>True if the trust chain is valid, otherwise false.</returns>
20-
public static bool IsTrustChainValid(this List<X509Certificate> trustChain)
44+
public static bool IsTrustChainValid(this IEnumerable<X509Certificate> trustChain)
2145
{
22-
var leafCert = trustChain.First();
46+
var chain = trustChain.ToList();
47+
if (chain.Count == 1)
48+
{
49+
return true;
50+
}
2351

24-
var subjects = trustChain.Select(cert => cert.SubjectDN);
52+
var leafCert = chain.First();
53+
54+
var subjects = chain.Select(cert => cert.SubjectDN);
2555
var rootCerts = new HashSet(
26-
trustChain
56+
chain
2757
.Where(cert => cert.IsSelfSigned() || !subjects.Contains(cert.IssuerDN))
2858
.Select(cert => new TrustAnchor(cert, null)));
2959

3060
var intermediateCerts = new HashSet(
31-
trustChain
61+
chain
3262
.Where(cert => !cert.IsSelfSigned())
3363
.Append(leafCert));
3464

3565
var storeSelector = new X509CertStoreSelector { Certificate = leafCert };
36-
66+
3767
var builderParams = new PkixBuilderParameters(rootCerts, storeSelector)
3868
{
3969
//TODO: Check if CRLs (Certificate Revocation Lists) are valid
@@ -58,6 +88,6 @@ public static X509Certificate ToBouncyCastleX509Certificate(this X509Certificate
5888
return certParser.ReadCertificate(cert.GetRawCertData());
5989
}
6090

61-
public static bool IsSelfSigned(this X509Certificate certificate) =>
62-
certificate.IssuerDN.Equivalent(certificate.SubjectDN);
91+
public static X509Certificate2 ToSystemX509Certificate(this X509Certificate cert) =>
92+
new(cert.GetEncoded());
6393
}

src/WalletFramework.Oid4Vc/Constants.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ public static class Constants
77
public const string SdJwtDcFormat = "dc+sd-jwt";
88

99
public const string MdocFormat = "mso_mdoc";
10+
11+
public const string RegistrationCertificateFormat = "jwt";
1012
}

src/WalletFramework.Oid4Vc/CredentialSet/CredentialSetService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
using Hyperledger.Aries.Storage;
22
using LanguageExt;
33
using WalletFramework.Core.Credentials;
4+
using WalletFramework.Core.StatusList;
45
using WalletFramework.Oid4Vc.CredentialSet.Models;
5-
using WalletFramework.SdJwtVc.Services;
66

77
namespace WalletFramework.Oid4Vc.CredentialSet;
88

src/WalletFramework.Oid4Vc/CredentialSet/Models/CredentialSetRecord.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
using WalletFramework.Core.Credentials;
77
using WalletFramework.Core.Functional;
88
using WalletFramework.Core.Json;
9+
using WalletFramework.Core.StatusList;
910
using WalletFramework.Core.String;
1011
using WalletFramework.MdocLib;
1112
using WalletFramework.MdocVc;
1213
using WalletFramework.Oid4Vc.Oid4Vci.Issuer.Models;
1314
using WalletFramework.SdJwtVc.Models;
1415
using WalletFramework.SdJwtVc.Models.Records;
15-
using WalletFramework.SdJwtVc.Models.StatusList;
1616
using CredentialState = WalletFramework.Core.Credentials.CredentialState;
1717

1818
namespace WalletFramework.Oid4Vc.CredentialSet.Models;

0 commit comments

Comments
 (0)