Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用私钥生成自签名X509Certificate2证书_C#_.net_Winapi_Pki_X509certificate2 - Fatal编程技术网

C# 使用私钥生成自签名X509Certificate2证书

C# 使用私钥生成自签名X509Certificate2证书,c#,.net,winapi,pki,x509certificate2,C#,.net,Winapi,Pki,X509certificate2,我不是最熟悉的,但我正在尝试生成一个自签名的X509Certificate2证书 以下是完整的代码: using System; using System.Security; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; using System.Security.Cryptography.X509Certificates; namespace Example { [Struc

我不是最熟悉的,但我正在尝试生成一个自签名的X509Certificate2证书

以下是完整的代码:

using System;
using System.Security;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Security.Cryptography.X509Certificates;

namespace Example
{

    [StructLayout(LayoutKind.Sequential)]
    public struct SystemTime
    {
        public short Year;
        public short Month;
        public short DayOfWeek;
        public short Day;
        public short Hour;
        public short Minute;
        public short Second;
        public short Milliseconds;
    }

    public static class MarshalHelper
    {
        public static void ErrorCheck(bool nativeCallSucceeded)
        {
            if (!nativeCallSucceeded)
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
        }
    }

    public static class DateTimeExtensions
    {

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern bool FileTimeToSystemTime(ref long fileTime, out SystemTime systemTime);

        public static SystemTime ToSystemTime(this DateTime dateTime)
        {
            long fileTime = dateTime.ToFileTime();
            SystemTime systemTime;
            MarshalHelper.ErrorCheck(FileTimeToSystemTime(ref fileTime, out systemTime));
            return systemTime;
        }
    }

    class X509Certificate2Helper
    {

        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        static extern bool CryptAcquireContextW(out IntPtr providerContext, string container, string provider, int providerType, int flags);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool CryptReleaseContext(IntPtr providerContext, int flags);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool CryptGenKey(IntPtr providerContext, int algorithmId, int flags, out IntPtr cryptKeyHandle);

        [DllImport("advapi32.dll", SetLastError = true)]
        static extern bool CryptDestroyKey(IntPtr cryptKeyHandle);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern bool CertStrToNameW(int certificateEncodingType, IntPtr x500, int strType, IntPtr reserved, byte[] encoded, ref int encodedLength, out IntPtr errorString);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern IntPtr CertCreateSelfSignCertificate(IntPtr providerHandle, ref CryptoApiBlob subjectIssuerBlob, int flags, ref CryptKeyProviderInformation keyProviderInformation, IntPtr signatureAlgorithm, ref SystemTime startTime, ref SystemTime endTime, IntPtr extensions);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern bool CertFreeCertificateContext(IntPtr certificateContext);

        [DllImport("crypt32.dll", SetLastError = true)]
        static extern bool CertSetCertificateContextProperty(IntPtr certificateContext, int propertyId, int flags, ref CryptKeyProviderInformation data);

        public static X509Certificate2 GenerateSelfSignedCertificate(String name = "CN = Example", DateTime? startTime = null, DateTime? endTime = null)
        {
            if (name == null)
                name = String.Empty;
            var startSystemTime = default(SystemTime);
            if (startTime == null || (DateTime)startTime < DateTime.FromFileTimeUtc(0))
                startTime = DateTime.FromFileTimeUtc(0);
            var startSystemTime = ((DateTime)startTime).ToSystemTime();
            if (endTime == null)
                endTime = DateTime.MaxValue;
            var endSystemTime = ((DateTime)endTime).ToSystemTime();
            string containerName = Guid.NewGuid().ToString();
            GCHandle dataHandle = new GCHandle();
            IntPtr providerContext = IntPtr.Zero;
            IntPtr cryptKey = IntPtr.Zero;
            IntPtr certificateContext = IntPtr.Zero;
            IntPtr algorithmPointer = IntPtr.Zero;
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                MarshalHelper.ErrorCheck(CryptAcquireContextW(out providerContext, containerName, null, 1, 0x8));
                MarshalHelper.ErrorCheck(CryptGenKey(providerContext, 1, 0x8000001, out cryptKey));
                IntPtr errorStringPtr;
                int nameDataLength = 0;
                byte[] nameData;
                dataHandle = GCHandle.Alloc(name, GCHandleType.Pinned);
                if (!CertStrToNameW(0x00010001, dataHandle.AddrOfPinnedObject(), 3, IntPtr.Zero, null, ref nameDataLength, out errorStringPtr))
                {
                    string error = Marshal.PtrToStringUni(errorStringPtr);
                    throw new ArgumentException(error);
                }
                nameData = new byte[nameDataLength];
                if (!CertStrToNameW(0x00010001, dataHandle.AddrOfPinnedObject(), 3, IntPtr.Zero, nameData, ref nameDataLength, out errorStringPtr))
                {
                    string error = Marshal.PtrToStringUni(errorStringPtr);
                    throw new ArgumentException(error);
                }
                dataHandle.Free();
                dataHandle = GCHandle.Alloc(nameData, GCHandleType.Pinned);
                CryptoApiBlob nameBlob = new CryptoApiBlob { cbData = nameData.Length, pbData = dataHandle.AddrOfPinnedObject() };
                dataHandle.Free();
                CryptKeyProviderInformation keyProvider = new CryptKeyProviderInformation { pwszContainerName = containerName, dwProvType = 1, dwKeySpec = 1 };
                CryptAlgorithmIdentifier algorithm = new CryptAlgorithmIdentifier { pszObjId = "1.2.840.113549.1.1.13", Parameters = new CryptoApiBlob() };
                algorithmPointer = Marshal.AllocHGlobal(Marshal.SizeOf(algorithm));
                Marshal.StructureToPtr(algorithm, algorithmPointer, false);
                certificateContext = CertCreateSelfSignCertificate(providerContext, ref nameBlob, 0, ref keyProvider, algorithmPointer, ref startSystemTime, ref endSystemTime, IntPtr.Zero);
                MarshalHelper.ErrorCheck(certificateContext != IntPtr.Zero);
                return new X509Certificate2(certificateContext);
            }
            finally
            {
                if (dataHandle.IsAllocated)
                    dataHandle.Free();
                if (certificateContext != IntPtr.Zero)
                    CertFreeCertificateContext(certificateContext);
                if (cryptKey != IntPtr.Zero)
                    CryptDestroyKey(cryptKey);
                if (providerContext != IntPtr.Zero)
                    CryptReleaseContext(providerContext, 0);
                if (algorithmPointer != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(algorithmPointer, typeof(CryptAlgorithmIdentifier));
                    Marshal.FreeHGlobal(algorithmPointer);
                }
            }
        }

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

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

        struct CryptKeyProviderInformation
        {
            public String pwszContainerName;
            public String pwszProvName;
            public Int32 dwProvType;
            public Int32 dwFlags;
            public Int32 cProvParam;
            public IntPtr rgProvParam;
            public Int32 dwKeySpec;
        }
    }
}

但是,您可以看到,试图通过
证书获取私钥。PrivateKey
抛出的
密钥集不存在。我曾试图查阅文档,但我不明白为什么证书上下文作为X509Certificate2加载时没有设置其私钥。有人有什么想法吗?实现中是否存在导致未设置密钥的问题?我的意思是,我在这里有点困惑,因为我希望自签名证书总是携带它的私钥,因为它自己使用私钥签名,或者不是这样?

问题在于
CryptKeyProviderInformation
结构签名。它缺少
字符集
(具有Auto或Unicode)属性,因为容器和提供程序名称应为Unicode(编组后)。更新结构定义,如下所示:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct CryptKeyProviderInformation
{
    public String pwszContainerName;
    public String pwszProvName;
    public Int32 dwProvType;
    public Int32 dwFlags;
    public Int32 cProvParam;
    public IntPtr rgProvParam;
    public Int32 dwKeySpec;
}

然后钥匙应该是accessbile。

谢谢,我真不敢相信我错过了。这对我来说是非常棘手的。出于好奇,如果将来会发生这种情况,您是否知道找到此类封送问题的最佳方法是什么?如果没有本地源,这是不可能的。但是,参数名称和/或文档中可能有指示。由于CryptoAPI在其名称中使用匈牙利符号,因此它确实提供了一些线索。例如,LPSTR类型是ANSI字符串,而LPWSTR(注意“W”字符)表示Unicode。参数名称包含以下信息:“psz”或“pwsz”。第一个是ANSI,第二个是Unicode。并且文档(在本例中)说它需要Unicode字符串。hths有时,结构可能具有冲突字符串类型。一个字段是ANSI,另一个是Unicode。可以通过对字段进行统一的属性设置来解决此问题:
[Marshallas(UnmanagedType.LPStr)]
用于ANSI和
[Marshallas(UnmanagedType.LPWStr)]
对于Unicode字符串,我想问的是,除了检查是否存在返回值外,是否还有其他方法可以检测封送是否无法将值封送回来?事实上,这并没有失败,问题是关于输入数据和封送规则。如果函数没有严格检查输入数据,那么就没有通用的方法来确定issue来源。
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
struct CryptKeyProviderInformation
{
    public String pwszContainerName;
    public String pwszProvName;
    public Int32 dwProvType;
    public Int32 dwFlags;
    public Int32 cProvParam;
    public IntPtr rgProvParam;
    public Int32 dwKeySpec;
}