예제 #1
0
        /// <summary>
        /// Accepts a CSR-like object to sign by another key
        /// </summary>
        /// <param name="request">The request to sign</param>
        /// <param name="CACert">The signing key</param>
        /// <returns>Returns a signed certificate</returns>
        public static X509Certificate2 SignCertificate(CertificateSigningRequest request, X509Certificate2 CACert)
        {
            IntPtr hCAProv = IntPtr.Zero;

            IntPtr hProvAllocPtr = IntPtr.Zero;
            IntPtr subordinateCertInfoAllocPtr = IntPtr.Zero;

            RuntimeHelpers.PrepareConstrainedRegions();

            try
            {
                // Get CA cert into CERT_CONTEXT
                // Get CA cert into CERT_INFO from context.pCertInfo

                NativeMethods.CERT_CONTEXT CAContext  = (NativeMethods.CERT_CONTEXT)Marshal.PtrToStructure(CACert.Handle, typeof(NativeMethods.CERT_CONTEXT));
                NativeMethods.CERT_INFO    CACertInfo = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(CAContext.pCertInfo, typeof(NativeMethods.CERT_INFO));

                uint pcbData = 0;

                // get the context property handle of the CA Cert

                if (!NativeMethods.CertGetCertificateContextProperty(CACert.Handle, 2, hProvAllocPtr, ref pcbData))
                {
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                }

                hProvAllocPtr = NativeMethods.LocalAlloc(0, new IntPtr((long)pcbData));

                if (!NativeMethods.CertGetCertificateContextProperty(CACert.Handle, 2, hProvAllocPtr, ref pcbData))
                {
                    throw new CryptographicException(Marshal.GetLastWin32Error());
                }

                // get the key handle of the CA Cert

                NativeMethods.CRYPT_KEY_PROV_INFO pKeyInfo = (NativeMethods.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(hProvAllocPtr, typeof(NativeMethods.CRYPT_KEY_PROV_INFO));

                // Acquire a context to the provider for crypto

                if (!NativeMethods.CryptAcquireContext(ref hCAProv, pKeyInfo.pwszContainerName, pKeyInfo.pwszProvName, pKeyInfo.dwProvType, pKeyInfo.dwFlags))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                // Get subordinate cert into CERT_CONTEXT
                // Get subordinate cert into CERT_INFO from context.pCertInfo

                NativeMethods.CERT_CONTEXT subordinateCertContext = (NativeMethods.CERT_CONTEXT)Marshal.PtrToStructure(request.Certificate.Handle, typeof(NativeMethods.CERT_CONTEXT));
                NativeMethods.CERT_INFO    subordinateCertInfo    = (NativeMethods.CERT_INFO)Marshal.PtrToStructure(subordinateCertContext.pCertInfo, typeof(NativeMethods.CERT_INFO));

                NativeMethods.CRYPT_ALGORITHM_IDENTIFIER signatureAlgo = new NativeMethods.CRYPT_ALGORITHM_IDENTIFIER()
                {
                    pszObjId = string.IsNullOrWhiteSpace(request.SignatureAlgorithm) ? NativeMethods.OID_RSA_SHA256RSA : request.SignatureAlgorithm
                };

                // apply new issuer

                subordinateCertInfo.NotBefore = CertUtil.FileTimeFromDateTime(DateTime.UtcNow.AddHours(-1));
                subordinateCertInfo.NotAfter  = CertUtil.FileTimeFromDateTime(DateTime.UtcNow.Add(request.ExpirationLength));

                var caExtensions = CertUtil.ConvertExtensions(request.Extensions)[0];

                subordinateCertInfo.cExtension  = request.Extensions == null ? 0 : (uint)request.Extensions.Count;
                subordinateCertInfo.rgExtension = caExtensions;

                subordinateCertInfo.SignatureAlgorithm = signatureAlgo;
                subordinateCertInfo.Issuer             = CACertInfo.Subject;

                subordinateCertInfoAllocPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(NativeMethods.CERT_INFO)));
                Marshal.StructureToPtr(subordinateCertInfo, subordinateCertInfoAllocPtr, false);

                byte[] pbEncodedCert       = null;
                uint   pbEncodedCertLength = 0;

                if (!NativeMethods.CryptSignAndEncodeCertificate(hCAProv,
                                                                 (uint)request.KeySpecification,
                                                                 NativeMethods.X509_ASN_ENCODING,
                                                                 NativeMethods.X509_CERT_TO_BE_SIGNED,
                                                                 subordinateCertInfoAllocPtr,
                                                                 ref signatureAlgo,
                                                                 IntPtr.Zero,
                                                                 pbEncodedCert,
                                                                 ref pbEncodedCertLength))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                pbEncodedCert = new byte[pbEncodedCertLength];

                if (!NativeMethods.CryptSignAndEncodeCertificate(hCAProv,
                                                                 (uint)request.KeySpecification,
                                                                 NativeMethods.X509_ASN_ENCODING,
                                                                 NativeMethods.X509_CERT_TO_BE_SIGNED,
                                                                 subordinateCertInfoAllocPtr,
                                                                 ref signatureAlgo,
                                                                 IntPtr.Zero,
                                                                 pbEncodedCert,
                                                                 ref pbEncodedCertLength))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                var cert3 = new X509Certificate2(pbEncodedCert);

                return(cert3);
            }
            finally
            {
                if (hProvAllocPtr != IntPtr.Zero)
                {
                    NativeMethods.CryptReleaseContext(hProvAllocPtr, 0);
                }

                if (hCAProv != IntPtr.Zero)
                {
                    NativeMethods.CryptReleaseContext(hCAProv, 0);
                }

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

                if (subordinateCertInfoAllocPtr != IntPtr.Zero)
                {
                    Marshal.FreeHGlobal(subordinateCertInfoAllocPtr);
                }
            }
        }
        /// <summary>
        /// Create a certificate
        /// </summary>
        /// <param name="request">A request to generate certificate</param>
        /// <returns>Returns a pointer to the signed certificate</returns>
        internal static unsafe IntPtr CreateSelfSignedCertificatePtr(CertificateGenerationRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            if (string.IsNullOrWhiteSpace(request.Subject))
            {
                throw new ArgumentException("request.Subject is null");
            }

            NativeMethods.CERT_NAME_BLOB pSubjectIssuerBlob = new NativeMethods.CERT_NAME_BLOB(0, null);

            IntPtr extensionsPtr = IntPtr.Zero;

            var subjectName = request.Subject;
            var extensions  = request.Extensions;

            var parameters = request.Parameters;

            if (parameters == null)
            {
                parameters = new CspParameters()
                {
                    ProviderName     = MS_ENH_RSA_AES_PROV,
                    ProviderType     = PROV_RSA_AES,
                    KeyContainerName = Guid.NewGuid().ToString(),
                    KeyNumber        = (int)KeyNumber.Exchange,
                    Flags            = CspProviderFlags.UseMachineKeyStore
                }
            }
            ;

            var keySize = request.KeySize;

            if (keySize <= 0)
            {
                keySize = MINIMUM_SELF_SIGNED_CERTIFICATE_KEYSIZE;
            }

            var expirationLength = request.ExpirationLength;

            if (expirationLength <= TimeSpan.MinValue)
            {
                expirationLength = TimeSpan.FromDays(365);
            }

            var durationInMinutes = expirationLength.TotalMinutes;

            var signatureAlgo = request.SignatureAlgorithm;

            if (string.IsNullOrWhiteSpace(signatureAlgo))
            {
                signatureAlgo = NativeMethods.OID_RSA_SHA256RSA;
            }

            string container = Guid.NewGuid().ToString();

            try
            {
                uint pcbEncoded = 0;

                if (!NativeMethods.CertStrToName(NativeMethods.X509_ASN_ENCODING, subjectName, NativeMethods.CERT_X500_NAME_STR, IntPtr.Zero, null, ref pcbEncoded, IntPtr.Zero) && pcbEncoded <= 0)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                byte[] pbEncoded = new byte[pcbEncoded];

                if (!NativeMethods.CertStrToName(NativeMethods.X509_ASN_ENCODING, subjectName, NativeMethods.CERT_X500_NAME_STR, IntPtr.Zero, pbEncoded, ref pcbEncoded, IntPtr.Zero))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                using (new RSACryptoServiceProvider(keySize, parameters))
                {
                    pSubjectIssuerBlob.CopyData(pbEncoded);

                    NativeMethods.CRYPT_KEY_PROV_INFO pKeyProvInfo = new NativeMethods.CRYPT_KEY_PROV_INFO
                    {
                        pwszProvName      = parameters.ProviderName,
                        pwszContainerName = parameters.KeyContainerName,
                        dwProvType        = (uint)parameters.ProviderType,
                        dwFlags           = 0x20, //(uint)parameters.Flags,
                        dwKeySpec         = (uint)parameters.KeyNumber
                    };

                    NativeMethods.CRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm = new NativeMethods.CRYPT_ALGORITHM_IDENTIFIER
                    {
                        pszObjId = signatureAlgo
                    };

                    pSignatureAlgorithm.parameters.cbData = 0;
                    pSignatureAlgorithm.parameters.pbData = IntPtr.Zero;

                    NativeMethods.SYSTEM_TIME pStartTime = new NativeMethods.SYSTEM_TIME(DateTime.UtcNow);
                    NativeMethods.SYSTEM_TIME pEndTime   = new NativeMethods.SYSTEM_TIME(DateTime.UtcNow.AddMinutes((double)durationInMinutes));

                    extensionsPtr = CertUtil.ConvertExtensions(extensions)[0];

                    IntPtr handle = NativeMethods.CertCreateSelfSignCertificate(IntPtr.Zero, ref pSubjectIssuerBlob, 0, ref pKeyProvInfo, ref pSignatureAlgorithm, ref pStartTime, ref pEndTime, extensionsPtr);

                    if (handle == IntPtr.Zero)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    return(handle);
                }
            }
            finally
            {
                if (IntPtr.Zero != extensionsPtr)
                {
                    Marshal.FreeHGlobal(extensionsPtr);
                    extensionsPtr = IntPtr.Zero;
                }

                pSubjectIssuerBlob.Dispose();
            }
        }
    }