Example #1
0
static ioa_socket_handle dtls_server_input_handler(dtls_listener_relay_server_type* server,
				ioa_socket_handle s,
				ioa_network_buffer_handle nbh)
{
	FUNCSTART;

	if (!server || !nbh) {
		return NULL;
	}

	SSL* connecting_ssl = NULL;

	BIO *wbio = NULL;
	struct timeval timeout;

	/* Create BIO */
	wbio = BIO_new_dgram(s->fd, BIO_NOCLOSE);
	(void)BIO_dgram_set_peer(wbio, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr));

	/* Set and activate timeouts */
	timeout.tv_sec = DTLS_MAX_RECV_TIMEOUT;
	timeout.tv_usec = 0;
	BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);

#if DTLSv1_2_SUPPORTED
	if(get_dtls_version(ioa_network_buffer_data(nbh),
							(int)ioa_network_buffer_get_size(nbh)) == 1) {
		connecting_ssl = SSL_NEW(server->dtls_ctx_v1_2);
	} else {
		connecting_ssl = SSL_NEW(server->dtls_ctx);
	}
#else
	{
		connecting_ssl = SSL_NEW(server->dtls_ctx);
	}
#endif

	SSL_set_accept_state(connecting_ssl);

	SSL_set_bio(connecting_ssl, NULL, wbio);
	SSL_set_options(connecting_ssl, SSL_OP_COOKIE_EXCHANGE);

	SSL_set_max_cert_list(connecting_ssl, 655350);

	ioa_socket_handle rc = dtls_accept_client_connection(server, s, connecting_ssl,
					&(server->sm.m.sm.nd.src_addr),
					&(server->addr),
					nbh);

	if (!rc) {
		if (!(SSL_get_shutdown(connecting_ssl) & SSL_SENT_SHUTDOWN)) {
			SSL_set_shutdown(connecting_ssl, SSL_RECEIVED_SHUTDOWN);
			SSL_shutdown(connecting_ssl);
		}
		SSL_FREE(connecting_ssl);
	}

	return rc;
}
Example #2
0
/*
 * Password retrieval
 */
int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh)
{
	int ret = -1;

	if(max_session_time)
		*max_session_time = 0;

	if(in_oauth && out_oauth && usname && usname[0]) {

		stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh),
								ioa_network_buffer_get_size(nbh),
								STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN);
		if(sar) {

			int len = stun_attr_get_len(sar);
			const u08bits *value = stun_attr_get_value(sar);

			*out_oauth = 1;

			if(len>0 && value) {

				const turn_dbdriver_t * dbd = get_dbdriver();

				if (dbd && dbd->get_oauth_key) {

					oauth_key_data_raw rawKey;
					ns_bzero(&rawKey,sizeof(rawKey));

					int gres = (*(dbd->get_oauth_key))(usname,&rawKey);
					if(gres<0)
						return ret;

					if(!rawKey.kid[0])
						return ret;

					if(rawKey.lifetime) {
						if(!turn_time_before(turn_time(),(turn_time_t)(rawKey.timestamp + rawKey.lifetime+OAUTH_TIME_DELTA))) {
							return ret;
						}
					}

					oauth_key_data okd;
					ns_bzero(&okd,sizeof(okd));

					convert_oauth_key_data_raw(&rawKey, &okd);

					char err_msg[1025] = "\0";
					size_t err_msg_size = sizeof(err_msg) - 1;

					oauth_key okey;
					ns_bzero(&okey,sizeof(okey));

					if (convert_oauth_key_data(&okd, &okey, err_msg, err_msg_size) < 0) {
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s\n", err_msg);
						return -1;
					}

					oauth_token dot;
					ns_bzero((&dot),sizeof(dot));

					encoded_oauth_token etoken;
					ns_bzero(&etoken,sizeof(etoken));

					if((size_t)len > sizeof(etoken.token)) {
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Encoded oAuth token is too large\n");
						return -1;
					}
					ns_bcopy(value,etoken.token,(size_t)len);
					etoken.size = (size_t)len;

					const char* server_name = (char*)turn_params.oauth_server_name;
					if(!(server_name && server_name[0])) {
						server_name = (char*)realm;
						if(!(server_name && server_name[0])) {
							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot determine oAuth server name");
							return -1;
						}
					}

					if (decode_oauth_token((const u08bits *) server_name, &etoken,&okey, &dot) < 0) {
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot decode oauth token\n");
						return -1;
					}

					switch(dot.enc_block.key_length) {
					case SHA1SIZEBYTES:
						if(turn_params.shatype != SHATYPE_SHA1) {
							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(1): %d\n",(int)dot.enc_block.key_length);
							return -1;
						}
						break;
					case SHA256SIZEBYTES:
						if(turn_params.shatype != SHATYPE_SHA256) {
							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(2): %d\n",(int)dot.enc_block.key_length);
							return -1;
						}
						break;
					case SHA384SIZEBYTES:
						if(turn_params.shatype != SHATYPE_SHA384) {
							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length);
							return -1;
						}
						break;
					case SHA512SIZEBYTES:
						if(turn_params.shatype != SHATYPE_SHA512) {
							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length);
							return -1;
						}
						break;
					default:
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length);
						return -1;
					};

					password_t pwdtmp;
					if(stun_check_message_integrity_by_key_str(TURN_CREDENTIALS_LONG_TERM,
								ioa_network_buffer_data(nbh),
								ioa_network_buffer_get_size(nbh),
								dot.enc_block.mac_key,
								pwdtmp,
								turn_params.shatype,NULL)>0) {

						turn_time_t lifetime = (turn_time_t)(dot.enc_block.lifetime);
						if(lifetime) {
							turn_time_t ts = (turn_time_t)(dot.enc_block.timestamp >> 16);
							turn_time_t to = ts + lifetime + OAUTH_TIME_DELTA;
							turn_time_t ct = turn_time();
							if(!turn_time_before(ct,to)) {
								TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "oAuth token is too old\n");
								return -1;
							}
							if(max_session_time) {
								*max_session_time = to - ct;
							}
						}

						ns_bcopy(dot.enc_block.mac_key,key,dot.enc_block.key_length);

						ret = 0;
					}
				}
			}
void udp_send_message(dtls_listener_relay_server_type *server, ioa_network_buffer_handle nbh, ioa_addr *dest)
{
	if(server && dest && nbh && (server->udp_listen_s))
		udp_send(server->udp_listen_s, dest, (s08bits*)ioa_network_buffer_data(nbh), (int)ioa_network_buffer_get_size(nbh));
}
static int handle_udp_packet(dtls_listener_relay_server_type *server,
				struct message_to_relay *sm,
				ioa_engine_handle ioa_eng, turn_turnserver *ts)
{
	int verbose = ioa_eng->verbose;
	ioa_socket_handle s = sm->m.sm.s;

	ur_addr_map_value_type mvt = 0;
	ur_addr_map *amap = server->children_ss;

	ioa_socket_handle chs = NULL;
	if ((ur_addr_map_get(amap, &(sm->m.sm.nd.src_addr), &mvt) > 0) && mvt) {
		chs = (ioa_socket_handle) mvt;
	}

	if (chs && !ioa_socket_tobeclosed(chs)
			&& (chs->sockets_container == amap)
			&& (chs->magic == SOCKET_MAGIC)) {
		s = chs;
		sm->m.sm.s = s;
		if(s->ssl) {
			int read_len = (int)ioa_network_buffer_get_size(sm->m.sm.nd.nbh);
			int sslret = ssl_read(s->fd, s->ssl, (s08bits*)ioa_network_buffer_data(sm->m.sm.nd.nbh),
				(int)ioa_network_buffer_get_capacity(),
				verbose, &read_len);
			if(sslret < 0) {
				ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
				sm->m.sm.nd.nbh = NULL;
				ts_ur_super_session *ss = (ts_ur_super_session *) s->session;
				if (ss) {
					turn_turnserver *server = (turn_turnserver *) ss->server;
					if (server) {
						shutdown_client_connection(server, ss);
					}
				} else {
					close_ioa_socket(s);
				}
				ur_addr_map_del(amap, &(sm->m.sm.nd.src_addr), NULL);
				sm->m.sm.s = NULL;
				s = NULL;
				chs = NULL;
			} else if(read_len>0) {
				ioa_network_buffer_set_size(sm->m.sm.nd.nbh,(size_t)read_len);
			} else {
				ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
				sm->m.sm.nd.nbh = NULL;
			}
		}

		if (s && s->read_cb && sm->m.sm.nd.nbh) {
			s->e = ioa_eng;
			s->read_cb(s, IOA_EV_READ, &(sm->m.sm.nd), s->read_ctx);
			ioa_network_buffer_delete(ioa_eng, sm->m.sm.nd.nbh);
			sm->m.sm.nd.nbh = NULL;

			if (ioa_socket_tobeclosed(s)) {
				ts_ur_super_session *ss = (ts_ur_super_session *) s->session;
				if (ss) {
					turn_turnserver *server = (turn_turnserver *) ss->server;
					if (server) {
						shutdown_client_connection(server, ss);
					}
				}
			}
		}
	} else {
		if (chs && ioa_socket_tobeclosed(chs)) {
			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
					"%s: socket to be closed\n", __FUNCTION__);
			{
				u08bits saddr[129];
				u08bits rsaddr[129];
				long thrid = 0;
#if !defined(TURN_NO_THREADS)
				thrid = (long) pthread_self();
#endif
				addr_to_string(get_local_addr_from_ioa_socket(chs),saddr);
				addr_to_string(get_remote_addr_from_ioa_socket(chs),rsaddr);
				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
					"%s: thrid=0x%lx: Amap = 0x%lx, socket container=0x%lx, local addr %s, remote addr %s, s=0x%lx, done=%d, tbc=%d\n",
					__FUNCTION__, thrid, (long) amap,
					(long) (chs->sockets_container), (char*) saddr,
					(char*) rsaddr, (long) s, (int) (chs->done),
					(int) (chs->tobeclosed));
			}
		}

		if (chs && (chs->magic != SOCKET_MAGIC)) {
			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
					"%s: wrong socket magic\n", __FUNCTION__);
		}

		if (chs && (chs->sockets_container != amap)) {
			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
					"%s: wrong socket container\n", __FUNCTION__);
			{
				u08bits saddr[129];
				u08bits rsaddr[129];
				long thrid = 0;
#if !defined(TURN_NO_THREADS)
				thrid = (long) pthread_self();
#endif
				addr_to_string(get_local_addr_from_ioa_socket(chs),saddr);
				addr_to_string(get_remote_addr_from_ioa_socket(chs),rsaddr);
				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
					"%s: thrid=0x%lx: Amap = 0x%lx, socket container=0x%lx, local addr %s, remote addr %s, s=0x%lx, done=%d, tbc=%d, st=%d, sat=%d\n",
					__FUNCTION__, thrid, (long) amap,
					(long) (chs->sockets_container), (char*) saddr,
					(char*) rsaddr, (long) chs, (int) (chs->done),
					(int) (chs->tobeclosed), (int) (chs->st),
					(int) (chs->sat));
			}
		}

		chs = NULL;

#if !defined(TURN_NO_DTLS)
		if (!no_dtls &&
			is_dtls_handshake_message(ioa_network_buffer_data(sm->m.sm.nd.nbh),
			(int)ioa_network_buffer_get_size(sm->m.sm.nd.nbh))) {
			chs = dtls_server_input_handler(server,
				ioa_network_buffer_data(sm->m.sm.nd.nbh),
				(int)ioa_network_buffer_get_size(sm->m.sm.nd.nbh));
			ioa_network_buffer_delete(server->e, sm->m.sm.nd.nbh);
			sm->m.sm.nd.nbh = NULL;
		}
#endif

		if(!chs) {
			chs = create_ioa_socket_from_fd(ioa_eng, s->fd, s,
				UDP_SOCKET, CLIENT_SOCKET, &(sm->m.sm.nd.src_addr),
				get_local_addr_from_ioa_socket(s));
		}

		s = chs;
		sm->m.sm.s = s;

		if (s) {
			if(verbose) {
				u08bits saddr[129];
				u08bits rsaddr[129];
				addr_to_string(get_local_addr_from_ioa_socket(s),saddr);
				addr_to_string(get_remote_addr_from_ioa_socket(s),rsaddr);
				TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
					"%s: New UDP endpoint: local addr %s, remote addr %s\n",
					__FUNCTION__, (char*) saddr,(char*) rsaddr);
			}
			s->e = ioa_eng;
			add_socket_to_map(s, amap);
			open_client_connection_session(ts, &(sm->m.sm));
		}
	}

	return 0;
}
Example #5
0
static int create_new_connected_udp_socket(
		dtls_listener_relay_server_type* server, ioa_socket_handle s)
{

	evutil_socket_t udp_fd = socket(s->local_addr.ss.sa_family, CLIENT_DGRAM_SOCKET_TYPE, CLIENT_DGRAM_SOCKET_PROTOCOL);
	if (udp_fd < 0) {
		perror("socket");
		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s: Cannot allocate new socket\n",
				__FUNCTION__);
		return -1;
	}

	if (sock_bind_to_device(udp_fd, (unsigned char*) (s->e->relay_ifname))
			< 0) {
		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
				"Cannot bind udp server socket to device %s\n",
				(char*) (s->e->relay_ifname));
	}

	ioa_socket_handle ret = (ioa_socket*) turn_malloc(sizeof(ioa_socket));
	if (!ret) {
		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
				"%s: Cannot allocate new socket structure\n", __FUNCTION__);
		close(udp_fd);
		return -1;
	}

	ns_bzero(ret, sizeof(ioa_socket));

	ret->magic = SOCKET_MAGIC;

	ret->fd = udp_fd;

	ret->family = s->family;
	ret->st = s->st;
	ret->sat = CLIENT_SOCKET;
	ret->local_addr_known = 1;
	addr_cpy(&(ret->local_addr), &(s->local_addr));

	if (addr_bind(udp_fd,&(s->local_addr),1,1,UDP_SOCKET) < 0) {
		TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
				"Cannot bind new detached udp server socket to local addr\n");
		IOA_CLOSE_SOCKET(ret);
		return -1;
	}
	ret->bound = 1;

	{
		int connect_err = 0;
		if (addr_connect(udp_fd, &(server->sm.m.sm.nd.src_addr), &connect_err) < 0) {
			char sl[129];
			char sr[129];
			addr_to_string(&(ret->local_addr),(u08bits*)sl);
			addr_to_string(&(server->sm.m.sm.nd.src_addr),(u08bits*)sr);
			TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
					"Cannot connect new detached udp client socket from local addr %s to remote addr %s\n",sl,sr);
			IOA_CLOSE_SOCKET(ret);
			return -1;
		}
	}
	ret->connected = 1;
	addr_cpy(&(ret->remote_addr), &(server->sm.m.sm.nd.src_addr));

	set_socket_options(ret);

	ret->current_ttl = s->current_ttl;
	ret->default_ttl = s->default_ttl;

	ret->current_tos = s->current_tos;
	ret->default_tos = s->default_tos;

#if DTLS_SUPPORTED
	if (!turn_params.no_dtls
			&& is_dtls_handshake_message(
					ioa_network_buffer_data(server->sm.m.sm.nd.nbh),
					(int) ioa_network_buffer_get_size(
							server->sm.m.sm.nd.nbh))) {

		SSL* connecting_ssl = NULL;

		BIO *wbio = NULL;
		struct timeval timeout;

		/* Create BIO */
		wbio = BIO_new_dgram(ret->fd, BIO_NOCLOSE);
		(void) BIO_dgram_set_peer(wbio, (struct sockaddr*) &(server->sm.m.sm.nd.src_addr));

		BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &(server->sm.m.sm.nd.src_addr));

		/* Set and activate timeouts */
		timeout.tv_sec = DTLS_MAX_RECV_TIMEOUT;
		timeout.tv_usec = 0;
		BIO_ctrl(wbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);

#if DTLSv1_2_SUPPORTED
		if(get_dtls_version(ioa_network_buffer_data(server->sm.m.sm.nd.nbh),
							(int)ioa_network_buffer_get_size(server->sm.m.sm.nd.nbh)) == 1) {
			connecting_ssl = SSL_NEW(server->dtls_ctx_v1_2);
		} else {
			connecting_ssl = SSL_NEW(server->dtls_ctx);
		}
#else
		{
			connecting_ssl = SSL_NEW(server->dtls_ctx);
		}
#endif

		SSL_set_accept_state(connecting_ssl);

		SSL_set_bio(connecting_ssl, NULL, wbio);

		SSL_set_options(connecting_ssl, SSL_OP_COOKIE_EXCHANGE);
		SSL_set_max_cert_list(connecting_ssl, 655350);
		int rc = ssl_read(ret->fd, connecting_ssl, server->sm.m.sm.nd.nbh,
				server->verbose);

		if (rc < 0) {
			if (!(SSL_get_shutdown(connecting_ssl) & SSL_SENT_SHUTDOWN)) {
				SSL_set_shutdown(connecting_ssl, SSL_RECEIVED_SHUTDOWN);
				SSL_shutdown(connecting_ssl);
			}
			SSL_FREE(connecting_ssl);
			IOA_CLOSE_SOCKET(ret);
			return -1;
		}

		addr_debug_print(server->verbose, &(server->sm.m.sm.nd.src_addr),
				"Accepted DTLS connection from");

		ret->ssl = connecting_ssl;

		ioa_network_buffer_delete(server->e, server->sm.m.sm.nd.nbh);
		server->sm.m.sm.nd.nbh = NULL;

		ret->st = DTLS_SOCKET;
	}
#endif

	server->sm.m.sm.s = ret;
	return server->connect_cb(server->e, &(server->sm));
}
Example #6
0
/*
 * Password retrieval
 */
int get_user_key(int in_oauth, int *out_oauth, int *max_session_time, u08bits *usname, u08bits *realm, hmackey_t key, ioa_network_buffer_handle nbh)
{

    /* Decode certificate */
    struct certificate cert;
    memset(&cert, 0, sizeof cert);
    unsigned char const *secret_key = (unsigned char *)turn_params.secret_key;
    unsigned char const *iv = (unsigned char *)turn_params.secret_iv;
    
    stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh), ioa_network_buffer_get_size(nbh), STUN_ATTRIBUTE_SOFTWARE);
    if (sar)
    {
        int token_len = stun_attr_get_len(sar);
        const u08bits* token_ptr = stun_attr_get_value(sar);
        u08bits token[128];
        memcpy(token, token_ptr, token_len);
        token[token_len]=0;
        int err = stun_check_message_certificate(token, token_len, &cert, secret_key, iv);
        if(token_len && err == 0)
         {
             const char* password = cert.call_id;
             size_t sz = get_hmackey_size(SHATYPE_DEFAULT) * 2;
             
             char skey[sizeof(hmackey_t) * 2 + 1];
             password2hmac(password, usname, realm, skey);
             
             if(convert_string_key_to_binary(skey, key, sz / 2) < 0) {
                 TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong key: %s, user %s\n", skey, usname);
             }

             char buff[20];
             struct tm * timeinfo;
             timeinfo = localtime (&cert.deadline);
             strftime(buff, sizeof(buff), "%Y %b %d %H:%M", timeinfo);
             
             time_t     now;
             now = time(NULL);
             
       /*      if(now - cert.deadline < -60 || // server's time's wrong? more tann 60 sec time diff
                now - cert.deadline > 60*60*24 ) // too much diff, something wrong
             {
                 TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Token expired: user: %s token: %s time: %s time_diff: %d sec\n", usname, token, buff, now - cert.deadline);
                 return -1;
             } */

             TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO, "Token decrypted: user:%s seq:%s time:%s call:%s \n", usname, cert.seq, buff, cert.call_id);
             return 0;
         }
        else
        {
            TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Incorrect token: user %s token: %s Error: %d\n", usname, token, err);
            return -1;
        }
    }
    else
        TURN_LOG_FUNC(TURN_LOG_LEVEL_WARNING, "Tokent not found: user %s\n", usname);
    
    int ret = -1;
    
	if(max_session_time)
		*max_session_time = 0;

	if(in_oauth && out_oauth && usname && usname[0]) {

		stun_attr_ref sar = stun_attr_get_first_by_type_str(ioa_network_buffer_data(nbh),
								ioa_network_buffer_get_size(nbh),
								STUN_ATTRIBUTE_OAUTH_ACCESS_TOKEN);
		if(sar) {

			int len = stun_attr_get_len(sar);
			const u08bits *value = stun_attr_get_value(sar);

			*out_oauth = 1;

			if(len>0 && value) {

				const turn_dbdriver_t * dbd = get_dbdriver();

				if (dbd && dbd->get_oauth_key) {

					oauth_key_data_raw rawKey;
					ns_bzero(&rawKey,sizeof(rawKey));

					int gres = (*(dbd->get_oauth_key))(usname,&rawKey);
					if(gres<0)
						return ret;

					if(!rawKey.kid[0])
						return ret;

					if(rawKey.lifetime) {
						if(!turn_time_before(turn_time(),(turn_time_t)(rawKey.timestamp + rawKey.lifetime+OAUTH_TIME_DELTA))) {
							return ret;
						}
					}

					oauth_key_data okd;
					ns_bzero(&okd,sizeof(okd));

					convert_oauth_key_data_raw(&rawKey, &okd);

					char err_msg[1025] = "\0";
					size_t err_msg_size = sizeof(err_msg) - 1;

					oauth_key okey;
					ns_bzero(&okey,sizeof(okey));

					if (convert_oauth_key_data(&okd, &okey, err_msg, err_msg_size) < 0) {
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "%s\n", err_msg);
						return -1;
					}

					oauth_token dot;
					ns_bzero((&dot),sizeof(dot));

					encoded_oauth_token etoken;
					ns_bzero(&etoken,sizeof(etoken));

					if((size_t)len > sizeof(etoken.token)) {
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Encoded oAuth token is too large\n");
						return -1;
					}
					ns_bcopy(value,etoken.token,(size_t)len);
					etoken.size = (size_t)len;

					const char* server_name = (char*)turn_params.oauth_server_name;
					if(!(server_name && server_name[0])) {
						server_name = (char*)realm;
						if(!(server_name && server_name[0])) {
							TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot determine oAuth server name");
							return -1;
						}
					}

					if (decode_oauth_token((const u08bits *) server_name, &etoken,&okey, &dot) < 0) {
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Cannot decode oauth token\n");
						return -1;
					}

					switch(dot.enc_block.key_length) {
					case SHA1SIZEBYTES:
						break;
					case SHA256SIZEBYTES:
					case SHA384SIZEBYTES:
					case SHA512SIZEBYTES:
					default:
						TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "Wrong size of the MAC key in oAuth token(3): %d\n",(int)dot.enc_block.key_length);
						return -1;
					};

					password_t pwdtmp;
					if(stun_check_message_integrity_by_key_str(TURN_CREDENTIALS_LONG_TERM,
								ioa_network_buffer_data(nbh),
								ioa_network_buffer_get_size(nbh),
								dot.enc_block.mac_key,
								pwdtmp,
								SHATYPE_DEFAULT)>0) {

						turn_time_t lifetime = (turn_time_t)(dot.enc_block.lifetime);
						if(lifetime) {
							turn_time_t ts = (turn_time_t)(dot.enc_block.timestamp >> 16);
							turn_time_t to = ts + lifetime + OAUTH_TIME_DELTA;
							turn_time_t ct = turn_time();
							if(!turn_time_before(ct,to)) {
								TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR, "oAuth token is too old\n");
								return -1;
							}
							if(max_session_time) {
								*max_session_time = to - ct;
							}
						}

						ns_bcopy(dot.enc_block.mac_key,key,dot.enc_block.key_length);

						ret = 0;
					}
				}
			}