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}