mbed-os/source/Security/protocols/radius_sec_prot/avp_helper.c

260 lines
6.5 KiB
C

/*
* Copyright (c) 2020, Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nsconfig.h"
#include "ns_types.h"
#include "eventOS_event.h"
#include "ns_trace.h"
#include "string.h"
#include "common_functions.h"
#include "Security/protocols/radius_sec_prot/avp_helper.h"
#ifdef HAVE_WS
#define TRACE_GROUP "avp"
// RFC 2865
// 1 User-Name
#define AVP_TYPE_USER_NAME 1
// 4 for NAS-IP-Address
#define AVP_TYPE_NAS_IP_ADDRESS 4
// 5 NAS-Port
#define AVP_TYPE_NAS_PORT 5
// 12 Framed-MTU
#define AVP_TYPE_FRAMED_MTU 12
// 24 State
#define AVP_TYPE_STATE 24
// 26 Vendor-Specific
#define AVP_TYPE_VENDOR_SPECIFIC 26
// 30 Called-Station-Id
#define AVP_TYPE_CALLED_STATION_ID 30
// 31 Calling-Station-Id
#define AVP_TYPE_CALLING_STATION_ID 31
// 32 NAS-Identifier
#define AVP_TYPE_NAS_IDENTIFIER 32
// 61 NAS-Port-Type
#define AVP_TYPE_NAS_PORT_TYPE 61
// RFC 3579
// 79 EAP-Message
#define AVP_TYPE_EAP_MESSAGE 79
// 80 Message-Authenticator
#define AVP_TYPE_MESSAGE_AUTHENTICATOR 80
// RFC 3162
// 95 NAS-IPv6-Address
#define AVP_TYPE_NAS_IPV6_ADDRESS 95
static uint8_t *avp_header_write(uint8_t *ptr, const uint8_t type, const uint8_t data_length)
{
*ptr++ = type;
*ptr++ = data_length + AVP_FIXED_LEN;
return ptr;
}
static uint8_t *avp_search(uint8_t *ptr, uint16_t len, const uint8_t type, uint8_t *avp_len)
{
while (len >= AVP_FIXED_LEN) {
*avp_len = ptr[1];
// Validates length field
if (*avp_len > len) {
return NULL;
}
if (ptr[0] == type) {
return ptr + AVP_FIXED_LEN;
}
if (len > *avp_len) {
len -= *avp_len;
ptr += *avp_len;
} else {
return NULL;
}
}
return NULL;
}
static uint8_t *avp_vpa_search(uint8_t *ptr, uint16_t len, const uint32_t vendor_id, const uint8_t vendor_type, uint8_t *vendor_len)
{
uint8_t avp_len = 0;
while (len >= AVP_FIXED_LEN) {
avp_len = ptr[1];
// Validates length field
if (avp_len > len) {
return NULL;
}
if (ptr[0] == AVP_TYPE_VENDOR_SPECIFIC && avp_len >= 9) {
ptr[2] = 0;
uint32_t avp_vendor_id = common_read_32_bit(&ptr[2]);
*vendor_len = ptr[7];
if (avp_vendor_id == vendor_id && ptr[6] == vendor_type) {
return &ptr[8];
}
}
if (len > avp_len) {
len -= avp_len;
ptr += avp_len;
} else {
return NULL;
}
}
return NULL;
}
uint8_t *avp_user_name_write(uint8_t *ptr, const uint8_t name_len, const uint8_t *name)
{
ptr = avp_header_write(ptr, AVP_TYPE_USER_NAME, name_len);
memcpy(ptr, name, name_len);
return ptr + name_len;
}
uint8_t *avp_nas_ip_address_write(uint8_t *ptr, uint32_t addr)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_IP_ADDRESS, 4);
memcpy(ptr, &addr, 4);
return ptr + 4;
}
uint8_t *avp_nas_port_write(uint8_t *ptr, const uint32_t port)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_PORT, 4);
ptr = common_write_32_bit(port, ptr);
return ptr;
}
uint8_t *avp_framed_mtu_write(uint8_t *ptr, const uint32_t mtu)
{
ptr = avp_header_write(ptr, AVP_TYPE_FRAMED_MTU, 4);
ptr = common_write_32_bit(mtu, ptr);
return ptr;
}
uint8_t *avp_state_write(uint8_t *ptr, const uint8_t state_len, const uint8_t *state)
{
ptr = avp_header_write(ptr, AVP_TYPE_STATE, state_len);
memcpy(ptr, state, state_len);
return ptr + state_len;
}
uint8_t *avp_called_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id)
{
ptr = avp_header_write(ptr, AVP_TYPE_CALLED_STATION_ID, id_len);
memcpy(ptr, id, id_len);
return ptr + id_len;
}
uint8_t *avp_calling_station_id_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id)
{
ptr = avp_header_write(ptr, AVP_TYPE_CALLING_STATION_ID, id_len);
memcpy(ptr, id, id_len);
return ptr + id_len;
}
uint8_t *avp_nas_identifier_write(uint8_t *ptr, const uint8_t id_len, const uint8_t *id)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_IDENTIFIER, id_len);
memcpy(ptr, id, id_len);
return ptr + id_len;
}
uint8_t *avp_nas_port_type_write(uint8_t *ptr, const uint32_t port_type)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_PORT_TYPE, 4);
ptr = common_write_32_bit(port_type, ptr);
return ptr;
}
uint8_t *avp_eap_message_write(uint8_t *ptr, const uint8_t eap_len, const uint8_t *eap)
{
ptr = avp_header_write(ptr, AVP_TYPE_EAP_MESSAGE, eap_len);
memcpy(ptr, eap, eap_len);
return ptr + eap_len;
}
uint8_t *avp_message_authenticator_write(uint8_t *ptr, const uint8_t *auth)
{
ptr = avp_header_write(ptr, AVP_TYPE_MESSAGE_AUTHENTICATOR, 16);
memcpy(ptr, auth, 16);
return ptr + 16;
}
uint8_t *avp_nas_ipv6_address_write(uint8_t *ptr, const uint8_t *address)
{
ptr = avp_header_write(ptr, AVP_TYPE_NAS_IPV6_ADDRESS, 16);
memcpy(ptr, address, 16);
return ptr + 16;
}
uint8_t *avp_eap_message_read(uint8_t *ptr, uint16_t len, uint8_t *eap_len)
{
ptr = avp_search(ptr, len, AVP_TYPE_EAP_MESSAGE, eap_len);
if (ptr == NULL) {
return NULL;
}
return ptr;
}
uint8_t *avp_message_authenticator_read(uint8_t *ptr, uint16_t len)
{
uint8_t auth_len = 0;
ptr = avp_search(ptr, len, AVP_TYPE_MESSAGE_AUTHENTICATOR, &auth_len);
if (ptr == NULL) {
return NULL;
}
if (auth_len < 18) {
return NULL;
}
return ptr;
}
uint8_t *avp_state_read(uint8_t *ptr, uint16_t len, uint8_t *state_len)
{
ptr = avp_search(ptr, len, AVP_TYPE_STATE, state_len);
if (ptr == NULL) {
return NULL;
}
return ptr;
}
uint8_t *avp_vsa_ms_mppe_recv_key_read(uint8_t *ptr, uint16_t len, uint8_t *recv_key_len)
{
const uint32_t vendor_id = 311;
const uint8_t vendor_type = 17;
ptr = avp_vpa_search(ptr, len, vendor_id, vendor_type, recv_key_len);
if (ptr == NULL) {
return NULL;
}
return ptr;
}
#endif