uds_protocol/services/
security_access.rs

1use crate::{
2    Error, NegativeResponseCode, SecurityAccessType, SingleValueWireFormat,
3    SuppressablePositiveResponse, WireFormat,
4};
5use byteorder::{ReadBytesExt, WriteBytesExt};
6use std::io::{Read, Write};
7
8/// List of allowed [`NegativeResponseCode`] variants for the `SecurityAccess` service
9const SECURITY_ACCESS_NEGATIVE_RESPONSE_CODES: [NegativeResponseCode; 8] = [
10    NegativeResponseCode::SubFunctionNotSupported,
11    NegativeResponseCode::IncorrectMessageLengthOrInvalidFormat,
12    NegativeResponseCode::ConditionsNotCorrect,
13    NegativeResponseCode::RequestSequenceError,
14    NegativeResponseCode::RequestOutOfRange,
15    NegativeResponseCode::InvalidKey,
16    NegativeResponseCode::ExceedNumberOfAttempts,
17    NegativeResponseCode::RequiredTimeDelayNotExpired,
18];
19
20/// Client request to access a security level
21///
22/// This service supports two primary types of request:
23///
24/// ## Request Seed
25///
26/// When requesting a seed, the request data represents implementation defined
27/// `SecurityAccessDataRecord` values.
28/// This data is optional, and its use is implementation defined.
29/// Suppressing a positive response to this request is not supported.
30///
31/// ## Send Key
32///
33/// When sending a key, the request data represents the key to be sent.
34/// After receiving a seed,
35/// the client must calculate the corresponding key and send it to the server.
36/// The server will then validate the key and respond with a positive or negative response.
37/// Successful verification of the key will result in the server unlocking the requested security level.
38/// Suppressing a positive response to this request is allowed.
39#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
40#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
41#[derive(Clone, Debug, Eq, PartialEq)]
42pub struct SecurityAccessRequest {
43    access_type: SuppressablePositiveResponse<SecurityAccessType>,
44    request_data: Vec<u8>,
45}
46
47impl SecurityAccessRequest {
48    /// Create a new '`SecurityAccessRequest`'
49    pub(crate) fn new(
50        suppress_positive_response: bool,
51        access_type: SecurityAccessType,
52        request_data: Vec<u8>,
53    ) -> Self {
54        Self {
55            access_type: SuppressablePositiveResponse::new(suppress_positive_response, access_type),
56            request_data,
57        }
58    }
59
60    /// Getter for whether a positive response should be suppressed
61    #[must_use]
62    pub fn suppress_positive_response(&self) -> bool {
63        self.access_type.suppress_positive_response()
64    }
65
66    /// Getter for the requested [`SecurityAccessType`]
67    #[must_use]
68    pub fn access_type(&self) -> SecurityAccessType {
69        self.access_type.value()
70    }
71
72    /// Getter for the request data
73    #[must_use]
74    pub fn request_data(&self) -> &[u8] {
75        &self.request_data
76    }
77
78    /// Get the allowed [`NegativeResponseCode`] variants for this request
79    #[must_use]
80    pub fn allowed_nack_codes() -> &'static [NegativeResponseCode] {
81        &SECURITY_ACCESS_NEGATIVE_RESPONSE_CODES
82    }
83}
84
85impl WireFormat for SecurityAccessRequest {
86    /// Deserialization function to read a [`SecurityAccessRequest`] from a `Reader`
87    fn decode<T: std::io::Read>(reader: &mut T) -> Result<Option<Self>, Error> {
88        let access_type = SuppressablePositiveResponse::try_from(reader.read_u8()?)?;
89        let mut request_data: Vec<u8> = Vec::new();
90        _ = reader.read_to_end(&mut request_data)?;
91        Ok(Some(Self {
92            access_type,
93            request_data,
94        }))
95    }
96
97    fn required_size(&self) -> usize {
98        1 + self.request_data().len()
99    }
100
101    /// Serialization function to write a [`SecurityAccessRequest`] to a `Writer`
102    fn encode<T: std::io::Write>(&self, writer: &mut T) -> Result<usize, Error> {
103        writer.write_u8(u8::from(self.access_type))?;
104        writer.write_all(&self.request_data)?;
105        Ok(self.required_size())
106    }
107
108    fn is_positive_response_suppressed(&self) -> bool {
109        self.suppress_positive_response()
110    }
111}
112
113impl SingleValueWireFormat for SecurityAccessRequest {}
114
115/// Response to `SecurityAccessRequest`
116///
117/// ## Request Seed
118///
119/// When responding to a seed request, the `security_seed` field shall contain the seed value.
120///
121/// ## Send Key
122///
123/// The positive response to a `SendKey` request shall not have any data in the security seed field.
124#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
125#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
126#[derive(Clone, Debug, Eq, PartialEq)]
127#[non_exhaustive]
128pub struct SecurityAccessResponse {
129    pub access_type: SecurityAccessType,
130    pub security_seed: Vec<u8>,
131}
132
133impl SecurityAccessResponse {
134    /// Create a new '`SecurityAccessResponse`'
135    pub(crate) fn new(access_type: SecurityAccessType, security_seed: Vec<u8>) -> Self {
136        Self {
137            access_type,
138            security_seed,
139        }
140    }
141}
142
143impl WireFormat for SecurityAccessResponse {
144    /// Deserialization function to read a `SecurityAccessResponse` from a [`Reader`](std::io::Read)
145    fn decode<T: Read>(reader: &mut T) -> Result<Option<Self>, Error> {
146        let access_type = SecurityAccessType::try_from(reader.read_u8()?)?;
147        let mut security_seed = Vec::new();
148        let _ = reader.read_to_end(&mut security_seed)?;
149        Ok(Some(Self {
150            access_type,
151            security_seed,
152        }))
153    }
154
155    fn required_size(&self) -> usize {
156        1 + self.security_seed.len()
157    }
158
159    /// Serialization function to write a `SecurityAccessResponse` to a [`Writer`](std::io::Write)
160    fn encode<T: Write>(&self, writer: &mut T) -> Result<usize, Error> {
161        writer.write_u8(u8::from(self.access_type))?;
162        writer.write_all(&self.security_seed)?;
163        Ok(self.required_size())
164    }
165}
166
167impl SingleValueWireFormat for SecurityAccessResponse {}
168
169#[cfg(test)]
170mod request {
171    use super::*;
172
173    #[test]
174    fn request_seed() {
175        let bytes: [u8; 6] = [
176            0x01, // aka SecurityAccessType::RequestSeed(0x01)
177            0x00, 0x01, 0x02, 0x03, 0x04, // fake data
178        ];
179        let req = SecurityAccessRequest::decode_single_value(&mut bytes.as_slice()).unwrap();
180
181        assert_eq!(
182            req.access_type,
183            SuppressablePositiveResponse::new(false, SecurityAccessType::RequestSeed(0x01))
184        );
185
186        let mut buf = Vec::new();
187        let written = req.encode(&mut buf).unwrap();
188        assert_eq!(written, bytes.len());
189        assert_eq!(written, req.required_size());
190    }
191}
192
193#[cfg(test)]
194mod response {
195    use super::*;
196
197    #[test]
198    fn response_send() {
199        let bytes: [u8; 6] = [
200            0x02, // aka SecurityAccessType::SendKey(0x02)
201            0x00, 0x01, 0x02, 0x03, 0x04, // fake data
202        ];
203        let resp = SecurityAccessResponse::decode_single_value(&mut bytes.as_slice()).unwrap();
204
205        assert_eq!(resp.access_type, SecurityAccessType::SendKey(0x02));
206        assert_eq!(resp.security_seed, vec![0x00, 0x01, 0x02, 0x03, 0x04]);
207
208        let mut buf = Vec::new();
209        let written = resp.encode(&mut buf).unwrap();
210        assert_eq!(written, bytes.len());
211        assert_eq!(written, resp.required_size());
212    }
213}