title: C# generate Self Signed Cert with Subject Alternative Name?
body: <p>We have an app that generates a Self Signed Cert but now with Chrome 58 we need to add the Subject Alternative Name.  The Cert is generated using C# but invoking the CertCreateSelfSignCertificate function in win32.  So far all the examples I am finding are not passing the extensions param and I'm finding it hard to create an extension to pass to generate the SAN.  </p>
  
  <p><strong>Note I will be cleaning this up once I get it working</strong>
  This is what I am using to create an Entry and then the Extension: </p>
  
  <pre><code>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
              }; 
  </code></pre>
  
  <p><strong>Structs Used</strong>  </p>
  
  <pre><code>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-&gt;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;
          }
  </code></pre>
  
  <p><strong>Full Code - Pieced together from a few examples I found</strong></p>
  
  <pre><code>private static CertExtensions CreateExtensions(IList&lt;CERT_ALT_NAME_ENTRY&gt; items)
          {
  
              IntPtr itemBlob = Marshal.AllocHGlobal(items.Count * Marshal.SizeOf(typeof(CERT_ALT_NAME_ENTRY)));
  
              for (int i = 0; i &lt; 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;
          }
  </code></pre>