Open bugnuker opened 2 years ago
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!");
}
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!
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.