Deployment of TLS support with Open SIP Express Router The aim of this guide is to describe how to implement the TLS support on a proxy OpenSER (http://www.openser.org/). TLS is an optional part of the OpenSER's core, not a module. As defined in SIP RFC 3261, is a mandatory feature for proxies and can be used to secure the SIP signaling on a hop-by-hop basis (not end-to-end). TLS works on top of TCP. 1 The TLS support was originally developed by Peter Griffiths and posted as a patch on SER development mailing list. The TLS support was simultaneously added in both projects. In SER, the support was committed in a separate "experimental" CVS tree, as patch to the main CVS tree. In OpenSER, the support was integrated directly into the CVS tree, as a built-in component. This support act as a security tool, as described by the authors on the related doc (available at http://www.openser.org/docs/tls.html) that providers adopt to prevent for a user to receive calls from totally unknown people or, in the worst case, to receive unwanted calls. It is possible to check trusted calls (i.e. from a client with verified identity) and untrusted calls (i.e. from a client whose identity is not verified)just by changing the phone ring. It is possible to setting up multiple rings manipulating the Alert-Info header. In the example we refer only to the hardphones: 1. CISCO ATA 2. CISCO 7960 3. SNOM Tools and software 2 Proxy servers OpenSER v1.2.x installed on Fedora 7 linux machines OpenSSL required on both proxy to run crypto functions OpenSSLl o libssl >= 0.9.6 OpenSSL-dev o libssl-dev MySQL database for authenticating trusted user; Setting up a Certification Authority (using openserctl script) 2 Client softphone X-Lite for Mac
Installation The first step is to install the O.S. linux (we used Fedora 7) and compile OpenSER with TLS support from the rpm files available at http://www.openser.org/pub/openser/latest/packages/fedora/7/. No matter how you do it, the important is the version (1.2.x). We used the yum package installer and it worked fine. First of all we need to setting up the certification authority using the openserctl script: On a root shell type the command: 2 openserctl tls rootca this will produce a private-key and the self-signed certificate authority on /etc/openser/tls/ Then generate and sign the proxy openser certificates by typing openserctl tls usercert foobar.cnf Actually you can copy and rename the foobar.cnf file into the proxy name file; then you need to edit it and a directory /etc/openser/tls/foobar/ will be created with private key, certificate etc. Keep in mind that the calist.pem file is always needed for a verifier in order to trust the certificate signer. Obviously then you have to copy the proxy certificate related directory on his local disc in order to be accessed, so the next step is to putting the certificate, private key and CA list in /etc/openser/tls/foobar/ of the other proxy and setting the following parameters: set up ser to use the certificate : tls_certificate=/etc/openser/tls/foobar/cert.pem set up ser to use the private key : tls_private_key=/etc/openser/tls/foobar/privkey.pem set up ser to use the CA list (optional - make sens only if tls_verify is turned on) tls_ca_list=/etc/openser/tls/foobar/calist.pem
Configuration and first call After the installation cut and paste the following basic config file and modify it (foobar is replaced by stefano and ip address are converted from public to local for privacy purposes): # $Id: openser.cfg,v 1.6.2.1 2006/07/17 15:51:03 klaus_darilion Exp $ # # simple quick-start config script # # ----------- global configuration parameters ------------------------ debug=3 fork=no log_stderror=yes 3 check_via=no dns=no rev_dns=no listen=192.168.1.88 port=5060 children=4 #fifo="/tmp/openser_fifo" # tls_verify=on disable_tls = 0 listen = tls:192.168.1.88:5061 tls_verify_server = 1 tls_verify_client = 1 tls_require_client_certificate = 1 tls_method = TLSv1 #TLS specific settings tls_certificate="/etc/openser/tls/stefano/stefano-cert.pem" tls_private_key="/etc/openser/tls/stefano/stefano-privkey.pem" tls_ca_list="/etc/openser/tls/stefano/stefano-calist.pem" alias=_dns_alias_ # ------------------ module loading ---------------------------------- loadmodule "/usr/lib/openser/modules/mysql.so" loadmodule "/usr/lib/openser/modules/sl.so" loadmodule "/usr/lib/openser/modules/tm.so" loadmodule "/usr/lib/openser/modules/rr.so" loadmodule "/usr/lib/openser/modules/maxfwd.so" loadmodule "/usr/lib/openser/modules/usrloc.so" loadmodule "/usr/lib/openser/modules/registrar.so" loadmodule "/usr/lib/openser/modules/textops.so" loadmodule "/usr/lib/openser/modules/mi_fifo.so" loadmodule "/usr/lib/openser/modules/auth.so" loadmodule "/usr/lib/openser/modules/auth_db.so" loadmodule "/usr/lib/openser/modules/uri_db.so" # ----------------- setting module-specific parameters ---------------
modparam("mi_fifo", "fifo_name", "/tmp/openser_fifo") # -- auth_db params -- # modparam("auth_db", "db_url", "mysql://openser:openserrw@localhost/openser") modparam("auth_db uri_db usrloc", "db_url", "mysql://openser:openserrw@localhost/openser") modparam("usrloc", "db_mode", 2) modparam("auth_db", "password_column", "password") modparam("auth_db", "calculate_ha1", 1) 4 # -- registrar params -- # no multiple registrations modparam("registrar", "append_branches", 0) # -- 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{ # initial sanity checks if (!mf_process_maxfwd_header("10")) { sl_send_reply("483","too Many Hops"); # if somene claims to belong to our domain in From, # challenge him (skip REGISTERs -- we will chalenge them later) if (from_uri==myself) { setflag(1); if ( (method=="invite" method=="subscribe" method=="message") &&!(src_ip==myself) ) { if (!(proxy_authorize( "", "subscriber" ))) { proxy_challenge("","0"/*no-qop*/); if (!check_from()) { log("log: From Cheating attempt in INVITE\n"); sl_send_reply("403", "That is ugly -- use From=id next time (OB)"); # non-register from other domain } else if ( method=="invite" && uri!=myself ) { sl_send_reply("403", "No relaying"); /* ******** do record-route and loose-route ******* */ if (!(method=="register")) record_route(); if (loose_route()) { append_hf("p-hint: rr-enforced\r\n"); route(1);
/* ******* check for requests targeted out of our domain ******* */ if ( uri!=myself ) { append_hf("p-hint: OUTBOUND\r\n"); if (uri=~"@192.168.1.74") { t_relay("tls:192.168.1.74:5061"); } else { route(1); 5 /* ******* divert to other domain according to prefixes ******* */ if (method!="register") { if ( uri=~"sip:201") { sethost("192.168.1.74"); t_relay("tls:192.168.1.74:5061"); } else if ( uri=~"sip:202" ) { /* ************ requests for our domain ********** */ if (method=="register") { if (!www_authorize( "", "subscriber" )) { # challenge if none or invalid credentials www_challenge( "192.168.1.88" /* realm */, "0" /* no qop -- some phones can't deal with it */); if (!check_to()) { log("log: To Cheating attempt\n"); sl_send_reply("403", "That is ugly -- use To=id in REGISTERs"); # it is an authenticated request, update Contact database now if (!save("location")) { sl_reply_error(); # if (uri!=myself) { # t_relay(); # sl_reply_error(); # # native SIP destinations are handled using USRLOC DB if (!lookup("location")) { # handle user which was not found sl_send_reply("404", "Not Found nel USRLOC DB locale"); # remove all present Alert-info headers remove_hf("alert-info"); if (method=="invite" && (proto==tls isflagset(1))) { append_hf("alert-info: 1\r\n"); # cisco 7960 append_hf("alert-info: Bellcore-dr4\r\n"); # cisco ATA append_hf("alert-info: http://foo.bar/x.wav\r\n"); # snom # do forwarding
if (!t_relay()) { sl_reply_error(); #end of script } 6 (Be sure to modify the paths according to yours and the names you give) The final step is to register the client with his own server and make a call. If the clients are respectively 200 e 201 and you want to call from 200 to 201, just type the number: 201 The call will succeed and you can debug log output to see how the handshake between the two proxies works. They exchange certificate information and authenticate each other. Final considerations TLS support is aimed to keep secure the first signaling phase of SIP protocol. The trusted concept is on a multilevel basis: there is a mutual agreement chain between domains, in which a domain can verify only local user, not those of the outside. This could be a weak chain if it is too long and if only one proxy OpenSER in the middle was attacked, the end to end ones are not able to detect the threat. Soon TLS support will be available also on UDP (DTLS), released from IETF. Remember that the TLS support has been tested on OpenSER project; if you wish to use it on SER project, be sure to change the syntax and always refer to the site iptel.org. We hope this helps! Stefano Abbate stef.abbate@gmail.com Mariantonietta Noemi La Polla noemi.lapolla@gmail.com