Example #1
0
QString StunClient::getStunAddress(QByteArray resp, uint16_t attr_type)
{
    stun_buffer buf;
    u08bits addr_buff[STUN_BUFFER_SIZE] = {0};

    buf.len = resp.length();
    memcpy(buf.buf, resp.data(), resp.length());

    uint16_t t_attr_type;
    const u08bits *attr_value;
    int attr_len;
    ioa_addr stun_addr;
    stun_attr_ref raw_attr = stun_attr_get_first_str(buf.buf, buf.len);
    for ( ; raw_attr ; raw_attr = stun_attr_get_next_str(buf.buf, buf.len, raw_attr)) {
        t_attr_type = stun_attr_get_type(raw_attr);
        attr_value = stun_attr_get_value(raw_attr);
        attr_len = stun_attr_get_len(raw_attr);

        if (t_attr_type == attr_type) {
            stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &stun_addr, NULL);
            addr_to_string(&stun_addr, (u08bits*)addr_buff);
            break;
        }
    }

    return QString((char*)addr_buff);
}
Example #2
0
int read_mobility_ticket(app_ur_conn_info *clnet_info, stun_buffer *message)
{
	int ret = 0;
	if(clnet_info && message) {
		stun_attr_ref s_mobile_id_sar = stun_attr_get_first_by_type(message, STUN_ATTRIBUTE_MOBILITY_TICKET);
		if(s_mobile_id_sar) {
			int smid_len = stun_attr_get_len(s_mobile_id_sar);
			if(smid_len>0 && (((size_t)smid_len)<sizeof(clnet_info->s_mobile_id))) {
				const u08bits* smid_val = stun_attr_get_value(s_mobile_id_sar);
				if(smid_val) {
					ns_bcopy(smid_val, clnet_info->s_mobile_id, (size_t)smid_len);
					clnet_info->s_mobile_id[smid_len] = 0;
					if (clnet_verbose)
						TURN_LOG_FUNC(TURN_LOG_LEVEL_INFO,
									"%s: smid=%s\n", __FUNCTION__, clnet_info->s_mobile_id);
				}
			} else {
				TURN_LOG_FUNC(TURN_LOG_LEVEL_ERROR,
							"%s: ERROR: smid_len=%d\n", __FUNCTION__, smid_len);
				ret = -1;
			}
		}
	}
	return ret;
}
Example #3
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;
					}
				}
			}
Example #4
0
void StunClient::debugStunResponse(QByteArray resp)
{
    u08bits rbuf[STUN_BUFFER_SIZE];
    size_t rlen = 0;
    stun_buffer buf;
    u08bits addr_buff[STUN_BUFFER_SIZE] = {0};

    rlen = resp.length();
    memcpy(rbuf, resp.data(), resp.length());

    buf.len = resp.length();
    memcpy(buf.buf, resp.data(), resp.length());

    if (!stun_is_command_message(&buf)) {
        qDebug()<<resp.length()<<("The response is not a STUN message\n");
        return;
    }

    if (!stun_is_response(&buf)) {
        qDebug()<<resp.length()<<("The response is not a reponse message\n");
        // return;
    }

    u16bits stun_method;
    u16bits stun_msg_type;
    stun_method = stun_get_method_str(buf.buf, buf.len);
    stun_msg_type = stun_get_msg_type_str(buf.buf, buf.len);
    qDebug()<<"method:"<<stun_method<<getMethodName(stun_method)<<",msg type:"<<stun_msg_type;

    int attr_type;
    const u08bits *attr_value;
    int attr_len;
    char relayed_addr_str[32] = {0};
    char mapped_addr_str[32] = {0};
    char addr_str[32] = {0};
    ioa_addr relayed_addr;
    ioa_addr mapped_addr;
    ioa_addr stun_addr;
    uint32_t lifetime = 0;
    uint32_t bandwidth = 0;
    stun_attr_ref raw_attr = stun_attr_get_first_str(buf.buf, buf.len);
    for ( ; raw_attr ; raw_attr = stun_attr_get_next_str(buf.buf, buf.len, raw_attr)) {
        attr_type = stun_attr_get_type(raw_attr);
        attr_value = stun_attr_get_value(raw_attr);
        attr_len = stun_attr_get_len(raw_attr);

        switch (attr_type) {
        case STUN_ATTRIBUTE_SOFTWARE:
            qDebug()<<"attr software:"<<QByteArray((char*)attr_value, attr_len);
            break;
        case STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS:
            stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &mapped_addr, NULL);
            addr_to_string(&mapped_addr, (u08bits*)mapped_addr_str);
            qDebug()<<"mapped addr:"<<mapped_addr_str;
            break;
        case STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS:
            stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &relayed_addr, NULL);
            addr_to_string(&relayed_addr, (u08bits*)relayed_addr_str);
            qDebug()<<"relayed addr:"<<relayed_addr_str;
            break;
        case STUN_ATTRIBUTE_MESSAGE_INTEGRITY:
            qDebug()<<"message integrity:"<<attr_len<<QByteArray((char*)attr_value, attr_len).toHex();
            break;
        case STUN_ATTRIBUTE_LIFETIME:
            memcpy(&lifetime, attr_value, attr_len);
            lifetime = nswap32(lifetime);
            qDebug()<<"lifetime:"<<lifetime;
            break;
        case STUN_ATTRIBUTE_BANDWIDTH:
            memcpy(&bandwidth, attr_value, attr_len);
            bandwidth = nswap32(bandwidth);
            qDebug()<<"bandwidth:"<<bandwidth;
            break;
        case STUN_ATTRIBUTE_XOR_PEER_ADDRESS:
            stun_attr_get_addr_str(buf.buf, buf.len, raw_attr, &stun_addr, NULL);
            addr_to_string(&stun_addr, (u08bits*)addr_str);
            qDebug()<<"xor peer addr:"<<addr_str;
            break;
        case STUN_ATTRIBUTE_DATA:
            
            qDebug()<<"attr data len:"<<attr_len<<QString(QByteArray((char*)attr_value + 4, attr_len - 4)).left(50)<<"...";
            break;
        default:
            qDebug()<<"unkown attr:"<<attr_type<<attr_len;
            break;
        }
    }
}
Example #5
0
void StunClient::processResponse(QByteArray resp, QString peer_addr)
{
    u08bits rbuf[STUN_BUFFER_SIZE];
    size_t rlen = 0;
    stun_buffer buf;
    QString mapped_addr;
    u08bits addr_buff[STUN_BUFFER_SIZE] = {0};

    rlen = resp.length();
    memcpy(rbuf, resp.data(), resp.length());

    buf.len = resp.length();
    memcpy(buf.buf, resp.data(), resp.length());

    if (!stun_is_command_message(&buf)) {
        qDebug()<<resp.length()<<("The response is not a STUN message")<<peer_addr;
        // should be a relayed raw UDP packet to peerA
        emit packetReceived(resp, peer_addr);
        return;
    }

    u16bits stun_method;
    u16bits stun_msg_type;
    stun_method = stun_get_method_str(buf.buf, buf.len);
    stun_msg_type = stun_get_msg_type_str(buf.buf, buf.len);
    qDebug()<<"method:"<<stun_method<<getMethodName(stun_method)<<",msg type:"<<stun_msg_type;

    if (stun_method == STUN_METHOD_BINDING) {
    } else {
        this->debugStunResponse(resp);
    }

    // channel data
    if (stun_is_indication(&buf)) {
        u16bits chan_no;
        size_t blen = 0;

        qDebug()<<"indication data:"<<buf.len;

        stun_attr_ref t_attr = stun_attr_get_first_by_type(&buf, STUN_ATTRIBUTE_DATA);
        const u08bits *t_value = stun_attr_get_value(t_attr);
        blen = stun_attr_get_len(t_attr);
        QString xor_peer_addr = getStunAddress(resp, STUN_ATTRIBUTE_XOR_PEER_ADDRESS);

        qDebug()<<"is chan msg:"<<stun_is_channel_message_str(t_value, &blen, &chan_no, 0);
        qDebug()<<"chan no:"<<chan_no<<blen<<xor_peer_addr;

        emit this->packetReceived(QByteArray((char*)t_value + 4, blen - 4), xor_peer_addr);

        return;
    }

    if (!stun_is_response(&buf)) {
        qDebug()<<resp.length()<<("The response is not a reponse message\n");
        return;
    }

    if (!stun_is_success_response(&buf)) {
        int err_code = 0;
        u08bits err_msg[1025] = "\0";
        size_t err_msg_size = sizeof(err_msg);
        if (stun_is_error_response(&buf, &err_code, err_msg, err_msg_size)) {
            printf("The response is an error %d (%s)\n", err_code, (char*) err_msg);
        } else {
            printf("The response is an unrecognized error\n");
        }

        
        // test unauth
        u08bits realm[128] = {0};
        u08bits nonce[256] = {0};
        
        if (stun_is_challenge_response_str(buf.buf, buf.len, &err_code, err_msg, err_msg_size, realm, nonce)) {
            qDebug()<<err_code;
            qDebug()<<err_code<<(char*)err_msg<<(char*)realm<<(char*)nonce;

            m_realm = QByteArray((char*)realm);
            m_nonce = QByteArray((char*)nonce);

            if (stun_method == STUN_METHOD_ALLOCATE) {
                this->allocate((char*)realm, (char*)nonce);
            }
            if (stun_method == STUN_METHOD_CHANNEL_BIND) {
                QThread::msleep(100);
                this->channelBind(m_peer_addr);
            }
        }

        if (err_code == 437) {
            assert(err_code != 437); // allocate mismatch
        }

        if (err_code == 438) {
            assert(err_code != 438); // stale nonce
        }

        if (err_code == 486) {
            assert(err_code != 486); // allocate quota reached
        }

        return;
    }


    if (stun_is_binding_response(&buf)) {
        ioa_addr reflexive_addr;
        addr_set_any(&reflexive_addr);
        if (stun_attr_get_first_addr(&buf, STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS, &reflexive_addr, NULL) >= 0) {
            stun_attr_ref sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_OTHER_ADDRESS);
            if (sar) {
                // *rfc5780 = 1;
                printf("\n========================================\n");
                // printf("RFC 5780 response %d\n",++counter);
                ioa_addr other_addr;
                stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &other_addr, NULL);
                sar = stun_attr_get_first_by_type_str(buf.buf, buf.len, STUN_ATTRIBUTE_RESPONSE_ORIGIN);
                if (sar) {
                    ioa_addr response_origin;
                    stun_attr_get_addr_str((u08bits *) buf.buf, (size_t) buf.len, sar, &response_origin, NULL);
                    addr_debug_print(1, &response_origin, "Response origin: ");
                }
                addr_debug_print(1, &other_addr, "Other addr: ");
            }
            addr_debug_print(1, &reflexive_addr, "UDP reflexive addr");
            addr_to_string(&reflexive_addr, addr_buff);
        } else {
            printf("Cannot read the response\n");
        }

        // emit got addr
        if (strlen((char*)addr_buff) > 0) {
            mapped_addr = QString((char*)addr_buff);
            emit this->mappedAddressRecieved(mapped_addr);
        }
        return;
    } // end bind resp


    if (stun_method == STUN_METHOD_ALLOCATE) {
        m_relayed_addr = this->getStunAddress(resp, STUN_ATTRIBUTE_XOR_RELAYED_ADDRESS);
        this->saveAllocatePuples(m_realm, m_nonce);
        emit this->allocateDone(m_relayed_addr);

        if (!m_channel_refresh_timer) {
            m_channel_refresh_timer = new QTimer();
            QObject::connect(m_channel_refresh_timer, &QTimer::timeout, this, &StunClient::onRefreshTimeout);
        }
        if (!m_channel_refresh_timer->isActive()) {
            m_channel_refresh_timer->start(m_channel_refresh_timeout);
        }
    }

    if (stun_method == STUN_METHOD_CREATE_PERMISSION) {
        if (!m_permission_keepalive_timer) {
            emit this->createPermissionDone();
        }

        if (!m_permission_keepalive_timer) {
            m_permission_keepalive_timer = new QTimer();
            QObject::connect(m_permission_keepalive_timer, &QTimer::timeout, this, &StunClient::onPermKATimeout);
        }
        if (!m_permission_keepalive_timer->isActive()) {
            m_permission_keepalive_timer->start(m_permission_keepalive_timeout);
        }
    }

    if (stun_method == STUN_METHOD_CHANNEL_BIND) {
        emit this->channelBindDone(m_relayed_addr);
    }

    if (stun_method == STUN_METHOD_REFRESH) {
        qDebug()<<"refresh responsed.";
    }
}
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;
					}
				}
			}