瀏覽代碼

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 年之前
父節點
當前提交
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;