internal static extern bool CryptAcquireCertificatePrivateKey( SafeCertContextHandle pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, IntPtr pvParameters, out IntPtr phCryptProvOrNCryptKey, out CryptKeySpec pdwKeySpec, out bool pfCallerFreeProvOrNCryptKey);
public static partial bool CryptAcquireCertificatePrivateKey( SafeCertContextHandle pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, IntPtr pvParameters, out SafeNCryptKeyHandle phCryptProvOrNCryptKey, out CryptKeySpec pdwKeySpec, [MarshalAs(UnmanagedType.Bool)] out bool pfCallerFreeProvOrNCryptKey);
/// <summary> /// Obtains the private key for a certificate. This function is used to obtain access to a user's private key when the user's certificate is available, but the handle of the user's key container is not available. This function can only be used by the owner of a private key and not by any other user. /// If a CSP handle and the key container containing a user's private key are available, the CryptGetUserKey function should be used instead. /// </summary> /// <param name="pCert">The address of a CERT_CONTEXT structure that contains the certificate context for which a private key will be obtained.</param> /// <param name="dwFlags">A set of flags that modify the behavior of this function. This can be zero or a combination of one or more of <see cref="CryptAcquireCertificatePrivateKeyFlags"/> values.</param> /// <param name="pvParameters"> /// If the <see cref="CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_WINDOW_HANDLE_FLAG"/> is set, then this is the address of an HWND. If the <see cref="CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_WINDOW_HANDLE_FLAG"/> is not set, then this parameter must be NULL. /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This parameter was named pvReserved and reserved for future use and must be NULL. /// </param> /// <param name="cryptHandle"> /// Receives a safe handle to either CNG key handle of type NCRYPT_KEY_HANDLE or CryptoAPI provider handle of type HCRYPTPROV. /// </param> /// <returns> /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. /// </returns> public static unsafe bool CryptAcquireCertificatePrivateKey( IntPtr pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, IntPtr pvParameters, out SafeHandle cryptHandle) { IntPtr cryptProvOrNCryptKey; uint keySpec; bool callerFreeProvOrNCryptKey; if (!CryptAcquireCertificatePrivateKey( pCert, dwFlags, (void*)pvParameters, out cryptProvOrNCryptKey, out keySpec, out callerFreeProvOrNCryptKey)) { cryptHandle = AdvApi32.SafeCryptographicProviderHandle.Null; return false; } if (keySpec == CERT_NCRYPT_KEY_SPEC) { cryptHandle = new NCrypt.SafeKeyHandle(cryptProvOrNCryptKey, callerFreeProvOrNCryptKey); } else { cryptHandle = new AdvApi32.SafeCryptographicProviderHandle(cryptProvOrNCryptKey, callerFreeProvOrNCryptKey); } return true; }
/// <summary> /// Obtains the private key for a certificate. This function is used to obtain access to a user's private key when the user's certificate is available, but the handle of the user's key container is not available. This function can only be used by the owner of a private key and not by any other user. /// If a CSP handle and the key container containing a user's private key are available, the CryptGetUserKey function should be used instead. /// </summary> /// <param name="pCert">The address of a CERT_CONTEXT structure that contains the certificate context for which a private key will be obtained.</param> /// <param name="dwFlags">A set of flags that modify the behavior of this function. This can be zero or a combination of one or more of <see cref="CryptAcquireCertificatePrivateKeyFlags"/> values.</param> /// <param name="pvParameters"> /// If the <see cref="CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_WINDOW_HANDLE_FLAG"/> is set, then this is the address of an HWND. If the <see cref="CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_WINDOW_HANDLE_FLAG"/> is not set, then this parameter must be NULL. /// Windows Server 2008 R2, Windows 7, Windows Server 2008, Windows Vista, Windows Server 2003 and Windows XP: This parameter was named pvReserved and reserved for future use and must be NULL. /// </param> /// <param name="cryptHandle"> /// Receives a safe handle to either CNG key handle of type NCRYPT_KEY_HANDLE or CryptoAPI provider handle of type HCRYPTPROV. /// </param> /// <returns> /// If the function succeeds, the return value is nonzero. /// If the function fails, the return value is zero. /// </returns> public static unsafe bool CryptAcquireCertificatePrivateKey( IntPtr pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, IntPtr pvParameters, out SafeHandle cryptHandle) { IntPtr cryptProvOrNCryptKey; uint keySpec; bool callerFreeProvOrNCryptKey; if (!CryptAcquireCertificatePrivateKey( pCert, dwFlags, (void *)pvParameters, out cryptProvOrNCryptKey, out keySpec, out callerFreeProvOrNCryptKey)) { cryptHandle = AdvApi32.SafeCryptographicProviderHandle.Null; return(false); } if (keySpec == CERT_NCRYPT_KEY_SPEC) { cryptHandle = new NCrypt.SafeKeyHandle(cryptProvOrNCryptKey, callerFreeProvOrNCryptKey); } else { cryptHandle = new AdvApi32.SafeCryptographicProviderHandle(cryptProvOrNCryptKey, callerFreeProvOrNCryptKey); } return(true); }
private static extern unsafe bool CryptAcquireCertificatePrivateKey( IntPtr pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, void *pvParameters, out IntPtr phCryptProvOrNCryptKey, out uint pdwKeySpec, [MarshalAs(UnmanagedType.Bool)] out bool pfCallerFreeProvOrNCryptKey);
private static SafeProvOrNCryptKeyHandle TryGetCertificatePrivateKey(X509Certificate2 cert, bool silent, out Exception exception) { CryptAcquireCertificatePrivateKeyFlags flags = CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_COMPARE_KEY_FLAG // Note: Using CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG rather than CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG because wrapping an NCrypt wrapper over CAPI keys unconditionally // causes some legacy features (such as RC4 support) to break. | CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG; if (silent) { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_SILENT_FLAG; } bool mustFree; using (SafeCertContextHandle hCertContext = cert.CreateCertContextHandle()) { IntPtr hKey; CryptKeySpec keySpec; if (!Interop.Crypt32.CryptAcquireCertificatePrivateKey(hCertContext, flags, IntPtr.Zero, out hKey, out keySpec, out mustFree)) { exception = Marshal.GetHRForLastWin32Error().ToCryptographicException(); return(null); } // We need to know whether we got back a CRYPTPROV or NCrypt handle. Unfortunately, NCryptIsKeyHandle() is a prohibited api on UWP. // Fortunately, CryptAcquireCertificatePrivateKey() is documented to tell us which one we got through the keySpec value. bool isNCrypt; switch (keySpec) { case CryptKeySpec.AT_KEYEXCHANGE: case CryptKeySpec.AT_SIGNATURE: isNCrypt = false; break; case CryptKeySpec.CERT_NCRYPT_KEY_SPEC: isNCrypt = true; break; default: // As of this writing, we've exhausted all the known values of keySpec. We have no idea what kind of key handle we got so // play it safe and fail fast. throw new NotSupportedException(SR.Format(SR.Cryptography_Cms_UnknownKeySpec, keySpec)); } SafeProvOrNCryptKeyHandleUwp hProvOrNCryptKey = new SafeProvOrNCryptKeyHandleUwp(hKey, ownsHandle: mustFree, isNcrypt: isNCrypt); exception = null; return(hProvOrNCryptKey); } }
private static extern unsafe bool CryptAcquireCertificatePrivateKey( IntPtr pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, void* pvParameters, out IntPtr phCryptProvOrNCryptKey, out uint pdwKeySpec, [MarshalAs(UnmanagedType.Bool)] out bool pfCallerFreeProvOrNCryptKey);
internal static SafeProvOrNCryptKeyHandle GetCertificatePrivateKey( X509Certificate2 cert, bool silent, bool preferNCrypt, out CryptKeySpec keySpec, out Exception exception) { CryptAcquireCertificatePrivateKeyFlags flags = CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_USE_PROV_INFO_FLAG | CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_COMPARE_KEY_FLAG; if (preferNCrypt) { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG; } else { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG; } if (silent) { flags |= CryptAcquireCertificatePrivateKeyFlags.CRYPT_ACQUIRE_SILENT_FLAG; } bool isNCrypt; bool mustFree; using (SafeCertContextHandle hCertContext = cert.CreateCertContextHandle()) { IntPtr hKey; int cbSize = IntPtr.Size; if (Interop.Crypt32.CertGetCertificateContextProperty( hCertContext, CertContextPropId.CERT_NCRYPT_KEY_HANDLE_PROP_ID, out hKey, ref cbSize)) { exception = null; keySpec = CryptKeySpec.CERT_NCRYPT_KEY_SPEC; return(new SafeProvOrNCryptKeyHandleUwp(hKey, hCertContext)); } if (!Interop.Crypt32.CryptAcquireCertificatePrivateKey( hCertContext, flags, IntPtr.Zero, out hKey, out keySpec, out mustFree)) { exception = Marshal.GetHRForLastWin32Error().ToCryptographicException(); return(null); } // We need to know whether we got back a CRYPTPROV or NCrypt handle. // Unfortunately, NCryptIsKeyHandle() is a prohibited api on UWP. // Fortunately, CryptAcquireCertificatePrivateKey() is documented to tell us which // one we got through the keySpec value. switch (keySpec) { case CryptKeySpec.AT_KEYEXCHANGE: case CryptKeySpec.AT_SIGNATURE: isNCrypt = false; break; case CryptKeySpec.CERT_NCRYPT_KEY_SPEC: isNCrypt = true; break; default: // As of this writing, we've exhausted all the known values of keySpec. // We have no idea what kind of key handle we got so play it safe and fail fast. throw new NotSupportedException(SR.Format(SR.Cryptography_Cms_UnknownKeySpec, keySpec)); } SafeProvOrNCryptKeyHandleUwp hProvOrNCryptKey = new SafeProvOrNCryptKeyHandleUwp( hKey, ownsHandle: mustFree, isNcrypt: isNCrypt); exception = null; return(hProvOrNCryptKey); } }
internal static extern bool CryptAcquireCertificatePrivateKey(SafeCertContextHandle pCert, CryptAcquireCertificatePrivateKeyFlags dwFlags, IntPtr pvParameters, out IntPtr phCryptProvOrNCryptKey, out CryptKeySpec pdwKeySpec, out bool pfCallerFreeProvOrNCryptKey);