internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions)
        {
            AllowRenegotiation             = sslServerAuthenticationOptions.AllowRenegotiation;
            ApplicationProtocols           = sslServerAuthenticationOptions.ApplicationProtocols;
            EnabledSslProtocols            = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols);
            EncryptionPolicy               = sslServerAuthenticationOptions.EncryptionPolicy;
            RemoteCertRequired             = sslServerAuthenticationOptions.ClientCertificateRequired;
            CipherSuitesPolicy             = sslServerAuthenticationOptions.CipherSuitesPolicy;
            CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode;
            if (sslServerAuthenticationOptions.ServerCertificateContext != null)
            {
                CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext;
            }
            else if (sslServerAuthenticationOptions.ServerCertificate is X509Certificate2 certificateWithKey &&
                     certificateWithKey.HasPrivateKey)
            {
                // given cert is X509Certificate2 with key. We can use it directly.
                CertificateContext = SslStreamCertificateContext.Create(certificateWithKey);
            }

            if (sslServerAuthenticationOptions.RemoteCertificateValidationCallback != null)
            {
                CertValidationDelegate = sslServerAuthenticationOptions.RemoteCertificateValidationCallback;
            }
        }
        internal SslAuthenticationOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions)
        {
            // Common options.
            AllowRenegotiation   = sslServerAuthenticationOptions.AllowRenegotiation;
            ApplicationProtocols = sslServerAuthenticationOptions.ApplicationProtocols;
            CheckCertName        = false;
            EnabledSslProtocols  = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols);
            EncryptionPolicy     = sslServerAuthenticationOptions.EncryptionPolicy;
            IsServer             = true;
            RemoteCertRequired   = sslServerAuthenticationOptions.ClientCertificateRequired;
            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Info(this, $"Server RemoteCertRequired: {RemoteCertRequired}.");
            }
            TargetHost = string.Empty;

            // Server specific options.
            CipherSuitesPolicy             = sslServerAuthenticationOptions.CipherSuitesPolicy;
            CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode;

            if (sslServerAuthenticationOptions.ServerCertificateContext != null)
            {
                CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext;
            }
            else if (sslServerAuthenticationOptions.ServerCertificate != null)
            {
                X509Certificate2?certificateWithKey = sslServerAuthenticationOptions.ServerCertificate as X509Certificate2;

                if (certificateWithKey != null && certificateWithKey.HasPrivateKey)
                {
                    // given cert is X509Certificate2 with key. We can use it directly.
                    CertificateContext = SslStreamCertificateContext.Create(certificateWithKey, null);
                }
                else
                {
                    // This is legacy fix-up. If the Certificate did not have key, we will search stores and we
                    // will try to find one with matching hash.
                    certificateWithKey = SecureChannel.FindCertificateWithPrivateKey(this, true, sslServerAuthenticationOptions.ServerCertificate);
                    if (certificateWithKey == null)
                    {
                        throw new AuthenticationException(SR.net_ssl_io_no_server_cert);
                    }

                    CertificateContext = SslStreamCertificateContext.Create(certificateWithKey);
                }
            }

            if (sslServerAuthenticationOptions.RemoteCertificateValidationCallback != null)
            {
                CertValidationDelegate = sslServerAuthenticationOptions.RemoteCertificateValidationCallback;
            }
        }
Example #3
0
        private static SecurityStatusPal HandshakeInternal(
            SafeFreeCredentials credential,
            ref SafeDeleteSslContext?context,
            ReadOnlySpan <byte> inputBuffer,
            ref byte[]?outputBuffer,
            SslAuthenticationOptions sslAuthenticationOptions,
            SelectClientCertificate?clientCertificateSelectionCallback)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context);

                if ((null == context) || context.IsInvalid)
                {
                    sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions);
                    context    = sslContext;
                }

                if (inputBuffer.Length > 0)
                {
                    sslContext !.Write(inputBuffer);
                }

                SafeSslHandle     sslHandle = sslContext !.SslContext;
                SecurityStatusPal status    = PerformHandshake(sslHandle);
                if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded && clientCertificateSelectionCallback != null)
                {
                    X509Certificate2?clientCertificate = clientCertificateSelectionCallback(out bool _);
                    if (clientCertificate != null)
                    {
                        sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate);
                        SafeDeleteSslContext.SetCertificate(sslContext.SslContext, sslAuthenticationOptions.CertificateContext);
                    }

                    // We either got certificate or we can proceed without it. It is up to the server to decide if either is OK.
                    status = PerformHandshake(sslHandle);
                }

                outputBuffer = sslContext.ReadPendingWrites();
                return(status);
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }
        internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticationOptions)
        {
            if (sslServerAuthenticationOptions.ServerCertificate == null &&
                sslServerAuthenticationOptions.ServerCertificateContext == null &&
                sslServerAuthenticationOptions.ServerCertificateSelectionCallback == null &&
                CertSelectionDelegate == null)
            {
                throw new NotSupportedException(SR.net_ssl_io_no_server_cert);
            }

            if ((sslServerAuthenticationOptions.ServerCertificate != null ||
                 sslServerAuthenticationOptions.ServerCertificateContext != null ||
                 CertSelectionDelegate != null) &&
                sslServerAuthenticationOptions.ServerCertificateSelectionCallback != null)
            {
                throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(ServerCertificateSelectionCallback)));
            }

            if (CertValidationDelegate == null)
            {
                CertValidationDelegate = sslServerAuthenticationOptions.RemoteCertificateValidationCallback;
            }
            else if (sslServerAuthenticationOptions.RemoteCertificateValidationCallback != null &&
                     CertValidationDelegate != sslServerAuthenticationOptions.RemoteCertificateValidationCallback)
            {
                // Callback was set in constructor to differet value.
                throw new InvalidOperationException(SR.Format(SR.net_conflicting_options, nameof(RemoteCertificateValidationCallback)));
            }

            IsServer                       = true;
            AllowRenegotiation             = sslServerAuthenticationOptions.AllowRenegotiation;
            ApplicationProtocols           = sslServerAuthenticationOptions.ApplicationProtocols;
            EnabledSslProtocols            = FilterOutIncompatibleSslProtocols(sslServerAuthenticationOptions.EnabledSslProtocols);
            EncryptionPolicy               = sslServerAuthenticationOptions.EncryptionPolicy;
            RemoteCertRequired             = sslServerAuthenticationOptions.ClientCertificateRequired;
            CipherSuitesPolicy             = sslServerAuthenticationOptions.CipherSuitesPolicy;
            CertificateRevocationCheckMode = sslServerAuthenticationOptions.CertificateRevocationCheckMode;
            if (sslServerAuthenticationOptions.ServerCertificateContext != null)
            {
                CertificateContext = sslServerAuthenticationOptions.ServerCertificateContext;
            }
            else if (sslServerAuthenticationOptions.ServerCertificate != null)
            {
                X509Certificate2?certificateWithKey = sslServerAuthenticationOptions.ServerCertificate as X509Certificate2;

                if (certificateWithKey != null && certificateWithKey.HasPrivateKey)
                {
                    // given cert is X509Certificate2 with key. We can use it directly.
                    CertificateContext = SslStreamCertificateContext.Create(certificateWithKey, null);
                }
                else
                {
                    // This is legacy fix-up. If the Certificate did not have key, we will search stores and we
                    // will try to find one with matching hash.
                    certificateWithKey = SslStream.FindCertificateWithPrivateKey(this, true, sslServerAuthenticationOptions.ServerCertificate);
                    if (certificateWithKey == null)
                    {
                        throw new AuthenticationException(SR.net_ssl_io_no_server_cert);
                    }

                    CertificateContext = SslStreamCertificateContext.Create(certificateWithKey);
                }
            }

            if (sslServerAuthenticationOptions.ServerCertificateSelectionCallback != null)
            {
                ServerCertSelectionDelegate = sslServerAuthenticationOptions.ServerCertificateSelectionCallback;
            }
        }
Example #5
0
        private static SecurityStatusPal HandshakeInternal(
            SecureChannel secureChannel,
            SafeFreeCredentials credential,
            ref SafeDeleteSslContext?context,
            ReadOnlySpan <byte> inputBuffer,
            ref byte[]?outputBuffer,
            SslAuthenticationOptions sslAuthenticationOptions)
        {
            Debug.Assert(!credential.IsInvalid);

            try
            {
                SafeDeleteSslContext?sslContext = ((SafeDeleteSslContext?)context);

                if ((null == context) || context.IsInvalid)
                {
                    sslContext = new SafeDeleteSslContext((credential as SafeFreeSslCredentials) !, sslAuthenticationOptions);
                    context    = sslContext;

                    if (!string.IsNullOrEmpty(sslAuthenticationOptions.TargetHost) && !sslAuthenticationOptions.IsServer)
                    {
                        Interop.AppleCrypto.SslSetTargetName(sslContext.SslContext, sslAuthenticationOptions.TargetHost);
                    }

                    if (sslAuthenticationOptions.CertificateContext == null && sslAuthenticationOptions.CertSelectionDelegate != null)
                    {
                        // certificate was not provided but there is user callback. We can break handshake if server asks for certificate
                        // and we can try to get it based on remote certificate and trusted issuers.
                        Interop.AppleCrypto.SslBreakOnCertRequested(sslContext.SslContext, true);
                    }

                    if (sslAuthenticationOptions.IsServer && sslAuthenticationOptions.RemoteCertRequired)
                    {
                        Interop.AppleCrypto.SslSetAcceptClientCert(sslContext.SslContext);
                    }
                }

                if (inputBuffer.Length > 0)
                {
                    sslContext !.Write(inputBuffer);
                }

                SafeSslHandle     sslHandle = sslContext !.SslContext;
                SecurityStatusPal status    = PerformHandshake(sslHandle);
                if (status.ErrorCode == SecurityStatusPalErrorCode.CredentialsNeeded)
                {
                    X509Certificate2?clientCertificate = secureChannel.SelectClientCertificate(out _);
                    if (clientCertificate != null)
                    {
                        sslAuthenticationOptions.CertificateContext = SslStreamCertificateContext.Create(clientCertificate);
                        SafeDeleteSslContext.SetCertificate(sslContext.SslContext, sslAuthenticationOptions.CertificateContext);
                    }

                    // We either got certificate or we can proceed without it. It is up to the server to decide if either is OK.
                    status = PerformHandshake(sslHandle);
                }

                outputBuffer = sslContext.ReadPendingWrites();
                return(status);
            }
            catch (Exception exc)
            {
                return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, exc));
            }
        }