open5gs/src/mme/nas-security.c

238 lines
8.0 KiB
C
Raw Normal View History

2019-07-11 12:53:54 +00:00
/*
* Copyright (C) 2019 by Sukchan Lee <acetcom@gmail.com>
*
* This file is part of Open5GS.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
2019-06-11 13:10:47 +00:00
#include "nas-security.h"
2017-03-08 06:27:48 +00:00
2020-05-23 02:24:48 +00:00
#define NAS_SECURITY_BEARER 0
#define NAS_SECURITY_MAC_SIZE 4
ogs_pkbuf_t *nas_eps_security_encode(
mme_ue_t *mme_ue, ogs_nas_eps_message_t *message)
2017-03-08 10:10:01 +00:00
{
2017-03-08 13:54:16 +00:00
int integrity_protected = 0;
int new_security_context = 0;
int ciphered = 0;
2020-05-23 02:24:48 +00:00
ogs_nas_eps_security_header_t h;
ogs_pkbuf_t *new = NULL;
2017-03-08 13:54:16 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(mme_ue);
ogs_assert(message);
2017-03-08 10:10:01 +00:00
2019-07-11 12:53:54 +00:00
switch (message->h.security_header_type) {
2019-09-13 12:07:47 +00:00
case OGS_NAS_SECURITY_HEADER_PLAIN_NAS_MESSAGE:
2020-05-23 02:24:48 +00:00
return ogs_nas_eps_plain_encode(message);
2019-09-13 12:07:47 +00:00
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED:
2019-07-11 12:53:54 +00:00
integrity_protected = 1;
break;
2019-09-13 12:07:47 +00:00
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHERED:
2019-07-11 12:53:54 +00:00
integrity_protected = 1;
ciphered = 1;
break;
2019-09-13 12:07:47 +00:00
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_NEW_SECURITY_CONTEXT:
2019-07-11 12:53:54 +00:00
integrity_protected = 1;
new_security_context = 1;
break;
2019-09-13 12:07:47 +00:00
case OGS_NAS_SECURITY_HEADER_INTEGRITY_PROTECTED_AND_CIPHTERD_WITH_NEW_INTEGRITY_CONTEXT:
2019-07-11 12:53:54 +00:00
integrity_protected = 1;
new_security_context = 1;
ciphered = 1;
break;
default:
2019-11-30 07:45:09 +00:00
ogs_error("Not implemented(securiry header type:0x%x)",
2019-07-11 12:53:54 +00:00
message->h.security_header_type);
2019-11-30 07:45:09 +00:00
return NULL;
2017-03-08 13:54:16 +00:00
}
2017-03-08 10:10:01 +00:00
2019-07-11 12:53:54 +00:00
if (new_security_context) {
mme_ue->dl_count = 0;
mme_ue->ul_count.i32 = 0;
2017-03-08 13:54:16 +00:00
}
2017-03-08 10:10:01 +00:00
2017-07-14 12:39:21 +00:00
if (mme_ue->selected_enc_algorithm == 0)
2017-03-08 14:42:27 +00:00
ciphered = 0;
2017-07-14 12:39:21 +00:00
if (mme_ue->selected_int_algorithm == 0)
2017-03-08 14:42:27 +00:00
integrity_protected = 0;
memset(&h, 0, sizeof(h));
h.security_header_type = message->h.security_header_type;
h.protocol_discriminator = message->h.protocol_discriminator;
h.sequence_number = (mme_ue->dl_count & 0xff);
2020-05-23 02:24:48 +00:00
new = ogs_nas_eps_plain_encode(message);
if (!new) {
2020-05-23 02:24:48 +00:00
ogs_error("ogs_nas_eps_plain_encode() failed");
return NULL;
}
2017-03-08 10:10:01 +00:00
if (ciphered) {
/* encrypt NAS message */
2020-05-23 02:24:48 +00:00
ogs_nas_encrypt(mme_ue->selected_enc_algorithm,
mme_ue->knas_enc, mme_ue->dl_count, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_DOWNLINK_DIRECTION, new);
}
2017-03-08 13:54:16 +00:00
/* encode sequence number */
ogs_assert(ogs_pkbuf_push(new, 1));
*(uint8_t *)(new->data) = h.sequence_number;
2018-05-22 08:39:43 +00:00
if (integrity_protected) {
uint8_t mac[NAS_SECURITY_MAC_SIZE];
2017-03-08 14:42:27 +00:00
/* calculate NAS MAC(message authentication code) */
2020-05-23 02:24:48 +00:00
ogs_nas_mac_calculate(mme_ue->selected_int_algorithm,
mme_ue->knas_int, mme_ue->dl_count, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_DOWNLINK_DIRECTION, new, mac);
memcpy(&h.message_authentication_code, mac, sizeof(mac));
}
2017-03-08 10:10:01 +00:00
/* increase dl_count */
mme_ue->dl_count = (mme_ue->dl_count + 1) & 0xffffff; /* Use 24bit */
2017-03-08 15:09:30 +00:00
/* encode all security header */
ogs_assert(ogs_pkbuf_push(new, 5));
2020-05-23 02:24:48 +00:00
memcpy(new->data, &h, sizeof(ogs_nas_eps_security_header_t));
2017-03-08 10:10:01 +00:00
mme_ue->security_context_available = 1;
2019-11-30 07:45:09 +00:00
return new;
2017-03-08 10:10:01 +00:00
}
2020-05-23 02:24:48 +00:00
int nas_eps_security_decode(mme_ue_t *mme_ue,
ogs_nas_security_header_type_t security_header_type, ogs_pkbuf_t *pkbuf)
2017-03-08 13:39:28 +00:00
{
2019-04-27 14:54:30 +00:00
ogs_assert(mme_ue);
ogs_assert(pkbuf);
ogs_assert(pkbuf->data);
2017-03-08 14:04:35 +00:00
2019-07-11 12:53:54 +00:00
if (security_header_type.service_request) {
2018-05-22 02:31:09 +00:00
#define SHORT_MAC_SIZE 2
2019-09-13 12:07:47 +00:00
ogs_nas_ksi_and_sequence_number_t *ksi_and_sequence_number =
(ogs_nas_ksi_and_sequence_number_t *)(pkbuf->data + 1);
2019-04-27 14:54:30 +00:00
uint8_t original_mac[SHORT_MAC_SIZE];
uint8_t estimated_sequence_number;
uint8_t sequence_number_high_3bit;
uint8_t mac[NAS_SECURITY_MAC_SIZE];
2017-07-28 14:07:57 +00:00
2019-07-11 12:53:54 +00:00
if (mme_ue->selected_int_algorithm == 0) {
2019-04-27 14:54:30 +00:00
ogs_warn("integrity algorithm is not defined");
return OGS_ERROR;
2017-07-28 14:07:57 +00:00
}
2017-07-25 14:29:02 +00:00
2019-04-27 14:54:30 +00:00
ogs_assert(ksi_and_sequence_number);
2017-07-28 14:07:57 +00:00
estimated_sequence_number =
ksi_and_sequence_number->sequence_number;
2017-07-25 14:29:02 +00:00
2017-07-28 14:07:57 +00:00
sequence_number_high_3bit = mme_ue->ul_count.sqn & 0xe0;
2019-07-11 12:53:54 +00:00
if ((mme_ue->ul_count.sqn & 0x1f) > estimated_sequence_number) {
2017-07-28 14:07:57 +00:00
sequence_number_high_3bit += 0x20;
}
estimated_sequence_number += sequence_number_high_3bit;
2017-07-25 14:29:02 +00:00
2017-07-28 14:07:57 +00:00
if (mme_ue->ul_count.sqn > estimated_sequence_number)
mme_ue->ul_count.overflow++;
mme_ue->ul_count.sqn = estimated_sequence_number;
2017-07-25 14:29:02 +00:00
2019-04-27 14:54:30 +00:00
memcpy(original_mac, pkbuf->data + 2, SHORT_MAC_SIZE);
2018-05-22 02:31:09 +00:00
2019-04-27 14:54:30 +00:00
ogs_pkbuf_trim(pkbuf, 2);
2020-05-23 02:24:48 +00:00
ogs_nas_mac_calculate(mme_ue->selected_int_algorithm,
2017-07-28 14:07:57 +00:00
mme_ue->knas_int, mme_ue->ul_count.i32, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_UPLINK_DIRECTION, pkbuf, mac);
2018-05-22 02:31:09 +00:00
2019-04-27 14:54:30 +00:00
ogs_pkbuf_put_data(pkbuf, original_mac, SHORT_MAC_SIZE);
2019-07-11 12:53:54 +00:00
if (memcmp(mac + 2, pkbuf->data + 2, 2) != 0) {
2019-07-13 13:52:50 +00:00
ogs_warn("NAS MAC verification failed(%x%x != %x%x)",
mac[2], mac[3],
((unsigned char *)pkbuf->data)[2],
((unsigned char *)pkbuf->data)[3]);
2017-07-28 14:07:57 +00:00
mme_ue->mac_failed = 1;
2017-07-25 14:29:02 +00:00
}
2017-03-08 14:42:27 +00:00
2019-04-27 14:54:30 +00:00
return OGS_OK;
2017-07-28 14:07:57 +00:00
}
2017-03-08 14:42:27 +00:00
2019-07-11 12:53:54 +00:00
if (!mme_ue->security_context_available) {
2017-07-28 14:07:57 +00:00
security_header_type.integrity_protected = 0;
security_header_type.new_security_context = 0;
security_header_type.ciphered = 0;
2017-03-08 14:42:27 +00:00
}
2019-07-11 12:53:54 +00:00
if (security_header_type.new_security_context) {
mme_ue->ul_count.i32 = 0;
2017-03-08 14:42:27 +00:00
}
2017-07-14 12:39:21 +00:00
if (mme_ue->selected_enc_algorithm == 0)
2017-07-28 14:07:57 +00:00
security_header_type.ciphered = 0;
2017-07-14 12:39:21 +00:00
if (mme_ue->selected_int_algorithm == 0)
2017-07-28 14:07:57 +00:00
security_header_type.integrity_protected = 0;
2017-03-08 14:42:27 +00:00
2017-07-28 14:07:57 +00:00
if (security_header_type.ciphered ||
2019-07-11 12:53:54 +00:00
security_header_type.integrity_protected) {
2020-05-23 02:24:48 +00:00
ogs_nas_eps_security_header_t *h = NULL;
2017-07-28 14:07:57 +00:00
/* NAS Security Header */
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_push(pkbuf, 6));
2020-05-23 02:24:48 +00:00
h = (ogs_nas_eps_security_header_t *)pkbuf->data;
2017-07-28 14:07:57 +00:00
/* NAS Security Header.Sequence_Number */
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, 5));
2017-03-08 14:42:27 +00:00
2017-04-11 05:26:54 +00:00
/* calculate ul_count */
if (mme_ue->ul_count.sqn > h->sequence_number)
mme_ue->ul_count.overflow++;
mme_ue->ul_count.sqn = h->sequence_number;
2017-04-11 05:26:54 +00:00
2019-07-11 12:53:54 +00:00
if (security_header_type.integrity_protected) {
2019-04-27 14:54:30 +00:00
uint8_t mac[NAS_SECURITY_MAC_SIZE];
uint32_t mac32;
uint32_t original_mac = h->message_authentication_code;
2017-03-08 14:42:27 +00:00
/* calculate NAS MAC(message authentication code) */
2020-05-23 02:24:48 +00:00
ogs_nas_mac_calculate(mme_ue->selected_int_algorithm,
mme_ue->knas_int, mme_ue->ul_count.i32, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_UPLINK_DIRECTION, pkbuf, mac);
2018-05-22 02:31:09 +00:00
h->message_authentication_code = original_mac;
2017-03-08 14:42:27 +00:00
memcpy(&mac32, mac, NAS_SECURITY_MAC_SIZE);
2019-07-11 12:53:54 +00:00
if (h->message_authentication_code != mac32) {
2019-04-27 14:54:30 +00:00
ogs_warn("NAS MAC verification failed(0x%x != 0x%x)",
2020-10-01 17:27:58 +00:00
be32toh(h->message_authentication_code), be32toh(mac32));
2017-07-28 14:07:57 +00:00
mme_ue->mac_failed = 1;
2017-03-08 14:42:27 +00:00
}
}
2017-07-28 14:07:57 +00:00
/* NAS EMM Header or ESM Header */
2019-04-27 14:54:30 +00:00
ogs_assert(ogs_pkbuf_pull(pkbuf, 1));
2018-05-22 08:39:43 +00:00
2019-07-11 12:53:54 +00:00
if (security_header_type.ciphered) {
2018-05-22 08:39:43 +00:00
/* decrypt NAS message */
if (pkbuf->len == 0) {
ogs_error("Cannot decrypt Malformed NAS Message");
return OGS_ERROR;
}
2020-05-23 02:24:48 +00:00
ogs_nas_encrypt(mme_ue->selected_enc_algorithm,
2018-05-22 08:39:43 +00:00
mme_ue->knas_enc, mme_ue->ul_count.i32, NAS_SECURITY_BEARER,
OGS_NAS_SECURITY_UPLINK_DIRECTION, pkbuf);
2018-05-22 08:39:43 +00:00
}
2017-03-08 14:04:35 +00:00
}
2019-04-27 14:54:30 +00:00
return OGS_OK;
2017-03-08 13:39:28 +00:00
}