diff --git a/legacy/ecore/ChangeLog b/legacy/ecore/ChangeLog index d62ec30d5e..d572522a9b 100644 --- a/legacy/ecore/ChangeLog +++ b/legacy/ecore/ChangeLog @@ -388,3 +388,4 @@ 2011-12-07 Mike Blumenkrantz * Allow SSL certificates to be loaded for STARTTLS + * Added functions to set/get the hostname used for SSL certificate verification diff --git a/legacy/ecore/NEWS b/legacy/ecore/NEWS index bfce1ebba9..dfe0d8749c 100644 --- a/legacy/ecore/NEWS +++ b/legacy/ecore/NEWS @@ -8,6 +8,7 @@ Additions: - ecore_timer_reset() * ecore_con - ecore_con_socks api + - ecore_con_ssl_server_verify_name_set/get * ecore_x: - ecore_x_randr_output_backlight_available() diff --git a/legacy/ecore/src/lib/ecore_con/Ecore_Con.h b/legacy/ecore/src/lib/ecore_con/Ecore_Con.h index 61f1eb580b..56c914b1b6 100644 --- a/legacy/ecore/src/lib/ecore_con/Ecore_Con.h +++ b/legacy/ecore/src/lib/ecore_con/Ecore_Con.h @@ -707,6 +707,8 @@ EAPI Eina_Bool ecore_con_ssl_server_crl_add(Ecore_Con_Server *svr, const 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); EAPI void ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr); +EAPI void ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name); +EAPI const char *ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr); EAPI Eina_Bool ecore_con_ssl_server_upgrade(Ecore_Con_Server *svr, Ecore_Con_Type compl_type); EAPI Eina_Bool ecore_con_ssl_client_upgrade(Ecore_Con_Client *cl, Ecore_Con_Type compl_type); diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con.c b/legacy/ecore/src/lib/ecore_con/ecore_con.c index 5c0fbc1a1f..da59dc54e0 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con.c +++ b/legacy/ecore/src/lib/ecore_con/ecore_con.c @@ -1264,6 +1264,7 @@ _ecore_con_server_free(Ecore_Con_Server *svr) free(svr->path); eina_stringshare_del(svr->ip); + eina_stringshare_del(svr->verify_name); if (svr->ecs_buf) eina_binbuf_free(svr->ecs_buf); if (svr->ecs_recvbuf) eina_binbuf_free(svr->ecs_recvbuf); diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con_private.h b/legacy/ecore/src/lib/ecore_con/ecore_con_private.h index 532c1a837c..85e4722054 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con_private.h +++ b/legacy/ecore/src/lib/ecore_con/ecore_con_private.h @@ -150,6 +150,7 @@ struct _Ecore_Con_Server const char *proxyip; int proxyport; /* endsocks */ + const char *verify_name; #if USE_GNUTLS gnutls_session_t session; gnutls_anon_client_credentials_t anoncred_c; diff --git a/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c b/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c index 3b528464c0..0461e4b752 100644 --- a/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c +++ b/legacy/ecore/src/lib/ecore_con/ecore_con_ssl.c @@ -355,6 +355,51 @@ ecore_con_ssl_server_verify_basic(Ecore_Con_Server *svr) svr->verify_basic = EINA_TRUE; } +/** + * @brief Set the hostname to verify against in certificate verification + * + * Sometimes the certificate hostname will not match the hostname that you are + * connecting to, and will instead match a different name. An example of this is + * that if you connect to talk.google.com to use Google Talk, you receive Google's + * certificate for gmail.com. This certificate should be trusted, and so you must call + * this function with "gmail.com" as @p name. + * See RFC2818 for more details. + * @param svr The server object + * @param name The hostname to verify against + * @since 1.2 + */ +EAPI void +ecore_con_ssl_server_verify_name_set(Ecore_Con_Server *svr, const char *name) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return; + } + eina_stringshare_replace(&svr->verify_name, name); +} + +/** + * @brief Get the hostname to verify against in certificate verification + * + * This function returns the name which will be used to validate the SSL certificate + * common name (CN) or alt name (subjectAltName). It will default to the @p name + * param in ecore_con_server_connect(), but can be changed with ecore_con_ssl_server_verify_name_set(). + * @param svr The server object + * @return The hostname which will be used + * @since 1.2 + */ +EAPI const char * +ecore_con_ssl_server_verify_name_get(Ecore_Con_Server *svr) +{ + if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_CON_SERVER)) + { + ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_CON_SERVER, __func__); + return NULL; + } + return svr->verify_name ?: svr->name; +} + /** * @brief Add an ssl certificate for use in ecore_con functions. * @@ -764,8 +809,28 @@ _ecore_con_ssl_server_init_gnutls(Ecore_Con_Server *svr) 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)); +#ifdef ISCOMFITOR + { + size_t clen = 0; + char *c; + gnutls_x509_crt_get_subject_alt_name(cert, 0, NULL, &clen, NULL); + if (clen++) + { + c = alloca(clen); + gnutls_x509_crt_get_subject_alt_name(cert, 0, c, &clen, NULL); + } + else + { + gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, NULL, &clen); + SSL_ERROR_CHECK_GOTO_ERROR(!clen); + c = alloca(++clen); + gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, c, &clen); + } + INF("CERT NAME: %s\n", c); + } +#endif - SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->name)); + SSL_ERROR_CHECK_GOTO_ERROR(!gnutls_x509_crt_check_hostname(cert, svr->verify_name ?: svr->name)); gnutls_x509_crt_deinit(cert); DBG("SSL certificate verification succeeded!"); return ECORE_CON_SSL_ERROR_NONE; @@ -1344,17 +1409,24 @@ _ecore_con_ssl_server_init_openssl(Ecore_Con_Server *svr) cert = SSL_get_peer_certificate(svr->ssl); if (cert) { - char buf[256] = {0}; + char *c; + size_t clen; + ASN1_OBJECT *obj = NULL; + if (svr->verify) SSL_ERROR_CHECK_GOTO_ERROR(SSL_get_verify_result(svr->ssl)); - X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, buf, sizeof(buf)); - if (buf[0]) - SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(buf, svr->name)); + clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_subject_alt_name, NULL, 0); + if (clen) + obj = NID_subject_alt_name; else - { - X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, buf, sizeof(buf)); - SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(buf, svr->name)); - } + clen = X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, NULL, 0); + SSL_ERROR_CHECK_GOTO_ERROR(!clen); + if (!obj) obj = NID_commonName; + c = alloca(++clen); + X509_NAME_get_text_by_NID(X509_get_subject_name(cert), obj, c, clen); + INF("CERT NAME: %s\n", c); + SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(buf, svr->verify_name ?: svr->name)); + SSL_ERROR_CHECK_GOTO_ERROR(!_openssl_name_verify(buf, svr->verify_name ?: svr->name)); } }