C#生成具有主题替代名称的自签名证书?

时间:2017-05-10 18:02:01

标签: c# x509certificate

我们有一个应用程序可以生成自签名证书但现在使用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;
        }

0 个答案:

没有答案