| /////////////////////////////////////////////////////////////////////////////// |
| // 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__); |