<p>Hoernchen has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/24304">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add support for multiple encryption algorithms + a5/4<br><br>config file syntax is backwards compatible<br><br>Change-Id: Ie6700c4e9d2df1eb5fde1b971e287b62668cc2de<br>Related: SYS#5324<br>---<br>M include/osmocom/sgsn/gprs_sgsn.h<br>M include/osmocom/sgsn/sgsn.h<br>M src/sgsn/gprs_gmm.c<br>M src/sgsn/gprs_llc.c<br>M src/sgsn/gprs_sgsn.c<br>M src/sgsn/sgsn_vty.c<br>6 files changed, 93 insertions(+), 31 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-sgsn refs/changes/04/24304/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h</span><br><span>index 289e0c4..c176494 100644</span><br><span>--- a/include/osmocom/sgsn/gprs_sgsn.h</span><br><span>+++ b/include/osmocom/sgsn/gprs_sgsn.h</span><br><span>@@ -175,6 +175,7 @@</span><br><span>    /* Iu: CK, IK, KSI */</span><br><span>        /* CKSN */</span><br><span>   enum gprs_ciph_algo     ciph_algo;</span><br><span style="color: hsl(120, 100%, 40%);">+    uint8_t ue_cipher_mask;</span><br><span>      /* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */</span><br><span>       uint8_t ac_ref_nr_used;</span><br><span> </span><br><span>diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h</span><br><span>index b686c7c..5b29873 100644</span><br><span>--- a/include/osmocom/sgsn/sgsn.h</span><br><span>+++ b/include/osmocom/sgsn/sgsn.h</span><br><span>@@ -76,7 +76,7 @@</span><br><span>     struct gprs_ns2_inst *nsi;</span><br><span> </span><br><span>       enum sgsn_auth_policy auth_policy;</span><br><span style="color: hsl(0, 100%, 40%);">-      enum gprs_ciph_algo cipher;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t cipher_support_mask;</span><br><span>         struct llist_head imsi_acl;</span><br><span> </span><br><span>      struct sockaddr_in gsup_server_addr;</span><br><span>diff --git a/src/sgsn/gprs_gmm.c b/src/sgsn/gprs_gmm.c</span><br><span>index edddd2d..4654709 100644</span><br><span>--- a/src/sgsn/gprs_gmm.c</span><br><span>+++ b/src/sgsn/gprs_gmm.c</span><br><span>@@ -445,6 +445,17 @@</span><br><span>         return false;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static enum gprs_ciph_algo gprs_ms_net_select_best_gea(uint8_t net_mask, uint8_t ms_mask) {</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t common_mask = net_mask & ms_mask;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t r = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      while (common_mask >>= 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+             r++;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return r;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* 3GPP TS 24.008 § 9.4.9: Authentication and Ciphering Request */</span><br><span> int gsm48_tx_gmm_auth_ciph_req(struct sgsn_mm_ctx *mm,</span><br><span>                                    const struct osmo_auth_vector *vec,</span><br><span>@@ -1147,6 +1158,21 @@</span><br><span> </span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static uint8_t gprs_ms_net_cap_gea_mask(const uint8_t *ms_net_cap, uint8_t cap_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t mask = (1 << GPRS_ALGO_GEA0);</span><br><span style="color: hsl(120, 100%, 40%);">+   mask |= (0x80 & ms_net_cap[0]) ? (1 << GPRS_ALGO_GEA1) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if(cap_len < 2)</span><br><span style="color: hsl(120, 100%, 40%);">+            return mask;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* extended GEA bits start from 2nd bit of the next byte */</span><br><span style="color: hsl(120, 100%, 40%);">+   mask |= (0x40 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA2) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ mask |= (0x20 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA3) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ mask |= (0x10 & ms_net_cap[1]) ? (1 << GPRS_ALGO_GEA4) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ return mask;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* 3GPP TS 24.008 § 9.4.1 Attach request */</span><br><span> static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg,</span><br><span>                              struct gprs_llc_llme *llme)</span><br><span>@@ -1290,15 +1316,27 @@</span><br><span>                ctx->ms_radio_access_capa.len);</span><br><span>   ctx->ms_network_capa.len = msnc_len;</span><br><span>      memcpy(ctx->ms_network_capa.buf, msnc, msnc_len);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (!gprs_ms_net_cap_gea_supported(ctx->ms_network_capa.buf, msnc_len,</span><br><span style="color: hsl(0, 100%, 40%);">-                                          ctx->ciph_algo)) {</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    ctx->ue_cipher_mask = gprs_ms_net_cap_gea_mask(ctx->ms_network_capa.buf, msnc_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!(ctx->ue_cipher_mask & sgsn->cfg.cipher_support_mask)) {</span><br><span>              reject_cause = GMM_CAUSE_PROTO_ERR_UNSPEC;</span><br><span>           LOGMMCTXP(LOGL_NOTICE, ctx, "Rejecting ATTACH REQUEST with MI "</span><br><span style="color: hsl(0, 100%, 40%);">-                         "%s because MS do not support required %s "</span><br><span style="color: hsl(0, 100%, 40%);">-                   "encryption\n", mi_log_string,</span><br><span style="color: hsl(0, 100%, 40%);">-                        get_value_string(gprs_cipher_names,ctx->ciph_algo));</span><br><span style="color: hsl(120, 100%, 40%);">+                       "%s because MS do not support required encryption, mask UE:0x%02x NW:0x%02x \n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            mi_log_string, ctx->ue_cipher_mask, sgsn->cfg.cipher_support_mask);</span><br><span>          goto rejected;</span><br><span>       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* just assume that everythig is fine if the phone offers a5/4:</span><br><span style="color: hsl(120, 100%, 40%);">+        * it requires a valid umts security context which we can only have after</span><br><span style="color: hsl(120, 100%, 40%);">+      * 1) IDENTITY REQUEST to know what to ask the HLR for</span><br><span style="color: hsl(120, 100%, 40%);">+         * 2) and AUTHENTICATION AND CIPHERING REQUEST</span><br><span style="color: hsl(120, 100%, 40%);">+         * ... but 2) already requires selecting a cipher mode.</span><br><span style="color: hsl(120, 100%, 40%);">+        * So let's just assume we will have the auth data required to make it work.</span><br><span style="color: hsl(120, 100%, 40%);">+       */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ctx->ciph_algo = gprs_ms_net_select_best_gea(ctx->ue_cipher_mask, sgsn->cfg.cipher_support_mask);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #ifdef PTMSI_ALLOC</span><br><span>   /* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */</span><br><span>     ptmsi_update(ctx);</span><br><span>diff --git a/src/sgsn/gprs_llc.c b/src/sgsn/gprs_llc.c</span><br><span>index e357d16..73fb97f 100644</span><br><span>--- a/src/sgsn/gprs_llc.c</span><br><span>+++ b/src/sgsn/gprs_llc.c</span><br><span>@@ -42,6 +42,8 @@</span><br><span> #include <osmocom/sgsn/gprs_sndcp_comp.h></span><br><span> #include <osmocom/sgsn/gprs_sndcp.h></span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/crypt/kdf.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> const struct value_string gprs_llc_llme_state_names[] = {</span><br><span>    { GPRS_LLMS_UNASSIGNED, "UNASSIGNED" },</span><br><span>    { GPRS_LLMS_ASSIGNED,   "ASSIGNED" },</span><br><span>@@ -713,6 +715,7 @@</span><br><span>        /* Compute the 'Input' Paraemeter */</span><br><span>         uint32_t fcs_calc, iv = gprs_cipher_gen_input_ui(lle->llme->iov_ui, sapi,</span><br><span>                                                       nu, oc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>  /* Compute gamma that we need to XOR with the data */</span><br><span>        int r = gprs_cipher_run(cipher_out, crypt_len, lle->llme->algo,</span><br><span>                                lle->llme->kc, iv,</span><br><span>@@ -1042,8 +1045,13 @@</span><br><span>            llme->algo = mm->ciph_algo;</span><br><span>            if (llme->cksn != mm->auth_triplet.key_seq &&</span><br><span>              mm->auth_triplet.key_seq != GSM_KEY_SEQ_INVAL) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 memcpy(llme->kc, mm->auth_triplet.vec.kc,</span><br><span style="color: hsl(0, 100%, 40%);">-                        gprs_cipher_key_length(mm->ciph_algo));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   /* gea4 needs kc128 */</span><br><span style="color: hsl(120, 100%, 40%);">+                        if (mm->ciph_algo == GPRS_ALGO_GEA4)</span><br><span style="color: hsl(120, 100%, 40%);">+                               osmo_kdf_kc128(mm->auth_triplet.vec.ck, mm->auth_triplet.vec.ik, llme->kc);</span><br><span style="color: hsl(120, 100%, 40%);">+                  else</span><br><span style="color: hsl(120, 100%, 40%);">+                          memcpy(llme->kc, mm->auth_triplet.vec.kc, gprs_cipher_key_length(mm->ciph_algo));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                         llme->cksn = mm->auth_triplet.key_seq;</span><br><span>                 }</span><br><span>    } else</span><br><span>diff --git a/src/sgsn/gprs_sgsn.c b/src/sgsn/gprs_sgsn.c</span><br><span>index f744257..3441f54 100644</span><br><span>--- a/src/sgsn/gprs_sgsn.c</span><br><span>+++ b/src/sgsn/gprs_sgsn.c</span><br><span>@@ -293,11 +293,9 @@</span><br><span>   memcpy(&ctx->ra, raid, sizeof(ctx->ra));</span><br><span>   ctx->ran_type = MM_CTX_T_GERAN_Gb;</span><br><span>        ctx->gb.tlli = tlli;</span><br><span style="color: hsl(0, 100%, 40%);">- ctx->ciph_algo = sgsn->cfg.cipher;</span><br><span style="color: hsl(120, 100%, 40%);">+      ctx->ciph_algo = GPRS_ALGO_GEA4; // overwritten on attach</span><br><span>         osmo_fsm_inst_update_id_f(ctx->gb.mm_state_fsm, "%" PRIu32, tlli);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     LOGMMCTXP(LOGL_DEBUG, ctx, "Allocated with %s cipher.\n",</span><br><span style="color: hsl(0, 100%, 40%);">-               get_value_string(gprs_cipher_names, ctx->ciph_algo));</span><br><span>   return ctx;</span><br><span> }</span><br><span> </span><br><span>diff --git a/src/sgsn/sgsn_vty.c b/src/sgsn/sgsn_vty.c</span><br><span>index 76d5202..533f9ca 100644</span><br><span>--- a/src/sgsn/sgsn_vty.c</span><br><span>+++ b/src/sgsn/sgsn_vty.c</span><br><span>@@ -206,6 +206,7 @@</span><br><span>  struct apn_ctx *actx;</span><br><span>        struct ares_addr_node *server;</span><br><span>       struct sgsn_mme_ctx *mme;</span><br><span style="color: hsl(120, 100%, 40%);">+     int i;</span><br><span> </span><br><span>   vty_out(vty, "sgsn%s", VTY_NEWLINE);</span><br><span> </span><br><span>@@ -236,10 +237,15 @@</span><br><span>   for (server = sgsn->ares_servers; server; server = server->next)</span><br><span>               vty_out(vty, " grx-dns-add %s%s", inet_ntoa(server->addr.addr4), VTY_NEWLINE);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (g_cfg->cipher != GPRS_ALGO_GEA0)</span><br><span style="color: hsl(0, 100%, 40%);">-         vty_out(vty, " encryption %s%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                      get_value_string(gprs_cipher_names, g_cfg->cipher),</span><br><span style="color: hsl(0, 100%, 40%);">-                  VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (g_cfg->cipher_support_mask != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             vty_out(vty, " encryption");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              for (i = 0; i < 6; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (g_cfg->cipher_support_mask >> i & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                         vty_out(vty, " %s", get_value_string(gprs_cipher_names, i));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              vty_out(vty, "%s", VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span>    if (g_cfg->sgsn_ipa_name)</span><br><span>                 vty_out(vty, " gsup ipa-name %s%s", g_cfg->sgsn_ipa_name, VTY_NEWLINE);</span><br><span>         if (g_cfg->gsup_server_addr.sin_addr.s_addr)</span><br><span>@@ -723,27 +729,36 @@</span><br><span> }</span><br><span> </span><br><span> DEFUN(cfg_encrypt, cfg_encrypt_cmd,</span><br><span style="color: hsl(0, 100%, 40%);">-      "encryption (GEA0|GEA1|GEA2|GEA3|GEA4)",</span><br><span style="color: hsl(0, 100%, 40%);">-      "Set encryption algorithm for SGSN\n"</span><br><span style="color: hsl(0, 100%, 40%);">-      "Use GEA0 (no encryption)\n"</span><br><span style="color: hsl(0, 100%, 40%);">-      "Use GEA1\nUse GEA2\nUse GEA3\nUse GEA4\n")</span><br><span style="color: hsl(120, 100%, 40%);">+   "encryption (GEA0-4) [GEA0-4] [GEA0-4] [GEA0-4] [GEA0-4]",</span><br><span style="color: hsl(120, 100%, 40%);">+  "Set encryption algorithm for SGSN\n"</span><br><span style="color: hsl(120, 100%, 40%);">+       "GEAn Algorithm Number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "GEAn Algorithm Number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "GEAn Algorithm Number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "GEAn Algorithm Number\n"</span><br><span style="color: hsl(120, 100%, 40%);">+   "GEAn Algorithm Number\n")</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-       enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[0]);</span><br><span style="color: hsl(0, 100%, 40%);">-   if (c != GPRS_ALGO_GEA0) {</span><br><span style="color: hsl(0, 100%, 40%);">-              if (!gprs_cipher_supported(c)) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                       return CMD_WARNING;</span><br><span style="color: hsl(120, 100%, 40%);">+   int i = argc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       g_cfg->cipher_support_mask = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < argc; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+               enum gprs_ciph_algo c = get_string_value(gprs_cipher_names, argv[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+         if (c != GPRS_ALGO_GEA0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                    if (!gprs_cipher_supported(c)) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              vty_out(vty, "%% cipher %s is unsupported in current version%s", argv[i], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                             return CMD_ERR_INCOMPLETE;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (!g_cfg->require_authentication) {</span><br><span style="color: hsl(120, 100%, 40%);">+                              vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",</span><br><span style="color: hsl(120, 100%, 40%);">+                                  argv[i], VTY_NEWLINE);</span><br><span style="color: hsl(120, 100%, 40%);">+                                return CMD_ERR_INCOMPLETE;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span>            }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           if (!g_cfg->require_authentication) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        vty_out(vty, "%% unable to use encryption %s without authentication: please adjust auth-policy%s",</span><br><span style="color: hsl(0, 100%, 40%);">-                            argv[0], VTY_NEWLINE);</span><br><span style="color: hsl(0, 100%, 40%);">-                  return CMD_WARNING;</span><br><span style="color: hsl(0, 100%, 40%);">-             }</span><br><span style="color: hsl(120, 100%, 40%);">+             g_cfg->cipher_support_mask |= (1 << c);</span><br><span>     }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   g_cfg->cipher = c;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>        return CMD_SUCCESS;</span><br><span> }</span><br><span> </span><br><span>@@ -1692,6 +1707,8 @@</span><br><span>         /* make sure sgsn_vty_init() was called before this */</span><br><span>       OSMO_ASSERT(g_cfg);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       g_cfg->cipher_support_mask = 1; // default to GEA0 support</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>      rc = vty_read_config_file(config_file, NULL);</span><br><span>        if (rc < 0) {</span><br><span>             fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-sgsn/+/24304">change 24304</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-sgsn/+/24304"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-sgsn </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ie6700c4e9d2df1eb5fde1b971e287b62668cc2de </div>
<div style="display:none"> Gerrit-Change-Number: 24304 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Hoernchen <ewild@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>