RSS

GIOでSTARTTLSを実装

めんどくさい。STARTTLSへの入り方はプロトコルによって違うので関数一発とはいかないのはわかるが…。すでにあるGSocketConnectionからGIOStreamを経由してGTlsConnectionを生成。そのあとhandshakeを行う手順。wiresharkでキャプチャしたが何も読めないことが確認できた。

#include <glib.h>
#include <gio/gio.h>

// $ gcc -Wall $(pkg-config --libs --cflags gio-2.0) gio_starttls.c

int
main(int argc, char **argv)
{
    GSocketClient *client;
    GCancellable *cancellable = NULL;
    GSocketConnection *connection; 
    GSocketConnectable  *connectable = NULL;
    GError *error;

    g_type_init();
    client = g_socket_client_new();
    connection = g_socket_client_connect_to_host(client, 
						 "imap.example.com",
						 143,
						 cancellable,
						 &error);
    if (connection == NULL) {
	 g_printerr ("%s can't connect: %s\n", argv[0], error->message);
	 return 1;
    }
    
    GInputStream *input = g_io_stream_get_input_stream(G_IO_STREAM(connection));
    GOutputStream *output = g_io_stream_get_output_stream(G_IO_STREAM(connection));
    char *buf; 
    buf = g_strnfill(1024, 0);
    g_input_stream_read(input, buf, 10240,NULL, &error);
    g_print("%s\n", buf);

    char str[] = "STARTTLS\n";
    g_output_stream_write(output, str, sizeof(str), NULL, &error);


    g_free(buf);
    buf = g_strnfill(1024, 0);
    g_input_stream_read(input, buf, 9999,NULL, &error);
    g_print("%s\n", buf);

    
    GIOStream *tls_conn;
    tls_conn = g_tls_client_connection_new (G_IO_STREAM(connection),
					    connectable, &error);
    if (!tls_conn) {
          g_printerr ("Could not create TLS connection: %s\n",
                      error->message);
          return 1;
    }

    if (!g_tls_connection_handshake (G_TLS_CONNECTION (tls_conn),
				     cancellable, &error))
    {
	g_printerr ("Error during TLS handshake: %s\n",
		    error->message);
	return 1;
    }

    input = g_io_stream_get_input_stream(tls_conn);
    output = g_io_stream_get_output_stream(tls_conn);

    char str2[] = "a01 capability\n";
    g_output_stream_write(output, str2, sizeof(str2), NULL, &error);

    g_free(buf);
    buf = g_strnfill(1024, 0);
    g_input_stream_read(input, buf, 1024,NULL, &error);
    g_print("%s\n", buf);

    return 0;
}

実行するとこうなる。handshakeの処理をしないinput・outputを渡すと謎の文字が表示されるだけである。

$ ./a.out 
* OK [CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE ACL ACL2=UNION STARTTLS] Courier-IMAP ready. Copyright 1998-2008 Double Precision, Inc.  See COPYING for distribution information.

STARTTLS OK Begin SSL/TLS negotiation now.

* CAPABILITY IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA IDLE AUTH=PLAIN ACL ACL2=UNION
 OK CAPABILITY completed

$