GnuTLSとは
GnuTLSはSSL/TLSプロトコルのフリーな実装です。
SSL/TLSプロトコルの実装としてはOpenSSLが有名ですが、OpenSSLのライセンスはGPLに対し非互換のため、GPLの下にあるソフトウェアはOpenSSLを使うことができませんでした。
GnuTLSは、その問題を解決しGNUプロジェクトのアプリケーションでもTLSのようなプロトコルを扱えることを目的として開発されました。
GnuTLSのインストール
MacOSXの場合は、MacPortを使うことで簡単にGnuTLSをインストールできます。
$ port install gnutls他の環境でもパッケージシステムから同様にインストールできると思います。
GnuTLSのソースコードは、以下のページからダウンロードできます。
http://www.gnu.org/software/gnutls/download.html
GnuTLSを使ったサンプルを試してみる
GnuTLSのドキュメント7.3.1に、HTTPSでサーバに接続してデータを取得するサンプルがあるので、それを試してみました。
sample.c
/* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <gnutls/gnutls.h> /* A very basic TLS client, with anonymous authentication. */ #define MAX_BUF 1024 #define MSG "GET / HTTP/1.0\r\n\r\n" extern int tcp_connect (void); extern void tcp_close (int sd); int main (void) { int ret, sd, ii; gnutls_session_t session; char buffer[MAX_BUF + 1]; gnutls_anon_client_credentials_t anoncred; /* Need to enable anonymous KX specifically. */ gnutls_global_init (); gnutls_anon_allocate_client_credentials (&anoncred); /* Initialize TLS session */ gnutls_init (&session, GNUTLS_CLIENT); /* Use default priorities */ gnutls_priority_set_direct (session, "PERFORMANCE:+ANON-DH:!ARCFOUR-128", NULL); /* put the anonymous credentials to the current session */ gnutls_credentials_set (session, GNUTLS_CRD_ANON, anoncred); /* connect to the peer */ sd = tcp_connect (); gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) sd); /* Perform the TLS handshake */ ret = gnutls_handshake (session); if (ret < 0) { fprintf (stderr, "*** Handshake failed\n"); gnutls_perror (ret); goto end; } else { printf ("- Handshake was completed\n"); } gnutls_record_send (session, MSG, strlen (MSG)); ret = gnutls_record_recv (session, buffer, MAX_BUF); if (ret == 0) { printf ("- Peer has closed the TLS connection\n"); goto end; } else if (ret < 0) { fprintf (stderr, "*** Error: %s\n", gnutls_strerror (ret)); goto end; } printf ("- Received %d bytes: ", ret); for (ii = 0; ii < ret; ii++) { fputc (buffer[ii], stdout); } fputs ("\n", stdout); gnutls_bye (session, GNUTLS_SHUT_RDWR); end: tcp_close (sd); gnutls_deinit (session); gnutls_anon_free_client_credentials (anoncred); gnutls_global_deinit (); return 0; }
このサンプルでは、同ドキュメントの7.3.10に書かれている、TCP接続のためのヘルパー関数を使うため、そのコードも用意します。
helper.c
/* This example code is placed in the public domain. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <unistd.h> #define SA struct sockaddr /* tcp.c */ int tcp_connect (void); void tcp_close (int sd); /* Connects to the peer and returns a socket * descriptor. */ extern int tcp_connect (void) { const char *PORT = "5556"; const char *SERVER = "127.0.0.1"; int err, sd; struct sockaddr_in sa; /* connects to server */ sd = socket (AF_INET, SOCK_STREAM, 0); memset (&sa, '\0', sizeof (sa)); sa.sin_family = AF_INET; sa.sin_port = htons (atoi (PORT)); inet_pton (AF_INET, SERVER, &sa.sin_addr); err = connect (sd, (SA *) & sa, sizeof (sa)); if (err < 0) { fprintf (stderr, "Connect error\n"); exit (1); } return sd; } /* closes the given socket descriptor. */ extern void tcp_close (int sd) { shutdown (sd, SHUT_RDWR); /* no more receptions */ close (sd); }※IP、ポートは適切に変更してください
ビルドするためにMakefileを用意します。
Makefile
sample: sample.o helper.o gcc -o sample sample.o helper.o `pkg-config gnutls --libs` .c.o: gcc -c $< -I/opt/local/include
makeして実行してみると、handshakeに失敗してエラーになります。
$ make $ ./sample *** Handshake failed GNUTLS ERROR: A TLS fatal alert has been received.
handshakeとは何でしょうか?HTTPSの仕組みを調べる必要がありそうです。
--