public DuplicateSafeNCryptKeyHandle(SafeNCryptKeyHandle original)
            : base()
        {
            bool success = false;

            original.DangerousAddRef(ref success);
            if (!success)
            {
                throw new CryptographicException(); // DangerousAddRef() never actually sets success to false, so no need to expend a resource string here.
            }
            SetHandle(original.DangerousGetHandle());
            _original = original;
        }
Exemple #2
0
        private static SafeNCryptKeyHandle TryAcquireCngPrivateKey(
            SafeCertContextHandle certificateContext,
            out CngKeyHandleOpenOptions handleOptions)
        {
            Debug.Assert(certificateContext != null, "certificateContext != null");
            Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid,
                         "!certificateContext.IsClosed && !certificateContext.IsInvalid");

            IntPtr privateKeyPtr;

            // If the certificate has a key handle instead of a key prov info, return the
            // ephemeral key
            {
                int cbData = IntPtr.Size;

                if (Interop.crypt32.CertGetCertificateContextProperty(
                        certificateContext,
                        CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID,
                        out privateKeyPtr,
                        ref cbData))
                {
                    handleOptions = CngKeyHandleOpenOptions.EphemeralKey;
                    return(new SafeNCryptKeyHandle(privateKeyPtr, certificateContext));
                }
            }

            bool freeKey = true;
            SafeNCryptKeyHandle privateKey = null;

            handleOptions = CngKeyHandleOpenOptions.None;
            try
            {
                int keySpec = 0;
                if (!Interop.crypt32.CryptAcquireCertificatePrivateKey(
                        certificateContext,
                        CryptAcquireFlags.CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,
                        IntPtr.Zero,
                        out privateKey,
                        out keySpec,
                        out freeKey))
                {
                    int dwErrorCode = Marshal.GetLastWin32Error();

                    // The documentation for CryptAcquireCertificatePrivateKey says that freeKey
                    // should already be false if "key acquisition fails", and it can be presumed
                    // that privateKey was set to 0.  But, just in case:
                    freeKey = false;
                    privateKey?.SetHandleAsInvalid();
                    return(null);
                }

                // It is very unlikely that Windows will tell us !freeKey other than when reporting failure,
                // because we set neither CRYPT_ACQUIRE_CACHE_FLAG nor CRYPT_ACQUIRE_USE_PROV_INFO_FLAG, which are
                // currently the only two success situations documented. However, any !freeKey response means the
                // key's lifetime is tied to that of the certificate, so re-register the handle as a child handle
                // of the certificate.
                if (!freeKey && privateKey != null && !privateKey.IsInvalid)
                {
                    var newKeyHandle = new SafeNCryptKeyHandle(privateKey.DangerousGetHandle(), certificateContext);
                    privateKey.SetHandleAsInvalid();
                    privateKey = newKeyHandle;
                    freeKey    = true;
                }

                return(privateKey);
            }
            catch
            {
                // If we aren't supposed to free the key, and we're not returning it,
                // just tell the SafeHandle to not free itself.
                if (privateKey != null && !freeKey)
                {
                    privateKey.SetHandleAsInvalid();
                }

                return(null);
            }
        }
Exemple #3
0
 public DuplicateSafeNCryptKeyHandle(SafeNCryptKeyHandle original)
     : base()
 {
     bool success = false;
     original.DangerousAddRef(ref success);
     if (!success)
         throw new CryptographicException(); // DangerousAddRef() never actually sets success to false, so no need to expend a resource string here.
     SetHandle(original.DangerousGetHandle());
     _original = original;
 }