CertCreateSelfSignCertificate返回null,错误代码为87

时间:2019-05-03 05:08:22

标签: c# cryptography pinvoke

我在C#中使用crypt api创建SSL证书时遇到问题,CertCreateSelfSignCertificate返回null,错误代码为87(参数不正确)。 不知道错过了什么。

Win32Native.CRYPTOAPI_BLOB SubjectIssuerBlob = new Win32Native.CRYPTOAPI_BLOB();
                GCHandle asnNameHandle = GCHandle.Alloc(pbEncoded, GCHandleType.Pinned);
                // SubjectIssuerBlob.pbData = Marshal.AllocHGlobal(pbEncoded.Length);
                //Marshal.Copy(pbEncoded, 0, SubjectIssuerBlob.pbData, pbEncoded.Length);
                SubjectIssuerBlob.pbData = asnNameHandle.AddrOfPinnedObject();
                SubjectIssuerBlob.cbData = cbEncoded;

Win32Native.CRYPT_KEY_PROV_INFO providerInfo = new Win32Native.CRYPT_KEY_PROV_INFO();
                providerInfo.pwszContainerName = hostname;
                providerInfo.pwszProvName = null;
                providerInfo.dwProvType = PROV_RSA_FULL;
                providerInfo.dwFlags = CRYPT_MACHINE_KEYSET;
                providerInfo.cProvParam = 0;
                providerInfo.rgProvParam = IntPtr.Zero;
                providerInfo.dwKeySpec = AT_SIGNATURE;

                Win32Native.CRYPT_ALGORITHM_IDENTIFIER algorithmID = new Win32Native.CRYPT_ALGORITHM_IDENTIFIER();
                algorithmID.pszObjId = "1.2.840.113549.1.1.5"; //szOID_RSA_SHA1RSA

pContext = Win32Native.CertCreateSelfSignCertificate(IntPtr.Zero, ref SubjectIssuerBlob, 0, ref providerInfo, ref algorithmID, null, endtime, IntPtr.Zero);

win32api呼叫

[DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
        internal static extern IntPtr CertCreateSelfSignCertificate(
           IntPtr providerHandle,
           ref CRYPTOAPI_BLOB subjectIssuerBlob,
           uint flags,
           ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
           ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
           SystemTime startTime,
           SystemTime endTime,
           IntPtr extensions);

1 个答案:

答案 0 :(得分:0)

在Windows 10 VS 2015上使用 CertCreateSelfSignCertificate 进行的测试=>

对话框(法语):

enter image description here

        //Guid guidContainerName = Guid.NewGuid();
        Guid guidContainerName = Guid.Empty;
        int nRet = UuidCreate(out guidContainerName);
        if (nRet == 0)
        {
            IntPtr pContainerName = new IntPtr();
            nRet = UuidToString(ref guidContainerName, ref pContainerName);
            string sContainerName;
            sContainerName = Marshal.PtrToStringUni(pContainerName);

            string sProviderName = MS_DEF_PROV;
            IntPtr hProv = IntPtr.Zero;
            bool bRet = CryptAcquireContext(ref hProv, sContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET);

            IntPtr hKey = IntPtr.Zero;
            bRet = CryptGenKey(hProv, AT_KEYEXCHANGE, RSA1024BIT_KEY | CRYPT_EXPORTABLE, ref hKey);               
            string sSubject = "CN=TEST,OU=TESTOU";               
            byte[] encodedSubjectName = null;
            uint nNameLenght = 0;
            if (CertStrToName(X509_ASN_ENCODING, sSubject, CERT_X500_NAME_STR, IntPtr.Zero, null, ref nNameLenght, IntPtr.Zero))
            {
                encodedSubjectName = new byte[nNameLenght];
                CertStrToName(X509_ASN_ENCODING, sSubject, CERT_X500_NAME_STR, IntPtr.Zero, encodedSubjectName, ref nNameLenght, IntPtr.Zero);
            }              
            CERT_NAME_BLOB subjectblob = new CERT_NAME_BLOB();
            subjectblob.pbData = Marshal.AllocHGlobal(encodedSubjectName.Length);
            Marshal.Copy(encodedSubjectName, 0, subjectblob.pbData, encodedSubjectName.Length);
            subjectblob.cbData = encodedSubjectName.Length;

            CRYPT_KEY_PROV_INFO pKeyProvInfo = new CRYPT_KEY_PROV_INFO();
            pKeyProvInfo.pwszContainerName = sContainerName;
            pKeyProvInfo.pwszProvName = sProviderName;
            pKeyProvInfo.dwProvType = PROV_RSA_FULL;
            pKeyProvInfo.rgProvParam = IntPtr.Zero;
            pKeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;

            IntPtr pcCertContext = CertCreateSelfSignCertificate(hProv, ref subjectblob, 0, ref pKeyProvInfo, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
            if (pcCertContext != IntPtr.Zero)
            {
                X509Certificate cert = new X509Certificate(pcCertContext);
                // Add reference to System.Security
                X509Certificate2UI.DisplayCertificate(new X509Certificate2(cert));
                CertFreeCertificateContext(pcCertContext);
            }
            else
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }                            

            Marshal.FreeHGlobal(subjectblob.pbData);               
            CryptDestroyKey(hKey);
            CryptReleaseContext(hProv, 0);
            RpcStringFree(ref pContainerName);
        }

带有声明=>

    [DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern IntPtr CertCreateSelfSignCertificate(IntPtr hCryptProvOrNCryptKey, ref CERT_NAME_BLOB pSubjectIssuerBlob, int dwFlags, ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
        IntPtr pSignatureAlgorithm, IntPtr pStartTime, IntPtr pEndTime, IntPtr pExtensions);

    [DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool CertFreeCertificateContext(IntPtr pCertContext);

    [StructLayout(LayoutKind.Sequential)]
    public struct CERT_NAME_BLOB
    {
        public int cbData;
        public IntPtr pbData;
    }

    [DllImport("Rpcrt4.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern int UuidCreate(out Guid Uuid);

    [DllImport("rpcrt4.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern int UuidToString(ref Guid uuid, ref IntPtr str);

    [DllImport("rpcrt4.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern int RpcStringFree(ref IntPtr str);

    [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool CryptAcquireContext(ref IntPtr phProv, string szContainer, string szProvider, int dwProvType, uint dwFlags);

    [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool CryptReleaseContext(IntPtr hProv, uint dwFlags);

    [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool CryptGenKey(IntPtr hProv, uint Algid, int dwFlags, ref IntPtr phKey);

    [DllImport("Advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool CryptDestroyKey(IntPtr hKey);

    public const int RSA1024BIT_KEY = 0x04000000;
    public const int CRYPT_EXPORTABLE = 0x00000001;

    [DllImport("Crypt32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool CertStrToName(uint dwCertEncodingType, string pszX500, uint dwStrType, IntPtr pvReserved,
        [In, Out] byte[] pbEncoded, ref uint pcbEncoded, IntPtr ppszError);

    public const int CRYPT_ASN_ENCODING = 0x00000001;
    public const int CRYPT_NDR_ENCODING = 0x00000002;
    public const int X509_ASN_ENCODING = 0x00000001;
    public const int X509_NDR_ENCODING = 0x00000002;
    public const int PKCS_7_ASN_ENCODING = 0x00010000;
    public const int PKCS_7_NDR_ENCODING = 0x00020000;

    public const string MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";
    public const int PROV_RSA_FULL = 1;

    public const uint CRYPT_VERIFYCONTEXT = 0xF0000000;
    public const uint CRYPT_NEWKEYSET = 0x00000008;
    public const uint CRYPT_DELETEKEYSET = 0x00000010;
    public const uint CRYPT_MACHINE_KEYSET = 0x00000020;
    public const uint CRYPT_SILENT = 0x00000040;

    public const int CERT_SIMPLE_NAME_STR = 1;
    public const int CERT_OID_NAME_STR = 2;
    public const int CERT_X500_NAME_STR = 3;
    public const int CERT_XML_NAME_STR = 4;

    public const int CERT_NAME_STR_SEMICOLON_FLAG = 0x40000000;
    public const int CERT_NAME_STR_NO_PLUS_FLAG = 0x20000000;
    public const int CERT_NAME_STR_NO_QUOTING_FLAG = 0x10000000;
    public const int CERT_NAME_STR_CRLF_FLAG = 0x08000000;
    public const int CERT_NAME_STR_COMMA_FLAG = 0x04000000;
    public const int CERT_NAME_STR_REVERSE_FLAG = 0x02000000;
    public const int CERT_NAME_STR_FORWARD_FLAG = 0x01000000;

    public const int CERT_NAME_STR_DISABLE_IE4_UTF8_FLAG = 0x00010000;
    public const int CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG = 0x00020000;
    public const int CERT_NAME_STR_ENABLE_UTF8_UNICODE_FLAG = 0x00040000;
    public const int CERT_NAME_STR_FORCE_UTF8_DIR_STR_FLAG = 0x00080000;
    public const int CERT_NAME_STR_DISABLE_UTF8_DIR_STR_FLAG = 0x00100000;
    public const int CERT_NAME_STR_ENABLE_PUNYCODE_FLAG = 0x00200000;

    [StructLayout(LayoutKind.Sequential)]
    public struct CRYPT_KEY_PROV_INFO
    {
        [MarshalAs(UnmanagedType.LPWStr)] public string pwszContainerName;
        [MarshalAs(UnmanagedType.LPWStr)] public string pwszProvName;
        public int dwProvType;
        public int dwFlags;
        public int cProvParam;
        public IntPtr rgProvParam;
        public int dwKeySpec;
    }

    public const int AT_KEYEXCHANGE = 1;
    public const int AT_SIGNATURE = 2;