private static Exception TryGetKeySpecForCertificate(X509Certificate2 cert, out CryptKeySpec keySpec) { using (SafeCertContextHandle hCertContext = cert.CreateCertContextHandle()) { int cbSize = 0; if (!Interop.Crypt32.CertGetCertificateContextProperty(hCertContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, null, ref cbSize)) { ErrorCode errorCode = (ErrorCode)(Marshal.GetLastWin32Error()); keySpec = default(CryptKeySpec); return errorCode.ToCryptographicException(); } byte[] pData = new byte[cbSize]; unsafe { fixed (byte* pvData = pData) { if (!Interop.Crypt32.CertGetCertificateContextProperty(hCertContext, CertContextPropId.CERT_KEY_PROV_INFO_PROP_ID, pData, ref cbSize)) { ErrorCode errorCode = (ErrorCode)(Marshal.GetLastWin32Error()); keySpec = default(CryptKeySpec); return errorCode.ToCryptographicException(); } CRYPT_KEY_PROV_INFO* pCryptKeyProvInfo = (CRYPT_KEY_PROV_INFO*)pvData; keySpec = pCryptKeyProvInfo->dwKeySpec; return null; } } } }
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; } }
public sealed override byte[] GetSubjectKeyIdentifier(X509Certificate2 certificate) { using (SafeCertContextHandle hCertContext = certificate.CreateCertContextHandle()) { byte[] ski = hCertContext.GetSubjectKeyIdentifer(); return ski; } }