public static extern bool CryptEncodeObjectEx ( [param: In, MarshalAs(UnmanagedType.U4)] EncodingType dwCertEncodingType, [param: In, MarshalAs(UnmanagedType.LPStr)] string lpszStructType, [param: In, MarshalAs(UnmanagedType.Struct)] ref CERT_ALT_NAME_INFO pvStructInfo, [param: In, MarshalAs(UnmanagedType.U4)] uint dwFlags, [param: In, MarshalAs(UnmanagedType.SysInt)] IntPtr pEncodePara, [param: Out] out LocalBufferSafeHandle pvEncoded, [param: In, Out, MarshalAs(UnmanagedType.U4)] ref uint pcbEncoded );
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(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(altNames[index].Value) }; unionValues.Add(altName.Value.pwszURL); break; } Marshal.StructureToPtr(altName, IntPtrArithmetic.Add(altNamesBuffer, offset), false); } certAltName.rgAltEntry = altNamesBuffer; uint dataSize = 0; byte[] 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("Failed to encode object."); } return data; } finally { Marshal.FreeHGlobal(altNamesBuffer); unionValues.ForEach(Marshal.FreeHGlobal); } }
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); } }