/////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000-2019 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: TCCIPsec_XFRM_SA.cc // Description: TCC Useful Functions: IPsec XFRM Functions // Rev: R36B // Prodnr: CNL 113 472 // /////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #include #include #ifdef LINUX #include #else #include #endif #include "TCCIPsec_XFRM_Definitions.hh" #include "TCCIPsec_XFRM.hh" #include "Logger.hh" using namespace TCCIPsec__XFRM__Definitions; //Sets the IP address to the addr parameter and returns the address family int f_set_IP_address(CHARSTRING address, xfrm_address_t* addr){ int temp = inet_pton(AF_INET,address,(void*)&addr->a4); if(temp > 0){ return AF_INET; }else{ temp = inet_pton(AF_INET6,address,(void*)&addr->a6); if(temp > 0){ return AF_INET6; }else{ TTCN_Logger::log( TTCN_DEBUG,"###### dst: "+address+" is not a well-formed IP address!"); return -1; }; }; } xfrm_lifetime_cfg f_set_IP_lifetime(Limits limits){ //Set default values xfrm_lifetime_cfg lft; lft.soft_byte_limit = XFRM_INF; lft.hard_byte_limit = XFRM_INF; lft.soft_packet_limit = XFRM_INF; lft.hard_packet_limit = XFRM_INF; lft.soft_add_expires_seconds = 0; lft.hard_add_expires_seconds = 0; lft.soft_use_expires_seconds = 0; lft.hard_use_expires_seconds = 0; if(limits.soft__byte__limit().ispresent()){ lft.soft_byte_limit = limits.soft__byte__limit()(); }; if(limits.hard__byte__limit().ispresent()){ lft.hard_byte_limit = limits.hard__byte__limit()(); }; if(limits.soft__packet__limit().ispresent()){ lft.soft_packet_limit = limits.soft__packet__limit()(); }; if(limits.hard__packet__limit().ispresent()){ lft.hard_packet_limit = limits.hard__packet__limit()(); }; if(limits.soft__add__expires__seconds().ispresent()){ lft.soft_add_expires_seconds = limits.soft__add__expires__seconds()(); }; if(limits.hard__add__expires__seconds().ispresent()){ lft.hard_add_expires_seconds = limits.hard__add__expires__seconds()(); }; if(limits.soft__use__expires__seconds().ispresent()){ lft.soft_use_expires_seconds = limits.soft__use__expires__seconds()(); }; if(limits.hard__use__expires__seconds().ispresent()){ lft.hard_use_expires_seconds = limits.hard__use__expires__seconds()(); }; return lft; } void f_process_additionalInfo( xfrm_usersa_info* sa, const SAAdditionalInfo& info ){ if(info.sel__src().ispresent()){ f_set_IP_address(info.sel__src()().ip__address(), &sa->sel.saddr); if(info.sel__src()().address__prefix().ispresent())sa->sel.prefixlen_s = info.sel__src()().address__prefix()(); if(info.sel__src()().port__number().ispresent()){ sa->sel.sport = htons(info.sel__src()().port__number()()); sa->sel.sport_mask = 0xffff; }; }; if(info.sel__dst().ispresent()){ f_set_IP_address(info.sel__dst()().ip__address(), &sa->sel.daddr); if(info.sel__dst()().address__prefix().ispresent())sa->sel.prefixlen_d = info.sel__dst()().address__prefix()(); if(info.sel__dst()().port__number().ispresent()){ sa->sel.dport = htons(info.sel__dst()().port__number()()); sa->sel.dport_mask = 0xffff; }; }; if(info.reqid().ispresent()){ sa->reqid = info.reqid()().get_long_long_val(); }; if(info.limits().ispresent()){ sa->lft = f_set_IP_lifetime(info.limits()()); }; return; } void f_set_encryptionInfo( xfrm_algo* alg, const Encryption& info, int enc_key_len ){ bool not_null = true; switch(info.name()){ case EncryptionAlgorithms::NULL__ENCR: {strcpy(alg->alg_name,"ecb(cipher_null)");alg->alg_key_len = 0;memcpy(alg->alg_key,"",0);not_null = false;break;} case EncryptionAlgorithms::CBC__AES: {strcpy(alg->alg_name,"cbc(aes)");break;} case EncryptionAlgorithms::CBC__DES: {strcpy(alg->alg_name,"cbc(des)");break;} case EncryptionAlgorithms::CBC__3DES: {strcpy(alg->alg_name,"cbc(des3_ede)");break;} case EncryptionAlgorithms::CBC__CAST5: {strcpy(alg->alg_name,"cbc(cast5)");break;} case EncryptionAlgorithms::CBC__BLOWFISH: {strcpy(alg->alg_name,"cbc(blowfish)");break;} case EncryptionAlgorithms::CBC__SERPENT: {strcpy(alg->alg_name,"cbc(serpent)");break;} case EncryptionAlgorithms::CBC__CAMELLIA: {strcpy(alg->alg_name,"cbc(camellia)");break;} case EncryptionAlgorithms::CBC__TWOFISH: {strcpy(alg->alg_name,"cbc(twofish)");break;} default: { strcpy(alg->alg_name,"ecb(cipher_null)"); alg -> alg_key_len = 0; memcpy(alg->alg_key,"",0); not_null = false; } }; if(not_null){ alg->alg_key_len = enc_key_len*8; if(info.key().get_selection() == IPSecKey::ALT_text){ memcpy(alg->alg_key,info.key().text(),enc_key_len); } else { memcpy(alg->alg_key,(const char*)(const unsigned char*)hex2oct(info.key().hex()),enc_key_len); }; }; return; } void f_set_authenticationInfo( xfrm_algo* alg, const Authentication& info, int auth_key_len ){ bool not_null = true; switch(info.name()){ case AuthenticationAlgorithms::NULL__AUTH: {strcpy(alg->alg_name,"digest_null");alg->alg_key_len = 0;memcpy(alg->alg_key,"",0);not_null = false;break;} case AuthenticationAlgorithms::HMAC__MD5: {strcpy(alg->alg_name,"hmac(md5)");break;} case AuthenticationAlgorithms::HMAC__SHA1: {strcpy(alg->alg_name,"hmac(sha1)");break;} case AuthenticationAlgorithms::HMAC__SHA256: {strcpy(alg->alg_name,"hmac(sha256)");break;} case AuthenticationAlgorithms::HMAC__SHA384: {strcpy(alg->alg_name,"hmac(sha384)");break;} case AuthenticationAlgorithms::HMAC__SHA512: {strcpy(alg->alg_name,"hmac(sha512)");break;} case AuthenticationAlgorithms::HMAC__RMD160: {strcpy(alg->alg_name,"hmac(rmd160)");break;} default: { strcpy(alg->alg_name,"ecb(cipher_null)"); alg -> alg_key_len = 0; memcpy(alg->alg_key,"",0); not_null = false; } }; if(not_null){ alg->alg_key_len = auth_key_len*8; if(info.key().get_selection() == IPSecKey::ALT_text){ memcpy(alg->alg_key,info.key().text(),auth_key_len); } else { memcpy(alg->alg_key,(const char*)(const unsigned char*)hex2oct(info.key().hex()),auth_key_len); }; }; return; } void f_set_MessageBody_for_addSA( void* memo, const SAAddInfo& sa_info, const unsigned int enc_key_len, const unsigned int auth_key_len ){ struct xfrm_usersa_info* sa; struct xfrm_algo* alg; struct xfrm_encap_tmpl* nat; struct nlattr* ahdr = NULL; bool multiple_attr = false; sa = (struct xfrm_usersa_info*)NLMSG_DATA(memo); memset(sa,0,sizeof(struct xfrm_usersa_info)); //set destination address int addr_family = f_set_IP_address(sa_info.dst().ip__address(), &sa->id.daddr); if(addr_family >= 0){ sa->family = sa->sel.family = addr_family; }; //else default value will be set: 0.0.0.0 //set source address addr_family = f_set_IP_address(sa_info.src().ip__address(), &sa->saddr); if(addr_family >= 0){ sa->family = sa->sel.family = addr_family; }; //else default value will be set: 0.0.0.0 sa->sel.prefixlen_d = sa->sel.prefixlen_s = 0; if(sa_info.protocol() != TransportProtocol::ANY){ sa->sel.proto = sa_info.protocol(); } else { //in case of ANY no value should be defined } //Setting default values for each parameter //Some of the parameters are not configurable, but can be added later sa->sel.ifindex = 0; sa->sel.user = 0; sa->id.spi = htonl(sa_info.spi().get_long_long_val()); sa->id.proto = sa_info.ipsec(); sa->mode = sa_info.mode(); sa->curlft.bytes = 0; sa->curlft.packets = 0; sa->curlft.add_time = 0; sa->curlft.use_time = 0; sa->stats.replay_window = 0; sa->stats.replay = 0; sa->stats.integrity_failed = 0; sa->seq = 0; sa->reqid = 0; sa->replay_window = sa->stats.replay_window; sa->flags = 0; if(sa_info.info().ispresent()){ f_process_additionalInfo(sa, sa_info.info()()); }; if(sa_info.ipsec__algos().enc().ispresent()){ TTCN_Logger::log( TTCN_DEBUG,"###### Encryption enabled."); ahdr = (struct nlattr*)((char*)sa+NLA_ALIGN(sizeof(*sa))); ahdr->nla_len = NLA_HDRLEN+sizeof(struct xfrm_algo)+enc_key_len; ahdr->nla_type = XFRMA_ALG_CRYPT; alg = (struct xfrm_algo*)((char*)ahdr+NLA_HDRLEN); f_set_encryptionInfo(alg, sa_info.ipsec__algos().enc()(),enc_key_len); multiple_attr = true; }; if(sa_info.ipsec__algos().auth().ispresent()){ TTCN_Logger::log( TTCN_DEBUG,"###### Authentication enabled."); if(multiple_attr){ahdr = (struct nlattr*)((char*)ahdr+NLA_ALIGN(ahdr->nla_len));} else {ahdr = (struct nlattr*)((char*)sa+NLA_ALIGN(sizeof(*sa)));}; ahdr->nla_len = NLA_HDRLEN+sizeof(struct xfrm_algo)+auth_key_len; ahdr->nla_type = XFRMA_ALG_AUTH; alg = (struct xfrm_algo*)((char*)ahdr+NLA_HDRLEN); f_set_authenticationInfo(alg, sa_info.ipsec__algos().auth()(),auth_key_len); multiple_attr = true; }; if(sa_info.nat__t().ispresent()){ TTCN_Logger::log( TTCN_DEBUG,"###### NAT traversal enabled."); if(multiple_attr){ahdr = (struct nlattr*)((char*)ahdr+NLA_ALIGN(ahdr->nla_len));} else {ahdr = (struct nlattr*)((char*)sa+NLA_ALIGN(sizeof(*sa)));}; ahdr->nla_len = NLA_HDRLEN+sizeof(*nat); ahdr->nla_type = XFRMA_ENCAP; nat = (struct xfrm_encap_tmpl*)((char*)ahdr+NLA_HDRLEN); nat->encap_type = sa_info.nat__t()().encap__type(), nat->encap_sport = htons(sa_info.nat__t()().sport()); nat->encap_dport = htons(sa_info.nat__t()().dport()); if(sa_info.nat__t()().oa().ispresent()){ addr_family = f_set_IP_address(sa_info.nat__t()().oa()(), &nat->encap_oa); }; }; return; } void f_set_MessageBody_for_deleteSA( void* memo, const SADelInfo& sa_info ){ struct xfrm_usersa_id* sa; xfrm_address_t* src; struct nlattr* ahdr; sa = (struct xfrm_usersa_id*)NLMSG_DATA(memo); memset(sa,0,sizeof(struct xfrm_usersa_id)); int addr_family = f_set_IP_address(sa_info.dst().ip__address(), &sa->daddr); if(addr_family >= 0){ sa->family = addr_family; }; //else default value will be set: 0.0.0.0 sa->spi = htonl(sa_info.spi().get_long_long_val()); sa->proto = sa_info.proto(); ahdr = (struct nlattr*)((char*)sa+NLA_ALIGN(sizeof(*sa))); ahdr->nla_len = NLA_HDRLEN+sizeof(*src); ahdr->nla_type = XFRMA_SRCADDR; src = (xfrm_address_t*)((char*)ahdr+NLA_HDRLEN); addr_family = f_set_IP_address(sa_info.src().ip__address(), src); return; }