Ejemplo n.º 1
0
/**
 * gnutls_server_name_set:
 * @session: is a #gnutls_session_t type.
 * @type: specifies the indicator type
 * @name: is a string that contains the server name.
 * @name_length: holds the length of name
 *
 * This function is to be used by clients that want to inform (via a
 * TLS extension mechanism) the server of the name they connected to.
 * This should be used by clients that connect to servers that do
 * virtual hosting.
 *
 * The value of @name depends on the @type type.  In case of
 * %GNUTLS_NAME_DNS, a UTF-8 null-terminated domain name string,
 * without the trailing dot, is expected.
 *
 * IPv4 or IPv6 addresses are not permitted to be set by this function.
 * If the function is called with a name of @name_length zero it will clear
 * all server names set.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
 *   otherwise a negative error code is returned.
 **/
int
gnutls_server_name_set(gnutls_session_t session,
		       gnutls_server_name_type_t type,
		       const void *name, size_t name_length)
{
	int ret;
	gnutls_datum_t idn_name = {NULL,0};

	if (session->security_parameters.entity == GNUTLS_SERVER) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	if (name_length == 0) { /* unset extension */
		_gnutls_ext_unset_session_data(session, GNUTLS_EXTENSION_SERVER_NAME);
		return 0;
	}

	ret = gnutls_idna_map(name, name_length, &idn_name, 0);
	if (ret < 0) {
		 _gnutls_debug_log("unable to convert name %s to IDNA2003 format\n", (char*)name);
		 return ret;
	}

	name = idn_name.data;
	name_length = idn_name.size;

	ret = _gnutls_server_name_set_raw(session, type, name, name_length);
	gnutls_free(idn_name.data);

	return ret;
}
Ejemplo n.º 2
0
/**
 * gnutls_server_name_get:
 * @session: is a #gnutls_session_t type.
 * @data: will hold the data
 * @data_length: will hold the data length. Must hold the maximum size of data.
 * @type: will hold the server name indicator type
 * @indx: is the index of the server_name
 *
 * This function will allow you to get the name indication (if any), a
 * client has sent.  The name indication may be any of the enumeration
 * gnutls_server_name_type_t.
 *
 * If @type is GNUTLS_NAME_DNS, then this function is to be used by
 * servers that support virtual hosting, and the data will be a null
 * terminated IDNA ACE string (prior to GnuTLS 3.4.0 it was a UTF-8 string).
 *
 * If @data has not enough size to hold the server name
 * GNUTLS_E_SHORT_MEMORY_BUFFER is returned, and @data_length will
 * hold the required size.
 *
 * @index is used to retrieve more than one server names (if sent by
 * the client).  The first server name has an index of 0, the second 1
 * and so on.  If no name with the given index exists
 * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, on UTF-8
 *  decoding error %GNUTLS_E_IDNA_ERROR is returned, otherwise a negative
 *  error code is returned.
 **/
int
gnutls_server_name_get(gnutls_session_t session, void *data,
		       size_t * data_length,
		       unsigned int *type, unsigned int indx)
{
	char *_data = data;
	server_name_ext_st *priv;
	int ret;
	gnutls_datum_t idn_name = {NULL,0};
	extension_priv_data_t epriv;

	if (session->security_parameters.entity == GNUTLS_CLIENT) {
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	ret =
	    _gnutls_ext_get_session_data(session,
					 GNUTLS_EXTENSION_SERVER_NAME,
					 &epriv);
	if (ret < 0) {
		gnutls_assert();
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

	priv = epriv;

	if (indx + 1 > priv->server_names_size) {
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
	}

	*type = priv->server_names[indx].type;

	ret = gnutls_idna_map((char*)priv->server_names[indx].name, priv->server_names[indx].name_length, &idn_name, 0);
	if (ret < 0) {
		 _gnutls_debug_log("unable to convert name %s to IDNA2003 format\n", (char*)priv->server_names[indx].name);
		 return GNUTLS_E_IDNA_ERROR;
	}

	if (*data_length >	/* greater since we need one extra byte for the null */
	    idn_name.size) {
		*data_length = idn_name.size;
		memcpy(data, idn_name.data, *data_length);

		if (*type == GNUTLS_NAME_DNS)	/* null terminate */
			_data[(*data_length)] = 0;

	} else {
		*data_length = idn_name.size + 1;
		ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
		goto cleanup;
	}

	ret = 0;
 cleanup:
	gnutls_free(idn_name.data);
	return ret;
}
Ejemplo n.º 3
0
void
socket_open(socket_st * hd, const char *hostname, const char *service,
	    const char *app_proto, int flags, const char *msg, gnutls_datum_t *rdata)
{
	struct addrinfo hints, *res, *ptr;
	int sd, err = 0;
	int udp = flags & SOCKET_FLAG_UDP;
	int ret;
	int fastopen = flags & SOCKET_FLAG_FASTOPEN;
	char buffer[MAX_BUF + 1];
	char portname[16] = { 0 };
	gnutls_datum_t idna;
	char *a_hostname;

	memset(hd, 0, sizeof(*hd));

	if (flags & SOCKET_FLAG_VERBOSE)
		hd->verbose = 1;

	if (rdata) {
		hd->rdata.data = rdata->data;
		hd->rdata.size = rdata->size;
	}

	ret = gnutls_idna_map(hostname, strlen(hostname), &idna, 0);
	if (ret < 0) {
		fprintf(stderr, "Cannot convert %s to IDNA: %s\n", hostname, gnutls_strerror(ret));
		exit(1);
	}

	hd->hostname = strdup(hostname);
	a_hostname = (char*)idna.data;

	if (msg != NULL)
		printf("Resolving '%s:%s'...\n", a_hostname, service);

	/* get server name */
	memset(&hints, 0, sizeof(hints));
	hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM;
	if ((err = getaddrinfo(a_hostname, service, &hints, &res))) {
		fprintf(stderr, "Cannot resolve %s:%s: %s\n", hostname,
			service, gai_strerror(err));
		exit(1);
	}

	sd = -1;
	for (ptr = res; ptr != NULL; ptr = ptr->ai_next) {
		sd = socket(ptr->ai_family, ptr->ai_socktype,
			    ptr->ai_protocol);
		if (sd == -1)
			continue;

		if ((err =
		     getnameinfo(ptr->ai_addr, ptr->ai_addrlen, buffer,
				 MAX_BUF, portname, sizeof(portname),
				 NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
			fprintf(stderr, "getnameinfo(): %s\n",
				gai_strerror(err));
			continue;
		}

		if (hints.ai_socktype == SOCK_DGRAM) {
#if defined(IP_DONTFRAG)
			int yes = 1;
			if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAG,
				       (const void *) &yes,
				       sizeof(yes)) < 0)
				perror("setsockopt(IP_DF) failed");
#elif defined(IP_MTU_DISCOVER)
			int yes = IP_PMTUDISC_DO;
			if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER,
				       (const void *) &yes,
				       sizeof(yes)) < 0)
				perror("setsockopt(IP_DF) failed");
#endif
		}

		if (fastopen && ptr->ai_socktype == SOCK_STREAM
		    && (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)) {
			memcpy(&hd->connect_addr, ptr->ai_addr, ptr->ai_addrlen);
			hd->connect_addrlen = ptr->ai_addrlen;

			if (msg)
				printf("%s '%s:%s' (TFO)...\n", msg, buffer, portname);

		} else {
			if (msg)
				printf("%s '%s:%s'...\n", msg, buffer, portname);

			if ((err = connect(sd, ptr->ai_addr, ptr->ai_addrlen)) < 0)
				continue;
		}

		hd->fd = sd;
		if (flags & SOCKET_FLAG_STARTTLS) {
			hd->app_proto = app_proto;
			socket_starttls(hd);
			hd->app_proto = NULL;
		}

		if (!(flags & SOCKET_FLAG_SKIP_INIT)) {
			hd->session = init_tls_session(hostname);
			if (hd->session == NULL) {
				fprintf(stderr, "error initializing session\n");
				exit(1);
			}
		}

		if (hd->session) {
			if (hd->rdata.data) {
				gnutls_session_set_data(hd->session, hd->rdata.data, hd->rdata.size);
			}

			gnutls_transport_set_int(hd->session, sd);
		}

		if (!(flags & SOCKET_FLAG_RAW) && !(flags & SOCKET_FLAG_SKIP_INIT)) {
			err = do_handshake(hd);
			if (err == GNUTLS_E_PUSH_ERROR) { /* failed connecting */
				gnutls_deinit(hd->session);
				hd->session = NULL;
				continue;
			}
			else if (err < 0) {
				fprintf(stderr, "*** handshake has failed: %s\n", gnutls_strerror(err));
				exit(1);
			}
		}

		break;
	}

	if (err != 0) {
		int e = errno;
		fprintf(stderr, "Could not connect to %s:%s: %s\n",
				buffer, portname, strerror(e));
		exit(1);
	}

	if (sd == -1) {
		fprintf(stderr, "Could not find a supported socket\n");
		exit(1);
	}

	if ((flags & SOCKET_FLAG_RAW) || (flags & SOCKET_FLAG_SKIP_INIT))
		hd->secure = 0;
	else
		hd->secure = 1;

	hd->fd = sd;
	hd->ip = strdup(buffer);
	hd->service = strdup(portname);
	hd->ptr = ptr;
	hd->addr_info = res;
	hd->rdata.data = NULL;
	gnutls_free(idna.data);
	return;
}