Search code examples
integration-testingx509x509certificate2

In C#, how do I create an invalid X509Chain?


The X509ChainStatusFlags enum contains a lot of possible values: https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509chainstatusflags?view=netframework-4.8

Are there easy ways to construct a certificate and chain that produce some of these flags? I want to construct them in order to integration-test my certificate validation logic.


Solution

  • Each different kind of failure requires a different amount of work to test for. Some are easy, some require heroic effort.

    The easiest: error code 1: X509ChainStatusFlags.NotTimeValid.

    X509Certificate2 cert = ...;
    X509Chain chain = new X509Chain();
    chain.ChainPolicy.VerificationTime = cert.NotBefore.AddSeconds(-1);
    bool valid = chain.Build();
    // valid is false, and the 0 element will have NotTimeValid as one of the reasons.
    

    Next up: X509ChainStatusFlags.NotValidSignature.

    X509Certificate2 cert = ...;
    byte[] certBytes = cert.RawData;
    // flip all the bits in the last byte
    certBytes[certBytes.Length - 1] ^= 0xFF;
    X509Certificate2 badCert = new X509Certificate2(certBytes);
    chain.ChainPolicy.ApplicationPolicy.Add(new Oid("0.0", null));
    bool valid = chain.Build();
    // valid is false. On macOS this results in PartialChain,
    // on Windows and Linux it reports NotValidSignature in element 0
    

    Next up: X509ChainStatusFlags.NotValidForUsage.

    X509Certificate2 cert = ...;
    X509Chain chain = new X509Chain();
    chain.ChainPolicy.ApplicationPolicy.Add(new Oid("0.0", null));
    bool valid = chain.Build();
    // valid is false if the certificate has an EKU extension,
    // since it shouldn't contain the 0.0 OID.
    // and the 0 element will report NotValidForUsage.
    

    Some of the more complicated ones require building certificate chains incorrectly, such as making an child certificate have a NotBefore/NotAfter that isn't nestled within the CA's NotBefore/NotAfter. Some of these heroic efforts are tested in https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/libraries/System.Security.Cryptography.X509Certificates/tests/DynamicChainTests.cs and/or https://github.com/dotnet/runtime/blob/4f9ae42d861fcb4be2fcd5d3d55d5f227d30e723/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/DynamicRevocationTests.cs.