P/Invoking CertCreateSelfSignCertificate 时出现问题

Problems when P/Invoking CertCreateSelfSignCertificate

我正在关注 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

我为它创建了这个结构:

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

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

我试图用来创建它的代码是:

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);

然后我将 algorithmPointer 传递给方法。

当我尝试将它传递给 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)

有没有人碰巧知道为什么会这样,或者能看出我定义结构或在内存中分配结构的方式有任何问题吗?

正如@Luaan 指出的那样,在 p/invoke 中正确编组字符串可能很棘手,如果可以的话,通常最容易避免 p/invoke 互操作。不过我还是很好奇这里出了什么问题。

PCRYPT_ALGORITHM_IDENTIFIER 上的 MSDN 文档看来,在这种情况下您应该传入算法 "2.16.840.1.101.3.4.1.42" 的实际 OID。列表中的 szOID_NIST_AES256_CBC 只有 C/C++ 标识符(或宏)扩展为所述 OID 字符串。

这个问题很老了,但我想我会分享我的见解。 MSDN 将 CRYPT_ALGORITHM_IDENTIFIER 列为:

typedef struct _CRYPT_ALGORITHM_IDENTIFIER {
    LPSTR            pszObjId;
    CRYPT_OBJID_BLOB Parameters;
} CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER;

需要注意的重要一点是它是 LPSTR不是 LPWSTR。所以字符串需要编组为 ANSI。除非明确指定,否则 .NET 会将字符串编组为 unicode。所以我们对应的struct需要额外的修饰:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
struct AlgorithmIdentifier
{
    public string ObjectId;
    public CryptoBlob Parameters;
}

CharSet 添加到 StructLayout 属性将使 .NET 以所需的编码编组字符串。然后就可以直接使用了:

var algId = new AlgorithmIdentifier
{
    ObjectId = "1.2.840.113549.1.1.5" // szOID_RSA_SHA1RSA
};