Skip to content
This repository has been archived by the owner on Aug 7, 2023. It is now read-only.

CSharp version not compatible with .NET Core and .NET 5/6 #33

Open
bugnuker opened this issue Jan 5, 2022 · 2 comments
Open

CSharp version not compatible with .NET Core and .NET 5/6 #33

bugnuker opened this issue Jan 5, 2022 · 2 comments

Comments

@bugnuker
Copy link

bugnuker commented Jan 5, 2022

The included sample is not compatible with .NET core, or .NET 5 and 6. This only works with .NET Framework.

The underlying issue is extracting the keys from the token.

.NET and .NET Core will throw a null ref exception because the cast to JArray is not working for .NET and .NET Core.

The real error is: ​Unable to cast object of type 'Microsoft.IdentityModel.Json.Linq.JArray'

It seems this might be due to .NET using System.Text.Json rather than newtonsoft. The space 'Microsoft.IdentityModel.Json.Linq.JArray' is private and can not be accessed.

@brunopiovan
Copy link

brunopiovan commented Feb 4, 2022

this should get you started...

using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography.X509Certificates;
using System.Text.Json;
using Microsoft.IdentityModel.Tokens;

const string attestationStatementString = "token here";
const string validHostName = "attest.android.com";

var token = new JwtSecurityToken(attestationStatementString);
var x5c = JsonSerializer.Deserialize<string[]>(token.Header.X5c)!;

//or use this if you don't need JwtSecurityToken
//var array = attestationStatementString.Split(new[] { '.' }, 2);
//var header = JwtHeader.Base64UrlDeserialize(array[0]);
//var x5c = JsonSerializer.Deserialize<string[]>(header.X5c)!;

if (x5c.Length == 0) return;

var signingKeys = x5c
    .Select(Convert.FromBase64String)
    .Select(x => new X509Certificate2(x))
    .Select(x => new X509SecurityKey(x));

var validationParameters = new TokenValidationParameters
{
    ValidateIssuer = false,
    ValidateAudience = false,
    ValidateLifetime = false,
    ValidateIssuerSigningKey = true,
    IssuerSigningKeys = signingKeys
};

var handler = new JwtSecurityTokenHandler();
handler.ValidateToken(attestationStatementString, validationParameters, out var validatedToken);

if (validatedToken.SigningKey is not X509SecurityKey x509SecurityKey)
{
    Console.WriteLine("The signing key is invalid.");
    return;
}

var chain = new X509Chain();
var chainBuilt = chain.Build(x509SecurityKey.Certificate);
if (!chainBuilt)
{
    foreach (var chainStatus in chain.ChainStatus)
    {
        Console.WriteLine(string.Format("Chain error: {0} {1}", chainStatus.Status, chainStatus.StatusInformation));
    }

    return;
}

var isHostNameValid = x509SecurityKey.Certificate.GetNameInfo(X509NameType.DnsName, false) == validHostName;
if (isHostNameValid)
{
    Console.WriteLine("Validation ok!");
}
else
{
    Console.WriteLine("Validation failed!");
}

@bugnuker
Copy link
Author

bugnuker commented Feb 4, 2022

This worked great, thanks! The part that was needed:

var x5c = JsonSerializer.Deserialize<string[]>(token.Header.X5c)!;
if (x5c.Length == 0) return;

var signingKeys = x5c
    .Select(Convert.FromBase64String)
    .Select(x => new X509Certificate2(x))
    .Select(x => new X509SecurityKey(x));

Thanks again!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants