我们有一个应用程序可以生成自签名证书但现在使用Chrome 58我们需要添加主题备用名称。 Cert使用C#生成,但在win32中调用CertCreateSelfSignCertificate函数。到目前为止,我发现的所有示例都没有通过扩展参数,我发现很难创建一个扩展来传递生成SAN。
请注意,一旦我开始工作,我就会清理它 这是我用来创建一个条目,然后是扩展名:
CERT_ALT_NAME_ENTRY entry = new CERT_ALT_NAME_ENTRY {
dwAltNameChoice = AlternativeNameType.Dns, // 3
Name = Marshal.StringToHGlobalUni("127.0.0.1")
};
IntPtr entryBlob Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CERT_ALT_NAME_ENTRY)));
var pvStructInfo = new CERT_ALT_NAME_INFO { cAltEntry = 1, rgAltEntry = entryBlob };
IntPtr pvEncoded = IntPtr.Zero;
int pcbEncoded = 0;
var status = InvokeMethods.CryptEncodeObjectEx(
CertEncodingType.X509_ASN_ENCODING | CertEncodingType.PKCS_7_ASN_ENCODING, // 1 | 0x10000
new IntPtr(12),
ref pvStructInfo,
EncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG, // 0x8000
IntPtr.Zero,
ref pvEncoded,
ref pcbEncoded);
Marshal.FreeHGlobal(entryBlob);
if (!status)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var extension = new CERT_EXTENSION
{
ExtensionOid = OidSubjectAltName, //2.5.29.17
IsCritical = false,
Value = new CRYPTOAPI_BLOB
{
Length = (uint)pcbEncoded,
Data = pvEncoded
}
};
var result = new CertExtensions
{
cExtension = 1,
rgExtension = extension
};
使用的结构
internal struct CertExtensions
{
public uint cExtension;
public CERT_EXTENSION rgExtension;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct CRYPTOAPI_BLOB
{
public uint Length;
public IntPtr Data;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal class CERT_EXTENSION
{
[MarshalAs(UnmanagedType.LPWStr)]
public string ExtensionOid;
public bool IsCritical;
public CRYPTOAPI_BLOB Value;
}
[StructLayoutAttribute(LayoutKind.Sequential)]
internal struct CERT_ALT_NAME_INFO
{
/// DWORD->unsigned int
public uint cAltEntry;
public IntPtr rgAltEntry;
}
[StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct CERT_ALT_NAME_ENTRY
{
public AlternativeNameType dwAltNameChoice;
public IntPtr Name;
}
完整代码 - 从我发现的几个例子拼凑而成
private static CertExtensions CreateExtensions(IList<CERT_ALT_NAME_ENTRY> items)
{
IntPtr itemBlob = Marshal.AllocHGlobal(items.Count * Marshal.SizeOf(typeof(CERT_ALT_NAME_ENTRY)));
for (int i = 0; i < items.Count; i++)
{
var offset = (IntPtr)((long)itemBlob + i * Marshal.SizeOf(typeof(CERT_ALT_NAME_ENTRY)));
Marshal.StructureToPtr(items[i], offset, false);
}
var pvStructInfo = new CERT_ALT_NAME_INFO { cAltEntry = (uint)items.Count, rgAltEntry = itemBlob };
IntPtr pvEncoded = IntPtr.Zero;
int pcbEncoded = 0;
var status = InvokeMethods.CryptEncodeObjectEx(
CertEncodingType.X509_ASN_ENCODING | CertEncodingType.PKCS_7_ASN_ENCODING,
new IntPtr(12),
ref pvStructInfo,
EncodeObjectFlags.CRYPT_ENCODE_ALLOC_FLAG,
IntPtr.Zero,
ref pvEncoded,
ref pcbEncoded);
Marshal.FreeHGlobal(itemBlob);
if (!status)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var extension = new CERT_EXTENSION
{
ExtensionOid = OidSubjectAltName,
IsCritical = false,
Value = new CRYPTOAPI_BLOB
{
Length = (uint)pcbEncoded,
Data = pvEncoded
}
};
var result = new CertExtensions
{
cExtension = 1,
rgExtension = extension
};
return result;
}