diff --git a/auth.c b/auth.c index 544e1a9..34197c2 100644 --- a/auth.c +++ b/auth.c @@ -78,7 +78,7 @@ SQN sqn_he={0x00,0x00,0x00,0x00,0x00,0x00}; int createAuthHeaderMD5(char * user, char * password, int password_len, char * method, - char * uri, char * msgbody, char * auth, + char * uri, char * msgbody, char * auth, char * algo, char * result); int createAuthHeaderAKAv1MD5(char * user, char * OP, char * AMF, @@ -117,14 +117,14 @@ char *stristr (const char *s1, const char *s2) { char *cp = (char*) s1; char *p1, *p2, *endp; char l, r; - + endp = (char*)s1 + (strlen(s1) - strlen(s2)) ; while (*cp && (cp <= endp)) { p1 = cp; p2 = (char*)s2; while (*p1 && *p2) { l = toupper(*p1); - r = toupper(*p2); + r = toupper(*p2); if (l != r) { break; } @@ -140,7 +140,7 @@ char *stristr (const char *s1, const char *s2) { } int createAuthHeader(char * user, char * password, char * method, - char * uri, char * msgbody, char * auth, + char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, @@ -169,7 +169,7 @@ int createAuthHeader(char * user, char * password, char * method, return createAuthHeaderAKAv1MD5(user, aka_OP, aka_AMF, aka_K, - method,uri,msgbody,auth,algo,result); + method,uri,msgbody,auth,algo,result); }else{ sprintf(result, "createAuthHeader: authentication must use MD5 or AKAv1-MD5"); return 0; @@ -213,7 +213,7 @@ int getAuthParameter(char *name, char *header, char *result, int len) { } int createAuthHeaderMD5(char * user, char * password, int password_len, char * method, - char * uri, char * msgbody, char * auth, + char * uri, char * msgbody, char * auth, char * algo, char * result) { md5_byte_t ha1[MD5_HASH_SIZE], ha2[MD5_HASH_SIZE]; @@ -226,7 +226,7 @@ int createAuthHeaderMD5(char * user, char * password, int password_len, char * m md5_state_t Md5Ctx; char tmpbuf[2048]; - // Extract the Auth Type - If not present, using 'none' + // Extract the Auth Type - If not present, using 'none' cnonce[0] = '\0'; if (getAuthParameter("qop", auth, authtype, sizeof(authtype))) { sprintf(cnonce, "%x", rand()); @@ -238,13 +238,13 @@ int createAuthHeaderMD5(char * user, char * password, int password_len, char * m has_opaque = 1; } - // Extract the Realm + // Extract the Realm if (!getAuthParameter("realm", auth, tmp, sizeof(tmp))) { sprintf(result, "createAuthHeaderMD5: couldn't parse realm in '%s'", auth); return 0; } - // Load in A1 + // Load in A1 md5_init(&Md5Ctx); md5_append(&Md5Ctx, user, strlen(user)); md5_append(&Md5Ctx, ":", 1); @@ -256,14 +256,14 @@ int createAuthHeaderMD5(char * user, char * password, int password_len, char * m sprintf(result, "Digest username=\"%s\",realm=\"%s\"",user,tmp); - // Construct the URI + // Construct the URI if (auth_uri == NULL) { sprintf(tmp, "sip:%s", uri); } else { sprintf(tmp, "sip:%s", auth_uri); } - // If using Auth-Int make a hash of the body - which is NULL for REG + // If using Auth-Int make a hash of the body - which is NULL for REG if (stristr(authtype, "auth-int") != NULL) { md5_init(&Md5Ctx); md5_append(&Md5Ctx, msgbody, strlen(msgbody)); @@ -272,7 +272,7 @@ int createAuthHeaderMD5(char * user, char * password, int password_len, char * m sprintf(authtype, "auth-int"); } - // Load in A2 + // Load in A2 md5_init(&Md5Ctx); md5_append(&Md5Ctx, method, strlen(method)); md5_append(&Md5Ctx, ":", 1); @@ -291,7 +291,7 @@ int createAuthHeaderMD5(char * user, char * password, int password_len, char * m snprintf(tmpbuf, 2048, ",uri=\"%s\"",tmp); strcat(result,tmpbuf); - // Extract the Nonce + // Extract the Nonce if (!getAuthParameter("nonce", auth, tmp, sizeof(tmp))) { sprintf(result, "createAuthHeader: couldn't parse nonce"); return 0; @@ -333,7 +333,7 @@ int createAuthResponseMD5(char * user, char * password, int password_len, char * char tmp[MAX_HEADER_LEN]; md5_state_t Md5Ctx; - // Load in A1 + // Load in A1 md5_init(&Md5Ctx); md5_append(&Md5Ctx, user, strlen(user)); md5_append(&Md5Ctx, ":", 1); @@ -349,7 +349,7 @@ int createAuthResponseMD5(char * user, char * password, int password_len, char * strcpy(tmp, uri); } - // Load in A2 + // Load in A2 md5_init(&Md5Ctx); md5_append(&Md5Ctx, method, strlen(method)); md5_append(&Md5Ctx, ":", 1); @@ -495,7 +495,7 @@ char * base64_decode_string( const char *buf, unsigned int len, int *newlen ) x1 = base64_val(buf[i]); if (i+1stats->nRtds()); if (!start_time_rtd) { @@ -652,7 +652,7 @@ call::~call() if (use_tdmmap) { tdm_map[tdm_map_number] = false; } - + # ifdef PCAPPLAY if (media_thread != 0) { pthread_cancel(media_thread); @@ -761,7 +761,7 @@ bool call::connect_socket_if_needed() } else { saddr.ss_family = AF_INET; } - + if (peripsocket) { struct addrinfo * h ; struct addrinfo hints; @@ -771,7 +771,7 @@ bool call::connect_socket_if_needed() getaddrinfo(peripaddr, NULL, &hints, - &h); + &h); memcpy(&saddr, h->ai_addr, SOCK_ADDR_SIZE( @@ -833,7 +833,7 @@ bool call::connect_socket_if_needed() if (existing) { return true; } - + sipp_customize_socket(call_socket); if (use_remote_sending_addr) { @@ -899,30 +899,30 @@ bool call::lost(int index) return (((double)rand() / (double)RAND_MAX) < (percent / 100.0)); } -int call::send_raw(char * msg, int index, int len) +int call::send_raw(char * msg, int index, int len) { struct sipp_socket *sock; int rc; callDebug("Sending %s message for call %s (index %d, hash %u):\n%s\n\n", TRANSPORT_TO_STRING(transport), id, index, hash(msg), msg); - + if (useShortMessagef == 1) { struct timeval currentTime; GET_TIME (¤tTime); char* cs=get_header_content(msg,"CSeq:"); TRACE_SHORTMSG("%s\tS\t%s\tCSeq:%s\t%s\n", CStat::formatTime(¤tTime),id, cs, get_first_line(msg)); - } - + } + if((index!=-1) && (lost(index))) { TRACE_MSG("%s message voluntary lost (while sending).", TRANSPORT_TO_STRING(transport)); callDebug("%s message voluntary lost (while sending) (index %d, hash %u).\n", TRANSPORT_TO_STRING(transport), index, hash(msg)); - + if(comp_state) { comp_free(&comp_state); } call_scenario->messages[index] -> nb_lost++; return 0; } - + sock = call_socket; if ((use_remote_sending_addr) && (sendMode == MODE_SERVER)) { @@ -963,7 +963,7 @@ int call::send_raw(char * msg, int index, int len) if (len==0) { len = strlen(msg); } - + assert(sock); rc = write_socket(sock, msg, len, WS_BUFFER, &call_peer); @@ -1110,7 +1110,7 @@ char * call::get_header(char* message, char * name, bool content) while((ptr) && ((*(ptr+1) == ' ' ) || (*(ptr+1) == '\t') )) { - ptr = strchr(ptr + 1, '\n'); + ptr = strchr(ptr + 1, '\n'); } if(ptr) { *ptr = 0; } @@ -1166,19 +1166,19 @@ char * call::get_header(char* message, char * name, bool content) *(dest--) = 0; /* Remove trailing whitespaces, tabs, and CRs */ - while ((dest > last_header) && + while ((dest > last_header) && ((*dest == ' ') || (*dest == '\r')|| (*dest == '\t'))) { *(dest--) = 0; } - + /* Remove leading whitespaces */ for (start = last_header; *start == ' '; start++); /* remove enclosed CRs in multilines */ /* don't remove enclosed CRs for multiple headers (e.g. Via) (Rhys) */ while((ptr = strstr(last_header, "\r\n")) != NULL - && ( *(ptr + 2) == ' ' - || *(ptr + 2) == '\r' + && ( *(ptr + 2) == ' ' + || *(ptr + 2) == '\r' || *(ptr + 2) == '\t') ) { /* Use strlen(ptr) to include trailing zero */ memmove(ptr, ptr+1, strlen(ptr)); @@ -1188,7 +1188,7 @@ char * call::get_header(char* message, char * name, bool content) while((ptr = strstr(last_header, "\r\r")) != NULL) { memmove(ptr, ptr+1, strlen(ptr)); } - /* Remove illegal double Newline characters */ + /* Remove illegal double Newline characters */ while((ptr = strstr(last_header, "\n\n")) != NULL) { memmove(ptr, ptr+1, strlen(ptr)); } @@ -1211,7 +1211,7 @@ char * call::get_first_line(char * message) src = message; dest = last_header; - + int i=0; while (*src){ if((*src=='\n')||(*src=='\r')){ @@ -1224,7 +1224,7 @@ char * call::get_first_line(char * message) i++; src++; } - + return last_header; } @@ -1265,7 +1265,7 @@ char * call::get_last_request_uri () } last_request_uri[tmp_len] = '\0'; return last_request_uri; - + } char * call::send_scene(int index, int *send_status, int *len) @@ -1536,8 +1536,8 @@ bool call::executeMessage(message *curmsg) { /* Handle counters and RTDs for this message. */ do_bookkeeping(curmsg); - /* decide whether to increment cseq or not - * basically increment for anything except response, ACK or CANCEL + /* decide whether to increment cseq or not + * basically increment for anything except response, ACK or CANCEL * Note that cseq is only used by the [cseq] keyword, and * not by default */ @@ -1549,7 +1549,7 @@ bool call::executeMessage(message *curmsg) { ++cseq; incr_cseq = 1; } - + msg_snd = send_scene(msg_index, &send_status, &msgLen); if(send_status == -1 && errno == EWOULDBLOCK) { if (incr_cseq) --cseq; @@ -1607,7 +1607,7 @@ bool call::executeMessage(message *curmsg) { callDebug("Set Retransmission Hash: %u (recv index %d, send index %d)\n", recv_retrans_hash, recv_retrans_recv_index, recv_retrans_send_index); - /* Prevent from detecting the cause relation between send and recv + /* Prevent from detecting the cause relation between send and recv * in the next valid send */ last_recv_hash = 0; } @@ -1646,7 +1646,7 @@ bool call::executeMessage(message *curmsg) { recv_timeout = 0; curmsg->nb_timeout++; if (curmsg->on_timeout < 0) { - // if you set a timeout but not a label, the call is aborted + // if you set a timeout but not a label, the call is aborted WARNING("Call-Id: %s, receive timeout on message %s:%d without label to jump to (ontimeout attribute): aborting call", id, curmsg->desc, curmsg->index); computeStat(CStat::E_CALL_FAILED); @@ -1965,7 +1965,7 @@ bool call::process_unexpected(char * msg) TRANSPORT_TO_STRING(transport), msg_index, hash(msg), msg); if (default_behaviors & DEFAULT_BEHAVIOR_ABORTUNEXP) { - // if twin socket call => reset the other part here + // if twin socket call => reset the other part here if (twinSippSocket && (msg_index > 0)) { sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1)); } @@ -2005,14 +2005,14 @@ bool call::abortCall(bool writeLog) is_inv = !strncmp(last_send_msg, "INVITE", 6); } else { is_inv = false; - } + } if ((creationMode != MODE_SERVER) && (msg_index > 0)) { if ((call_established == false) && (is_inv)) { src_recv = last_recv_msg ; char L_msg_buffer[SIPP_MAX_MSG_SIZE]; L_msg_buffer[0] = '\0'; - // Answer unexpected errors (4XX, 5XX and beyond) with an ACK + // Answer unexpected errors (4XX, 5XX and beyond) with an ACK // Contributed by F. Tarek Rogers if((src_recv) && (get_reply_code(src_recv) >= 400)) { sendBuffer(createSendingMessage(get_default_message("ack"), -2)); @@ -2484,7 +2484,7 @@ char* call::createSendingMessage(SendingMessage *src, int P_index, char *msg_buf if (length_marker || auth_marker) { body = strstr(msg_buffer, "\r\n\r\n"); if (body) { - auth_body = body; + auth_body = body; auth_body += strlen("\r\n\r\n"); } } @@ -2674,13 +2674,13 @@ bool call::checkInternalCmd(char * cmd) while((*L_ptr1 == ' ') || (*L_ptr1 == '\t')) { L_ptr1++; } if (!(*L_ptr1)) {return (false);} L_ptr2 = L_ptr1; - while((*L_ptr2) && - (*L_ptr2 != ' ') && - (*L_ptr2 != '\t') && - (*L_ptr2 != '\r') && - (*L_ptr2 != '\n')) { + while((*L_ptr2) && + (*L_ptr2 != ' ') && + (*L_ptr2 != '\t') && + (*L_ptr2 != '\r') && + (*L_ptr2 != '\n')) { L_ptr2 ++; - } + } if(!*L_ptr2) { return (false); } L_backup = *L_ptr2; *L_ptr2 = 0; @@ -2720,7 +2720,7 @@ bool call::check_peer_src(char * msg, int search_index) *L_ptr2 = L_backup; return(true); } - + *L_ptr2 = L_backup; return (false); } @@ -2776,7 +2776,7 @@ void call::formatNextReqUrl (char* next_req_url) that needs to be removed */ char* actual_req_url = strchr(next_req_url, '<'); - if (actual_req_url) + if (actual_req_url) { /* using a temporary buffer */ char tempBuffer[MAX_HEADER_LEN]; @@ -2824,9 +2824,9 @@ void call::computeRouteSetAndRemoteTargetUri (char* rr, char* contact, bool bReq pointer = strrchr(rr, ','); } - if (pointer) + if (pointer) { - if (!isFirst) + if (!isFirst) { if (strlen(actual_rr) ) { @@ -2837,8 +2837,8 @@ void call::computeRouteSetAndRemoteTargetUri (char* rr, char* contact, bool bReq strcpy(actual_rr, pointer + 1); } strcat(actual_rr, ","); - } - else + } + else { isFirst = false; if (NULL == strstr (pointer, ";lr")) @@ -2857,17 +2857,17 @@ void call::computeRouteSetAndRemoteTargetUri (char* rr, char* contact, bool bReq strcat(actual_rr, ","); } } - } - else + } + else { - if (!isFirst) + if (!isFirst) { strcat(actual_rr, rr); - } + } // // this is the *only* RR header that was found // - else + else { if (NULL == strstr (rr, ";lr")) { @@ -2902,12 +2902,12 @@ void call::computeRouteSetAndRemoteTargetUri (char* rr, char* contact, bool bReq } } - if (strlen(actual_rr)) + if (strlen(actual_rr)) { dialog_route_set = (char *) calloc(1, strlen(actual_rr) + 2); sprintf(dialog_route_set, "%s", actual_rr); - } + } if (strlen (targetURI)) { @@ -3047,13 +3047,13 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) } /* Is it a response ? */ - if((msg[0] == 'S') && + if((msg[0] == 'S') && (msg[1] == 'I') && (msg[2] == 'P') && (msg[3] == '/') && (msg[4] == '2') && (msg[5] == '.') && - (msg[6] == '0') ) { + (msg[6] == '0') ) { reply_code = get_reply_code(msg); if(!reply_code) { @@ -3094,10 +3094,10 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) /* In case of INVITE or re-INVITE, ACK or PRACK get the media info if needed (= we got a pcap play action) */ - if ((strncmp(request, "INVITE", 6) == 0) - || (strncmp(request, "ACK", 3) == 0) + if ((strncmp(request, "INVITE", 6) == 0) + || (strncmp(request, "ACK", 3) == 0) || (strncmp(request, "PRACK", 5) == 0) - && (hasMedia == 1)) + && (hasMedia == 1)) get_remote_media_addr(msg); #endif @@ -3128,7 +3128,7 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) /* TODO : this is a little buggy: If a 100 trying from an INVITE * is delayed by the network until the BYE is sent, it may * stop BYE transmission erroneously, if the BYE also expects - * a 100 trying. */ + * a 100 trying. */ break; } @@ -3142,7 +3142,7 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) if(matches_scenario(search_index, reply_code, request, responsecseqmethod, txn)) { if (contig || call_scenario->messages[search_index]->optional == OPTIONAL_GLOBAL) { found = true; - break; + break; } else { if (int checkTxn = call_scenario->messages[search_index]->response_txn) { /* This is a reply to an old transaction. */ @@ -3287,8 +3287,8 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) if (rcseq > cseq) cseq = rcseq; } - /* This is an ACK/PRACK or a response, and its index is greater than the - * current active retransmission message, so we stop the retrans timer. + /* This is an ACK/PRACK or a response, and its index is greater than the + * current active retransmission message, so we stop the retrans timer. * True also for CANCEL and BYE that we also want to answer to */ if(((reply_code) || ((!strcmp(request, "ACK")) || @@ -3297,7 +3297,7 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) (search_index > last_send_index)) { /* * We should stop any retransmission timers on receipt of a provisional response only for INVITE - * transactions. Non INVITE transactions continue to retransmit at T2 until a final response is + * transactions. Non INVITE transactions continue to retransmit at T2 until a final response is * received */ if ( (0 == reply_code) || // means this is a request. @@ -3379,6 +3379,74 @@ bool call::process_incoming(char * msg, struct sockaddr_storage *src) dialog_challenge_type = reply_code; } + if ((call_scenario->messages[search_index] -> bShouldExportAKAIPSecKeys) && + (reply_code == 401 || reply_code == 407)) { + + MessageComponent* auth_comp = call_scenario->messages[search_index] -> auth_comp; + bool auth_comp_allocated = false; + if (auth_comp->type == E_Message_Injection) { + /* Need to read OP/K/AMF keys from CSV file. */ + char buf[200]; + char *dest = buf; + getFieldFromInputFile(auth_comp->comp_param.field_param.filename, + auth_comp->comp_param.field_param.field, + auth_comp->comp_param.field_param.line, dest); + dest = buf; + if (char *tmp = strstr(dest, "[authentication")) { + char *auth_marker = tmp; + auth_comp = (struct MessageComponent *)calloc(1, sizeof(struct MessageComponent)); + if (!auth_comp) { ERROR("Out of memory!"); } + auth_comp_allocated = true; + + tmp = strchr(auth_marker, ']'); + char c = *tmp; + *tmp = '\0'; + SendingMessage::parseAuthenticationKeyword(call_scenario, auth_comp, auth_marker); + *tmp = c; + } else { + ERROR("Expected authentication field"); + } + } + + /* Decode CK and IK using the supplied keys and the challenge nonce */ + char my_aka_OP[100]; + char my_aka_AMF[100]; + char my_aka_K[100]; + createSendingMessage(auth_comp->comp_param.auth_param.aka_K, -2, my_aka_K, sizeof(my_aka_K)); + createSendingMessage(auth_comp->comp_param.auth_param.aka_AMF, -2, my_aka_AMF, sizeof(my_aka_AMF)); + createSendingMessage(auth_comp->comp_param.auth_param.aka_OP, -2, my_aka_OP, sizeof(my_aka_OP)); + char ck[16]; + char ik[16]; + decodeAKAIPSecKeys(my_aka_OP, + my_aka_AMF, + my_aka_K, + dialog_authentication, + ck, + ik); + + /* Convert CK and IK to hex strings. */ + char hexa[]="0123456789abcdef"; + char* ck_s = (char*)calloc(33, sizeof(char)); + char* ik_s = (char*)calloc(33, sizeof(char)); + for (int i = 0; i < 16; i++) { + ck_s[2*i] = hexa[(ck[i] & 0xF0) >> 4]; + ck_s[2*i+1] = hexa[ck[i] & 0x0F]; + ik_s[2*i] = hexa[(ik[i] & 0xF0) >> 4]; + ik_s[2*i+1] = hexa[ik[i] & 0x0F]; + } + ck_s[33] = '\0'; + ik_s[33] = '\0'; + + /* Export CK and IK as $ck and $ik variables. */ + M_callVariableTable->getVar(call_scenario->messages[search_index]->ck_varId)->setString(ck_s); + M_callVariableTable->getVar(call_scenario->messages[search_index]->ik_varId)->setString(ik_s); + + if (auth_comp_allocated) + { + SendingMessage::freeMessageComponent(auth_comp); + } + } + /* If we are not advancing state, we should quite before we change this stuff. */ if (!call_scenario->messages[search_index]->advance_state) { return true; @@ -3836,7 +3904,7 @@ call::T_ActionResult call::executeAction(char * msg, message *curmsg) WARNING("system call error for %s",x); } } - exit(EXIT_OTHER); + exit(EXIT_OTHER); } break; default: @@ -3921,13 +3989,13 @@ void call::extractSubMessage(char * msg, char * matchingString, char* result, bo char mat2 = toupper(*matchingString); ptr = msg; - while (*ptr) { + while (*ptr) { if (!case_indep) { ptr = strstr(ptr, matchingString); if (ptr == NULL) break; if (headers == true && ptr != msg && *(ptr-1) != '\n') { ++ptr; - continue; + continue; } } else { if (headers) { @@ -3944,7 +4012,7 @@ void call::extractSubMessage(char * msg, char * matchingString, char* result, bo if (ptr1 == NULL) break; ptr = ptr1; } else { - if (ptr1 != NULL && ptr1 < ptr) ptr = ptr1; + if (ptr1 != NULL && ptr1 < ptr) ptr = ptr1; } } if (strncasecmp(ptr, matchingString, len) != 0) { @@ -3953,7 +4021,7 @@ void call::extractSubMessage(char * msg, char * matchingString, char* result, bo } } // here with ptr pointing to a matching string - if (occurrence <= 1) break; + if (occurrence <= 1) break; --occurrence; ++ptr; } @@ -3961,7 +4029,7 @@ void call::extractSubMessage(char * msg, char * matchingString, char* result, bo if(ptr != NULL && *ptr != 0) { strncpy(result, ptr+len, MAX_SUB_MESSAGE_LENGTH); sizeOf = strlen(result); - if(sizeOf >= MAX_SUB_MESSAGE_LENGTH) + if(sizeOf >= MAX_SUB_MESSAGE_LENGTH) sizeOf = MAX_SUB_MESSAGE_LENGTH-1; while((i reset the other part here + + // if twin socket call => reset the other part here if (twinSippSocket && (msg_index > 0)) { res = sendCmdBuffer (createSendingMessage(get_default_message("3pcc_abort"), -1)); } - + computeStat(CStat::E_CALL_FAILED); computeStat(CStat::E_FAILED_UNEXPECTED_MSG); delete this; @@ -4074,22 +4142,22 @@ bool call::automaticResponseMode(T_AutoMode P_case, char * P_recv) WARNING("Continuing call on unexpected CANCEL for call: %s", (id==NULL)?"none":id); } break ; - + case E_AM_PING: // response for a random ping // usage of last_ keywords last_recv_msg = (char *) realloc(last_recv_msg, strlen(P_recv) + 1); strcpy(last_recv_msg, P_recv); - + if (default_behaviors & DEFAULT_BEHAVIOR_PINGREPLY) { WARNING("Automatic response mode for an unexpected PING for call: %s", (id==NULL)?"none":id); sendBuffer(createSendingMessage(get_default_message("200"), -1)); - // Note: the call ends here but it is not marked as bad. PING is a + // Note: the call ends here but it is not marked as bad. PING is a // normal message. - // if twin socket call => reset the other part here + // if twin socket call => reset the other part here if (twinSippSocket && (msg_index > 0)) { res = sendCmdBuffer(createSendingMessage(get_default_message("3pcc_abort"), -1)); } - + CStat::globalStat(CStat::E_AUTO_ANSWERED); delete this; } else { diff --git a/call.hpp b/call.hpp index 63366a9..6ab57e1 100644 --- a/call.hpp +++ b/call.hpp @@ -53,9 +53,11 @@ #ifdef __HPUX extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result); + extern int decodeAKAIPSecKeys(char * aka_OP, char * aka_AMF, char * aka_K, char * auth, char * ck, char * ik); #else extern "C" { extern int createAuthHeader(char * user, char * password, char * method, char * uri, char * msgbody, char * auth, char * aka_OP, char * aka_AMF, char * aka_K, char * result); } extern "C" { int verifyAuthHeader(char * user, char * password, char * method, char * auth); } + extern "C" { int decodeAKAIPSecKeys(char * aka_OP, char * aka_AMF, char * aka_K, char * auth, char * ck, char * ik); } #endif struct txnInstanceInfo { @@ -140,7 +142,7 @@ class call : virtual public task, virtual public listener, public virtual socket /* How long until sending this message times out. */ unsigned int send_timeout; - /* Last received message (expected, not optional, and not + /* Last received message (expected, not optional, and not * retransmitted) and the associated hash. Stills setted until a new * scenario steps sends a message */ unsigned long last_recv_hash; @@ -170,7 +172,7 @@ class call : virtual public task, virtual public listener, public virtual socket play_args_t play_args_v; #endif - + /* holds the auth header and if the challenge was 401 or 407 */ char * dialog_authentication; int dialog_challenge_type; @@ -186,7 +188,7 @@ class call : virtual public task, virtual public listener, public virtual socket bool *rtd_done; char *peer_tag; - + struct sipp_socket *call_remote_socket; int call_port; @@ -198,7 +200,7 @@ class call : virtual public task, virtual public listener, public virtual socket // ie ACK received or sent // => init to false bool ack_is_pending; // == true if an ACK is pending - // Needed to avoid abortCall sending a + // Needed to avoid abortCall sending a // CANCEL instead of BYE in some extreme // cases for 3PCC scenario. // => init to false @@ -223,7 +225,7 @@ class call : virtual public task, virtual public listener, public virtual socket /* Store the last action result to allow */ /* call to continue and mark it as failed */ T_ActionResult last_action_result; - + /* rc == true means call not deleted by processing */ void formatNextReqUrl (char* next_req_url); void computeRouteSetAndRemoteTargetUri (char* rrList, char* contact, bool bRequestIncoming); @@ -231,8 +233,8 @@ class call : virtual public task, virtual public listener, public virtual socket bool executeMessage(message *curmsg); T_ActionResult executeAction(char * msg, message *message); - void extractSubMessage(char * msg, char * matchingString, char* result, bool case_indep, - int occurrence, bool headers); + void extractSubMessage(char * msg, char * matchingString, char* result, bool case_indep, + int occurrence, bool headers); bool rejectCall(); double get_rhs(CAction *currentAction); @@ -243,13 +245,13 @@ class call : virtual public task, virtual public listener, public virtual socket char* createSendingMessage(char * src, int P_index, bool skip_sanity = false); char* createSendingMessage(SendingMessage *src, int P_index, char *msg_buffer, int buflen, int *msgLen=NULL); - // method for the management of unexpected messages + // method for the management of unexpected messages bool checkInternalCmd(char* cmd); // check of specific internal command // received from the twin socket // used for example to cancel the call // of the third party bool check_peer_src(char* msg, - int search_index); // 3pcc extended mode:check if + int search_index); // 3pcc extended mode:check if // the twin message received // comes from the expected sender void sendBuffer(char *buf, int len = 0); // send a message out of a scenario @@ -259,7 +261,7 @@ class call : virtual public task, virtual public listener, public virtual socket int sendCmdMessage(message *curmsg); // 3PCC - int sendCmdBuffer(char* cmd); // for 3PCC, send a command out of a + int sendCmdBuffer(char* cmd); // for 3PCC, send a command out of a // scenario execution static void readInputFileContents(const char* fileName); diff --git a/message.hpp b/message.hpp index 65dd9ac..965f865 100644 --- a/message.hpp +++ b/message.hpp @@ -105,6 +105,12 @@ class SendingMessage { static void parseAuthenticationKeyword(scenario *msg_scenario, struct MessageComponent *dst, char *keyword); static void freeMessageComponent(struct MessageComponent *comp); + + // Get parameters from a [keyword] + static void getQuotedParam(char * dest, char * src, int * len); + static void getHexStringParam(char * dest, char * src, int * len); + static void getKeywordParam(char * src, char * param, char * output); + private: std::vector messageComponents; @@ -117,10 +123,6 @@ class SendingMessage { scenario *msg_scenario; - // Get parameters from a [keyword] - static void getQuotedParam(char * dest, char * src, int * len); - static void getHexStringParam(char * dest, char * src, int * len); - static void getKeywordParam(char * src, char * param, char * output); }; /* Custom Keyword Function Type. */ diff --git a/scenario.cpp b/scenario.cpp index 5c49a9b..8456e69 100644 --- a/scenario.cpp +++ b/scenario.cpp @@ -47,6 +47,7 @@ message::message(int index, const char *desc) sessions = 0; bShouldRecordRoutes = 0; bShouldAuthenticate = 0; + bShouldExportAKAIPSecKeys = 0; send_scheme = NULL; retrans_delay = 0; @@ -647,7 +648,7 @@ scenario::scenario(char * filename, int deflt) char *method_list = NULL; unsigned int scenario_file_cursor = 0; int L_content_length = 0 ; - char * peer; + char * peer; last_recv_optional = false; @@ -901,6 +902,49 @@ scenario::scenario(char * filename, int deflt) bool temp = get_bool(ptr, "message authentication"); curmsg -> bShouldAuthenticate = temp; } + + /* extract and decode the AKA crypto and integrity keys */ + if((ptr = xp_get_value((char *)"akakeys"))) { + curmsg -> bShouldExportAKAIPSecKeys = true; + curmsg->auth_comp = (struct MessageComponent *)calloc(1, sizeof(struct MessageComponent)); + if (!curmsg->auth_comp) { ERROR("Out of memory!"); } + + if (char *tmp = strstr(ptr, "[authentication")) { + /* authentication keys specified in scenario file */ + char *auth_marker = tmp; + tmp = strchr(auth_marker, ']'); + char c = *tmp; + *tmp = '\0'; + SendingMessage::parseAuthenticationKeyword(this, curmsg->auth_comp, auth_marker); + *tmp = c; + } else if (char* tmp = strstr(ptr, "[field")) { + /* authentication keys in CSV file */ + curmsg->auth_comp->type = E_Message_Injection; + + /* Parse out the interesting things like file and number. */ + curmsg->auth_comp->comp_param.field_param.field = atoi(tmp + strlen("[field")); + + char fileName[256]; + SendingMessage::getKeywordParam(tmp, "file=", fileName); + if (fileName[0] == '\0') { + if (!default_file) { + ERROR("No injection file was specified!\n"); + } + curmsg->auth_comp->comp_param.field_param.filename = strdup(default_file); + } else { + curmsg->auth_comp->comp_param.field_param.filename = strdup(fileName); + } + if (inFiles.find(curmsg->auth_comp->comp_param.field_param.filename) == inFiles.end()) { + ERROR("Invalid injection file: %s\n", fileName); + } + } else { + ERROR("akakeys must specify either authentication keys or a field"); + } + + /* Allocate the ck and ik variables and remember the identifiers. */ + curmsg->ck_varId = get_var("ck", "ck"); + curmsg->ik_varId = get_var("ik", "ck"); + } } else if(!strcmp(elem, "pause") || !strcmp(elem, "timewait")) { checkOptionalRecv(elem, scenario_file_cursor); curmsg->M_type = MSG_TYPE_PAUSE; @@ -956,7 +1000,7 @@ scenario::scenario(char * filename, int deflt) /* Sent messages descriptions */ /* 3pcc extended mode */ - if((ptr = xp_get_value((char *)"dest"))) { + if((ptr = xp_get_value((char *)"dest"))) { peer = strdup(ptr) ; curmsg ->peer_dest = peer ; peer_map::iterator peer_it; @@ -968,7 +1012,7 @@ scenario::scenario(char * filename, int deflt) T_peer_infos infos; infos.peer_socket = 0; strcpy(infos.peer_host, get_peer_addr(peer)); - peers[std::string(peer)] = infos; + peers[std::string(peer)] = infos; } } else if (extendedTwinSippMode) { ERROR("You must specify a 'dest' for sendCmd with extended 3pcc mode!"); @@ -1162,7 +1206,7 @@ CSample *parse_distribution(bool oldstyle = false) { /* 3pcc extended mode: get the correspondances between - slave and master names and their + slave and master names and their addresses */ void parse_slave_cfg() @@ -1194,7 +1238,7 @@ void parse_slave_cfg() } -// Determine in which mode the sipp tool has been +// Determine in which mode the sipp tool has been // launched (client, server, 3pcc client, 3pcc server, 3pcc extended master or slave) void scenario::computeSippMode() { @@ -1718,7 +1762,7 @@ int isWellFormed(char * P_listeStr, int * nombre) (*nombre) = 0; sizeOf = strlen(P_listeStr); - // getting the number + // getting the number if(sizeOf > 0) { // is the string well formed ? [0-9] [,] @@ -1729,13 +1773,13 @@ int isWellFormed(char * P_listeStr, int * nombre) { case ',': if(isANumber == false) - { + { return(0); } else { - (*nombre)++; - } + (*nombre)++; + } isANumber = false; break; case '0': @@ -1755,13 +1799,13 @@ int isWellFormed(char * P_listeStr, int * nombre) break; case '\0': if(isANumber == false) - { + { return(0); } else { (*nombre)++; - } + } break; default: return(0); @@ -1771,8 +1815,8 @@ int isWellFormed(char * P_listeStr, int * nombre) return(1); } -int createIntegerTable(char * P_listeStr, - unsigned int ** listeInteger, +int createIntegerTable(char * P_listeStr, + unsigned int ** listeInteger, int * sizeOfList) { int nb=0; @@ -1780,7 +1824,7 @@ int createIntegerTable(char * P_listeStr, char * ptr_prev = P_listeStr; unsigned int current_int; - if(P_listeStr){ + if(P_listeStr){ if(isWellFormed(P_listeStr, sizeOfList) == 1) { (*listeInteger) = new unsigned int[(*sizeOfList)]; @@ -1793,12 +1837,12 @@ int createIntegerTable(char * P_listeStr, (*listeInteger)[nb] = current_int; nb++; ptr_prev = ptr+1; - } + } ptr++; } // Read the last - sscanf(ptr_prev, "%u", ¤t_int); + sscanf(ptr_prev, "%u", ¤t_int); if (nb<(*sizeOfList)) (*listeInteger)[nb] = current_int; nb++; @@ -1995,7 +2039,7 @@ char * default_scenario [] = { "\n" "\n" "\n" -, +, /************* Default_scenario[1] ***************/ (char *) @@ -2400,7 +2444,7 @@ char * default_scenario [] = { "\n", /************* Default_scenario[4] ***************/ -(char*) +(char*) "\n" "\n" "\n" @@ -2532,7 +2576,7 @@ char * default_scenario [] = { "\n", /************* Default_scenario[5] ***************/ -(char*) +(char*) "\n" "\n" "\n" @@ -2628,7 +2672,7 @@ char * default_scenario [] = { "\n", /************* Default_scenario[6] ***************/ -(char*) +(char*) "\n" "\n" "\n" diff --git a/scenario.hpp b/scenario.hpp index 497aceb..80c30f0 100644 --- a/scenario.hpp +++ b/scenario.hpp @@ -45,11 +45,11 @@ #define MODE_3PCC_NONE 0 #define MODE_3PCC_CONTROLLER_A 2 -#define MODE_3PCC_CONTROLLER_B 3 +#define MODE_3PCC_CONTROLLER_B 3 #define MODE_3PCC_A_PASSIVE 4 /* 3pcc extended mode*/ -#define MODE_MASTER 5 +#define MODE_MASTER 5 #define MODE_MASTER_PASSIVE 6 #define MODE_SLAVE 7 @@ -69,7 +69,7 @@ class message { bool timewait; /* Number of sessions in a pause */ - int sessions; + int sessions; /* should collect route set? */ bool bShouldRecordRoutes; @@ -77,6 +77,14 @@ class message { /* should collect authentication info? */ bool bShouldAuthenticate; + /* should export AKA IPSec crypto and integrity keys (plus the parsed + * message component with the OP, K and AMF keys needed to decode them). + */ + bool bShouldExportAKAIPSecKeys; + struct MessageComponent * auth_comp; + int ck_varId; + int ik_varId; + /* If this is a send */ SendingMessage *send_scheme; unsigned int retrans_delay; @@ -137,7 +145,7 @@ class message { ContentLengthValueZero, ContentLengthValueNoZero }ContentLengthFlag; - + ContentLengthFlag content_length_flag ; char *recv_response_for_cseq_method_list; @@ -230,7 +238,7 @@ extern int thirdPartyMode; extern message::ContentLengthFlag content_length_flag; -void load_scenario(char * filename, +void load_scenario(char * filename, int deflt); /* 3pcc extended mode */ @@ -238,11 +246,11 @@ void parse_slave_cfg(); void getActionForThisMessage(); CSample *parse_distribution(bool oldstyle); -int createIntegerTable(char * P_listeStr, - unsigned int ** listeInteger, +int createIntegerTable(char * P_listeStr, + unsigned int ** listeInteger, int * sizeOfList); -int isWellFormed(char * P_listeStr, +int isWellFormed(char * P_listeStr, int * nombre); /* String table functions. */