//This is called when requests are routed through router to this endpoint //For ssl requests private static void HandleClient(TransparentProxyEndPoint endPoint, TcpClient tcpClient) { Stream clientStream = tcpClient.GetStream(); CustomBinaryReader clientStreamReader = null; StreamWriter clientStreamWriter = null; X509Certificate2 certificate = null; if (endPoint.EnableSsl) { var sslStream = new SslStream(clientStream, true); //if(endPoint.UseServerNameIndication) //{ // //implement in future once SNI supported by SSL stream // certificate = CertManager.CreateCertificate(endPoint.GenericCertificateName); //} //else certificate = CertManager.CreateCertificate(endPoint.GenericCertificateName); try { //Successfully managed to authenticate the client using the fake certificate sslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls, false); clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII); clientStreamWriter = new StreamWriter(sslStream); //HTTPS server created - we can now decrypt the client's traffic } catch (Exception) { if (sslStream != null) sslStream.Dispose(); Dispose(tcpClient, sslStream, clientStreamReader, clientStreamWriter, null); return; } clientStream = sslStream; } else { clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII); } var httpCmd = clientStreamReader.ReadLine(); //Now create the request HandleHttpSessionRequest(tcpClient, httpCmd, clientStream, clientStreamReader, clientStreamWriter, true); }
/// <summary> /// Begin the secure negotiation and server authentication. /// </summary> /// <exception cref="System.Exception"></exception> /// <exception cref="System.Security.Authentication.AuthenticationException"></exception> public virtual void BeginSslNegotiation() { if (!_isSslAuthenticated && _useSslConnection && _networkStream == null) { // Block the socket for now. _socket.Blocking = true; // Initialy assign the network stream _networkStream = new NetworkStream(_socket); } try { // If not authenticated. if (!_isSslAuthenticated) { // If ssl certificate has not been assigned. if (_x509Certificate == null) { throw new Exception("Please add an SSL certificate for secure connections."); } // Get the current ssl stream // from the socket. _sslStream = new SslStream(_networkStream); // Load the certificate into the // secure stream used for secure communication. _sslStream.AuthenticateAsServer(_x509Certificate, false, _sslProtocols, false); // Get the state of the authentication. if (_sslStream.IsAuthenticated && _sslStream.IsEncrypted) { _isSslAuthenticated = true; } else { _isSslAuthenticated = false; } } } catch (System.Security.Authentication.AuthenticationException) { if (_sslStream != null) { _sslStream.Dispose(); } throw; } }
public async Task<Stream> ConnectAsync(string host, int port, X509Certificate clientCert, CancellationToken cancel) { Stream lowerStream = null; SslStream sslStream = null; X509CertificateCollection certCollection = null;; if (clientCert != null) { certCollection = new X509CertificateCollection(new[] { clientCert }); } try { lowerStream = await _connectionResolver.ConnectAsync(host, port, cancel); sslStream = new SslStream(lowerStream); await sslStream.AuthenticateAsClientAsync(host, certCollection, _protocols, checkCertificateRevocation: true); return sslStream; } catch (Exception) { if (sslStream != null) { sslStream.Dispose(); } if (lowerStream != null) { lowerStream.Dispose(); } throw; } }
private static TcpConnection CreateClient(string Hostname, int port, bool IsSecure) { var client = new TcpClient(Hostname, port); var stream = (Stream)client.GetStream(); if (IsSecure) { var sslStream = (SslStream)null; try { sslStream = new SslStream(stream); sslStream.AuthenticateAsClient(Hostname); stream = (Stream)sslStream; } catch { if (sslStream != null) sslStream.Dispose(); throw; } } return new TcpConnection() { HostName = Hostname, port = port, IsSecure = IsSecure, TcpClient = client, ServerStreamReader = new CustomBinaryReader(stream, Encoding.ASCII), Stream = stream }; }
private bool TryConnectSsl(Stream stream, out SslStream ssl) { ssl = new SslStream(stream, false, UserCertificateValidationCallback, UserCertificateSelectionCallback, EncryptionPolicy.RequireEncryption); try { ssl.AuthenticateAsClient("Local", null, SslProtocols.Tls12, false); } catch (Exception ex) { Log.Publish(MessageLevel.Info, "Authentication Failed", null, null, ex); ssl.Dispose(); ssl = null; return false; } return true; }
/// <summary> /// Establish a connection to the specified SMTP or SMTP/S server using the provided socket. /// </summary> /// <remarks> /// <para>Establishes a connection to the specified SMTP or SMTP/S server.</para> /// <para>If the <paramref name="port"/> has a value of <c>0</c>, then the /// <paramref name="options"/> parameter is used to determine the default port to /// connect to. The default port used with <see cref="SecureSocketOptions.SslOnConnect"/> /// is <c>465</c>. All other values will use a default port of <c>25</c>.</para> /// <para>If the <paramref name="options"/> has a value of /// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used /// to determine the default security options. If the <paramref name="port"/> has a value /// of <c>465</c>, then the default options used will be /// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use /// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para> /// <para>Once a connection is established, properties such as /// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be /// populated.</para> /// <note type="note">The connection established by any of the /// <a href="Overload_MailKit_Net_Smtp_SmtpClient_Connect.htm">Connect</a> /// methods may be re-used if an application wishes to send multiple messages /// to the same SMTP server. Since connecting and authenticating can be expensive /// operations, re-using a connection can significantly improve performance when /// sending a large number of messages to the same SMTP server over a short /// period of time./</note> /// </remarks> /// <param name="socket">The socket to use for the connection.</param> /// <param name="host">The host name to connect to.</param> /// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param> /// <param name="options">The secure socket options to when connecting.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="socket"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="host"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>. /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="socket"/> is not connected.</para> /// <para>-or-</para> /// The <paramref name="host"/> is a zero-length string. /// </exception> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="SmtpClient"/> has been disposed. /// </exception> /// <exception cref="System.InvalidOperationException"> /// The <see cref="SmtpClient"/> is already connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// <paramref name="options"/> was set to /// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/> /// and the SMTP server does not support the STARTTLS extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="SmtpCommandException"> /// An SMTP command failed. /// </exception> /// <exception cref="SmtpProtocolException"> /// An SMTP protocol error occurred. /// </exception> public void Connect (Socket socket, string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { if (socket == null) throw new ArgumentNullException (nameof (socket)); if (!socket.Connected) throw new ArgumentException ("The socket is not connected.", nameof (socket)); if (host == null) throw new ArgumentNullException (nameof (host)); if (host.Length == 0) throw new ArgumentException ("The host name cannot be empty.", nameof (host)); if (port < 0 || port > 65535) throw new ArgumentOutOfRangeException (nameof (port)); CheckDisposed (); if (IsConnected) throw new InvalidOperationException ("The SmtpClient is already connected."); capabilities = SmtpCapabilities.None; AuthenticationMechanisms.Clear (); MaxSize = 0; SmtpResponse response; Stream stream; bool starttls; Uri uri; ComputeDefaultValues (host, ref port, ref options, out uri, out starttls); this.host = host; if (options == SecureSocketOptions.SslOnConnect) { var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate); try { #if COREFX ssl.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else ssl.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif } catch { ssl.Dispose (); throw; } secure = true; stream = ssl; } else { stream = new NetworkStream (socket, true); secure = false; } if (stream.CanTimeout) { stream.WriteTimeout = timeout; stream.ReadTimeout = timeout; } ProtocolLogger.LogConnect (uri); Stream = new SmtpStream (stream, socket, ProtocolLogger); try { // read the greeting response = Stream.ReadResponse (cancellationToken); if (response.StatusCode != SmtpStatusCode.ServiceReady) throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); // Send EHLO and get a list of supported extensions Ehlo (cancellationToken); if (options == SecureSocketOptions.StartTls && (capabilities & SmtpCapabilities.StartTLS) == 0) throw new NotSupportedException ("The SMTP server does not support the STARTTLS extension."); if (starttls && (capabilities & SmtpCapabilities.StartTLS) != 0) { response = SendCommand ("STARTTLS", cancellationToken); if (response.StatusCode != SmtpStatusCode.ServiceReady) throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); var tls = new SslStream (stream, false, ValidateRemoteCertificate); #if COREFX tls.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else tls.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif Stream.Stream = tls; secure = true; // Send EHLO again and get the new list of supported extensions Ehlo (cancellationToken); } connected = true; } catch { Stream.Dispose (); secure = false; Stream = null; throw; } OnConnected (); }
private void PopBeforeSmtp(MailParameters mailParams) { Stream stream = null; System.Net.Sockets.TcpClient popclient = null; try { string rstr; popclient = new System.Net.Sockets.TcpClient(); // POPサーバーに接続 popclient.Connect(mailParams.PopServer, mailParams.PopPort); logs.AppendLine("POP: Connected."); X509CertificateCollection clientCertificateCollection = new X509CertificateCollection(); if (mailParams.IsClientCertValidate) { var clientCertificate = Cert.GetCert(mailParams.ClientCertSerialNo); clientCertificateCollection.Add(clientCertificate); } // サーバーとデータの送受信を行うストリームを取得する // 通信開始(SSL有り) switch (mailParams.PopSecureMode) { case SecureMode.SSL2: // SSL2で運用しているサーバは存在しないはずだが、一応対応しておく stream = new System.Net.Security.SslStream(popclient.GetStream(), false, ServerCertificateValidation); ((System.Net.Security.SslStream)stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Ssl2, false); logs.AppendLine("POP: socket is over SSL2."); break; case SecureMode.SSL3: // SSL3で運用しているサーバはあるかもしれない stream = new System.Net.Security.SslStream(popclient.GetStream(), false, ServerCertificateValidation); ((System.Net.Security.SslStream)stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Ssl3, false); logs.AppendLine("POP: socket is over SSL3."); break; case SecureMode.TLS: // TLSは現状では主流 case SecureMode.STARTTLS: stream = new System.Net.Security.SslStream(popclient.GetStream(), false, ServerCertificateValidation); ((System.Net.Security.SslStream)stream).AuthenticateAsClient(mailParams.SmtpServer, clientCertificateCollection, SslProtocols.Tls, false); logs.AppendLine("POP: socket is over TLS."); break; case SecureMode.None: stream = popclient.GetStream(); logs.AppendLine("POP: socket unsecure."); break; } stream.ReadTimeout = 5000; stream.WriteTimeout = 500; //サーバーからのはじめのメッセージを受信 // POPサーバー接続時のレスポンス受信 string connectstr = PopWriteAndRead(stream, ""); if (connectstr.StartsWith("+OK") != true) { throw new PopException("POPサーバー接続エラー"); } switch (mailParams.PopAuth) { case PopAuthMethod.Standard: // ユーザIDの送信 rstr = PopWriteAndRead(stream, "USER " + mailParams.PopUserId + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("ユーザIDエラー"); } // パスワードの送信 rstr = PopWriteAndRead(stream, "PASS " + mailParams.PopPasswd + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("パスワードエラー"); } break; case PopAuthMethod.APOP: // APOP用のタイムスタンプ文字列を取得しておく var timestamp = GetAPopTimeStamp(connectstr); if (string.IsNullOrWhiteSpace(timestamp)) { throw new PopException("APOP未対応"); } Byte[] byt = System.Text.Encoding.ASCII.GetBytes(string.Format("<{0}>{1}", mailParams.PopUserId, mailParams.PopPasswd)); System.Security.Cryptography.MD5CryptoServiceProvider md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); Byte[] res = md5.ComputeHash(byt); string aps = BitConverter.ToString(res).Replace("-", "").ToLower(); rstr = PopWriteAndRead(stream, "APOP " + mailParams.PopUserId + " " + aps + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("ユーザIDまたはパスワードエラー"); } break; case PopAuthMethod.NTLM: // ユーザIDの送信 rstr = PopWriteAndRead(stream, "USER " + mailParams.PopUserId + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("ユーザIDエラー"); } // パスワードの送信 rstr = PopWriteAndRead(stream, "PASS " + mailParams.PopPasswd + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("パスワードエラー"); } break; case PopAuthMethod.CramMd5: rstr = PopWriteAndRead(stream, "AUTH CRAM-MD5\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("CRAM-MD5未対応"); } rstr = PopWriteAndRead(stream, CreateCramMd5ResponseString(rstr.Substring(4), mailParams.PopUserId, mailParams.PopPasswd) + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("認証エラー"); } break; } // ステータスの送信 rstr = PopWriteAndRead(stream, "STAT" + "\r\n"); if (rstr.StartsWith("+OK") != true) { throw new PopException("STATエラー"); } // 終了の送信 rstr = PopWriteAndRead(stream, "QUIT" + "\r\n"); // 戻り値は無視 } catch (PopException ex) { throw ex; } catch (Exception ex) { throw new PopException("内部例外発生", ex); } finally { if (stream != null) { stream.Close(); stream.Dispose(); } if (popclient != null) { popclient.Close(); } } }
public bool Connect(int maxTryCount = 5) { TcpClient newTcpClient = null; SslStream newSslStream = null; int tryCount = 0; bool loggedIn = false; while (tryCount < maxTryCount && !loggedIn) { ++tryCount; bool retrying = tryCount > 1 ? true : false; if (retrying) { Debug.WriteLine("ImapClient.Connect(): Trying to connect to " + Account.ImapServerName + ":" + Account.ImapPortNumber + "..." + tryCount); if (newTcpClient != null) { newTcpClient.Close(); } if (newSslStream != null) { newSslStream.Dispose(); } Thread.Sleep(1000); } bool connected = false; try { newTcpClient = new TcpClient(); var result = newTcpClient.BeginConnect(Account.ImapServerName, Account.ImapPortNumber, null, null); var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5)); if (success && newTcpClient.Connected) { connected = true; if (retrying) { Debug.WriteLine("ImapClient.Connect(): Connection succeeded."); } } newTcpClient.EndConnect(result); } catch (Exception e) { Error = e.Message; Debug.WriteLine("ImapClient.Connect(): Exception occured while trying to connect to " + Account.ImapServerName + ":" + Account.ImapPortNumber + ".\n" + Error); newTcpClient.Close(); return false; } if (!connected) { if (tryCount < maxTryCount) { // Retry connecting. continue; } else { Error = "Unable to connect to " + Account.ImapServerName + ":" + Account.ImapPortNumber; Debug.WriteLine("ImapClient.Connect(): " + Error); newTcpClient.Close(); return false; } } // Now we're connected through TCP. Try to authenticate through SSL. try { newSslStream = new SslStream(newTcpClient.GetStream(), false); newSslStream.AuthenticateAsClient(Account.ImapServerName); } catch (Exception e) { Error = e.Message; Debug.WriteLine("ImapClient.Connect(): Exception occured while creating SSL stream to " + Account.ImapServerName + ":" + Account.ImapPortNumber + ".\n" + Error); newTcpClient.Close(); return false; } // Now we're on SSL. Try to log in. if (retrying) { Debug.WriteLine("ImapClient.Connect(): Logging in to " + Account.ImapServerName + "(" + Account.AccountName + ")."); } newSslStream.ReadTimeout = 5000; // For synchronous read calls. if (TryLogin(newSslStream)) { loggedIn = true; if (retrying) { Debug.WriteLine("ImapClient.Connect(): Login succeeded."); } } } if (!loggedIn) { // Reached max retry count. Clean up and return. Error = "Could not log in to " + Account.ImapServerName + "(" + Account.AccountName + "). Check credentials."; Debug.WriteLine("ImapClient.Connect(): " + Error); newTcpClient.Close(); newSslStream.Dispose(); return false; } this.tcpClient = newTcpClient; this.sslStream = newSslStream; return true; }
public string DonwloadTimeSheetMail() { string sUserid, sPassword; GetMailUseridAndPassword(out sUserid, out sPassword); string sTempDir = GetTempDir(); string sPrefix = GetTempFileNamePrefix(); string sLpath = sTempDir + "\\" + sPrefix + "maillog.txt"; // if (File.Exists(sLpath)) File.Delete(sLpath); string sDpath = sTempDir + "\\" + sPrefix + "mailtext.txt"; // if (File.Exists(sDpath)) File.Delete(sDpath); string sEpath = sTempDir + "\\" + sPrefix + "timesheet"; string sRes; StreamWriter strmlgw = new System.IO.StreamWriter(System.IO.File.Create(sLpath)); TcpClient tcpclnt = new System.Net.Sockets.TcpClient("imap.gmail.com", 993); SslStream sslstrm = new System.Net.Security.SslStream(tcpclnt.GetStream()); // There should be no gap between the imap command and the \r\n // sslstrm.read() -- while sslstrm.readbyte!= eof does not work // because there is no eof from server and cannot check for \r\n // because in case of larger response from server ex:read email // message. There are lot of lines so \r\n appears at the end of // each line sslstrm.timeout sets the underlying tcp connections // timeout if the read or writetime out exceeds then the undelying // connectionis closed. strmlgw.WriteLine("### START ====================================", sslstrm); sslstrm.AuthenticateAsClient("imap.gmail.com"); strmlgw.WriteLine("# Send blank =================================", sslstrm); SendImapCommand("", sslstrm); sRes = ReceiveImapRespons(sslstrm); strmlgw.Write(sRes); strmlgw.WriteLine("# Send 'LOGIN' ===============================", sslstrm); SendImapCommand("$ LOGIN " + sUserid + " " + sPassword + " \r\n", sslstrm); sRes = ReceiveImapRespons(sslstrm); strmlgw.Write(sRes); strmlgw.WriteLine("# Send 'SELECT INBOX' ========================", sslstrm); SendImapCommand("$ SELECT INBOX\r\n", sslstrm); sRes = ReceiveImapRespons(sslstrm); strmlgw.Write(sRes); // strmlgw.WriteLine("# Send 'TATUS INBOX (MESSAGES)' ==============", sslstrm); // SendImapCommand("$ STATUS INBOX (MESSAGES)\r\n", sslstrm); // sRes = ReceiveImapRespons(sslstrm); // strmlgw.Write(sRes); // int number = 1; // strmlgw.WriteLine("# Send 'FETCH " + number.ToString() + " BODYSTRUCTURE' =======", sslstrm); // SendImapCommand("$ FETCH " + number + " bodystructure\r\n", sslstrm); // sRes = ReceiveImapRespons(sslstrm); // strmlgw.Write(sRes); // strmlgw.WriteLine("# Send 'FETCH " + number.ToString() + " BODY[HEADER]' ========", sslstrm); // SendImapCommand("$ FETCH " + number + " body[header]\r\n", sslstrm); // sRes = ReceiveImapRespons(sslstrm); // strmlgw.Write(sRes); strmlgw.WriteLine("# Send 'FETCH 1 body[text]' ==================", sslstrm); SendImapCommand("$ FETCH 1 body[text]\r\n", sslstrm); ReceiveMailBody(sDpath, tcpclnt, sslstrm); string sTempTimeSheetPath = ExtractAttachedFile(sDpath, sEpath); strmlgw.WriteLine("# Send 'LOGOUT' ==============================", sslstrm); SendImapCommand("$ LOGOUT\r\n", sslstrm); sRes = ReceiveImapRespons(sslstrm); strmlgw.Write(sRes); strmlgw.WriteLine("### END ======================================", sslstrm); strmlgw.Close(); strmlgw.Dispose(); sslstrm.Close(); sslstrm.Dispose(); tcpclnt.Close(); File.Delete(sLpath); File.Delete(sDpath); return(sTempTimeSheetPath); }
private static void HandleClient(TcpClient client) { Stream clientStream = client.GetStream(); CustomBinaryReader clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII); StreamWriter clientStreamWriter = new StreamWriter(clientStream); string tunnelHostName = null; int tunnelPort = 0; try { string securehost = null; List<string> requestLines = new List<string>(); string tmpLine; while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) { requestLines.Add(tmpLine); } //read the first line HTTP command String httpCmd = requestLines.Count > 0 ? requestLines[0] : null; if (String.IsNullOrEmpty(httpCmd)) { throw new EndOfStreamException(); } //break up the line into three components (method, remote URL & Http Version) String[] splitBuffer = httpCmd.Split(spaceSplit, 3); String method = splitBuffer[0]; String remoteUri = splitBuffer[1]; Version version; string RequestVersion; if (splitBuffer[2] == "HTTP/1.1") { version = new Version(1, 1); RequestVersion = "HTTP/1.1"; } else { version = new Version(1, 0); RequestVersion = "HTTP/1.0"; } //Client wants to create a secure tcp tunnel (its a HTTPS request) if (splitBuffer[0].ToUpper() == "CONNECT") { //Browser wants to create a secure tunnel //instead = we are going to perform a man in the middle "attack" //the user's browser should warn them of the certification errors, //to avoid that we need to install our root certficate in users machine as Certificate Authority. remoteUri = "https://" + splitBuffer[1]; tunnelHostName = splitBuffer[1].Split(':')[0]; int.TryParse(splitBuffer[1].Split(':')[1], out tunnelPort); if (tunnelPort == 0) tunnelPort = 443; requestLines.Clear(); clientStreamWriter.WriteLine(RequestVersion + " 200 Connection established"); clientStreamWriter.WriteLine(String.Format("Timestamp: {0}", DateTime.Now.ToString())); clientStreamWriter.WriteLine(String.Format("connection:close")); clientStreamWriter.WriteLine(); clientStreamWriter.Flush(); //If port is not 443 its not a HTTP request, so just relay if (tunnelPort != 443) { TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); return; } //Create the fake certificate signed using our fake certificate authority Monitor.Enter(certificateAccessLock); var certificate = ProxyServer.CertManager.CreateCertificate(tunnelHostName); Monitor.Exit(certificateAccessLock); SslStream sslStream = null; //Pinned certificate clients cannot be proxied //Example dropbox.com uses certificate pinning //So just relay the request after identifying it by first failure if (!pinnedCertificateClients.Contains(tunnelHostName)) { try { sslStream = new SslStream(clientStream, true); //Successfully managed to authenticate the client using the fake certificate sslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false); clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII); clientStreamWriter = new StreamWriter(sslStream); //HTTPS server created - we can now decrypt the client's traffic clientStream = sslStream; } catch { //if authentication failed it could be because client uses pinned certificates //So add the hostname to this list so that next time we can relay without touching it (tunnel the request) if (pinnedCertificateClients.Contains(tunnelHostName) == false) { pinnedCertificateClients.Add(tunnelHostName); } if (sslStream != null) sslStream.Dispose(); throw; } } else { //Hostname was a previously failed request due to certificate pinning, just relay (tunnel the request) TcpHelper.SendRaw(tunnelHostName, tunnelPort, clientStreamReader.BaseStream); if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); return; } while (!String.IsNullOrEmpty(tmpLine = clientStreamReader.ReadLine())) { requestLines.Add(tmpLine); } //read the new http command. httpCmd = requestLines.Count > 0 ? requestLines[0] : null; if (String.IsNullOrEmpty(httpCmd)) { throw new EndOfStreamException(); } securehost = remoteUri; } //Now create the request Task.Factory.StartNew(() => HandleHttpSessionRequest(client, httpCmd, clientStream, tunnelHostName, requestLines, clientStreamReader, clientStreamWriter, securehost)); } catch { if (clientStreamReader != null) clientStreamReader.Dispose(); if (clientStreamWriter != null) clientStreamWriter.Dispose(); if (clientStream != null) clientStream.Dispose(); if (client != null) client.Close(); } }
public static void SendRaw(Stream clientStream, string httpCmd, List<HttpHeader> requestHeaders, string hostName, int tunnelPort, bool isHttps) { StringBuilder sb = null; if (httpCmd != null || requestHeaders != null) { sb = new StringBuilder(); if (httpCmd != null) { sb.Append(httpCmd); sb.Append(Environment.NewLine); } if (requestHeaders != null) foreach (var header in requestHeaders.Select(t => t.ToString())) { sb.Append(header); sb.Append(Environment.NewLine); } sb.Append(Environment.NewLine); } TcpClient tunnelClient = null; Stream tunnelStream = null; try { tunnelClient = new TcpClient(hostName, tunnelPort); tunnelStream = tunnelClient.GetStream(); if (isHttps) { SslStream sslStream = null; try { sslStream = new SslStream(tunnelStream); sslStream.AuthenticateAsClient(hostName); tunnelStream = sslStream; } catch { if (sslStream != null) sslStream.Dispose(); throw; } } var sendRelay = Task.Factory.StartNew(() => { if (sb != null) clientStream.CopyToAsync(sb.ToString(), tunnelStream, BUFFER_SIZE); else clientStream.CopyToAsync(tunnelStream, BUFFER_SIZE); }); var receiveRelay = Task.Factory.StartNew(() => tunnelStream.CopyToAsync(clientStream, BUFFER_SIZE)); Task.WaitAll(sendRelay, receiveRelay); } catch { if (tunnelStream != null) { tunnelStream.Close(); tunnelStream.Dispose(); } if (tunnelClient != null) tunnelClient.Close(); throw; } }
private static bool TryConnect(out TcpClient tcpClient, out SslStream stream, string ip, int port) { tcpClient = null; stream = null; var client = new TcpClient(); try { var result = client.BeginConnect(ip, port, null, null); var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3)); if (!success) return false; client.EndConnect(result); } catch (Exception) { return false; } var sslStream = new SslStream(client.GetStream(), false, UserCertificateValidationCallback); try { var serverName = Environment.MachineName; sslStream.AuthenticateAsClient(serverName); } catch (AuthenticationException) { sslStream.Dispose(); client.Close(); return false; } tcpClient = client; stream = sslStream; return true; }
/// <summary> /// Sets up a connection to APNS and initializes the thread for sending notifications /// </summary> void _Connect() { var configuration = ApnsServiceConfiguration.GetConfiguration (); _certificate = new X509Certificate2 (File.ReadAllBytes (configuration.Certificate), configuration.Password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); try { if (!_connection.IsNullOrDefault ()) _connection.Close (); #if DEBUG NSLogger.Log (NSLogLevel.Info, "Connecting to APNS..."); #endif _connection = new TcpClient (apnsHostName, 2195); if (!_sslStream.IsNullOrDefault ()) _sslStream.Close (); _sslStream = new SslStream (_connection.GetStream (), false, new RemoteCertificateValidationCallback ((sender, cert, chain, sslPolicyErrors) => { return true; }), new LocalCertificateSelectionCallback ((sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return _certificate; })); var certificates = new X509CertificateCollection { _certificate }; _sslStream.AuthenticateAsClient (apnsHostName, certificates, SslProtocols.Ssl3, false); if (!_sslStream.IsMutuallyAuthenticated) throw new ApplicationException ("SSL Stream Failed to Authenticate", null); if (!_sslStream.CanWrite) throw new ApplicationException ("SSL Stream is not Writable", null); #if DEBUG NSLogger.Log (NSLogLevel.Info, "Connected!"); #endif } catch (Exception) { if (_connection.Connected) { _connection.Close (); } if (!_sslStream.IsNullOrDefault ()) { _sslStream.Close (); _sslStream.Dispose (); } throw; } }
public void Run(ApplePushChannelSettings settings, CancellationToken cancelToken) { var encoding = Encoding.ASCII; var certificate = settings.Certificate; var certificates = new X509CertificateCollection(); certificates.Add(certificate); var client = new TcpClient(settings.FeedbackHost, settings.FeedbackPort); var stream = new SslStream(client.GetStream(), true, (sender, cert, chain, sslErrs) => { return true; }, (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return certificate; }); stream.AuthenticateAsClient(settings.FeedbackHost, certificates, System.Security.Authentication.SslProtocols.Ssl3, false); //Set up byte[] buffer = new byte[38]; int recd = 0; DateTime minTimestamp = DateTime.Now.AddYears(-1); //Get the first feedback recd = stream.Read(buffer, 0, buffer.Length); //Continue while we have results and are not disposing while (recd > 0 && !cancelToken.IsCancellationRequested) { try { //Get our seconds since 1970 ? byte[] bSeconds = new byte[4]; byte[] bDeviceToken = new byte[32]; Array.Copy(buffer, 0, bSeconds, 0, 4); //Check endianness if (BitConverter.IsLittleEndian) Array.Reverse(bSeconds); int tSeconds = BitConverter.ToInt32(bSeconds, 0); //Add seconds since 1970 to that date, in UTC var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(tSeconds); //flag to allow feedback times in UTC or local, but default is local if (!settings.FeedbackTimeIsUTC) timestamp = timestamp.ToLocalTime(); //Now copy out the device token Array.Copy(buffer, 6, bDeviceToken, 0, 32); var deviceToken = BitConverter.ToString(bDeviceToken).Replace("-", "").ToLower().Trim(); //Make sure we have a good feedback tuple if (deviceToken.Length == 64 && timestamp > minTimestamp) { //Raise event RaiseFeedbackReceived(deviceToken, timestamp); } } catch { } //Clear our array to reuse it Array.Clear(buffer, 0, buffer.Length); //Read the next feedback recd = stream.Read(buffer, 0, buffer.Length); } try { stream.Close (); stream.Dispose(); } catch { } try { client.Client.Shutdown (SocketShutdown.Both); client.Client.Dispose (); } catch { } try { client.Close (); } catch { } }
/// <summary> /// Establish a connection to the specified IMAP or IMAP/S server using the provided socket. /// </summary> /// <remarks> /// <para>Establishes a connection to the specified IMAP or IMAP/S server using /// the provided socket.</para> /// <para>If the <paramref name="port"/> has a value of <c>0</c>, then the /// <paramref name="options"/> parameter is used to determine the default port to /// connect to. The default port used with <see cref="SecureSocketOptions.SslOnConnect"/> /// is <c>993</c>. All other values will use a default port of <c>143</c>.</para> /// <para>If the <paramref name="options"/> has a value of /// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used /// to determine the default security options. If the <paramref name="port"/> has a value /// of <c>993</c>, then the default options used will be /// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use /// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para> /// <para>Once a connection is established, properties such as /// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be /// populated.</para> /// </remarks> /// <param name="socket">The socket to use for the connection.</param> /// <param name="host">The host name to connect to.</param> /// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param> /// <param name="options">The secure socket options to when connecting.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ArgumentNullException"> /// <para><paramref name="socket"/> is <c>null</c>.</para> /// <para>-or-</para> /// <para><paramref name="host"/> is <c>null</c>.</para> /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>. /// </exception> /// <exception cref="System.ArgumentException"> /// <para><paramref name="socket"/> is not connected.</para> /// <para>-or-</para> /// The <paramref name="host"/> is a zero-length string. /// </exception> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="ImapClient"/> has been disposed. /// </exception> /// <exception cref="System.InvalidOperationException"> /// The <see cref="ImapClient"/> is already connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// <paramref name="options"/> was set to /// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/> /// and the IMAP server does not support the STARTTLS extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled via the cancellation token. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="ImapProtocolException"> /// An IMAP protocol error occurred. /// </exception> public void Connect (Socket socket, string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { if (socket == null) throw new ArgumentNullException (nameof (socket)); if (!socket.Connected) throw new ArgumentException ("The socket is not connected.", nameof (socket)); if (host == null) throw new ArgumentNullException (nameof (host)); if (host.Length == 0) throw new ArgumentException ("The host name cannot be empty.", nameof (host)); if (port < 0 || port > 65535) throw new ArgumentOutOfRangeException (nameof (port)); CheckDisposed (); if (IsConnected) throw new InvalidOperationException ("The ImapClient is already connected."); Stream stream; bool starttls; Uri uri; ComputeDefaultValues (host, ref port, ref options, out uri, out starttls); engine.Uri = uri; if (options == SecureSocketOptions.SslOnConnect) { var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate); try { #if COREFX ssl.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else ssl.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif } catch { ssl.Dispose (); throw; } secure = true; stream = ssl; } else { stream = new NetworkStream (socket, true); secure = false; } if (stream.CanTimeout) { stream.WriteTimeout = timeout; stream.ReadTimeout = timeout; } ProtocolLogger.LogConnect (uri); engine.Connect (new ImapStream (stream, socket, ProtocolLogger), cancellationToken); try { // Only query the CAPABILITIES if the greeting didn't include them. if (engine.CapabilitiesVersion == 0) engine.QueryCapabilities (cancellationToken); if (options == SecureSocketOptions.StartTls && (engine.Capabilities & ImapCapabilities.StartTLS) == 0) throw new NotSupportedException ("The IMAP server does not support the STARTTLS extension."); if (starttls && (engine.Capabilities & ImapCapabilities.StartTLS) != 0) { var ic = engine.QueueCommand (cancellationToken, null, "STARTTLS\r\n"); engine.Wait (ic); ProcessResponseCodes (ic); if (ic.Response == ImapCommandResponse.Ok) { var tls = new SslStream (stream, false, ValidateRemoteCertificate); #if COREFX tls.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else tls.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif engine.Stream.Stream = tls; secure = true; // Query the CAPABILITIES again if the server did not include an // untagged CAPABILITIES response to the STARTTLS command. if (engine.CapabilitiesVersion == 1) engine.QueryCapabilities (cancellationToken); } else if (options == SecureSocketOptions.StartTls) { throw ImapCommandException.Create ("STARTTLS", ic); } } } catch { engine.Disconnect (); secure = false; throw; } engine.Disconnected += OnEngineDisconnected; OnConnected (); }
/// <summary> /// Establish a connection to the specified IMAP server. /// </summary> /// <remarks> /// <para>Establishes a connection to the specified IMAP or IMAP/S server.</para> /// <para>If the <paramref name="port"/> has a value of <c>0</c>, then the /// <paramref name="options"/> parameter is used to determine the default port to /// connect to. The default port used with <see cref="SecureSocketOptions.SslOnConnect"/> /// is <c>993</c>. All other values will use a default port of <c>143</c>.</para> /// <para>If the <paramref name="options"/> has a value of /// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used /// to determine the default security options. If the <paramref name="port"/> has a value /// of <c>993</c>, then the default options used will be /// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use /// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para> /// <para>Once a connection is established, properties such as /// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be /// populated.</para> /// </remarks> /// <example> /// <code language="c#" source="Examples\ImapExamples.cs" region="DownloadMessages"/> /// </example> /// <param name="host">The host name to connect to.</param> /// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param> /// <param name="options">The secure socket options to when connecting.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="host"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>. /// </exception> /// <exception cref="System.ArgumentException"> /// The <paramref name="host"/> is a zero-length string. /// </exception> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="ImapClient"/> has been disposed. /// </exception> /// <exception cref="System.InvalidOperationException"> /// The <see cref="ImapClient"/> is already connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// <paramref name="options"/> was set to /// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/> /// and the IMAP server does not support the STARTTLS extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled via the cancellation token. /// </exception> /// <exception cref="System.Net.Sockets.SocketException"> /// A socket error occurred trying to connect to the remote host. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="ImapProtocolException"> /// An IMAP protocol error occurred. /// </exception> public override void Connect (string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { if (host == null) throw new ArgumentNullException (nameof (host)); if (host.Length == 0) throw new ArgumentException ("The host name cannot be empty.", nameof (host)); if (port < 0 || port > 65535) throw new ArgumentOutOfRangeException (nameof (port)); CheckDisposed (); if (IsConnected) throw new InvalidOperationException ("The ImapClient is already connected."); Stream stream; bool starttls; Uri uri; ComputeDefaultValues (host, ref port, ref options, out uri, out starttls); #if !NETFX_CORE #if COREFX var ipAddresses = Dns.GetHostAddressesAsync (uri.DnsSafeHost).GetAwaiter ().GetResult (); #else var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost); #endif Socket socket = null; for (int i = 0; i < ipAddresses.Length; i++) { socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp) { ReceiveTimeout = timeout, SendTimeout = timeout }; try { cancellationToken.ThrowIfCancellationRequested (); if (LocalEndPoint != null) socket.Bind (LocalEndPoint); socket.Connect (ipAddresses[i], port); break; } catch (OperationCanceledException) { socket.Dispose (); throw; } catch { socket.Dispose (); if (i + 1 == ipAddresses.Length) throw; } } if (socket == null) throw new IOException (string.Format ("Failed to resolve host: {0}", host)); engine.Uri = uri; if (options == SecureSocketOptions.SslOnConnect) { var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate); try { #if COREFX ssl.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else ssl.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif } catch { ssl.Dispose (); throw; } secure = true; stream = ssl; } else { stream = new NetworkStream (socket, true); secure = false; } #else var protection = options == SecureSocketOptions.SslOnConnect ? SocketProtectionLevel.Tls12 : SocketProtectionLevel.PlainSocket; socket = new StreamSocket (); try { cancellationToken.ThrowIfCancellationRequested (); socket.ConnectAsync (new HostName (host), port.ToString (), protection) .AsTask (cancellationToken) .GetAwaiter () .GetResult (); } catch { socket.Dispose (); socket = null; throw; } stream = new DuplexStream (socket.InputStream.AsStreamForRead (0), socket.OutputStream.AsStreamForWrite (0)); secure = options == SecureSocketOptions.SslOnConnect; engine.Uri = uri; #endif if (stream.CanTimeout) { stream.WriteTimeout = timeout; stream.ReadTimeout = timeout; } ProtocolLogger.LogConnect (uri); engine.Connect (new ImapStream (stream, socket, ProtocolLogger), cancellationToken); try { // Only query the CAPABILITIES if the greeting didn't include them. if (engine.CapabilitiesVersion == 0) engine.QueryCapabilities (cancellationToken); if (options == SecureSocketOptions.StartTls && (engine.Capabilities & ImapCapabilities.StartTLS) == 0) throw new NotSupportedException ("The IMAP server does not support the STARTTLS extension."); if (starttls && (engine.Capabilities & ImapCapabilities.StartTLS) != 0) { var ic = engine.QueueCommand (cancellationToken, null, "STARTTLS\r\n"); engine.Wait (ic); ProcessResponseCodes (ic); if (ic.Response == ImapCommandResponse.Ok) { #if !NETFX_CORE var tls = new SslStream (stream, false, ValidateRemoteCertificate); #if COREFX tls.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else tls.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif engine.Stream.Stream = tls; #else socket.UpgradeToSslAsync (SocketProtectionLevel.Tls12, new HostName (host)) .AsTask (cancellationToken) .GetAwaiter () .GetResult (); #endif secure = true; // Query the CAPABILITIES again if the server did not include an // untagged CAPABILITIES response to the STARTTLS command. if (engine.CapabilitiesVersion == 1) engine.QueryCapabilities (cancellationToken); } else if (options == SecureSocketOptions.StartTls) { throw ImapCommandException.Create ("STARTTLS", ic); } } } catch { engine.Disconnect (); secure = false; throw; } engine.Disconnected += OnEngineDisconnected; OnConnected (); }
public void Run(ApplePushChannelSettings settings, CancellationToken cancelToken) { var encoding = Encoding.ASCII; var certificate = settings.Certificate; var certificates = new X509CertificateCollection(); certificates.Add(certificate); var client = new TcpClient(settings.FeedbackHost, settings.FeedbackPort); var stream = new SslStream(client.GetStream(), true, (sender, cert, chain, sslErrs) => { return true; }, (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return certificate; }); stream.AuthenticateAsClient(settings.FeedbackHost, certificates, System.Security.Authentication.SslProtocols.Tls, false); //Set up byte[] buffer = new byte[1482]; int bufferIndex = 0; int bufferLevel = 0; int completePacketSize = 4 + 2 + 32; int recd = 0; DateTime minTimestamp = DateTime.Now.AddYears(-1); //Get the first feedback recd = stream.Read(buffer, 0, buffer.Length); //Continue while we have results and are not disposing while (recd > 0 && !cancelToken.IsCancellationRequested) { //Update how much data is in the buffer, and reset the position to the beginning bufferLevel += recd; bufferIndex = 0; try { //Process each complete notification "packet" available in the buffer while (bufferLevel - bufferIndex >= completePacketSize) { //Get our seconds since 1970 ? byte[] bSeconds = new byte[4]; byte[] bDeviceToken = new byte[32]; Array.Copy(buffer, bufferIndex, bSeconds, 0, 4); //Check endianness if (BitConverter.IsLittleEndian) Array.Reverse(bSeconds); int tSeconds = BitConverter.ToInt32(bSeconds, 0); //Add seconds since 1970 to that date, in UTC var timestamp = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(tSeconds); //flag to allow feedback times in UTC or local, but default is local if (!settings.FeedbackTimeIsUTC) timestamp = timestamp.ToLocalTime(); //Now copy out the device token Array.Copy(buffer, bufferIndex + 6, bDeviceToken, 0, 32); var deviceToken = BitConverter.ToString(bDeviceToken).Replace("-", "").ToLower().Trim(); //Make sure we have a good feedback tuple if (deviceToken.Length == 64 && timestamp > minTimestamp) { //Raise event try { RaiseFeedbackReceived(deviceToken, timestamp); } catch { } } //Keep track of where we are in the received data buffer bufferIndex += completePacketSize; } } catch { } //Figure out how much data we have left over in the buffer still bufferLevel -= bufferIndex; //Copy any leftover data in the buffer to the start of the buffer if (bufferLevel > 0) Array.Copy(buffer, bufferIndex, buffer, 0, bufferLevel); //Read the next feedback recd = stream.Read(buffer, bufferLevel, buffer.Length - bufferLevel); } try { stream.Close (); stream.Dispose(); } catch { } try { client.Client.Shutdown (SocketShutdown.Both); client.Client.Dispose (); } catch { } try { client.Close (); } catch { } }
public static async Task<EpoxyNetworkStream> MakeServerStreamAsync( Socket socket, EpoxyServerTlsConfig tlsConfig, Logger logger) { Stream serverStream; var networkStream = new NetworkStream(socket, ownsSocket: false); if (tlsConfig == null) { serverStream = networkStream; } else { const bool leaveInnerStreamOpen = false; var sslStream = new SslStream( networkStream, leaveInnerStreamOpen, MakeServerCertificateValidationCallback(tlsConfig, logger)); await sslStream.AuthenticateAsServerAsync( tlsConfig.Certificate, tlsConfig.ClientCertificateRequired, enabledSslProtocols: AllowedTlsProtocols, checkCertificateRevocation: tlsConfig.CheckCertificateRevocation); if (tlsConfig.ClientCertificateRequired && !sslStream.IsMutuallyAuthenticated) { sslStream.Dispose(); throw new AuthenticationException("Mutual authentication was required, but it could not be performed."); } logger.Site().Debug( "Authenticated connection from {0}. Mutually authenticated?: {1}", socket.RemoteEndPoint, sslStream.IsMutuallyAuthenticated); serverStream = sslStream; } return new EpoxyNetworkStream(socket, serverStream, logger); }
/// <summary> /// Establishes a connection to the specified SMTP or SMTP/S server. /// </summary> /// <remarks> /// <para>Establishes a connection to the specified SMTP or SMTP/S server.</para> /// <para>If the <paramref name="port"/> has a value of <c>0</c>, then the /// <paramref name="options"/> parameter is used to determine the default port to /// connect to. The default port used with <see cref="SecureSocketOptions.SslOnConnect"/> /// is <c>465</c>. All other values will use a default port of <c>25</c>.</para> /// <para>If the <paramref name="options"/> has a value of /// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used /// to determine the default security options. If the <paramref name="port"/> has a value /// of <c>465</c>, then the default options used will be /// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use /// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para> /// <para>Once a connection is established, properties such as /// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be /// populated.</para> /// <note type="note">The connection established by any of the /// <a href="Overload_MailKit_Net_Smtp_SmtpClient_Connect.htm">Connect</a> /// methods may be re-used if an application wishes to send multiple messages /// to the same SMTP server. Since connecting and authenticating can be expensive /// operations, re-using a connection can significantly improve performance when /// sending a large number of messages to the same SMTP server over a short /// period of time.</note> /// </remarks> /// <example> /// <code language="c#" source="Examples\SmtpExamples.cs" region="SendMessage"/> /// </example> /// <param name="host">The host name to connect to.</param> /// <param name="port">The port to connect to. If the specified port is <c>0</c>, then the default port will be used.</param> /// <param name="options">The secure socket options to when connecting.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <exception cref="System.ArgumentNullException"> /// <paramref name="host"/> is <c>null</c>. /// </exception> /// <exception cref="System.ArgumentOutOfRangeException"> /// <paramref name="port"/> is not between <c>0</c> and <c>65535</c>. /// </exception> /// <exception cref="System.ArgumentException"> /// The <paramref name="host"/> is a zero-length string. /// </exception> /// <exception cref="System.ObjectDisposedException"> /// The <see cref="SmtpClient"/> has been disposed. /// </exception> /// <exception cref="System.InvalidOperationException"> /// The <see cref="SmtpClient"/> is already connected. /// </exception> /// <exception cref="System.NotSupportedException"> /// <paramref name="options"/> was set to /// <see cref="MailKit.Security.SecureSocketOptions.StartTls"/> /// and the SMTP server does not support the STARTTLS extension. /// </exception> /// <exception cref="System.OperationCanceledException"> /// The operation was canceled. /// </exception> /// <exception cref="System.Net.Sockets.SocketException"> /// A socket error occurred trying to connect to the remote host. /// </exception> /// <exception cref="System.IO.IOException"> /// An I/O error occurred. /// </exception> /// <exception cref="SmtpCommandException"> /// An SMTP command failed. /// </exception> /// <exception cref="SmtpProtocolException"> /// An SMTP protocol error occurred. /// </exception> public override void Connect (string host, int port = 0, SecureSocketOptions options = SecureSocketOptions.Auto, CancellationToken cancellationToken = default (CancellationToken)) { if (host == null) throw new ArgumentNullException (nameof (host)); if (host.Length == 0) throw new ArgumentException ("The host name cannot be empty.", nameof (host)); if (port < 0 || port > 65535) throw new ArgumentOutOfRangeException (nameof (port)); CheckDisposed (); if (IsConnected) throw new InvalidOperationException ("The SmtpClient is already connected."); capabilities = SmtpCapabilities.None; AuthenticationMechanisms.Clear (); MaxSize = 0; SmtpResponse response; Stream stream; bool starttls; Uri uri; ComputeDefaultValues (host, ref port, ref options, out uri, out starttls); #if !NETFX_CORE #if COREFX var ipAddresses = Dns.GetHostAddressesAsync (uri.DnsSafeHost).GetAwaiter ().GetResult (); #else var ipAddresses = Dns.GetHostAddresses (uri.DnsSafeHost); #endif Socket socket = null; for (int i = 0; i < ipAddresses.Length; i++) { socket = new Socket (ipAddresses[i].AddressFamily, SocketType.Stream, ProtocolType.Tcp) { ReceiveTimeout = timeout, SendTimeout = timeout }; try { cancellationToken.ThrowIfCancellationRequested (); if (LocalEndPoint != null) socket.Bind (LocalEndPoint); socket.Connect (ipAddresses[i], port); break; } catch (OperationCanceledException) { socket.Dispose (); socket = null; throw; } catch { socket.Dispose (); socket = null; if (i + 1 == ipAddresses.Length) throw; } } if (socket == null) throw new IOException (string.Format ("Failed to resolve host: {0}", host)); this.host = host; if (options == SecureSocketOptions.SslOnConnect) { var ssl = new SslStream (new NetworkStream (socket, true), false, ValidateRemoteCertificate); try { #if COREFX ssl.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else ssl.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif } catch { ssl.Dispose (); throw; } secure = true; stream = ssl; } else { stream = new NetworkStream (socket, true); secure = false; } #else var protection = options == SecureSocketOptions.SslOnConnect ? SocketProtectionLevel.Tls12 : SocketProtectionLevel.PlainSocket; var socket = new StreamSocket (); try { cancellationToken.ThrowIfCancellationRequested (); socket.ConnectAsync (new HostName (host), port.ToString (), protection) .AsTask (cancellationToken) .GetAwaiter () .GetResult (); } catch { socket.Dispose (); throw; } stream = new DuplexStream (socket.InputStream.AsStreamForRead (0), socket.OutputStream.AsStreamForWrite (0)); secure = options == SecureSocketOptions.SslOnConnect; this.host = host; #endif if (stream.CanTimeout) { stream.WriteTimeout = timeout; stream.ReadTimeout = timeout; } ProtocolLogger.LogConnect (uri); Stream = new SmtpStream (stream, socket, ProtocolLogger); try { // read the greeting response = Stream.ReadResponse (cancellationToken); if (response.StatusCode != SmtpStatusCode.ServiceReady) throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); // Send EHLO and get a list of supported extensions Ehlo (cancellationToken); if (options == SecureSocketOptions.StartTls && (capabilities & SmtpCapabilities.StartTLS) == 0) throw new NotSupportedException ("The SMTP server does not support the STARTTLS extension."); if (starttls && (capabilities & SmtpCapabilities.StartTLS) != 0) { response = SendCommand ("STARTTLS", cancellationToken); if (response.StatusCode != SmtpStatusCode.ServiceReady) throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); #if !NETFX_CORE var tls = new SslStream (stream, false, ValidateRemoteCertificate); #if COREFX tls.AuthenticateAsClientAsync (host, ClientCertificates, SslProtocols, true).GetAwaiter ().GetResult (); #else tls.AuthenticateAsClient (host, ClientCertificates, SslProtocols, true); #endif Stream.Stream = tls; #else socket.UpgradeToSslAsync (SocketProtectionLevel.Tls12, new HostName (host)) .AsTask (cancellationToken) .GetAwaiter () .GetResult (); #endif secure = true; // Send EHLO again and get the new list of supported extensions Ehlo (cancellationToken); } connected = true; } catch { Stream.Dispose (); secure = false; Stream = null; throw; } OnConnected (); }
/// <summary> /// Accept callback method for SSL connection. /// </summary> /// <param name="ar">The socket server</param> private void AcceptSSLCallback(IAsyncResult ar) { AbstractSocketServer server = (AbstractSocketServer)ar.AsyncState; SslStream sslStream = null; try { // Get the socket that handles the client request. TcpClient sslTcpClient = server.sslListener.EndAcceptTcpClient(ar); Trace.WriteLine("Start incoming ssl connection ..."); sslStream = new SslStream(sslTcpClient.GetStream(), false, new RemoteCertificateValidationCallback(server.OnVerifyClientCertificate)); sslStream.AuthenticateAsServer(server.serverCertificate, true, SslProtocols.Ssl3, false); Socket handler = sslTcpClient.Client; handler.Blocking = true; AbstractTcpSocketClientHandler clientHandler = this.GetHandler(handler, sslStream); clientHandler.KeepAlive = this.KeepAlive; clientHandler.ReceiveMessageEvent += new ReceiveMessageDelegate(server.OnReceiveMessage); clientHandler.CloseConnectionEvent += new SocketConnectionDelegate(server.clientHandler_CloseConnectionEvent); server.OnConnection(clientHandler); server.clientList.AddClient(this.GetClientInfo(clientHandler)); clientHandler.StartReceive(); Trace.WriteLine("New connection completed"); } catch (Exception ex) { Trace.WriteLine(string.Format("Failed to accept incoming connection. Exception", ex)); try { if (sslStream != null) { sslStream.Close(); sslStream.Dispose(); } } catch (Exception ex2) { Trace.WriteLine(ex2); } } finally { // Signal the main thread to continue. server.listenerCompleteConnectionEvent.Set(); } }
public static void SendRaw(string httpCmd, string secureHostName, List<string> requestLines, bool isHttps, Stream clientStream) { StringBuilder sb = new StringBuilder(); sb.Append(httpCmd); sb.Append(Environment.NewLine); string hostname = secureHostName; for (int i = 1; i < requestLines.Count; i++) { var header = requestLines[i]; if (secureHostName == null) { String[] headerParsed = httpCmd.Split(colonSpaceSplit, 2, StringSplitOptions.None); switch (headerParsed[0].ToLower()) { case "host": var hostdetail = headerParsed[1]; if (hostdetail.Contains(":")) hostname = hostdetail.Split(':')[0].Trim(); else hostname = hostdetail.Trim(); break; default: break; } } sb.Append(header); sb.Append(Environment.NewLine); } sb.Append(Environment.NewLine); int tunnelPort = 80; if (isHttps) { tunnelPort = 443; } System.Net.Sockets.TcpClient tunnelClient = null; Stream tunnelStream = null; try { tunnelClient = new System.Net.Sockets.TcpClient(hostname, tunnelPort); tunnelStream = tunnelClient.GetStream() as Stream; if (isHttps) { SslStream sslStream = null; try { sslStream = new SslStream(tunnelStream); sslStream.AuthenticateAsClient(hostname); tunnelStream = sslStream; } catch { if (sslStream != null) sslStream.Dispose(); } } var sendRelay = new Task(() => StreamHelper.CopyTo(sb.ToString(), clientStream, tunnelStream, BUFFER_SIZE)); var receiveRelay = new Task(() => StreamHelper.CopyTo(tunnelStream, clientStream, BUFFER_SIZE)); sendRelay.Start(); receiveRelay.Start(); Task.WaitAll(sendRelay, receiveRelay); } catch { if (tunnelStream != null) { tunnelStream.Close(); tunnelStream.Dispose(); } if (tunnelClient != null) tunnelClient.Close(); throw; } }
private static void HandleClient(TcpClient client) { Stream clientStream = client.GetStream(); var clientStreamReader = new CustomBinaryReader(clientStream, Encoding.ASCII); var clientStreamWriter = new StreamWriter(clientStream); Uri httpRemoteUri; try { //read the first line HTTP command var httpCmd = clientStreamReader.ReadLine(); if (string.IsNullOrEmpty(httpCmd)) { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } //break up the line into three components (method, remote URL & Http Version) var httpCmdSplit = httpCmd.Split(SpaceSplit, 3); var httpVerb = httpCmdSplit[0]; if (httpVerb.ToUpper() == "CONNECT") httpRemoteUri = new Uri("http://" + httpCmdSplit[1]); else httpRemoteUri = new Uri(httpCmdSplit[1]); var httpVersion = httpCmdSplit[2]; var excluded = ExcludedHttpsHostNameRegex.Any(x => Regex.IsMatch(httpRemoteUri.Host, x)); //Client wants to create a secure tcp tunnel (its a HTTPS request) if (httpVerb.ToUpper() == "CONNECT" && !excluded && httpRemoteUri.Port == 443) { httpRemoteUri = new Uri("https://" + httpCmdSplit[1]); clientStreamReader.ReadAllLines(); WriteConnectResponse(clientStreamWriter, httpVersion); var certificate = CertManager.CreateCertificate(httpRemoteUri.Host); SslStream sslStream = null; try { sslStream = new SslStream(clientStream, true); //Successfully managed to authenticate the client using the fake certificate sslStream.AuthenticateAsServer(certificate, false, SslProtocols.Tls | SslProtocols.Ssl3 | SslProtocols.Ssl2, false); clientStreamReader = new CustomBinaryReader(sslStream, Encoding.ASCII); clientStreamWriter = new StreamWriter(sslStream); //HTTPS server created - we can now decrypt the client's traffic clientStream = sslStream; } catch { if (sslStream != null) sslStream.Dispose(); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } httpCmd = clientStreamReader.ReadLine(); } else if (httpVerb.ToUpper() == "CONNECT") { clientStreamReader.ReadAllLines(); WriteConnectResponse(clientStreamWriter, httpVersion); TcpHelper.SendRaw(clientStreamReader.BaseStream, null, null, httpRemoteUri.Host, httpRemoteUri.Port, false); Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); return; } //Now create the request HandleHttpSessionRequest(client, httpCmd, clientStream, clientStreamReader, clientStreamWriter, httpRemoteUri.Scheme == Uri.UriSchemeHttps ? httpRemoteUri.OriginalString : null); } catch { Dispose(client, clientStream, clientStreamReader, clientStreamWriter, null); } }
// guarantees to close the socket on error public static void TlsConnect(Socket sock, string host, RemoteCertificateValidationCallback rcvc, Action<Exception,SslStream> cb) { SslStream ssl = null; try { ssl = new SslStream (new NetworkStream (sock, true), false, rcvc); ssl.BeginAuthenticateAsClient (host, (ar) => { try { ssl.EndAuthenticateAsClient (ar); } catch (Exception ex) { ssl.Dispose (); sock.Dispose (); cb (ex, null); return; } cb (null, ssl); }, null); } catch (Exception ex) { if (ssl != null) ssl.Dispose (); sock.Dispose (); cb (ex, null); } }
private bool ConnectSync(string sHost, int nPort) { bool result = false; try { var imapServer = new TcpClient(sHost, nPort); _imapSslStream = new SslStream(imapServer.GetStream(), false, ValidateServerCertificate, null); try { _imapSslStream.AuthenticateAsClient(sHost, null, SslProtocols.Default, false); } catch (AuthenticationException authEx) { _logger.Warn(authEx, "Authentication failed"); _imapSslStream.Dispose(); imapServer.Close(); return false; } _imapSslStreamReader = new StreamReader(_imapSslStream); var text = _imapSslStreamReader.ReadLine(); if (text != null && text.StartsWith("* OK")) { result = Capability(); } } catch (IOException ioEx) { _logger.Warn(ioEx, "Failed to connect"); } return result; }
public MFTestResults RunClient() { MFTestResults testResult = MFTestResults .Pass; try { if (ipAddress == null) Console.WriteLine("IpAddress must be initialized before calling RunClient()"); else serverEp = new IPEndPoint(ipAddress, port); IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName()); IPAddress localAddr = null; foreach (IPAddress addr in hostEntry.AddressList) { if (addr.AddressFamily == AddressFamily.InterNetwork) { localAddr = addr; } } IPEndPoint localEnpoint = new IPEndPoint(localAddr, port); Console.WriteLine("Connect to IPAddress: " + serverEp.Address.ToString() + " Port Number: " + serverEp.Port.ToString()); // Create a TCP/IP client socket. bool connected = false; int retries = 0; while (!connected) { try { clientSocket = new TcpClient(localEnpoint); clientSocket.Connect(serverEp); connected = true; } catch { } Thread.Sleep(1000); retries++; if (retries > 20) { Console.WriteLine("Tried to connect 20 times without success. Failing test."); return MFTestResults.Fail; } } // Create an SSL stream that will close the client's stream. sslClient = new SslStream(clientSocket.GetStream()); Console.WriteLine("Calling AuthenticateAsClient()"); // The server name must match the name on the server certificate. sslClient.AuthenticateAsClient(targetHost, certificateCollection, sslProtocols, false); // Send hello message to the server. byte[] message = Encoding.UTF8.GetBytes(messageSent); sslClient.Write(message, 0, message.Length); Console.WriteLine("Sent: " + messageSent); // Read message from the server. messageReceived = ReadMessage(sslClient); Console.WriteLine("Received: " + messageReceived); if (messageSent != messageReceived) testResult = MFTestResults.Fail; } catch (SocketException e) { if (!expectedException) testResult = MFTestResults.Fail; Console.WriteLine("ErrorCode: " + e.ErrorCode); Console.WriteLine("An exception occurred: " + e.Message); } catch (Exception e) { if (!expectedException) testResult = MFTestResults.Fail; Console.WriteLine("An exception occurred: " + e.Message); } finally { if (sslClient != null) { Thread.Sleep(50); sslClient.Dispose(); sslClient = null; } if (clientSocket != null) { clientSocket.Close(); clientSocket = null; } } return testResult; }
public MFTestResults RunServer() { MFTestResults testResult = MFTestResults.Fail; SslStream sslStream = null; try { sslServer = new TcpListener(ipAddress, port); // Start listening for client requests. sslServer.Start(); // Buffer for reading data Byte[] bytes = new Byte[2048]; String data = null; // Start Listening for a connection. Console.Write("Waiting for a connection... "); // Perform a blocking call to accept requests. // You could also user server.AcceptSocket() here. TcpClient client = sslServer.AcceptTcpClient(); Console.WriteLine("Connected!"); data = null; // Get a stream object for reading and writing sslStream = new SslStream(client.GetStream()); sslStream.AuthenticateAsServer(certificate, clientCertificateRequired, enabledSslProtocols, false); TestUtilities.PrintSslStreamProperties(sslStream); int i = 0; // Loop to receive all the data sent by the client. while ((i = sslStream.Read(bytes, 0, bytes.Length)) != 0) { // Translate data bytes to a string. // The encoding used is application specific. data = System.Text.Encoding.UTF8.GetString(bytes, 0, i); Console.WriteLine("Received: {0}", data); byte[] msg = System.Text.Encoding.UTF8.GetBytes(data); // Send back a response. sslStream.Write(msg, 0, msg.Length); Console.WriteLine("Sent: {0}", data); } testResult = MFTestResults.Pass; } catch (SocketException e) { if (expectedException) testResult = MFTestResults.Pass; Console.WriteLine("SocketException in StartServer(): " + e.ToString()); Console.WriteLine("ErrorCode: " + e.ErrorCode.ToString()); } catch (Exception e) { if (expectedException) testResult = MFTestResults.Pass; Console.WriteLine("Exception in StartServer(): " + e.ToString()); } finally { if (sslStream != null) { sslStream.Dispose(); sslStream = null; } if (sslServer != null) { sslServer.Stop(); sslServer = null; } } return testResult; }
public void Check () { var encoding = Encoding.ASCII; var certificate = Configuration.Certificate; var certificates = new X509CertificateCollection(); certificates.Add(certificate); var client = new TcpClient (Configuration.FeedbackHost, Configuration.FeedbackPort); var stream = new SslStream (client.GetStream(), true, (sender, cert, chain, sslErrs) => { return true; }, (sender, targetHost, localCerts, remoteCert, acceptableIssuers) => { return certificate; }); stream.AuthenticateAsClient(Configuration.FeedbackHost, certificates, System.Security.Authentication.SslProtocols.Tls, false); //Set up byte[] buffer = new byte[4096]; int recd = 0; var data = new List<byte> (); //Get the first feedback recd = stream.Read(buffer, 0, buffer.Length); //Continue while we have results and are not disposing while (recd > 0) { // Add the received data to a list buffer to work with (easier to manipulate) for (int i = 0; i < recd; i++) data.Add (buffer [i]); //Process each complete notification "packet" available in the buffer while (data.Count >= (4 + 2 + 32)) // Minimum size for a valid packet { var secondsBuffer = data.GetRange (0, 4).ToArray (); var tokenLengthBuffer = data.GetRange (4, 2).ToArray (); // Get our seconds since epoch // Check endianness and reverse if needed if (BitConverter.IsLittleEndian) Array.Reverse (secondsBuffer); var seconds = BitConverter.ToInt32 (secondsBuffer, 0); //Add seconds since 1970 to that date, in UTC var timestamp = new DateTime (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds (seconds); //flag to allow feedback times in UTC or local, but default is local if (!Configuration.FeedbackTimeIsUTC) timestamp = timestamp.ToLocalTime(); if (BitConverter.IsLittleEndian) Array.Reverse (tokenLengthBuffer); var tokenLength = BitConverter.ToInt16 (tokenLengthBuffer, 0); if (data.Count >= 4 + 2 + tokenLength) { var tokenBuffer = data.GetRange (6, tokenLength).ToArray (); // Strings shouldn't care about endian-ness... this shouldn't be reversed //if (BitConverter.IsLittleEndian) // Array.Reverse (tokenBuffer); var token = BitConverter.ToString (tokenBuffer).Replace ("-", "").ToLower ().Trim (); // Remove what we parsed from the buffer data.RemoveRange (0, 4 + 2 + tokenLength); // Raise the event to the consumer var evt = FeedbackReceived; if (evt != null) evt (token, timestamp); } else { continue; } } //Read the next feedback recd = stream.Read (buffer, 0, buffer.Length); } try { stream.Close (); stream.Dispose(); } catch { } try { client.Client.Shutdown (SocketShutdown.Both); client.Client.Dispose (); } catch { } try { client.Close (); } catch { } }