security.c File Reference


Detailed Description

Proxy-CSCF - Gm Security Operations.

IPSec only is now supported and it is transparent in the sense that if the client does not employ it, the functionality is disabled.

The ipsec_P_*.sh scripts are used to control the IPSec and are give as an example for usage with the linux-2.6 kernel. ipsec_tools is required for this (setkey).

Added TLS support

Author:
Dragos Vingarzan vingarzan -at- fokus dot fraunhofer dot de

Definition in file security.c.

#include <signal.h>
#include <stdlib.h>
#include "security.h"
#include "mod.h"
#include "sip.h"
#include "registration.h"
#include "registrar.h"
#include "registrar_subscribe.h"
#include "../../ip_addr.h"
#include "../../data_lump.h"

Go to the source code of this file.

Defines

#define get_qparam(src, name, dst)
#define get_param(src, name, dst)
#define strtoint(src, dest)

Functions

int get_next_spi ()
 Returns the next unused SPI.
unsigned long tls_get_session_hash (struct sip_msg *req)
 Looks for the tls session hash.
static int str_trim (str *s)
 trims the str
static r_security_type cscf_get_security_type (str security_header_body)
 Looks for the security type in the Security header .
str cscf_get_pref_security_header (struct sip_msg *req, str header_name, r_security_type *type, float *q)
 Looks for the prefered Security header .
r_contactsave_contact_security (struct sip_msg *req, str auth, str sec_hdr, r_security_type type, float q)
 Saves the Contact Security information into the P-CSCF registrar for this contact.
int execute_cmd (char *cmd)
 Executes an external command.
int P_verify_security (struct sip_msg *req, char *str1, char *str2)
 Process the REGISTER and verify Client-Security.
int P_security_401 (struct sip_msg *rpl, char *str1, char *str2)
 Process the 401 response for REGISTER and creates the first Security-Associations.
int P_security_200 (struct sip_msg *rpl, char *str1, char *str2)
 Process the 200 response for REGISTER and creates the first Security-Associations.
void P_security_drop (r_contact *c, r_security *s)
 Drops the SAs for the given contact.
int P_check_via_sent_by (struct sip_msg *msg, char *str1, char *str2)
 Checks if the sent-by parameter in the first Via header equals the source IP address of the message.
int P_follows_via_list (struct sip_msg *rpl, char *str1, char *str2)
 Checks if a response coming from a UE contains the same Via headers sent in the corresponding request.
int P_enforce_via_list (struct sip_msg *rpl, char *str1, char *str2)
 enforce a response coming from a UE to contain the same Via headers sent in the corresponding request
int P_add_via_received (struct sip_msg *msg, char *str1, char *str2)
 Adds a received parameter to the first via with the source IP of the message.
int P_remove_header_tag (struct sip_msg *msg, char *str1, char *str2)
 Remove from <str1> headers the <str2> tag.
int P_remove_security_client (struct sip_msg *msg, char *str1, char *str2)
 Look for Security-Client and delete it if found.
int P_remove_security_verify (struct sip_msg *msg, char *str1, char *str2)
 Look for Security-Verify and delete it if found.
int P_remove_security_headers (struct sip_msg *msg, char *str1, char *str2)
 Removes the Security-Client,Security-Verify headers.

Variables

int pcscf_use_ipsec
 whether to use or not ipsec
char * pcscf_ipsec_host
 IP for protected server.
int pcscf_ipsec_port_c
 PORT for protected client.
int pcscf_ipsec_port_s
 PORT for protected server.
char * pcscf_ipsec_P_Inc_Req
 Req E->P.
char * pcscf_ipsec_P_Out_Rpl
 Rpl E<-P.
char * pcscf_ipsec_P_Out_Req
 Req E<-P.
char * pcscf_ipsec_P_Inc_Rpl
 Rpl E->P.
char * pcscf_ipsec_P_Drop
 Drop.
r_hash_slotregistrar
 the contacts
int r_hash_size
 records tables parameters
int current_spi = 5000
 current SPI value
int pcscf_use_tls
 whether to use or not tls
int pcscf_tls_port
 PORT for TLS server.
int tls_disable
str s_security_client = {"Security-Client",15}
str s_security_verify = {"Security-Verify",15}
str s_security_server_s = {"Security-Server: ",17}
str s_security_server_e = {"\r\n",2}
static str s_ck = {"ck=\"",4}
static str s_ik = {"ik=\"",4}
static str s_ealg = {"ealg=",5}
static str s_alg = {"alg=",4}
static str s_spi_c = {"spi-c=",6}
static str s_spi_s = {"spi-s=",6}
static str s_port_c = {"port-c=",7}
static str s_port_s = {"port-s=",7}
static str s_des_in = {"des-ede3-cbc",12}
static str s_des_out = {"3des-cbc",8}
static str s_aes_in = {"aes-cbc",7}
static str s_aes_out = {"rijndael-cbc",12}
static str s_null_out = {"null",4}
static str s_md5_in = {"hmac-md5-96",11}
static str s_md5_out = {"hmac-md5",8}
static str s_sha_in = {"hmac-sha-1-96",13}
static str s_sha_out = {"hmac-sha1",9}
time_t time_now
 current time
static str s_tls = {"tls", 3}
static str s_ipsec = {"ipsec-3gpp", 10}
static str s_q = {"q=", 2}
static str via_hdr_s = {"Via: ",5}
static str via_hdr_e = {"\r\n",2}
static str s_received = {";received=",10}
static str s_received2 = {"received",8}


Define Documentation

#define get_qparam ( src,
name,
dst   ) 

Value:

{\
    int i,j;\
    (dst).s=0;(dst).len=0;\
    for(i=0;i<(src).len-(name).len;i++)\
        if (strncasecmp((src).s+i,(name).s,(name).len)==0){\
            j=i+(name).len;\
            (dst).s = (src).s+j;\
            (dst).len = 0;\
            while(j<(src).len && (src).s[j]!='\"') \
                j++;            \
            (dst).len = j-i-(name).len;\
            break;\
        }       \
}

Definition at line 108 of file security.c.

#define get_param ( src,
name,
dst   ) 

Value:

{\
    int i,j;\
    (dst).s=0;(dst).len=0;\
    for(i=0;i<(src).len-(name).len;i++)\
        if (strncasecmp((src).s+i,(name).s,(name).len)==0 &&\
            ((src).s[i-1]==' ' ||(src).s[i-1]==';'||(src).s[i-1]=='\t')){\
            j=i+(name).len;\
            (dst).s = (src).s+j;\
            (dst).len = 0;\
            while(j<(src).len && (src).s[j]!=','&& (src).s[j]!=' '&& (src).s[j]!='\t'&& (src).s[j]!=';') \
                j++;            \
            (dst).len = j-i-(name).len;\
            break;\
        }       \
}

Definition at line 124 of file security.c.

#define strtoint ( src,
dest   ) 

Value:

{\
    int i;\
    (dest)=0;\
    for(i=0;i<(src).len;i++)\
        if ((src).s[i]>='0' && (src).s[i]<='9')\
            (dest) = (dest)*10 + (src).s[i] -'0';\
}

Definition at line 141 of file security.c.

Referenced by P_verify_security(), and save_contact_security().


Function Documentation

int get_next_spi (  ) 

Returns the next unused SPI.

Todo:
  • make sure that this SPI is not used at the moment
Returns:
the next SPI

Definition at line 101 of file security.c.

References current_spi.

Referenced by save_contact_security().

00102 {
00103     return current_spi++;
00104 }

unsigned long tls_get_session_hash ( struct sip_msg *  req  ) 

Looks for the tls session hash.

Parameters:
req - sip msg request
Returns:
tls session hash on success or 0

Definition at line 189 of file security.c.

References get_tls_session_hash, M_NAME, and pcscf_use_tls.

Referenced by P_security_200().

00190 {
00191     unsigned long s_hash = 0;
00192     if (!pcscf_use_tls) return 0;
00193     s_hash = get_tls_session_hash(req);
00194     if (!s_hash){
00195         LOG(L_ERR,"ERR:"M_NAME":tls_get_session_hash: Session Hash could not be obtained !\n");
00196         return 0;
00197     }
00198     return s_hash;
00199 }

static int str_trim ( str *  s  )  [static]

trims the str

Parameters:
s - str param to trim

Definition at line 205 of file security.c.

00206 {
00207     int i;
00208     for (i = 0;i < s->len; i++)
00209     {
00210         if (s->s[i] != '\r' && s->s[i] != '\t' && s->s[i] != ' ')
00211         {
00212             break;
00213         }
00214     }
00215     s->s = s->s + i;    
00216     s->len -= i;
00217 
00218     for (i = s->len;i >=0; i--)
00219     {
00220         if (s->s[i] == '\r' && s->s[i] == '\t' && s->s[i] == ' ')
00221         {
00222             s->len--;
00223         }
00224         else
00225         {
00226             break;
00227         }
00228     }
00229     return 1;
00230 }

static r_security_type cscf_get_security_type ( str  security_header_body  )  [static]

Looks for the security type in the Security header .

Parameters:
security_header_body - input security header
Returns:
the type of security

Definition at line 237 of file security.c.

Referenced by cscf_get_pref_security_header().

00238 {
00239     str sec_type_s;
00240     int i;
00241     
00242     sec_type_s.s = security_header_body.s;
00243     sec_type_s.len = security_header_body.len;
00244     for (i = 0; i< security_header_body.len; i++)
00245         if (security_header_body.s[i] == ';') {
00246             sec_type_s.len = i;
00247             break;
00248         }   
00249     str_trim(&sec_type_s);
00250     if (sec_type_s.len==s_tls.len &&
00251         !strncasecmp(sec_type_s.s, s_tls.s , s_tls.len))
00252         return SEC_TLS;
00253     else if (sec_type_s.len==s_ipsec.len &&
00254             !strncasecmp(sec_type_s.s, s_ipsec.s , s_ipsec.len))
00255             return SEC_IPSEC;
00256     return SEC_NONE;
00257 }

str cscf_get_pref_security_header ( struct sip_msg *  req,
str  header_name,
r_security_type type,
float *  q 
)

Looks for the prefered Security header .

Parameters:
req - the SIP message
header_name - SIP header name
type - output value of the security type
q - output preferate value
Returns:
the security body for the provided SIP message

Definition at line 267 of file security.c.

References cscf_get_next_header(), cscf_get_security_type(), get_param, M_NAME, pcscf_use_ipsec, pcscf_use_tls, s_q, SEC_IPSEC, SEC_NONE, and SEC_TLS.

Referenced by P_security_200(), P_security_401(), and P_verify_security().

00268 {
00269     str q_sec={0,0},t_sec;
00270     r_security_type q_type=SEC_NONE,t_type;
00271     float q_q=-1,t_q;
00272     struct hdr_field *hdr=0;    
00273     str tmp={0,0};
00274     char c; 
00275 
00276         
00277     /* first find the highest q */
00278     for(hdr = cscf_get_next_header(req,header_name,(void*)0);hdr;hdr = cscf_get_next_header(req,header_name,hdr)){
00279         t_sec = hdr->body;
00280         /* if unknown type, skip */
00281         t_type = cscf_get_security_type(t_sec);
00282         if (t_type==SEC_NONE ||
00283             (!pcscf_use_ipsec&&t_type==SEC_IPSEC)||
00284             (!pcscf_use_tls&&t_type==SEC_TLS)) continue;
00285         /* check if q is maximum */
00286         get_param(t_sec,s_q,tmp);
00287         if (tmp.len) {
00288             c = tmp.s[tmp.len];
00289             tmp.s[tmp.len]=0;           
00290             t_q = atof(tmp.s);
00291             tmp.s[tmp.len]=c;
00292         }   
00293         else t_q = -1;
00294         if (t_q > q_q || q_sec.len==0)  {           
00295             q_sec = t_sec;
00296             q_q = t_q;
00297             q_type = t_type;
00298         }       
00299     }
00300 
00301     if (!q_sec.len) {
00302         LOG(L_INFO,"DBG:"M_NAME":cscf_get_pref_security_header: No known Security header found.\n");
00303         return q_sec;
00304     }   
00305     
00306     if (type) *type = q_type;
00307     if (q) *q = q_q;
00308     return q_sec;
00309 }

r_contact* save_contact_security ( struct sip_msg *  req,
str  auth,
str  sec_hdr,
r_security_type  type,
float  q 
)

Saves the Contact Security information into the P-CSCF registrar for this contact.

Parameters:
req - REGISTER request
auth - WWW-Authenticate header
sec_hdr - Security header
type - Security Type
q - Preference Value

Definition at line 320 of file security.c.

References ck, cscf_parse_contacts(), free_r_security(), get_next_spi(), get_param, get_qparam, ik, M_NAME, new_r_ipsec(), new_r_security(), _r_ipsec::port_us, r_act_time(), REG_PENDING, s_aes_in, s_aes_out, s_alg, s_ck, s_des_in, s_des_out, s_ealg, s_ik, s_md5_in, s_md5_out, s_null_out, s_port_c, s_port_s, s_sha_in, s_sha_out, s_spi_c, s_spi_s, SEC_IPSEC, SEC_NONE, SEC_TLS, strtoint, time_now, and update_r_contact_sec().

Referenced by P_security_401().

00321 {
00322     contact_t* c=0;
00323     contact_body_t* b=0;    
00324     r_contact *rc;
00325     enum Reg_States reg_state=REG_PENDING;
00326     int expires,pending_expires=60;
00327     struct sip_uri puri;
00328     r_security *s=0;
00329     
00330     b = cscf_parse_contacts(req);
00331     
00332     if (!b||!b->contacts) {
00333         LOG(L_ERR,"ERR:"M_NAME":save_contact_security: No contacts found\n");
00334         goto error; 
00335     }
00336     
00337     if (b) c = b->contacts;
00338             
00339     r_act_time();
00340     /* the Security works for just 1 contact/registration! */
00341     if(c){
00342         LOG(L_DBG,"DBG:"M_NAME":save_contact_security: <%.*s>\n",c->uri.len,c->uri.s);
00343         
00344         expires = time_now+pending_expires;
00345         
00346         if (parse_uri(c->uri.s,c->uri.len,&puri)<0){
00347             LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Error parsing Contact URI <%.*s>\n",c->uri.len,c->uri.s);
00348             goto error;         
00349         }
00350         if (puri.port_no==0) puri.port_no=5060;
00351         LOG(L_DBG,"DBG:"M_NAME":save_contact_security: %d %.*s : %d\n",
00352             puri.proto, puri.host.len,puri.host.s,puri.port_no);
00353 
00354         if (type == SEC_TLS) 
00355             puri.proto = PROTO_TLS;
00356 
00357         /* create the r_security structure */
00358         s = new_r_security(sec_hdr,type,q);
00359         if (!s) goto error; 
00360 
00361         switch(type) {
00362             case SEC_NONE:
00363                 break;
00364             case SEC_TLS:
00365                 // r_tls creation happens on 200
00366                 break;
00367             case SEC_IPSEC:
00368             {
00369                 /* then parse the parameters */
00370                 r_ipsec *ipsec; 
00371                 str ck,ik,ealg,alg,tmp;
00372                 str alg_setkey,ealg_setkey;
00373                 unsigned int spi_uc,spi_us;
00374                 unsigned int spi_pc,spi_ps;
00375                 int port_uc,port_us;
00376                 char ck_c[64],ik_c[64];
00377                 str ck_esp={ck_c,0},ik_esp={ik_c,0};
00378                                     
00379                 get_qparam(auth,s_ck,ck);
00380                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: CK: <%.*s>\n",
00381                     ck.len,ck.s);
00382                 get_qparam(auth,s_ik,ik);
00383                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: IK: <%.*s>\n",
00384                     ik.len,ik.s);       
00385                 get_param(sec_hdr,s_ealg,ealg);
00386                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Enc Algorithm: <%.*s>\n",
00387                     ealg.len,ealg.s);
00388                 get_param(sec_hdr,s_alg,alg);
00389                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Int Algorithm: <%.*s>\n",
00390                     alg.len,alg.s);
00391                 /* and for spis */
00392                 get_param(sec_hdr,s_spi_c,tmp);
00393                 strtoint(tmp,spi_uc);
00394                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-C: %d\n",
00395                     spi_uc);
00396                 get_param(sec_hdr,s_spi_s,tmp);
00397                 strtoint(tmp,spi_us);
00398                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: SPI-S: %d\n",
00399                     spi_us);
00400                 /* and for ports */
00401                 get_param(sec_hdr,s_port_c,tmp);
00402                 strtoint(tmp,port_uc);
00403                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-C: %d\n",
00404                     port_uc);
00405                 get_param(sec_hdr,s_port_s,tmp);
00406                 strtoint(tmp,port_us);
00407                 LOG(L_DBG,"DBG:"M_NAME":save_contact_security: Port-S: %d\n",
00408                     port_us);
00409         
00410                 ck_esp.s[ck_esp.len++]='0';
00411                 ck_esp.s[ck_esp.len++]='x'; 
00412                 if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) {
00413                     memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32;
00414                     memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16;
00415                     ealg_setkey = s_des_out;
00416                 }
00417                 else
00418                 if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) {
00419                     memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
00420                     ealg_setkey = s_aes_out;
00421                 }else {
00422                     memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len;
00423                     ealg_setkey = s_null_out;
00424                     ealg = s_null_out;
00425                 }
00426             
00427                 ik_esp.s[ik_esp.len++]='0';
00428                 ik_esp.s[ik_esp.len++]='x';     
00429                 if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) {
00430                     memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
00431                     alg_setkey = s_md5_out;
00432                 }
00433                 else
00434                 if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) {      
00435                     memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len;
00436                     memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8;
00437                     alg_setkey = s_sha_out;
00438                 }else{
00439                     LOG(L_ERR,"ERR:"M_NAME":save_contact_security: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s);
00440                     goto error;
00441                 }
00442                 
00443                 spi_pc=get_next_spi();  
00444                 spi_ps=get_next_spi();  
00445 
00446                 ipsec = new_r_ipsec(spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us,
00447                     ealg_setkey,ealg, ck_esp,alg_setkey,alg, ik_esp);
00448                 if (!ipsec) goto error;
00449                 s->data.ipsec = ipsec;
00450                 
00451                 puri.port_no = ipsec->port_us;
00452                 /*
00453                  * this should actually be port_uc... then the cscf_get_ue_via should be 
00454                  * changed to give rport and not the port in the via. but this would
00455                  * break NATed clients...
00456                  */
00457             }
00458                 break;
00459         }
00460     }
00461     
00462     rc = update_r_contact_sec(puri.host,puri.port_no,puri.proto,
00463             &(c->uri),&reg_state,&expires,s);                       
00464 
00465     return rc;  
00466 error:
00467     if (s) free_r_security(s);
00468     return 0;   
00469 }

int execute_cmd ( char *  cmd  )  [inline]

Executes an external command.

Used to call the IPSec scripts/commands.

Note:
Temporarily disabled the signal for SIGCHLD. Logs the output of the command
Parameters:
cmd - full command to execute, with parameters
Returns:
1 if ok, 0 on error

Definition at line 479 of file security.c.

References M_NAME, and out.

Referenced by P_security_200(), P_security_401(), and P_security_drop().

00480 {
00481     FILE *p;
00482     void *prev;
00483     char out[256];
00484     LOG(L_INFO,"INF:"M_NAME":execute_cmd: [%s]\n",cmd);     
00485     /* because SER forked dies when a chield dies, SIGCHLD is masked temporary */
00486     prev = signal(SIGCHLD,SIG_DFL);
00487     p = popen(cmd,"r");
00488     if (!p) {       
00489         LOG(L_ERR,"ERR:"M_NAME":execute_cmd: Error executing cmd> %s\n",cmd);
00490         signal(SIGCHLD,prev);   
00491         return 0;
00492     }
00493     while(fgets(out,256,p))
00494         LOG(L_DBG,"DBG:"M_NAME":execute_cmd: > %s",out);
00495     pclose(p);
00496     signal(SIGCHLD,prev);   
00497     return 1;
00498 }

int P_verify_security ( struct sip_msg *  req,
char *  str1,
char *  str2 
)

Process the REGISTER and verify Client-Security.

Parameters:
req - Register request
str1 - not used
str2 - not used
Returns:
1 if ok, 0 if not

Definition at line 507 of file security.c.

References cscf_get_first_via(), cscf_get_pref_security_header(), CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, _r_security::data, get_param, get_r_contact(), _r_contact::hash, _r_security::ipsec, M_NAME, pcscf_ipsec_port_c, pcscf_ipsec_port_s, pcscf_tls_port, r_act_time(), _r_ipsec::r_alg, _r_ipsec::r_ealg, r_unlock(), r_valid_contact(), s_alg, s_ealg, s_port_c, s_port_s, s_security_verify, s_spi_c, s_spi_s, SEC_IPSEC, SEC_NONE, SEC_TLS, _r_contact::security_temp, _r_ipsec::spi_pc, _r_ipsec::spi_ps, strtoint, and _r_security::type.

00508 {
00509     str sec_hdr;
00510     struct hdr_field *h;
00511     struct via_body *vb;
00512     r_contact *c;
00513     r_security *s;
00514     r_security_type sec_type;
00515     float sec_q;
00516     
00517     str ealg,alg,tmp;
00518     unsigned int spi_pc,spi_ps;;
00519     int port_pc,port_ps;
00520 
00521     vb = cscf_get_first_via(req,&h);
00522 
00523     LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Looking for <%d://%.*s:%d> \n", vb->proto,vb->host.len,vb->host.s,vb->port);
00524 
00525     c = get_r_contact(vb->host,vb->port,vb->proto);
00526 
00527     r_act_time();
00528     if (!c){
00529         //first register
00530         LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Contact found ! \n");
00531         return CSCF_RETURN_TRUE;
00532     }
00533 
00534     if (!r_valid_contact(c) || !c->security_temp){
00535         LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No security temp !.\n");
00536         r_unlock(c->hash);
00537         return CSCF_RETURN_TRUE;
00538     }
00539 
00540     sec_hdr = cscf_get_pref_security_header(req,s_security_verify, &sec_type,&sec_q);
00541     if (!sec_hdr.len)
00542     {   
00543         LOG(L_DBG,"DBG:"M_NAME":P_verify_security: No Security-Verify header found.\n");
00544         r_unlock(c->hash);
00545         return CSCF_RETURN_TRUE;
00546     }
00547     
00548     s = c->security_temp;
00549     
00550     switch (s->type)
00551     {
00552     case SEC_NONE:
00553         break;
00554     case SEC_TLS:
00555         if (sec_type != SEC_TLS || req->rcv.dst_port != pcscf_tls_port)
00556                     goto error;
00557         break;
00558     case SEC_IPSEC:
00559         if (sec_type != SEC_IPSEC || req->rcv.dst_port != pcscf_ipsec_port_s)
00560         {
00561             LOG(L_INFO,"DBG:"M_NAME":P_verify_security: Not IPSEC tunnel!.\n");
00562             r_unlock(c->hash);
00563             goto error;
00564         }
00565         get_param(sec_hdr,s_ealg,ealg);
00566         get_param(sec_hdr,s_alg,alg);
00567         /* and for spis */
00568         get_param(sec_hdr,s_spi_c,tmp);
00569         strtoint(tmp,spi_pc);
00570         get_param(sec_hdr,s_spi_s,tmp);
00571         strtoint(tmp,spi_ps);
00572         /* and for ports */
00573         get_param(sec_hdr,s_port_c,tmp);
00574         strtoint(tmp,port_pc);
00575         get_param(sec_hdr,s_port_s,tmp);
00576         strtoint(tmp,port_ps);
00577         if ((s->data.ipsec->r_ealg.len != ealg.len || strncasecmp(s->data.ipsec->r_ealg.s, ealg.s, ealg.len)) ||
00578                 (s->data.ipsec->r_alg.len != alg.len || strncasecmp(s->data.ipsec->r_alg.s, alg.s, alg.len)) || 
00579                 (s->data.ipsec->spi_pc != spi_pc) ||
00580                 (s->data.ipsec->spi_ps != spi_ps) ||
00581                 (pcscf_ipsec_port_c != port_pc) ||
00582                 (pcscf_ipsec_port_s != port_ps))
00583         {       
00584             LOG(L_INFO,"DBG:"M_NAME":P_verify_security: No valid Security-Verify header!.\n");
00585             r_unlock(c->hash);
00586             goto error;
00587         }
00588         break;
00589     }
00590     r_unlock(c->hash);
00591     
00592     return CSCF_RETURN_TRUE;
00593 error:  
00594     return CSCF_RETURN_FALSE;
00595 }

int P_security_401 ( struct sip_msg *  rpl,
char *  str1,
char *  str2 
)

Process the 401 response for REGISTER and creates the first Security-Associations.

IPSEc: Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER could come over that one.

Parameters:
rpl - the 401 response
str1 - not used
str2 - not used
Returns:
1 if ok, 0 if not

Definition at line 606 of file security.c.

References _r_ipsec::alg, _r_ipsec::ck, cscf_add_header(), cscf_get_authenticate(), cscf_get_pref_security_header(), cscf_get_request_from_reply(), CSCF_RETURN_ERROR, CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, _r_security::data, _r_ipsec::ealg, execute_cmd(), _r_contact::hash, _r_contact::host, _r_ipsec::ik, _r_security::ipsec, M_NAME, pcscf_ipsec_host, pcscf_ipsec_P_Inc_Req, pcscf_ipsec_port_c, pcscf_ipsec_port_s, pcscf_use_ipsec, pcscf_use_tls, _r_ipsec::port_uc, _r_ipsec::r_alg, _r_ipsec::r_ealg, r_unlock(), s_security_client, s_security_server_e, s_security_server_s, save_contact_security(), SEC_IPSEC, SEC_NONE, SEC_TLS, _r_contact::security_temp, _r_ipsec::spi_pc, _r_ipsec::spi_ps, and STR_APPEND.

00607 {
00608     struct sip_msg *req;
00609     struct hdr_field *hdr;  
00610     str sec_hdr,sec_srv={0,0};
00611     r_security_type sec_type;
00612     char cmd[256];
00613     r_contact *c;
00614     r_ipsec *ipsec;
00615     float sec_q=-1;
00616     str auth;
00617 
00618     if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false;
00619     
00620     req = cscf_get_request_from_reply(rpl);
00621     if (!req){
00622         LOG(L_ERR,"ERR:"M_NAME":P_security_401: No transactional request found.\n");
00623         goto error;
00624     }
00625     auth = cscf_get_authenticate(rpl,&hdr);
00626     if (!auth.len){
00627         LOG(L_ERR,"ERR:"M_NAME":P_security_401: No WWW-Authenticate header found.\n");
00628         goto ret_false; 
00629     }
00630     
00631     sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q);
00632     if (!sec_hdr.len) { 
00633         LOG(L_DBG,"DBG:"M_NAME":P_security_401: No Security-Client header found.\n");
00634         goto ret_false;
00635     }
00636     LOG(L_INFO,"DBG:"M_NAME":P_security_401: Security-Client header found : <%.*s>.\n", sec_hdr.len, sec_hdr.s);    
00637 
00638 
00639     /* save data into registrar */
00640     c = save_contact_security(req, auth, sec_hdr, sec_type, sec_q); 
00641     if (!c) goto error;
00642     switch(sec_type){
00643         case SEC_NONE:
00644             break;
00645         case SEC_TLS:           
00646             /* try to add the Security-Server header */     
00647             sec_srv.len = s_security_server_s.len+sec_hdr.len+s_security_server_e.len;
00648             sec_srv.s = pkg_malloc(sec_srv.len);
00649             if (!sec_srv.s){
00650                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len);
00651                 goto error;
00652             }
00653             sec_srv.len=0;
00654             STR_APPEND(sec_srv,s_security_server_s);
00655             STR_APPEND(sec_srv,sec_hdr);
00656             STR_APPEND(sec_srv,s_security_server_e);
00657 
00658             if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
00659                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
00660                 pkg_free(sec_srv.s);
00661                 goto error;
00662             }
00663             break;
00664         case SEC_IPSEC:
00665             ipsec = c->security_temp->data.ipsec;
00666             /* try to add the Security-Server header */
00667             sprintf(cmd,"Security-Server: ipsec-3gpp; ealg=%.*s; alg=%.*s; spi-c=%d; spi-s=%d; port-c=%d; port-s=%d; q=0.1\r\n",
00668                 ipsec->r_ealg.len,ipsec->r_ealg.s,
00669                 ipsec->r_alg.len,ipsec->r_alg.s,
00670                 ipsec->spi_pc,ipsec->spi_ps,
00671                 pcscf_ipsec_port_c,pcscf_ipsec_port_s);
00672             
00673             sec_srv.len = strlen(cmd);
00674             sec_srv.s = pkg_malloc(sec_srv.len);
00675             if (!sec_srv.s){
00676                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len);
00677                 goto error;
00678             }
00679             memcpy(sec_srv.s,cmd,sec_srv.len);
00680             if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) {
00681                 LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s);
00682                 pkg_free(sec_srv.s);
00683                 goto error;
00684             }
00685     
00686             /* run the IPSec script */  
00687             /* P_Inc_Req */
00688             sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s",
00689                 pcscf_ipsec_P_Inc_Req,
00690                 c->host.len,c->host.s,
00691                 ipsec->port_uc,
00692                 pcscf_ipsec_host,
00693                 pcscf_ipsec_port_s,
00694                 ipsec->spi_ps,
00695                 ipsec->ealg.len,ipsec->ealg.s,
00696                 ipsec->ck.len,ipsec->ck.s,
00697                 ipsec->alg.len,ipsec->alg.s,
00698                 ipsec->ik.len,ipsec->ik.s);
00699 
00700             r_unlock(c->hash);
00701                 
00702             execute_cmd(cmd);
00703             break;                      
00704     }
00705     
00706     return CSCF_RETURN_TRUE;
00707 ret_false:
00708     return CSCF_RETURN_FALSE;
00709 error:
00710     return CSCF_RETURN_ERROR;
00711 }

int P_security_200 ( struct sip_msg *  rpl,
char *  str1,
char *  str2 
)

Process the 200 response for REGISTER and creates the first Security-Associations.

The rest of the SA are not set. could come over that one.

Parameters:
rpl - the 200 response
str1 - not used
str2 - not used
Returns:
1 if ok, 0 if not

Definition at line 723 of file security.c.

References _r_ipsec::alg, _r_ipsec::ck, cscf_get_first_via(), cscf_get_max_expires(), cscf_get_pref_security_header(), cscf_get_request_from_reply(), CSCF_RETURN_ERROR, CSCF_RETURN_FALSE, CSCF_RETURN_TRUE, _r_security::data, DEREGISTERED, _r_ipsec::ealg, execute_cmd(), _r_contact::expires, free_r_security(), get_r_contact(), get_tls_session_hash, _r_contact::hash, _r_contact::host, _r_ipsec::ik, _r_security::ipsec, M_NAME, new_r_tls(), P_security_drop(), pcscf_ipsec_host, pcscf_ipsec_P_Inc_Rpl, pcscf_ipsec_P_Out_Req, pcscf_ipsec_P_Out_Rpl, pcscf_ipsec_port_c, pcscf_ipsec_port_s, pcscf_use_ipsec, pcscf_use_tls, _r_tls::port_tls, _r_ipsec::port_uc, _r_ipsec::port_us, r_act_time(), r_unlock(), r_valid_contact(), _r_contact::reg_state, s_security_client, SEC_IPSEC, SEC_NONE, SEC_TLS, _r_contact::security, _r_contact::security_temp, _r_tls::session_hash, _r_ipsec::spi_pc, _r_ipsec::spi_uc, _r_ipsec::spi_us, time_now, _r_security::tls, tls_get_session_hash(), and _r_security::type.

00724 {
00725     struct sip_msg *req;
00726     str sec_hdr;
00727     r_security_type sec_type;
00728     float sec_q;
00729     struct hdr_field *h;
00730     struct via_body *vb;
00731     r_contact *c;
00732     r_ipsec *i;
00733     int expires;
00734     unsigned long s_hash;
00735     char out_rpl[256],out_req[256],inc_rpl[256];
00736 
00737     if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false;
00738 
00739     req = cscf_get_request_from_reply(rpl);
00740     if (!req){
00741         LOG(L_ERR,"ERR:"M_NAME":P_security_200: No transactional request found.\n");
00742         goto error;
00743     }   
00744 
00745     sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q);   
00746     if (!sec_hdr.len) { 
00747         LOG(L_DBG,"DBG:"M_NAME":P_security_200: No Security-Verify header found.\n");
00748         goto error;
00749     }
00750     
00751     /* find the expires (reg or dereg?) */
00752     expires = cscf_get_max_expires(req);
00753     
00754     /* get the IPSec info from the registrar */
00755     
00756     vb = cscf_get_first_via(req,&h);    
00757     LOG(L_DBG,"DBG:"M_NAME":P_security_200: Looking for <%d://%.*s:%d> \n",
00758         vb->proto,vb->host.len,vb->host.s,vb->port);
00759 
00760     c = get_r_contact(vb->host,vb->port,vb->proto);
00761         
00762     r_act_time();
00763     if (!c){
00764         LOG(L_ERR,"ERR:"M_NAME":P_security_200: Contact not found\n");      
00765         goto error;
00766     }
00767     
00768     if (c->security_temp){
00769         if (c->security && c->security->type == SEC_TLS && 
00770                 (c->security->data.tls && c->security->