3

I understand from reading MSDN that the X509 v3 extensions must be handcrafted. This involves the CRL, AIA, name and policy constraints, policy mapping, private key usage period, and subject directory attributes.

I tried to make a CRL distribution point but the result is garbage:

    $crlExt = New-Object -ComObject X509Enrollment.CX509Extension
    $crlOid = New-Object -ComObject X509Enrollment.CObjectId
    $crlOid.InitializeFromValue('2.5.29.31')
    $crlValue = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes('http://www.test.com'))
    $crlExt.Initialize($crlOid, 0x1, $crlValue)
    $crlExt.Critical = $false

Is there any reference on how to encode the values for each of the following? I have searched all over but no luck.

  • AuthorityInformationAccess
  • CrlDistributionPoints
  • FreshestCRL
  • NameConstraints
  • PolicyConstraints
  • PolicyMappings
  • PrivateKeyUsagePeriod
  • SubjectDirectoryAttributes

Note that this is about the certenroll com interface in Windows. openssl is not applicable here.

Max
  • 77
  • 5
  • Most of them are defined (in ASN.1 format) in RFC5280, ASN.1 module appendixes. – Crypt32 Mar 08 '16 at 20:36
  • But is there not way but to roll your own? CryptoEncodeObjectEx seems hopeful but still can't figure it out. – Max Mar 09 '16 at 13:22
  • 1
    I have implemented few managed extension classes in PSPKI module: http://pkix2.sysadmins.lv/library/html/N_System_Security_Cryptography_X509Certificates.htm, new extensions are expected to appear in the next version. – Crypt32 Mar 10 '16 at 14:40

1 Answers1

0

I've just came across the same issue in C#, trying to generate certificates with CDPs (CRL Distribution Points) extension through CertEnroll.dll

The only way I could make this work was by handcrafting the extension at byte level, though I didn't find any documentation about how the bytes should be ordered or the meaning of some bytes. To figure it out I generated some certs using OpenSSL in Linux and inspected the raw bytes in C# (load the certificate in X509Certificate2 class and take a look at the Extensions property. The X509Extension class has a RawData property).

You should be able to convert my code to PowerShell, so I ended up with:

var urisStr = new string[]
{
    "http://pki.example.com/list.crl"
};
var uris = urisStr.Select(u => Encoding.UTF8.GetBytes(u));
var zero = new byte[] { 48 }; //"0", delimiter ?
var nbsp = new byte[] { 160 }; //" ", separator ?
var dagger = new byte[] { 134 }; //"dagger", separator ?

var zeroSize = zero.Length + 1;
var nbspSize = nbsp.Length + 1;
var daggerSize = dagger.Length + 1;

var col = new List<byte>();
col.AddRange(zero); //delimiter
int totalBytes = uris.Sum(u => u.Length);
totalBytes += (zeroSize + (nbspSize * 2) + daggerSize) * uris.Count();
col.Add((byte)totalBytes); //size of everything it contains

foreach (var uri in uris)
{
    var uriSize = uri.Length;
    col.AddRange(zero); //delimiter
    col.Add((byte)(nbspSize + nbspSize + uriSize + daggerSize)); //size of everything it contains
    col.AddRange(nbsp);
    col.Add((byte)(nbspSize + uriSize + daggerSize)); //size of everything it contains
    col.AddRange(nbsp);
    col.Add((byte)(uriSize + daggerSize)); //size of everything it contains
    col.AddRange(dagger); //separator ?
    col.Add((byte)uriSize);
    col.AddRange(uri);
}
var bytes = col.ToArray();
var base64 = Convert.ToBase64String(bytes);

var oidCDP = new CObjectId();
oidCDP.InitializeFromName(CERTENROLL_OBJECTID.XCN_OID_CRL_DIST_POINTS);

// There is no specific class to CDPs, so we use the CX509Extension
var crlList = new CX509Extension();
crlList.Initialize(oidCDP, EncodingType.XCN_CRYPT_STRING_BASE64, base64);
certRequest.X509Extensions.Add(crlList);

Please note that I didn't found any documentation about the format of the bytes that I'm generating, so this code has no official basis. It's based only on observations of working certificates.

Dinei
  • 4,494
  • 4
  • 36
  • 60