Coverage Report

Created: 2025-07-12 06:15

/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
}