Reputation: 1
for a legacy .NET Framework application I need to create a self-signed certificate using CERTENROLLLib (i.e. CERTEnroll.dll from the Windows SDK). A basic certificate can be successfully created using this method.
As a new feature this certicicate must contain an Authority Key Identifier extension. This is added to the working certificate request:
var dn = new CX500DistinguishedName();
dn.Encode("CN=" + certificate.SubjectName);
var rng = RandomNumberGenerator.Create();
var serialNumberBytes = new byte[SerialNumberLengthMin];
rng.GetBytes(serialNumberBytes);
// Only positive numbers are allowed
serialNumberBytes[serialNumberBytes.Length - 1] &= 0x7f;
// Convert it to a hex string in little endian
var serialNumber = GetHexString(serialNumberBytes, true);
var certificateRequest = new CX509CertificateRequestCertificate();
CX509ExtensionAuthorityKeyIdentifier aki = new CX509ExtensionAuthorityKeyIdentifierClass();
aki.InitializeEncode(EncodingType.XCN_CRYPT_STRING_HEX, CreateAuthorityKeyIdentifier(dn.Name, serialNumberBytes));
certificateRequest.X509Extensions.Add((CX509Extension)aki);
The method CreateAuthorityKeyIdentifier uses AsnWriter(AsnEncodingRules.DER) to generate a string that is converted to a big endian hex string.
private static string CreateAuthorityKeyIdentifier(string issuer, byte[] serialNumber)
{
var keyId = "2.5.29.35";
var writer = new AsnWriter(AsnEncodingRules.DER);
writer.PushSequence();
var keyIdTag = new Asn1Tag(TagClass.ContextSpecific, 0);
writer.WriteOctetString(Encoding.ASCII.GetBytes(keyId), keyIdTag);
var issuerNameTag = new Asn1Tag(TagClass.ContextSpecific, 1);
writer.PushSequence(issuerNameTag);
var directoryNameTag = new Asn1Tag(TagClass.ContextSpecific, 4, true);
writer.PushSetOf(directoryNameTag);
writer.WriteEncodedValue((new X500DistinguishedName(issuer)).RawData);
writer.PopSetOf(directoryNameTag);
writer.PopSequence(issuerNameTag);
var issuerSerialTag = new Asn1Tag(TagClass.ContextSpecific, 2);
var issuerSerial = new BigInteger(serialNumber);
writer.WriteInteger(issuerSerial, issuerSerialTag);
writer.PopSequence();
return GetHexString(writer.Encode());
}
After creating an enrollment and calling CX509Enrollment.CreatePFX this throws an exception with error code CertEnroll::CX509Enrollment::CreatePFX: Invalid Signature. 0x80090006 (-2146893818 NTE_BAD_SIGNATURE). The CX509Enrollment.InstallResponse is called before and does not throw an exception.
I'm at a loss solving the cause of the exception.
The certificate is correctly created with other extensions. Sadly the authority key identifier is needed by the used library to accept this certificate.
Upvotes: 0
Views: 48