Certificate.BuildChainAsync fails with custom trust root
Describe the bug
Trying to validate a certificate which is issued by a known authority, that is not installed in the Trusted Root Store fails with COMException 'The operation attempted to access data outside the valid range (0x8000000B)'
This happens when the known issuer is added to the ExclusiveTrustRoots list of the ChainBuildingParameters object.
Steps to reproduce the bug
- Create a project targeting .NET 7 and call the VerifyCertificate method as specified below
- The exception will be thrown .
- If the line
builderParams.ExclusiveTrustRoots.Add(issuerCert);is removed, it will successfully validate the certificate, but of course with a result of Untrusted.
` public static async Task VerifyCertificate() { var childBlob = System.Convert.FromBase64String("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"); var issuerBlob = System.Convert.FromBase64String("MIIFTzCCAzegAwIBAgIQGiooCWlWUr9EvAa05KWP2jANBgkqhkiG9w0BAQsFADBTMSMwIQYDVQQDExpWaWRpVmlldyBMaWNlbnNlIEF1dGhvcml0eTEfMB0GA1UEChMWRGlzdHJpYnV0ZWQgTWVkaWNhbCBBQjELMAkGA1UEBhMCU0UwIBcNMTYxMDI1MDcyMDEyWhgPMjA3OTEyMzEwMDAwMDBaMFMxIzAhBgNVBAMTGlZpZGlWaWV3IExpY2Vuc2UgQXV0aG9yaXR5MR8wHQYDVQQKExZEaXN0cmlidXRlZCBNZWRpY2FsIEFCMQswCQYDVQQGEwJTRTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvUTa+JNG5L60mCZAAztFoYCUBMGs76Yk/7+a0DCfuNY367uUx8L1Qne6S2ei0awQiEBgrndeCSXV7Y8avCdaLZjAv85YLwuYf3J94K2Xj6HDqWsTxJ4H0o6tuL2pmY+cz99AIZA3nPWMF0FfneeM+pxo7sZ4IBhzqaNKSluhjE9ReS1h+230n6/lzvCPv3iw2ksnvKTNXKELUGA6kXJzSRPU/vhRDqtdAjJp+YkhpHr5VP3Gz4glUx3mobVOb7u/xJDll6f2IIn8O/BrgkatBbEmKcoJOMcmFJclcjBz8ZCfHmK9KQuk73nU+Ijuo5UugBx+cuZ6R3GrV2c4fmIcRChCNsO6Hs34uqM94ATzwydzZ4I6Vpk4f6PR8N8rk4ZoDmaQXd/s1cARxVH49ts6C201ygQ8wD2ds7GOD9RtoQ2VsNl4Nrzo0p8THPx7tMJyLy2GjdJiMtlQ6AFezeH0BkERmswU+CXyNHR6jfuWcnse0c+KhK4OUkUfb7t61Igfiu8LwPyvOtd9/lJZgt0kXcMBvYwaSR2VwSiHXtVf7lcrJr+w17ytZgVCuot2+5SJ8Aa1QEFR+KtzYYmtbGU/PvZgNjGwYMpYrPrZikf6xPSQDb9954bB6sj8BOy6tb7+DjkkYK8FkjEd2uaM5F+JD0Zv1cqMVlLx+PtYrZxy1LAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MA0GCSqGSIb3DQEBCwUAA4ICAQCEMicj4FxdXn5nItAUoJ2oAtOPIMpp3sUnBWtNq0EYViCD7JfjJc1q2BFhgXwSQMqzPZ3onZlryms68ygdLMDav2aUjrzfrM82ncX1aZBso6Vdl0GS/HDA38aX5wTTEjpv3LueFbOm3x4vh6WDPaWDBssgtEefx6tdzTWK3XOYaHhDw5fnn1k1NNUa3Yx1DJ2HuXxnULJkgdjIDGIZuZ5wduB3OKqiV673OKnKMppPXDLNamVg63gco420sfcqgm3xU0PYDKkPIJ6P1HU3A/MdIlLEE+VaHDqvbPcckSQZALsiDrIHqK1vSgbCYdaeEXqCE6EVT1kLiYS6u+TDQfNQy+VNpTwyleqpbBvIrEJ5/qYRBs2fq7BPceZG+Pa2PH8svqMypTkB0gLwMY2jMLl0ckZkyHD0fcJsKxlAEUNwzcai8z1d2wBHBfDuYsh54+F4PB5bqT031nbTHewjQYhW0GvexI1r9qT9O/d+vP21g62DIJ3TVTH5cYPySx4H2vuAW3a+umX1E1jV18FKPMDxESuS8WfOCofGkgNVgCfEvXbu730pAT50TY6YDt+a713LDFTQpMyhL+2NRUS+emE8nxrrCWlhEhZhqYW7RBTg1yR+Ohja4RESilZ9D4BJNSMxZC2u37Uf8A6kbLnykGulQhW18iZk8BtT4sfG+iII4A==");
var childCert = new Windows.Security.Cryptography.Certificates.Certificate(childBlob.AsBuffer());
var issuerCert = new Windows.Security.Cryptography.Certificates.Certificate(issuerBlob.AsBuffer());
var builderParams = new Windows.Security.Cryptography.Certificates.ChainBuildingParameters()
{
CurrentTimeValidationEnabled = true,
NetworkRetrievalEnabled = false,
RevocationCheckEnabled = false,
};
builderParams.ExclusiveTrustRoots.Add(issuerCert);
var result = await childCert.BuildChainAsync(new[] { issuerCert }, builderParams);
var r = result.Validate();
System.Diagnostics.Debug.Assert(r == Windows.Security.Cryptography.Certificates.ChainValidationResult.Success);
}
`
Expected behavior
I would expect the code to successfully validate the certificate if it is issued by one of the certificates in the ExclusiveTrustRoot with a result of ChainValidationResult.Success.
Also, if the certificate is issued by any other authority (even the ones installed in the Trusted Root Store), it should succeed but return ChainValidationResult.Untrusted since the trust list is exclusive.
Screenshots
No response
NuGet package version
Windows App SDK 1.3.0: 1.3.230331000
Packaging type
No response
Windows version
Windows 11 version 22H2 (22621, 2022 Update)
IDE
Visual Studio 2022
Additional context
No response
@bjorn-malmo Can you help us understand how this is connected with Windows App SDK? Did the blobs in question come from the signature on a Windows App SDK binary?
The same two certificates as in the previous example, will work as expected with the X509Chain class to validate a child certificate with a specific trusted root (not present in the Trusted Certificate Root store), as in the following example.
The problem I'm trying to solve is connecting to a host having a certificate that is issued by an internal authority, and this should be verified by the client. The client will never have this issuer in the Trusted Root store though. Using X509Certificate2 and X509Chain, the custom issuer can be added to the chain and hereafter successfully validate.
However, using the newer Windows...Certificate does not work as in the previous sample.
public static async Task VerifyLegacyCertificate()
{
var childBlob = System.Convert.FromBase64String("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");
var issuerBlob = System.Convert.FromBase64String("MIIFTzCCAzegAwIBAgIQGiooCWlWUr9EvAa05KWP2jANBgkqhkiG9w0BAQsFADBTMSMwIQYDVQQDExpWaWRpVmlldyBMaWNlbnNlIEF1dGhvcml0eTEfMB0GA1UEChMWRGlzdHJpYnV0ZWQgTWVkaWNhbCBBQjELMAkGA1UEBhMCU0UwIBcNMTYxMDI1MDcyMDEyWhgPMjA3OTEyMzEwMDAwMDBaMFMxIzAhBgNVBAMTGlZpZGlWaWV3IExpY2Vuc2UgQXV0aG9yaXR5MR8wHQYDVQQKExZEaXN0cmlidXRlZCBNZWRpY2FsIEFCMQswCQYDVQQGEwJTRTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvUTa+JNG5L60mCZAAztFoYCUBMGs76Yk/7+a0DCfuNY367uUx8L1Qne6S2ei0awQiEBgrndeCSXV7Y8avCdaLZjAv85YLwuYf3J94K2Xj6HDqWsTxJ4H0o6tuL2pmY+cz99AIZA3nPWMF0FfneeM+pxo7sZ4IBhzqaNKSluhjE9ReS1h+230n6/lzvCPv3iw2ksnvKTNXKELUGA6kXJzSRPU/vhRDqtdAjJp+YkhpHr5VP3Gz4glUx3mobVOb7u/xJDll6f2IIn8O/BrgkatBbEmKcoJOMcmFJclcjBz8ZCfHmK9KQuk73nU+Ijuo5UugBx+cuZ6R3GrV2c4fmIcRChCNsO6Hs34uqM94ATzwydzZ4I6Vpk4f6PR8N8rk4ZoDmaQXd/s1cARxVH49ts6C201ygQ8wD2ds7GOD9RtoQ2VsNl4Nrzo0p8THPx7tMJyLy2GjdJiMtlQ6AFezeH0BkERmswU+CXyNHR6jfuWcnse0c+KhK4OUkUfb7t61Igfiu8LwPyvOtd9/lJZgt0kXcMBvYwaSR2VwSiHXtVf7lcrJr+w17ytZgVCuot2+5SJ8Aa1QEFR+KtzYYmtbGU/PvZgNjGwYMpYrPrZikf6xPSQDb9954bB6sj8BOy6tb7+DjkkYK8FkjEd2uaM5F+JD0Zv1cqMVlLx+PtYrZxy1LAgMBAAGjHTAbMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MA0GCSqGSIb3DQEBCwUAA4ICAQCEMicj4FxdXn5nItAUoJ2oAtOPIMpp3sUnBWtNq0EYViCD7JfjJc1q2BFhgXwSQMqzPZ3onZlryms68ygdLMDav2aUjrzfrM82ncX1aZBso6Vdl0GS/HDA38aX5wTTEjpv3LueFbOm3x4vh6WDPaWDBssgtEefx6tdzTWK3XOYaHhDw5fnn1k1NNUa3Yx1DJ2HuXxnULJkgdjIDGIZuZ5wduB3OKqiV673OKnKMppPXDLNamVg63gco420sfcqgm3xU0PYDKkPIJ6P1HU3A/MdIlLEE+VaHDqvbPcckSQZALsiDrIHqK1vSgbCYdaeEXqCE6EVT1kLiYS6u+TDQfNQy+VNpTwyleqpbBvIrEJ5/qYRBs2fq7BPceZG+Pa2PH8svqMypTkB0gLwMY2jMLl0ckZkyHD0fcJsKxlAEUNwzcai8z1d2wBHBfDuYsh54+F4PB5bqT031nbTHewjQYhW0GvexI1r9qT9O/d+vP21g62DIJ3TVTH5cYPySx4H2vuAW3a+umX1E1jV18FKPMDxESuS8WfOCofGkgNVgCfEvXbu730pAT50TY6YDt+a713LDFTQpMyhL+2NRUS+emE8nxrrCWlhEhZhqYW7RBTg1yR+Ohja4RESilZ9D4BJNSMxZC2u37Uf8A6kbLnykGulQhW18iZk8BtT4sfG+iII4A==");
var childCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(childBlob);
var issuerCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(issuerBlob);
using var chain = new System.Security.Cryptography.X509Certificates.X509Chain();
chain.ChainPolicy.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
bool success = chain.Build(childCert);
System.Diagnostics.Debug.Assert(success == false);
using var chainWithCustomIssuer = new System.Security.Cryptography.X509Certificates.X509Chain();
chainWithCustomIssuer.ChainPolicy.RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck;
chainWithCustomIssuer.ChainPolicy.TrustMode = System.Security.Cryptography.X509Certificates.X509ChainTrustMode.CustomRootTrust;
chainWithCustomIssuer.ChainPolicy.CustomTrustStore.Add(issuerCert);
success = chain.Build(childCert);
System.Diagnostics.Debug.Assert(success == true);
}
I have the exact same issue.