private static byte[] EncodeData(byte[] publicKey, byte[] serialNumber)
        {
            IntPtr publicKeyPtr = IntPtr.Zero, serialNumberPtr = IntPtr.Zero;

            try
            {
                var identifier = new CERT_AUTHORITY_KEY_ID2_INFO();
                identifier.AuthorityCertIssuer = new CERT_ALT_NAME_INFO {
                    cAltEntry = 0
                };
                if (serialNumber != null)
                {
                    serialNumberPtr = Marshal.AllocHGlobal(serialNumber.Length);
                    Marshal.Copy(serialNumber, 0, serialNumberPtr, serialNumber.Length);
                    identifier.AuthorityCertSerialNumber = new CRYPTOAPI_BLOB {
                        cbData = (uint)serialNumber.Length, pbData = serialNumberPtr
                    };
                }
                if (publicKey != null)
                {
                    publicKeyPtr = Marshal.AllocHGlobal(publicKey.Length);
                    Marshal.Copy(publicKey, 0, publicKeyPtr, publicKey.Length);
                    identifier.KeyId = new CRYPTOAPI_BLOB {
                        cbData = (uint)publicKey.Length, pbData = publicKeyPtr
                    };
                }
                uint dataSize = 0;
                LocalBufferSafeHandle data;
                if (!Crypt32.CryptEncodeObjectEx(EncodingType.X509_ASN_ENCODING, OIDs.szOID_AUTHORITY_KEY_IDENTIFIER2, ref identifier, 0x8000, IntPtr.Zero, out data, ref dataSize))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
                using (data)
                {
                    var buffer = new byte[dataSize];
                    Marshal.Copy(data.DangerousGetHandle(), buffer, 0, (int)dataSize);
                    return(buffer);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(publicKeyPtr);
                Marshal.FreeHGlobal(serialNumberPtr);
            }
        }
        private static byte[] EncodeExtension(IList <X509AlternativeName> altNames)
        {
            var certAltName = new CERT_ALT_NAME_INFO();

            certAltName.cAltEntry = (uint)altNames.Count;
            var structSize     = Marshal.SizeOf(typeof(CERT_ALT_NAME_ENTRY));
            var altNamesBuffer = Marshal.AllocHGlobal(structSize * altNames.Count);
            var unionValues    = new List <IntPtr>();

            try
            {
                for (int index = 0, offset = 0; index < altNames.Count; index++, offset += structSize)
                {
                    var altName = new CERT_ALT_NAME_ENTRY();
                    altName.dwAltNameChoice = (CertAltNameChoice)altNames[index].Type;
                    switch (altName.dwAltNameChoice)
                    {
                    case CertAltNameChoice.CERT_ALT_NAME_DNS_NAME:
                        altName.Value = new CERT_ALT_NAME_ENTRY_UNION
                        {
                            pwszDNSName = Marshal.StringToHGlobalUni((string)altNames[index].Value)
                        };
                        unionValues.Add(altName.Value.pwszDNSName);
                        break;

                    case CertAltNameChoice.CERT_ALT_NAME_URL:
                        altName.Value = new CERT_ALT_NAME_ENTRY_UNION
                        {
                            pwszURL = Marshal.StringToHGlobalUni((string)altNames[index].Value)
                        };
                        unionValues.Add(altName.Value.pwszURL);
                        break;

                    case CertAltNameChoice.CERT_ALT_NAME_IP_ADDRESS:
                        var ip           = (IPAddress)altNames[index].Value;
                        var addressBytes = ip.GetAddressBytes();
                        var ipBytes      = Marshal.AllocHGlobal(addressBytes.Length);
                        Marshal.Copy(addressBytes, 0, ipBytes, addressBytes.Length);
                        altName.Value = new CERT_ALT_NAME_ENTRY_UNION
                        {
                            IPAddress = new CRYPTOAPI_BLOB
                            {
                                cbData = (uint)addressBytes.Length,
                                pbData = ipBytes
                            }
                        };
                        unionValues.Add(ipBytes);
                        break;
                    }
                    Marshal.StructureToPtr(altName, IntPtrArithmetic.Add(altNamesBuffer, offset), false);
                }
                certAltName.rgAltEntry = altNamesBuffer;
                uint dataSize = 0;
                LocalBufferSafeHandle data;
                if (!Crypt32.CryptEncodeObjectEx(EncodingType.X509_ASN_ENCODING, OIDs.szOID_SUBJECT_ALT_NAME2, ref certAltName, 0x8000, IntPtr.Zero, out data, ref dataSize))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
                using (data)
                {
                    var buffer = new byte[dataSize];
                    Marshal.Copy(data.DangerousGetHandle(), buffer, 0, (int)dataSize);
                    return(buffer);
                }
            }
            finally
            {
                Marshal.FreeHGlobal(altNamesBuffer);
                unionValues.ForEach(Marshal.FreeHGlobal);
            }
        }