<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/10236">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">import oap_client into libosmogsm<br><br>This imports the code from osmo-msc 6afef893e17bce67e4d4119acd34d480ed03ba77<br>with minimal changes to make it compile.  Symbol renaming to osmo_<br>prefix is done separately in a follow-up patch to have a as-clean-as-possible<br>import first.<br><br>Change-Id: I9bc38102318da02d1fe46ef516df3cfd6bf8e3da<br>---<br>M include/Makefile.am<br>A include/osmocom/gsm/oap_client.h<br>M src/gsm/Makefile.am<br>M src/gsm/libosmogsm.map<br>A src/gsm/oap_client.c<br>5 files changed, 369 insertions(+), 1 deletion(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/Makefile.am b/include/Makefile.am</span><br><span>index 38ba14c..ef8ec65 100644</span><br><span>--- a/include/Makefile.am</span><br><span>+++ b/include/Makefile.am</span><br><span>@@ -100,6 +100,7 @@</span><br><span>                        osmocom/gsm/prim.h \</span><br><span>                        osmocom/gsm/l1sap.h \</span><br><span>                        osmocom/gsm/oap.h \</span><br><span style="color: hsl(120, 100%, 40%);">+                       osmocom/gsm/oap_client.h \</span><br><span>                        osmocom/gsm/protocol/gsm_03_40.h \</span><br><span>                        osmocom/gsm/protocol/gsm_03_41.h \</span><br><span>                        osmocom/gsm/protocol/gsm_04_08.h \</span><br><span>diff --git a/include/osmocom/gsm/oap_client.h b/include/osmocom/gsm/oap_client.h</span><br><span>new file mode 100644</span><br><span>index 0000000..80c86d5</span><br><span>--- /dev/null</span><br><span>+++ b/include/osmocom/gsm/oap_client.h</span><br><span>@@ -0,0 +1,82 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Osmocom Authentication Protocol API */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2015 by Sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_oap_message;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* This is the config part for vty. It is essentially copied in</span><br><span style="color: hsl(120, 100%, 40%);">+ * oap_client_state, where values are copied over once the config is</span><br><span style="color: hsl(120, 100%, 40%);">+ * considered valid. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct oap_client_config {</span><br><span style="color: hsl(120, 100%, 40%);">+        uint16_t client_id;</span><br><span style="color: hsl(120, 100%, 40%);">+   int secret_k_present;</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t secret_k[16];</span><br><span style="color: hsl(120, 100%, 40%);">+ int secret_opc_present;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t secret_opc[16];</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%);">+/* The runtime state of the OAP client. client_id and the secrets are in fact</span><br><span style="color: hsl(120, 100%, 40%);">+ * duplicated from oap_client_config, so that a separate validation of the</span><br><span style="color: hsl(120, 100%, 40%);">+ * config data is possible, and so that only a struct oap_client_state* is</span><br><span style="color: hsl(120, 100%, 40%);">+ * passed around. */</span><br><span style="color: hsl(120, 100%, 40%);">+struct oap_client_state {</span><br><span style="color: hsl(120, 100%, 40%);">+ enum {</span><br><span style="color: hsl(120, 100%, 40%);">+                OAP_UNINITIALIZED = 0,  /* just allocated. */</span><br><span style="color: hsl(120, 100%, 40%);">+         OAP_DISABLED,           /* disabled by config. */</span><br><span style="color: hsl(120, 100%, 40%);">+             OAP_INITIALIZED,        /* enabled, config is valid. */</span><br><span style="color: hsl(120, 100%, 40%);">+               OAP_REQUESTED_CHALLENGE,</span><br><span style="color: hsl(120, 100%, 40%);">+              OAP_SENT_CHALLENGE_RESULT,</span><br><span style="color: hsl(120, 100%, 40%);">+            OAP_REGISTERED</span><br><span style="color: hsl(120, 100%, 40%);">+        } state;</span><br><span style="color: hsl(120, 100%, 40%);">+      uint16_t client_id;</span><br><span style="color: hsl(120, 100%, 40%);">+   uint8_t secret_k[16];</span><br><span style="color: hsl(120, 100%, 40%);">+ uint8_t secret_opc[16];</span><br><span style="color: hsl(120, 100%, 40%);">+       int registration_failures;</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%);">+/* From config, initialize state. Return 0 on success. */</span><br><span style="color: hsl(120, 100%, 40%);">+int oap_client_init(struct oap_client_config *config,</span><br><span style="color: hsl(120, 100%, 40%);">+                struct oap_client_state *state);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Construct an OAP registration message and return in *msg_tx. Use</span><br><span style="color: hsl(120, 100%, 40%);">+ * state->client_id and update state->state.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return 0 on success, or a negative value on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If an error is returned, *msg_tx is guaranteed to be NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+int oap_client_register(struct oap_client_state *state, struct msgb **msg_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Decode and act on a received OAP message msg_rx. Update state->state.  If a</span><br><span style="color: hsl(120, 100%, 40%);">+ * non-NULL pointer is returned in *msg_tx, that msgb should be sent to the OAP</span><br><span style="color: hsl(120, 100%, 40%);">+ * server (and freed) by the caller. The received msg_rx is not freed.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return 0 on success, or a negative value on error.</span><br><span style="color: hsl(120, 100%, 40%);">+ * If an error is returned, *msg_tx is guaranteed to be NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+int oap_client_handle(struct oap_client_state *state,</span><br><span style="color: hsl(120, 100%, 40%);">+                      const struct msgb *msg_rx, struct msgb **msg_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Allocate a msgb and in it, return the encoded oap_client_msg. Return</span><br><span style="color: hsl(120, 100%, 40%);">+ * NULL on error. (Like oap_client_encode(), but also allocates a msgb.)</span><br><span style="color: hsl(120, 100%, 40%);">+ * About the name: the idea is do_something(oap_client_encoded(my_struct))</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *oap_client_encoded(const struct osmo_oap_message *oap_client_msg);</span><br><span>diff --git a/src/gsm/Makefile.am b/src/gsm/Makefile.am</span><br><span>index 900fcfa..29299a6 100644</span><br><span>--- a/src/gsm/Makefile.am</span><br><span>+++ b/src/gsm/Makefile.am</span><br><span>@@ -30,7 +30,7 @@</span><br><span>                  milenage/aes-internal.c milenage/aes-internal-enc.c \</span><br><span>                        milenage/milenage.c gan.c ipa.c gsm0341.c apn.c \</span><br><span>                    gsup.c gprs_gea.c gsm0503_conv.c oap.c gsm0808_utils.c \</span><br><span style="color: hsl(0, 100%, 40%);">-                        gsm23003.c mncc.c bts_features.c</span><br><span style="color: hsl(120, 100%, 40%);">+                      gsm23003.c mncc.c bts_features.c oap_client.c</span><br><span> libgsmint_la_LDFLAGS = -no-undefined</span><br><span> libgsmint_la_LIBADD = $(top_builddir)/src/libosmocore.la</span><br><span> </span><br><span>diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map</span><br><span>index b44cfd2..6eb60cc 100644</span><br><span>--- a/src/gsm/libosmogsm.map</span><br><span>+++ b/src/gsm/libosmogsm.map</span><br><span>@@ -493,5 +493,10 @@</span><br><span> osmo_mncc_names;</span><br><span> _osmo_mncc_log;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+oap_client_encoded;</span><br><span style="color: hsl(120, 100%, 40%);">+oap_client_handle;</span><br><span style="color: hsl(120, 100%, 40%);">+oap_client_init;</span><br><span style="color: hsl(120, 100%, 40%);">+oap_client_register;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> local: *;</span><br><span> };</span><br><span>diff --git a/src/gsm/oap_client.c b/src/gsm/oap_client.c</span><br><span>new file mode 100644</span><br><span>index 0000000..2227a3c</span><br><span>--- /dev/null</span><br><span>+++ b/src/gsm/oap_client.c</span><br><span>@@ -0,0 +1,280 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* Osmocom Authentication Protocol API */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2015 by Sysmocom s.f.m.c. GmbH</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Author: Neels Hofmeyr</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/crypt/auth.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/oap.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/gsm/oap_client.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int oap_client_init(struct oap_client_config *config,</span><br><span style="color: hsl(120, 100%, 40%);">+              struct oap_client_state *state)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(state->state == OAP_UNINITIALIZED);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!config)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto disable;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (config->client_id == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto disable;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       if (config->secret_k_present == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLOAP, LOGL_NOTICE, "OAP: client ID set, but secret K missing.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+            goto disable;</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 (config->secret_opc_present == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             LOGP(DLOAP, LOGL_NOTICE, "OAP: client ID set, but secret OPC missing.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          goto disable;</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%);">+   state->client_id = config->client_id;</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy(state->secret_k, config->secret_k, sizeof(state->secret_k));</span><br><span style="color: hsl(120, 100%, 40%);">+  memcpy(state->secret_opc, config->secret_opc, sizeof(state->secret_opc));</span><br><span style="color: hsl(120, 100%, 40%);">+    state->state = OAP_INITIALIZED;</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+disable:</span><br><span style="color: hsl(120, 100%, 40%);">+ state->state = OAP_DISABLED;</span><br><span style="color: hsl(120, 100%, 40%);">+       return 0;</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%);">+/* From the given state and received RAND and AUTN octets, validate the</span><br><span style="color: hsl(120, 100%, 40%);">+ * server's authenticity and formulate the matching milenage reply octets in</span><br><span style="color: hsl(120, 100%, 40%);">+ * *tx_xres. The state is not modified.</span><br><span style="color: hsl(120, 100%, 40%);">+ * On success, and if tx_res is not NULL, exactly 8 octets will be written to</span><br><span style="color: hsl(120, 100%, 40%);">+ * *tx_res. If not NULL, tx_res must point at allocated memory of at least 8</span><br><span style="color: hsl(120, 100%, 40%);">+ * octets. The caller will want to send XRES back to the server in a challenge</span><br><span style="color: hsl(120, 100%, 40%);">+ * response message and update the state.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Return 0 on success; -1 if OAP is disabled; -2 if rx_random and rx_autn fail</span><br><span style="color: hsl(120, 100%, 40%);">+ * the authentication check; -3 for any other errors. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int oap_evaluate_challenge(const struct oap_client_state *state,</span><br><span style="color: hsl(120, 100%, 40%);">+                                  const uint8_t *rx_random,</span><br><span style="color: hsl(120, 100%, 40%);">+                             const uint8_t *rx_autn,</span><br><span style="color: hsl(120, 100%, 40%);">+                               uint8_t *tx_xres)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_auth_vector vec;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sub_auth_data auth = {</span><br><span style="color: hsl(120, 100%, 40%);">+            .type           = OSMO_AUTH_TYPE_UMTS,</span><br><span style="color: hsl(120, 100%, 40%);">+                .algo           = OSMO_AUTH_ALG_MILENAGE,</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%);">+  osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.k)</span><br><span style="color: hsl(120, 100%, 40%);">+                          == sizeof(state->secret_k), _secret_k_size_match);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_static_assert(sizeof(((struct osmo_sub_auth_data*)0)->u.umts.opc)</span><br><span style="color: hsl(120, 100%, 40%);">+                        == sizeof(state->secret_opc), _secret_opc_size_match);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        switch (state->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case OAP_UNINITIALIZED:</span><br><span style="color: hsl(120, 100%, 40%);">+       case OAP_DISABLED:</span><br><span style="color: hsl(120, 100%, 40%);">+            return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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%);">+   memcpy(auth.u.umts.k, state->secret_k, sizeof(auth.u.umts.k));</span><br><span style="color: hsl(120, 100%, 40%);">+     memcpy(auth.u.umts.opc, state->secret_opc, sizeof(auth.u.umts.opc));</span><br><span style="color: hsl(120, 100%, 40%);">+       memset(auth.u.umts.amf, '\0', sizeof(auth.u.umts.amf));</span><br><span style="color: hsl(120, 100%, 40%);">+       auth.u.umts.sqn = 41; /* TODO use incrementing sequence nr */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       memset(&vec, 0, sizeof(vec));</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_auth_gen_vec(&vec, &auth, rx_random);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (vec.res_len != 8) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLOAP, LOGL_ERROR, "OAP: Expected XRES to be 8 octets, got %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   vec.res_len);</span><br><span style="color: hsl(120, 100%, 40%);">+            return -3;</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 (osmo_constant_time_cmp(vec.autn, rx_autn, sizeof(vec.autn)) != 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLOAP, LOGL_ERROR, "OAP: AUTN mismatch!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGP(DLOAP, LOGL_INFO, "OAP: AUTN from server: %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_hexdump_nospc(rx_autn, sizeof(vec.autn)));</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DLOAP, LOGL_INFO, "OAP: AUTN expected:    %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    osmo_hexdump_nospc(vec.autn, sizeof(vec.autn)));</span><br><span style="color: hsl(120, 100%, 40%);">+         return -2;</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 (tx_xres != NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+          memcpy(tx_xres, vec.res, 8);</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</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%);">+struct msgb *oap_client_encoded(const struct osmo_oap_message *oap_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct msgb *msg = msgb_alloc_headroom(1000, 64, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+   OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_oap_encode(msg, oap_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+        return msg;</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%);">+/* Create a new msgb containing an OAP registration message.</span><br><span style="color: hsl(120, 100%, 40%);">+ * On error, return NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb* oap_msg_register(uint16_t client_id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_oap_message oap_msg = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (client_id < 1) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLOAP, LOGL_ERROR, "OAP: Invalid client ID: %d\n", client_id);</span><br><span style="color: hsl(120, 100%, 40%);">+         return NULL;</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%);">+   oap_msg.message_type = OAP_MSGT_REGISTER_REQUEST;</span><br><span style="color: hsl(120, 100%, 40%);">+     oap_msg.client_id = client_id;</span><br><span style="color: hsl(120, 100%, 40%);">+        return oap_client_encoded(&oap_msg);</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%);">+int oap_client_register(struct oap_client_state *state, struct msgb **msg_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       *msg_tx = oap_msg_register(state->client_id);</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!(*msg_tx))</span><br><span style="color: hsl(120, 100%, 40%);">+               return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  state->state = OAP_REQUESTED_CHALLENGE;</span><br><span style="color: hsl(120, 100%, 40%);">+    return 0;</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%);">+/* Create a new msgb containing an OAP challenge response message.</span><br><span style="color: hsl(120, 100%, 40%);">+ * xres must point at 8 octets to return as challenge response.</span><br><span style="color: hsl(120, 100%, 40%);">+ * On error, return NULL. */</span><br><span style="color: hsl(120, 100%, 40%);">+static struct msgb* oap_msg_challenge_response(uint8_t *xres)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_oap_message oap_reply = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    oap_reply.message_type = OAP_MSGT_CHALLENGE_RESULT;</span><br><span style="color: hsl(120, 100%, 40%);">+   memcpy(oap_reply.xres, xres, sizeof(oap_reply.xres));</span><br><span style="color: hsl(120, 100%, 40%);">+ oap_reply.xres_present = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   return oap_client_encoded(&oap_reply);</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%);">+static int handle_challenge(struct oap_client_state *state,</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct osmo_oap_message *oap_rx,</span><br><span style="color: hsl(120, 100%, 40%);">+                      struct msgb **msg_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t xres[8];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!(oap_rx->rand_present && oap_rx->autn_present)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "OAP challenge incomplete (rand_present: %d, autn_present: %d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                  oap_rx->rand_present, oap_rx->autn_present);</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = -2;</span><br><span style="color: hsl(120, 100%, 40%);">+              goto failure;</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%);">+   rc = oap_evaluate_challenge(state,</span><br><span style="color: hsl(120, 100%, 40%);">+                                oap_rx->rand,</span><br><span style="color: hsl(120, 100%, 40%);">+                              oap_rx->autn,</span><br><span style="color: hsl(120, 100%, 40%);">+                              xres);</span><br><span style="color: hsl(120, 100%, 40%);">+    if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                goto failure;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       *msg_tx = oap_msg_challenge_response(xres);</span><br><span style="color: hsl(120, 100%, 40%);">+   if ((*msg_tx) == NULL) {</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+              goto failure;</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%);">+   state->state = OAP_SENT_CHALLENGE_RESULT;</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+failure:</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(rc < 0);</span><br><span style="color: hsl(120, 100%, 40%);">+       state->state = OAP_INITIALIZED;</span><br><span style="color: hsl(120, 100%, 40%);">+    return rc;</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%);">+int oap_client_handle(struct oap_client_state *state,</span><br><span style="color: hsl(120, 100%, 40%);">+                      const struct msgb *msg_rx, struct msgb **msg_tx)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     uint8_t *data = msgb_l2(msg_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+      size_t data_len = msgb_l2len(msg_rx);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_oap_message oap_msg = {0};</span><br><span style="color: hsl(120, 100%, 40%);">+        int rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *msg_tx = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  rc = osmo_oap_decode(&oap_msg, data, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Decoding OAP message failed with error '%s' (%d)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               get_value_string(gsm48_gmm_cause_names, -rc), -rc);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -10;</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%);">+   switch (state->state) {</span><br><span style="color: hsl(120, 100%, 40%);">+    case OAP_UNINITIALIZED:</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Received OAP message %d, but the OAP client is"</span><br><span style="color: hsl(120, 100%, 40%);">+                    " not initialized\n", oap_msg.message_type);</span><br><span style="color: hsl(120, 100%, 40%);">+           return -ENOTCONN;</span><br><span style="color: hsl(120, 100%, 40%);">+     case OAP_DISABLED:</span><br><span style="color: hsl(120, 100%, 40%);">+            LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Received OAP message %d, but the OAP client is"</span><br><span style="color: hsl(120, 100%, 40%);">+                    " disabled\n", oap_msg.message_type);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -ENOTCONN;</span><br><span style="color: hsl(120, 100%, 40%);">+     default:</span><br><span style="color: hsl(120, 100%, 40%);">+              break;</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%);">+   switch (oap_msg.message_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+       case OAP_MSGT_CHALLENGE_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+              return handle_challenge(state, &oap_msg, msg_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       case OAP_MSGT_REGISTER_RESULT:</span><br><span style="color: hsl(120, 100%, 40%);">+                /* successfully registered */</span><br><span style="color: hsl(120, 100%, 40%);">+         state->state = OAP_REGISTERED;</span><br><span style="color: hsl(120, 100%, 40%);">+             break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      case OAP_MSGT_REGISTER_ERROR:</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "OAP registration failed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+          state->state = OAP_INITIALIZED;</span><br><span style="color: hsl(120, 100%, 40%);">+            if (state->registration_failures < 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 state->registration_failures++;</span><br><span style="color: hsl(120, 100%, 40%);">+                    return oap_client_register(state, msg_tx);</span><br><span style="color: hsl(120, 100%, 40%);">+            }</span><br><span style="color: hsl(120, 100%, 40%);">+             return -11;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ case OAP_MSGT_REGISTER_REQUEST:</span><br><span style="color: hsl(120, 100%, 40%);">+       case OAP_MSGT_CHALLENGE_RESULT:</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Received invalid OAP message type for OAP client side: %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              (int)oap_msg.message_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -12;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DLOAP, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                    "Unknown OAP message type: %d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                   (int)oap_msg.message_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              return -13;</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 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10236">change 10236</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/10236"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: I9bc38102318da02d1fe46ef516df3cfd6bf8e3da </div>
<div style="display:none"> Gerrit-Change-Number: 10236 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>