Search code examples
c#bouncycastlex509certificate2.net-4.7.2

Add CRL Distribution Points (CDP) Extension to X509Certificate2 Certificate


I trying to add certificate extension to my X509Certificate2 object in pure .NET 4.7.2
I was using BouncyCastle by this method:

private static void AddCdpUrl(X509V3CertificateGenerator certificateGenerator, string cdptUrl)
{
    var uriGeneralName = new GeneralName(GeneralName.UniformResourceIdentifier, cdptUrl);
    var cdpName = new DistributionPointName(DistributionPointName.FullName, uriGeneralName);
    var cdp = new DistributionPoint(cdpName, null, null);
    certificateGenerator.AddExtension(X509Extensions.CrlDistributionPoints, false, new CrlDistPoint(new[] { cdp }));
}

Add its works and I get great result:
enter image description here

Now in pure .NET I am using this method:

const string X509CRLDistributionPoints = "2.5.29.31";    
certificateRequest.CertificateExtensions.Add(new X509Extension(new Oid(X509CRLDistributionPoints), Encoding.UTF8.GetBytes("http://crl.example.com"), false));

And get this result:
enter image description here

I am missing the sequences for "Distribution Point Name", "Full Name" and "URL="

How can I generate the same result that BouncyCastle does with pure .NET

Thanks


Solution

  • Update (2023-03-20): .NET 7 now has the CertificateRevocationListBuilder method to do this for you (and isn't even limited to a single 119-character value!).

    X509Extension cdpExtension =
        CertificateRevocationListBuilder.BuildCrlDistributionPointExtension(
            new[] { url });
    

    Original Answer (.NET <7)

    If you only want to write one distribution point, and it's less than or equal to 119 ASCII characters long, and you aren't delegating CRL signing authority to a different certificate:

    private static X509Extension MakeCdp(string url)
    {
        byte[] encodedUrl = Encoding.ASCII.GetBytes(url);
    
        if (encodedUrl.Length > 119)
        {
            throw new NotSupportedException();
        }
    
        byte[] payload = new byte[encodedUrl.Length + 10];
        int offset = 0;
        payload[offset++] = 0x30;
        payload[offset++] = (byte)(encodedUrl.Length + 8);
        payload[offset++] = 0x30;
        payload[offset++] = (byte)(encodedUrl.Length + 6);
        payload[offset++] = 0xA0;
        payload[offset++] = (byte)(encodedUrl.Length + 4);
        payload[offset++] = 0xA0;
        payload[offset++] = (byte)(encodedUrl.Length + 2);
        payload[offset++] = 0x86;
        payload[offset++] = (byte)(encodedUrl.Length);
        Buffer.BlockCopy(encodedUrl, 0, payload, offset, encodedUrl.Length);
    
        return new X509Extension("2.5.29.31", payload, critical: false);
    }
    

    Past 119 characters the outer payload length exceeds 0x7F and then you really start wanting a proper DER encoder. You definitely want one for variable numbers of URLs, or including any of the optional data from the extension.