Make UTRAN encryption algorithms configurable

Allow the user fine-grained control over which UMTS encryption
algorithms are permitted, rather than always permitting UEA1 and UEA2
or neither.

This brings the handling of UEA in line with the handling of A5 for
GERAN.

Change-Id: I91f9e50f9c1439aa19528f887b83ae9de628fcfd
Closes: OS#4144
Depends: osmo-iuh.git I6d2d033b0427bdc84fee61e0f3cb7b29935214bf
diff --git a/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index 565e7ad..fc1b2e2 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/src/libmsc/gsm_04_08.c
@@ -414,7 +414,7 @@
 				net->vlr, msc_a, vlr_lu_type, tmsi, imsi,
 				&old_lai, &msc_a->via_cell.lai,
 				is_utran || net->authentication_required,
-				is_utran ? net->uea_encryption : net->a5_encryption_mask > 0x01,
+				is_utran ? net->uea_encryption_mask > 0x01 : net->a5_encryption_mask > 0x01,
 				lu->key_seq,
 				osmo_gsm48_classmark1_is_r99(&lu->classmark1),
 				is_utran,
@@ -805,7 +805,7 @@
 			 req->cm_service_type,
 			 &mi, &msc_a->via_cell.lai,
 			 is_utran || net->authentication_required,
-			 is_utran ? net->uea_encryption : net->a5_encryption_mask > 0x01,
+			 is_utran ? net->uea_encryption_mask > 0x01 : net->a5_encryption_mask > 0x01,
 			 req->cipher_key_seq,
 			 osmo_gsm48_classmark2_is_r99(cm2, cm2_len),
 			 is_utran);
@@ -931,7 +931,7 @@
 			 VLR_PR_ARQ_T_CM_RE_ESTABLISH_REQ, 0,
 			 &mi, &msc_a->via_cell.lai,
 			 is_utran || net->authentication_required,
-			 is_utran ? net->uea_encryption : net->a5_encryption_mask > 0x01,
+			 is_utran ? net->uea_encryption_mask > 0x01 : net->a5_encryption_mask > 0x01,
 			 req->cipher_key_seq,
 			 osmo_gsm48_classmark2_is_r99(cm2, cm2_len),
 			 is_utran);
@@ -1293,7 +1293,7 @@
 			 net->vlr, msc_a,
 			 VLR_PR_ARQ_T_PAGING_RESP, 0, &mi, &msc_a->via_cell.lai,
 			 is_utran || net->authentication_required,
-			 is_utran ? net->uea_encryption : net->a5_encryption_mask > 0x01,
+			 is_utran ? net->uea_encryption_mask > 0x01 : net->a5_encryption_mask > 0x01,
 			 pr->key_seq,
 			 osmo_gsm48_classmark2_is_r99(cm2, classmark2_len),
 			 is_utran);
diff --git a/src/libmsc/msc_a.c b/src/libmsc/msc_a.c
index fe3af14..a79cf6a 100644
--- a/src/libmsc/msc_a.c
+++ b/src/libmsc/msc_a.c
@@ -349,8 +349,8 @@
 				.chosen_key = &msc_a->geran_encr,
 			},
 			.utran = {
-				.uea_encryption = net->uea_encryption
-			}
+				.uea_encryption_mask = net->uea_encryption_mask,
+			},
 		},
 	};
 
diff --git a/src/libmsc/msc_net_init.c b/src/libmsc/msc_net_init.c
index 9e3e8b3..d53156b 100644
--- a/src/libmsc/msc_net_init.c
+++ b/src/libmsc/msc_net_init.c
@@ -67,7 +67,8 @@
 
 	/* Permit a compile-time default of A5/3 and A5/1 */
 	net->a5_encryption_mask = (1 << 3) | (1 << 1);
-	net->uea_encryption = true;
+	/* Permit a compile-time default of UEA2 and UEA1 */
+	net->uea_encryption_mask = (1 << 2) | (1 << 1);
 
 	net->mncc_guard_timeout = 180;
 	net->ncss_guard_timeout = 30;
diff --git a/src/libmsc/msc_vty.c b/src/libmsc/msc_vty.c
index e4e0937..6be09d8 100644
--- a/src/libmsc/msc_vty.c
+++ b/src/libmsc/msc_vty.c
@@ -169,41 +169,21 @@
 	return CMD_SUCCESS;
 }
 
-/* So far just a boolean switch, a future patch might add individual config for UEA1 and UEA2, see OS#4143 */
 DEFUN(cfg_net_encryption_uea,
       cfg_net_encryption_uea_cmd,
       "encryption uea <0-2> [<0-2>] [<0-2>]",
       ENCRYPTION_STR
-      "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2."
-        " NOTE: the current implementation does not allow free choice of combining encryption algorithms yet."
-	" The only valid settings are either 'encryption uea 0' or 'encryption uea 1 2'.\n"
+      "UTRAN (3G) encryption algorithms to allow: 0 = UEA0 (no encryption), 1 = UEA1, 2 = UEA2.\n"
       "UEAn Algorithm Number\n"
       "UEAn Algorithm Number\n"
       "UEAn Algorithm Number\n"
      )
 {
 	unsigned int i;
-	uint8_t mask = 0;
 
+	gsmnet->uea_encryption_mask = 0;
 	for (i = 0; i < argc; i++)
-		mask |= (1 << atoi(argv[i]));
-
-	if (mask == (1 << 0)) {
-		/* UEA0. Disable encryption. */
-		gsmnet->uea_encryption = false;
-	} else if (mask == ((1 << 1) | (1 << 2))) {
-		/* UEA1 and UEA2. Enable encryption. */
-		gsmnet->uea_encryption = true;
-	} else {
-		vty_out(vty,
-			"%% Error: the current implementation does not allow free choice of combining%s"
-			"%% encryption algorithms yet. The only valid settings are either%s"
-			"%%   encryption uea 0%s"
-			"%% or%s"
-			"%%   encryption uea 1 2%s",
-			VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE, VTY_NEWLINE);
-		return CMD_WARNING;
-	}
+		gsmnet->uea_encryption_mask |= (1 << atoi(argv[i]));
 
 	return CMD_SUCCESS;
 }
@@ -386,10 +366,12 @@
 	}
 	vty_out(vty, "%s", VTY_NEWLINE);
 
-	if (!gsmnet->uea_encryption)
-		vty_out(vty, " encryption uea 0%s", VTY_NEWLINE);
-	else
-		vty_out(vty, " encryption uea 1 2%s", VTY_NEWLINE);
+	vty_out(vty, " encryption uea");
+	for (i = 0; i < 8; i++) {
+		if (gsmnet->uea_encryption_mask & (1 << i))
+			vty_out(vty, " %u", i);
+	}
+	vty_out(vty, "%s", VTY_NEWLINE);
 	vty_out(vty, " authentication %s%s",
 		gsmnet->authentication_required ? "required" : "optional", VTY_NEWLINE);
 	vty_out(vty, " rrlp mode %s%s", msc_rrlp_mode_name(gsmnet->rrlp.mode),
diff --git a/src/libmsc/ran_msg_iu.c b/src/libmsc/ran_msg_iu.c
index 6120918..7b3dd1c 100644
--- a/src/libmsc/ran_msg_iu.c
+++ b/src/libmsc/ran_msg_iu.c
@@ -367,9 +367,13 @@
 						      const struct ran_cipher_mode_command *cm)
 {
 
-	LOG_RAN_IU_ENC(caller_fi, LOGL_DEBUG, "Tx RANAP SECURITY MODE COMMAND to RNC, ik %s\n",
-			osmo_hexdump_nospc(cm->vec->ik, 16));
-	return ranap_new_msg_sec_mod_cmd(cm->vec->ik, cm->utran.uea_encryption ? cm->vec->ck : NULL, RANAP_KeyStatus_new);
+	LOG_RAN_IU_ENC(caller_fi, LOGL_DEBUG, "Tx RANAP SECURITY MODE COMMAND to RNC, IK=%s, CK=%s\n",
+			osmo_hexdump_nospc(cm->vec->ik, 16),
+			cm->utran.uea_encryption_mask > 0x01 ? osmo_hexdump_nospc(cm->vec->ck, 16) : "NONE");
+	/* TODO: Do we need to check if the UE supports all of the algorithms and build an intersection like
+	 * in the case of A5? */
+	return ranap_new_msg_sec_mod_cmd2(cm->vec->ik, cm->utran.uea_encryption_mask > 0x01 ? cm->vec->ck : NULL,
+					  RANAP_KeyStatus_new, 0x06, cm->utran.uea_encryption_mask);
 }