Search code examples
c#.netpinvokemarshallingx509certificate2

Problems when P/Invoking CertCreateSelfSignCertificate


I was following this article (in it there is a link to a .cs file at the bottom of the page) to generate a self-signed X509Certificate2. The code in the article works but now I want to extend it. I am trying to pass the optional argument, _In_opt_ PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm, into CertCreateSelfSignCertificate.

I have created this structure for it:

struct CryptoApiBlob
{
    public Int32 cbData;
    public IntPtr pbData;
}

struct CryptAlgorithmIdentifier {
    public String pszObjId;
    public CryptoApiBlob Parameters;
}

The code I am trying to use to create it is:

CryptAlgorithmIdentifier algorithm = new CryptAlgorithmIdentifier { pszObjId = "szOID_NIST_AES256_CBC", Parameters = new CryptoApiBlob { cbData = 0 } };
algorithmPointer = Marshal.AllocHGlobal(Marshal.SizeOf(algorithm));
Marshal.StructureToPtr(algorithm, algorithmPointer, false);

I then pass the algorithmPointer into the method.

I get this error when I try to pass it into CertCreateSelfSignCertificate:

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll

Additional information: ASN1 bad arguments to function call. (Exception from HRESULT: 0x80093109)

Does anyone happen to know why this happens, or can see any problems with the way I've defined my structure or allocated it in memory?


Solution

  • As @Luaan noted, strings can be tricky to marshal correctly in p/invoke, it's often easiest to avoid p/invoke interop when you can. However I was still curious what was going wrong here.

    From the MSDN docs on PCRYPT_ALGORITHM_IDENTIFIER it looks as though you should pass in the actual OID of the algorithm "2.16.840.1.101.3.4.1.42" in this case. The szOID_NIST_AES256_CBC that is in the list there is only the C/C++ identifier (or macro) that expands to said OID string.