From ec6eca60fcb37a35890f688072f016f954b8d81b Mon Sep 17 00:00:00 2001 From: Nadja Reitzenstein Date: Wed, 16 Nov 2022 12:35:37 +0100 Subject: [PATCH] Update nom to the current version 7 Closes #37, #92 --- Cargo.toml | 2 +- lber/Cargo.toml | 7 +- lber/src/lib.rs | 7 +- lber/src/parse.rs | 157 +++++++++-------------------- lber/src/structures/integer.rs | 9 +- lber/src/write.rs | 16 +-- src/controls_impl/content_sync.rs | 8 +- src/controls_impl/paged_results.rs | 5 +- src/controls_impl/read_entry.rs | 4 +- src/exop_impl/passmod.rs | 4 +- src/protocol.rs | 24 ++--- src/result.rs | 3 +- 12 files changed, 91 insertions(+), 155 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8093777..82fd091 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ async-trait = "0.1.41" [dependencies.lber] path = "lber" -version = "0.3.0" +version = "0.4.0" [features] default = ["sync", "tls"] diff --git a/lber/Cargo.toml b/lber/Cargo.toml index 5ed2381..4a79bda 100644 --- a/lber/Cargo.toml +++ b/lber/Cargo.toml @@ -1,5 +1,5 @@ [package] -authors = ["Gregor Reitzenstein ", "Ivan Nejgebauer "] +authors = ["Nadja Reitzenstein ", "Ivan Nejgebauer "] categories = ["encoding", "parsing"] description = "An ASN.1/BER parser/encoder based on nom" keywords = ["ASN1", "BER", "nom"] @@ -7,9 +7,8 @@ license = "MIT" name = "lber" repository = "https://github.com/inejge/ldap3" documentation = "https://docs.rs/ldap3" -version = "0.3.0" +version = "0.4.0" [dependencies] -byteorder = "1" bytes = "1" -nom = "2" +nom = "7" diff --git a/lber/src/lib.rs b/lber/src/lib.rs index a291604..5995910 100644 --- a/lber/src/lib.rs +++ b/lber/src/lib.rs @@ -1,6 +1,4 @@ -extern crate byteorder; extern crate bytes; -#[macro_use] extern crate nom; pub mod common; @@ -10,6 +8,5 @@ pub mod structures; pub mod universal; pub mod write; -pub use nom::IResult::*; -pub use nom::{Consumer, ConsumerState, IResult, Input, Move}; -pub use parse::Parser; +pub use nom::IResult; +pub use parse::Parser; \ No newline at end of file diff --git a/lber/src/parse.rs b/lber/src/parse.rs index 720fd99..9cc7c62 100644 --- a/lber/src/parse.rs +++ b/lber/src/parse.rs @@ -3,148 +3,91 @@ use common::TagStructure; use structure::{StructureTag, PL}; use nom; -use nom::Consumer; -use nom::ConsumerState; -use nom::ConsumerState::*; -use nom::IResult; -use nom::Input; -use nom::Input::*; -use nom::InputLength; -use nom::Move; - -named!(class_bits<(&[u8], usize), TagClass>, - map_opt!( - take_bits!(u8, 2), - TagClass::from_u8 - ) -); +use nom::bits::streaming as bits; +use nom::number::streaming as number; +use nom::bytes::streaming::take; +use nom::combinator::map_opt; +use nom::{InputLength, IResult, Needed}; +use nom::sequence::tuple; + +fn class_bits(i: (&[u8], usize)) -> nom::IResult<(&[u8], usize), TagClass> { + map_opt(bits::take(2usize), TagClass::from_u8)(i) +} -named!(pc_bit<(&[u8], usize), TagStructure>, - map_opt!( - take_bits!(u8, 1), - TagStructure::from_u8 - ) -); +fn pc_bit(i: (&[u8], usize)) -> nom::IResult<(&[u8], usize), TagStructure> { + map_opt(bits::take(1usize), TagStructure::from_u8)(i) +} -named!(tagnr_bits<(&[u8], usize), u64>, - take_bits!(u64, 5) -); +fn tagnr_bits(i: (&[u8], usize)) -> nom::IResult<(&[u8], usize), u64> { + bits::take(5usize)(i) +} -named!(pub parse_type_header<(TagClass, TagStructure, u64)>, bits!( - do_parse!( - class: class_bits >> - pc: pc_bit >> - tagnr: tagnr_bits >> - ((class, pc, tagnr)) - ) -)); +fn parse_type_header(i: &[u8]) -> nom::IResult<&[u8], (TagClass, TagStructure, u64)> { + nom::bits(tuple((class_bits, pc_bit, tagnr_bits)))(i) +} -named!(pub parse_length, - alt!( - bits!( - do_parse!( - // Short length form - tag_bits!(u8, 1, 0u8) >> - len: take_bits!(u64, 7) >> - (len) - ) - ) - | - length_value!( - bits!( - do_parse!( - /* // TODO: Fix nom to be able to do this. - *return_error!(nom::ErrorKind::Custom(1), - * not!(tag_bits!(u8, 8, 255u8)) - *) >> - */ - // Long length form - tag_bits!(u8, 1, 1u8) >> - len: take_bits!(u8, 7) >> - (len) - ) - ), - parse_uint - ) - ) -); +fn parse_length(i: &[u8]) -> nom::IResult<&[u8], u64> { + let (i, len) = number::be_u8(i)?; + if len < 128 { + Ok((i, len as u64)) + } else { + let len = len - 128; + let (i, b) = take(len)(i)?; + let (_, len) = parse_uint(b)?; + Ok((i, len)) + } +} /// Extract an unsigned integer value from BER data. pub fn parse_uint(i: &[u8]) -> nom::IResult<&[u8], u64> { - nom::IResult::Done(i, i.iter().fold(0, |res, &byte| (res << 8) | byte as u64)) + Ok((i, i.iter().fold(0, |res, &byte| (res << 8) | byte as u64))) } /// Parse raw BER data into a serializable structure. pub fn parse_tag(i: &[u8]) -> nom::IResult<&[u8], StructureTag> { - let (mut i, ((class, structure, id), len)) = try_parse!( - i, - do_parse!(hdr: parse_type_header >> len: parse_length >> ((hdr, len))) - ); + let (mut i, ((class, structure, id), len)) = tuple((parse_type_header, parse_length))(i)?; let pl: PL = match structure { TagStructure::Primitive => { - let (j, content) = try_parse!(i, length_data!(value!(len))); + let (j, content) = take(len)(i)?; i = j; PL::P(content.to_vec()) } TagStructure::Constructed => { - let (j, mut content) = try_parse!(i, length_bytes!(value!(len))); + let (j, mut content) = take(len)(i)?; i = j; let mut tv: Vec = Vec::new(); while content.input_len() > 0 { - let pres = try_parse!(content, call!(parse_tag)); - content = pres.0; - let res: StructureTag = pres.1; - tv.push(res); + let (j, sub) = parse_tag(content)?; + content = j; + tv.push(sub); } PL::C(tv) } }; - nom::IResult::Done( + Ok(( i, StructureTag { - class: class, - id: id, + class, + id, payload: pl, }, - ) + )) } -pub struct Parser { - state: ConsumerState, -} +pub struct Parser; impl Parser { - pub fn new() -> Parser { - Parser { - state: Continue(Move::Consume(0)), - } - } -} - -impl<'a> Consumer<&'a [u8], StructureTag, (), Move> for Parser { - fn handle(&mut self, input: Input<&[u8]>) -> &ConsumerState { - use nom::Offset; - match input { - Empty | Eof(None) => self.state(), - Element(data) | Eof(Some(data)) => { - self.state = match parse_tag(data) { - IResult::Incomplete(n) => Continue(Move::Await(n)), - IResult::Error(_) => Error(()), - IResult::Done(i, o) => Done(Move::Consume(data.offset(i)), o), - }; - - &self.state - } - } + pub fn new() -> Self { + Self } - - fn state(&self) -> &ConsumerState { - &self.state + pub fn parse<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], StructureTag, nom::error::Error<&'a [u8]>> { + if input.is_empty() { return Err(nom::Err::Incomplete(Needed::Unknown)) }; + parse_tag(input) } } @@ -167,7 +110,7 @@ mod test { let tag = parse_tag(&bytes[..]); - assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag)); + assert_eq!(tag, Ok((&rest_tag[..], result_tag))); } #[test] @@ -188,7 +131,7 @@ mod test { let tag = parse_tag(&bytes[..]); - assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag)); + assert_eq!(tag, Ok((&rest_tag[..], result_tag))); } #[test] @@ -251,6 +194,6 @@ mod test { let rest_tag = Vec::new(); let tag = parse_tag(&bytes[..]); - assert_eq!(tag, IResult::Done(&rest_tag[..], result_tag)); + assert_eq!(tag, Ok((&rest_tag[..], result_tag))); } } diff --git a/lber/src/structures/integer.rs b/lber/src/structures/integer.rs index 3d85769..2fc88f0 100644 --- a/lber/src/structures/integer.rs +++ b/lber/src/structures/integer.rs @@ -5,8 +5,6 @@ use universal; use std::default; -use byteorder::{BigEndian, WriteBytesExt}; - /// Integer value. #[derive(Clone, Copy, Debug, PartialEq)] pub struct Integer { @@ -40,8 +38,11 @@ fn i_e_into_structure(id: u64, class: TagClass, inner: i64) -> structure::Struct } let mut out: Vec = Vec::with_capacity(count as usize); - - out.write_int::(inner, count as usize).unwrap(); + let repr = inner.to_be_bytes(); + if (count as usize) > repr.len() { + out.push(0); + } + out.extend_from_slice(&repr); structure::StructureTag { id: id, diff --git a/lber/src/write.rs b/lber/src/write.rs index 69c8103..bcceab4 100644 --- a/lber/src/write.rs +++ b/lber/src/write.rs @@ -1,5 +1,4 @@ //! BER encoding support. -use byteorder::{BigEndian, WriteBytesExt}; use bytes::BytesMut; use common::{TagClass, TagStructure}; use structure::{StructureTag, PL}; @@ -75,7 +74,7 @@ fn write_type(w: &mut dyn Write, class: TagClass, structure: TagStructure, id: u } }; // let type_byte - let _ = w.write_u8(type_byte); + let _ = w.write(&[type_byte]); if let Some(mut ext_bytes) = extended_tag { for _ in 0..ext_bytes.len() - 1 { @@ -84,11 +83,11 @@ fn write_type(w: &mut dyn Write, class: TagClass, structure: TagStructure, id: u // Set the first bit byte |= 0x80; - let _ = w.write_u8(byte); + let _ = w.write(&[byte]); } let byte = ext_bytes.pop().unwrap(); - let _ = w.write_u8(byte); + let _ = w.write(&[byte]); } } @@ -96,7 +95,7 @@ fn write_type(w: &mut dyn Write, class: TagClass, structure: TagStructure, id: u fn write_length(w: &mut dyn Write, length: usize) { // Short form if length < 128 { - let _ = w.write_u8(length as u8); + let _ = w.write(&[length as u8]); } // Long form else { @@ -108,8 +107,11 @@ fn write_length(w: &mut dyn Write, length: usize) { len > 0 } {} - let _ = w.write_u8(count | 0x80); - let _ = w.write_uint::(length as u64, count as usize); + let _ = w.write(&[count | 0x80]); + let repr = &length.to_be_bytes(); + let len = repr.len(); + let bytes = &repr[(len-(count as usize))..]; + let _ = w.write_all(bytes); } } diff --git a/src/controls_impl/content_sync.rs b/src/controls_impl/content_sync.rs index 9c9e942..c32a208 100644 --- a/src/controls_impl/content_sync.rs +++ b/src/controls_impl/content_sync.rs @@ -107,7 +107,7 @@ pub enum EntryState { impl ControlParser for SyncState { fn parse(val: &[u8]) -> Self { let mut tags = match parse_tag(val) { - IResult::Done(_, tag) => tag, + IResult::Ok((_, tag)) => tag, _ => panic!("syncstate: failed to parse tag"), } .expect_constructed() @@ -122,7 +122,7 @@ impl ControlParser for SyncState { .expect("syncstate: state") .as_slice(), ) { - IResult::Done(_, state) => state, + Ok((_, state)) => state, _ => panic!("syncstate: failed to parse state"), } { 0 => EntryState::Present, @@ -157,7 +157,7 @@ pub struct SyncDone { impl ControlParser for SyncDone { fn parse(val: &[u8]) -> Self { let tags = match parse_tag(val) { - IResult::Done(_, tag) => tag, + Ok((_, tag)) => tag, _ => panic!("syncdone: failed to parse tag"), } .expect_constructed() @@ -229,7 +229,7 @@ pub fn parse_syncinfo(entry: ResultEntry) -> SyncInfo { Some(tag) if tag.id == 1 => { let syncinfo_val = match parse_tag(tag.expect_primitive().expect("octet string").as_ref()) { - IResult::Done(_, tag) => tag, + Ok((_, tag)) => tag, _ => panic!("syncinfo: error parsing value"), }; return match syncinfo_val { diff --git a/src/controls_impl/paged_results.rs b/src/controls_impl/paged_results.rs index 3483b9e..38fe408 100644 --- a/src/controls_impl/paged_results.rs +++ b/src/controls_impl/paged_results.rs @@ -7,7 +7,6 @@ use lber::parse::{parse_tag, parse_uint}; use lber::structures::{ASNTag, Integer, OctetString, Sequence, Tag}; use lber::universal::Types; use lber::write; -use lber::IResult; /// Paged Results control ([RFC 2696](https://tools.ietf.org/html/rfc2696)). /// @@ -56,7 +55,7 @@ impl From for RawControl { impl ControlParser for PagedResults { fn parse(val: &[u8]) -> PagedResults { let mut pr_comps = match parse_tag(val) { - IResult::Done(_, tag) => tag, + Ok((_, tag)) => tag, _ => panic!("failed to parse paged results value components"), } .expect_constructed() @@ -72,7 +71,7 @@ impl ControlParser for PagedResults { .expect("paged results size") .as_slice(), ) { - IResult::Done(_, size) => size as i32, + Ok((_, size)) => size as i32, _ => panic!("failed to parse size"), }; let cookie = pr_comps diff --git a/src/controls_impl/read_entry.rs b/src/controls_impl/read_entry.rs index 9cbf1fe..61e139f 100644 --- a/src/controls_impl/read_entry.rs +++ b/src/controls_impl/read_entry.rs @@ -6,7 +6,7 @@ use super::{ControlParser, MakeCritical, RawControl}; use crate::search::{ResultEntry, SearchEntry}; use lber::parse::parse_tag; use lber::structures::{ASNTag, OctetString, Sequence, Tag}; -use lber::{write, IResult}; +use lber::write; pub const PRE_READ_OID: &str = "1.3.6.1.1.13.1"; pub const POST_READ_OID: &str = "1.3.6.1.1.13.2"; @@ -109,7 +109,7 @@ fn from_read_entry>(re: ReadEntry) -> RawControl { impl ControlParser for ReadEntryResp { fn parse(val: &[u8]) -> ReadEntryResp { let tag = match parse_tag(val) { - IResult::Done(_, tag) => tag, + Ok((_, tag)) => tag, _ => panic!("failed to parse pre-read attribute values"), }; let se = SearchEntry::construct(ResultEntry::new(tag)); diff --git a/src/exop_impl/passmod.rs b/src/exop_impl/passmod.rs index 06cdcdb..156c7a1 100644 --- a/src/exop_impl/passmod.rs +++ b/src/exop_impl/passmod.rs @@ -5,7 +5,7 @@ use bytes::BytesMut; use lber::common::TagClass; use lber::parse::parse_tag; use lber::structures::{ASNTag, OctetString, Sequence, Tag}; -use lber::{write, IResult}; +use lber::write; pub const PASSMOD_OID: &str = "1.3.6.1.4.1.4203.1.11.1"; @@ -87,7 +87,7 @@ impl<'a> From> for Exop { impl ExopParser for PasswordModifyResp { fn parse(val: &[u8]) -> PasswordModifyResp { let tags = match parse_tag(val) { - IResult::Done(_, tag) => tag, + Ok((_, tag)) => tag, _ => panic!("failed to parse password modify return value"), }; let mut tags = tags diff --git a/src/protocol.rs b/src/protocol.rs index 55a35b6..f60c7df 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -11,18 +11,18 @@ use crate::RequestId; use lber::common::TagClass; use lber::parse::parse_uint; -use lber::parse::Parser; use lber::structure::{StructureTag, PL}; use lber::structures::{ASNTag, Integer, Sequence, Tag}; use lber::universal::Types; use lber::write; -use lber::{Consumer, ConsumerState, IResult, Input, Move}; use bytes::{Buf, BytesMut}; #[cfg(feature = "gssapi")] use cross_krb5::{ClientCtx, K5Ctx}; use tokio::sync::{mpsc, oneshot}; use tokio_util::codec::{Decoder, Encoder}; +#[cfg(feature = "x509-parser")] +use x509_parser::nom::Parser; pub(crate) struct LdapCodec { #[cfg(feature = "gssapi")] @@ -54,18 +54,14 @@ pub enum LdapOp { #[allow(clippy::type_complexity)] fn decode_inner(buf: &mut BytesMut) -> Result))>, io::Error> { let decoding_error = io::Error::new(io::ErrorKind::Other, "decoding error"); - let mut parser = Parser::new(); - let (amt, tag) = match *parser.handle(Input::Element(buf)) { - ConsumerState::Continue(_) => return Ok(None), - ConsumerState::Error(_e) => return Err(decoding_error), - ConsumerState::Done(amt, ref tag) => (amt, tag), + let mut parser = lber::Parser::new(); + let binding = parser.parse(buf); + let (i, tag) = match binding { + Err(e) if e.is_incomplete() => return Ok(None), + Err(_e) => return Err(decoding_error), + Ok((i, ref tag)) => (i, tag), }; - let amt = match amt { - Move::Await(_) => return Ok(None), - Move::Seek(_) => return Err(decoding_error), - Move::Consume(amt) => amt, - }; - buf.advance(amt); + buf.advance(buf.len() - i.len()); let tag = tag.clone(); let mut tags = match tag .match_id(Types::Sequence as u64) @@ -115,7 +111,7 @@ fn decode_inner(buf: &mut BytesMut) -> Result id as i32, + Ok((_, id)) => id as i32, _ => return Err(decoding_error), }; Ok(Some((msgid, (Tag::StructureTag(protoop), controls)))) diff --git a/src/result.rs b/src/result.rs index 519bd6b..5160f38 100644 --- a/src/result.rs +++ b/src/result.rs @@ -23,7 +23,6 @@ use lber::common::TagClass; use lber::parse::parse_uint; use lber::structures::Tag; use lber::universal::Types; -use lber::IResult; use thiserror::Error; use tokio::sync::{mpsc, oneshot}; @@ -334,7 +333,7 @@ impl From for LdapResultExt { .expect("result code") .as_slice(), ) { - IResult::Done(_, rc) => rc as u32, + Ok((_, rc)) => rc as u32, _ => panic!("failed to parse result code"), }; let matched = String::from_utf8(