first part of ssl rerererewrite: split functions, move stuff out of prepare(), and...
authordiscomfitor <discomfitor@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 28 Sep 2010 03:16:08 +0000 (03:16 +0000)
committerdiscomfitor <discomfitor@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Tue, 28 Sep 2010 03:16:08 +0000 (03:16 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ecore@52837 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/ecore_con/Ecore_Con.h
src/lib/ecore_con/ecore_con.c
src/lib/ecore_con/ecore_con_private.h
src/lib/ecore_con/ecore_con_ssl.c

index 94dcdd7..fa333f8 100644 (file)
@@ -350,15 +350,13 @@ typedef enum _Ecore_Con_Type
    ECORE_CON_USE_TLS = (1 << 6),
    /** Use both TLS and SSL3 */
    ECORE_CON_USE_MIXED = ECORE_CON_USE_SSL3 | ECORE_CON_USE_TLS,
-   /** Attempt to use the previously loaded certificate */
+   /** Attempt to use the loaded certificate */
    ECORE_CON_LOAD_CERT = (1 << 7)
 } Ecore_Con_Type;
 
 EAPI int               ecore_con_init(void);
 EAPI int               ecore_con_shutdown(void);
 
-EAPI int               ecore_con_ssl_available_get(void);
-
 EAPI Eina_Bool         ecore_con_lookup(const char *name,
                                             Ecore_Con_Dns_Cb done_cb,
                                             const void *data);
@@ -368,6 +366,20 @@ EAPI Eina_Bool         ecore_con_lookup(const char *name,
  */
 
 /**
+ * @defgroup Ecore_Con_SSL_Group Ecore Connection SSL Functions
+ *
+ * @{
+ */
+EAPI int               ecore_con_ssl_available_get(void);
+EAPI Eina_Bool         ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr, const char *cert);
+EAPI Eina_Bool         ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr, const char *key_file);
+EAPI Eina_Bool         ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, const char *crl_file);
+EAPI Eina_Bool         ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr, const char *ca_file);
+EAPI void              ecore_con_ssl_server_verify(Ecore_Con_Server *svr);
+
+/** }@ */
+
+/**
  * @defgroup Ecore_Con_Server_Group Ecore Connection Server Functions
  *
  * @{
@@ -399,7 +411,6 @@ EAPI const char *      ecore_con_server_ip_get(Ecore_Con_Server *svr);
 EAPI void              ecore_con_server_flush(Ecore_Con_Server *svr);
 EAPI void              ecore_con_server_timeout_set(Ecore_Con_Server *svr, double timeout);
 EAPI double            ecore_con_server_timeout_get(Ecore_Con_Server *svr);
-EAPI Eina_Bool         ecore_con_server_ssl_cert_add(const char *cert);
 
 /**
  * @}
@@ -424,9 +435,6 @@ EAPI void              ecore_con_client_flush(Ecore_Con_Client *cl);
 EAPI double            ecore_con_client_uptime_get(Ecore_Con_Client *cl);
 EAPI double            ecore_con_client_timeout_get(Ecore_Con_Client *cl);
 EAPI void              ecore_con_client_timeout_set(Ecore_Con_Client *cl, double timeout);
-EAPI Eina_Bool         ecore_con_client_ssl_cert_add(const char *cert_file,
-                                                     const char *crl_file,
-                                                     const char *key_file);
 /**
  * @}
  */
index d4c5ca7..67cf8be 100644 (file)
@@ -298,6 +298,7 @@ ecore_con_server_add(Ecore_Con_Type compl_type,
    svr->port = port;
    svr->data = (void *)data;
    svr->created = EINA_TRUE;
+   svr->use_cert = (compl_type & ECORE_CON_LOAD_CERT);
    svr->reject_excess_clients = EINA_FALSE;
    svr->client_limit = -1;
    svr->clients = NULL;
@@ -411,6 +412,7 @@ ecore_con_server_connect(Ecore_Con_Type compl_type,
    svr->port = port;
    svr->data = (void *)data;
    svr->created = EINA_FALSE;
+   svr->use_cert = (compl_type & ECORE_CON_LOAD_CERT);
    svr->reject_excess_clients = EINA_FALSE;
    svr->clients = NULL;
    svr->client_limit = -1;
@@ -815,29 +817,6 @@ ecore_con_server_flush(Ecore_Con_Server *svr)
    _ecore_con_server_flush(svr);
 }
 
-/**
- * Add an ssl certificate for use in ecore_con_server functions.
- *
- * Use this function to add a SSL PEM certificate.
- * Simply specify the cert here to make it available,
- * then OR the @ref ECORE_CON_LOAD_CERT flag into the @ref ecore_con_server_connect
- * call to use it.  If there is an error loading the certificate upon creating
- * the connection, an error will be automatically logged.
- * @param cert The path to the certificate.
- * @return EINA_FALSE if the file cannot be loaded,
- * otherwise EINA_TRUE.
- * @note Currently certificate verification is not implemented.
- */
-
-EAPI Eina_Bool
-ecore_con_server_ssl_cert_add(const char *cert)
-{
-
-   if (!eina_str_has_extension(cert, "pem"))
-      return EINA_FALSE;
-
-   return ecore_con_ssl_server_cert_add(cert);
-}
 
 /**
  * @}
@@ -1119,36 +1098,6 @@ ecore_con_client_flush(Ecore_Con_Client *cl)
 }
 
 /**
- * @brief Add an ssl certificate for use in ecore_con_client functions.
- *
- * Use this function to add a SSL PEM certificate.
- * Simply specify the cert here to make it available,
- * then OR the @ref ECORE_CON_LOAD_CERT flag into the @ref ecore_con_server_add
- * call to use it.  If there is an error loading the certificate upon creating
- * the connection, an error will be automatically logged.
- * @param cert_file The path to the certificate.
- * @param crl_file The path to the CRL file
- * @param key_file The path to the private key file. If not specified, the private key
- * from the cert will be loaded.
- * @return EINA_FALSE if the file cannot be loaded,
- * otherwise EINA_TRUE.
- * @note Currently CRL file adding and certificate verification is not implemented,
- * so specifying it here has no effect.
- */
-
-EAPI Eina_Bool
-ecore_con_client_ssl_cert_add(const char *cert_file,
-                              const char *crl_file,
-                              const char *key_file)
-{
-
-   if (!eina_str_has_extension(cert_file, "pem"))
-      return EINA_FALSE;
-
-   return ecore_con_ssl_client_cert_add(cert_file, crl_file, key_file);
-}
-
-/**
  * @}
  */
 
index d43c940..87efec6 100644 (file)
@@ -137,6 +137,7 @@ struct _Ecore_Con_Server
    gnutls_psk_client_credentials_t pskcred_c;
    gnutls_psk_server_credentials_t pskcred_s;
    gnutls_certificate_credentials_t cert;
+   char *cert_file;
    gnutls_dh_params_t dh_params;
 #elif USE_OPENSSL
    SSL_CTX *ssl_ctx;
@@ -148,9 +149,11 @@ struct _Ecore_Con_Server
    char *ip;
    Eina_Bool dead : 1;
    Eina_Bool created : 1; /* EINA_TRUE if server is our listening server */
-   Eina_Bool connecting : 1;
+   Eina_Bool connecting : 1; /* EINA_FALSE if just initialized or connected */
    Eina_Bool handshaking : 1; /* EINA_TRUE if server is ssl handshaking */
-   Ecore_Con_Ssl_State ssl_state;
+   Eina_Bool use_cert : 1; /* EINA_TRUE if using certificate auth */
+   Ecore_Con_Ssl_State ssl_state; /* current state of ssl handshake on the server */
+   Eina_Bool verify : 1; /* EINA_TRUE if certificates will be verified */
    Eina_Bool reject_excess_clients : 1;
    Eina_Bool delete_me : 1;
 };
@@ -231,10 +234,6 @@ int                 ecore_con_info_mcast_listen(Ecore_Con_Server *svr,
 /* from ecore_con_ssl.c */
 Ecore_Con_Ssl_Error ecore_con_ssl_init(void);
 Ecore_Con_Ssl_Error ecore_con_ssl_shutdown(void);
-Eina_Bool           ecore_con_ssl_server_cert_add(const char *cert);
-Eina_Bool           ecore_con_ssl_client_cert_add(const char *cert_file,
-                                                  const char *crl_file,
-                                                  const char *key_file);
 Ecore_Con_Ssl_Error ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, int ssl_type);
 Ecore_Con_Ssl_Error ecore_con_ssl_server_init(Ecore_Con_Server *svr);
 Ecore_Con_Ssl_Error ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr);
index 14344d8..ce298a5 100644 (file)
@@ -45,6 +45,13 @@ static int _client_connected = 0;
 #endif
 
 #if USE_GNUTLS
+static void
+_gnutls_print_errors(int ret)
+{
+  if (ret)
+    ERR("gnutls returned with error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
+}
+
 
 static const char*
 SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status)
@@ -81,27 +88,20 @@ SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status)
    return NULL;
 }
 
-typedef struct _cert_thingy
-{
-   gnutls_certificate_credentials_t cert;
-   int count;
-} gnutls;
-static gnutls *client_cert = NULL;
-static gnutls *server_cert = NULL;
 #elif USE_OPENSSL
-typedef struct _cert_thingy
-{
-   X509 *cert;
-   int count;
-} openssl;
-typedef struct _key_thingy
-{
-   EVP_PKEY *key;
-   int count;
-} openssl_pkey;
-static openssl_pkey *private_key = NULL;
-static openssl *client_cert = NULL;
-static openssl *server_cert = NULL;
+
+static void
+_openssl_print_errors(void)
+{
+   do
+     {
+        unsigned long err;
+
+        err = ERR_get_error();
+        if (!err) break;
+        ERR("openssl error: %s", ERR_reason_error_string(err));
+     } while (1);
+}
 #endif
 
 #define SSL_ERROR_CHECK_GOTO_ERROR(X) \
@@ -121,13 +121,10 @@ static Ecore_Con_Ssl_Error
 static Ecore_Con_Ssl_Error
                  SSL_SUFFIX(_ecore_con_ssl_shutdown) (void);
 
-static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_client_cert_add) (const char *
-                                                             cert_file,
-                                                             const char *
-                                                             crl_file,
-                                                             const char *
-                                                             key_file);
-static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (const char *cert);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cafile_add) (Ecore_Con_Server *svr, const char *ca_file);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_crl_add) (Ecore_Con_Server *svr, const char *crl_file);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (Ecore_Con_Server *svr, const char *cert);
+static Eina_Bool SSL_SUFFIX(_ecore_con_ssl_server_privkey_add) (Ecore_Con_Server *svr, const char *key_file);
 
 static Ecore_Con_Ssl_Error  SSL_SUFFIX(_ecore_con_ssl_server_prepare)(Ecore_Con_Server *svr, int ssl_type);
 static Ecore_Con_Ssl_Error
@@ -174,45 +171,11 @@ Ecore_Con_Ssl_Error
 ecore_con_ssl_shutdown(void)
 {
    if (!--_init_con_ssl_init_count)
-     {
-#if USE_OPENSSL || USE_GNUTLS
-        if (client_cert)
-           client_cert->count = 0;
-
-        if (server_cert)
-           server_cert->count = 0;
-#endif
-#if USE_OPENSSL && !USE_GNUTLS
-        if (private_key)
-           private_key->count = 0;
-
-#endif
-        SSL_SUFFIX(_ecore_con_ssl_shutdown) ();
-     }
+     SSL_SUFFIX(_ecore_con_ssl_shutdown) ();
 
    return _init_con_ssl_init_count;
 }
 
-/**
- * Returns if SSL support is available
- * @return 1 if SSL is available and provided by gnutls, 2 if provided by openssl,
- * 0 if it is not available.
- * @ingroup Ecore_Con_Client_Group
- */
-EAPI int
-ecore_con_ssl_available_get(void)
-{
-   return _ECORE_CON_SSL_AVAILABLE;
-}
-
-#if 0
-EAPI Eina_Bool
-ecore_con_ssl_server_reinit()
-{
-
-}
-#endif
-
 Ecore_Con_Ssl_Error
 ecore_con_ssl_server_prepare(Ecore_Con_Server *svr, int ssl_type)
 {
@@ -227,12 +190,6 @@ ecore_con_ssl_server_init(Ecore_Con_Server *svr)
    return SSL_SUFFIX(_ecore_con_ssl_server_init) (svr);
 }
 
-Eina_Bool
-ecore_con_ssl_server_cert_add(const char *cert)
-{
-   return SSL_SUFFIX(_ecore_con_ssl_server_cert_add) (cert);
-}
-
 Ecore_Con_Ssl_Error
 ecore_con_ssl_server_shutdown(Ecore_Con_Server *svr)
 {
@@ -263,15 +220,6 @@ ecore_con_ssl_client_init(Ecore_Con_Client *cl)
    return SSL_SUFFIX(_ecore_con_ssl_client_init) (cl);
 }
 
-Eina_Bool
-ecore_con_ssl_client_cert_add(const char *cert_file,
-                              const char *crl_file,
-                              const char *key_file)
-{
-   return SSL_SUFFIX(_ecore_con_ssl_client_cert_add) (cert_file, crl_file,
-                                                      key_file);
-}
-
 Ecore_Con_Ssl_Error
 ecore_con_ssl_client_shutdown(Ecore_Con_Client *cl)
 {
@@ -290,6 +238,140 @@ ecore_con_ssl_client_write(Ecore_Con_Client *cl, unsigned char *buf, int size)
    return SSL_SUFFIX(_ecore_con_ssl_client_write) (cl, buf, size);
 }
 
+/**
+ * @addtogroup Ecore_Con_SSL_Group Ecore Connection SSL Functions
+ *
+ * Functions that operate on Ecore connection objects pertaining to SSL.
+ *
+ * @{
+ */
+
+/**
+ * Returns if SSL support is available
+ * @return 1 if SSL is available and provided by gnutls, 2 if provided by openssl,
+ * 0 if it is not available.
+ * @ingroup Ecore_Con_Client_Group
+ */
+EAPI int
+ecore_con_ssl_available_get(void)
+{
+   return _ECORE_CON_SSL_AVAILABLE;
+}
+
+/**
+ * @brief Enable certificate verification on a server object
+ *
+ * Call this function on a server object before main loop has started
+ * to enable verification of certificates against loaded certificates.
+ * @param svr The server object
+ */
+EAPI void
+ecore_con_ssl_server_verify(Ecore_Con_Server *svr)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_verify");
+        return;
+     }
+   svr->verify = EINA_TRUE;
+}
+/**
+ * @brief Add an ssl certificate for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM certificate.
+ * Simply specify the cert here to use it in the server object for connecting or listening.
+ * If there is an error loading the certificate, an error will automatically be logged.
+ * @param cert The path to the certificate.
+ * @return EINA_FALSE if the file cannot be loaded, otherwise EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_cert_add(Ecore_Con_Server *svr,
+                              const char *cert)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_cert_add");
+        return EINA_FALSE;
+     }
+
+   return SSL_SUFFIX(_ecore_con_ssl_server_cert_add)(svr, cert);
+}
+
+/**
+ * @brief Add an ssl CA file for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM CA file.
+ * Simply specify the file here to use it in the server object for connecting or listening.
+ * If there is an error loading the CAs, an error will automatically be logged.
+ * @param ca_file The path to the CA file.
+ * @return EINA_FALSE if the file cannot be loaded, otherwise EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_cafile_add(Ecore_Con_Server *svr,
+                              const char *ca_file)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_cafile_add");
+        return EINA_FALSE;
+     }
+
+   return SSL_SUFFIX(_ecore_con_ssl_server_cafile_add)(svr, ca_file);
+}
+
+/**
+ * @brief Add an ssl private key for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM private key
+ * Simply specify the key file here to use it in the server object for connecting or listening.
+ * If there is an error loading the key, an error will automatically be logged.
+ * @param key_file The path to the key file.
+ * @return EINA_FALSE if the file cannot be loaded,
+ * otherwise EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_privkey_add(Ecore_Con_Server *svr,
+                              const char *key_file)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_privkey_add");
+        return EINA_FALSE;
+     }
+
+   return SSL_SUFFIX(_ecore_con_ssl_server_privkey_add)(svr, key_file);
+}
+
+/**
+ * @brief Add an ssl CRL for use in ecore_con functions.
+ *
+ * Use this function to add a SSL PEM CRL file
+ * Simply specify the CRL file here to use it in the server object for connecting or listening.
+ * If there is an error loading the CRL, an error will automatically be logged.
+ * @param crl_file The path to the CRL file.
+ * @return EINA_FALSE if the file cannot be loaded,
+ * otherwise EINA_TRUE.
+ */
+
+EAPI Eina_Bool
+ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr,
+                              const char *crl_file)
+{
+   if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER))
+     {
+        ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, "ecore_con_ssl_server_crl_add");
+        return EINA_FALSE;
+     }
+
+   return SSL_SUFFIX(_ecore_con_ssl_server_crl_add)(svr, crl_file);
+}
+
+/** }@ */
+
 #if USE_GNUTLS
 
 /*
@@ -320,26 +402,11 @@ _ecore_con_ssl_shutdown_gnutls(void)
 }
 
 static Ecore_Con_Ssl_Error
-_ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *svr, int ssl_type)
+_ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *svr, int ssl_type __UNUSED__)
 {
    int ret;
 
-   if ((ssl_type & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT)
-     {
-        if ((server_cert) && (server_cert->cert) && (svr->created))
-          { /* load server cert */
-             svr->cert = server_cert->cert;
-             server_cert->count++;
-          }
-        else if ((client_cert) && (client_cert->cert))
-          { /* load client cert */
-             svr->cert = client_cert->cert;
-             client_cert->count++;
-          }
-     }
-   else
-     /* if LOAD_CERT is not specified, allocate here */
-     SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_allocate_credentials(&svr->cert));
+   SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_allocate_credentials(&svr->cert));
 
    if (svr->created)
      {
@@ -363,7 +430,7 @@ _ecore_con_ssl_server_prepare_gnutls(Ecore_Con_Server *svr, int ssl_type)
    return ECORE_CON_SSL_ERROR_NONE;
 
 error:
-   ERR("gnutls returned with error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
+   _gnutls_print_errors(ret);
    _ecore_con_ssl_server_shutdown_gnutls(svr);
    return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
 }
@@ -375,6 +442,9 @@ error:
 static Ecore_Con_Ssl_Error
 _ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr)
 {
+   const gnutls_datum_t *cert_list;
+   unsigned int iter, cert_list_size;
+   gnutls_x509_crt_t cert = NULL;
    const int *proto = NULL;
    const int compress[] = { GNUTLS_COMP_DEFLATE, GNUTLS_COMP_NULL, 0 };
    int ret = 0;
@@ -461,50 +531,109 @@ _ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr)
       default:
         break;
      }
+   if (svr->ssl_state != ECORE_CON_SSL_STATE_DONE)
+     return ECORE_CON_SSL_ERROR_NONE;
+
+   if (!svr->verify)
+     /* not verifying certificates, so we're done! */
+     return ECORE_CON_SSL_ERROR_NONE;
+   ret = 0;
+   /* use CRL/CA lists to verify */
+   SSL_ERROR_CHECK_GOTO_ERROR(ret = gnutls_certificate_verify_peers2(svr->session, &iter));
+   if (iter & GNUTLS_CERT_INVALID)
+     ERR("The certificate is not trusted.");
+   else if (iter & GNUTLS_CERT_SIGNER_NOT_FOUND)
+     ERR ("The certificate hasn't got a known issuer.");
+   else if (iter & GNUTLS_CERT_REVOKED)
+     ERR ("The certificate has been revoked.");
+   else if (iter & GNUTLS_CERT_EXPIRED)
+     ERR ("The certificate has expired");
+   else if (iter & GNUTLS_CERT_NOT_ACTIVATED)
+     ERR ("The certificate is not yet activated");
+
+   if (iter)
+     goto error;
+
+   if (gnutls_certificate_type_get(svr->session) != GNUTLS_CRT_X509)
+     {
+        ERR("Warning: PGP certificates are not yet supported!");
+        goto error;
+     }
+
+
+   SSL_ERROR_CHECK_GOTO_ERROR(!(cert_list = gnutls_certificate_get_peers(svr->session, &cert_list_size)));
+   SSL_ERROR_CHECK_GOTO_ERROR(!cert_list_size);
 
+   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_init(&cert));
+   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER));
+
+   SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->name));
+   gnutls_x509_crt_deinit(cert);
    return ECORE_CON_SSL_ERROR_NONE;
 
 error:
-   ERR("gnutls returned with error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
+   _gnutls_print_errors(ret);
    if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
      ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(svr->session)));
-   ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(svr->session)));
-   ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(svr->session)));
+   if (svr->ssl_state != ECORE_CON_SSL_STATE_DONE)
+     {
+       ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(svr->session)));
+       ERR("last in: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(svr->session)));
+     }
+   if (cert)
+     gnutls_x509_crt_deinit(cert);
    _ecore_con_ssl_server_shutdown_gnutls(svr);
    return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
 }
 
 static Eina_Bool
-_ecore_con_ssl_server_cert_add_gnutls(const char *cert_file)
+_ecore_con_ssl_server_cafile_add_gnutls(Ecore_Con_Server *svr, const char *ca_file)
 {
-   gnutls_certificate_credentials_t cert = NULL;
-
-   /* cert load */
-   if (gnutls_certificate_set_x509_trust_file(cert, cert_file,
-                                              GNUTLS_X509_FMT_PEM) < 0)
-      goto on_error;
+   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_trust_file(svr->cert, ca_file,
+                                              GNUTLS_X509_FMT_PEM) < 1);
 
-   if (!server_cert)
-     {
-        server_cert = malloc(sizeof(gnutls));
-        if (!server_cert)
-           return EINA_FALSE;
-     }
-   else if ((server_cert->cert) && ((--server_cert->count) < 1))
-      gnutls_certificate_free_credentials(server_cert->cert);
+   return EINA_TRUE;
+error:
+   ERR("Could not load CA file!");
+   return EINA_FALSE;
+}
 
-   server_cert->cert = cert;
-   server_cert->count = 1;
+static Eina_Bool
+_ecore_con_ssl_server_crl_add_gnutls(Ecore_Con_Server *svr, const char *crl_file)
+{
+   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_crl_file(svr->cert, crl_file,
+                                            GNUTLS_X509_FMT_PEM) < 1);
 
    return EINA_TRUE;
+error:
+   ERR("Could not load CRL file!");
+   return EINA_FALSE;
+}
 
-on_error:
-   if (cert)
-      gnutls_certificate_free_credentials(cert);
 
+static Eina_Bool
+_ecore_con_ssl_server_privkey_add_gnutls(Ecore_Con_Server *svr, const char *key_file)
+{
+   SSL_ERROR_CHECK_GOTO_ERROR(gnutls_certificate_set_x509_key_file(svr->cert, svr->cert_file, key_file,
+                                            GNUTLS_X509_FMT_PEM) < 1);
+
+   return EINA_TRUE;
+error:
+   ERR("Could not load certificate/key file!");
    return EINA_FALSE;
 }
 
+
+static Eina_Bool
+_ecore_con_ssl_server_cert_add_gnutls(Ecore_Con_Server *svr, const char *cert_file)
+{
+   if (!(svr->cert_file = strdup(cert_file)))
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+
 static Ecore_Con_Ssl_Error
 _ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *svr)
 {
@@ -514,18 +643,15 @@ _ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *svr)
         gnutls_deinit(svr->session);
      }
 
+   if (svr->cert_file)
+     free(svr->cert_file);
+   svr->cert_file = NULL;
+   if (svr->cert)
+     gnutls_certificate_free_credentials(svr->cert);
+   svr->cert = NULL;
+
    if ((svr->type & ECORE_CON_SSL) && svr->created)
      {
-        if ((server_cert) && (--server_cert->count < 1) && (svr->cert == server_cert->cert))
-          { /* only ever free this if it is used and dead */
-             gnutls_certificate_free_credentials(server_cert->cert);
-             free(server_cert);
-             server_cert = NULL;
-          }
-        else if (svr->cert && ((!server_cert) || (svr->cert != server_cert->cert)))
-          /* otherwise just free the anon cert */
-          gnutls_certificate_free_credentials(svr->cert);
-
         if (svr->dh_params)
           {
              gnutls_dh_params_deinit(svr->dh_params);
@@ -541,16 +667,6 @@ _ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *svr)
      }
    else if (svr->type & ECORE_CON_SSL)
      {
-        if ((client_cert) && (--client_cert->count < 1) && (svr->cert == client_cert->cert))
-          { /* only ever free this if it is used and dead */
-             gnutls_certificate_free_credentials(client_cert->cert);
-             free(client_cert);
-             client_cert = NULL;
-          }
-        else if (svr->cert && ((!client_cert) || (svr->cert != client_cert->cert)))
-          /* otherwise just free the anon cert */
-          gnutls_certificate_free_credentials(svr->cert);
-
         if (svr->anoncred_c)
           gnutls_anon_free_client_credentials(svr->anoncred_c);
         if (svr->pskcred_c)
@@ -561,7 +677,6 @@ _ecore_con_ssl_server_shutdown_gnutls(Ecore_Con_Server *svr)
      }
 
    svr->session = NULL;
-   svr->cert = NULL;
 
    return ECORE_CON_SSL_ERROR_NONE;
 }
@@ -736,7 +851,7 @@ _ecore_con_ssl_client_init_gnutls(Ecore_Con_Client *cl)
    return ECORE_CON_SSL_ERROR_NONE;
 
 error:
-   ERR("gnutls returned with error: %s - %s", gnutls_strerror_name(ret), gnutls_strerror(ret));
+   _gnutls_print_errors(ret);
    if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == GNUTLS_E_FATAL_ALERT_RECEIVED))
      ERR("Also received alert: %s", gnutls_alert_get_name(gnutls_alert_get(cl->session)));
    ERR("last out: %s", SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(cl->session)));
@@ -756,69 +871,11 @@ _ecore_con_ssl_client_shutdown_gnutls(Ecore_Con_Client *cl)
         cl->session_ticket.data = NULL;
      }
 
-   if (((cl->host_server->type & ECORE_CON_TYPE) & ECORE_CON_LOAD_CERT) &&
-       (client_cert) &&
-       (client_cert->cert) && (--client_cert->count < 1))
-     {
-        free(client_cert);
-        client_cert = NULL;
-     }
-
    cl->session = NULL;
 
    return ECORE_CON_SSL_ERROR_NONE;
 }
 
-static Eina_Bool
-_ecore_con_ssl_client_cert_add_gnutls(const char *cert_file,
-                                      const char *crl_file __UNUSED__,
-                                      const char *key_file)
-{
-   gnutls_certificate_credentials_t cert = NULL;
-
-   if (gnutls_certificate_allocate_credentials(&cert) < 0)
-      return EINA_FALSE;
-
-   /* cert load */
-   if (gnutls_certificate_set_x509_trust_file(cert, cert_file,
-                                              GNUTLS_X509_FMT_PEM) < 0)
-      goto on_error;
-
-   /* private key load */
-   if (gnutls_certificate_set_x509_key_file(cert, cert_file, key_file,
-                                            GNUTLS_X509_FMT_PEM) < 0)
-      goto on_error;
-
-#if 0
-   //TODO: uncomment once we implement cert checking
-   if (crl_file)
-      /* CRL file load */
-      if (gnutls_certificate_set_x509_crl_mem(cert, crl_file,
-                                              GNUTLS_X509_FMT_PEM) < 0)
-         goto on_error;
-
-}
-#endif
-   if (!client_cert)
-     {
-        client_cert = malloc(sizeof(gnutls));
-        if (!client_cert)
-           return EINA_FALSE;
-     }
-   else if ((client_cert->cert) && ((--client_cert->count) < 1))
-      gnutls_certificate_free_credentials(client_cert->cert);
-
-   client_cert->cert = cert;
-   client_cert->count = 1;
-
-   return EINA_TRUE;
-
-on_error:
-   if (cert)
-      gnutls_certificate_free_credentials(cert);
-
-   return EINA_FALSE;
-}
 
 static int
 _ecore_con_ssl_client_read_gnutls(Ecore_Con_Client *cl, unsigned char *buf,
@@ -952,25 +1009,7 @@ _ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *svr, int ssl_type)
          break;
      }
 
-   if ((client_cert) && (client_cert->cert) && (private_key->key) && (svr->created) &&
-       ((ssl_type & ECORE_CON_LOAD_CERT) == ECORE_CON_LOAD_CERT))
-     { /* this is a server */
-        SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_certificate(svr->ssl_ctx, client_cert->cert) < 1);
-        SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_PrivateKey(svr->ssl_ctx, private_key->key) < 1);
-        SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_check_private_key(svr->ssl_ctx) < 1);
-
-        client_cert->count++;
-        private_key->count++;
-     }
-
-   if ((server_cert) && (server_cert->cert) && (!svr->created) &&
-       ((ssl_type & ECORE_CON_LOAD_CERT)))
-     { /* this is a client */
-        SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_certificate(svr->ssl_ctx, server_cert->cert) < 1);
-
-        server_cert->count++;
-     }
-   else if (!(ssl_type & ECORE_CON_LOAD_CERT) && svr->created)
+   if ((!svr->use_cert) && svr->created)
      {
         DH *dh_params;
         SSL_ERROR_CHECK_GOTO_ERROR(!(dh_params = DH_new()));
@@ -982,7 +1021,7 @@ _ecore_con_ssl_server_prepare_openssl(Ecore_Con_Server *svr, int ssl_type)
         DH_free(dh_params);
         SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:@STRENGTH"));
      }
-   else if (!(ssl_type & ECORE_CON_LOAD_CERT))
+   else if (!svr->use_cert)
      SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_set_cipher_list(svr->ssl_ctx, "aNULL:!eNULL:!LOW:!EXPORT:!ECDH:RSA:AES:!PSK:@STRENGTH"));
 
      return ECORE_CON_SSL_ERROR_NONE;
@@ -996,18 +1035,14 @@ error:
           ERR("openssl error: dh_params could not generate a safe prime!");
      }
    else
-     do
-       {
-          unsigned long err;
-
-          err = ERR_get_error();
-          if (!err) break;
-          ERR("openssl error: %s", ERR_reason_error_string(err));
-       } while (1);
+     _openssl_print_errors();
    _ecore_con_ssl_server_shutdown_openssl(svr);
    return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
 }
 
+
+
+
 static Ecore_Con_Ssl_Error
 _ecore_con_ssl_server_init_openssl(Ecore_Con_Server *svr)
 {
@@ -1040,51 +1075,90 @@ _ecore_con_ssl_server_init_openssl(Ecore_Con_Server *svr)
    return ECORE_CON_SSL_ERROR_NONE;
 
 error:
-   do
-     {
-        unsigned long sslerr;
-
-        sslerr = ERR_get_error();
-        if (!sslerr) break;
-        ERR("openssl error: %s", ERR_reason_error_string(sslerr));
-     } while (1);
+   _openssl_print_errors();
    _ecore_con_ssl_server_shutdown_openssl(svr);
    return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
 }
 
 static Eina_Bool
-_ecore_con_ssl_server_cert_add_openssl(const char *cert_file)
+_ecore_con_ssl_server_cafile_add_openssl(Ecore_Con_Server *svr, const char *ca_file)
 {
-   FILE *fp = NULL;
-   X509 *cert = NULL;
+   SSL_ERROR_CHECK_GOTO_ERROR(!SSL_CTX_load_verify_locations(svr->ssl_ctx, ca_file, NULL));
+   return EINA_TRUE;
 
-   if (!(fp = fopen(cert_file, "r")))
-      goto on_error;
+error:
+   _openssl_print_errors();
+   return EINA_FALSE;
+}
 
-   if (!(cert = PEM_read_X509(fp, NULL, NULL, NULL)))
-      goto on_error;
+static Eina_Bool
+_ecore_con_ssl_server_crl_add_openssl(Ecore_Con_Server *svr, const char *crl_file)
+{
+   FILE *fp = NULL;
+   X509_CRL *crl = NULL;
+
+   if (!(fp = fopen(crl_file, "r")))
+      goto error;
+#warning IMPLEMENT FIXME!
+   SSL_ERROR_CHECK_GOTO_ERROR(!(crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL)));
 
    fclose(fp);
 
-   if (!server_cert)
-     {
-        server_cert = malloc(sizeof(openssl));
-        if (!server_cert)
-           return EINA_FALSE;
-     }
-   else if ((server_cert->cert) && ((--server_cert->count) < 1))
-      X509_free(server_cert->cert);
+   return EINA_TRUE;
 
-   server_cert->cert = cert;
+error:
+   if (fp)
+      fclose(fp);
+   _openssl_print_errors();
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_privkey_add_openssl(Ecore_Con_Server *svr, const char *key_file)
+{
+   FILE *fp = NULL;
+   EVP_PKEY *privkey = NULL;
+
+   if (!(fp = fopen(key_file, "r")))
+      goto error;
+
+   SSL_ERROR_CHECK_GOTO_ERROR(!(privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)));
 
-   server_cert->count = 1;
+   fclose(fp);
+   SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_PrivateKey(svr->ssl_ctx, privkey) < 1);
+   SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_check_private_key(svr->ssl_ctx) < 1);
 
    return EINA_TRUE;
 
-on_error:
+error:
    if (fp)
       fclose(fp);
+   _openssl_print_errors();
+   return EINA_FALSE;
+}
+
+
+static Eina_Bool
+_ecore_con_ssl_server_cert_add_openssl(Ecore_Con_Server *svr, const char *cert_file)
+{
+   FILE *fp = NULL;
+   X509 *cert = NULL;
+
+   if (!(fp = fopen(cert_file, "r")))
+      goto error;
+
+   SSL_ERROR_CHECK_GOTO_ERROR(!(cert = PEM_read_X509(fp, NULL, NULL, NULL)));
+
+   fclose(fp);
+
+   SSL_ERROR_CHECK_GOTO_ERROR(SSL_CTX_use_certificate(svr->ssl_ctx, cert) < 1);
 
+   return EINA_TRUE;
+
+error:
+   if (fp)
+      fclose(fp);
+   _openssl_print_errors();
    return EINA_FALSE;
 }
 
@@ -1099,15 +1173,6 @@ _ecore_con_ssl_server_shutdown_openssl(Ecore_Con_Server *svr)
         SSL_free(svr->ssl);
      }
 
-   if (((svr->type & ECORE_CON_TYPE) & ECORE_CON_LOAD_CERT) &&
-       (server_cert) && (server_cert->cert) &&
-       (--server_cert->count < 1))
-     {
-        X509_free(server_cert->cert);
-        free(server_cert);
-        server_cert = NULL;
-     }
-
    if (svr->ssl_ctx)
       SSL_CTX_free(svr->ssl_ctx);
 
@@ -1247,83 +1312,12 @@ _ecore_con_ssl_client_init_openssl(Ecore_Con_Client *cl)
    return ECORE_CON_SSL_ERROR_NONE;
 
 error:
-   do
-     {
-        unsigned long sslerr;
-
-        sslerr = ERR_get_error();
-        if (!sslerr) break;
-        ERR("openssl error: %s", ERR_reason_error_string(sslerr));
-     } while (1);
+   _openssl_print_errors();
    _ecore_con_ssl_client_shutdown_openssl(cl);
    return ECORE_CON_SSL_ERROR_SERVER_INIT_FAILED;
 }
 
 
-static Eina_Bool
-_ecore_con_ssl_client_cert_add_openssl(const char *cert_file,
-                                       const char *crl_file __UNUSED__,
-                                       const char *key_file)
-{
-   FILE *fp = NULL;
-   EVP_PKEY *privkey = NULL;
-   X509 *cert = NULL;
-
-   if (!(fp = fopen(cert_file, "r")))
-      goto on_error;
-
-   if (!(cert = PEM_read_X509(fp, NULL, NULL, NULL)))
-      goto on_error;
-
-   if (key_file)
-     {
-        fclose(fp);
-        if (!(fp = fopen(key_file, "r")))
-           goto on_error;
-     }
-
-   if (!(privkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)))
-      goto on_error;
-
-        fclose(fp);
-
-   if (!client_cert)
-     {
-        client_cert = malloc(sizeof(openssl));
-           if (!client_cert)
-           return EINA_FALSE;
-     }
-   else if ((client_cert->cert) && (--client_cert->count < 1))
-      X509_free(client_cert->cert);
-
-   if (!private_key)
-     {
-        private_key = malloc(sizeof(openssl_pkey));
-           if (!private_key) return EINA_FALSE;
-     }
-   else if ((private_key->key) && ((--private_key->count) < 1))
-      EVP_PKEY_free(private_key->key);
-
-   private_key->key = privkey;
-   client_cert->cert = cert;
-
-   private_key->count = client_cert->count = 1;
-
-   return EINA_TRUE;
-
-on_error:
-   if (fp)
-      fclose(fp);
-
-   if (cert)
-      X509_free(cert);
-
-   if (privkey)
-      EVP_PKEY_free(privkey);
-
-   return EINA_FALSE;
-}
-
 static Ecore_Con_Ssl_Error
 _ecore_con_ssl_client_shutdown_openssl(Ecore_Con_Client *cl)
 {
@@ -1438,9 +1432,27 @@ _ecore_con_ssl_server_init_none(Ecore_Con_Server *svr __UNUSED__)
 }
 
 static Eina_Bool
-_ecore_con_ssl_server_cert_add_none(const char *cert_file __UNUSED__)
+_ecore_con_ssl_server_cafile_add_none(Ecore_Con_Server *svr __UNUSED__, const char *ca_file __UNUSED__)
 {
-   return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_cert_add_none(Ecore_Con_Server *svr __UNUSED__, const char *cert_file __UNUSED__)
+{
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_privkey_add_none(Ecore_Con_Server *svr __UNUSED__, const char *key_file __UNUSED__)
+{
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_ecore_con_ssl_server_crl_add_none(Ecore_Con_Server *svr __UNUSED__, const char *crl_file __UNUSED__)
+{
+   return EINA_FALSE;
 }
 
 static Ecore_Con_Ssl_Error
@@ -1479,14 +1491,6 @@ _ecore_con_ssl_client_init_none(Ecore_Con_Client *cl __UNUSED__)
    return ECORE_CON_SSL_ERROR_NOT_SUPPORTED;
 }
 
-static Eina_Bool
-_ecore_con_ssl_client_cert_add_none(const char *cert_file __UNUSED__,
-                                    const char *crl_file __UNUSED__,
-                                    const char *key_file __UNUSED__)
-{
-   return EINA_TRUE;
-}
-
 static Ecore_Con_Ssl_Error
 _ecore_con_ssl_client_shutdown_none(Ecore_Con_Client *cl __UNUSED__)
 {