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?
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.
This question is old, but I thought I'd share my insight. MSDN lists CRYPT_ALGORITHM_IDENTIFIER
as:
typedef struct _CRYPT_ALGORITHM_IDENTIFIER {
LPSTR pszObjId;
CRYPT_OBJID_BLOB Parameters;
} CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER;
The important thing to note that it's an LPSTR
, not a LPWSTR
. So the string needs to be marshalled as ANSI. Unless specified explicitly, .NET will marshal the strings as unicode. So our corresponding struct needs additional decoration:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct AlgorithmIdentifier
{
public string ObjectId;
public CryptoBlob Parameters;
}
Adding CharSet
into the StructLayout
attribute will make .NET marshal the strings in the required encoding. Then it can be used in a straightforward manner:
var algId = new AlgorithmIdentifier
{
ObjectId = "1.2.840.113549.1.1.5" // szOID_RSA_SHA1RSA
};
User contributions licensed under CC BY-SA 3.0