2006/10/13

SSLStream for GMail POP3s

GMailに大変お世話になっています。

未だにβ版とはいえ便利すぎて手放せません。まぁGMailFSとかも使ってるからですが。
POP3に対応というかPOP3s 対応しているのもちょっと魅力。

それで以前にC#でTLS物を作ろうとして苦労をしていたのを思い出したのですが、.NET 2.0なるとSSLStreamとかってクラスが追加されてて、簡単に出来そうな感じだったので試してみました。



元のサンプルプログラムを弄っただけもので、あくまでもクラスのテスト用のコードですが。


using System;
using System.IO;
using System.Net;
using System.Text;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace ConsoleSecureTcpClient
{

    class SecureClient
    {

        [STAThread]
        static void Main()
        {
            string server = "pop.gmail.com";
            string sUser = "USER " +  "Your Account@gmail.com" + "\r\n";
            string sPassword = "PASS " + "Your Password" + "\r\n";
            int port = 995;
            SslStream stream = null;

            try
            {
                // Instantiate a TcpClient with the target server and port number
                TcpClient client = new TcpClient(server, port);

                // Specify the callback function that will act as the validation delegate. This
                // lets you inspect the certificate to see if it meets your
                // validation requirements.
                RemoteCertificateValidationCallback callback =
                                                    new RemoteCertificateValidationCallback(OnCertificateValidation);

                // Instantiate an SslStream with the NetworkStream returned from the TcpClient.
                stream = new SslStream(client.GetStream(), false, callback);

             
                // As a client, you can authenticate the server and validate the results using the SslStream.
                // This is the host name of the server you are connecting to, which may or may not
                // be the name used to connect to the server when TcpClient is instantiated.
                stream.AuthenticateAsClient(server);
                if (stream.IsAuthenticated)
                {
                    // Indicates whether the authentication was successful.
                    Console.WriteLine("IsAuthenticated: {0}", stream.IsAuthenticated);
                    // Indicates whether both the client and server has been authenticated.
                    // In this example only the server is authenticated.
                    Console.WriteLine("IsMutuallyAuthenticated: {0}", stream.IsMutuallyAuthenticated);
                    // Indicates whether the SslStream uses data encryption.
                    Console.WriteLine("IsEncrypted: {0}", stream.IsEncrypted);
                    // Indicates whether the data sent is signed.
                    Console.WriteLine("IsSigned: {0}", stream.IsSigned);
                    // Indicates whether the current side of the connection is authenticated as a server.
                    Console.WriteLine("IsServer: {0}", stream.IsServer);
                }

                Byte []data = new Byte[256];
                int bytes = stream.Read(data, 0, data.Length);
                string responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
                Console.WriteLine("Received: {0}", responseData);

                data = System.Text.Encoding.ASCII.GetBytes(sUser);
                stream.Write(data, 0, data.Length);
                Console.WriteLine("Sent: {0}", Encoding.ASCII.GetString(data));

                data = new Byte[256];
                bytes = stream.Read(data, 0, data.Length);
                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
                Console.WriteLine("Received: {0}", responseData);

                data = System.Text.Encoding.ASCII.GetBytes(sPassword);
                stream.Write(data, 0, data.Length);
                Console.WriteLine("Sent: {0}", Encoding.ASCII.GetString(data));
             
                data = new Byte[256];
                bytes = stream.Read(data, 0, data.Length);
                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
                Console.WriteLine("Received: {0}", responseData);

                data = System.Text.Encoding.ASCII.GetBytes("QUIT\r\n");
                stream.Write(data, 0, data.Length);
                Console.WriteLine("Sent: {0}", Encoding.ASCII.GetString(data));
             
                data = new Byte[1024*1024];
                bytes = stream.Read(data, 0, data.Length);
                responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
                Console.WriteLine("Received: {0}", responseData);

            }
            catch (AuthenticationException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (SocketException ex)
            {
                Console.WriteLine(ex.Message);
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                // Make sure that the SslStream is closed.
                if (stream != null)
                    stream.Close();
            }

            Console.WriteLine("\n Press Enter to continue...");
            Console.Read();
        }
        // Check the certificate for errors and to make sure it meets your security policy.
        private static bool OnCertificateValidation(object sender, X509Certificate certificate
                    , X509Chain chain, SslPolicyErrors errors)
        {
            Console.WriteLine("Server Certificate Issued To: {0}", certificate.GetName());
            Console.WriteLine("Server Certificate Issued By: {0}", certificate.GetIssuerName());
            // Return true if there are no policy errors
            // The certificate can also be manually verified to make sure it meets your specific
            // policies by interrogating the x509Certificate object.

            if (errors != SslPolicyErrors.None)
            {
                Console.WriteLine("Server Certificate Validation Error");
                Console.WriteLine(errors.ToString());
                return false;
            }
            else
            {
                Console.WriteLine("No Certificate Validation Errors");
                return true;
            }
        }
    }
}


以前は、Mentalis.org Security Library を使用して満足していましたが、Frameworkに入ったという事でこれはこれでよい感じです。

しかしFrameworkもここまでくると、IntelliSense無しのCodingはちょっと辛いですね。

関連のありそうな記事

0 コメント: