Beispiel #1
0
            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);
            }
Beispiel #2
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);
        }
Beispiel #3
0
 internal static extern IntPtr GetX509StackField(SafeSharedX509StackHandle stack, int loc);
Beispiel #4
0
 internal static extern int GetX509StackFieldCount(SafeSharedX509StackHandle stack);
Beispiel #5
0
 internal static extern bool PushX509StackField(SafeSharedX509StackHandle stack, SafeX509Handle x509);
Beispiel #6
0
 private static extern int GetPkcs7Certificates(SafePkcs7Handle p7, out SafeSharedX509StackHandle certs);
Beispiel #7
0
        //
        // 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);
        }
Beispiel #8
0
            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();
                }
            }
Beispiel #9
0
        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);
        }
Beispiel #10
0
        //
        // 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);
        }
Beispiel #11
0
 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);
                }
            }