Browse Source

modules/ims_usrloc_scscf: Added ability to do AKA resync of auth vectors
- this functionality is required for AKA authentication between network and SIM should they get out
of sync with each other re. sequence numbers

Jason Penton 11 năm trước cách đây
mục cha
commit
65e945a66f

+ 1 - 0
modules/ims_auth/api.h

@@ -53,6 +53,7 @@
  * return codes to config by auth functions
  */
 typedef enum auth_cfg_result {
+	AUTH_RESYNC_REQUESTED = -9,	/*!< resync requested from UE via auts param */
 	AUTH_USER_MISMATCH = -8,    /*!< Auth user != From/To user */
 	AUTH_NONCE_REUSED = -6,     /*!< Returned if nonce is used more than once */
 	AUTH_NO_CREDENTIALS = -5,   /*!< Credentials missing */

+ 1 - 0
modules/ims_auth/authims_mod.c

@@ -119,6 +119,7 @@ int ignore_failed_auth = 0;
 static cmd_export_t cmds[] = {
     {"ims_www_authenticate", (cmd_function) www_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
     {"ims_www_challenge", (cmd_function) www_challenge, 2, challenge_fixup_async, 0, REQUEST_ROUTE},
+    {"ims_www_resync_auth", (cmd_function) www_resync_auth, 2, challenge_fixup_async, 0, REQUEST_ROUTE},
     {"ims_proxy_authenticate", (cmd_function) proxy_authenticate, 1, auth_fixup, 0, REQUEST_ROUTE},
     {"ims_proxy_challenge", (cmd_function) proxy_challenge, 2, auth_fixup_async, 0, REQUEST_ROUTE},
     {"bind_ims_auth", (cmd_function) bind_ims_auth, 0, 0, 0, 0},

+ 187 - 27
modules/ims_auth/authorize.c

@@ -276,7 +276,6 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
     str private_identity, public_identity, auts = {0, 0}, nonce = {0, 0};
     auth_vector *av = 0;
     int algo_type;
-    
     str route_name;
 
     saved_transaction_t* saved_t;
@@ -346,8 +345,8 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
 
     algo_type = registration_default_algorithm_type;
 
-    /* check if it is a synchronization request */
-    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
+//    /* check if it is a synchronization request */
+//    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
 //    auts = ims_get_auts(msg, realm, is_proxy_auth);
 //    if (auts.len) {
 //        LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
@@ -363,19 +362,15 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
 //            av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_SENT, &nonce, &aud_hash);
 //
 //        if (!av) {
-//            LM_ERR("Nonce not regonized as sent, no sync!\n");
+//            LM_ERR("nonce not recognized as sent, no sync!\n");
 //            auts.len = 0;
 //            auts.s = 0;
 //        } else {
 //            av->status = AUTH_VECTOR_USELESS;
 //            auth_data_unlock(aud_hash);
 //            av = 0;
+//            resync = 1;
 //        }
-//
-//        //RICHARD REMOVED REALM - this is diameter realm set in cxdx not SIP domain
-//        // if synchronization - force MAR - if MAR ok, old avs will be droped
-//        multimedia_auth_request(msg, public_identity, private_identity, av_request_at_sync,
-//                auth_scheme_types[algo_type], nonce, auts, scscf_name_str);
 //    }
 
     //RICHARD changed this
@@ -446,7 +441,6 @@ int challenge(struct sip_msg* msg, char* str1, char* str2, int is_proxy_auth, ch
         memcpy(saved_t->realm.s, realm.s, realm.len);
         saved_t->realm.len = realm.len;
 
-
         saved_t->is_proxy_auth = is_proxy_auth;
 
         LM_DBG("Suspending SIP TM transaction\n");
@@ -474,6 +468,158 @@ int www_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
     return challenge(msg, str1, str2, 0, _route);
 }
 
+int www_resync_auth(struct sip_msg* msg, char* _route, char* str1, char* str2) {
+
+    str realm = {0, 0};
+    unsigned int aud_hash;
+    str private_identity, public_identity, auts = {0, 0}, nonce = {0, 0};
+    auth_vector *av = 0;
+    int algo_type;
+    int is_proxy_auth=0;
+    str route_name;
+
+    saved_transaction_t* saved_t;
+    tm_cell_t *t = 0;
+    cfg_action_t* cfg_action;
+
+    if (fixup_get_svalue(msg, (gparam_t*) _route, &route_name) != 0) {
+        LM_ERR("no async route block for assign_server_unreg\n");
+        return -1;
+    }
+
+    LM_DBG("Looking for route block [%.*s]\n", route_name.len, route_name.s);
+    int ri = route_get(&main_rt, route_name.s);
+    if (ri < 0) {
+        LM_ERR("unable to find route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+    cfg_action = main_rt.rlist[ri];
+    if (cfg_action == NULL) {
+        LM_ERR("empty action lists in route block [%.*s]\n", route_name.len, route_name.s);
+        return -1;
+    }
+
+    if (get_str_fparam(&realm, msg, (fparam_t*) str1) < 0) {
+        LM_ERR("failed to get realm value\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    if (realm.len == 0) {
+        LM_ERR("invalid realm value - empty content\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    create_return_code(CSCF_RETURN_ERROR);
+
+    if (msg->first_line.type != SIP_REQUEST) {
+        LM_ERR("This message is not a request\n");
+        return CSCF_RETURN_ERROR;
+    }
+
+    /* get the private_identity */
+    private_identity = get_private_identity(msg, realm, is_proxy_auth);
+    if (!private_identity.len) {
+        LM_ERR("No private identity specified (Authorization: username)\n");
+        stateful_request_reply(msg, 403, MSG_403_NO_PRIVATE);
+        return CSCF_RETURN_BREAK;
+    }
+    /* get the public_identity */
+    public_identity = get_public_identity(msg);
+    if (!public_identity.len) {
+        LM_ERR("No public identity specified (To:)\n");
+        stateful_request_reply(msg, 403, MSG_403_NO_PUBLIC);
+        return CSCF_RETURN_BREAK;
+    }
+
+    algo_type = registration_default_algorithm_type;
+
+    /* check if it is a synchronization request */
+    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
+    auts = ims_get_auts(msg, realm, is_proxy_auth);
+    if (auts.len) {
+        LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
+
+        nonce = ims_get_nonce(msg, realm);
+        if (nonce.len == 0) {
+            LM_DBG("Nonce not found (Authorization: nonce)\n");
+            stateful_request_reply(msg, 403, MSG_403_NO_NONCE);
+            return CSCF_RETURN_BREAK;
+        }
+        av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_USED, &nonce, &aud_hash);
+        if (!av)
+            av = get_auth_vector(private_identity, public_identity, AUTH_VECTOR_SENT, &nonce, &aud_hash);
+
+        if (!av) {
+            LM_ERR("nonce not recognized as sent, no sync!\n");
+            auts.len = 0;
+            auts.s = 0;
+        } else {
+            av->status = AUTH_VECTOR_USELESS;
+            auth_data_unlock(aud_hash);
+            av = 0;
+        }
+    }
+
+	//before we send lets suspend the transaction
+	t = tmb.t_gett();
+	if (t == NULL || t == T_UNDEFINED) {
+		if (tmb.t_newtran(msg) < 0) {
+			LM_ERR("cannot create the transaction for MAR async\n");
+			stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+			return CSCF_RETURN_BREAK;
+		}
+		t = tmb.t_gett();
+		if (t == NULL || t == T_UNDEFINED) {
+			LM_ERR("cannot lookup the transaction\n");
+			stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+			return CSCF_RETURN_BREAK;
+		}
+	}
+
+	saved_t = shm_malloc(sizeof(saved_transaction_t));
+	if (!saved_t) {
+		LM_ERR("no more memory trying to save transaction state\n");
+		return CSCF_RETURN_ERROR;
+
+	}
+	memset(saved_t, 0, sizeof(saved_transaction_t));
+	saved_t->act = cfg_action;
+
+	saved_t->realm.s = (char*) shm_malloc(realm.len + 1);
+	if (!saved_t->realm.s) {
+		LM_ERR("no more memory trying to save transaction state : callid\n");
+		shm_free(saved_t);
+		return CSCF_RETURN_ERROR;
+	}
+	memset(saved_t->realm.s, 0, realm.len + 1);
+	memcpy(saved_t->realm.s, realm.s, realm.len);
+	saved_t->realm.len = realm.len;
+
+	saved_t->is_proxy_auth = is_proxy_auth;
+	saved_t->is_resync = 1;
+
+	LM_DBG("Suspending SIP TM transaction\n");
+	if (tmb.t_suspend(msg, &saved_t->tindex, &saved_t->tlabel) < 0) {
+		LM_ERR("failed to suspend the TM processing\n");
+		free_saved_transaction_data(saved_t);
+
+		stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+		return CSCF_RETURN_BREAK;
+	}
+
+	if (multimedia_auth_request(msg, public_identity, private_identity,
+			av_request_at_sync, auth_scheme_types[algo_type], nonce, auts,
+			scscf_name_str, saved_t) != 0) {
+		LM_ERR("ERR:I_MAR: Error sending MAR or MAR time-out\n");
+		tmb.t_cancel_suspend(saved_t->tindex, saved_t->tlabel);
+		free_saved_transaction_data(saved_t);
+		stateful_request_reply(msg, 480, MSG_480_DIAMETER_ERROR);
+		return CSCF_RETURN_BREAK;
+	}
+
+	return CSCF_RETURN_BREAK;
+}
+
 int proxy_challenge(struct sip_msg* msg, char* _route, char* str1, char* str2) {
     return challenge(msg, str1, str2, 1, _route);
 }
@@ -554,7 +700,7 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
     unsigned int aud_hash = 0;
     str realm;
     str private_identity, public_identity;
-    str nonce, response16, nc, cnonce, qop_str = {0, 0}, body, *next_nonce = &empty_s;
+    str nonce, response16, nc, cnonce, qop_str = {0, 0}, auts = {0, 0}, body, *next_nonce = &empty_s;
     enum qop_type qop = QOP_UNSPEC;
     str uri = {0, 0};
     HASHHEX expected, ha1, hbody, rspauth;
@@ -631,7 +777,7 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
         /* if none found, or nonce reuse is disabled, look for a fresh vector
          * We should also drop every other used vector at this point
          * (there souldn't be more than one) */
-
+    	LM_DBG("Looking for auth vector based on IMPI: [%.*s] and IMPU: [%.*s]\n", private_identity.len, private_identity.s, public_identity.len, public_identity.s);
         auth_userdata *aud;
         auth_vector *av_it;
         aud = get_auth_userdata(private_identity, public_identity);
@@ -815,7 +961,15 @@ int authenticate(struct sip_msg* msg, char* _realm, char* str2, int is_proxy_aut
                 authenticate_hex_len,authenticate_hex,
                 authorise_len,
                 authorise_len, authorise);
-        ret = AUTH_INVALID_PASSWORD;
+//        /* check for auts in authorization header - if it is then we need to resync */
+		auts = ims_get_auts(msg, realm, is_proxy_auth);
+		if (auts.len) {
+			LM_DBG("IMS Auth Synchronization requested <%.*s>\n", auts.len, auts.s);
+			ret = AUTH_RESYNC_REQUESTED;
+			av->status = AUTH_VECTOR_SENT;
+		} else {
+			ret = AUTH_INVALID_PASSWORD;
+		}
     }
 
     if (ignore_failed_auth) {
@@ -1113,6 +1267,8 @@ auth_vector * new_auth_vector(int item_number, str auth_scheme, str authenticate
     x->status = AUTH_VECTOR_UNUSED;
     x->expires = 0;
 
+    LM_DBG("new auth-vector with ck [%.*s] with status %d\n", x->ck.len, x->ck.s, x->status);
+
 done:
     return x;
 }
@@ -1315,26 +1471,28 @@ int multimedia_auth_request(struct sip_msg *msg, str public_identity, str privat
     str authorization = {0, 0};
     int result = -1;
 
-    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
-    //int is_sync = 0;
-//    if (auts.len) {
-//        authorization.s = pkg_malloc(nonce.len * 3 / 4 + auts.len * 3 / 4 + 8);
-//        if (!authorization.s) goto done;
-//        authorization.len = base64_to_bin(nonce.s, nonce.len, authorization.s);
-//        authorization.len = RAND_LEN;
-//        authorization.len += base64_to_bin(auts.s, auts.len, authorization.s + authorization.len);
-//        is_sync = 1;
-//    }
+    int is_sync = 0;
+    if (auts.len) {
+        authorization.s = pkg_malloc(nonce.len * 3 / 4 + auts.len * 3 / 4 + 8);
+        if (!authorization.s)  {
+        	LM_ERR("no more pkg mem\n");
+        	return result;
+        }
+        authorization.len = base64_to_bin(nonce.s, nonce.len, authorization.s);
+        authorization.len = RAND_LEN;
+        authorization.len += base64_to_bin(auts.s, auts.len, authorization.s + authorization.len);
+        is_sync = 1;
+    }
+
+    if (is_sync) {
+    	drop_auth_userdata(private_identity, public_identity);
+    }
 
 
     LM_DBG("Sending MAR\n");
     result = cxdx_send_mar(msg, public_identity, private_identity, count, auth_scheme, authorization, servername, transaction_data);
     if (authorization.s) pkg_free(authorization.s);
 
-    //TODO this is MAR syncing - have removed it currently - TOD maybe put back in
-    //if (is_sync)
-    //    drop_auth_userdata(private_identity, public_identity);
-
     return result;
 }
 
@@ -1500,12 +1658,14 @@ int drop_auth_userdata(str private_identity, str public_identity) {
 
     av = aud->head;
     while (av) {
+    	LM_DBG("dropping auth vector that was in status %d\n", av->status);
         av->status = AUTH_VECTOR_USELESS;
         av = av->next;
     }
     auth_data_unlock(aud->hash);
     return 1;
 error:
+	LM_DBG("no authdata to drop any auth vectors\n");
     if (aud) auth_data_unlock(aud->hash);
     return 0;
 }

+ 1 - 0
modules/ims_auth/authorize.h

@@ -140,6 +140,7 @@ int proxy_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
  */
 int www_authenticate(struct sip_msg* _msg, char* _realm, char* _table);
 int www_challenge(struct sip_msg* msg, char* route, char* _realm, char* str2);
+int www_resync_auth(struct sip_msg* msg, char* _route, char* str1, char* str2);
 
 
 /*

+ 21 - 18
modules/ims_auth/cxdx_mar.c

@@ -387,8 +387,6 @@ success:
         //TODO need to confirm that removing this has done no problems
         //tmp->auth_data->code = -tmp->auth_data->code;
 
-	LM_DBG("Added new auth-vector.\n");
-
         tmp = tmp->next;
     }
 
@@ -396,29 +394,34 @@ success:
     //right now we take the first and put the rest in the AV queue
     //then we use the first one and then add it to the queue as sent!
 
-    for (i = 1; i < sip_number_auth_items; i++)
+    for (i = 1; i < sip_number_auth_items; i++) {
         if (!add_auth_vector(private_identity, public_identity, avlist[i]))
             free_auth_vector(avlist[i]);
-
-    if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) {
-        stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV);
-        result = CSCF_RETURN_FALSE;
-        goto done;
     }
 
-    if (data->is_proxy_auth)
-        stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE);
-    else
-        stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE);
+    if (!data->is_resync) {
+		if (!pack_challenge(t->uas.request, data->realm, avlist[0], data->is_proxy_auth)) {
+			stateful_request_reply_async(t, t->uas.request, 500, MSG_500_PACK_AV);
+			result = CSCF_RETURN_FALSE;
+			goto done;
+		}
+
+		if (data->is_proxy_auth)
+			stateful_request_reply_async(t, t->uas.request, 407, MSG_407_CHALLENGE);
+		else
+			stateful_request_reply_async(t, t->uas.request, 401, MSG_401_CHALLENGE);
+    }
 
 done:
-    if (avlist) {
-        start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors
 
-        //now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
-        if (!add_auth_vector(private_identity, public_identity, avlist[0]))
-            free_auth_vector(avlist[0]);
-    }
+	if (avlist) {
+		if (!data->is_resync)	//only start the timer if we used the vector above - we dont use it resync mode
+		start_reg_await_timer(avlist[0]); //start the timer to remove stale or unused Auth Vectors
+
+		//now we add it to the queue as sent as we have already sent the challenge and used it and set the status to SENT
+		if (!add_auth_vector(private_identity, public_identity, avlist[0]))
+			free_auth_vector(avlist[0]);
+	}
 
     //free memory
     if (maa) cdpb.AAAFreeMessage(&maa);

+ 1 - 0
modules/ims_auth/cxdx_mar.h

@@ -63,6 +63,7 @@ typedef struct saved_transaction {
 	unsigned int ticks;
 	cfg_action_t *act;
 	int is_proxy_auth;
+	int is_resync;
     str realm;
 } saved_transaction_t;