]> jfr.im git - irc/rqf/shadowircd.git/blobdiff - libratbox/src/gnutls.c
Branch merge.
[irc/rqf/shadowircd.git] / libratbox / src / gnutls.c
index 5442bc10824a0d341885d6a54e203a8cd5335e43..51a25defe9dd54e119af66a7ca0b913784929056 100644 (file)
@@ -4,7 +4,6 @@
  *
  *  Copyright (C) 2007-2008 ircd-ratbox development team
  *  Copyright (C) 2007-2008 Aaron Sethman <androsyn@ratbox.org>
- *  Copyright (C) 2008 William Pitcock <nenolod@nenolod.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
  *  USA
  *
- *  $Id: commio.c 24808 2008-01-02 08:17:05Z androsyn $
+ *  $Id: gnutls.c 26092 2008-09-19 15:13:52Z androsyn $
  */
 
 #include <libratbox_config.h>
 #include <ratbox_lib.h>
-
-#ifdef HAVE_GNUTLS
-
 #include <commio-int.h>
 #include <commio-ssl.h>
+#ifdef HAVE_GNUTLS
+
 #include <gnutls/gnutls.h>
+#include <gcrypt.h>
+
+static gnutls_certificate_credentials x509;
+static gnutls_dh_params dh_params;
 
-static gnutls_certificate_credentials_t x509_cred;
-static gnutls_dh_params_t dh_params;
+
+
+#define SSL_P(x) *((gnutls_session_t *)F->ssl)
 
 void
-rb_ssl_shutdown(rb_fde_t * F)
+rb_ssl_shutdown(rb_fde_t *F)
 {
+       int i;
        if(F == NULL || F->ssl == NULL)
                return;
+       for(i = 0; i < 4; i++)
+       {
+               if(gnutls_bye(SSL_P(F), GNUTLS_SHUT_RDWR) == GNUTLS_E_SUCCESS)
+                       break;
+       }
+       gnutls_deinit(SSL_P(F));
+       rb_free(F->ssl);
+}
 
-       gnutls_bye((gnutls_session_t) F->ssl, GNUTLS_SHUT_RDWR);
-       gnutls_deinit((gnutls_session_t) F->ssl);
+unsigned int
+rb_ssl_handshake_count(rb_fde_t *F)
+{
+       return F->handshake_count;
+}
+
+void
+rb_ssl_clear_handshake_count(rb_fde_t *F)
+{
+       F->handshake_count = 0;
 }
 
 static void
-rb_ssl_timeout(rb_fde_t * F, void *notused)
+rb_ssl_timeout(rb_fde_t *F, void *notused)
 {
        lrb_assert(F->accept != NULL);
        F->accept->callback(F, RB_ERR_TIMEOUT, NULL, 0, F->accept->data);
 }
 
-static void
-rb_ssl_tryaccept(rb_fde_t * F, void *data)
+
+static int
+do_ssl_handshake(rb_fde_t *F, PF * callback)
 {
-       int ssl_err;
-       lrb_assert(F->accept != NULL);
+       int ret;
        int flags;
-       struct acceptdata *ad;
 
-       if((ssl_err = gnutls_handshake((gnutls_session_t) F->ssl)) != 0)
+       ret = gnutls_handshake(SSL_P(F));
+       if(ret < 0)
        {
-               switch (ssl_err)
+               if((ret == GNUTLS_E_INTERRUPTED && rb_ignore_errno(errno)) || ret == GNUTLS_E_AGAIN)
                {
-               case GNUTLS_E_INTERRUPTED:
-                       if(rb_ignore_errno(errno))
-               case GNUTLS_E_AGAIN:
-                       {
-                               if(gnutls_record_get_direction((gnutls_session_t) F->ssl))
-                                       flags = RB_SELECT_WRITE;
-                               else
-                                       flags = RB_SELECT_READ;
-
-                               F->ssl_errno = ssl_err;
-                               rb_setselect(F, flags, rb_ssl_tryaccept, NULL);
-                               return;
-                       }
-                       break;
-               default:
-                       F->ssl_errno = ssl_err;
-                       F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
-                       break;
+                       if(gnutls_record_get_direction(SSL_P(F)) == 0)
+                               flags = RB_SELECT_READ;
+                       else
+                               flags = RB_SELECT_WRITE;
+                       rb_setselect(F, flags, callback, NULL);
+                       return 0;
                }
+               F->ssl_errno = ret;
+               return -1;
+       }
+       return 1;               /* handshake is finished..go about life */
+}
+
+static void
+rb_ssl_tryaccept(rb_fde_t *F, void *data)
+{
+       int ret;
+       struct acceptdata *ad;
+
+       lrb_assert(F->accept != NULL);
+
+       ret = do_ssl_handshake(F, rb_ssl_tryaccept);
+
+       switch (ret)
+       {
+       case -1:
+               F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data);
+               break;
+       case 0:
+               /* do_ssl_handshake does the rb_setselect stuff */
                return;
+       default:
+               break;
+
+
        }
        rb_settimeout(F, 0, NULL, NULL);
        rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
-       
+
        ad = F->accept;
        F->accept = NULL;
-       ad->callback(F, RB_OK, (struct sockaddr *) &ad->S, ad->addrlen,
-                           ad->data);
+       ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
        rb_free(ad);
+
 }
 
 void
-rb_ssl_start_accepted(rb_fde_t * new_F, ACCB * cb, void *data, int timeout)
+rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout)
 {
-       gnutls_session_t sess;
-       int ssl_err;
-
+       gnutls_session_t *ssl;
        new_F->type |= RB_FD_SSL;
-
-       gnutls_init(&sess, GNUTLS_SERVER);
-       gnutls_set_default_priority(sess);
-       gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
-       gnutls_dh_set_prime_bits(sess, 1024);
-       gnutls_certificate_server_set_request(sess, GNUTLS_CERT_REQUEST);
-
-       new_F->ssl = sess;
-
+       ssl = new_F->ssl = rb_malloc(sizeof(gnutls_session_t));
        new_F->accept = rb_malloc(sizeof(struct acceptdata));
 
        new_F->accept->callback = cb;
@@ -120,65 +145,29 @@ rb_ssl_start_accepted(rb_fde_t * new_F, ACCB * cb, void *data, int timeout)
 
        new_F->accept->addrlen = 0;
 
-       gnutls_transport_set_ptr((gnutls_session_t) new_F->ssl, (gnutls_transport_ptr_t) rb_get_fd(new_F));
-
-       if((ssl_err = gnutls_handshake((gnutls_session_t) new_F->ssl)) != 0)
-       {
-               switch(ssl_err)
-               {
-               case GNUTLS_E_INTERRUPTED:
-                       if(rb_ignore_errno(errno))
-               case GNUTLS_E_AGAIN:
-                       {
-                               int flags;
-
-                               if(gnutls_record_get_direction((gnutls_session_t) new_F->ssl))
-                                       flags = RB_SELECT_WRITE;
-                               else
-                                       flags = RB_SELECT_READ;
-
-                               new_F->ssl_errno = ssl_err;
-                               rb_setselect(new_F, flags, rb_ssl_tryaccept, NULL);
-                               return;
-                       }
-                       break;
-               default:
-                       new_F->ssl_errno = ssl_err;
-                       new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
-                       return;
-               }
-       }
-       else
+       gnutls_init(ssl, GNUTLS_SERVER);
+       gnutls_set_default_priority(*ssl);
+       gnutls_credentials_set(*ssl, GNUTLS_CRD_CERTIFICATE, x509);
+       gnutls_dh_set_prime_bits(*ssl, 1024);
+       gnutls_transport_set_ptr(*ssl, (gnutls_transport_ptr_t) (long int)new_F->fd);
+       if(do_ssl_handshake(new_F, rb_ssl_tryaccept))
        {
-               struct acceptdata *ad;
-
-               rb_settimeout(new_F, 0, NULL, NULL);
-               rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
-       
-               ad = new_F->accept;
+               struct acceptdata *ad = new_F->accept;
                new_F->accept = NULL;
-               ad->callback(new_F, RB_OK, (struct sockaddr *) &ad->S, ad->addrlen,
-                                   ad->data);
+               ad->callback(new_F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
                rb_free(ad);
        }
+
 }
 
-void
-rb_ssl_accept_setup(rb_fde_t * F, int new_fd, struct sockaddr *st, int addrlen)
-{
-       gnutls_session_t sess;
-       rb_fde_t *new_F;
-       int ssl_err;
 
-       new_F = rb_find_fd(new_fd);
 
-       gnutls_init(&sess, GNUTLS_SERVER);
-       gnutls_set_default_priority(sess);
-       gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
-       gnutls_dh_set_prime_bits(sess, 1024);
-       gnutls_certificate_server_set_request(sess, GNUTLS_CERT_REQUEST);
 
+void
+rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, int addrlen)
+{
        new_F->type |= RB_FD_SSL;
+       new_F->ssl = rb_malloc(sizeof(gnutls_session_t));
        new_F->accept = rb_malloc(sizeof(struct acceptdata));
 
        new_F->accept->callback = F->accept->callback;
@@ -187,139 +176,182 @@ rb_ssl_accept_setup(rb_fde_t * F, int new_fd, struct sockaddr *st, int addrlen)
        memcpy(&new_F->accept->S, st, addrlen);
        new_F->accept->addrlen = addrlen;
 
-       gnutls_transport_set_ptr((gnutls_session_t) new_F->ssl, (gnutls_transport_ptr_t) rb_get_fd(new_F));
-       if((ssl_err = gnutls_handshake((gnutls_session_t) new_F->ssl)) != 0)
-       {
-               switch(ssl_err)
-               {
-               case GNUTLS_E_INTERRUPTED:
-                       if(rb_ignore_errno(errno))
-               case GNUTLS_E_AGAIN:
-                       {
-                               int flags;
-
-                               if(gnutls_record_get_direction((gnutls_session_t) new_F->ssl))
-                                       flags = RB_SELECT_WRITE;
-                               else
-                                       flags = RB_SELECT_READ;
-
-                               new_F->ssl_errno = ssl_err;
-                               rb_setselect(new_F, flags, rb_ssl_tryaccept, NULL);
-                               return;
-                       }
-                       break;
-               default:
-                       new_F->ssl_errno = ssl_err;
-                       new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
-                       return;
-               }
-       }
-       else
+       gnutls_init((gnutls_session_t *) new_F->ssl, GNUTLS_SERVER);
+       gnutls_set_default_priority(SSL_P(new_F));
+       gnutls_credentials_set(SSL_P(new_F), GNUTLS_CRD_CERTIFICATE, x509);
+       gnutls_dh_set_prime_bits(SSL_P(new_F), 1024);
+       gnutls_transport_set_ptr(SSL_P(new_F), (gnutls_transport_ptr_t) (long int)rb_get_fd(new_F));
+       if(do_ssl_handshake(F, rb_ssl_tryaccept))
        {
-               struct acceptdata *ad;
-
-               rb_settimeout(new_F, 0, NULL, NULL);
-               rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL);
-       
-               ad = new_F->accept;
-               new_F->accept = NULL;
-               ad->callback(new_F, RB_OK, (struct sockaddr *) &ad->S, ad->addrlen,
-                                   ad->data);
+               struct acceptdata *ad = F->accept;
+               F->accept = NULL;
+               ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data);
                rb_free(ad);
        }
 }
 
+
+
+
 static ssize_t
-rb_ssl_read_or_write(int r_or_w, rb_fde_t * F, void *rbuf, const void *wbuf, size_t count)
+rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
 {
        ssize_t ret;
-       unsigned long err;
-       gnutls_session_t ssl = F->ssl;
+       gnutls_session_t *ssl = F->ssl;
 
        if(r_or_w == 0)
-               ret = gnutls_record_recv(ssl, rbuf, count);
+               ret = gnutls_record_recv(*ssl, rbuf, count);
        else
-               ret = gnutls_record_send(ssl, wbuf, count);
+               ret = gnutls_record_send(*ssl, wbuf, count);
 
        if(ret < 0)
        {
                switch (ret)
                {
                case GNUTLS_E_AGAIN:
-                       errno = EAGAIN;
-                       if (gnutls_record_get_direction(ssl))
-                               return RB_RW_SSL_NEED_WRITE;
-                       else
-                               return RB_RW_SSL_NEED_READ;
                case GNUTLS_E_INTERRUPTED:
-                       err = ret;
-                       if(err == 0)
+                       if(rb_ignore_errno(errno))
                        {
-                               F->ssl_errno = 0;
-                               return RB_RW_IO_ERROR;
+                               if(gnutls_record_get_direction(*ssl) == 0)
+                                       return RB_RW_SSL_NEED_READ;
+                               else
+                                       return RB_RW_SSL_NEED_WRITE;
+                               break;
                        }
-                       break;
                default:
-                       err = ret;
-                       break;
-               }
-               F->ssl_errno = err;
-               if(err > 0)
-               {
-                       errno = EIO;    /* not great but... */
-                       return RB_RW_SSL_ERROR;
+                       F->ssl_errno = ret;
+                       errno = EIO;
+                       return RB_RW_IO_ERROR;
                }
-               return RB_RW_IO_ERROR;
        }
        return ret;
 }
 
 ssize_t
-rb_ssl_read(rb_fde_t * F, void *buf, size_t count)
+rb_ssl_read(rb_fde_t *F, void *buf, size_t count)
 {
        return rb_ssl_read_or_write(0, F, buf, NULL, count);
 }
 
 ssize_t
-rb_ssl_write(rb_fde_t * F, const void *buf, size_t count)
+rb_ssl_write(rb_fde_t *F, const void *buf, size_t count)
 {
        return rb_ssl_read_or_write(1, F, NULL, buf, count);
 }
 
+static void
+rb_gcry_random_seed(void *unused)
+{
+       gcry_fast_random_poll();
+}
+
 int
 rb_init_ssl(void)
 {
-       int ret = 1, g_ret;
-
        gnutls_global_init();
 
-       if((g_ret = gnutls_dh_params_generate2(dh_params, 1024)) < 0)
+       if(gnutls_certificate_allocate_credentials(&x509) != GNUTLS_E_SUCCESS)
        {
-               rb_lib_log("rb_init_gnutls: Failed to generate GNUTLS DH params: %s", gnutls_strerror(g_ret));
-               ret = 0;
+               rb_lib_log("rb_init_ssl: Unable to allocate SSL/TLS certificate credentials");
+               return 0;
        }
+       rb_event_addish("rb_gcry_random_seed", rb_gcry_random_seed, NULL, 300);
+       return 1;
+}
+
+static void
+rb_free_datum_t(gnutls_datum_t * d)
+{
+       rb_free(d->data);
+       rb_free(d);
+}
 
-       gnutls_certificate_set_dh_params(x509_cred, dh_params);
+static gnutls_datum_t *
+rb_load_file_into_datum_t(const char *file)
+{
+       FILE *f;
+       gnutls_datum_t *datum;
+       struct stat fileinfo;
+       if((f = fopen(file, "r")) == NULL)
+               return NULL;
+       if(fstat(fileno(f), &fileinfo))
+               return NULL;
+
+       datum = rb_malloc(sizeof(gnutls_datum_t));
+
+       if(fileinfo.st_size > 131072)   /* deal with retards */
+               datum->size = 131072;
+       else
+               datum->size = fileinfo.st_size;
 
-       return ret;
+       datum->data = rb_malloc(datum->size + 1);
+       fread(datum->data, datum->size, 1, f);
+       fclose(f);
+       return datum;
 }
 
 int
 rb_setup_ssl_server(const char *cert, const char *keyfile, const char *dhfile)
 {
-       int ret = 0;
+       int ret;
+       gnutls_datum_t *d_cert, *d_key;
+       if(cert == NULL)
+       {
+               rb_lib_log("rb_setup_ssl_server: No certificate file");
+               return 0;
+       }
+
+       if((d_cert = rb_load_file_into_datum_t(cert)) == NULL)
+       {
+               rb_lib_log("rb_setup_ssl_server: Error loading certificate: %s", strerror(errno));
+               return 0;
+       }
+
+       if((d_key = rb_load_file_into_datum_t(keyfile)) == NULL)
+       {
+               rb_lib_log("rb_setup_ssl_server: Error loading key: %s", strerror(errno));
+               return 0;
+       }
+
 
-       if((ret = gnutls_certificate_set_x509_key_file(x509_cred, cert, keyfile, GNUTLS_X509_FMT_PEM)) < 0)
+       if((ret =
+           gnutls_certificate_set_x509_key_mem(x509, d_cert, d_key,
+                                               GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS)
        {
-               rb_lib_log("rb_setup_ssl_server: Setting x509 keys up failed: %s", gnutls_strerror(ret));
+               rb_lib_log("rb_setup_ssl_server: Error loading certificate or key file: %s",
+                          gnutls_strerror(ret));
                return 0;
        }
+       rb_free_datum_t(d_cert);
+       rb_free_datum_t(d_key);
 
+       if(dhfile != NULL)
+       {
+               if(gnutls_dh_params_init(&dh_params) == GNUTLS_E_SUCCESS)
+               {
+                       gnutls_datum_t *data;
+                       int xret;
+                       data = rb_load_file_into_datum_t(dhfile);
+                       if(data != NULL)
+                       {
+                               xret = gnutls_dh_params_import_pkcs3(dh_params, data,
+                                                                    GNUTLS_X509_FMT_PEM);
+                               if(xret < 0)
+                                       rb_lib_log
+                                               ("rb_setup_ssl_server: Error parsing DH file: %s\n",
+                                                gnutls_strerror(xret));
+                               rb_free_datum_t(data);
+                       }
+                       gnutls_certificate_set_dh_params(x509, dh_params);
+               }
+               else
+                       rb_lib_log("rb_setup_ssl_server: Unable to setup DH parameters");
+       }
        return 1;
 }
 
 int
-rb_ssl_listen(rb_fde_t * F, int backlog)
+rb_ssl_listen(rb_fde_t *F, int backlog)
 {
        F->type = RB_FD_SOCKET | RB_FD_LISTEN | RB_FD_SSL;
        return listen(F->fd, backlog);
@@ -333,7 +365,7 @@ struct ssl_connect
 };
 
 static void
-rb_ssl_connect_realcb(rb_fde_t * F, int status, struct ssl_connect *sconn)
+rb_ssl_connect_realcb(rb_fde_t *F, int status, struct ssl_connect *sconn)
 {
        F->connect->callback = sconn->callback;
        F->connect->data = sconn->data;
@@ -342,49 +374,39 @@ rb_ssl_connect_realcb(rb_fde_t * F, int status, struct ssl_connect *sconn)
 }
 
 static void
-rb_ssl_tryconn_timeout_cb(rb_fde_t * F, void *data)
+rb_ssl_tryconn_timeout_cb(rb_fde_t *F, void *data)
 {
        rb_ssl_connect_realcb(F, RB_ERR_TIMEOUT, data);
 }
 
 static void
-rb_ssl_tryconn_cb(rb_fde_t * F, void *data)
+rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
 {
        struct ssl_connect *sconn = data;
-       int ssl_err;
+       int ret;
 
-       if((ssl_err = gnutls_handshake((gnutls_session_t) F->ssl)) != 0)
-       {
-               switch (ssl_err)
-               {
-               case GNUTLS_E_INTERRUPTED:
-                       if(rb_ignore_errno(errno))
-               case GNUTLS_E_AGAIN:
-                               {
-                                       F->ssl_errno = ssl_err;
-                                       rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
-                                                    rb_ssl_tryconn_cb, sconn);
-                                       return;
-                               }
-               default:
-                       F->ssl_errno = ssl_err;
-                       rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
-                       return;
-               }
-       }
-       else
+       ret = do_ssl_handshake(F, rb_ssl_tryconn_cb);
+
+       switch (ret)
        {
-               rb_ssl_connect_realcb(F, RB_OK, sconn);
+       case -1:
+               rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
+               break;
+       case 0:
+               /* do_ssl_handshake does the rb_setselect stuff */
+               return;
+       default:
+               break;
+
+
        }
+       rb_ssl_connect_realcb(F, RB_OK, sconn);
 }
 
 static void
-rb_ssl_tryconn(rb_fde_t * F, int status, void *data)
+rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
 {
-       gnutls_session_t sess;
        struct ssl_connect *sconn = data;
-       int ssl_err;
-
        if(status != RB_OK)
        {
                rb_ssl_connect_realcb(F, status, sconn);
@@ -393,42 +415,22 @@ rb_ssl_tryconn(rb_fde_t * F, int status, void *data)
 
        F->type |= RB_FD_SSL;
 
-       gnutls_init(&sess, GNUTLS_CLIENT);
-       gnutls_set_default_priority(sess);
-       gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
-       gnutls_dh_set_prime_bits(sess, 1024);
-       gnutls_transport_set_ptr(sess, (gnutls_transport_ptr_t) F->fd);
-
-       F->ssl = sess;
 
        rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
-       if((ssl_err = gnutls_handshake((gnutls_session_t) F->ssl)) != 0)
-       {
-               switch (ssl_err)
-               {
-               case GNUTLS_E_INTERRUPTED:
-                       if(rb_ignore_errno(errno))
-               case GNUTLS_E_AGAIN:
-                               {
-                                       F->ssl_errno = ssl_err;
-                                       rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
-                                                    rb_ssl_tryconn_cb, sconn);
-                                       return;
-                               }
-               default:
-                       F->ssl_errno = ssl_err;
-                       rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
-                       return;
-               }
-       }
-       else
+       F->ssl = rb_malloc(sizeof(gnutls_session_t));
+       gnutls_init(F->ssl, GNUTLS_CLIENT);
+       gnutls_set_default_priority(SSL_P(F));
+       gnutls_dh_set_prime_bits(SSL_P(F), 1024);
+       gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd);
+
+       if(do_ssl_handshake(F, rb_ssl_tryconn_cb))
        {
                rb_ssl_connect_realcb(F, RB_OK, sconn);
        }
 }
 
 void
-rb_connect_tcp_ssl(rb_fde_t * F, struct sockaddr *dest,
+rb_connect_tcp_ssl(rb_fde_t *F, struct sockaddr *dest,
                   struct sockaddr *clocal, int socklen, CNCB * callback, void *data, int timeout)
 {
        struct ssl_connect *sconn;
@@ -440,14 +442,13 @@ rb_connect_tcp_ssl(rb_fde_t * F, struct sockaddr *dest,
        sconn->callback = callback;
        sconn->timeout = timeout;
        rb_connect_tcp(F, dest, clocal, socklen, rb_ssl_tryconn, sconn, timeout);
+
 }
 
 void
-rb_ssl_start_connected(rb_fde_t * F, CNCB * callback, void *data, int timeout)
+rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
 {
-       gnutls_session_t sess;
        struct ssl_connect *sconn;
-       int ssl_err;
        if(F == NULL)
                return;
 
@@ -459,57 +460,44 @@ rb_ssl_start_connected(rb_fde_t * F, CNCB * callback, void *data, int timeout)
        F->connect->callback = callback;
        F->connect->data = data;
        F->type |= RB_FD_SSL;
+       F->ssl = rb_malloc(sizeof(gnutls_session_t));
 
-       gnutls_init(&sess, GNUTLS_CLIENT);
-       gnutls_set_default_priority(sess);
-       gnutls_credentials_set(sess, GNUTLS_CRD_CERTIFICATE, x509_cred);
-       gnutls_dh_set_prime_bits(sess, 1024);
-       gnutls_transport_set_ptr(sess, (gnutls_transport_ptr_t) F->fd);
+       gnutls_init(F->ssl, GNUTLS_CLIENT);
+       gnutls_set_default_priority(SSL_P(F));
+       gnutls_dh_set_prime_bits(SSL_P(F), 1024);
+       gnutls_transport_set_ptr(SSL_P(F), (gnutls_transport_ptr_t) (long int)F->fd);
 
-       F->ssl = sess;
-        
        rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
-       if((ssl_err = gnutls_handshake((gnutls_session_t) F->ssl)) != 0)
-       {
-               switch (ssl_err)
-               {
-               case GNUTLS_E_INTERRUPTED:
-                       if(rb_ignore_errno(errno))
-               case GNUTLS_E_AGAIN:
-                               {
-                                       F->ssl_errno = ssl_err;
-                                       rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
-                                                    rb_ssl_tryconn_cb, sconn);
-                                       return;
-                               }
-               default:
-                       F->ssl_errno = ssl_err;
-                       rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
-                       return;
-               }
-       }
-       else
+
+       if(do_ssl_handshake(F, rb_ssl_tryconn_cb))
        {
                rb_ssl_connect_realcb(F, RB_OK, sconn);
        }
 }
 
-/* XXX: implement me */
 int
 rb_init_prng(const char *path, prng_seed_t seed_type)
 {
-       return -1;
+       gcry_fast_random_poll();
+       return 1;
 }
 
 int
 rb_get_random(void *buf, size_t length)
 {
-       return -1;
+       gcry_randomize(buf, length, GCRY_STRONG_RANDOM);
+       return 1;
 }
 
+int
+rb_get_pseudo_random(void *buf, size_t length)
+{
+       gcry_randomize(buf, length, GCRY_WEAK_RANDOM);
+       return 1;
+}
 
 const char *
-rb_get_ssl_strerror(rb_fde_t * F)
+rb_get_ssl_strerror(rb_fde_t *F)
 {
        return gnutls_strerror(F->ssl_errno);
 }