blob: 5706e8ff0736ac8bea26ffbde8a8b994a8f23451 [file] [log] [blame]
Harald Weltec0f00072016-04-27 18:32:35 +02001/* Osmocom Authentication Protocol message encoder/decoder */
2
3/* (C) 2015-2016 by sysmocom s.f.m.c. GmbH
4 * All Rights Reserved
5 *
6 * Author: Neels Hofmeyr
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 *
21 */
22
23#include <osmocom/core/utils.h>
24#include <osmocom/core/logging.h>
25#include <osmocom/core/msgb.h>
26#include <osmocom/gsm/tlv.h>
27#include <osmocom/gsm/oap.h>
28
29#include <stdint.h>
30
Harald Welte96e2a002017-06-12 21:44:18 +020031/*! \addtogroup oap
32 * @{
33 * \brief Osmocom Authentication Protocol
34 */
35
Harald Weltec0f00072016-04-27 18:32:35 +020036/*! \brief Decode OAP message data.
37 * \param[out] oap_msg Parsed data is written to this instance.
38 * \param[in] data Pointer to the data buffer containing the OAP message.
39 * \param[in] data_len Length of the OAP message data.
40 * \returns 0 on success, a negative cause value on failure.
41 */
42int osmo_oap_decode(struct osmo_oap_message *oap_msg,
43 const uint8_t *const_data, size_t data_len)
44{
45 int rc;
46 uint8_t tag;
47 /* the shift/match functions expect non-const pointers, but we'll
48 * either copy the data or cast pointers back to const before returning
49 * them
50 */
51 uint8_t *data = (uint8_t *)const_data;
52 uint8_t *value;
53 size_t value_len;
54
55 memset(oap_msg, 0, sizeof(*oap_msg));
56
57 /* message type */
58 rc = osmo_shift_v_fixed(&data, &data_len, 1, &value);
59 if (rc < 0)
60 return -GMM_CAUSE_INV_MAND_INFO;
61 oap_msg->message_type = osmo_decode_big_endian(value, 1);
62
63 /* specific parts */
64 while (data_len > 0) {
65 enum osmo_oap_iei iei;
66
67 rc = osmo_shift_tlv(&data, &data_len, &tag, &value, &value_len);
68 if (rc < 0)
69 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
70
71 iei = tag;
72
73 switch (iei) {
74 case OAP_CLIENT_ID_IE:
75 if (value_len != 2) {
76 LOGP(DLOAP, LOGL_NOTICE,
77 "OAP IE type client ID (%d) should be 2 octets, but has %d\n",
78 (int)iei, (int)value_len);
79 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
80 }
81
82 oap_msg->client_id = osmo_decode_big_endian(value, value_len);
83
84 if (oap_msg->client_id == 0) {
85 LOGP(DLOAP, LOGL_NOTICE,
86 "OAP IE type client ID (%d): client ID must be nonzero.\n",
87 (int)iei);
88 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
89 }
90 break;
91
92 case OAP_AUTN_IE:
93 if (value_len != sizeof(oap_msg->autn)) {
94 LOGP(DLOAP, LOGL_NOTICE,
95 "OAP IE type AUTN (%d) should be %d octets, but has %d\n",
96 (int)iei, (int)sizeof(oap_msg->autn), (int)value_len);
97 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
98 }
99 memcpy(oap_msg->autn, value, value_len);
Neels Hofmeyrdd979502016-12-08 17:48:24 +0100100 oap_msg->autn_present = value_len ? 1 : 0;
Harald Weltec0f00072016-04-27 18:32:35 +0200101 break;
102
103 case OAP_RAND_IE:
104 if (value_len != sizeof(oap_msg->rand)) {
105 LOGP(DLOAP, LOGL_NOTICE,
106 "OAP IE type RAND (%d) should be %d octets, but has %d\n",
107 (int)iei, (int)sizeof(oap_msg->rand), (int)value_len);
108 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
109 }
110 memcpy(oap_msg->rand, value, value_len);
Neels Hofmeyrdd979502016-12-08 17:48:24 +0100111 oap_msg->rand_present = value_len ? 1 : 0;
Harald Weltec0f00072016-04-27 18:32:35 +0200112 break;
113
114 case OAP_XRES_IE:
115 if (value_len != sizeof(oap_msg->xres)) {
116 LOGP(DLOAP, LOGL_NOTICE,
117 "OAP IE type XRES (%d) should be %d octets, but has %d\n",
118 (int)iei, (int)sizeof(oap_msg->xres), (int)value_len);
119 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
120 }
121 memcpy(oap_msg->xres, value, value_len);
Neels Hofmeyrdd979502016-12-08 17:48:24 +0100122 oap_msg->xres_present = value_len ? 1 : 0;
Harald Weltec0f00072016-04-27 18:32:35 +0200123 break;
124
125 case OAP_AUTS_IE:
126 if (value_len != sizeof(oap_msg->auts)) {
127 LOGP(DLOAP, LOGL_NOTICE,
128 "OAP IE type AUTS (%d) should be %d octets, but has %d\n",
129 (int)iei, (int)sizeof(oap_msg->auts), (int)value_len);
130 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
131 }
132 memcpy(oap_msg->auts, value, value_len);
Neels Hofmeyrdd979502016-12-08 17:48:24 +0100133 oap_msg->auts_present = value_len ? 1 : 0;
Harald Weltec0f00072016-04-27 18:32:35 +0200134 break;
135
136 case OAP_CAUSE_IE:
137 if (value_len > 1) {
138 LOGP(DLOAP, LOGL_ERROR,
139 "OAP cause may not exceed one octet, is %d", (int)value_len);
140 return -GMM_CAUSE_PROTO_ERR_UNSPEC;
141 }
142 oap_msg->cause = *value;
143 break;
144
145 default:
146 LOGP(DLOAP, LOGL_NOTICE,
147 "OAP IE type %d unknown\n", iei);
148 continue;
149 }
150 }
151
152 return 0;
153}
154
155/*! \brief Compose OAP message data.
156 * \param[out] msg OAP message data is appended to this message buffer.
157 * \param[in] oap_msg Elements to encode in the message data.
158 */
159void osmo_oap_encode(struct msgb *msg, const struct osmo_oap_message *oap_msg)
160{
161 uint8_t u8;
162
163 /* generic part */
164 OSMO_ASSERT(oap_msg->message_type);
165 msgb_v_put(msg, (uint8_t)oap_msg->message_type);
166
167 /* specific parts */
168 if ((u8 = oap_msg->cause))
169 msgb_tlv_put(msg, OAP_CAUSE_IE, sizeof(u8), &u8);
170
171 if (oap_msg->client_id > 0)
172 msgb_tlv_put(msg, OAP_CLIENT_ID_IE, sizeof(oap_msg->client_id),
173 osmo_encode_big_endian(oap_msg->client_id,
174 sizeof(oap_msg->client_id)));
175
176 if (oap_msg->rand_present)
177 msgb_tlv_put(msg, OAP_RAND_IE, sizeof(oap_msg->rand), oap_msg->rand);
178
179 if (oap_msg->autn_present)
180 msgb_tlv_put(msg, OAP_AUTN_IE, sizeof(oap_msg->autn), oap_msg->autn);
181
182 if (oap_msg->auts_present)
183 msgb_tlv_put(msg, OAP_AUTS_IE, sizeof(oap_msg->auts), oap_msg->auts);
184
185 if (oap_msg->xres_present)
186 msgb_tlv_put(msg, OAP_XRES_IE, sizeof(oap_msg->xres), oap_msg->xres);
187
188 msg->l2h = msg->data;
189}
Harald Welte96e2a002017-06-12 21:44:18 +0200190
191/*! @} */