internal static void X509StoreSetRevocationFlag(SafeX509StoreHandle ctx, X509RevocationFlag revocationFlag) { if (!CryptoNative_X509StoreSetRevocationFlag(ctx, revocationFlag)) { throw CreateOpenSslCryptographicException(); } }
public static void AddCrlForCertificate( X509Certificate2 cert, SafeX509StoreHandle store, X509RevocationMode revocationMode, DateTime verificationTime, ref TimeSpan remainingDownloadTime) { // In Offline mode, accept any cached CRL we have. // "CRL is Expired" is a better match for Offline than "Could not find CRL" if (revocationMode != X509RevocationMode.Online) { verificationTime = DateTime.MinValue; } if (AddCachedCrl(cert, store, verificationTime)) { return; } // Don't do any work if we're over limit or prohibited from fetching new CRLs if (remainingDownloadTime <= TimeSpan.Zero || revocationMode != X509RevocationMode.Online) { return; } DownloadAndAddCrl(cert, store, ref remainingDownloadTime); }
private static bool AddCachedCrl(X509Certificate2 cert, SafeX509StoreHandle store, DateTime verificationTime) { string crlFile = GetCachedCrlPath(cert); using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "rb")) { if (bio.IsInvalid) { Interop.Crypto.ErrClearError(); return(false); } // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still // dispose our copy. using (SafeX509CrlHandle crl = Interop.Crypto.PemReadBioX509Crl(bio)) { if (crl.IsInvalid) { Interop.Crypto.ErrClearError(); return(false); } // If crl.LastUpdate is in the past, downloading a new version isn't really going // to help, since we can't rewind the Internet. So this is just going to fail, but // at least it can fail without using the network. // // If crl.NextUpdate is in the past, try downloading a newer version. DateTime nextUpdate = OpenSslX509CertificateReader.ExtractValidityDateTime( Interop.Crypto.GetX509CrlNextUpdate(crl)); // OpenSSL is going to convert our input time to universal, so we should be in Local or // Unspecified (local-assumed). Debug.Assert( verificationTime.Kind != DateTimeKind.Utc, "UTC verificationTime should have been normalized to Local"); // In the event that we're to-the-second accurate on the match, OpenSSL will consider this // to be already expired. if (nextUpdate <= verificationTime) { return(false); } if (!Interop.Crypto.X509StoreAddCrl(store, crl)) { // Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared. if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError()) { Interop.Crypto.ErrClearError(); } else { throw Interop.Crypto.CreateOpenSslCryptographicException(); } } return(true); } } }
private static extern int CryptoNative_X509StoreSetVerifyTime( SafeX509StoreHandle ctx, int year, int month, int day, int hour, int minute, int second, [MarshalAs(UnmanagedType.Bool)] bool isDst);
internal static SafeX509StoreHandle X509ChainNew(SafeX509StackHandle systemTrust, SafeX509StackHandle userTrust) { SafeX509StoreHandle store = CryptoNative_X509ChainNew(systemTrust, userTrust); if (store.IsInvalid) { throw CreateOpenSslCryptographicException(); } return(store); }
private static void DownloadAndAddCrl( X509Certificate2 cert, SafeX509StoreHandle store, ref TimeSpan remainingDownloadTime) { string url = GetCdpUrl(cert); if (url == null) { return; } // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still // dispose our copy. using (SafeX509CrlHandle crl = CertificateAssetDownloader.DownloadCrl(url, ref remainingDownloadTime)) { // null is a valid return (e.g. no remainingDownloadTime) if (crl != null && !crl.IsInvalid) { if (!Interop.Crypto.X509StoreAddCrl(store, crl)) { // Ignore error "cert already in store", throw on anything else. In any case the error queue will be cleared. if (X509_R_CERT_ALREADY_IN_HASH_TABLE == Interop.Crypto.ErrPeekLastError()) { Interop.Crypto.ErrClearError(); } else { throw Interop.Crypto.CreateOpenSslCryptographicException(); } } // Saving the CRL to the disk is just a performance optimization for later requests to not // need to use the network again, so failure to save shouldn't throw an exception or mark // the chain as invalid. try { string crlFile = GetCachedCrlPath(cert, mkDir: true); using (SafeBioHandle bio = Interop.Crypto.BioNewFile(crlFile, "wb")) { if (bio.IsInvalid || Interop.Crypto.PemWriteBioX509Crl(bio, crl) == 0) { // No bio, or write failed Interop.Crypto.ErrClearError(); } } } catch (UnauthorizedAccessException) { } catch (IOException) { } } } }
public static AndroidKeyStore OpenDefault(OpenFlags openFlags) { SafeX509StoreHandle store = Interop.AndroidCrypto.X509StoreOpenDefault(); if (store.IsInvalid) { store.Dispose(); throw new CryptographicException(); } return(new AndroidKeyStore(store, openFlags)); }
internal static OpenSslX509ChainProcessor InitiateChain( SafeX509Handle leafHandle, X509Certificate2Collection customTrustStore, X509ChainTrustMode trustMode, DateTime verificationTime, TimeSpan remainingDownloadTime) { CachedSystemStoreProvider.GetNativeCollections( out SafeX509StackHandle systemTrust, out SafeX509StackHandle systemIntermediate); SafeX509StoreHandle store = null; SafeX509StackHandle untrusted = null; SafeX509StoreCtxHandle storeCtx = null; try { untrusted = Interop.Crypto.NewX509Stack(); Interop.Crypto.X509StackAddMultiple(untrusted, s_userIntermediateStore.GetNativeCollection()); Interop.Crypto.X509StackAddMultiple(untrusted, s_userPersonalStore.GetNativeCollection()); store = GetTrustStore(trustMode, customTrustStore, untrusted, systemTrust); Interop.Crypto.X509StackAddMultiple(untrusted, systemIntermediate); Interop.Crypto.X509StoreSetVerifyTime(store, verificationTime); storeCtx = Interop.Crypto.X509StoreCtxCreate(); if (!Interop.Crypto.X509StoreCtxInit(storeCtx, store, leafHandle, untrusted)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } return(new OpenSslX509ChainProcessor( leafHandle, store, untrusted, storeCtx, verificationTime, remainingDownloadTime)); } catch { store?.Dispose(); untrusted?.Dispose(); storeCtx?.Dispose(); throw; } }
private static bool AddCachedCrl(X509Certificate2 cert, SafeX509StoreHandle store, DateTime verificationTime) { string crlFile = GetCachedCrlPath(cert); using (SafeBioHandle bio = Interop.libcrypto.BIO_new_file(crlFile, "rb")) { if (bio.IsInvalid) { return(false); } // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still // dispose our copy. using (SafeX509CrlHandle crl = Interop.libcrypto.PEM_read_bio_X509_CRL(bio)) { if (crl.IsInvalid) { return(false); } // If crl.LastUpdate is in the past, downloading a new version isn't really going // to help, since we can't rewind the Internet. So this is just going to fail, but // at least it can fail without using the network. // // If crl.NextUpdate is in the past, try downloading a newer version. DateTime nextUpdate = OpenSslX509CertificateReader.ExtractValidityDateTime( Interop.Crypto.GetX509CrlNextUpdate(crl)); // OpenSSL is going to convert our input time to universal, so we should be in Local or // Unspecified (local-assumed). Debug.Assert( verificationTime.Kind != DateTimeKind.Utc, "UTC verificationTime should have been normalized to Local"); // In the event that we're to-the-second accurate on the match, OpenSSL will consider this // to be already expired. if (nextUpdate <= verificationTime) { return(false); } // TODO (#3063): Check the return value of X509_STORE_add_crl, and throw on any error other // than X509_R_CERT_ALREADY_IN_HASH_TABLE Interop.libcrypto.X509_STORE_add_crl(store, crl); return(true); } } }
private OpenSslX509ChainProcessor( SafeX509Handle leafHandle, SafeX509StoreHandle store, SafeX509StackHandle untrusted, SafeX509StoreCtxHandle storeCtx, DateTime verificationTime, TimeSpan remainingDownloadTime) { _leafHandle = leafHandle; _store = store; _untrustedLookup = untrusted; _storeCtx = storeCtx; _verificationTime = verificationTime; _remainingDownloadTime = remainingDownloadTime; }
internal static void X509StoreCtxResetForSignatureError( SafeX509StoreCtxHandle ctx, out SafeX509StoreHandle newStore) { if (CryptoNative_X509StoreCtxResetForSignatureError(ctx, out newStore) != 1) { newStore.Dispose(); newStore = null; throw CreateOpenSslCryptographicException(); } if (newStore.IsInvalid) { newStore.Dispose(); newStore = null; } }
internal static OpenSslX509ChainProcessor InitiateChain( SafeX509Handle leafHandle, DateTime verificationTime, TimeSpan remainingDownloadTime) { SafeX509StackHandle systemTrust = StorePal.GetMachineRoot().GetNativeCollection(); SafeX509StackHandle systemIntermediate = StorePal.GetMachineIntermediate().GetNativeCollection(); SafeX509StoreHandle store = null; SafeX509StackHandle untrusted = null; SafeX509StoreCtxHandle storeCtx = null; try { store = Interop.Crypto.X509ChainNew(systemTrust, s_userRootPath); untrusted = Interop.Crypto.NewX509Stack(); Interop.Crypto.X509StackAddDirectoryStore(untrusted, s_userIntermediatePath); Interop.Crypto.X509StackAddDirectoryStore(untrusted, s_userPersonalPath); Interop.Crypto.X509StackAddMultiple(untrusted, systemIntermediate); Interop.Crypto.X509StoreSetVerifyTime(store, verificationTime); storeCtx = Interop.Crypto.X509StoreCtxCreate(); if (!Interop.Crypto.X509StoreCtxInit(storeCtx, store, leafHandle, untrusted)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } return(new OpenSslX509ChainProcessor( leafHandle, store, untrusted, storeCtx, verificationTime, remainingDownloadTime)); } catch { store?.Dispose(); untrusted?.Dispose(); storeCtx?.Dispose(); throw; } }
private static void DownloadAndAddCrl( X509Certificate2 cert, SafeX509StoreHandle store, ref TimeSpan remainingDownloadTime) { string url = GetCdpUrl(cert); if (url == null) { return; } // X509_STORE_add_crl will increase the refcount on the CRL object, so we should still // dispose our copy. using (SafeX509CrlHandle crl = CertificateAssetDownloader.DownloadCrl(url, ref remainingDownloadTime)) { // null is a valid return (e.g. no remainingDownloadTime) if (crl != null && !crl.IsInvalid) { // TODO (#3063): Check the return value of X509_STORE_add_crl, and throw on any error other // than X509_R_CERT_ALREADY_IN_HASH_TABLE Interop.libcrypto.X509_STORE_add_crl(store, crl); // Saving the CRL to the disk is just a performance optimization for later requests to not // need to use the network again, so failure to save shouldn't throw an exception or mark // the chain as invalid. try { string crlFile = GetCachedCrlPath(cert, mkDir: true); using (SafeBioHandle bio = Interop.libcrypto.BIO_new_file(crlFile, "wb")) { if (!bio.IsInvalid) { Interop.libcrypto.PEM_write_bio_X509_CRL(bio, crl); } } } catch (IOException) { } } } }
internal static void X509StoreSetVerifyTime(SafeX509StoreHandle ctx, DateTime verifyTime) { // OpenSSL is going to convert our input time to universal, so we should be in Local or // Unspecified (local-assumed). Debug.Assert(verifyTime.Kind != DateTimeKind.Utc, "UTC verifyTime should have been normalized to Local"); int succeeded = CryptoNative_X509StoreSetVerifyTime( ctx, verifyTime.Year, verifyTime.Month, verifyTime.Day, verifyTime.Hour, verifyTime.Minute, verifyTime.Second, verifyTime.IsDaylightSavingTime()); if (succeeded != 1) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } }
public static void AddCrlForCertificate( SafeX509Handle cert, SafeX509StoreHandle store, X509RevocationMode revocationMode, DateTime verificationTime, TimeSpan downloadTimeout) { // In Offline mode, accept any cached CRL we have. // "CRL is Expired" is a better match for Offline than "Could not find CRL" if (revocationMode != X509RevocationMode.Online) { verificationTime = DateTime.MinValue; } string?url = GetCdpUrl(cert); if (url == null) { return; } string crlFileName = GetCrlFileName(cert, url); if (AddCachedCrl(crlFileName, store, verificationTime)) { return; } // Don't do any work if we're prohibited from fetching new CRLs if (revocationMode != X509RevocationMode.Online) { return; } DownloadAndAddCrl(url, crlFileName, store, downloadTimeout); }
internal static extern bool X509_STORE_add_cert(SafeX509StoreHandle ctx, SafeX509Handle x);
internal static extern bool X509_STORE_set_flags(SafeX509StoreHandle ctx, X509VerifyFlags flags);
internal static extern bool X509_STORE_add_crl(SafeX509StoreHandle ctx, SafeX509CrlHandle x);
internal static extern bool X509StoreSetRevocationFlag(SafeX509StoreHandle ctx, X509RevocationFlag revocationFlag);
internal static extern bool X509StoreAddCert(SafeX509StoreHandle ctx, SafeX509Handle x);
internal static unsafe partial bool X509StoreEnumerateCertificates( SafeX509StoreHandle storeHandle,
internal static extern unsafe bool X509StoreEnumerateCertificates( SafeX509StoreHandle storeHandle,
internal static extern bool X509StoreAddCrl(SafeX509StoreHandle ctx, SafeX509CrlHandle x);
public static IChainPal BuildChain( X509Certificate2 leaf, HashSet <X509Certificate2> candidates, HashSet <X509Certificate2> downloaded, HashSet <X509Certificate2> systemTrusted, OidCollection applicationPolicy, OidCollection certificatePolicy, X509RevocationMode revocationMode, X509RevocationFlag revocationFlag, DateTime verificationTime, ref TimeSpan remainingDownloadTime) { X509ChainElement[] elements; List <X509ChainStatus> overallStatus = new List <X509ChainStatus>(); WorkingChain workingChain = new WorkingChain(); Interop.Crypto.X509StoreVerifyCallback workingCallback = workingChain.VerifyCallback; // An X509_STORE is more comparable to Cryptography.X509Certificate2Collection than to // Cryptography.X509Store. So read this with OpenSSL eyes, not CAPI/CNG eyes. // // (If you need to think of it as an X509Store, it's a volatile memory store) using (SafeX509StoreHandle store = Interop.Crypto.X509StoreCreate()) using (SafeX509StoreCtxHandle storeCtx = Interop.Crypto.X509StoreCtxCreate()) { Interop.Crypto.CheckValidOpenSslHandle(store); Interop.Crypto.CheckValidOpenSslHandle(storeCtx); bool lookupCrl = revocationMode != X509RevocationMode.NoCheck; foreach (X509Certificate2 cert in candidates) { OpenSslX509CertificateReader pal = (OpenSslX509CertificateReader)cert.Pal; if (!Interop.Crypto.X509StoreAddCert(store, pal.SafeHandle)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } if (lookupCrl) { CrlCache.AddCrlForCertificate( cert, store, revocationMode, verificationTime, ref remainingDownloadTime); // If we only wanted the end-entity certificate CRL then don't look up // any more of them. lookupCrl = revocationFlag != X509RevocationFlag.EndCertificateOnly; } } if (revocationMode != X509RevocationMode.NoCheck) { if (!Interop.Crypto.X509StoreSetRevocationFlag(store, revocationFlag)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } } SafeX509Handle leafHandle = ((OpenSslX509CertificateReader)leaf.Pal).SafeHandle; if (!Interop.Crypto.X509StoreCtxInit(storeCtx, store, leafHandle)) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } Interop.Crypto.X509StoreCtxSetVerifyCallback(storeCtx, workingCallback); Interop.Crypto.SetX509ChainVerifyTime(storeCtx, verificationTime); int verify = Interop.Crypto.X509VerifyCert(storeCtx); if (verify < 0) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } // Because our callback tells OpenSSL that every problem is ignorable, it should tell us that the // chain is just fine (unless it returned a negative code for an exception) Debug.Assert(verify == 1, "verify == 1"); using (SafeX509StackHandle chainStack = Interop.Crypto.X509StoreCtxGetChain(storeCtx)) { int chainSize = Interop.Crypto.GetX509StackFieldCount(chainStack); elements = new X509ChainElement[chainSize]; int maybeRootDepth = chainSize - 1; // The leaf cert is 0, up to (maybe) the root at chainSize - 1 for (int i = 0; i < chainSize; i++) { List <X509ChainStatus> status = new List <X509ChainStatus>(); List <Interop.Crypto.X509VerifyStatusCode> elementErrors = i < workingChain.Errors.Count ? workingChain.Errors[i] : null; if (elementErrors != null) { AddElementStatus(elementErrors, status, overallStatus); } IntPtr elementCertPtr = Interop.Crypto.GetX509StackField(chainStack, i); if (elementCertPtr == IntPtr.Zero) { throw Interop.Crypto.CreateOpenSslCryptographicException(); } // Duplicate the certificate handle X509Certificate2 elementCert = new X509Certificate2(elementCertPtr); // If the last cert is self signed then it's the root cert, do any extra checks. if (i == maybeRootDepth && IsSelfSigned(elementCert)) { // If the root certificate was downloaded or the system // doesn't trust it, it's untrusted. if (downloaded.Contains(elementCert) || !systemTrusted.Contains(elementCert)) { AddElementStatus( Interop.Crypto.X509VerifyStatusCode.X509_V_ERR_CERT_UNTRUSTED, status, overallStatus); } } elements[i] = new X509ChainElement(elementCert, status.ToArray(), ""); } } } GC.KeepAlive(workingCallback); if ((certificatePolicy != null && certificatePolicy.Count > 0) || (applicationPolicy != null && applicationPolicy.Count > 0)) { List <X509Certificate2> certsToRead = new List <X509Certificate2>(); foreach (X509ChainElement element in elements) { certsToRead.Add(element.Certificate); } CertificatePolicyChain policyChain = new CertificatePolicyChain(certsToRead); bool failsPolicyChecks = false; if (certificatePolicy != null) { if (!policyChain.MatchesCertificatePolicies(certificatePolicy)) { failsPolicyChecks = true; } } if (applicationPolicy != null) { if (!policyChain.MatchesApplicationPolicies(applicationPolicy)) { failsPolicyChecks = true; } } if (failsPolicyChecks) { X509ChainElement leafElement = elements[0]; X509ChainStatus chainStatus = new X509ChainStatus { Status = X509ChainStatusFlags.InvalidPolicyConstraints, StatusInformation = SR.Chain_NoPolicyMatch, }; var elementStatus = new List <X509ChainStatus>(leafElement.ChainElementStatus.Length + 1); elementStatus.AddRange(leafElement.ChainElementStatus); AddUniqueStatus(elementStatus, ref chainStatus); AddUniqueStatus(overallStatus, ref chainStatus); elements[0] = new X509ChainElement( leafElement.Certificate, elementStatus.ToArray(), leafElement.Information); } } return(new OpenSslX509ChainProcessor { ChainStatus = overallStatus.ToArray(), ChainElements = elements, }); }
private static extern bool CryptoNative_X509StoreSetRevocationFlag(SafeX509StoreHandle ctx, X509RevocationFlag revocationFlag);
internal static extern bool X509StoreCtxInit(SafeX509StoreCtxHandle ctx, SafeX509StoreHandle store, SafeX509Handle x509);
internal static extern bool X509StoreCtxInit( SafeX509StoreCtxHandle ctx, SafeX509StoreHandle store, SafeX509Handle x509, SafeX509StackHandle extraCerts);
internal static unsafe partial bool X509StoreAddCertificateWithPrivateKey( SafeX509StoreHandle store, SafeX509Handle cert, SafeKeyHandle key, PAL_KeyAlgorithm algorithm, string hashString);
internal static extern bool X509_STORE_CTX_init(SafeX509StoreCtxHandle ctx, SafeX509StoreHandle store, SafeX509Handle x509, IntPtr zero);
internal static unsafe partial bool X509StoreContainsCertificate( SafeX509StoreHandle store, SafeX509Handle cert, string hashString);