Example #1
0
 public static extern IntPtr CertCreateSelfSignCertificate(IntPtr hProv,
                                                           ref CERT_NAME_BLOB pSubjectIssuerBlob,
                                                           uint dwFlagsm,
                                                           ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
                                                           ref CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
                                                           ref SYSTEM_TIME pStartTime,
                                                           ref SYSTEM_TIME pEndTime,
                                                           IntPtr other);
        public static extern IntPtr CertCreateSelfSignCertificate(
																	IntPtr hProv,
																	ref CERT_NAME_BLOB pSubjectIssuerBlob,
																	uint dwFlagsm,
																	ref CRYPT_KEY_PROV_INFO pKeyProvInfo,
																	IntPtr pSignatureAlgorithm,
																	IntPtr pStartTime,
																	IntPtr pEndTime,
																	IntPtr other);
Example #3
0
        /// <summary>
        /// Decodes a CERT_NAME_BLOB.
        /// </summary>
        public static string Decode_CERT_NAME_BLOB(CERT_NAME_BLOB blob)
        {
            int    dwChars = 0;
            IntPtr pName   = IntPtr.Zero;
            IntPtr pBlob   = IntPtr.Zero;

            try
            {
                pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32.CERT_NAME_BLOB)));
                Marshal.StructureToPtr(blob, pBlob, false);

                int bResult = Win32.CertNameToStrW(
                    Win32.PKCS_7_ASN_ENCODING | Win32.X509_ASN_ENCODING,
                    pBlob,
                    Win32.CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    dwChars);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadDecodingError, "Could not get size of CERT_X500_NAME_STR.");
                }

                dwChars = bResult;
                pName   = Marshal.AllocHGlobal((dwChars + 1) * 2);

                bResult = Win32.CertNameToStrW(
                    Win32.PKCS_7_ASN_ENCODING | Win32.X509_ASN_ENCODING,
                    pBlob,
                    Win32.CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    pName,
                    dwChars);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadDecodingError, "Could not decode CERT_X500_NAME_STR.");
                }

                return(Marshal.PtrToStringUni(pName));
            }
            finally
            {
                if (pBlob != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pBlob);
                }

                if (pName != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pName);
                }
            }
        }
Example #4
0
        /// <summary>
        /// Encodes a CERT_NAME_BLOB
        /// </summary>
        public static void Encode_CERT_NAME_BLOB(string name, ref CERT_NAME_BLOB pName)
        {
            int    dwSize  = 0;
            IntPtr pBuffer = IntPtr.Zero;

            try
            {
                // reconstruct name using comma as delimeter.
                name = ChangeSubjectNameDelimiter(name, ',');

                int bResult = Win32.CertStrToNameW(
                    X509_ASN_ENCODING,
                    name,
                    CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    ref dwSize,
                    IntPtr.Zero);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadEncodingError, "Could not get size for CERT_X500_NAME_STR.");
                }

                pBuffer = Marshal.AllocHGlobal(dwSize);

                bResult = Win32.CertStrToNameW(
                    X509_ASN_ENCODING,
                    name,
                    CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    pBuffer,
                    ref dwSize,
                    IntPtr.Zero);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadEncodingError, "Could not encode CERT_X500_NAME_STR.");
                }

                pName.pbData = pBuffer;
                pName.cbData = dwSize;
                pBuffer      = IntPtr.Zero;
            }
            finally
            {
                if (pBuffer != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pBuffer);
                }
            }
        }
Example #5
0
        public static extern Int32 CertNameToStr(

            Int32 dwCertEncodingType,

            ref CERT_NAME_BLOB pName,

            Int32 dwStrType,

            StringBuilder psz,

            Int32 csz

            );
        // frees the memory used by a X500 name blob.
        private static void DeleteX500Name(ref CERT_NAME_BLOB pName)
        {
	        Marshal.FreeHGlobal(pName.pbData);
	        pName.pbData = IntPtr.Zero;
	        pName.cbData = 0;
        }
        /// <summary>
        /// Creates and returns a self-signed X509 certificate.
        /// </summary>
        /// <param name="key">The key of the certificate.</param>
        /// <param name="issuerName">The encoded common name of the issuer.</param>
        /// <param name="settings">The settings of the X509 certificate.</param>
        /// <returns>An <see cref="X509Certificate"/> instance.</returns>
        /// <exception cref="CryptographicException">An error occurs while creating the self-signed certificate.</exception>
        public static X509Certificate Create(RSACryptoServiceProvider key, string issuerName, CertificateSettings settings)
        {
            if (settings == null)
                settings = new CertificateSettings();

            CspKeyContainerInfo container = key.CspKeyContainerInfo;
            IntPtr certHandle = IntPtr.Zero;
            byte[] issuerBlob = null;
            uint pcbEncoded = 0;
            if (CertStrToName(X509_ASN_ENCODING, issuerName, CERT_X500_NAME_STR, IntPtr.Zero, null, ref pcbEncoded, IntPtr.Zero)) {
                issuerBlob = new byte[pcbEncoded];
                CertStrToName(X509_ASN_ENCODING, issuerName, CERT_X500_NAME_STR, IntPtr.Zero, issuerBlob, ref pcbEncoded, IntPtr.Zero);
            } else {
                throw new CryptographicException("Cannot encode the issuer name! Please check whether the string is in a valid format.");
            }

            List<IntPtr> extensionList = new List<IntPtr>();
            CERT_NAME_BLOB subject = new CERT_NAME_BLOB();
            try {
                subject.pbData = Marshal.AllocHGlobal(issuerBlob.Length);
                Marshal.Copy(issuerBlob, 0, subject.pbData, issuerBlob.Length);
                subject.cbData = issuerBlob.Length;

                SYSTEMTIME startDate = ConvertDateTime(settings.StartDate);
                SYSTEMTIME endDate = ConvertDateTime(settings.EndDate);

                CRYPT_KEY_PROV_INFO providerInfo = new CRYPT_KEY_PROV_INFO();
                providerInfo.pwszContainerName = container.KeyContainerName;
                providerInfo.pwszProvName = container.ProviderName;
                providerInfo.dwProvType = container.ProviderType;
                providerInfo.dwFlags = (int)0;
                providerInfo.cProvParam = 0;
                providerInfo.rgProvParam = IntPtr.Zero;
                providerInfo.dwKeySpec = (int)container.KeyNumber;

                // convert the list of extensions to an unmanaged structure
                // the .NET marshallers don't handle recursive arrays too well,
                // so we do it manually :-/
                extensionList = ConvertExtensions(settings.Extensions);

                certHandle = CertCreateSelfSignCertificate(IntPtr.Zero, ref subject, settings.Flags, ref providerInfo, IntPtr.Zero, ref startDate, ref endDate, extensionList[0]);
                if (certHandle == IntPtr.Zero) {
                    throw new CryptographicException("Couldn't create unsigned certificate");
                }

                return new X509Certificate2(certHandle);
            } finally {
                if (subject.pbData != IntPtr.Zero)
                    Marshal.FreeHGlobal(subject.pbData);
                if (extensionList != null && extensionList.Count > 0) {
                    foreach (IntPtr ptr in extensionList) {
                        if (ptr != IntPtr.Zero)
                            Marshal.FreeHGlobal(ptr);
                    }
                }
            }
        }
        /// <summary>
        /// Parses an X500 name blob.
        /// </summary>
        private static void ParseX500Name(CERT_NAME_BLOB blob, out string subjectName)
        {
            int dwChars = 0;
            IntPtr pName = IntPtr.Zero;
            IntPtr pBlob = IntPtr.Zero;
                
            try
            {
                pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CERT_NAME_BLOB)));
                Marshal.StructureToPtr(blob, pBlob, false);

                int bResult = NativeMethods.CertNameToStrW(
	                PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
	                pBlob,
	                CERT_X500_NAME_STR,
	                IntPtr.Zero,
	                dwChars);

                if (bResult == 0)
                {
	                throw new InvalidOperationException("Could not get size of X500 name.");
                }

                dwChars = bResult;
                pName = Marshal.AllocHGlobal((dwChars+1)*2);

                bResult = NativeMethods.CertNameToStrW(
	                PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
	                pBlob,
	                CERT_X500_NAME_STR,
	                pName,
	                dwChars);

                if (bResult == 0)
                {
	                throw new InvalidOperationException("Could not decode X500 name blob.");
                }

                subjectName = Marshal.PtrToStringUni(pName);
            }
            finally
            {
                if (pBlob != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pBlob);
                }

                if (pName != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pName);
                }
            }
        }
        // Encodes an X500 name in a CrytoAPI compatible blob
        private static void CreateX500Name(string name, ref CERT_NAME_BLOB pName)
        {
            int dwSize = 0;
            IntPtr pBuffer = IntPtr.Zero;

            try
            {
                // reconstruct name using comma as delimeter.
                name = ChangeSubjectNameDelimiter(name, ',');
                            
                int bResult = NativeMethods.CertStrToNameW(
	                X509_ASN_ENCODING,
	                name,
	                CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
	                IntPtr.Zero,
	                IntPtr.Zero,
	                ref dwSize,
	                IntPtr.Zero);

                if (bResult == 0)
                {
                    throw ServiceResultException.Create(
                        StatusCodes.BadEncodingError,
                        "Could not get size of X500 name blob. Name={0}",
                        name);
                }
                
                pBuffer = Marshal.AllocHGlobal(dwSize);

                bResult = NativeMethods.CertStrToNameW(
	                X509_ASN_ENCODING,
	                name,
	                CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
	                IntPtr.Zero,
	                pBuffer,
	                ref dwSize,
	                IntPtr.Zero);

                if (bResult == 0)
                {
                    throw ServiceResultException.Create(
                        StatusCodes.BadEncodingError,
                        "Could not create  X500 name blob. Name={0}",
                        name);
                }

                pName.pbData = pBuffer;
                pName.cbData = dwSize;
                pBuffer = IntPtr.Zero;
            }
            finally
            {
                if (pBuffer != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pBuffer);
                }
            }
        }
        /// <summary>
        /// Creates the certificate and adds it to the store.
        /// </summary>
        private static string CreateSelfSignedCertificate(
            IntPtr hProvider,
            IntPtr hStore,
            bool useMachineStore,
            string applicationName,
            string applicationUri,
            string subjectName,
            IList<string> hostNames,
            ushort keySize,
            ushort lifetimeInMonths,
            ushort algorithm = 0)
        {
            IntPtr hKey = IntPtr.Zero;
            IntPtr pKpi = IntPtr.Zero;
            IntPtr pThumbprint = IntPtr.Zero;
            IntPtr pContext = IntPtr.Zero;
            IntPtr pAlgorithmId = IntPtr.Zero;
            IntPtr pNewContext = IntPtr.Zero;
            CRYPT_DATA_BLOB publicKeyId = new CRYPT_DATA_BLOB();
            CERT_NAME_BLOB subjectNameBlob = new CERT_NAME_BLOB();
            SYSTEMTIME stValidTo = new SYSTEMTIME();
            CERT_EXTENSIONS extensions = new CERT_EXTENSIONS();
            CRYPT_DATA_BLOB friendlyName = new CRYPT_DATA_BLOB();

            GCHandle hValidTo = new GCHandle();
            GCHandle hExtensionList = new GCHandle();
            GCHandle hSubjectNameBlob = new GCHandle();
            GCHandle hFriendlyName = new GCHandle();

            try
            {
                // create a new key pair.
                int bResult = NativeMethods.CryptGenKey(
                    hProvider,
                    AT_KEYEXCHANGE,
                    CRYPT_EXPORTABLE | (keySize << 16),
                    ref hKey);

                if (bResult == 0)
                {
                    Throw("Could not generate a new key pair. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                // gey the public key identifier.
                GetPublicKeyIdentifier(hProvider, ref publicKeyId);

                // construct the certificate subject name.
                CreateX500Name(subjectName, ref subjectNameBlob);
                GCHandle hSubjectName = GCHandle.Alloc(subjectNameBlob, GCHandleType.Pinned);

                // allocate memory for all possible extensions.
                extensions.cExtension = 0;
                extensions.rgExtension = Marshal.AllocHGlobal(6 * Marshal.SizeOf(typeof(CERT_EXTENSION)));

                // create the subject key info extension.
                IntPtr pPos = extensions.rgExtension;
                CERT_EXTENSION extension = new CERT_EXTENSION();
                CreateSubjectKeyIdentifierExtension(ref extension, ref publicKeyId);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the authority key info extension.
                extension = new CERT_EXTENSION();
                CreateAuthorityKeyIdentifierExtension(ref extension, ref publicKeyId);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the basic constraints extension.
                extension = new CERT_EXTENSION();
                CreateBasicConstraintsExtension(ref extension, false);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the key usage extension.
                extension = new CERT_EXTENSION();
                CreateKeyUsageExtension(ref extension, false);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the extended key usage extension.
                extension = new CERT_EXTENSION();
                CreateExtendedKeyUsageExtension(ref extension);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // create the subject alternate name extension.
                extension = new CERT_EXTENSION();
                CreateSubjectAltNameExtension(applicationUri, hostNames, ref extension);
                Marshal.StructureToPtr(extension, pPos, false);
                pPos = new IntPtr(pPos.ToInt64() + Marshal.SizeOf(typeof(CERT_EXTENSION)));
                extensions.cExtension++;

                // set the expiration date.
                DateTime validTo = DateTime.UtcNow.AddMonths(lifetimeInMonths);
                System.Runtime.InteropServices.ComTypes.FILETIME ftValidTo = new System.Runtime.InteropServices.ComTypes.FILETIME();
                ulong ticks = (ulong)(validTo.Ticks - new DateTime(1601, 1, 1).Ticks);
                ftValidTo.dwHighDateTime = (int)((0xFFFFFFFF00000000 & (ulong)ticks) >> 32);
                ftValidTo.dwLowDateTime = (int)((ulong)ticks & 0x00000000FFFFFFFF);

                NativeMethods.FileTimeToSystemTime(ref ftValidTo, ref stValidTo);

                // specify what key is being used to sign the certificate.
                CRYPT_KEY_PROV_INFO kpi = new CRYPT_KEY_PROV_INFO();

                kpi.pwszContainerName = KEY_CONTAINER_NAME; // must be the same as the hProvider
                kpi.pwszProvName = DEFAULT_CRYPTO_PROVIDER;
                kpi.dwProvType = PROV_RSA_FULL;
                kpi.dwFlags = CERT_SET_KEY_CONTEXT_PROP_ID;
                kpi.dwKeySpec = AT_KEYEXCHANGE;

                if (useMachineStore)
                {
                    kpi.dwFlags |= CRYPT_MACHINE_KEYSET;
                }
                else
                {
                    kpi.dwFlags |= CRYPT_USER_KEYSET;
                }

                pKpi = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPT_KEY_PROV_INFO)));
                Marshal.StructureToPtr(kpi, pKpi, false);

                hValidTo = GCHandle.Alloc(stValidTo, GCHandleType.Pinned);
                hExtensionList = GCHandle.Alloc(extensions, GCHandleType.Pinned);
                hSubjectNameBlob = GCHandle.Alloc(subjectNameBlob, GCHandleType.Pinned);

                if (algorithm == 1)
                {
                    CRYPT_ALGORITHM_IDENTIFIER algorithmID = new CRYPT_ALGORITHM_IDENTIFIER();
                    algorithmID.pszObjId = "1.2.840.113549.1.1.11"; //SHA256

                    pAlgorithmId = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CRYPT_ALGORITHM_IDENTIFIER)));
                    Marshal.StructureToPtr(algorithmID, pAlgorithmId, false);

                    //create the certificate
                    pContext = NativeMethods.CertCreateSelfSignCertificate(
                         hProvider,
                         hSubjectNameBlob.AddrOfPinnedObject(),
                         0,
                         pKpi,
                         pAlgorithmId,
                         IntPtr.Zero,
                         hValidTo.AddrOfPinnedObject(),
                         hExtensionList.AddrOfPinnedObject());
                }
                else
                {
                    // (default) create the certificate.
                    pContext = NativeMethods.CertCreateSelfSignCertificate(
                    hProvider,
                    hSubjectNameBlob.AddrOfPinnedObject(),
                    0,
                    pKpi,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    hValidTo.AddrOfPinnedObject(),
                    hExtensionList.AddrOfPinnedObject());
                }

                if (pContext == IntPtr.Zero)
                {
                    Throw("Could not create self-signed certificate. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                // get the thumbprint.
                int dwThumbprintSize = 20;
                pThumbprint = Marshal.AllocHGlobal(dwThumbprintSize);

                bResult = NativeMethods.CertGetCertificateContextProperty(
                    pContext,
                    CERT_SHA1_HASH_PROP_ID,
                    pThumbprint,
                    ref dwThumbprintSize);

                if (bResult == 0)
                {
                    Throw("Could not get the thumbprint of the new certificate. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                byte[] bytes = new byte[dwThumbprintSize];
                Marshal.Copy(pThumbprint, bytes, 0, dwThumbprintSize);
                string thumbprint = Utils.ToHexString(bytes);

                // set the friendly name.
                friendlyName.pbData = Marshal.StringToHGlobalUni(applicationName);
                friendlyName.cbData = (applicationName.Length+1)*Marshal.SizeOf(typeof(ushort));
                hFriendlyName = GCHandle.Alloc(friendlyName, GCHandleType.Pinned);

                bResult = NativeMethods.CertSetCertificateContextProperty(
                    pContext,
                    CERT_FRIENDLY_NAME_PROP_ID,
                    0,
                    hFriendlyName.AddrOfPinnedObject());

                if (bResult == 0)
                {
                    Throw("Could not set the friendly name for the certificate. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                // add into store.
                bResult = NativeMethods.CertAddCertificateContextToStore(
                    hStore,
                    pContext,
                    CERT_STORE_ADD_REPLACE_EXISTING,
                    ref pNewContext);

                if (bResult == 0)
                {
                    Throw("Could not add the certificate to the store. Error={0:X8}", Marshal.GetLastWin32Error());
                }

                return thumbprint;
            }
            finally
            {
                if (pContext != IntPtr.Zero)
                {
                    NativeMethods.CertFreeCertificateContext(pContext);
                }

                if (pNewContext != IntPtr.Zero)
                {
                    NativeMethods.CertFreeCertificateContext(pNewContext);
                }

                if (friendlyName.pbData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(friendlyName.pbData);
                }

                if (pThumbprint != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pThumbprint);
                }

                if (pAlgorithmId != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pAlgorithmId, typeof(CRYPT_ALGORITHM_IDENTIFIER));
                    Marshal.FreeHGlobal(pAlgorithmId);
                }

                if (hValidTo.IsAllocated) hValidTo.Free();
                if (hExtensionList.IsAllocated) hExtensionList.Free();
                if (hSubjectNameBlob.IsAllocated) hSubjectNameBlob.Free();
                if (hFriendlyName.IsAllocated) hFriendlyName.Free();

                if (pKpi != IntPtr.Zero)
                {
                    Marshal.DestroyStructure(pKpi, typeof(CRYPT_KEY_PROV_INFO));
                    Marshal.FreeHGlobal(pKpi);
                }

                DeleteExtensions(ref extensions.rgExtension, extensions.cExtension);
                DeleteX500Name(ref subjectNameBlob);

                if (publicKeyId.pbData != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(publicKeyId.pbData);
                }

                if (hKey != IntPtr.Zero)
                {
                    NativeMethods.CryptDestroyKey(hKey);
                }
            }
        }
Example #11
0
        /// <summary>
        /// Encodes a CERT_NAME_BLOB
        /// </summary>
        public static void Encode_CERT_NAME_BLOB(string name, ref CERT_NAME_BLOB pName)
        {
            int dwSize = 0;
            IntPtr pBuffer = IntPtr.Zero;

            try
            {
                // reconstruct name using comma as delimeter.
                name = ChangeSubjectNameDelimiter(name, ',');

                int bResult = Win32.CertStrToNameW(
                    X509_ASN_ENCODING,
                    name,
                    CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    IntPtr.Zero,
                    ref dwSize,
                    IntPtr.Zero);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadEncodingError, "Could not get size for CERT_X500_NAME_STR.");
                }

                pBuffer = Marshal.AllocHGlobal(dwSize);

                bResult = Win32.CertStrToNameW(
                    X509_ASN_ENCODING,
                    name,
                    CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    pBuffer,
                    ref dwSize,
                    IntPtr.Zero);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadEncodingError, "Could not encode CERT_X500_NAME_STR.");
                }

                pName.pbData = pBuffer;
                pName.cbData = dwSize;
                pBuffer = IntPtr.Zero;
            }
            finally
            {
                if (pBuffer != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pBuffer);
                }
            }
        }
Example #12
0
        /// <summary>
        /// Decodes a CERT_NAME_BLOB.
        /// </summary>
        public static string Decode_CERT_NAME_BLOB(CERT_NAME_BLOB blob)
        {
            int dwChars = 0;
            IntPtr pName = IntPtr.Zero;
            IntPtr pBlob = IntPtr.Zero;

            try
            {
                pBlob = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Win32.CERT_NAME_BLOB)));
                Marshal.StructureToPtr(blob, pBlob, false);

                int bResult = Win32.CertNameToStrW(
                    Win32.PKCS_7_ASN_ENCODING | Win32.X509_ASN_ENCODING,
                    pBlob,
                    Win32.CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    IntPtr.Zero,
                    dwChars);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadDecodingError, "Could not get size of CERT_X500_NAME_STR.");
                }

                dwChars = bResult;
                pName = Marshal.AllocHGlobal((dwChars + 1) * 2);

                bResult = Win32.CertNameToStrW(
                    Win32.PKCS_7_ASN_ENCODING | Win32.X509_ASN_ENCODING,
                    pBlob,
                    Win32.CERT_X500_NAME_STR | CERT_NAME_STR_REVERSE_FLAG,
                    pName,
                    dwChars);

                if (bResult == 0)
                {
                    throw GetLastError(StatusCodes.BadDecodingError, "Could not decode CERT_X500_NAME_STR.");
                }

                return Marshal.PtrToStringUni(pName);
            }
            finally
            {
                if (pBlob != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pBlob);
                }

                if (pName != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(pName);
                }
            }
        }
		private static IntPtr CreateUnsignedCertCntxt(String keycontainer, String provider, uint KEYSPEC, uint cspflags, String DN) {
			const uint AT_KEYEXCHANGE = 0x00000001;
			const uint AT_SIGNATURE = 0x00000002;
			const uint CRYPT_MACHINE_KEYSET = 0x00000020;
			const uint PROV_RSA_FULL = 0x00000001;
			const String MS_DEF_PROV = "Microsoft Base Cryptographic Provider v1.0";
			const String MS_STRONG_PROV = "Microsoft Strong Cryptographic Provider";
			const String MS_ENHANCED_PROV = "Microsoft Enhanced Cryptographic Provider v1.0";
			const uint CERT_CREATE_SELFSIGN_NO_SIGN = 1;
			const uint X509_ASN_ENCODING = 0x00000001;
			const uint CERT_X500_NAME_STR = 3;
			IntPtr hCertCntxt = IntPtr.Zero;
			byte[] encodedName = null;
			uint cbName = 0;

			if (provider != MS_DEF_PROV && provider != MS_STRONG_PROV && provider != MS_ENHANCED_PROV)
				return IntPtr.Zero;
			if (keycontainer == "")
				return IntPtr.Zero;
			if (KEYSPEC != AT_SIGNATURE && KEYSPEC != AT_KEYEXCHANGE)
				return IntPtr.Zero;
			if (cspflags != 0 && cspflags != CRYPT_MACHINE_KEYSET)   //only 0 (Current User) keyset is currently used.
				return IntPtr.Zero;
			if (DN == "")
				return IntPtr.Zero;


			if (Win32.CertStrToName(X509_ASN_ENCODING, DN, CERT_X500_NAME_STR, IntPtr.Zero, null, ref cbName, IntPtr.Zero)) {
				encodedName = new byte[cbName];
				Win32.CertStrToName(X509_ASN_ENCODING, DN, CERT_X500_NAME_STR, IntPtr.Zero, encodedName, ref cbName, IntPtr.Zero);
			}

			CERT_NAME_BLOB subjectblob = new CERT_NAME_BLOB();
			subjectblob.pbData = Marshal.AllocHGlobal(encodedName.Length);
			Marshal.Copy(encodedName, 0, subjectblob.pbData, encodedName.Length);
			subjectblob.cbData = encodedName.Length;

			CRYPT_KEY_PROV_INFO pInfo = new CRYPT_KEY_PROV_INFO();
			pInfo.pwszContainerName = keycontainer;
			pInfo.pwszProvName = provider;
			pInfo.dwProvType = PROV_RSA_FULL;
			pInfo.dwFlags = cspflags;
			pInfo.cProvParam = 0;
			pInfo.rgProvParam = IntPtr.Zero;
			pInfo.dwKeySpec = KEYSPEC;

			hCertCntxt = Win32.CertCreateSelfSignCertificate(IntPtr.Zero, ref subjectblob, CERT_CREATE_SELFSIGN_NO_SIGN, ref pInfo, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
			if (hCertCntxt == IntPtr.Zero)
				showWin32Error(Marshal.GetLastWin32Error());
			Marshal.FreeHGlobal(subjectblob.pbData);
			return hCertCntxt;
		}