blob: 73870681359498f128692d0cabe99a3739e6ebde [file] [log] [blame]
///////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2000-2018 Ericsson Telecom AB
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v2.0
// which accompanies this distribution, and is available at
// https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
///////////////////////////////////////////////////////////////////////////////
//
// File: STUN_EncDec.cc
// Description: Encoder/Decoder functions for STUN Protocol module
// Rev: <RnXnn>
// Prodnr: CNL 113 644
// Updated: 2009-09-19
// Contact: http://ttcn.ericsson.se
///////////////////////////////////////////////
#include "STUN_Types.hh"
#include <sys/timeb.h>
#include <arpa/inet.h>
#include <openssl/hmac.h>
#define MESSAGE_INTEGRITY_LENGTH 24
#define MESSAGE_INTEGRITY_VALUE_LENGTH 20
#define MESSAGE_INTEGRITY_TYPE 8
namespace STUN__Types{
static const unsigned char os_tr_id_octets[] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0};
static const unsigned char os_ip_octets[] = {0,0,0,0};
static const unsigned char os_integerity_octets[] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0};
static const OCTETSTRING os_dummy_oct(0,os_ip_octets);
static const OCTETSTRING os_tr_id_oct(16, os_tr_id_octets);
static const OCTETSTRING os_ip_oct(4, os_ip_octets);
const unsigned char * convertInt2char(unsigned int in)
{
static unsigned char out[4] ;
out[0] = (unsigned char)((in & 0xFF000000) >> 24);
out[1] = (unsigned char)((in & 0x00FF0000) >> 16);
out[2] = (unsigned char)((in & 0x0000FF00) >> 8);
out[3] = (unsigned char)(in & 0x000000FF);
return out;
}
unsigned int convertChar2int(const unsigned char * in)
{
return (((unsigned int)in[0]) << 24) + (((unsigned int)in[1]) << 16) + (((unsigned int)in[2]) << 8) + (((unsigned int)in[3]));
}
BOOLEAN f__STUN__checkMessageIntegrity(const OCTETSTRING& pl__msg, const OCTETSTRING& pl__key)
{
int offset2type = pl__msg.lengthof() - MESSAGE_INTEGRITY_LENGTH + 1;
if(*((const unsigned char *)pl__msg + offset2type) != MESSAGE_INTEGRITY_TYPE) {
TTCN_warning("Last attribute is not Message Integrity");
return true;
}
else {
//getMAC stores Messgage-Integerity attribute value from incomming STUN msg
int offset2value = pl__msg.lengthof() - MESSAGE_INTEGRITY_VALUE_LENGTH;
OCTETSTRING getMAC(MESSAGE_INTEGRITY_VALUE_LENGTH, ((const unsigned char *)pl__msg)+ offset2value);
//calcMAC stores the calculated MAC from incoming STUN msg
OCTETSTRING calcMAC = f__STUN__HMAC(pl__msg, pl__key);
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("\nget MAC \t\t\t\t= ");
getMAC.log();
TTCN_Logger::log_event("\ncalculated MAC \t= ");
calcMAC.log();
TTCN_Logger::end_event();
if(getMAC == calcMAC)
return true;
else
return false;
}
}
OCTETSTRING f__STUN__HMAC(const OCTETSTRING& pl__string, const OCTETSTRING& pl__key)
{
int size_t = pl__string.lengthof() - MESSAGE_INTEGRITY_LENGTH;
if (size_t < 0) {
TTCN_warning("Message length too short");
return OCTETSTRING(MESSAGE_INTEGRITY_VALUE_LENGTH, os_integerity_octets);;
}
else {
//store pl__string without Message-Integerity attribute
OCTETSTRING temp(size_t,(const unsigned char *)pl__string);
if (temp.lengthof() % 64 != 0) {
//padding temp with zerros up to multiple of 64
int paddingSize = 64 - (temp.lengthof() % 64);
unsigned char padding[paddingSize];
for (int i = 0; i < paddingSize; i++) {
padding[i] = 0;
}
temp+=OCTETSTRING(paddingSize, padding);
}
unsigned char md[MESSAGE_INTEGRITY_VALUE_LENGTH];
unsigned int md_len;
TTCN_Logger::begin_event(TTCN_DEBUG);
TTCN_Logger::log_event("Calculating MAC (user initiated from TTCN-3):\nkey = ");
pl__key.log();
TTCN_Logger::log_event("\nInput = ");
temp.log();
HMAC(EVP_sha1(), (const unsigned char*)pl__key, pl__key.lengthof(), (const unsigned char *)temp, temp.lengthof(), md, &md_len);
TTCN_Logger::log_event("\nOutput = %s", md);
TTCN_Logger::end_event();
return OCTETSTRING(MESSAGE_INTEGRITY_VALUE_LENGTH, md);
}
}
OCTETSTRING f__STUN__IP2oct(const CHARSTRING& pl__ip) {
int temp;
temp = ntohl(inet_addr(pl__ip));
if (temp == -1) {
TTCN_warning("Wrong IP address added, f_STUN_IP2oct() returns with \'00000000\'O");
return os_ip_oct;
} else {
return OCTETSTRING(4,convertInt2char(temp));
}
}
CHARSTRING f__STUN__oct2IP(const OCTETSTRING& pl__ip) {
struct in_addr temp;
temp.s_addr = htonl(convertChar2int((const unsigned char *)pl__ip));
return inet_ntoa(temp);
}
OCTETSTRING f__STUN__genTrasId()
{
OCTETSTRING ret = os_tr_id_oct;
timeb precise; // requires <sys/timeb.h>
if ( ftime(&precise) != -1 ) {
srand48(precise.time + precise.millitm);
ret = int2oct(lrand48(),4) + int2oct(lrand48(),4) + int2oct(lrand48(),4) + int2oct(lrand48(),4);
}
else TTCN_warning("f_STUN_genTrasId() returns with \'00000000000000000000000000000000\'O");
return ret;
}
static const unsigned char stun_magicCookie_octets[] = { 33, 18, 164, 66 }; // '2112A442'O
OCTETSTRING f__STUN__genTrasId__withMagicCookie()
{
OCTETSTRING ret = os_tr_id_oct;
timeb precise; // requires <sys/timeb.h>
if ( ftime(&precise) != -1 ) {
srand48(precise.time + precise.millitm);
ret = OCTETSTRING(4, stun_magicCookie_octets) + int2oct(lrand48(),4) + int2oct(lrand48(),4) + int2oct(lrand48(),4);
}
else TTCN_warning("f_STUN_genTrasId() returns with \'00000000000000000000000000000000\'O");
return ret;
}
INTEGER f__STUN__getMessageLength(const OCTETSTRING& stream)
{
int stream_length = stream.lengthof();
int pdu_length = 0;
unsigned char * stream_ptr = (unsigned char *)(const unsigned char *)stream;
if (stream_length >= 20){
stream_ptr = stream_ptr + 2;
pdu_length = oct2int(OCTETSTRING(2,(const unsigned char *)stream_ptr));
if ((pdu_length + 20)<= stream_length){
pdu_length = pdu_length + 20;
return pdu_length;}
else {return 0;}
}
else {return 0;}
}
OCTETSTRING f__STUN__Enc(const PDU__STUN& pl__pdu, const OCTETSTRING& pl__password = os_dummy_oct)
{
PDU__STUN* par=NULL;
if (pl__pdu.header().trans__id() == os_tr_id_oct){
par = new PDU__STUN(pl__pdu);
par->header().trans__id() = f__STUN__genTrasId();
}
TTCN_Buffer buf;
TTCN_EncDec::error_type_t err;
buf.clear();
TTCN_EncDec::clear_error();
TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);
if(par)
par->encode(PDU__STUN_descr_, buf, TTCN_EncDec::CT_RAW);
else
pl__pdu.encode(PDU__STUN_descr_, buf, TTCN_EncDec::CT_RAW);
err = TTCN_EncDec::get_last_error_type();
if(err != TTCN_EncDec::ET_NONE)
TTCN_warning("Encoding error: %s\n", TTCN_EncDec::get_error_str());
if (par)
delete par;
if(pl__password.lengthof() != 0) {
int offset2type = buf.get_len() - MESSAGE_INTEGRITY_LENGTH + 1;
//check the last attribute
if(*(buf.get_data() + offset2type) != MESSAGE_INTEGRITY_TYPE) {
TTCN_warning("Last attribute is not Message Integrity");
} else {
OCTETSTRING temp(MESSAGE_INTEGRITY_VALUE_LENGTH, os_integerity_octets);
temp = f__STUN__HMAC(OCTETSTRING(buf.get_len(), buf.get_data()),pl__password);
//replace the dunny Message-Integerity value with calculated MAC value
buf.set_pos(buf.get_len() - MESSAGE_INTEGRITY_VALUE_LENGTH);
buf.cut_end();
buf.put_os(temp);
}
}
return OCTETSTRING(buf.get_len(), buf.get_data());
}
PDU__STUN f__STUN__Dec(const OCTETSTRING& pl__oct)
{
PDU__STUN pdu;
TTCN_Buffer buf;
TTCN_EncDec::error_type_t err;
TTCN_EncDec::clear_error();
buf.clear();
buf.put_os(pl__oct);
TTCN_EncDec::set_error_behavior(TTCN_EncDec::ET_ALL, TTCN_EncDec::EB_WARNING);
pdu.decode(PDU__STUN_descr_, buf, TTCN_EncDec::CT_RAW);
err = TTCN_EncDec::get_last_error_type();
if(err != TTCN_EncDec::ET_NONE)
TTCN_warning("Decoding error: %s\n", TTCN_EncDec::get_error_str());
return pdu;
}
}
TTCN_Module STUN_EncDec("STUN_EncDec", __DATE__, __TIME__);