[Overview] [Code Structure] [Configuration and Usage] [Example]
The headers in question here are : Via, Path, Record-Route and Service-Route.
The solution is to encrypt the headers as they leave the network and to decrypt the messages when they enter the internal network.
The Twofish encryption algorithm has been chosen for this purpose because of its speed and flexibility. However, if you consider it necessary you can use some other algorithm as the interface of the application allows such changes to be performed with relative ease.
1.Initialization of the data structures needed by Twofish
2.Ability to encrypt a SER string (also adds padding in order to perform encryption, and performs BASE64 encoding in order to use only characters that do not confuse the SIP parsers).
3.Ability to decrypt a SER string (this removes the padding and decodes the previously BASE64 encoded string
Note: You may choose not to use the BASE64 encoding as this adds to the length of the SIP message.However be aware that doing so will result in incorrect parsing of the message as the ouput from the encryption algorithm can contain any character, including the ones used by the parser to delimit the parts of the message.If you choose to modify the parser accordingly, then the BASE64 encoding may indeed be superfluous.
If you choose to use another algorithm here you can call its own block encryption functions.
The file thig.c contains functions necessary to add the ICSCFs address to the SIP headers and also the functions that you can call to encrypt or decrypt headers.
in thig_ims_enc.c:
keySize - the Twofish key length.256 bits it's the biggest value and also provides the most security.If you choose to use a shorter key this can improve speed but also provide less security.
mode - the mode in which Twofish operates.MODE_EBC is not recommended as it yields obvious patterns in the encrypted strings and makes them prone to attacks or decyphering.
in thig_aes.h:
BLOCK_SIZE - number of bits per block (Twofish encrypts blocks of data)
MAX_BLK_CNT - max nr blocks per call in Twofish
You should be aware that a big value of the BLOCK_SIZE can lead to unnecessary padding being added to a SIPMessage (for Example if the BLOCK_SIZE converted into bytes is 16 a block of 2bytes will have to be padded with 14bytes to be encrypted).
Usage:
In provide thig functionality the functions from thig.c should be used.
I_THIG_encrypt_header and I_THIG_decrypt_header take as parameters the SIP message and the name of the header.Using this name the function searches for the header in the messages and then encrypts the information. However if you are not concerned with the details of each header then you should use I_THIG_encrypt_all_headers and I_THIG_decrypt_all_headers. Those functions try to encrypt/ decrypt all sensitive headers (Via, Route , Record-Route,Service-Route)
# # $Id: icscf.thig.cfg 81 2007-01-05 10:15:09Z vingarzan $ # # Interrogating - CSCF configuration script - THIG case # # ----------- global configuration parameters ------------------------ debug=3 log_stderror=yes memlog=4 sip_warning=yes fork=yes children=4 listen=127.0.0.1 port=5060 alias=icscf.open-ims.test alias=open-ims.test check_via=no # (cmd. line: -v) dns=no # (cmd. line: -r) rev_dns=no # (cmd. line: -R) # ------------------ module loading ---------------------------------- # Uncomment this if you want to use SQL database loadmodule "/opt/OpenIMSCore/ser_ims/modules/mysql/mysql.so" loadmodule "/opt/OpenIMSCore/ser_ims/modules/sl/sl.so" loadmodule "/opt/OpenIMSCore/ser_ims/modules/tm/tm.so" modparam("tm", "fr_timer", 10000) loadmodule "/opt/OpenIMSCore/ser_ims/modules/rr/rr.so" loadmodule "/opt/OpenIMSCore/ser_ims/modules/maxfwd/maxfwd.so" loadmodule "/opt/OpenIMSCore/ser_ims/modules/textops/textops.so" loadmodule "/opt/OpenIMSCore/ser_ims/modules/icscf/icscf.so" modparam("icscf","name","icscf.open-ims.test") modparam("icscf","db_url","mysql://icscf:heslo@localhost/icscf") modparam("icscf","db_nds_table","nds_trusted_domains") modparam("icscf","db_scscf_table","s_cscf") modparam("icscf","db_capabilities_table","s_cscf_capabilities") modparam("icscf","thig_name","thig@icscf.open-ims.test") modparam("icscf","thig_host","127.0.0.1") modparam("icscf","thig_port",5060) modparam("icscf","thig_param","thigenc") modparam("icscf","aaa_peer","hss.open-ims.test") modparam("icscf","hash_size",128) loadmodule "/opt/OpenIMSCore/ser_ims/modules/cdp/cdp.so" modparam("cdp","config_file","/opt/OpenIMSCore/icscf.xml") # -- rr params -- # add value to ;lr param to make some broken UAs happy modparam("rr", "enable_full_lr", 1) # ------------------------- request routing logic ------------------- # main routing logic route{ route(Sanity_Checks); #route(NDS); if (method=="REGISTER"){ route(REGISTER); break; } if (search("127\.0\.0\.1:5060;thigenc=")){ route(THIG_Request_decrypt); break; } #If there is a Route header we try to do loose route if (search("^Route:")){ log(1,"Route found\n"); if (search("thig@icscf.open-ims.test")){ route(THIG_Request_encrypt); } # subsequent messages withing a dialog should take the # path determined by record-routing if (loose_route()) { # mark routing logic in request append_hf("P-hint: I-CSCF rr-enforced\r\n"); if (!t_relay()){ sl_reply_error(); break; } break; } } if (method=="INVITE" || method=="SUBSCRIBE" || method=="MESSAGE"){ route(Initial_Request); break; }else{ # Shouldn't get here unless missconfigured (add more methods as initial) or # somebody is routing here unknown messages if ( !t_newtran()) { sl_reply_error(); break; }; append_to_reply("Allow: INVITE,SUBSCRIBE,MESSAGE\r\n"); t_reply("406","Initial Request Method not allowed at the I-CSCF"); break; } } route[Sanity_Checks] { # initial sanity checks -- messages with # max_forwards==0, or excessively long requests if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","Too Many Hops"); break; }; if (msg:len >= max_len ) { sl_send_reply("513", "Message too big"); break; }; } route[NDS] { if (!I_NDS_is_trusted()){ log(-1,"Received message from NDS untrusted domain!\n"); if (method=="REGISTER"){ sl_send_reply("403","Forbidden - Network Domain Security doesn't trust traffic from source domain"); break; } I_NDS_strip_headers(); } } route[REGISTER] { # first, don't repeat a succesful UAR if (I_trans_in_processing()) break; I_THIG_add_Path(); # I_UAR("0") means UAR_REGISTRATION/DEREGISTRATION # I_UAR("1") means UAR_REGISTRATION_AND_CAPABILITIES if (I_UAR("0")){ if (I_scscf_select("0")) { t_on_reply("REGISTER_reply"); t_on_failure("REGISTER_failure"); if (!t_relay()) { if ( !t_newtran()) { sl_reply_error(); break; }; t_reply("500","Error forwarding towards S-CSCF"); break; } break; }else{ I_scscf_drop(); if ( !t_newtran()) { sl_reply_error(); break; }; t_reply("500", "Server error on UAR select S-CSCF"); break; } }else{ if ( !t_newtran()) { sl_reply_error(); break; }; t_reply("500", "Server error on UAR"); break; } } onreply_route[REGISTER_reply] { I_THIG_encrypt_header("Service-route"); if (!t_check_status("408")&&!t_check_status("480")){ I_scscf_drop(); } } failure_route[REGISTER_failure] { if (t_check_status("408")||t_check_status("480")){ #log(-1,"Got a failure for REGISTER!!!\n"); if (I_scscf_select("1")) { t_on_reply("REGISTER_reply"); t_on_failure("REGISTER_failure"); if (!t_relay()) { t_reply("500","Error forwarding towards next S-CSCF"); break; } break; }else{ t_reply("500", "Server error on UAR select next S-CSCF"); break; } }else{ I_scscf_drop(); } } route[Initial_Request] { # first, don't repeat a succesful LIR if (I_trans_in_processing()) break; if (I_LIR()){ if (I_scscf_select("0")) { t_on_reply("Initial_Request_reply"); t_on_failure("Initial_Request_failure"); if (!t_relay()) { if ( !t_newtran()) { sl_reply_error(); break; }; t_reply("500","Error forwarding towards S-CSCF"); break; } break; }else{ I_scscf_drop(); if ( !t_newtran()) { sl_reply_error(); break; }; t_reply("500", "Server error on LIR select S-CSCF"); break; } }else{ if ( !t_newtran()) { sl_reply_error(); break; }; t_reply("500", "Server error on LIR"); break; } } onreply_route[Initial_Request_reply] { if (!t_check_status("408")&&!t_check_status("480")){ I_scscf_drop(); } } failure_route[Initial_Request_failure] { if (t_check_status("408")||t_check_status("480")){ #log(-1,"Got a failure for Initial Request!!\n"); if (I_scscf_select("1")) { t_on_reply("Initial_Request_reply"); t_on_failure("Initial_Request_failure"); if (!t_relay()) { t_reply("500","Error forwarding towards next S-CSCF"); break; } break; }else{ t_reply("500", "Server error on LIR select next S-CSCF"); break; } }else{ I_scscf_drop(); } } route[THIG_Request_encrypt] { if (!I_THIG_encrypt_header("Via")){ t_reply("500","THIG error encrypting Via headers"); exit; } if (loose_route()) { # mark routing logic in request append_hf("P-hint: THIG applied\r\n"); t_on_reply("THIG_Reply_decrypt"); if (!t_relay()){ sl_reply_error(); break; } } else t_reply("500","Error loose-routeing after THIG"); exit; } onreply_route[THIG_Reply_decrypt] { log(1,"THIG Reply decrypt reached\n"); if (!I_THIG_decrypt_header("Via")){ #t_reply("500","THIG error decrypting Via headers"); exit; } } route[THIG_Request_decrypt] { if (!I_THIG_decrypt_header("Route")){ t_reply("500","THIG error decrypting Route headers"); exit; } if (!t_relay_to_udp("127.0.0.1",5060)){ t_reply("500","THIG error bootstraping"); exit; } break; }
1.5.2