Fix invalid logics

This commit is contained in:
moznion
2020-11-27 23:29:19 +09:00
parent df257747ae
commit e0a56492e8
4 changed files with 69 additions and 41 deletions
+13 -16
View File
@@ -18,7 +18,7 @@ impl Attributes {
let mut i = 0; let mut i = 0;
let mut attrs = Vec::new(); let mut attrs = Vec::new();
while bs.len() < i { while bs.len() > i {
if bs[i..].len() < 2 { if bs[i..].len() < 2 {
return Err("short buffer".to_owned()); return Err("short buffer".to_owned());
} }
@@ -29,15 +29,16 @@ impl Attributes {
} }
attrs.push(AVP { attrs.push(AVP {
typ: bs[i + 0], typ: bs[i],
attribute: if length > 2 { attribute: if length > 2 {
Attribute(bs[i + 2..].to_vec()) debug!("ATTR {:?}", &bs[i + 2..length]);
Attribute(bs[i + 2..length + 2].to_vec())
} else { } else {
Attribute(vec![]) Attribute(vec![])
}, },
}); });
i += length; i += 2 + length;
} }
Ok(Attributes(attrs)) Ok(Attributes(attrs))
@@ -91,23 +92,19 @@ impl Attributes {
Ok(n) Ok(n)
} }
pub fn encode(&self, data: Vec<u8>) -> Vec<u8> { pub fn encode(&self) -> Result<Vec<u8>, String> {
let mut encoded: Vec<u8> = Vec::new(); let mut encoded: Vec<u8> = Vec::new();
for attr in &self.0 { for avp in &self.0 {
let attr_len = attr.attribute.0.len(); let attr_len = avp.attribute.0.len();
if attr_len > 253 { if attr_len > 253 {
continue; return Err("attribute is too large".to_owned());
} }
let size = 1 + 1 + attr_len; encoded.push(avp.typ);
encoded.push(attr_len as u8);
encoded = Vec::new(); encoded.extend(&avp.attribute.0);
encoded.push(attr.typ);
encoded.push(size as u8);
encoded.extend(&attr.attribute.0);
encoded = encoded[size..].to_owned();
} }
encoded Ok(encoded)
} }
} }
+2 -2
View File
@@ -68,9 +68,9 @@ where
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
let program = args[0].clone(); let _program = args[0].clone();
let mut opts = Options::new(); let opts = Options::new();
let matches = opts let matches = opts
.parse(&args[1..]) .parse(&args[1..])
.unwrap_or_else(|f| panic!(f.to_string())); .unwrap_or_else(|f| panic!(f.to_string()));
+1
View File
@@ -74,6 +74,7 @@ impl Client {
} }
}; };
debug!("Client resp: {:?}", &buf[..len].to_vec());
match Packet::parse(&buf[..len].to_vec(), request_packet.get_secret()) { match Packet::parse(&buf[..len].to_vec(), request_packet.get_secret()) {
Ok(response_packet) => Ok(response_packet), Ok(response_packet) => Ok(response_packet),
Err(e) => Err(FailedParsingUDPResponse(e)), Err(e) => Err(FailedParsingUDPResponse(e)),
+50 -20
View File
@@ -7,6 +7,7 @@ use crate::attributes::{AVPType, Attributes};
use crate::code::Code; use crate::code::Code;
const MAX_PACKET_LENGTH: usize = 4096; const MAX_PACKET_LENGTH: usize = 4096;
const RADIUS_PACKET_HEADER_LENGTH: usize = 20; // i.e. minimum packet lengt
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Packet { pub struct Packet {
@@ -43,19 +44,20 @@ impl Packet {
} }
pub fn parse(bs: &[u8], secret: &[u8]) -> Result<Self, String> { pub fn parse(bs: &[u8], secret: &[u8]) -> Result<Self, String> {
if bs.len() < 20 { if bs.len() < RADIUS_PACKET_HEADER_LENGTH {
return Err("radius packet doesn't have enough length of bytes; that has to be at least 20 bytes".to_owned()); return Err(format!("radius packet doesn't have enough length of bytes; that has to be at least {} bytes", RADIUS_PACKET_HEADER_LENGTH));
} }
let len = match bs[2..4].try_into() { let len = match bs[2..4].try_into() {
Ok(v) => u16::from_be_bytes(v), Ok(v) => u16::from_be_bytes(v),
Err(e) => return Err(e.to_string()), Err(e) => return Err(e.to_string()),
} as usize; } as usize;
if len < 20 || len > MAX_PACKET_LENGTH || bs.len() < len { if len < RADIUS_PACKET_HEADER_LENGTH || len > MAX_PACKET_LENGTH || bs.len() < len {
return Err("invalid radius packat lengt".to_owned()); return Err("invalid radius packat lengt".to_owned());
} }
let attributes = match Attributes::parse_attributes(&bs[20..len].to_vec()) { let attributes =
match Attributes::parse_attributes(&bs[RADIUS_PACKET_HEADER_LENGTH..len].to_vec()) {
Ok(attributes) => attributes, Ok(attributes) => attributes,
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
@@ -63,7 +65,7 @@ impl Packet {
Ok(Packet { Ok(Packet {
code: Code::from(bs[0]), code: Code::from(bs[0]),
identifier: bs[1], identifier: bs[1],
authenticator: bs[4..20].to_owned(), authenticator: bs[4..RADIUS_PACKET_HEADER_LENGTH].to_owned(),
secret: secret.to_owned(), secret: secret.to_owned(),
attributes, attributes,
}) })
@@ -80,11 +82,12 @@ impl Packet {
} }
pub fn encode(&self) -> Result<Vec<u8>, String> { pub fn encode(&self) -> Result<Vec<u8>, String> {
let bs = match self.marshal_binary() { let mut bs = match self.marshal_binary() {
Ok(bs) => bs, Ok(bs) => bs,
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
debug!("encoded resp bs: {:?}", bs);
match self.code { match self.code {
Code::AccessRequest | Code::StatusServer => Ok(bs), Code::AccessRequest | Code::StatusServer => Ok(bs),
Code::AccessAccept Code::AccessAccept
@@ -107,24 +110,43 @@ impl Packet {
]); ]);
} }
_ => { _ => {
buf.extend(self.authenticator.clone()); buf.extend(self.authenticator.clone()); // TODO take from `bs`?
} }
} }
buf.extend(bs[20..].to_vec()); buf.extend(bs[RADIUS_PACKET_HEADER_LENGTH..].to_vec());
buf.extend(&self.secret); buf.extend(&self.secret);
Ok(md5::compute(buf).to_vec()) bs.splice(4..20, md5::compute(&buf).to_vec());
debug!("md5: {:?}", md5::compute(&buf).to_vec());
debug!("encoded resp bs: {:?}", bs);
Ok(bs)
} }
_ => Err("unknown packet code".to_owned()), _ => Err("unknown packet code".to_owned()),
} }
} }
/*
* Binary structure:
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Code | Identifier | Length |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | |
* | Authenticator |
* | |
* | |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Attributes ...
* +-+-+-+-+-+-+-+-+-+-+-+-+-
*/
pub fn marshal_binary(&self) -> Result<Vec<u8>, String> { pub fn marshal_binary(&self) -> Result<Vec<u8>, String> {
let attributes_len = match self.attributes.attributes_encoded_len() { let encoded_avp = match self.attributes.encode() {
Ok(attributes_len) => attributes_len, Ok(encoded) => encoded,
Err(e) => return Err(e), Err(e) => return Err(e),
}; };
let size = 20 + attributes_len; let size = RADIUS_PACKET_HEADER_LENGTH as u16 + encoded_avp.len() as u16;
if size as usize > MAX_PACKET_LENGTH { if size as usize > MAX_PACKET_LENGTH {
return Err("packet is too large".to_owned()); return Err("packet is too large".to_owned());
} }
@@ -134,29 +156,37 @@ impl Packet {
bs.push(self.identifier); bs.push(self.identifier);
bs.extend(u16::to_be_bytes(size).to_vec()); bs.extend(u16::to_be_bytes(size).to_vec());
bs.extend(self.authenticator.to_vec()); bs.extend(self.authenticator.to_vec());
Ok(self.attributes.encode(bs)) bs.extend(match self.attributes.encode() {
Ok(encoded) => encoded,
Err(e) => return Err(e),
});
debug!("{:?}", bs);
Ok(bs)
} }
pub fn is_authentic_response(response: Vec<u8>, request: Vec<u8>, secret: Vec<u8>) -> bool { pub fn is_authentic_response(response: Vec<u8>, request: Vec<u8>, secret: Vec<u8>) -> bool {
if response.len() < 20 || request.len() < 20 || secret.is_empty() { if response.len() < RADIUS_PACKET_HEADER_LENGTH
|| request.len() < RADIUS_PACKET_HEADER_LENGTH
|| secret.is_empty()
{
return false; return false;
} }
md5::compute( md5::compute(
[ [
&response[..4], &response[..4],
&request[4..20], &request[4..RADIUS_PACKET_HEADER_LENGTH],
&response[20..], // TODO length &response[RADIUS_PACKET_HEADER_LENGTH..], // TODO length
&secret, &secret,
] ]
.concat(), .concat(),
) )
.to_vec() .to_vec()
.eq(&response[4..20].to_vec()) .eq(&response[4..RADIUS_PACKET_HEADER_LENGTH].to_vec())
} }
pub fn is_authentic_request(request: &[u8], secret: &[u8]) -> bool { pub fn is_authentic_request(request: &[u8], secret: &[u8]) -> bool {
if request.len() < 20 || secret.is_empty() { if request.len() < RADIUS_PACKET_HEADER_LENGTH || secret.is_empty() {
return false; return false;
} }
@@ -170,13 +200,13 @@ impl Packet {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
], ],
&request[20..], // TODO length &request[RADIUS_PACKET_HEADER_LENGTH..], // TODO length
&secret, &secret,
] ]
.concat(), .concat(),
) )
.to_vec() .to_vec()
.eq(&request[4..20].to_vec()) .eq(&request[4..RADIUS_PACKET_HEADER_LENGTH].to_vec())
} }
_ => false, _ => false,
} }