1 //! Slice writer. 2 3 use crate::{ 4 asn1::*, Encode, EncodeValue, ErrorKind, Header, Length, Result, Tag, TagMode, TagNumber, 5 Tagged, Writer, 6 }; 7 8 /// [`Writer`] which encodes DER into a mutable output byte slice. 9 #[derive(Debug)] 10 pub struct SliceWriter<'a> { 11 /// Buffer into which DER-encoded message is written 12 bytes: &'a mut [u8], 13 14 /// Has the encoding operation failed? 15 failed: bool, 16 17 /// Total number of bytes written to buffer so far 18 position: Length, 19 } 20 21 impl<'a> SliceWriter<'a> { 22 /// Create a new encoder with the given byte slice as a backing buffer. new(bytes: &'a mut [u8]) -> Self23 pub fn new(bytes: &'a mut [u8]) -> Self { 24 Self { 25 bytes, 26 failed: false, 27 position: Length::ZERO, 28 } 29 } 30 31 /// Encode a value which impls the [`Encode`] trait. encode<T: Encode>(&mut self, encodable: &T) -> Result<()>32 pub fn encode<T: Encode>(&mut self, encodable: &T) -> Result<()> { 33 if self.is_failed() { 34 self.error(ErrorKind::Failed)? 35 } 36 37 encodable.encode(self).map_err(|e| { 38 self.failed = true; 39 e.nested(self.position) 40 }) 41 } 42 43 /// Return an error with the given [`ErrorKind`], annotating it with 44 /// context about where the error occurred. error<T>(&mut self, kind: ErrorKind) -> Result<T>45 pub fn error<T>(&mut self, kind: ErrorKind) -> Result<T> { 46 self.failed = true; 47 Err(kind.at(self.position)) 48 } 49 50 /// Did the decoding operation fail due to an error? is_failed(&self) -> bool51 pub fn is_failed(&self) -> bool { 52 self.failed 53 } 54 55 /// Finish encoding to the buffer, returning a slice containing the data 56 /// written to the buffer. finish(self) -> Result<&'a [u8]>57 pub fn finish(self) -> Result<&'a [u8]> { 58 let position = self.position; 59 60 if self.is_failed() { 61 return Err(ErrorKind::Failed.at(position)); 62 } 63 64 self.bytes 65 .get(..usize::try_from(position)?) 66 .ok_or_else(|| ErrorKind::Overlength.at(position)) 67 } 68 69 /// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode. context_specific<T>( &mut self, tag_number: TagNumber, tag_mode: TagMode, value: &T, ) -> Result<()> where T: EncodeValue + Tagged,70 pub fn context_specific<T>( 71 &mut self, 72 tag_number: TagNumber, 73 tag_mode: TagMode, 74 value: &T, 75 ) -> Result<()> 76 where 77 T: EncodeValue + Tagged, 78 { 79 ContextSpecificRef { 80 tag_number, 81 tag_mode, 82 value, 83 } 84 .encode(self) 85 } 86 87 /// Encode an ASN.1 `SEQUENCE` of the given length. 88 /// 89 /// Spawns a nested slice writer which is expected to be exactly the 90 /// specified length upon completion. sequence<F>(&mut self, length: Length, f: F) -> Result<()> where F: FnOnce(&mut SliceWriter<'_>) -> Result<()>,91 pub fn sequence<F>(&mut self, length: Length, f: F) -> Result<()> 92 where 93 F: FnOnce(&mut SliceWriter<'_>) -> Result<()>, 94 { 95 Header::new(Tag::Sequence, length).and_then(|header| header.encode(self))?; 96 97 let mut nested_encoder = SliceWriter::new(self.reserve(length)?); 98 f(&mut nested_encoder)?; 99 100 if nested_encoder.finish()?.len() == usize::try_from(length)? { 101 Ok(()) 102 } else { 103 self.error(ErrorKind::Length { tag: Tag::Sequence }) 104 } 105 } 106 107 /// Reserve a portion of the internal buffer, updating the internal cursor 108 /// position and returning a mutable slice. reserve(&mut self, len: impl TryInto<Length>) -> Result<&mut [u8]>109 fn reserve(&mut self, len: impl TryInto<Length>) -> Result<&mut [u8]> { 110 if self.is_failed() { 111 return Err(ErrorKind::Failed.at(self.position)); 112 } 113 114 let len = len 115 .try_into() 116 .or_else(|_| self.error(ErrorKind::Overflow))?; 117 118 let end = (self.position + len).or_else(|e| self.error(e.kind()))?; 119 let slice = self 120 .bytes 121 .get_mut(self.position.try_into()?..end.try_into()?) 122 .ok_or_else(|| ErrorKind::Overlength.at(end))?; 123 124 self.position = end; 125 Ok(slice) 126 } 127 } 128 129 impl<'a> Writer for SliceWriter<'a> { write(&mut self, slice: &[u8]) -> Result<()>130 fn write(&mut self, slice: &[u8]) -> Result<()> { 131 self.reserve(slice.len())?.copy_from_slice(slice); 132 Ok(()) 133 } 134 } 135 136 #[cfg(test)] 137 mod tests { 138 use super::SliceWriter; 139 use crate::{Encode, ErrorKind, Length}; 140 141 #[test] overlength_message()142 fn overlength_message() { 143 let mut buffer = []; 144 let mut writer = SliceWriter::new(&mut buffer); 145 let err = false.encode(&mut writer).err().unwrap(); 146 assert_eq!(err.kind(), ErrorKind::Overlength); 147 assert_eq!(err.position(), Some(Length::ONE)); 148 } 149 } 150