private static int VerifyCertChain(IntPtr storeCtxPtr, IntPtr arg) { List <X509Certificate2> otherCerts; bool success; using (SafeX509StoreCtxHandle storeCtx = new SafeX509StoreCtxHandle(storeCtxPtr, ownsHandle: false)) using (X509Chain chain = new X509Chain()) { chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; IntPtr leafCertPtr = Interop.Crypto.X509StoreCtxGetTargetCert(storeCtx); if (IntPtr.Zero == leafCertPtr) { Debug.Fail("Invalid target certificate"); return(-1); } using (SafeSharedX509StackHandle extraStack = Interop.Crypto.X509StoreCtxGetSharedUntrusted(storeCtx)) { int extraSize = extraStack.IsInvalid ? 0 : Interop.Crypto.GetX509StackFieldCount(extraStack); otherCerts = new List <X509Certificate2>(extraSize); for (int i = 0; i < extraSize; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(extraStack, i); if (certPtr != IntPtr.Zero) { X509Certificate2 cert = new X509Certificate2(certPtr); otherCerts.Add(cert); chain.ChainPolicy.ExtraStore.Add(cert); } } } using (X509Certificate2 leafCert = new X509Certificate2(leafCertPtr)) { success = chain.Build(leafCert); AddChannelBindingToken(leafCert, arg); } } foreach (X509Certificate2 otherCert in otherCerts) { otherCert.Dispose(); } return(success ? 1 : 0); }
private static bool TryReadPkcs7( SafePkcs7Handle pkcs7, bool single, out ICertificatePal?certPal, [NotNullWhen(true)] out List <ICertificatePal> certPals) { List <ICertificatePal>?readPals = single ? null : new List <ICertificatePal>(); using (SafeSharedX509StackHandle certs = Interop.Crypto.GetPkcs7Certificates(pkcs7)) { int count = Interop.Crypto.GetX509StackFieldCount(certs); if (single) { // In single mode for a PKCS#7 signed or signed-and-enveloped file we're supposed to return // the certificate which signed the PKCS#7 file. // // X509Certificate2Collection::Export(X509ContentType.Pkcs7) claims to be a signed PKCS#7, // but doesn't emit a signature block. So this is hard to test. // // TODO(2910): Figure out how to extract the signing certificate, when it's present. throw new CryptographicException(SR.Cryptography_X509_PKCS7_NoSigner); } Debug.Assert(readPals != null); // null if single == true for (int i = 0; i < count; i++) { // Use FromHandle to duplicate the handle since it would otherwise be freed when the PKCS7 // is Disposed. IntPtr certHandle = Interop.Crypto.GetX509StackField(certs, i); ICertificatePal pal = CertificatePal.FromHandle(certHandle); readPals.Add(pal); } } certPal = null; certPals = readPals; return(true); }
internal static extern IntPtr GetX509StackField(SafeSharedX509StackHandle stack, int loc);
internal static extern int GetX509StackFieldCount(SafeSharedX509StackHandle stack);
internal static extern bool PushX509StackField(SafeSharedX509StackHandle stack, SafeX509Handle x509);
private static extern int GetPkcs7Certificates(SafePkcs7Handle p7, out SafeSharedX509StackHandle certs);
// // Extracts a remote certificate upon request. // internal static X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore) { remoteCertificateStore = null; bool gotReference = false; if (securityContext == null) { return(null); } GlobalLog.Enter("CertificateValidationPal.Unix SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()"); X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { int errorCode = QueryContextRemoteCertificate(securityContext, out remoteContext); if (remoteContext != null && !remoteContext.IsInvalid) { remoteContext.DangerousAddRef(ref gotReference); result = new X509Certificate2(remoteContext.DangerousGetHandle()); } remoteCertificateStore = new X509Certificate2Collection(); using (SafeSharedX509StackHandle chainStack = Interop.OpenSsl.GetPeerCertificateChain(securityContext.SslContext)) { if (!chainStack.IsInvalid) { int count = Interop.Crypto.GetX509StackFieldCount(chainStack); for (int i = 0; i < count; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(chainStack, i); if (certPtr != IntPtr.Zero) { // X509Certificate2(IntPtr) calls X509_dup, so the reference is appropriately tracked. X509Certificate2 chainCert = new X509Certificate2(certPtr); remoteCertificateStore.Add(chainCert); } } } } } finally { if (gotReference) { remoteContext.DangerousRelease(); } if (remoteContext != null) { remoteContext.Dispose(); } } if (SecurityEventSource.Log.IsEnabled()) { SecurityEventSource.Log.RemoteCertificate(result == null ? "null" : result.ToString(true)); } GlobalLog.Leave("CertificateValidationPal.Unix SecureChannel#" + LoggingHash.HashString(securityContext) + "::GetRemoteCertificate()", (result == null ? "null" : result.Subject)); return(result); }
private static bool VerifyCertChain(SafeX509StoreCtxHandle storeCtx, EasyRequest easy) { IntPtr leafCertPtr = Interop.Crypto.X509StoreCtxGetTargetCert(storeCtx); if (leafCertPtr == IntPtr.Zero) { EventSourceTrace("Invalid certificate pointer", easy: easy); return(false); } X509Certificate2[] otherCerts = null; int otherCertsCount = 0; var leafCert = new X509Certificate2(leafCertPtr); try { // We need to respect the user's server validation callback if there is one. If there isn't one, // we can start by first trying to use OpenSSL's verification, though only if CRL checking is disabled, // as OpenSSL doesn't do that. if (easy._handler.ServerCertificateCustomValidationCallback == null && !easy._handler.CheckCertificateRevocationList) { // Start by using the default verification provided directly by OpenSSL. // If it succeeds in verifying the cert chain, we're done. Employing this instead of // our custom implementation will need to be revisited if we ever decide to introduce a // "disallowed" store that enables users to "untrust" certs the system trusts. int sslResult = Interop.Crypto.X509VerifyCert(storeCtx); if (sslResult == 1) { return(true); } // X509_verify_cert can return < 0 in the case of programmer error Debug.Assert(sslResult == 0, "Unexpected error from X509_verify_cert: " + sslResult); } // Either OpenSSL verification failed, or there was a server validation callback // or certificate revocation checking was enabled. Either way, fall back to manual // and more expensive verification that includes checking the user's certs (not // just the system store ones as OpenSSL does). using (var chain = new X509Chain()) { chain.ChainPolicy.RevocationMode = easy._handler.CheckCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; using (SafeSharedX509StackHandle extraStack = Interop.Crypto.X509StoreCtxGetSharedUntrusted(storeCtx)) { if (extraStack.IsInvalid) { otherCerts = Array.Empty <X509Certificate2>(); } else { int extraSize = Interop.Crypto.GetX509StackFieldCount(extraStack); otherCerts = new X509Certificate2[extraSize]; for (int i = 0; i < extraSize; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(extraStack, i); if (certPtr != IntPtr.Zero) { X509Certificate2 cert = new X509Certificate2(certPtr); otherCerts[otherCertsCount++] = cert; chain.ChainPolicy.ExtraStore.Add(cert); } } } } var serverCallback = easy._handler._serverCertificateValidationCallback; if (serverCallback == null) { SslPolicyErrors errors = CertificateValidation.BuildChainAndVerifyProperties(chain, leafCert, checkCertName: false, hostName: null); // libcurl already verifies the host name return(errors == SslPolicyErrors.None); } else { // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server). chain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid); SslPolicyErrors errors = CertificateValidation.BuildChainAndVerifyProperties(chain, leafCert, checkCertName: true, hostName: easy._requestMessage.RequestUri.Host); // we disabled automatic host verification, so we do it here return(serverCallback(easy._requestMessage, leafCert, chain, errors)); } } } finally { for (int i = 0; i < otherCertsCount; i++) { otherCerts[i].Dispose(); } leafCert.Dispose(); } }
private static X509Certificate2?GetRemoteCertificate(SafeDeleteContext?securityContext, X509Certificate2Collection?remoteCertificateStore) { bool gotReference = false; if (securityContext == null) { return(null); } if (NetEventSource.IsEnabled) { NetEventSource.Enter(securityContext); } X509Certificate2? result = null; SafeFreeCertContext?remoteContext = null; try { int errorCode = QueryContextRemoteCertificate(securityContext, out remoteContext); if (remoteContext != null && !remoteContext.IsInvalid) { remoteContext.DangerousAddRef(ref gotReference); result = new X509Certificate2(remoteContext.DangerousGetHandle()); } if (remoteCertificateStore != null) { using (SafeSharedX509StackHandle chainStack = Interop.OpenSsl.GetPeerCertificateChain(((SafeDeleteSslContext)securityContext).SslContext)) { if (!chainStack.IsInvalid) { int count = Interop.Crypto.GetX509StackFieldCount(chainStack); for (int i = 0; i < count; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(chainStack, i); if (certPtr != IntPtr.Zero) { // X509Certificate2(IntPtr) calls X509_dup, so the reference is appropriately tracked. X509Certificate2 chainCert = new X509Certificate2(certPtr); remoteCertificateStore.Add(chainCert); } } } } } } catch { result?.Dispose(); throw; } finally { if (remoteContext != null) { if (gotReference) { remoteContext.DangerousRelease(); } remoteContext.Dispose(); } } if (NetEventSource.IsEnabled) { NetEventSource.Log.RemoteCertificate(result); NetEventSource.Exit(securityContext, result); } return(result); }
// // Extracts a remote certificate upon request. // internal override X509Certificate2 GetRemoteCertificate(SafeDeleteContext securityContext, out X509Certificate2Collection remoteCertificateStore) { remoteCertificateStore = null; bool gotReference = false; if (securityContext == null) { return(null); } GlobalLog.Enter("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}"); X509Certificate2 result = null; SafeFreeCertContext remoteContext = null; try { int errorCode = SSPIWrapper.QueryContextRemoteCertificate(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext); if (remoteContext != null && !remoteContext.IsInvalid) { remoteContext.DangerousAddRef(ref gotReference); result = new X509Certificate2(remoteContext.DangerousGetHandle()); } remoteCertificateStore = new X509Certificate2Collection(); using (SafeSharedX509StackHandle chainStack = Interop.OpenSsl.GetPeerCertificateChain(securityContext.SslContext)) { if (!chainStack.IsInvalid) { int count = Interop.Crypto.GetX509StackFieldCount(chainStack); for (int i = 0; i < count; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(chainStack, i); if (certPtr != IntPtr.Zero) { // X509Certificate2(IntPtr) calls X509_dup, so the reference is appropriately tracked. X509Certificate2 chainCert = new X509Certificate2(certPtr); remoteCertificateStore.Add(chainCert); } } } } } finally { if (gotReference) { remoteContext.DangerousRelease(); } if (remoteContext != null) { remoteContext.Dispose(); } } if (Logging.On) { Logging.PrintInfo(Logging.Web, SR.Format(SR.net_log_remote_certificate, (result == null ? "null" : result.ToString(true)))); } GlobalLog.Leave("SecureChannel#" + Logging.HashString(this) + "::RemoteCertificate{get;}", (result == null ? "null" : result.Subject)); return(result); }
internal static partial int GetX509StackFieldCount(SafeSharedX509StackHandle stack);
private static int VerifyCertChain(IntPtr storeCtxPtr, IntPtr curlPtr) { EasyRequest easy; if (!TryGetEasyRequest(curlPtr, out easy)) { EventSourceTrace("Could not find associated easy request: {0}", curlPtr); return(0); } using (var storeCtx = new SafeX509StoreCtxHandle(storeCtxPtr, ownsHandle: false)) { IntPtr leafCertPtr = Interop.Crypto.X509StoreCtxGetTargetCert(storeCtx); if (IntPtr.Zero == leafCertPtr) { EventSourceTrace("Invalid certificate pointer"); return(0); } using (X509Certificate2 leafCert = new X509Certificate2(leafCertPtr)) { // Set up the CBT with this certificate. easy._requestContentStream?.SetChannelBindingToken(leafCert); // We need to respect the user's server validation callback if there is one. If there isn't one, // we can start by first trying to use OpenSSL's verification, though only if CRL checking is disabled, // as OpenSSL doesn't do that. if (easy._handler.ServerCertificateValidationCallback == null && !easy._handler.CheckCertificateRevocationList) { // Start by using the default verification provided directly by OpenSSL. // If it succeeds in verifying the cert chain, we're done. Employing this instead of // our custom implementation will need to be revisited if we ever decide to introduce a // "disallowed" store that enables users to "untrust" certs the system trusts. int sslResult = Interop.Crypto.X509VerifyCert(storeCtx); if (sslResult == 1) { return(1); } // X509_verify_cert can return < 0 in the case of programmer error Debug.Assert(sslResult == 0, "Unexpected error from X509_verify_cert: " + sslResult); } // Either OpenSSL verification failed, or there was a server validation callback. // Either way, fall back to manual and more expensive verification that includes // checking the user's certs (not just the system store ones as OpenSSL does). X509Certificate2[] otherCerts; int otherCertsCount = 0; bool success; using (X509Chain chain = new X509Chain()) { chain.ChainPolicy.RevocationMode = easy._handler.CheckCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; using (SafeSharedX509StackHandle extraStack = Interop.Crypto.X509StoreCtxGetSharedUntrusted(storeCtx)) { if (extraStack.IsInvalid) { otherCerts = Array.Empty <X509Certificate2>(); } else { int extraSize = Interop.Crypto.GetX509StackFieldCount(extraStack); otherCerts = new X509Certificate2[extraSize]; for (int i = 0; i < extraSize; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(extraStack, i); if (certPtr != IntPtr.Zero) { X509Certificate2 cert = new X509Certificate2(certPtr); otherCerts[otherCertsCount++] = cert; chain.ChainPolicy.ExtraStore.Add(cert); } } } } var serverCallback = easy._handler._serverCertificateValidationCallback; if (serverCallback == null) { SslPolicyErrors errors = CertificateValidation.BuildChainAndVerifyProperties(chain, leafCert, checkCertName: false, hostName: null); // libcurl already verifies the host name success = errors == SslPolicyErrors.None; } else { SslPolicyErrors errors = CertificateValidation.BuildChainAndVerifyProperties(chain, leafCert, checkCertName: true, hostName: easy._requestMessage.RequestUri.Host); // we disabled automatic host verification, so we do it here try { success = serverCallback(easy._requestMessage, leafCert, chain, errors); } catch (Exception exc) { EventSourceTrace("Server validation callback threw exception: {0}", exc); easy.FailRequest(exc); success = false; } } } for (int i = 0; i < otherCertsCount; i++) { otherCerts[i].Dispose(); } return(success ? 1 : 0); } } }
private static int VerifyCertChain(IntPtr storeCtxPtr, IntPtr arg) { using (SafeX509StoreCtxHandle storeCtx = new SafeX509StoreCtxHandle(storeCtxPtr, ownsHandle: false)) { // First use the default verification provided directly by OpenSSL. // If it succeeds in verifying the cert chain, we're done. // (Employing this instead of our custom implementation will need to be // revisited if we ever decide to a) introduce a "disallowed" store // that enables users to "untrust" certs the system trusts, or b) decide // CRL checking is required, neither of which is done by OpenSSL). int sslResult = Interop.Crypto.X509VerifyCert(storeCtx); if (sslResult == 1) { return(1); } // X509_verify_cert can return < 0 in the case of programmer error Debug.Assert(sslResult == 0, "Unexpected error from X509_verify_cert: " + sslResult); // Only if the fast default verification fails do we then fall back to our more // manual and more expensive verification that includes checking the user's // certs and not just the system store ones. List <X509Certificate2> otherCerts; bool success; using (X509Chain chain = new X509Chain()) { chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot; IntPtr leafCertPtr = Interop.Crypto.X509StoreCtxGetTargetCert(storeCtx); if (IntPtr.Zero == leafCertPtr) { Debug.Fail("Invalid target certificate"); return(-1); } using (SafeSharedX509StackHandle extraStack = Interop.Crypto.X509StoreCtxGetSharedUntrusted(storeCtx)) { int extraSize = extraStack.IsInvalid ? 0 : Interop.Crypto.GetX509StackFieldCount(extraStack); otherCerts = new List <X509Certificate2>(extraSize); for (int i = 0; i < extraSize; i++) { IntPtr certPtr = Interop.Crypto.GetX509StackField(extraStack, i); if (certPtr != IntPtr.Zero) { X509Certificate2 cert = new X509Certificate2(certPtr); otherCerts.Add(cert); chain.ChainPolicy.ExtraStore.Add(cert); } } } using (X509Certificate2 leafCert = new X509Certificate2(leafCertPtr)) { success = chain.Build(leafCert); AddChannelBindingToken(leafCert, arg); } } foreach (X509Certificate2 otherCert in otherCerts) { otherCert.Dispose(); } return(success ? 1 : 0); } }