*
* TODO:
* - double-check queueing logic
- * - actually check SSL certificates (#3038)
*/
#include "platform.h"
#include <microhttpd.h>
#include <gnutls/x509.h>
#include <gnutls/abstract.h>
#include <gnutls/crypto.h>
+#if HAVE_GNUTLS_DANE
+#include <gnutls/dane.h>
+#endif
#include <regex.h>
#include "gnunet_util_lib.h"
#include "gnunet_gns_service.h"
*/
char *leho;
+ /**
+ * Payload of the (last) DANE record encountered.
+ */
+ char *dane_data;
+
/**
* The URL to fetch
*/
*/
unsigned int response_code;
+ /**
+ * Number of bytes in @e dane_data.
+ */
+ size_t dane_data_len;
+
/**
* Number of bytes already in read buffer
*/
GNUNET_free_non_null (s5r->domain);
GNUNET_free_non_null (s5r->leho);
GNUNET_free_non_null (s5r->url);
+ GNUNET_free_non_null (s5r->dane_data);
GNUNET_free (s5r);
}
static int
check_ssl_certificate (struct Socks5Request *s5r)
{
- struct curl_tlsinfo tlsinfo;
unsigned int cert_list_size;
const gnutls_datum_t *chainp;
- union {
- struct curl_tlsinfo *tlsinfo;
- struct curl_slist *to_slist;
- } gptr;
+ const struct curl_tlssessioninfo *tlsinfo;
char certdn[GNUNET_DNSPARSER_MAX_NAME_LENGTH + 3];
size_t size;
- gnutls_x509_crt x509_cert;
+ gnutls_x509_crt_t x509_cert;
int rc;
const char *name;
- memset (&tlsinfo, 0, sizeof (tlsinfo));
- gptr.tlsinfo = &tlsinfo;
if (CURLE_OK !=
curl_easy_getinfo (s5r->curl,
CURLINFO_TLS_SESSION,
- &gptr))
+ (struct curl_slist **) &tlsinfo))
return GNUNET_SYSERR;
- if (CURLSSLBACKEND_GNUTLS != tlsinfo.ssl_backend)
+ if (CURLSSLBACKEND_GNUTLS != tlsinfo->backend)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
_("Unsupported CURL SSL backend %d\n"),
- tlsinfo.ssl_backend);
+ tlsinfo->backend);
return GNUNET_SYSERR;
}
- chainp = gnutls_certificate_get_peers (tlsinfo.internals, &cert_list_size);
+ chainp = gnutls_certificate_get_peers (tlsinfo->internals, &cert_list_size);
if ( (! chainp) || (0 == cert_list_size) )
return GNUNET_SYSERR;
&size)))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to fetch CN from cert: %s\n",
+ _("Failed to fetch CN from cert: %s\n"),
gnutls_strerror(rc));
gnutls_x509_crt_deinit (x509_cert);
return GNUNET_SYSERR;
}
- /* FIXME: here we should check for TLSA/DANE records */
-
- name = s5r->domain;
- if (NULL != s5r->leho)
- name = s5r->leho;
- if (NULL != name)
+ /* check for TLSA/DANE records */
+#if HAVE_GNUTLS_DANE
+ if (NULL != s5r->dane_data)
{
- if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
- name)))
+ char *dd[] = { s5r->dane_data, NULL };
+ int dlen[] = { s5r->dane_data_len, 0};
+ dane_state_t dane_state;
+ dane_query_t dane_query;
+ unsigned int verify;
+
+ /* FIXME: add flags to gnutls to NOT read UNBOUND_ROOT_KEY_FILE here! */
+ if (0 != (rc = dane_state_init (&dane_state,
+#ifdef DANE_F_IGNORE_DNSSEC
+ DANE_F_IGNORE_DNSSEC |
+#endif
+ DANE_F_IGNORE_LOCAL_RESOLVER)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to initialize DANE: %s\n"),
+ dane_strerror(rc));
+ gnutls_x509_crt_deinit (x509_cert);
+ return GNUNET_SYSERR;
+ }
+ if (0 != (rc = dane_raw_tlsa (dane_state,
+ &dane_query,
+ dd,
+ dlen,
+ GNUNET_YES,
+ GNUNET_NO)))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("SSL certificate subject name (%s) does not match `%s'\n"),
- certdn,
- name);
+ _("Failed to parse DANE record: %s\n"),
+ dane_strerror(rc));
+ dane_state_deinit (dane_state);
gnutls_x509_crt_deinit (x509_cert);
return GNUNET_SYSERR;
}
+ if (0 != (rc = dane_verify_crt_raw (dane_state,
+ chainp,
+ cert_list_size,
+ gnutls_certificate_type_get (tlsinfo->internals),
+ dane_query,
+ 0, 0,
+ &verify)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed to verify TLS connection using DANE: %s\n"),
+ dane_strerror(rc));
+ dane_query_deinit (dane_query);
+ dane_state_deinit (dane_state);
+ gnutls_x509_crt_deinit (x509_cert);
+ return GNUNET_SYSERR;
+ }
+ if (0 != verify)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Failed DANE verification failed with GnuTLS verify status code: %u\n"),
+ verify);
+ dane_query_deinit (dane_query);
+ dane_state_deinit (dane_state);
+ gnutls_x509_crt_deinit (x509_cert);
+ return GNUNET_SYSERR;
+ }
+ dane_query_deinit (dane_query);
+ dane_state_deinit (dane_state);
+ /* success! */
}
else
+#endif
{
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- _("No LEHO or domain name available and TLSA/DANE is not yet implemented!\n"));
- return GNUNET_SYSERR;
- }
- gnutls_x509_crt_deinit (x509_cert);
-#if 0
- {
- unsigned int i;
-
- for(i=0;i<cert_list_size;i++)
- {
- gnutls_x509_crt_t cert;
- gnutls_datum_t dn;
-
- if (GNUTLS_E_SUCCESS == gnutls_x509_crt_init (&cert))
+ /* try LEHO or ordinary domain name X509 verification */
+ name = s5r->domain;
+ if (NULL != s5r->leho)
+ name = s5r->leho;
+ if (NULL != name)
{
- if (GNUTLS_E_SUCCESS ==
- gnutls_x509_crt_import (cert, &chainp[i],
- GNUTLS_X509_FMT_DER))
+ if (0 == (rc = gnutls_x509_crt_check_hostname (x509_cert,
+ name)))
{
- if (GNUTLS_E_SUCCESS ==
- gnutls_x509_crt_print (cert,
- GNUTLS_CRT_PRINT_FULL,
- &dn))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Certificate #%d: %.*s", i, dn.size, dn.data);
- gnutls_free (dn.data);
- }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("SSL certificate subject name (%s) does not match `%s'\n"),
+ certdn,
+ name);
+ gnutls_x509_crt_deinit (x509_cert);
+ return GNUNET_SYSERR;
}
- gnutls_x509_crt_deinit (cert);
+ }
+ else
+ {
+ /* we did not even have the domain name!? */
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
}
- }
-#endif
+ gnutls_x509_crt_deinit (x509_cert);
return GNUNET_OK;
}
GNUNET_break (CURLE_OK ==
curl_easy_getinfo (msg->easy_handle,
CURLINFO_PRIVATE,
- &s5r));
+ (char **) &s5r ));
if (NULL == s5r)
{
GNUNET_break (0);
size_t *upload_data_size,
void **con_cls)
{
- /* struct MhdHttpList* hd = cls; */
struct Socks5Request *s5r = *con_cls;
char *curlurl;
char ipstring[INET6_ADDRSTRLEN];
return s5r;
}
}
+ GNUNET_break (0);
return NULL;
}
GNUNET_break (GNUTLS_E_SUCCESS == gnutls_x509_crt_set_key (request, proxy_ca.key));
pgc = GNUNET_new (struct ProxyGNSCertificate);
gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_COUNTRY_NAME,
- 0, "TNR", 2);
+ 0, "ZZ", 2);
gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_ORGANIZATION_NAME,
0, "GNU Name System", 4);
gnutls_x509_crt_set_dn_by_oid (request, GNUTLS_OID_X520_COMMON_NAME,
* Lookup (or create) an SSL MHD instance for a particular domain.
*
* @param domain the domain the SSL daemon has to serve
- * @return NULL on errro
+ * @return NULL on error
*/
static struct MhdHttpList *
lookup_ssl_httpd (const char* domain)
struct MhdHttpList *hd;
struct ProxyGNSCertificate *pgc;
+ if (NULL == domain)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
for (hd = mhd_httpd_head; NULL != hd; hd = hd->next)
if ( (NULL != hd->domain) &&
(0 == strcmp (hd->domain, domain)) )
s5r->leho = GNUNET_strndup (r->data,
r->data_size);
break;
+ case GNUNET_DNSPARSER_TYPE_TLSA:
+ GNUNET_free_non_null (s5r->dane_data);
+ s5r->dane_data_len = r->data_size;
+ s5r->dane_data = GNUNET_malloc (r->data_size);
+ memcpy (s5r->dane_data,
+ r->data,
+ r->data_size);
+ break;
default:
/* don't care */
break;
struct sockaddr_in *in;
s5r->port = ntohs (*port);
+ if (HTTPS_PORT == s5r->port)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("SSL connection to plain IPv4 address requested\n"));
+ signal_socks_failure (s5r,
+ SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE);
+ return;
+ }
alen = sizeof (struct in_addr);
if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) +
alen + sizeof (uint16_t))
struct sockaddr_in6 *in;
s5r->port = ntohs (*port);
+ if (HTTPS_PORT == s5r->port)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("SSL connection to plain IPv4 address requested\n"));
+ signal_socks_failure (s5r,
+ SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE);
+ return;
+ }
alen = sizeof (struct in6_addr);
if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) +
alen + sizeof (uint16_t))