diff --git a/README.md b/README.md index 3384475..2f958cf 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ This supports the following RFC dictionaries at the moment: - [RFC5090](https://tools.ietf.org/html/rfc5090) - [RFC5176](https://tools.ietf.org/html/rfc5176) - [RFC5607](https://tools.ietf.org/html/rfc5607) +- [RFC5904](https://tools.ietf.org/html/rfc5904) - [RFC6519](https://tools.ietf.org/html/rfc6519) - [RFC6677](https://tools.ietf.org/html/rfc6677) - [RFC6911](https://tools.ietf.org/html/rfc6911) @@ -47,7 +48,6 @@ Simple example implementations are here: - rfc4679 - rfc5447 - rfc5580 - - rfc5904 - rfc6572 - rfc6929 - rfc6930 diff --git a/code-generator/src/main.rs b/code-generator/src/main.rs index 56b0981..55b2a25 100644 --- a/code-generator/src/main.rs +++ b/code-generator/src/main.rs @@ -53,6 +53,7 @@ enum RadiusAttributeValueType { IfId, Date, Integer, + Short, VSA, } @@ -68,6 +69,7 @@ impl FromStr for RadiusAttributeValueType { "ifid" => Ok(RadiusAttributeValueType::IfId), "date" => Ok(RadiusAttributeValueType::Date), "integer" => Ok(RadiusAttributeValueType::Integer), + "short" => Ok(RadiusAttributeValueType::Short), "vsa" => Ok(RadiusAttributeValueType::VSA), _ => Err(()), } @@ -283,6 +285,10 @@ fn generate_attribute_code( }, } } + RadiusAttributeValueType::Short => match attr.has_tag { + true => unimplemented!("tagged-short"), + false => generate_short_attribute_code(w, &method_identifier, &type_identifier), + }, RadiusAttributeValueType::VSA => generate_vsa_attribute_code(), } } @@ -719,6 +725,32 @@ pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result, + method_identifier: &str, + type_identifier: &str, +) { + let code = format!( + "pub fn add_{method_identifier}(packet: &mut Packet, value: u16) {{ + packet.add(AVP::from_u16({type_identifier}, value)); +}} +pub fn lookup_{method_identifier}(packet: &Packet) -> Option> {{ + packet.lookup({type_identifier}).map(|v| v.encode_u16()) +}} +pub fn lookup_all_{method_identifier}(packet: &Packet) -> Result, AVPError> {{ + let mut vec = Vec::new(); + for avp in packet.lookup_all({type_identifier}) {{ + vec.push(avp.encode_u16()?) + }} + Ok(vec) +}} +", + method_identifier = method_identifier, + type_identifier = type_identifier, + ); + w.write_all(code.as_bytes()).unwrap(); +} + fn generate_vsa_attribute_code() { // NOP } diff --git a/dicts/dictionary.rfc5904 b/dicts/dictionary.rfc5904 new file mode 100644 index 0000000..56659e1 --- /dev/null +++ b/dicts/dictionary.rfc5904 @@ -0,0 +1,25 @@ +# -*- text -*- +# Copyright (C) 2020 The FreeRADIUS Server project and contributors +# This work is licensed under CC-BY version 4.0 https://creativecommons.org/licenses/by/4.0 +# Version $Id$ +# +# Attributes and values defined in RFC 5904. +# http://www.ietf.org/rfc/rfc5904.txt +# +# $Id$ +# + +# The next two attributes are continued, like EAP-Message +ATTRIBUTE PKM-SS-Cert 137 octets concat +ATTRIBUTE PKM-CA-Cert 138 octets concat + +# 28 bytes of data, 7 integers +ATTRIBUTE PKM-Config-Settings 139 octets +ATTRIBUTE PKM-Cryptosuite-List 140 octets +ATTRIBUTE PKM-SAID 141 short + +# 6 bytes of data: SAID, 1 byte of type, 3 of cryptosuite +ATTRIBUTE PKM-SA-Descriptor 142 octets + +# 133 bytes of data: integer lifetime, 1 byte sequence, 128 bytes of key +ATTRIBUTE PKM-Auth-Key 143 octets diff --git a/radius/src/avp.rs b/radius/src/avp.rs index 1a4b3be..30f1c35 100644 --- a/radius/src/avp.rs +++ b/radius/src/avp.rs @@ -48,6 +48,13 @@ impl AVP { } } + pub fn from_u16(typ: AVPType, value: u16) -> Self { + AVP { + typ, + value: u16::to_be_bytes(value).to_vec(), + } + } + pub fn from_tagged_u32(typ: AVPType, tag: Option<&Tag>, value: u32) -> Self { let tag = match tag { None => &Tag { @@ -287,6 +294,19 @@ impl AVP { } } + pub fn encode_u16(&self) -> Result { + const U16_SIZE: usize = std::mem::size_of::(); + if self.value.len() != U16_SIZE { + return Err(AVPError::InvalidAttributeLengthError(self.value.len())); + } + + let (int_bytes, _) = self.value.split_at(U16_SIZE); + match int_bytes.try_into() { + Ok(boxed_array) => Ok(u16::from_be_bytes(boxed_array)), + Err(e) => Err(AVPError::UnexpectedDecodingError(e.to_string())), + } + } + pub fn encode_tagged_u32(&self) -> Result<(u32, Tag), AVPError> { if self.value.is_empty() { return Err(AVPError::InvalidAttributeLengthError(self.value.len())); diff --git a/radius/src/lib.rs b/radius/src/lib.rs index f3600b3..c1febb9 100644 --- a/radius/src/lib.rs +++ b/radius/src/lib.rs @@ -20,6 +20,7 @@ pub mod rfc4849; pub mod rfc5090; pub mod rfc5176; pub mod rfc5607; +pub mod rfc5904; pub mod rfc6519; pub mod rfc6677; pub mod rfc6911; diff --git a/radius/src/rfc5904.rs b/radius/src/rfc5904.rs new file mode 100644 index 0000000..d70ab5e --- /dev/null +++ b/radius/src/rfc5904.rs @@ -0,0 +1,146 @@ +// Code generated by machine generator; DO NOT EDIT. + +use crate::avp::{AVPError, AVPType, AVP}; +use crate::packet::Packet; + +pub const PKM_SS_CERT_TYPE: AVPType = 137; +pub fn delete_pkm_ss_cert(packet: &mut Packet) { + packet.delete(PKM_SS_CERT_TYPE); +} +pub fn add_pkm_ss_cert(packet: &mut Packet, value: &[u8]) { + packet.extend( + value + .chunks(253) + .map(|chunk| AVP::from_bytes(PKM_SS_CERT_TYPE, chunk)) + .collect(), + ); +} +pub fn lookup_pkm_ss_cert(packet: &Packet) -> Option> { + let avps = packet.lookup_all(PKM_SS_CERT_TYPE); + match avps.is_empty() { + true => None, + false => Some(avps.into_iter().fold(Vec::new(), |mut acc, v| { + acc.extend(v.encode_bytes()); + acc + })), + } +} + +pub const PKM_CA_CERT_TYPE: AVPType = 138; +pub fn delete_pkm_ca_cert(packet: &mut Packet) { + packet.delete(PKM_CA_CERT_TYPE); +} +pub fn add_pkm_ca_cert(packet: &mut Packet, value: &[u8]) { + packet.extend( + value + .chunks(253) + .map(|chunk| AVP::from_bytes(PKM_CA_CERT_TYPE, chunk)) + .collect(), + ); +} +pub fn lookup_pkm_ca_cert(packet: &Packet) -> Option> { + let avps = packet.lookup_all(PKM_CA_CERT_TYPE); + match avps.is_empty() { + true => None, + false => Some(avps.into_iter().fold(Vec::new(), |mut acc, v| { + acc.extend(v.encode_bytes()); + acc + })), + } +} + +pub const PKM_CONFIG_SETTINGS_TYPE: AVPType = 139; +pub fn delete_pkm_config_settings(packet: &mut Packet) { + packet.delete(PKM_CONFIG_SETTINGS_TYPE); +} +pub fn add_pkm_config_settings(packet: &mut Packet, value: &[u8]) { + packet.add(AVP::from_bytes(PKM_CONFIG_SETTINGS_TYPE, value)); +} +pub fn lookup_pkm_config_settings(packet: &Packet) -> Option> { + packet + .lookup(PKM_CONFIG_SETTINGS_TYPE) + .map(|v| v.encode_bytes()) +} +pub fn lookup_all_pkm_config_settings(packet: &Packet) -> Vec> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(PKM_CONFIG_SETTINGS_TYPE) { + vec.push(avp.encode_bytes()) + } + vec +} + +pub const PKM_CRYPTOSUITE_LIST_TYPE: AVPType = 140; +pub fn delete_pkm_cryptosuite_list(packet: &mut Packet) { + packet.delete(PKM_CRYPTOSUITE_LIST_TYPE); +} +pub fn add_pkm_cryptosuite_list(packet: &mut Packet, value: &[u8]) { + packet.add(AVP::from_bytes(PKM_CRYPTOSUITE_LIST_TYPE, value)); +} +pub fn lookup_pkm_cryptosuite_list(packet: &Packet) -> Option> { + packet + .lookup(PKM_CRYPTOSUITE_LIST_TYPE) + .map(|v| v.encode_bytes()) +} +pub fn lookup_all_pkm_cryptosuite_list(packet: &Packet) -> Vec> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(PKM_CRYPTOSUITE_LIST_TYPE) { + vec.push(avp.encode_bytes()) + } + vec +} + +pub const PKM_SAID_TYPE: AVPType = 141; +pub fn delete_pkm_said(packet: &mut Packet) { + packet.delete(PKM_SAID_TYPE); +} +pub fn add_pkm_said(packet: &mut Packet, value: u16) { + packet.add(AVP::from_u16(PKM_SAID_TYPE, value)); +} +pub fn lookup_pkm_said(packet: &Packet) -> Option> { + packet.lookup(PKM_SAID_TYPE).map(|v| v.encode_u16()) +} +pub fn lookup_all_pkm_said(packet: &Packet) -> Result, AVPError> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(PKM_SAID_TYPE) { + vec.push(avp.encode_u16()?) + } + Ok(vec) +} + +pub const PKM_SA_DESCRIPTOR_TYPE: AVPType = 142; +pub fn delete_pkm_sa_descriptor(packet: &mut Packet) { + packet.delete(PKM_SA_DESCRIPTOR_TYPE); +} +pub fn add_pkm_sa_descriptor(packet: &mut Packet, value: &[u8]) { + packet.add(AVP::from_bytes(PKM_SA_DESCRIPTOR_TYPE, value)); +} +pub fn lookup_pkm_sa_descriptor(packet: &Packet) -> Option> { + packet + .lookup(PKM_SA_DESCRIPTOR_TYPE) + .map(|v| v.encode_bytes()) +} +pub fn lookup_all_pkm_sa_descriptor(packet: &Packet) -> Vec> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(PKM_SA_DESCRIPTOR_TYPE) { + vec.push(avp.encode_bytes()) + } + vec +} + +pub const PKM_AUTH_KEY_TYPE: AVPType = 143; +pub fn delete_pkm_auth_key(packet: &mut Packet) { + packet.delete(PKM_AUTH_KEY_TYPE); +} +pub fn add_pkm_auth_key(packet: &mut Packet, value: &[u8]) { + packet.add(AVP::from_bytes(PKM_AUTH_KEY_TYPE, value)); +} +pub fn lookup_pkm_auth_key(packet: &Packet) -> Option> { + packet.lookup(PKM_AUTH_KEY_TYPE).map(|v| v.encode_bytes()) +} +pub fn lookup_all_pkm_auth_key(packet: &Packet) -> Vec> { + let mut vec = Vec::new(); + for avp in packet.lookup_all(PKM_AUTH_KEY_TYPE) { + vec.push(avp.encode_bytes()) + } + vec +}