Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion maa.jwt.verifier.dotnet/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ private static bool VerifyUvmEndorsement(string endorsementsValue)

// Step 3: Validate full certificate chain (COSE Sign1 Object -> ProtectedHeaders -> x5chain).
var trustedRoots = new[] { Utils.PemStringToRsa(((CoseSign1.TrustedCertChainSigner)trustAnchor.Signer).CertChain.PemRootCaPublicKey) };
if (!Utils.BuildAndValidateCertChain(certificates, trustedRoots, Utils.CertValidationTarget.Root))
if (!Utils.BuildAndValidateCertChain(certificates, trustedRoots, Utils.CertValidationTarget.Root, ignoreLeafExpiration: true))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this recommendation can be passed on because the sample does not recommend disabling leaf certificate expiration validation. The sample is to demonstrate how to validate a MAA-issued JWT.

Crypto libraries such as OpenSSL (https://docs.openssl.org/master/man3/X509_VERIFY_PARAM_set_flags/) already provide flags that allow consumers to configure validation behavior based on their specific requirements or for testing purposes. Adding this flag provides the same convenience.

{
Console.WriteLine("ERROR: Certificate chain validation failed.");
return false;
Expand Down
31 changes: 26 additions & 5 deletions maa.jwt.verifier.dotnet/TrustedValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ public static class TrustedValues
// -----------------------------------------------------------------------------------

/// <summary>
/// AMD root key for validating UVM endorsements. Provided by AMD.
/// AMD Milan root key for validating SEVSNP reports. Provided by AMD.
/// Contact AMD for updates or rotated root keys.
/// </summary>
public const string AmdRootKey = @"-----BEGIN PUBLIC KEY-----
public const string AmdRootKeyMilan = @"-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsV
mD7FktuotWwX1fNgW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU
0V5tkKiU1EesNFta1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S
Expand All @@ -31,7 +31,7 @@ public static class TrustedValues
-----END PUBLIC KEY-----";

/// <summary>
/// AMD Genoa-specific root key for validating UVM endorsements from Genoa platforms.
/// AMD Genoa root key for validating SEVSNP reports. Provided by AMD.
/// Contact AMD for updates or rotated root keys.
/// </summary>
public const string AmdRootKeyGenoa = @"-----BEGIN PUBLIC KEY-----
Expand All @@ -49,10 +49,31 @@ public static class TrustedValues
0Hq/sbRuqesxz7wBWSY254cCAwEAAQ==
-----END PUBLIC KEY-----";

/// <summary>
/// AMD Turin root key for validating SEVSNP reports. Provided by AMD.
/// Contact AMD for updates or rotated root keys.
/// </summary>
public const string AmdRootKeyTurin = @"-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwaAriB7EIuVc4ZB1wD3Y
fDxL+9eyS7+izm0Jj3W772NINCWl8Bj3w/JD2ZjmbRxWdIq/4d9iarCKorXloJUB
1jRdgxqccTx1aOoig4+2w1XhVVJT7K457wT5ZLNJgQaxqa9Etkwjd6+9sOhlCDE9
l43kQ0R2BikVJa/uyyVOSwEk5w5tXKOuG9jvq6QtAMJasW38wlqRDaKEGtZ9VUgG
on27ZuL4sTJuC/azz9/iQBw8kEilzOl95AiTkeY5jSEBDWbAqnZk5qlM7kISKG20
kgQm14mhNKDI2p2oua+zuAG7i52epoRF2GfU0TYk/yf+vCNB2tnechFQuP2e8bLk
95ZdqPi9/UWw4JXjtdEA4u2JYplSSUPQVAXKt6LVqujtJcM59JKr2u0XQ75KwxcM
p15gSXhBfInvPAwuAY4dEwwGqT8oIg4esPHwEsmChhYeDIxPG9R4fx9O0q6p8Gb+
HXlTiS47P9YNeOpidOUKzDl/S1OvyhDtSL8LJc24QATFydo/iD/KUdvFTRlD0crk
AMkZLoWQ8hLDGc6BZJXsdd7Zf2e4UW3tI/1oh/2t23Ot3zyhTcv5gDbABu0LjVe9
8uRnS15SMwK//lJt9e5BqKvgABkSoABf+B4VFtPVEX0ygrYaFaI9i5ABrxnVBmzX
pRb21iI1NlNCfOGUPIhVpWECAwEAAQ==
-----END PUBLIC KEY-----";


public static readonly List<string> AmdRootKeys = new()
{
TrustedValues.AmdRootKey,
TrustedValues.AmdRootKeyGenoa
TrustedValues.AmdRootKeyMilan,
TrustedValues.AmdRootKeyGenoa,
TrustedValues.AmdRootKeyTurin
};

// -----------------------------------------------------------------------------------
Expand Down
29 changes: 28 additions & 1 deletion maa.jwt.verifier.dotnet/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,20 +183,47 @@ public enum CertValidationTarget
public static bool BuildAndValidateCertChain(
List<X509Certificate2>? certs,
RSA[] trustedKeys,
CertValidationTarget target)
CertValidationTarget target,
bool ignoreLeafExpiration = false)
{
using var chain = new X509Chain();
chain.ChainPolicy.ExtraStore.AddRange(certs?.ToArray() ?? []);
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;

if (ignoreLeafExpiration)
{
chain.ChainPolicy.VerificationFlags |= X509VerificationFlags.IgnoreNotTimeValid;
}

var leafCert = certs?.FirstOrDefault();
if (leafCert == null || !chain.Build(leafCert))
{
Console.WriteLine("ERROR: Failed to build certificate chain.");
return false;
}

if (ignoreLeafExpiration)
{
DateTime now = DateTime.UtcNow;
if (now < leafCert.NotBefore.ToUniversalTime())
{
Console.WriteLine("ERROR: Leaf certificate is not valid yet.");
return false;
}

foreach (var chainElement in chain.ChainElements.Cast<X509ChainElement>().Skip(1))
{
var certificate = chainElement.Certificate;
if (now < certificate.NotBefore.ToUniversalTime() ||
now > certificate.NotAfter.ToUniversalTime())
{
Console.WriteLine($"ERROR: Non-leaf certificate is outside its validity period: {certificate.Subject}");
return false;
}
}
}

X509Certificate2 certToValidate = target switch
{
CertValidationTarget.Leaf => chain.ChainElements[0].Certificate,
Expand Down