private static ECDsa DecodeECDsaPublicKey(CertificatePal certificatePal) { using (SafeBCryptKeyHandle bCryptKeyHandle = ImportPublicKeyInfo(certificatePal.CertContext)) { CngKeyBlobFormat blobFormat = CngKeyBlobFormat.EccPublicBlob; byte[] keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat)) { return new ECDsaCng(cngKey); } } }
private static ECDsa DecodeECDsaPublicKey(CertificatePal certificatePal) { ECDsa ecdsa; using (SafeBCryptKeyHandle bCryptKeyHandle = ImportPublicKeyInfo(certificatePal.CertContext)) { CngKeyBlobFormat blobFormat; byte[] keyBlob; #if NETNATIVE blobFormat = CngKeyBlobFormat.EccPublicBlob; keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat)) { ecdsa = new ECDsaCng(cngKey); } #else string curveName = GetCurveName(bCryptKeyHandle); if (curveName == null) { if (HasExplicitParameters(bCryptKeyHandle)) { blobFormat = CngKeyBlobFormat.EccFullPublicBlob; } else { blobFormat = CngKeyBlobFormat.EccPublicBlob; } keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); using (CngKey cngKey = CngKey.Import(keyBlob, blobFormat)) { ecdsa = new ECDsaCng(cngKey); } } else { blobFormat = CngKeyBlobFormat.EccPublicBlob; keyBlob = ExportKeyBlob(bCryptKeyHandle, blobFormat); ECParameters ecparams = new ECParameters(); ExportNamedCurveParameters(ref ecparams, keyBlob, false); ecparams.Curve = ECCurve.CreateFromFriendlyName(curveName); ecdsa = new ECDsaCng(); ecdsa.ImportParameters(ecparams); } #endif } return ecdsa; }
private CertificatePal(CertificatePal copyFrom) { // Use _certContext (instead of CertContext) to keep the original context handle from being // finalized until all cert copies are no longer referenced. _certContext = new SafeCertContextHandle(copyFrom._certContext); }
/// <summary> /// Returns the SafeCertContextHandle. Use this instead of FromHandle() when /// creating another X509Certificate object based on this one to ensure the underlying /// cert context is not released at the wrong time. /// </summary> public static ICertificatePal FromOtherCert(X509Certificate copyFrom) { CertificatePal pal = new CertificatePal((CertificatePal)copyFrom.Pal); return pal; }
private static ICertificatePal FromBlobOrFile(byte[] rawData, string fileName, string password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(rawData != null || fileName != null); bool loadFromFile = (fileName != null); PfxCertStoreFlags pfxCertStoreFlags = MapKeyStorageFlags(keyStorageFlags); bool persistKeySet = (0 != (keyStorageFlags & X509KeyStorageFlags.PersistKeySet)); CertEncodingType msgAndCertEncodingType; ContentType contentType; FormatType formatType; SafeCertStoreHandle hCertStore = null; SafeCryptMsgHandle hCryptMsg = null; SafeCertContextHandle pCertContext = null; try { unsafe { fixed (byte* pRawData = rawData) { fixed (char* pFileName = fileName) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(loadFromFile ? 0 : rawData.Length, pRawData); CertQueryObjectType objectType = loadFromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB; void* pvObject = loadFromFile ? (void*)pFileName : (void*)&certBlob; bool success = Interop.crypt32.CryptQueryObject( objectType, pvObject, X509ExpectedContentTypeFlags, X509ExpectedFormatTypeFlags, 0, out msgAndCertEncodingType, out contentType, out formatType, out hCertStore, out hCryptMsg, out pCertContext ); if (!success) { int hr = Marshal.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); } } } if (contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { if (loadFromFile) rawData = File.ReadAllBytes(fileName); pCertContext = FilterPFXStore(rawData, password, pfxCertStoreFlags); } CertificatePal pal = new CertificatePal(pCertContext, deleteKeyContainer: !persistKeySet); pCertContext = null; return pal; } } finally { if (hCertStore != null) hCertStore.Dispose(); if (hCryptMsg != null) hCryptMsg.Dispose(); if (pCertContext != null) pCertContext.Dispose(); } }
public X509ContentType GetCertContentType(string fileName) { // If we can't open the file, fail right away. using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(fileName, "rb")) { Interop.Crypto.CheckValidOpenSslHandle(fileBio); int bioPosition = Interop.Crypto.BioTell(fileBio); Debug.Assert(bioPosition >= 0); // X509ContentType.Cert { ICertificatePal certPal; if (CertificatePal.TryReadX509Der(fileBio, out certPal)) { certPal.Dispose(); return(X509ContentType.Cert); } CertificatePal.RewindBio(fileBio, bioPosition); if (CertificatePal.TryReadX509Pem(fileBio, out certPal)) { certPal.Dispose(); return(X509ContentType.Cert); } CertificatePal.RewindBio(fileBio, bioPosition); } // X509ContentType.Pkcs7 { if (PkcsFormatReader.IsPkcs7Der(fileBio)) { return(X509ContentType.Pkcs7); } CertificatePal.RewindBio(fileBio, bioPosition); if (PkcsFormatReader.IsPkcs7Pem(fileBio)) { return(X509ContentType.Pkcs7); } CertificatePal.RewindBio(fileBio, bioPosition); } // X509ContentType.Pkcs12 (aka PFX) { OpenSslPkcs12Reader pkcs12Reader; if (OpenSslPkcs12Reader.TryRead(fileBio, out pkcs12Reader)) { pkcs12Reader.Dispose(); return(X509ContentType.Pkcs12); } CertificatePal.RewindBio(fileBio, bioPosition); } } // Unsupported format. // Windows throws new CryptographicException(CRYPT_E_NO_MATCH) throw new CryptographicException(); }
private static ICertificatePal FromBlobOrFile(byte[] rawData, string fileName, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(rawData != null || fileName != null); Debug.Assert(password != null); bool loadFromFile = (fileName != null); PfxCertStoreFlags pfxCertStoreFlags = MapKeyStorageFlags(keyStorageFlags); bool deleteKeyContainer = false; CertEncodingType msgAndCertEncodingType; ContentType contentType; FormatType formatType; SafeCertStoreHandle hCertStore = null; SafeCryptMsgHandle hCryptMsg = null; SafeCertContextHandle pCertContext = null; try { unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(loadFromFile ? 0 : rawData.Length, pRawData); CertQueryObjectType objectType = loadFromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB; void *pvObject = loadFromFile ? (void *)pFileName : (void *)&certBlob; bool success = Interop.crypt32.CryptQueryObject( objectType, pvObject, X509ExpectedContentTypeFlags, X509ExpectedFormatTypeFlags, 0, out msgAndCertEncodingType, out contentType, out formatType, out hCertStore, out hCryptMsg, out pCertContext ); if (!success) { int hr = Interop.CPError.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); } } } if (contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { if (loadFromFile) { rawData = File.ReadAllBytes(fileName); } pCertContext = FilterPFXStore(rawData, password, pfxCertStoreFlags); // If PersistKeySet is set we don't delete the key, so that it persists. // If EphemeralKeySet is set we don't delete the key, because there's no file, so it's a wasteful call. const X509KeyStorageFlags DeleteUnless = X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.EphemeralKeySet | // begin: gost X509KeyStorageFlags.CspNoPersistKeySet; // end gost deleteKeyContainer = ((keyStorageFlags & DeleteUnless) == 0); } CertificatePal pal = new CertificatePal(pCertContext, deleteKeyContainer); pCertContext = null; return(pal); } } finally { if (hCertStore != null) { hCertStore.Dispose(); } if (hCryptMsg != null) { hCryptMsg.Dispose(); } if (pCertContext != null) { pCertContext.Dispose(); } } }
private static void LoadMachineStores() { Debug.Assert( Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)"); var rootStore = new List <X509Certificate2>(); var intermedStore = new List <X509Certificate2>(); DirectoryInfo rootStorePath = null; IEnumerable <FileInfo> trustedCertFiles; try { rootStorePath = new DirectoryInfo(Interop.Crypto.GetX509RootStorePath()); } catch (ArgumentException) { // If SSL_CERT_DIR is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStorePath value is ignored. } if (rootStorePath != null && rootStorePath.Exists) { trustedCertFiles = rootStorePath.EnumerateFiles(); } else { trustedCertFiles = Array.Empty <FileInfo>(); } FileInfo rootStoreFile = null; try { rootStoreFile = new FileInfo(Interop.Crypto.GetX509RootStoreFile()); } catch (ArgumentException) { // If SSL_CERT_FILE is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStoreFile value is ignored. } if (rootStoreFile != null && rootStoreFile.Exists) { trustedCertFiles = Append(trustedCertFiles, rootStoreFile); } HashSet <X509Certificate2> uniqueRootCerts = new HashSet <X509Certificate2>(); HashSet <X509Certificate2> uniqueIntermediateCerts = new HashSet <X509Certificate2>(); foreach (FileInfo file in trustedCertFiles) { using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb")) { ICertificatePal pal; while (CertificatePal.TryReadX509Pem(fileBio, out pal) || CertificatePal.TryReadX509Der(fileBio, out pal)) { X509Certificate2 cert = new X509Certificate2(pal); // The HashSets are just used for uniqueness filters, they do not survive this method. if (StringComparer.Ordinal.Equals(cert.Subject, cert.Issuer)) { if (uniqueRootCerts.Add(cert)) { rootStore.Add(cert); continue; } } else { if (uniqueIntermediateCerts.Add(cert)) { intermedStore.Add(cert); continue; } } // There's a good chance we'll encounter duplicates on systems that have both one-cert-per-file // and one-big-file trusted certificate stores. Anything that wasn't unique will end up here. cert.Dispose(); } } } var rootStorePal = new CollectionBackedStoreProvider(rootStore); s_machineIntermediateStore = new CollectionBackedStoreProvider(intermedStore); // s_machineRootStore's nullarity is the loaded-state sentinel, so write it with Volatile. Debug.Assert(Monitor.IsEntered(s_machineLoadLock), "LoadMachineStores assumes a lock(s_machineLoadLock)"); Volatile.Write(ref s_machineRootStore, rootStorePal); }
public static ILoaderPal FromBlob(ReadOnlySpan <byte> rawData, SafePasswordHandle password, X509KeyStorageFlags keyStorageFlags) { List <ICertificatePal>?certificateList = null; AppleCertificatePal.TryDecodePem( rawData, (derData, contentType) => { certificateList = certificateList ?? new List <ICertificatePal>(); certificateList.Add(AppleCertificatePal.FromDerBlob(derData, contentType, password, keyStorageFlags)); return(true); }); if (certificateList != null) { return(new CertCollectionLoader(certificateList)); } X509ContentType contentType = AppleCertificatePal.GetDerCertContentType(rawData); if (contentType == X509ContentType.Pkcs7) { throw new CryptographicException( SR.Cryptography_X509_PKCS7_Unsupported, new PlatformNotSupportedException(SR.Cryptography_X509_PKCS7_Unsupported)); } if (contentType == X509ContentType.Pkcs12) { ApplePkcs12Reader reader = new ApplePkcs12Reader(rawData); try { reader.Decrypt(password); return(new ApplePkcs12CertLoader(reader, password)); } catch { reader.Dispose(); throw; } } SafeCFArrayHandle certs = Interop.AppleCrypto.X509ImportCollection( rawData, contentType, password); using (certs) { long longCount = Interop.CoreFoundation.CFArrayGetCount(certs); if (longCount > int.MaxValue) { throw new CryptographicException(); } int count = (int)longCount; // Apple returns things in the opposite order from Windows, so read backwards. certificateList = new List <ICertificatePal>(count); for (int i = count - 1; i >= 0; i--) { IntPtr handle = Interop.CoreFoundation.CFArrayGetValueAtIndex(certs, i); if (handle != IntPtr.Zero) { ICertificatePal?certPal = CertificatePal.FromHandle(handle, throwOnFail: false); if (certPal != null) { certificateList.Add(certPal); } } } } return(new CertCollectionLoader(certificateList)); }
/// <summary> /// Returns the SafeCertContextHandle. Use this instead of FromHandle() when /// creating another X509Certificate object based on this one to ensure the underlying /// cert context is not released at the wrong time. /// </summary> public static ICertificatePal FromOtherCert(X509Certificate copyFrom) { CertificatePal pal = new CertificatePal((CertificatePal)copyFrom.Pal); return(pal); }
private static void LoadMachineStores() { Debug.Assert( Monitor.IsEntered(s_machineIntermediateStore), "LoadMachineStores assumes a lock(s_machineIntermediateStore)"); X509Certificate2Collection rootStore = new X509Certificate2Collection(); DirectoryInfo rootStorePath = null; IEnumerable <FileInfo> trustedCertFiles; try { rootStorePath = new DirectoryInfo(Interop.Crypto.GetX509RootStorePath()); } catch (ArgumentException) { // If SSL_CERT_DIR is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStorePath value is ignored. } if (rootStorePath != null && rootStorePath.Exists) { trustedCertFiles = rootStorePath.EnumerateFiles(); } else { trustedCertFiles = Array.Empty <FileInfo>(); } FileInfo rootStoreFile = null; try { rootStoreFile = new FileInfo(Interop.Crypto.GetX509RootStoreFile()); } catch (ArgumentException) { // If SSL_CERT_FILE is set to the empty string, or anything else which gives // "The path is not of a legal form", then the GetX509RootStoreFile value is ignored. } if (rootStoreFile != null && rootStoreFile.Exists) { trustedCertFiles = Append(trustedCertFiles, rootStoreFile); } HashSet <X509Certificate2> uniqueRootCerts = new HashSet <X509Certificate2>(); HashSet <X509Certificate2> uniqueIntermediateCerts = new HashSet <X509Certificate2>(); foreach (FileInfo file in trustedCertFiles) { using (SafeBioHandle fileBio = Interop.Crypto.BioNewFile(file.FullName, "rb")) { ICertificatePal pal; while (CertificatePal.TryReadX509Pem(fileBio, out pal) || CertificatePal.TryReadX509Der(fileBio, out pal)) { X509Certificate2 cert = new X509Certificate2(pal); // The HashSets are just used for uniqueness filters, they do not survive this method. if (StringComparer.Ordinal.Equals(cert.Subject, cert.Issuer)) { if (uniqueRootCerts.Add(cert)) { rootStore.Add(cert); } } else { if (uniqueIntermediateCerts.Add(cert)) { s_machineIntermediateStore.Add(cert); } } } } } s_machineRootStore = rootStore; }
private static ICertificatePal FromBlobOrFile(byte[] rawData, string fileName, string password, X509KeyStorageFlags keyStorageFlags) { Debug.Assert(rawData != null || fileName != null); bool loadFromFile = (fileName != null); PfxCertStoreFlags pfxCertStoreFlags = MapKeyStorageFlags(keyStorageFlags); bool persistKeySet = (0 != (keyStorageFlags & X509KeyStorageFlags.PersistKeySet)); CertEncodingType msgAndCertEncodingType; ContentType contentType; FormatType formatType; SafeCertStoreHandle hCertStore = null; SafeCryptMsgHandle hCryptMsg = null; SafeCertContextHandle pCertContext = null; try { unsafe { fixed(byte *pRawData = rawData) { fixed(char *pFileName = fileName) { CRYPTOAPI_BLOB certBlob = new CRYPTOAPI_BLOB(loadFromFile ? 0 : rawData.Length, pRawData); CertQueryObjectType objectType = loadFromFile ? CertQueryObjectType.CERT_QUERY_OBJECT_FILE : CertQueryObjectType.CERT_QUERY_OBJECT_BLOB; void *pvObject = loadFromFile ? (void *)pFileName : (void *)&certBlob; bool success = Interop.crypt32.CryptQueryObject( objectType, pvObject, X509ExpectedContentTypeFlags, X509ExpectedFormatTypeFlags, 0, out msgAndCertEncodingType, out contentType, out formatType, out hCertStore, out hCryptMsg, out pCertContext ); if (!success) { int hr = Marshal.GetHRForLastWin32Error(); throw hr.ToCryptographicException(); } } } if (contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED || contentType == ContentType.CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED) { pCertContext = GetSignerInPKCS7Store(hCertStore, hCryptMsg); } else if (contentType == ContentType.CERT_QUERY_CONTENT_PFX) { if (loadFromFile) { rawData = File.ReadAllBytes(fileName); } pCertContext = FilterPFXStore(rawData, password, pfxCertStoreFlags); } CertificatePal pal = new CertificatePal(pCertContext, deleteKeyContainer: !persistKeySet); pCertContext = null; return(pal); } } finally { if (hCertStore != null) { hCertStore.Dispose(); } if (hCryptMsg != null) { hCryptMsg.Dispose(); } if (pCertContext != null) { pCertContext.Dispose(); } } }
private static ILoaderPal FromBio(SafeBioHandle bio, SafePasswordHandle password) { int bioPosition = Interop.Crypto.BioTell(bio); Debug.Assert(bioPosition >= 0); ICertificatePal singleCert; if (CertificatePal.TryReadX509Pem(bio, out singleCert)) { return(SingleCertToLoaderPal(singleCert)); } // Rewind, try again. CertificatePal.RewindBio(bio, bioPosition); if (CertificatePal.TryReadX509Der(bio, out singleCert)) { return(SingleCertToLoaderPal(singleCert)); } // Rewind, try again. CertificatePal.RewindBio(bio, bioPosition); List <ICertificatePal> certPals; if (PkcsFormatReader.TryReadPkcs7Pem(bio, out certPals)) { return(ListToLoaderPal(certPals)); } // Rewind, try again. CertificatePal.RewindBio(bio, bioPosition); if (PkcsFormatReader.TryReadPkcs7Der(bio, out certPals)) { return(ListToLoaderPal(certPals)); } // Rewind, try again. CertificatePal.RewindBio(bio, bioPosition); // Capture the exception so in case of failure, the call to BioSeek does not override it. Exception openSslException; if (PkcsFormatReader.TryReadPkcs12(bio, password, out certPals, out openSslException)) { return(ListToLoaderPal(certPals)); } // Since we aren't going to finish reading, leaving the buffer where it was when we got // it seems better than leaving it in some arbitrary other position. // // Use BioSeek directly for the last seek attempt, because any failure here should instead // report the already created (but not yet thrown) exception. if (Interop.Crypto.BioSeek(bio, bioPosition) < 0) { Interop.Crypto.ErrClearError(); } Debug.Assert(openSslException != null); throw openSslException; }