/rust/registry/src/index.crates.io-6f17d22bba15001f/der-0.7.10/src/writer/slice.rs
Line | Count | Source (jump to first uncovered line) |
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. |
23 | 0 | pub fn new(bytes: &'a mut [u8]) -> Self { |
24 | 0 | Self { |
25 | 0 | bytes, |
26 | 0 | failed: false, |
27 | 0 | position: Length::ZERO, |
28 | 0 | } |
29 | 0 | } |
30 | | |
31 | | /// Encode a value which impls the [`Encode`] trait. |
32 | 0 | pub fn encode<T: Encode>(&mut self, encodable: &T) -> Result<()> { |
33 | 0 | if self.is_failed() { |
34 | 0 | self.error(ErrorKind::Failed)? |
35 | 0 | } |
36 | | |
37 | 0 | encodable.encode(self).map_err(|e| { |
38 | 0 | self.failed = true; |
39 | 0 | e.nested(self.position) |
40 | 0 | }) |
41 | 0 | } |
42 | | |
43 | | /// Return an error with the given [`ErrorKind`], annotating it with |
44 | | /// context about where the error occurred. |
45 | 0 | pub fn error<T>(&mut self, kind: ErrorKind) -> Result<T> { |
46 | 0 | self.failed = true; |
47 | 0 | Err(kind.at(self.position)) |
48 | 0 | } Unexecuted instantiation: <der::writer::slice::SliceWriter>::error::<der::length::Length> Unexecuted instantiation: <der::writer::slice::SliceWriter>::error::<()> |
49 | | |
50 | | /// Did the decoding operation fail due to an error? |
51 | 0 | pub fn is_failed(&self) -> bool { |
52 | 0 | self.failed |
53 | 0 | } |
54 | | |
55 | | /// Finish encoding to the buffer, returning a slice containing the data |
56 | | /// written to the buffer. |
57 | 0 | pub fn finish(self) -> Result<&'a [u8]> { |
58 | 0 | let position = self.position; |
59 | 0 |
|
60 | 0 | if self.is_failed() { |
61 | 0 | return Err(ErrorKind::Failed.at(position)); |
62 | 0 | } |
63 | 0 |
|
64 | 0 | self.bytes |
65 | 0 | .get(..usize::try_from(position)?) |
66 | 0 | .ok_or_else(|| ErrorKind::Overlength.at(position)) |
67 | 0 | } |
68 | | |
69 | | /// Encode a `CONTEXT-SPECIFIC` field with the provided tag number and mode. |
70 | 0 | pub fn context_specific<T>( |
71 | 0 | &mut self, |
72 | 0 | tag_number: TagNumber, |
73 | 0 | tag_mode: TagMode, |
74 | 0 | value: &T, |
75 | 0 | ) -> Result<()> |
76 | 0 | where |
77 | 0 | T: EncodeValue + Tagged, |
78 | 0 | { |
79 | 0 | ContextSpecificRef { |
80 | 0 | tag_number, |
81 | 0 | tag_mode, |
82 | 0 | value, |
83 | 0 | } |
84 | 0 | .encode(self) |
85 | 0 | } |
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. |
91 | 0 | pub fn sequence<F>(&mut self, length: Length, f: F) -> Result<()> |
92 | 0 | where |
93 | 0 | F: FnOnce(&mut SliceWriter<'_>) -> Result<()>, |
94 | 0 | { |
95 | 0 | Header::new(Tag::Sequence, length).and_then(|header| header.encode(self))?; |
96 | | |
97 | 0 | let mut nested_encoder = SliceWriter::new(self.reserve(length)?); |
98 | 0 | f(&mut nested_encoder)?; |
99 | | |
100 | 0 | if nested_encoder.finish()?.len() == usize::try_from(length)? { |
101 | 0 | Ok(()) |
102 | | } else { |
103 | 0 | self.error(ErrorKind::Length { tag: Tag::Sequence }) |
104 | | } |
105 | 0 | } |
106 | | |
107 | | /// Reserve a portion of the internal buffer, updating the internal cursor |
108 | | /// position and returning a mutable slice. |
109 | 0 | fn reserve(&mut self, len: impl TryInto<Length>) -> Result<&mut [u8]> { |
110 | 0 | if self.is_failed() { |
111 | 0 | return Err(ErrorKind::Failed.at(self.position)); |
112 | 0 | } |
113 | | |
114 | 0 | let len = len |
115 | 0 | .try_into() |
116 | 0 | .or_else(|_| self.error(ErrorKind::Overflow))?; |
117 | | |
118 | 0 | let end = (self.position + len).or_else(|e| self.error(e.kind()))?; |
119 | 0 | let slice = self |
120 | 0 | .bytes |
121 | 0 | .get_mut(self.position.try_into()?..end.try_into()?) |
122 | 0 | .ok_or_else(|| ErrorKind::Overlength.at(end))?; |
123 | | |
124 | 0 | self.position = end; |
125 | 0 | Ok(slice) |
126 | 0 | } |
127 | | } |
128 | | |
129 | | impl<'a> Writer for SliceWriter<'a> { |
130 | 0 | fn write(&mut self, slice: &[u8]) -> Result<()> { |
131 | 0 | self.reserve(slice.len())?.copy_from_slice(slice); |
132 | 0 | Ok(()) |
133 | 0 | } |
134 | | } |
135 | | |
136 | | #[cfg(test)] |
137 | | mod tests { |
138 | | use super::SliceWriter; |
139 | | use crate::{Encode, ErrorKind, Length}; |
140 | | |
141 | | #[test] |
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 | | } |