Skip to main content

kmip_ttlv/
types.rs

1//! Low-level APIs for (de)serializing Rust primitives from/to TTLV bytes.
2//!
3//! Using the types in this module you can deserialize TTLV bytes to Rust equivalents of the TTLV header fields and
4//! primitive TTLV value types, and vice versa.
5//!
6//! For example:
7//!
8//! ```
9//! use kmip_ttlv::types::{TtlvTag, TtlvType, TtlvLength, TtlvInteger};
10//! use kmip_ttlv::types::SerializableTtlvType;
11//! # fn main() -> kmip_ttlv::types::Result<()> {
12//!
13//! // Hand craft some TTLV bytes to deserialize
14//! let mut ttlv_wire = Vec::new();
15//! ttlv_wire.extend(b"\x66\x00\x01");     // 3-byte tag
16//! ttlv_wire.extend(b"\x02");             // 1-byte type with value 2 (for Integer)
17//! ttlv_wire.extend(b"\x00\x00\x00\x04"); // 4-byte length with value 4 (for a 4-byte value length)
18//! ttlv_wire.extend(b"\x00\x00\x00\x03"); // 4-byte big-endian integer value 3
19//! ttlv_wire.extend(b"\x00\x00\x00\x00"); // 4-byte padding
20//!
21//! // Create a cursor for "Read"ing from the buffer
22//! let mut cursor = std::io::Cursor::new(&ttlv_wire);
23//!
24//! // Deserialize the TTLV bytes
25//! let tag = TtlvTag::read(&mut cursor)?;
26//! let typ = TtlvType::read(&mut cursor)?;
27//! let val = TtlvInteger::read(&mut cursor)?; // reads the length and padding bytes as well
28//!
29//! // Verify the result
30//! assert_eq!(*tag, 0x660001);
31//! assert_eq!(typ, TtlvType::Integer);
32//! assert_eq!(*val, 3);
33//!
34//! // Serialize the value back to TTLV bytes
35//! let mut buf = Vec::new();
36//! tag.write(&mut buf);
37//! val.write(&mut buf); // writes the type, length, value and padding bytes
38//!
39//! // Verify that the serialized bytes match our handcrafted bytes
40//! assert_eq!(&ttlv_wire, &buf);
41//! # Ok(())
42//! # }
43//! ```
44use std::{
45    convert::TryFrom,
46    fmt::{Debug, Display},
47    io::{Read, Write},
48    ops::Deref,
49    str::FromStr,
50};
51
52// --- FieldType ------------------------------------------------------------------------------------------------------
53
54/// The type of TTLV header or value field represented by some TTLV bytes.
55///
56/// This field is also used by the [TtlvStateMachine] to represent the next expected field type or types.
57#[derive(Copy, Clone, Debug, PartialEq, Eq)]
58pub enum FieldType {
59    Tag,
60    Type,
61    Length,
62    Value,
63    LengthAndValue,        // used when deserializing
64    TypeAndLengthAndValue, // used when serializing
65}
66
67impl Default for FieldType {
68    fn default() -> Self {
69        Self::Tag
70    }
71}
72
73impl Display for FieldType {
74    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75        match self {
76            FieldType::Tag => f.write_str("Tag"),
77            FieldType::Type => f.write_str("Type"),
78            FieldType::Length => f.write_str("Length"),
79            FieldType::Value => f.write_str("Value"),
80            FieldType::LengthAndValue => f.write_str("LengthAndValue"),
81            FieldType::TypeAndLengthAndValue => f.write_str("TypeAndLengthAndValue"),
82        }
83    }
84}
85
86// --- ByteOffset -----------------------------------------------------------------------------------------------------
87
88/// An offset into a collection of TTLV bytes.
89#[derive(Copy, Clone, Debug, PartialEq, Eq)]
90pub struct ByteOffset(pub u64);
91
92impl std::ops::Deref for ByteOffset {
93    type Target = u64;
94
95    fn deref(&self) -> &Self::Target {
96        &self.0
97    }
98}
99
100impl From<&u64> for ByteOffset {
101    fn from(v: &u64) -> Self {
102        ByteOffset(*v)
103    }
104}
105
106impl From<u64> for ByteOffset {
107    fn from(v: u64) -> Self {
108        ByteOffset(v)
109    }
110}
111
112impl TryFrom<usize> for ByteOffset {
113    type Error = ();
114
115    fn try_from(value: usize) -> std::result::Result<Self, Self::Error> {
116        if value < (u64::MAX as usize) {
117            Ok(ByteOffset(value as u64))
118        } else {
119            Err(())
120        }
121    }
122}
123
124impl<T> From<&std::io::Cursor<T>> for ByteOffset {
125    fn from(cursor: &std::io::Cursor<T>) -> Self {
126        ByteOffset(cursor.position())
127    }
128}
129
130impl<T> From<std::io::Cursor<T>> for ByteOffset {
131    fn from(cursor: std::io::Cursor<T>) -> Self {
132        ByteOffset(cursor.position())
133    }
134}
135
136/// Errors reported by the low-level (de)serialization API.
137#[derive(Debug)]
138#[allow(clippy::enum_variant_names)]
139pub enum Error {
140    IoError(std::io::Error),
141    InvalidTtlvTag(String),
142    UnexpectedTtlvField {
143        expected: FieldType,
144        actual: FieldType,
145    },
146    UnsupportedTtlvType(u8),
147    InvalidTtlvType(u8),
148    InvalidTtlvValueLength {
149        expected: u32,
150        actual: u32,
151        r#type: TtlvType,
152    },
153    InvalidTtlvValue(TtlvType),
154    InvalidStateMachineOperation,
155}
156
157impl From<std::io::Error> for Error {
158    fn from(e: std::io::Error) -> Self {
159        Error::IoError(e)
160    }
161}
162
163pub type Result<T> = std::result::Result<T, Error>;
164
165// --- TtlvTag --------------------------------------------------------------------------------------------------------
166
167/// A type for (de)serializing a TTLV Tag.
168///
169/// According to the [KMIP specification 1.0 section 9.1.1.1 Item Tag](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_toc8560):
170/// > _An Item Tag is a three-byte binary unsigned integer, transmitted big endian, which contains a number that
171///   designates the specific Protocol Field or Object that the TTLV object represents._
172#[derive(Clone, Copy, PartialEq, Eq, Hash)]
173pub struct TtlvTag(u32);
174
175impl TtlvTag {
176    pub fn read<T: Read>(src: &mut T) -> Result<Self> {
177        let mut raw_item_tag = [0u8; 3];
178        src.read_exact(&mut raw_item_tag)?;
179        Ok(TtlvTag::from(raw_item_tag))
180    }
181
182    pub fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
183        dst.write_all(&<[u8; 3]>::from(self)).map_err(Error::IoError)
184    }
185}
186
187impl Debug for TtlvTag {
188    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189        f.write_fmt(format_args!("0x{:0X}", &self.0))
190    }
191}
192
193impl Deref for TtlvTag {
194    type Target = u32;
195
196    fn deref(&self) -> &Self::Target {
197        &self.0
198    }
199}
200
201impl FromStr for TtlvTag {
202    type Err = Error;
203
204    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
205        let v =
206            u32::from_str_radix(s.trim_start_matches("0x"), 16).map_err(|_| Error::InvalidTtlvTag(s.to_string()))?;
207        Ok(TtlvTag(v))
208    }
209}
210
211impl std::fmt::Display for TtlvTag {
212    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213        write!(f, "0x{:06X}", self)
214    }
215}
216
217impl std::fmt::UpperHex for TtlvTag {
218    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219        write!(f, "{:X}", self.0)
220    }
221}
222
223impl From<TtlvTag> for [u8; 3] {
224    fn from(tag: TtlvTag) -> Self {
225        <[u8; 3]>::from(&tag)
226    }
227}
228
229impl From<&TtlvTag> for [u8; 3] {
230    fn from(tag: &TtlvTag) -> Self {
231        let b: [u8; 4] = tag.to_be_bytes();
232        [b[1], b[2], b[3]]
233    }
234}
235
236impl From<[u8; 3]> for TtlvTag {
237    fn from(b: [u8; 3]) -> Self {
238        TtlvTag(u32::from_be_bytes([0x00u8, b[0], b[1], b[2]]))
239    }
240}
241
242impl From<&[u8; 3]> for TtlvTag {
243    fn from(b: &[u8; 3]) -> Self {
244        TtlvTag(u32::from_be_bytes([0x00u8, b[0], b[1], b[2]]))
245    }
246}
247
248// --- TtlvType -------------------------------------------------------------------------------------------------------
249
250/// A type for (de)serializing a TTLV Type.
251///
252/// According to the [KMIP specification 1.0 section 9.1.1.2 Item Type](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_toc8562):
253/// > _An Item Type is a byte containing a coded value that indicates the data type of the data object._
254#[repr(u8)]
255#[derive(Copy, Clone, Debug, PartialEq)]
256pub enum TtlvType {
257    Structure = 0x01,
258    Integer = 0x02,
259    LongInteger = 0x03,
260    BigInteger = 0x04,
261    Enumeration = 0x05,
262    Boolean = 0x06,
263    TextString = 0x07,
264    ByteString = 0x08,
265    DateTime = 0x09,
266    // Interval = 0x0A,
267}
268
269impl TtlvType {
270    pub fn read<T: Read>(src: &mut T) -> Result<Self> {
271        let mut raw_item_type = [0u8; 1];
272        src.read_exact(&mut raw_item_type)?;
273        TtlvType::try_from(raw_item_type[0])
274    }
275
276    pub fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
277        dst.write_all(&[*self as u8]).map_err(Error::IoError)
278    }
279}
280
281impl std::fmt::Display for TtlvType {
282    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
283        match self {
284            TtlvType::Structure => f.write_str("Structure (0x01)"),
285            TtlvType::Integer => f.write_str("Integer (0x02)"),
286            TtlvType::LongInteger => f.write_str("LongInteger (0x03)"),
287            TtlvType::BigInteger => f.write_str("BigInteger (0x04)"),
288            TtlvType::Enumeration => f.write_str("Enumeration (0x05)"),
289            TtlvType::Boolean => f.write_str("Boolean (0x06)"),
290            TtlvType::TextString => f.write_str("TextString (0x07)"),
291            TtlvType::ByteString => f.write_str("ByteString (0x08)"),
292            TtlvType::DateTime => f.write_str("DateTime (0x09)"),
293        }
294    }
295}
296
297impl TryFrom<u8> for TtlvType {
298    type Error = Error;
299
300    fn try_from(value: u8) -> std::result::Result<Self, Self::Error> {
301        match value {
302            0x01 => Ok(TtlvType::Structure),
303            0x02 => Ok(TtlvType::Integer),
304            0x03 => Ok(TtlvType::LongInteger),
305            0x04 => Ok(TtlvType::BigInteger),
306            0x05 => Ok(TtlvType::Enumeration),
307            0x06 => Ok(TtlvType::Boolean),
308            0x07 => Ok(TtlvType::TextString),
309            0x08 => Ok(TtlvType::ByteString),
310            0x09 => Ok(TtlvType::DateTime),
311            // 0x0A => Ok(TtlvType::Interval),
312            0x0A => Err(Error::UnsupportedTtlvType(0x0A)),
313            _ => Err(Error::InvalidTtlvType(value)),
314        }
315    }
316}
317
318impl From<TtlvType> for [u8; 1] {
319    fn from(item_type: TtlvType) -> Self {
320        [item_type as u8]
321    }
322}
323
324// --- TtlvLength -----------------------------------------------------------------------------------------------------
325
326/// A type for (de)serializing a TTLV Length.
327///
328/// According to the [KMIP specification 1.0 section 9.1.1.3 Item Length](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Toc236497868):
329/// > _An Item Length is a 32-bit binary integer, transmitted big-endian, containing the number of bytes in the Item
330///   Value._
331#[derive(Clone, Copy, PartialEq, Eq, Hash)]
332pub struct TtlvLength(u32);
333
334impl TtlvLength {
335    pub fn new(value: u32) -> Self {
336        Self(value)
337    }
338
339    pub fn read<T: Read>(src: &mut T) -> Result<Self> {
340        let mut value_length = [0u8; 4];
341        src.read_exact(&mut value_length)?;
342        Ok(Self(u32::from_be_bytes(value_length)))
343    }
344
345    pub fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
346        dst.write_all(&self.0.to_be_bytes()).map_err(Error::IoError)
347    }
348}
349
350impl Debug for TtlvLength {
351    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
352        f.write_fmt(format_args!("0x{:0X}", &self.0))
353    }
354}
355
356impl Deref for TtlvLength {
357    type Target = u32;
358
359    fn deref(&self) -> &Self::Target {
360        &self.0
361    }
362}
363
364impl std::fmt::Display for TtlvLength {
365    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
366        write!(f, "0x{:08X}", self)
367    }
368}
369
370impl std::fmt::UpperHex for TtlvLength {
371    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
372        write!(f, "{:X}", self.0)
373    }
374}
375
376// --- SerializableTtlvType ------------------------------------------------------------------------------------------------------
377
378/// A type that knows how to (de)serialize itself from/to TTLV byte format.
379///
380/// This type provides a common interface for (de)serializing Rust companion types to their TTLV byte form equivalents.
381///
382/// It is also provides default implementations that handle the TTLV padding byte rules.
383///
384/// According to the [KMIP specification 1.0 section 9.1.1.3 Item Length](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Toc236497868):
385/// > An Item Length is a 32-bit binary integer, transmitted big-endian, containing the number of bytes in the
386/// > Item Value. The allowed values are:
387/// >
388/// >   Data Type    | Length
389/// >   -------------|----------------------
390/// >   Structure    | Varies, multiple of 8
391/// >   Integer      | 4
392/// >   Long Integer | 8
393/// >   Big Integer  | Varies, multiple of 8
394/// >   Enumeration  | 4
395/// >   Boolean      | 8
396/// >   Text String  | Varies
397/// >   Byte String  | Varies
398/// >   Date-Time    | 8
399/// >   Interval     | 4
400/// >
401/// >   Table 192: Allowed Item Length Values
402/// >
403/// > If the Item Type is Structure, then the Item Length is the total length of all of the sub-items contained in
404/// > the structure, including any padding. If the Item Type is Integer, Enumeration, Text String, Byte String, or
405/// > Interval, then the Item Length is the number of bytes excluding the padding bytes. Text Strings and Byte
406/// > Strings SHALL be padded with the minimal number of bytes following the Item Value to obtain a multiple
407/// > of eight bytes. Integers, Enumerations, and Intervals SHALL be padded with four bytes following the Item
408/// > Value.
409pub trait SerializableTtlvType: Sized + Deref {
410    const TTLV_TYPE: TtlvType;
411
412    fn ttlv_type(&self) -> TtlvType {
413        Self::TTLV_TYPE
414    }
415
416    fn calc_pad_bytes(value_len: u32) -> u32 {
417        // pad to the next higher multiple of eight
418        let remainder = value_len % 8;
419
420        if remainder == 0 {
421            // already on the alignment boundary, no need to add pad bytes to reach the boundary
422            0
423        } else {
424            // for a shorter value, say 6 bytes, this calculates 8-(6%8) = 8-6 = 2, i.e. after having read 6 bytes the
425            // next pad boundary is 2 bytes away.
426            // for a longer value, say 10 bytes, this calcualtes 8-(10%8) = 8-2 = 6, i.e. after having read 10 bytes the
427            // next pad boundary is 6 bytes away.
428            8 - remainder
429        }
430    }
431
432    fn read_pad_bytes<T: Read>(src: &mut T, value_len: u32) -> Result<()> {
433        let num_pad_bytes = Self::calc_pad_bytes(value_len) as usize;
434        if num_pad_bytes > 0 {
435            let mut dst = [0u8; 8];
436            src.read_exact(&mut dst[..num_pad_bytes])?;
437        }
438        Ok(())
439    }
440
441    fn write_pad_bytes<T: Write>(dst: &mut T, value_len: u32) -> Result<()> {
442        let num_pad_bytes = Self::calc_pad_bytes(value_len) as usize;
443        if num_pad_bytes > 0 {
444            const PADDING_BYTES: [u8; 8] = [0; 8];
445            dst.write_all(&PADDING_BYTES[..num_pad_bytes])?;
446        }
447        Ok(())
448    }
449
450    fn read<T: Read>(src: &mut T) -> Result<Self> {
451        // The TTLV T_ype has already been read by the caller in order to determine which Primitive struct to use so
452        // we only have to read the L_ength and and the V_alue.
453        let mut value_len = [0u8; 4];
454        src.read_exact(&mut value_len)?; // read L_ength
455        let value_len = u32::from_be_bytes(value_len);
456        let v = Self::read_value(src, value_len)?; // read V_alue
457        Self::read_pad_bytes(src, value_len)?; // read 8-byte alignment padding bytes
458        Ok(v)
459    }
460
461    // Writes the TLV part of TTLV, i.e. the type, length and value. It doesn't write the preceeding tag as that is
462    // not part of the primitive value but is part of the callers context and only they can know which tag value to
463    // write.
464    fn write<T: Write>(&self, dst: &mut T) -> Result<()> {
465        dst.write_all(&[Self::TTLV_TYPE as u8])?; // write T_ype
466        let value_len = self.write_length_and_value(dst)?; // write L_ength and V_alue
467        Self::write_pad_bytes(dst, value_len) // Write 8-byte alignment padding bytes
468    }
469
470    fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self>;
471
472    fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32>;
473}
474
475// E.g. simple_primitive!(MyType, ItemType::Integer, i32, 4) would define a new Rust struct called MyType which wraps an
476// i32 value and implements the SerializableTtlvType trait to define how to read/write from/to a sequence of 4
477// big-endian encoded bytes prefixed by a TTLV item type byte of value ItemType::Integer.
478macro_rules! define_fixed_value_length_serializable_ttlv_type {
479    ($(#[$meta:meta])* $NEW_TYPE_NAME:ident, $TTLV_ITEM_TYPE:expr, $RUST_TYPE:ty, $TTLV_VALUE_LEN:literal) => {
480        #[derive(Clone, Debug)]
481        $(#[$meta])*
482        pub struct $NEW_TYPE_NAME(pub $RUST_TYPE);
483        impl $NEW_TYPE_NAME {
484            const TTLV_FIXED_VALUE_LENGTH: u32 = $TTLV_VALUE_LEN;
485        }
486        impl Deref for $NEW_TYPE_NAME {
487            type Target = $RUST_TYPE;
488
489            fn deref(&self) -> &Self::Target {
490                &self.0
491            }
492        }
493        impl SerializableTtlvType for $NEW_TYPE_NAME {
494            const TTLV_TYPE: TtlvType = $TTLV_ITEM_TYPE;
495
496            fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
497                if value_len != Self::TTLV_FIXED_VALUE_LENGTH {
498                    Err(Error::InvalidTtlvValueLength {
499                        expected: Self::TTLV_FIXED_VALUE_LENGTH,
500                        actual: value_len,
501                        r#type: Self::TTLV_TYPE,
502                    })
503                } else {
504                    let mut dst = [0u8; Self::TTLV_FIXED_VALUE_LENGTH as usize];
505                    src.read_exact(&mut dst)?;
506                    let v: $RUST_TYPE = <$RUST_TYPE>::from_be_bytes(dst);
507                    Ok($NEW_TYPE_NAME(v))
508                }
509            }
510
511            fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
512                dst.write_all(&Self::TTLV_FIXED_VALUE_LENGTH.to_be_bytes())?; // Write L_ength
513                dst.write_all(&self.0.to_be_bytes())?; // Write V_alue
514                Ok(Self::TTLV_FIXED_VALUE_LENGTH)
515            }
516        }
517    };
518}
519
520// --- TtlvInteger ----------------------------------------------------------------------------------------------------
521
522define_fixed_value_length_serializable_ttlv_type!(
523    /// A type for (de)serializing a TTLV Integer.
524    ///
525    /// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
526    /// > _Integers are encoded as four-byte long (32 bit) binary signed numbers in 2's complement notation,
527    /// > transmitted big-endian._
528    TtlvInteger,
529    TtlvType::Integer,
530    i32,
531    4
532);
533
534// --- TtlvLongInteger ------------------------------------------------------------------------------------------------
535
536define_fixed_value_length_serializable_ttlv_type!(
537    /// A type for (de)serializing a TTLV Long Integer.
538    ///
539    /// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
540    /// > _Long Integers are encoded as eight-byte long (64 bit) binary signed numbers in 2's complement
541    /// > notation, transmitted big-endian._
542    TtlvLongInteger,
543    TtlvType::LongInteger,
544    i64,
545    8
546);
547
548// --- TtlvBigInteger -------------------------------------------------------------------------------------------------
549
550/// A type for (de)serializing a TTLV Big Integer.
551///
552/// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
553/// > _Big Integers are encoded as a sequence of eight-bit bytes, in two's complement notation,
554///   transmitted big-endian. If the length of the sequence is not a multiple of eight bytes, then Big
555///   Integers SHALL be padded with the minimal number of leading sign-extended bytes to make the
556///   length a multiple of eight bytes. These padding bytes are part of the Item Value and SHALL be
557///   counted in the Item Length._
558#[derive(Clone, Debug)]
559pub struct TtlvBigInteger(pub Vec<u8>);
560impl Deref for TtlvBigInteger {
561    type Target = Vec<u8>;
562
563    fn deref(&self) -> &Self::Target {
564        &self.0
565    }
566}
567impl SerializableTtlvType for TtlvBigInteger {
568    const TTLV_TYPE: TtlvType = TtlvType::BigInteger;
569
570    fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
571        let mut dst = vec![0; value_len as usize];
572        src.read_exact(&mut dst)?;
573        Ok(TtlvBigInteger(dst))
574    }
575
576    fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
577        let v = self.0.as_slice();
578        let v_len = v.len() as u32;
579        let num_pad_bytes = Self::calc_pad_bytes(v_len);
580        let v_len = v_len + num_pad_bytes;
581        dst.write_all(&v_len.to_be_bytes())?; // Write L_ength
582                                              // Write pad bytes out as leading sign extending bytes, i.e. if the sign is positive then pad with zeros
583                                              // otherwise pad with ones.
584        let pad_byte = if v_len > 0 && v[0] & 0b1000_0000 == 0b1000_0000 {
585            0b1111_1111
586        } else {
587            0b0000_0000
588        };
589        for _ in 1..=num_pad_bytes {
590            dst.write_all(&[pad_byte])?;
591        }
592        dst.write_all(v)?; // Write V_alue
593        Ok(v_len)
594    }
595}
596
597// --- TtlvEnumeration ------------------------------------------------------------------------------------------------
598
599define_fixed_value_length_serializable_ttlv_type!(
600    /// A type for (de)serializing a TTLV Enumeration.
601    ///
602    /// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
603    /// > _Enumerations are encoded as four-byte long (32 bit) binary unsigned numbers transmitted big-
604    ///   endian. Extensions, which are permitted, but are not defined in this specification, contain the
605    ///   value 8 hex in the first nibble of the first byte._
606    TtlvEnumeration,
607    TtlvType::Enumeration,
608    u32,
609    4
610);
611
612// --- TtlvBoolean ----------------------------------------------------------------------------------------------------
613
614/// A type for (de)serializing a TTLV Boolean.
615///
616/// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
617/// > _Booleans are encoded as an eight-byte value that SHALL either contain the hex value
618///   0000000000000000, indicating the Boolean value False, or the hex value 0000000000000001,
619///   transmitted big-endian, indicating the Boolean value True._
620/// Boolean cannot be implemented using the define_fixed_value_length_serializable_ttlv_type! macro because it has
621/// special value verification rules.
622#[derive(Clone, Debug)]
623pub struct TtlvBoolean(pub bool);
624impl TtlvBoolean {
625    const TTLV_FIXED_VALUE_LENGTH: u32 = 8;
626}
627impl Deref for TtlvBoolean {
628    type Target = bool;
629
630    fn deref(&self) -> &Self::Target {
631        &self.0
632    }
633}
634impl SerializableTtlvType for TtlvBoolean {
635    const TTLV_TYPE: TtlvType = TtlvType::Boolean;
636
637    fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
638        if value_len != Self::TTLV_FIXED_VALUE_LENGTH {
639            Err(Error::InvalidTtlvValueLength {
640                expected: Self::TTLV_FIXED_VALUE_LENGTH,
641                actual: value_len,
642                r#type: Self::TTLV_TYPE,
643            })
644        } else {
645            let mut dst = [0u8; Self::TTLV_FIXED_VALUE_LENGTH as usize];
646            src.read_exact(&mut dst)?;
647            match u64::from_be_bytes(dst) {
648                0 => Ok(TtlvBoolean(false)),
649                1 => Ok(TtlvBoolean(true)),
650                _ => Err(Error::InvalidTtlvValue(Self::TTLV_TYPE)),
651            }
652        }
653    }
654
655    fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
656        let v = match self.0 {
657            true => 1u64,
658            false => 0u64,
659        };
660        dst.write_all(&Self::TTLV_FIXED_VALUE_LENGTH.to_be_bytes())?; // Write L_ength
661        dst.write_all(&v.to_be_bytes())?; // Write V_alue
662        Ok(Self::TTLV_FIXED_VALUE_LENGTH)
663    }
664}
665
666// --- TtlvTextString -------------------------------------------------------------------------------------------------
667
668// TextString cannot be implemented using the define_fixed_value_length_serializable_ttlv_type! macro because it has a
669// dynamic length._
670
671/// A type for (de)serializing a TTLV Text String.
672///
673/// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
674/// > _Text Strings are sequences of bytes that encode character values according to the UTF-8
675///   encoding standard. There SHALL NOT be null-termination at the end of such strings._
676#[derive(Clone, Debug)]
677pub struct TtlvTextString(pub String);
678impl Deref for TtlvTextString {
679    type Target = String;
680
681    fn deref(&self) -> &Self::Target {
682        &self.0
683    }
684}
685impl SerializableTtlvType for TtlvTextString {
686    const TTLV_TYPE: TtlvType = TtlvType::TextString;
687
688    fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
689        // AnySyncRead the UTF-8 bytes, without knowing if they are valid UTF-8
690        let mut dst = vec![0; value_len as usize];
691        src.read_exact(&mut dst)?;
692
693        // Use the bytes as-is as the internal buffer for a String, verifying that the bytes are indeed valid
694        // UTF-8
695        let new_str = String::from_utf8(dst).map_err(|_| Error::InvalidTtlvValue(Self::TTLV_TYPE))?;
696
697        Ok(TtlvTextString(new_str))
698    }
699
700    fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
701        let v = self.0.as_bytes();
702        let v_len = v.len() as u32;
703        dst.write_all(&v_len.to_be_bytes())?; // Write L_ength
704        dst.write_all(v)?; // Write V_alue
705        Ok(v_len)
706    }
707}
708
709// --- TtlvByteString -------------------------------------------------------------------------------------------------
710
711// ByteString cannot be implemented using the define_fixed_value_length_serializable_ttlv_type! macro because it has a
712// dynamic length.
713
714/// A type for (de)serializing a TTLV Byte String.
715///
716/// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
717/// > _Byte Strings are sequences of bytes containing individual unspecified eight-bit binary values, and are interpreted
718///   in the same sequence order._
719#[derive(Clone, Debug)]
720pub struct TtlvByteString(pub Vec<u8>);
721impl Deref for TtlvByteString {
722    type Target = Vec<u8>;
723
724    fn deref(&self) -> &Self::Target {
725        &self.0
726    }
727}
728impl SerializableTtlvType for TtlvByteString {
729    const TTLV_TYPE: TtlvType = TtlvType::ByteString;
730
731    fn read_value<T: Read>(src: &mut T, value_len: u32) -> Result<Self> {
732        // AnySyncRead the UTF-8 bytes, without knowing if they are valid UTF-8
733        let mut dst = vec![0; value_len as usize];
734        src.read_exact(&mut dst)?;
735        Ok(TtlvByteString(dst))
736    }
737
738    fn write_length_and_value<T: Write>(&self, dst: &mut T) -> Result<u32> {
739        let v = self.0.as_slice();
740        let v_len = v.len() as u32;
741        dst.write_all(&v_len.to_be_bytes())?; // Write L_ength
742        dst.write_all(v)?; // Write V_alue
743        Ok(v_len)
744    }
745}
746
747// --- TtlvDateTime ---------------------------------------------------------------------------------------------------
748
749define_fixed_value_length_serializable_ttlv_type!(
750    /// A type for (de)serializing a TTLV Date-Time.
751    ///
752    /// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
753    /// > _Date-Time values are POSIX Time values encoded as Long Integers. POSIX Time, as described
754    ///   in IEEE Standard 1003.1 [IEEE1003-1], is the number of seconds since the Epoch (1970 Jan 1,
755    ///   00:00:00 UTC), not counting leap seconds._
756    TtlvDateTime,
757    TtlvType::DateTime,
758    i64,
759    8
760);
761
762// --- TtlvInterval ---------------------------------------------------------------------------------------------------
763
764/// A type for (de)serializing a TTLV Interval.
765///
766/// According to the [KMIP specification 1.0 section 9.1.1.4 Item Value](http://docs.oasis-open.org/kmip/spec/v1.0/os/kmip-spec-1.0-os.html#_Ref262577330):
767/// > _Intervals are encoded as four-byte long (32 bit) binary unsigned numbers, transmitted big-endian.
768///   They have a resolution of one second._
769#[allow(dead_code)]
770pub type TtlvInterval = TtlvEnumeration;
771
772// --- TtlvStateMachine ---------------------------------------------------------------------------------------------
773
774/// A flag used by [TtlvStateMachine] to know which rules to apply.
775#[derive(Clone, Copy, Debug, PartialEq, Eq)]
776pub enum TtlvStateMachineMode {
777    Deserializing,
778    Serializing,
779}
780
781/// A state machine for enforcing TTLV field order rules.
782pub struct TtlvStateMachine {
783    mode: TtlvStateMachineMode,
784    expected_next_field_type: FieldType,
785    ignore_next_tag: bool,
786}
787
788impl TtlvStateMachine {
789    pub fn new(mode: TtlvStateMachineMode) -> Self {
790        Self {
791            mode,
792            expected_next_field_type: FieldType::default(),
793            ignore_next_tag: false,
794        }
795    }
796
797    pub fn advance(&mut self, next_field_type: FieldType) -> std::result::Result<bool, Error> {
798        use TtlvStateMachineMode as Mode;
799
800        let next_expected_next_field_type = match (self.mode, self.expected_next_field_type, next_field_type) {
801            // First, the normal cases: expect a certain field type to be written next and that is what is indicated
802            (_, FieldType::Tag, FieldType::Tag) => FieldType::Type,
803            (_, FieldType::Type, FieldType::Type) => FieldType::Length,
804            (Mode::Serializing, FieldType::Type, FieldType::TypeAndLengthAndValue) => FieldType::Tag,
805            (_, FieldType::Length, FieldType::Length) => FieldType::Value,
806            (Mode::Deserializing, FieldType::Length, FieldType::LengthAndValue) => FieldType::Tag,
807            (_, FieldType::Value, FieldType::Value) => FieldType::Tag,
808
809            // In the leaf case a V always follows TTL, but higher in the TTLV structure hierarchy the first item in
810            // a structure can be another TTLV item (i.e. we see a tag being written instead of a value)
811            (_, FieldType::Value, FieldType::Tag) => FieldType::Type,
812
813            // Special case: we've been explicitly asked after writing a tag to ignore a subsequent attempt to write
814            // another tag. Normally attempting to write TT would be an error, but in this case the second T should be
815            // silently ignored. This supports use cases like the KMIP Attribute Value which is of the form XTLV where
816            // X is constant tag value and not the normal tag associated with the item being serialized.
817            (Mode::Serializing, FieldType::Type, FieldType::Tag) if self.ignore_next_tag => {
818                self.ignore_next_tag = false;
819                FieldType::Type
820            }
821
822            // Error, don't permit invalid things like TTVL etc.
823            (_, expected, actual) => {
824                return Err(Error::UnexpectedTtlvField { expected, actual });
825            }
826        };
827
828        // Advance the state machine if needed
829        if self.mode == Mode::Deserializing || next_expected_next_field_type != self.expected_next_field_type {
830            self.expected_next_field_type = next_expected_next_field_type;
831            Ok(true)
832        } else {
833            // It was permitted to stay in the current state. Signalling this allows calling code to know that it should
834            // NOT write out the next field, which normally would be an error and we would abort but in this case it is
835            // going to be okay as long as the caller respects this return value.
836            Ok(false)
837        }
838    }
839
840    pub fn ignore_next_tag(&mut self) -> std::result::Result<(), Error> {
841        if matches!(self.mode, TtlvStateMachineMode::Serializing) {
842            self.ignore_next_tag = true;
843            Ok(())
844        } else {
845            Err(Error::InvalidStateMachineOperation)
846        }
847    }
848
849    pub fn reset(&mut self) {
850        self.expected_next_field_type = FieldType::default();
851        self.ignore_next_tag = false;
852    }
853}