示例#1
0
        public async Task <SocksProxyUdpAssociateHandler> UdpAssociateAsync(EndPoint localEP)
        {
            //bind local ep
            Socket udpSocket = new Socket(localEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

            udpSocket.Bind(localEP);

            //connect to proxy server
            Socket socket = await GetTcpConnectionAsync(_proxyEP);

            try
            {
                Stream stream = new WriteBufferedStream(new NetworkStream(socket));

                await AuthenticateAsync(stream);

                EndPoint relayEP = await RequestAsync(stream, new SocksProxyRequest(SocksProxyRequestCommand.UdpAssociate, udpSocket.LocalEndPoint));

                return(new SocksProxyUdpAssociateHandler(socket, udpSocket, relayEP));
            }
            catch
            {
                if (socket != null)
                {
                    socket.Dispose();
                }

                if (udpSocket != null)
                {
                    udpSocket.Dispose();
                }

                throw;
            }
        }
        private Stream GetConnection()
        {
            lock (_getConnectionLock)
            {
                Stream tcpStream = _tcpStream;

                if (tcpStream != null)
                {
                    return(tcpStream);
                }

                Socket socket;

                if (_proxy == null)
                {
                    if (_server.IPEndPoint == null)
                    {
                        _server.RecursiveResolveIPAddress(new SimpleDnsCache());
                    }

                    socket = new Socket(_server.IPEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                    IAsyncResult result = socket.BeginConnect(_server.IPEndPoint, null, null);
                    if (!result.AsyncWaitHandle.WaitOne(_timeout))
                    {
                        throw new SocketException((int)SocketError.TimedOut);
                    }

                    if (!socket.Connected)
                    {
                        throw new SocketException((int)SocketError.ConnectionRefused);
                    }
                }
                else
                {
                    socket = _proxy.Connect(_server.EndPoint, _timeout);
                }

                socket.SendTimeout       = _timeout;
                socket.ReceiveTimeout    = SOCKET_RECEIVE_TIMEOUT;
                socket.SendBufferSize    = 512;
                socket.ReceiveBufferSize = 2048;
                socket.NoDelay           = true;

                tcpStream  = new WriteBufferedStream(GetNetworkStream(socket), 2048);
                _tcpStream = tcpStream;

                _readThread = new Thread(ReadDnsDatagramAsync);
                _readThread.IsBackground = true;
                _readThread.Start();

                return(tcpStream);
            }
        }
示例#3
0
        protected override async Task <Socket> ConnectAsync(EndPoint remoteEP, Socket viaSocket)
        {
            try
            {
                Stream stream = new WriteBufferedStream(new NetworkStream(viaSocket));

                await AuthenticateAsync(stream);
                await RequestAsync(stream, new SocksProxyRequest(SocksProxyRequestCommand.Connect, remoteEP));

                return(viaSocket);
            }
            catch
            {
                viaSocket.Dispose();
                throw;
            }
        }
示例#4
0
            private void AcceptTcpConnectionAsync(object parameter)
            {
                try
                {
                    while (true)
                    {
                        Socket socket = _tcpListener.Accept();

                        socket.NoDelay        = true;
                        socket.SendTimeout    = SOCKET_SEND_TIMEOUT;
                        socket.ReceiveTimeout = SOCKET_RECV_TIMEOUT;

                        ThreadPool.QueueUserWorkItem(delegate(object state)
                        {
                            try
                            {
                                using (Stream s = new WriteBufferedStream(new NetworkStream(socket, true), WRITE_BUFFERED_STREAM_SIZE))
                                {
                                    IPEndPoint remoteNodeEP = socket.RemoteEndPoint as IPEndPoint;

                                    if (remoteNodeEP.Address.IsIPv4MappedToIPv6)
                                    {
                                        remoteNodeEP = new IPEndPoint(remoteNodeEP.Address.MapToIPv4(), remoteNodeEP.Port);
                                    }

                                    _dhtNode.AcceptConnection(s, remoteNodeEP);
                                }
                            }
                            catch (Exception ex)
                            {
                                Debug.Write(this.GetType().Name, ex);

                                socket.Dispose();
                            }
                        });
                    }
                }
                catch (ThreadAbortException)
                {
                    //stopping
                }
                catch (Exception ex)
                {
                    Debug.Write(this.GetType().Name, ex);
                }
            }
示例#5
0
        public async Task <SocksProxyBindHandler> BindAsync(AddressFamily family = AddressFamily.InterNetwork)
        {
            EndPoint endPoint;

            switch (family)
            {
            case AddressFamily.InterNetwork:
                endPoint = new IPEndPoint(IPAddress.Any, 0);
                break;

            case AddressFamily.InterNetworkV6:
                endPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
                break;

            default:
                throw new NotSupportedException("Address family not supported.");
            }

            //connect to proxy server
            Socket socket = await GetTcpConnectionAsync(_proxyEP);

            try
            {
                Stream stream = new WriteBufferedStream(new NetworkStream(socket));

                await AuthenticateAsync(stream);

                EndPoint bindEP = await RequestAsync(stream, new SocksProxyRequest(SocksProxyRequestCommand.Bind, endPoint));

                return(new SocksProxyBindHandler(socket, bindEP));
            }
            catch
            {
                socket.Dispose();
                throw;
            }
        }
示例#6
0
            public async Task StartAsync()
            {
                bool dontDispose = false;

                try
                {
                    NetworkStream localNetworkStream = new NetworkStream(_localSocket);
                    Stream        localStream        = new WriteBufferedStream(localNetworkStream, 512);

                    #region authenticate

                    SocksProxyNegotiationRequest negotiationRequest = await SocksProxyNegotiationRequest.ReadRequestAsync(localStream).WithTimeout(CLIENT_WAIT_TIMEOUT);

                    if (!negotiationRequest.IsVersionSupported)
                    {
                        await new SocksProxyNegotiationReply(SocksProxyAuthenticationMethod.NoAcceptableMethods).WriteToAsync(localStream);
                        await localStream.FlushAsync();

                        return;
                    }

                    //match method and authenticate
                    bool methodMatched = false;
                    SocksProxyAuthenticationMethod serverMethod = _authenticationManager == null ? SocksProxyAuthenticationMethod.NoAuthenticationRequired : SocksProxyAuthenticationMethod.UsernamePassword;

                    foreach (SocksProxyAuthenticationMethod method in negotiationRequest.Methods)
                    {
                        if (method == serverMethod)
                        {
                            //method matches
                            await new SocksProxyNegotiationReply(method).WriteToAsync(localStream);
                            await localStream.FlushAsync();

                            switch (serverMethod)
                            {
                            case SocksProxyAuthenticationMethod.NoAuthenticationRequired:
                                methodMatched = true;
                                break;

                            case SocksProxyAuthenticationMethod.UsernamePassword:
                                //read method version

                                SocksProxyAuthenticationRequest authenticationRequest = await SocksProxyAuthenticationRequest.ReadRequestAsync(localStream).WithTimeout(CLIENT_WAIT_TIMEOUT);

                                if (!authenticationRequest.IsVersionSupported)
                                {
                                    await new SocksProxyAuthenticationReply(SocksProxyAuthenticationStatus.Failure).WriteToAsync(localStream);
                                    await localStream.FlushAsync();

                                    return;
                                }

                                if (!_authenticationManager.Authenticate(authenticationRequest.Username, authenticationRequest.Password))
                                {
                                    await new SocksProxyAuthenticationReply(SocksProxyAuthenticationStatus.Failure).WriteToAsync(localStream);
                                    await localStream.FlushAsync();

                                    return;
                                }

                                await new SocksProxyAuthenticationReply(SocksProxyAuthenticationStatus.Success).WriteToAsync(localStream);
                                await localStream.FlushAsync();

                                methodMatched = true;
                                break;
                            }

                            break;
                        }
                    }

                    if (!methodMatched)
                    {
                        //no method matched
                        await new SocksProxyNegotiationReply(SocksProxyAuthenticationMethod.NoAcceptableMethods).WriteToAsync(localStream);
                        await localStream.FlushAsync();

                        return;
                    }

                    #endregion

                    #region process request

                    //read request
                    SocksProxyRequest request = await SocksProxyRequest.ReadRequestAsync(localStream).WithTimeout(CLIENT_WAIT_TIMEOUT);

                    if (!request.IsVersionSupported)
                    {
                        await new SocksProxyReply(SocksProxyReplyCode.GeneralSocksServerFailure).WriteToAsync(localStream);
                        await localStream.FlushAsync();

                        return;
                    }

                    //process command
                    SocksProxyReplyCode reply;
                    EndPoint            bindEP;

                    switch (request.Command)
                    {
                    case SocksProxyRequestCommand.Connect:
                    {
                        try
                        {
                            _remoteSocket = await _connectionManager.ConnectAsync(request.DestinationEndPoint);

                            reply  = SocksProxyReplyCode.Succeeded;
                            bindEP = _remoteSocket.LocalEndPoint;
                        }
                        catch (SocketException ex)
                        {
                            switch (ex.SocketErrorCode)
                            {
                            case SocketError.NetworkUnreachable:
                                reply = SocksProxyReplyCode.NetworkUnreachable;
                                break;

                            case SocketError.HostUnreachable:
                                reply = SocksProxyReplyCode.HostUnreachable;
                                break;

                            case SocketError.ConnectionRefused:
                                reply = SocksProxyReplyCode.ConnectionRefused;
                                break;

                            default:
                                reply = SocksProxyReplyCode.GeneralSocksServerFailure;
                                break;
                            }

                            bindEP = new IPEndPoint(IPAddress.Any, 0);
                        }
                    }
                    break;

                    case SocksProxyRequestCommand.Bind:
                    {
                        _bindHandler = await _connectionManager.GetBindHandlerAsync(request.DestinationEndPoint.AddressFamily);

                        reply  = _bindHandler.ReplyCode;
                        bindEP = _bindHandler.ProxyLocalEndPoint;
                    }
                    break;

                    case SocksProxyRequestCommand.UdpAssociate:
                    {
                        switch (_localSocket.LocalEndPoint.AddressFamily)
                        {
                        case AddressFamily.InterNetwork:
                        case AddressFamily.InterNetworkV6:
                            EndPoint localEP = new IPEndPoint((_localSocket.LocalEndPoint as IPEndPoint).Address, 0);

                            _udpRelaySocket = new Socket(localEP.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                            _udpRelaySocket.Bind(localEP);

                            reply  = SocksProxyReplyCode.Succeeded;
                            bindEP = _udpRelaySocket.LocalEndPoint as IPEndPoint;
                            break;

                        default:
                            reply  = SocksProxyReplyCode.AddressTypeNotSupported;
                            bindEP = new IPEndPoint(IPAddress.Any, 0);
                            break;
                        }
                    }
                    break;

                    default:
                        reply  = SocksProxyReplyCode.CommandNotSupported;
                        bindEP = new IPEndPoint(IPAddress.Any, 0);
                        break;
                    }

                    //send response
                    await new SocksProxyReply(reply, bindEP).WriteToAsync(localStream);
                    await localStream.FlushAsync();

                    if (reply != SocksProxyReplyCode.Succeeded)
                    {
                        return; //nothing to do further
                    }
                    //final command process
                    switch (request.Command)
                    {
                    case SocksProxyRequestCommand.Connect:
                    {
                        //pipe sockets
                        _           = _localSocket.CopyToAsync(_remoteSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                        _           = _remoteSocket.CopyToAsync(_localSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                        dontDispose = true;
                    }
                    break;

                    case SocksProxyRequestCommand.Bind:
                    {
                        try
                        {
                            _remoteSocket = await _bindHandler.AcceptAsync().WithTimeout(CLIENT_WAIT_TIMEOUT);
                        }
                        catch (SocksProxyException ex)
                        {
                            //send second reply
                            await new SocksProxyReply(ex.ReplyCode, _bindHandler.ProxyLocalEndPoint).WriteToAsync(localStream);
                            await localStream.FlushAsync();
                        }
                        catch
                        {
                            //send second reply
                            await new SocksProxyReply(SocksProxyReplyCode.GeneralSocksServerFailure, _bindHandler.ProxyLocalEndPoint).WriteToAsync(localStream);
                            await localStream.FlushAsync();
                        }

                        if (_remoteSocket != null)
                        {
                            _bindHandler.Dispose();

                            //send second reply
                            await new SocksProxyReply(SocksProxyReplyCode.Succeeded, _bindHandler.ProxyRemoteEndPoint).WriteToAsync(localStream);
                            await localStream.FlushAsync();

                            //pipe sockets
                            _           = _localSocket.CopyToAsync(_remoteSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                            _           = _remoteSocket.CopyToAsync(_localSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                            dontDispose = true;
                        }
                    }
                    break;

                    case SocksProxyRequestCommand.UdpAssociate:
                    {
                        EndPoint localEP = null;

                        switch (_localSocket.LocalEndPoint.AddressFamily)
                        {
                        case AddressFamily.InterNetwork:
                            localEP = new IPEndPoint(IPAddress.Any, 0);
                            break;

                        case AddressFamily.InterNetworkV6:
                            localEP = new IPEndPoint(IPAddress.IPv6Any, 0);
                            break;

                        default:
                            throw new NotSupportedException();
                        }

                        using (IProxyServerUdpAssociateHandler udpRemoteHandler = await _connectionManager.GetUdpAssociateHandlerAsync(localEP))
                        {
                            using (IProxyServerUdpAssociateHandler udpLocalHandler = new SocksProxyUdpAssociateHandler(_localSocket, _udpRelaySocket, new IPEndPoint((_localSocket.RemoteEndPoint as IPEndPoint).Address, (request.DestinationEndPoint as IPEndPoint).Port)))
                            {
                                _ = CopyToAsync(udpRemoteHandler, udpLocalHandler);
                                await CopyToAsync(udpLocalHandler, udpRemoteHandler);
                            }
                        }
                    }
                    break;
                    }

                    #endregion
                }
                finally
                {
                    if (!dontDispose)
                    {
                        Dispose();
                    }
                }
            }
示例#7
0
        private void Start(Stream stream)
        {
            try
            {
                WriteBufferedStream bufferedStream;

                if (!(stream is WriteBufferedStream))
                {
                    bufferedStream = new WriteBufferedStream(stream, 8 * 1024);
                }
                else
                {
                    bufferedStream = stream as WriteBufferedStream;
                }

                //read client hello
                SecureChannelHandshakeHello clientHello = new SecureChannelHandshakeHello(bufferedStream);

                switch (clientHello.Version)
                {
                case 1:
                    ProtocolV1(bufferedStream, clientHello);
                    break;

                default:
                    throw new SecureChannelException(SecureChannelCode.ProtocolVersionNotSupported, _remotePeerEP, _remotePeerUserId, "SecureChannel protocol version not supported: " + clientHello.Version);
                }
            }
            catch (SecureChannelException ex)
            {
                if (ex.Code == SecureChannelCode.RemoteError)
                {
                    throw new SecureChannelException(ex.Code, _remotePeerEP, _remotePeerUserId, ex.Message, ex);
                }
                else
                {
                    try
                    {
                        Stream s;

                        if (_baseStream == null)
                        {
                            s = stream;
                        }
                        else
                        {
                            s = this;
                        }

                        new SecureChannelHandshakePacket(ex.Code).WriteTo(s);
                        s.Flush();
                    }
                    catch
                    { }

                    if (ex.PeerEP == null)
                    {
                        throw new SecureChannelException(ex.Code, _remotePeerEP, _remotePeerUserId, ex.Message, ex);
                    }

                    throw;
                }
            }
            catch (IOException)
            {
                throw;
            }
            catch
            {
                try
                {
                    Stream s;

                    if (_baseStream == null)
                    {
                        s = stream;
                    }
                    else
                    {
                        s = this;
                    }

                    new SecureChannelHandshakePacket(SecureChannelCode.UnknownException).WriteTo(s);
                    s.Flush();
                }
                catch
                { }

                throw;
            }
        }
示例#8
0
        private void ProtocolV1(WriteBufferedStream bufferedStream, SecureChannelHandshakeHello clientHello)
        {
            #region 1. hello handshake check

            //select crypto option
            SecureChannelCipherSuite availableCiphers = _supportedCiphers & clientHello.SupportedCiphers;

            if (availableCiphers == SecureChannelCipherSuite.None)
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }
            else if (availableCiphers.HasFlag(SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256))
            {
                _selectedCipher = SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256;
            }
            else if (availableCiphers.HasFlag(SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256))
            {
                _selectedCipher = SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256;
            }
            else
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //match options
            if (_options != clientHello.Options)
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingOptionsAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //write server hello
            SecureChannelHandshakeHello serverHello = new SecureChannelHandshakeHello(_selectedCipher, _options);
            serverHello.WriteTo(bufferedStream);

            #endregion

            #region 2. key exchange

            KeyAgreement keyAgreement;

            switch (_selectedCipher)
            {
            case SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256:
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
                keyAgreement = new DiffieHellman(DiffieHellmanGroupType.RFC3526_GROUP14_2048BIT, KeyAgreementKeyDerivationFunction.Hmac, KeyAgreementKeyDerivationHashAlgorithm.SHA256);
                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            //send server key exchange data
            SecureChannelHandshakeKeyExchange serverKeyExchange = new SecureChannelHandshakeKeyExchange(keyAgreement, serverHello, clientHello, _preSharedKey);
            serverKeyExchange.WriteTo(bufferedStream);
            bufferedStream.Flush();

            //read client key exchange data
            SecureChannelHandshakeKeyExchange clientKeyExchange = new SecureChannelHandshakeKeyExchange(bufferedStream);

            if (_options.HasFlag(SecureChannelOptions.PRE_SHARED_KEY_AUTHENTICATION_REQUIRED))
            {
                if (!clientKeyExchange.IsPskAuthValid(serverHello, clientHello, _preSharedKey))
                {
                    throw new SecureChannelException(SecureChannelCode.PskAuthenticationFailed, _remotePeerEP, _remotePeerUserId);
                }
            }

            #endregion

            #region 3. enable encryption

            EnableEncryption(bufferedStream, serverHello, clientHello, keyAgreement, clientKeyExchange);

            #endregion

            #region 4. UserId based authentication

            switch (_selectedCipher)
            {
            case SecureChannelCipherSuite.DHE2048_RSA2048_WITH_AES256_CBC_HMAC_SHA256:
                if (_options.HasFlag(SecureChannelOptions.CLIENT_AUTHENTICATION_REQUIRED))
                {
                    //read client auth
                    SecureChannelHandshakeAuthentication clientAuth = new SecureChannelHandshakeAuthentication(this);
                    _remotePeerUserId = clientAuth.UserId;

                    //authenticate client
                    if (!clientAuth.IsSignatureValid(clientKeyExchange, serverHello, clientHello))
                    {
                        throw new SecureChannelException(SecureChannelCode.PeerAuthenticationFailed, _remotePeerEP, _remotePeerUserId);
                    }

                    //check if client is trusted
                    if (!clientAuth.IsTrustedUserId(_trustedUserIds))
                    {
                        throw new SecureChannelException(SecureChannelCode.UntrustedRemotePeerUserId, _remotePeerEP, _remotePeerUserId);
                    }
                }

                //write server auth
                new SecureChannelHandshakeAuthentication(serverKeyExchange, serverHello, clientHello, _userId, _privateKey).WriteTo(this);
                this.Flush();
                break;

            case SecureChannelCipherSuite.DHE2048_ANON_WITH_AES256_CBC_HMAC_SHA256:
                break;     //no auth for ANON

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCipherAvailable, _remotePeerEP, _remotePeerUserId);
            }

            #endregion
        }
示例#9
0
        private void ProtocolV4(Stream stream)
        {
            WriteBufferedStream bufferedStream = new WriteBufferedStream(stream, 8 * 1024);

            #region 1. hello handshake

            //read client hello
            SecureChannelHandshakeHello clientHello = new SecureChannelHandshakeHello(bufferedStream);

            //select crypto option
            _selectedCryptoOption = _supportedOptions & clientHello.CryptoOptions;

            if (_selectedCryptoOption == SecureChannelCryptoOptionFlags.None)
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert);
            }
            else if ((_selectedCryptoOption & SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256) > 0)
            {
                _selectedCryptoOption = SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256;
            }
            else if ((_selectedCryptoOption & SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256) > 0)
            {
                _selectedCryptoOption = SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256;
            }
            else
            {
                throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert);
            }

            //send server hello
            SecureChannelHandshakeHello serverHello = new SecureChannelHandshakeHello(BinaryNumber.GenerateRandomNumber256(), _selectedCryptoOption);
            serverHello.WriteTo(bufferedStream);

            #endregion

            #region 2. key exchange

            SymmetricEncryptionAlgorithm encAlgo;
            string       hashAlgo;
            KeyAgreement keyAgreement;

            switch (_selectedCryptoOption)
            {
            case SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256:
                encAlgo      = SymmetricEncryptionAlgorithm.Rijndael;
                hashAlgo     = "SHA256";
                keyAgreement = new DiffieHellman(DiffieHellmanGroupType.RFC3526, 2048, KeyAgreementKeyDerivationFunction.Hmac, KeyAgreementKeyDerivationHashAlgorithm.SHA256);
                break;

            case SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256:
                encAlgo      = SymmetricEncryptionAlgorithm.Rijndael;
                hashAlgo     = "SHA256";
                keyAgreement = new TechnitiumLibrary.Security.Cryptography.ECDiffieHellman(256, KeyAgreementKeyDerivationFunction.Hmac, KeyAgreementKeyDerivationHashAlgorithm.SHA256);
                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert);
            }

            //send server key exchange data
            new SecureChannelHandshakeKeyExchange(keyAgreement.GetPublicKey(), _serverCredentials.PrivateKey, hashAlgo).WriteTo(bufferedStream);
            bufferedStream.Flush();

            //read client key exchange data
            SecureChannelHandshakeKeyExchange clientKeyExchange = new SecureChannelHandshakeKeyExchange(bufferedStream);

            //generate master key
            byte[] masterKey = GenerateMasterKey(clientHello, serverHello, _preSharedKey, keyAgreement, clientKeyExchange.PublicKey);

            //verify master key using HMAC authentication
            {
                SecureChannelHandshakeAuthentication clientAuthentication = new SecureChannelHandshakeAuthentication(bufferedStream);
                if (!clientAuthentication.IsValid(serverHello, masterKey))
                {
                    throw new SecureChannelException(SecureChannelCode.ProtocolAuthenticationFailed, _remotePeerEP, _remotePeerCert);
                }

                SecureChannelHandshakeAuthentication serverAuthentication = new SecureChannelHandshakeAuthentication(clientHello, masterKey);
                serverAuthentication.WriteTo(bufferedStream);
                bufferedStream.Flush();
            }

            //enable channel encryption
            switch (encAlgo)
            {
            case SymmetricEncryptionAlgorithm.Rijndael:
                //using MD5 for generating AES IV of 128bit block size
                HashAlgorithm md5Hash = HashAlgorithm.Create("MD5");
                byte[]        eIV     = md5Hash.ComputeHash(serverHello.Nonce.Number);
                byte[]        dIV     = md5Hash.ComputeHash(clientHello.Nonce.Number);

                //create encryption and decryption objects
                SymmetricCryptoKey encryptionKey = new SymmetricCryptoKey(SymmetricEncryptionAlgorithm.Rijndael, masterKey, eIV, PaddingMode.None);
                SymmetricCryptoKey decryptionKey = new SymmetricCryptoKey(SymmetricEncryptionAlgorithm.Rijndael, masterKey, dIV, PaddingMode.None);

                //enable encryption
                EnableEncryption(stream, encryptionKey, decryptionKey, new HMACSHA256(masterKey), new HMACSHA256(masterKey));
                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert);
            }

            //channel encryption is ON!

            #endregion

            #region 3. exchange & verify certificates & signatures

            if (!IsReNegotiating())
            {
                //read client certificate
                _remotePeerCert = new SecureChannelHandshakeCertificate(this).Certificate;

                //verify client certificate
                try
                {
                    _remotePeerCert.Verify(_trustedRootCertificates);
                }
                catch (Exception ex)
                {
                    throw new SecureChannelException(SecureChannelCode.InvalidRemoteCertificate, _remotePeerEP, _remotePeerCert, "Invalid remote certificate.", ex);
                }
            }

            //verify key exchange signature
            switch (_selectedCryptoOption)
            {
            case SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256:
            case SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256:
                if (_remotePeerCert.PublicKeyEncryptionAlgorithm != AsymmetricEncryptionAlgorithm.RSA)
                {
                    throw new SecureChannelException(SecureChannelCode.InvalidRemoteCertificateAlgorithm, _remotePeerEP, _remotePeerCert);
                }

                if (!clientKeyExchange.IsSignatureValid(_remotePeerCert, "SHA256"))
                {
                    throw new SecureChannelException(SecureChannelCode.InvalidRemoteKeyExchangeSignature, _remotePeerEP, _remotePeerCert);
                }

                break;

            default:
                throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert);
            }

            if ((_manager != null) && !_manager.ProceedConnection(_remotePeerCert))
            {
                throw new SecureChannelException(SecureChannelCode.SecurityManagerDeclinedAccess, _remotePeerEP, _remotePeerCert, "Security manager declined access.");
            }

            //send server certificate
            if (!IsReNegotiating())
            {
                new SecureChannelHandshakeCertificate(_serverCredentials.Certificate).WriteTo(this);
                this.Flush();
            }

            #endregion
        }
示例#10
0
            public async Task StartAsync()
            {
                bool dontDispose = false;

                try
                {
                    NetworkStream localStream  = new NetworkStream(_localSocket);
                    Stream        remoteStream = null;

                    string lastHost = null;
                    int    lastPort = 0;

                    while (true)
                    {
                        HttpRequest httpRequest;
                        {
                            Task <HttpRequest> task = HttpRequest.ReadRequestAsync(localStream);

                            using (CancellationTokenSource timeoutCancellationTokenSource = new CancellationTokenSource())
                            {
                                if (await Task.WhenAny(task, Task.Delay(CLIENT_REQUEST_TIMEOUT, timeoutCancellationTokenSource.Token)) != task)
                                {
                                    return;                              //request timed out
                                }
                                timeoutCancellationTokenSource.Cancel(); //cancel delay task
                            }

                            httpRequest = await task;
                        }

                        if (httpRequest == null)
                        {
                            return; //connection closed gracefully by client
                        }
                        if (_authenticationManager != null)
                        {
                            string proxyAuth = httpRequest.Headers[HttpRequestHeader.ProxyAuthorization];
                            if (string.IsNullOrEmpty(proxyAuth))
                            {
                                await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1>");

                                return;
                            }

                            string username;
                            string password;
                            {
                                string[] parts = proxyAuth.Split(new char[] { ' ' }, 2);

                                if (!parts[0].Equals("BASIC", StringComparison.OrdinalIgnoreCase) || (parts.Length < 2))
                                {
                                    await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1><p>Proxy authentication method is not supported.</p>");

                                    return;
                                }

                                string[] credParts = Encoding.ASCII.GetString(Convert.FromBase64String(parts[1])).Split(new char[] { ':' }, 2);
                                if (credParts.Length != 2)
                                {
                                    await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1><p>Proxy authentication method is not supported.</p>");

                                    return;
                                }

                                username = credParts[0];
                                password = credParts[1];
                            }

                            if (!_authenticationManager.Authenticate(username, password))
                            {
                                await SendResponseAsync(407, "<h1>Proxy Authentication Required</h1><p>Invalid username or password.</p>");

                                return;
                            }
                        }

                        if (httpRequest.HttpMethod.Equals("CONNECT", StringComparison.OrdinalIgnoreCase))
                        {
                            await DoConnectAsync(localStream, httpRequest);

                            dontDispose = true;
                            break;
                        }
                        else
                        {
                            #region connect to remote server

                            string host;
                            int    port;
                            string requestPathAndQuery;

                            if (Uri.TryCreate(httpRequest.RequestPathAndQuery, UriKind.Absolute, out Uri requestUri))
                            {
                                host = requestUri.Host;
                                port = requestUri.Port;
                                requestPathAndQuery = requestUri.PathAndQuery;
                            }
                            else
                            {
                                string hostHeader = httpRequest.Headers[HttpRequestHeader.Host];
                                if (string.IsNullOrEmpty(hostHeader))
                                {
                                    throw new HttpProxyServerException("Invalid proxy request.");
                                }

                                string[] parts = hostHeader.Split(':');

                                host = parts[0];

                                if (parts.Length > 1)
                                {
                                    port = int.Parse(parts[1]);
                                }
                                else
                                {
                                    port = 80;
                                }

                                requestPathAndQuery = httpRequest.RequestPathAndQuery;
                            }

                            if (!host.Equals(lastHost) || port != lastPort || !_remoteSocket.Connected)
                            {
                                if (_remoteSocket != null)
                                {
                                    if (_remoteSocket.Connected)
                                    {
                                        try
                                        {
                                            _remoteSocket.Shutdown(SocketShutdown.Both);
                                        }
                                        catch
                                        { }
                                    }

                                    _remoteSocket.Dispose();
                                }

                                _remoteSocket = await _connectionManager.ConnectAsync(EndPointExtension.GetEndPoint(host, port));

                                remoteStream = new WriteBufferedStream(new NetworkStream(_remoteSocket), 512);

                                lastHost = host;
                                lastPort = port;

                                //pipe response stream
                                _ = _remoteSocket.CopyToAsync(_localSocket).ContinueWith(delegate(Task prevTask) { Dispose(); });
                            }

                            #endregion

                            #region relay client request to server

                            foreach (string header in httpRequest.Headers.AllKeys)
                            {
                                if (header.StartsWith("Proxy-", StringComparison.OrdinalIgnoreCase))
                                {
                                    httpRequest.Headers.Remove(header);
                                }
                            }

                            await remoteStream.WriteAsync(Encoding.ASCII.GetBytes(httpRequest.HttpMethod + " " + requestPathAndQuery + " " + httpRequest.Protocol + "\r\n"));

                            await remoteStream.WriteAsync(httpRequest.Headers.ToByteArray());

                            if (httpRequest.InputStream != null)
                            {
                                await httpRequest.InputStream.CopyToAsync(remoteStream);
                            }

                            await remoteStream.FlushAsync();

                            #endregion
                        }
                    }
                }
                catch (Exception ex)
                {
                    await SendResponseAsync(ex);
                }
                finally
                {
                    if (!dontDispose)
                    {
                        Dispose();
                    }
                }
            }