// Get CK and IK from WWW-Authenticate static int get_ck_ik(const struct sip_msg* m, str* ck, str* ik) { struct hdr_field *www_auth_hdr = NULL; str www_auth; memset(&www_auth, 0, sizeof(str)); www_auth = cscf_get_authenticate((sip_msg_t*)m, &www_auth_hdr); *ck = get_www_auth_param("ck", www_auth); if (ck->len == 0) { LM_ERR("Error getting CK\n"); return -1; } *ik = get_www_auth_param("ik", www_auth); if (ck->len == 0) { LM_ERR("Error getting IK\n"); return -1; } return 0; }
/** * 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. * @param rpl - the 401 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_security_401(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; struct hdr_field *hdr; str sec_hdr,sec_srv={0,0}; r_security_type sec_type; char cmd[256]; r_contact *c; r_ipsec *ipsec; float sec_q=-1; str auth; if (!pcscf_use_ipsec &&!pcscf_use_tls) goto ret_false; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: No transactional request found.\n"); goto error; } auth = cscf_get_authenticate(rpl,&hdr); if (!auth.len){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: No WWW-Authenticate header found.\n"); goto ret_false; } sec_hdr = cscf_get_pref_security_header(req,s_security_client, &sec_type,&sec_q); if (!sec_hdr.len) { LOG(L_DBG,"DBG:"M_NAME":P_security_401: No Security-Client header found.\n"); goto ret_false; } LOG(L_INFO,"DBG:"M_NAME":P_security_401: Security-Client header found : <%.*s>.\n", sec_hdr.len, sec_hdr.s); /* save data into registrar */ c = save_contact_security(req, auth, sec_hdr, sec_type, sec_q); if (!c) goto error; switch(sec_type){ case SEC_NONE: break; case SEC_TLS: /* try to add the Security-Server header */ sec_srv.len = s_security_server_s.len+sec_hdr.len+s_security_server_e.len; sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } sec_srv.len=0; STR_APPEND(sec_srv,s_security_server_s); STR_APPEND(sec_srv,sec_hdr); STR_APPEND(sec_srv,s_security_server_e); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } break; case SEC_IPSEC: ipsec = c->security_temp->data.ipsec; /* try to add the Security-Server header */ 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", ipsec->r_ealg.len,ipsec->r_ealg.s, ipsec->r_alg.len,ipsec->r_alg.s, ipsec->spi_pc,ipsec->spi_ps, pcscf_ipsec_port_c,pcscf_ipsec_port_s); sec_srv.len = strlen(cmd); sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } memcpy(sec_srv.s,cmd,sec_srv.len); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_security_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } /* run the IPSec script */ /* P_Inc_Req */ sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Req, c->host.len,c->host.s, ipsec->port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, ipsec->spi_ps, ipsec->ealg.len,ipsec->ealg.s, ipsec->ck.len,ipsec->ck.s, ipsec->alg.len,ipsec->alg.s, ipsec->ik.len,ipsec->ik.s); r_unlock(c->hash); execute_cmd(cmd); break; } return CSCF_RETURN_TRUE; ret_false: return CSCF_RETURN_FALSE; error: return CSCF_RETURN_ERROR; }
/** * Process the 401 response for REGISTER and creates the first Security-Associations. * Only the SA for P_Inc_Req - Incoming Requests is set now as the next REGISTER * could come over that one. * @param rpl - the 401 response * @param str1 - not used * @param str2 - not used * @returns 1 if ok, 0 if not */ int P_IPSec_401(struct sip_msg *rpl,char *str1, char *str2) { struct sip_msg *req; str auth; struct hdr_field *hdr; str sec_cli,sec_srv={0,0}; str ck,ik; char ck_c[64],ik_c[64]; str ck_esp={ck_c,0},ik_esp={ik_c,0}; str alg,ealg; str alg_setkey,ealg_setkey; str tmp; unsigned int spi_uc,spi_us; unsigned int spi_pc,spi_ps; int port_uc,port_us; char cmd[256]; str ue; contact_body_t *contact; struct sip_uri uri; req = cscf_get_request_from_reply(rpl); if (!req){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No transactional request found.\n"); goto error; } auth = cscf_get_authenticate(rpl,&hdr); if (!auth.len){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: No authorization header found.\n"); goto error; } sec_cli = cscf_get_security_client(req,&hdr); if (!sec_cli.len){ LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: No Security-Client header found.\n"); goto error; } /* first we look for CK, IK */ get_qparam(auth,s_ck,ck); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: CK: <%.*s>\n", ck.len,ck.s); get_qparam(auth,s_ik,ik); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: IK: <%.*s>\n", ik.len,ik.s); /* then for algorithms */ get_param(sec_cli,s_ealg,ealg); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Enc Algorithm: <%.*s>\n", ealg.len,ealg.s); get_param(sec_cli,s_alg,alg); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Int Algorithm: <%.*s>\n", alg.len,alg.s); /* and for spis */ get_param(sec_cli,s_spi_c,tmp); strtoint(tmp,spi_uc); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-C: %d\n", spi_uc); get_param(sec_cli,s_spi_s,tmp); strtoint(tmp,spi_us); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: SPI-S: %d\n", spi_us); /* and for ports */ get_param(sec_cli,s_port_c,tmp); strtoint(tmp,port_uc); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-C: %d\n", port_uc); get_param(sec_cli,s_port_s,tmp); strtoint(tmp,port_us); LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: Port-S: %d\n", port_us); contact = cscf_parse_contacts(req); if (!contact) { LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Message contains no Contact!\n"); goto error; } if (contact->contacts){ ue = contact->contacts->uri; if (parse_uri(ue.s,ue.len,&uri)){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error parsing uri <%.*s>\n",ue.len,ue.s); goto error; } ue = uri.host; if (uri.port_no==0) port_uc=5060; }else ue = req->via1->host; LOG(L_DBG,"DBG:"M_NAME":P_ipsec_401: UE IP: <%.*s> \n",ue.len,ue.s); spi_pc=get_next_spi(); spi_ps=get_next_spi(); ck_esp.s[ck_esp.len++]='0'; ck_esp.s[ck_esp.len++]='x'; if (ealg.len == s_des_in.len && strncasecmp(ealg.s,s_des_in.s,ealg.len)==0) { memcpy(ck_esp.s+ck_esp.len,ck.s,32);ck_esp.len+=32; memcpy(ck_esp.s+ck_esp.len,ck.s,16);ck_esp.len+=16; ealg_setkey = s_des_out; } else if (ealg.len == s_aes_in.len && strncasecmp(ealg.s,s_aes_in.s,ealg.len)==0) { memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len; ealg_setkey = s_aes_out; }else { memcpy(ck_esp.s+ck_esp.len,ck.s,ck.len);ck_esp.len+=ck.len; ealg_setkey = s_null_out; ealg = s_null_out; } ik_esp.s[ik_esp.len++]='0'; ik_esp.s[ik_esp.len++]='x'; if (alg.len == s_md5_in.len && strncasecmp(alg.s,s_md5_in.s,alg.len)==0) { memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len; alg_setkey = s_md5_out; } else if (alg.len == s_sha_in.len && strncasecmp(alg.s,s_sha_in.s,alg.len)==0) { memcpy(ik_esp.s+ik_esp.len,ik.s,ik.len);ik_esp.len+=ik.len; memcpy(ik_esp.s+ik_esp.len,"00000000",8);ik_esp.len+=8; alg_setkey = s_sha_out; }else{ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Unknown Integrity algorithm <%.*s>\n",alg.len,alg.s); goto error; } /* try to add the Security-Server header */ 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", ealg.len,ealg.s, alg.len,alg.s, spi_pc,spi_ps, pcscf_ipsec_port_c,pcscf_ipsec_port_s); sec_srv.len = strlen(cmd); sec_srv.s = pkg_malloc(sec_srv.len); if (!sec_srv.s){ LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error allocating %d pkg bytes \n",sec_srv.len); goto error; } memcpy(sec_srv.s,cmd,sec_srv.len); if (!cscf_add_header(rpl,&sec_srv,HDR_OTHER_T)) { LOG(L_ERR,"ERR:"M_NAME":P_ipsec_401: Error adding header <%.*s> \n",sec_srv.len,sec_srv.s); pkg_free(sec_srv.s); goto error; } /* run the IPSec script */ /* P_Inc_Req */ sprintf(cmd,"%s %.*s %d %s %d %d %.*s %.*s %.*s %.*s", pcscf_ipsec_P_Inc_Req, ue.len,ue.s, port_uc, pcscf_ipsec_host, pcscf_ipsec_port_s, spi_ps, ealg_setkey.len,ealg_setkey.s, ck_esp.len,ck_esp.s, alg_setkey.len,alg_setkey.s, ik_esp.len,ik_esp.s); execute_cmd(cmd); /* save data into registrar */ save_contact_ipsec(req,rpl, spi_uc,spi_us,spi_pc,spi_ps,port_uc,port_us, ealg_setkey,ck_esp,alg_setkey,ik_esp); return 1; error: return 0; }