private ICertificatePal CopyWithEphemeralKey(CngKey cngKey)
        {
            Debug.Assert(string.IsNullOrEmpty(cngKey.KeyName));

            // Handle makes a copy of the handle.  This is required given that CertSetCertificateContextProperty accepts a SafeHandle
            // and transfers ownership of the handle to the certificate.  We can't transfer that ownership out of the cngKey, as it's
            // owned by the caller, so we make a copy (using Handle rather than HandleNoDuplicate).
            using (SafeNCryptKeyHandle handle = cngKey.Handle)
            {
                // Make a new pal from bytes.
                CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);
                try
                {
                    if (!Interop.Crypt32.CertSetCertificateContextProperty(
                            pal._certContext,
                            Interop.Crypt32.CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID,
                            Interop.Crypt32.CertSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
                            handle))
                    {
                        throw Marshal.GetLastPInvokeError().ToCryptographicException();
                    }

                    // The value was transferred to the certificate.
                    handle.SetHandleAsInvalid();

                    return(pal);
                }
                catch
                {
                    pal.Dispose();
                    throw;
                }
            }
        }
        private unsafe ICertificatePal?CopyWithPersistedCapiKey(CspKeyContainerInfo keyContainerInfo)
        {
            if (string.IsNullOrEmpty(keyContainerInfo.KeyContainerName))
            {
                return(null);
            }

            // Make a new pal from bytes.
            CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);

            Interop.Crypt32.CRYPT_KEY_PROV_INFO keyProvInfo = default;

            fixed(char *keyName = keyContainerInfo.KeyContainerName)
            fixed(char *provName = keyContainerInfo.ProviderName)
            {
                keyProvInfo.pwszContainerName = keyName;
                keyProvInfo.pwszProvName      = provName;
                keyProvInfo.dwFlags           = keyContainerInfo.MachineKeyStore ? Interop.Crypt32.CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET : 0;
                keyProvInfo.dwProvType        = keyContainerInfo.ProviderType;
                keyProvInfo.dwKeySpec         = (int)keyContainerInfo.KeyNumber;

                if (!Interop.Crypt32.CertSetCertificateContextProperty(
                        pal._certContext,
                        Interop.Crypt32.CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID,
                        Interop.Crypt32.CertSetPropertyFlags.None,
                        &keyProvInfo))
                {
                    Exception e = Marshal.GetLastPInvokeError().ToCryptographicException();
                    pal.Dispose();
                    throw e;
                }
            }

            return(pal);
        }
        private unsafe ICertificatePal?CopyWithPersistedCngKey(CngKey cngKey)
        {
            if (string.IsNullOrEmpty(cngKey.KeyName))
            {
                return(null);
            }

            // Make a new pal from bytes.
            CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);

            CngProvider provider   = cngKey.Provider !;
            string      keyName    = cngKey.KeyName;
            bool        machineKey = cngKey.IsMachineKey;

            // CAPI RSA_SIGN keys won't open correctly under CNG without the key number being specified, so
            // check to see if we can figure out what key number it needs to re-open.
            int keySpec = GuessKeySpec(provider, keyName, machineKey, cngKey.AlgorithmGroup);

            Interop.Crypt32.CRYPT_KEY_PROV_INFO keyProvInfo = default;

            fixed(char *keyNamePtr = cngKey.KeyName)
            fixed(char *provNamePtr = cngKey.Provider !.Provider)
            {
                keyProvInfo.pwszContainerName = keyNamePtr;
                keyProvInfo.pwszProvName      = provNamePtr;
                keyProvInfo.dwFlags           = machineKey ? Interop.Crypt32.CryptAcquireContextFlags.CRYPT_MACHINE_KEYSET : 0;
                keyProvInfo.dwKeySpec         = keySpec;

                if (!Interop.Crypt32.CertSetCertificateContextProperty(
                        pal._certContext,
                        Interop.Crypt32.CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID,
                        Interop.Crypt32.CertSetPropertyFlags.None,
                        &keyProvInfo))
                {
                    Exception e = Marshal.GetLastPInvokeError().ToCryptographicException();
                    pal.Dispose();
                    throw e;
                }
            }

            return(pal);
        }
        private ICertificatePal CopyWithEphemeralKey(CngKey cngKey)
        {
            Debug.Assert(string.IsNullOrEmpty(cngKey.KeyName));

            SafeNCryptKeyHandle handle = cngKey.Handle;

            // Make a new pal from bytes.
            CertificatePal pal = (CertificatePal)FromBlob(RawData, SafePasswordHandle.InvalidHandle, X509KeyStorageFlags.PersistKeySet);

            if (!Interop.Crypt32.CertSetCertificateContextProperty(
                    pal._certContext,
                    Interop.Crypt32.CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID,
                    Interop.Crypt32.CertSetPropertyFlags.CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG,
                    handle))
            {
                pal.Dispose();
                throw Marshal.GetLastWin32Error().ToCryptographicException();
            }

            // The value was transferred to the certificate.
            handle.SetHandleAsInvalid();
            return(pal);
        }