msc: test auth options, and fall-back to no-auth

Test 12 permutations of
(auth optional,required) x (a5 '0', '0 3', '3') x (hlr has auth info)

In TC_auth_options_2(), expect behavior after implementing OS#4830: if
the HLR fails to return auth info and auth + ciph are configured
optional, fall back to no authentication. This test will start
succeeding starting with commit
I5feda196fa481dd8a46b0e4721c64b7c6600f0d1 in osmo-msc.git.

All other tests yield the current behavior of osmo-msc.

Related: I5feda196fa481dd8a46b0e4721c64b7c6600f0d1 (osmo-msc)
Related: OS#4830
Change-Id: I8e3b02ca83e56ef5349d85f08407509e19fa353c
diff --git a/msc/MSC_Tests.ttcn b/msc/MSC_Tests.ttcn
index e6d270d..36fe1eb 100644
--- a/msc/MSC_Tests.ttcn
+++ b/msc/MSC_Tests.ttcn
@@ -371,7 +371,11 @@
 runs on MTC_CT return BSC_ConnHdlrPars {
 	var BSC_ConnHdlrNetworkPars net_pars := {
 		kc_support := '0A'O,	/* A5/1 and A5/3 enabled */
+		net_config := { "authentication optional", "encryption a5 0" },
+		expect_attach_success := true,
 		expect_tmsi := true,
+		expect_auth_attempt := false,
+		hlr_has_auth_info := true,
 		expect_auth := false,
 		expect_ciph := false,
 		expect_imei := false,
@@ -4474,7 +4478,7 @@
 	/* TODO: Verify MSC is using the best cipher available! How? */
 
 	f_msc_lu_hlr();
-	f_accept_reject_lu();
+	as_accept_reject_lu();
 	f_expect_clear();
 	setverdict(pass);
 }
@@ -6848,6 +6852,325 @@
 	vc_conn.done;
 }
 
+/*                              a5 0       a5 0        a5 0 3         a5 0 3   a5 3       a5 3
+ *         HLR has auth info    no         yes         no             yes      no         yes
+ *
+ *           test case index    [0]        [1]         [2]            [3]      [4]        [5]
+ *   authentication optional    No auth    No auth     attempt auth,  auth     reject     auth
+ *                                         (%)         fall back to   +ciph               +ciph
+ *                                                     no-auth
+ *
+ *                              [6]        [7]         [8]            [9]      [10]       [11]
+ *  authentication mandatory    reject     auth        reject         auth     reject     auth
+ *                                         only                       +ciph               +ciph
+ *
+ *  (%): Arguably, when HLR has auth info, the MSC should use it. Current behavior of osmo-msc is to not attempt auth at
+ *       all. Related: OS#4830.
+ */
+type record of BSC_ConnHdlrNetworkPars rof_netpars;
+
+const rof_netpars auth_options_testcases := {
+	{
+		/* [0] auth optional, encr a5 0: no-auth" */
+		kc_support := '01'O,
+		net_config := { "authentication optional",
+				"encryption a5 0" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := false,
+		hlr_has_auth_info := false,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [1] auth optional, encr a5 0, HLR HAS auth info: no-auth */
+		kc_support := '01'O,
+		net_config := { "authentication optional",
+				"encryption a5 0" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := false,
+		hlr_has_auth_info := true,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [2] auth optional, encr a5 0 3, HLR has NO Auth Info: Fall back to no-auth" */
+		kc_support := '09'O,
+		net_config := { "authentication optional",
+				"encryption a5 0 3" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := false,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [3] auth optional, encr a5 0 3, HLR HAS Auth Info: Use A5/3 */
+		kc_support := '09'O,
+		net_config := { "authentication optional",
+				"encryption a5 0 3" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := true,
+		expect_auth := true,
+		expect_ciph := true,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [4] auth optional, encr a5 3, HLR has NO Auth Info: reject.
+		 * Auth is required implicitly because ciph is required. */
+		kc_support := '08'O,
+		net_config := { "authentication optional",
+				"encryption a5 3" },
+		expect_attach_success := false,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := false,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [5] auth optional, encr a5 3, HLR HAS Auth Info: auth + ciph.
+		 * Auth is required implicitly because ciph is required. */
+		kc_support := '08'O,
+		net_config := { "authentication optional",
+				"encryption a5 3" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := true,
+		expect_auth := true,
+		expect_ciph := true,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+
+	/* Same as above, but with 'authentication required' */
+
+	{
+		/* [6] auth required, encr a5 0, HLR has NO auth info: reject */
+		kc_support := '01'O,
+		net_config := { "authentication required",
+				"encryption a5 0" },
+		expect_attach_success := false,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := false,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [7] auth required, encr a5 0, HLR HAS auth info: do auth, no ciph" */
+		kc_support := '01'O,
+		net_config := { "authentication required",
+				"encryption a5 0" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := true,
+		expect_auth := true,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [8] auth required, encr a5 0 3, HLR has NO Auth Info: reject */
+		kc_support := '09'O,
+		net_config := { "authentication required",
+				"encryption a5 0 3" },
+		expect_attach_success := false,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := false,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [9] auth required, encr a5 0 3, HLR HAS Auth Info: Use A5/3 */
+		kc_support := '09'O,
+		net_config := { "authentication required",
+				"encryption a5 0 3" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := true,
+		expect_auth := true,
+		expect_ciph := true,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [10] auth required, encr a5 3, HLR has NO Auth Info: reject. */
+		kc_support := '08'O,
+		net_config := { "authentication required",
+				"encryption a5 3" },
+		expect_attach_success := false,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := false,
+		expect_auth := false,
+		expect_ciph := false,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	},
+	{
+		/* [11] auth required, encr a5 3, HLR HAS Auth Info: auth + ciph. */
+		kc_support := '08'O,
+		net_config := { "authentication required",
+				"encryption a5 3" },
+		expect_attach_success := true,
+		expect_tmsi := true,
+		expect_auth_attempt := true,
+		hlr_has_auth_info := true,
+		expect_auth := true,
+		expect_ciph := true,
+		expect_imei := false,
+		expect_imei_early := false,
+		check_imei_result := OSMO_GSUP_IMEI_RESULT_ACK,
+		check_imei_error := false
+	}
+};
+
+private function f_tc_auth_options(charstring id, BSC_ConnHdlrPars pars) runs on BSC_ConnHdlr {
+	f_init_handler(pars);
+
+	/* Location Updating */
+	log(MSCVTY, "f_perform_lu() starting");
+	f_perform_lu();
+	log(MSCVTY, "f_perform_lu() done");
+
+	f_sleep(1.0);
+
+	if (not pars.net.expect_attach_success) {
+		/* Expected above LU to fail. In order to test CM Service Request below, a LU has to succeed first. So
+		 * run another LU that will be successful. Careful not to load auth tokens into the VLR that may taint
+		 * the test for CM Service Request below. */
+
+		log(MSCVTY, "Running a successful LU so that CM Service Request can be tested");
+		var BSC_ConnHdlrNetworkPars saved_net := g_pars.net;
+		g_pars.net.kc_support := '01'O;
+		g_pars.net.expect_attach_success := true;
+		g_pars.net.expect_auth_attempt := false;
+		g_pars.net.expect_auth := false;
+		g_pars.net.expect_ciph := false;
+		f_vty_config3(MSCVTY, {"network"}, {"authentication optional", "encryption a5 0"});
+		f_perform_lu();
+
+		/* Reconfigure like it was before */
+		g_pars.net := saved_net;
+		f_vty_config3(MSCVTY, {"network"}, g_pars.net.net_config);
+		log(MSCVTY, "Running a successful LU done");
+	}
+
+	/* CM Service Request */
+	log(MSCVTY, "f_establish_fully() starting");
+	f_establish_fully();
+	log(MSCVTY, "f_establish_fully() done");
+	BSSAP.send(ts_BSSMAP_ClearRequest(0));
+	f_expect_clear();
+}
+
+function f_TC_auth_options(integer tc_i) runs on MTC_CT {
+	f_init();
+
+	var BSC_ConnHdlrNetworkPars tc := auth_options_testcases[tc_i];
+
+	f_vty_config3(MSCVTY, {"network"}, tc.net_config);
+
+	var BSC_ConnHdlrPars pars := f_init_pars(42300 + tc_i);
+	pars.net := tc;
+
+	var BSC_ConnHdlr vc_conn;
+	vc_conn := f_start_handler_with_pars(refers(f_tc_auth_options), pars);
+	vc_conn.done;
+}
+
+testcase TC_auth_options_0() runs on MTC_CT {
+	f_TC_auth_options(0);
+}
+
+testcase TC_auth_options_1() runs on MTC_CT {
+	f_TC_auth_options(1);
+}
+
+testcase TC_auth_options_2() runs on MTC_CT {
+	f_TC_auth_options(2);
+}
+
+testcase TC_auth_options_3() runs on MTC_CT {
+	f_TC_auth_options(3);
+}
+
+testcase TC_auth_options_4() runs on MTC_CT {
+	f_TC_auth_options(4);
+}
+
+testcase TC_auth_options_5() runs on MTC_CT {
+	f_TC_auth_options(5);
+}
+
+testcase TC_auth_options_6() runs on MTC_CT {
+	f_TC_auth_options(6);
+}
+
+testcase TC_auth_options_7() runs on MTC_CT {
+	f_TC_auth_options(7);
+}
+
+testcase TC_auth_options_8() runs on MTC_CT {
+	f_TC_auth_options(8);
+}
+
+testcase TC_auth_options_9() runs on MTC_CT {
+	f_TC_auth_options(9);
+}
+
+testcase TC_auth_options_10() runs on MTC_CT {
+	f_TC_auth_options(10);
+}
+
+testcase TC_auth_options_11() runs on MTC_CT {
+	f_TC_auth_options(11);
+}
+
 control {
 	execute( TC_cr_before_reset() );
 	execute( TC_lu_imsi_noauth_tmsi() );
@@ -7012,6 +7335,19 @@
 	execute( TC_call_re_establishment_ciph() );
 
 	execute( TC_cm_serv_wrong_mi() );
+
+	execute( TC_auth_options_0() );
+	execute( TC_auth_options_1() );
+	execute( TC_auth_options_2() );
+	execute( TC_auth_options_3() );
+	execute( TC_auth_options_4() );
+	execute( TC_auth_options_5() );
+	execute( TC_auth_options_6() );
+	execute( TC_auth_options_7() );
+	execute( TC_auth_options_8() );
+	execute( TC_auth_options_9() );
+	execute( TC_auth_options_10() );
+	execute( TC_auth_options_11() );
 }