xref: /cloud-hypervisor/tpm/src/lib.rs (revision 3ce0fef7fd546467398c914dbc74d8542e45cf6f)
1 // Copyright © 2022, Microsoft Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 #[macro_use]
7 extern crate log;
8 
9 pub mod emulator;
10 pub mod socket;
11 
12 use anyhow::anyhow;
13 use std::convert::TryInto;
14 use thiserror::Error;
15 
16 pub const TPM_CRB_BUFFER_MAX: usize = 3968; // 0x1_000 - 0x80
17 pub const TPM_SUCCESS: u32 = 0x0;
18 
19 /*
20  * Structures required to process Request and Responses of Control commands
21  * used by control channel over UNIX socket interface
22  *
23  * All messages contain big-endian data.
24  *
25  * Reference: https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod
26  */
27 #[derive(Debug, Clone, Copy)]
28 pub enum Commands {
29     CmdGetCapability = 1,
30     CmdInit,
31     CmdShutdown,
32     CmdGetTpmEstablished,
33     CmdSetLocality,
34     CmdHashStart,
35     CmdHashData,
36     CmdHashEnd,
37     CmdCancelTpmCmd,
38     CmdStoreVolatile,
39     CmdResetTpmEstablished,
40     CmdGetStateBlob,
41     CmdSetStateBlob,
42     CmdStop,
43     CmdGetConfig,
44     CmdSetDatafd,
45     CmdSetBufferSize,
46 }
47 
48 #[derive(Error, Debug)]
49 pub enum Error {
50     #[error("Failed converting buf to PTM : {0}")]
51     ConvertToPtm(#[source] anyhow::Error),
52 }
53 type Result<T> = anyhow::Result<T, Error>;
54 
55 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
56 pub enum MemberType {
57     Request,
58     Response,
59     Error,
60     Cap,
61 }
62 
63 pub trait Ptm {
64     // Get Member Type
65     fn get_member_type(&self) -> MemberType;
66 
67     // Set Member Type
68     fn set_member_type(&mut self, mem: MemberType);
69 
70     // Convert PTM Request to bytes to be sent to tpm
71     fn ptm_to_request(&self) -> Vec<u8>;
72 
73     // Update PTM from tpm's response
74     fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()>;
75 
76     // Update tpm result
77     fn set_result_code(&mut self, res: u32);
78 
79     fn get_result_code(&self) -> u32;
80 }
81 
82 /*
83  * Every response for a tpm Control Command execution must hold tpm return
84  * code (PtmResult) as its first element.
85  * Based on the type of input Control Command additional data could be
86  * appended to the response.
87  */
88 pub type PtmResult = u32;
89 
90 impl Ptm for PtmResult {
91     fn ptm_to_request(&self) -> Vec<u8> {
92         Vec::new()
93     }
94 
95     fn get_member_type(&self) -> MemberType {
96         MemberType::Response
97     }
98 
99     fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> {
100         let expected_len = 4;
101         let len = buf.len();
102         if len != expected_len {
103             return Err(Error::ConvertToPtm(anyhow!(
104                 "PtmRes buffer is of incorrect length. Got {len} expected {expected_len}."
105             )));
106         }
107 
108         *self = u32::from_be_bytes(buf[..].try_into().unwrap());
109         Ok(())
110     }
111 
112     fn set_member_type(&mut self, _mem: MemberType) {}
113 
114     fn set_result_code(&mut self, res: u32) {
115         *self = res;
116     }
117 
118     fn get_result_code(&self) -> u32 {
119         *self
120     }
121 }
122 
123 /* GET_CAPABILITY Response */
124 pub type PtmCap = u64;
125 impl Ptm for PtmCap {
126     fn ptm_to_request(&self) -> Vec<u8> {
127         // tpm's GetCapability call doesn't need any supporting message
128         // return an empty Buffer
129         Vec::new()
130     }
131 
132     fn get_member_type(&self) -> MemberType {
133         MemberType::Cap
134     }
135 
136     fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> {
137         let expected_len = 8;
138         let len = buf.len();
139         if len != expected_len {
140             return Err(Error::ConvertToPtm(anyhow!(
141                 "Response for GetCapability cmd is of incorrect length. Got {len} expected {expected_len}."
142             )));
143         }
144         *self = u64::from_be_bytes(buf[..].try_into().unwrap());
145         Ok(())
146     }
147 
148     fn set_member_type(&mut self, _mem: MemberType) {}
149 
150     fn set_result_code(&mut self, _res: u32) {}
151 
152     fn get_result_code(&self) -> u32 {
153         ((*self) >> 32) as u32
154     }
155 }
156 
157 /* GET_TPMESTABLISHED Response */
158 #[derive(Debug)]
159 pub struct PtmEstResp {
160     pub bit: u8,
161 }
162 
163 #[derive(Debug)]
164 pub struct PtmEst {
165     member: MemberType,
166     pub resp: PtmEstResp,
167     pub result_code: PtmResult,
168 }
169 
170 impl PtmEst {
171     pub fn new() -> Self {
172         Self {
173             member: MemberType::Response,
174             result_code: 0,
175             resp: PtmEstResp { bit: 0 },
176         }
177     }
178 }
179 
180 impl Default for PtmEst {
181     fn default() -> Self {
182         Self::new()
183     }
184 }
185 
186 impl Ptm for PtmEst {
187     fn ptm_to_request(&self) -> Vec<u8> {
188         // tpm's GetTpmEstablished call doesn't need any supporting message
189         // return an empty Buffer
190         Vec::new()
191     }
192 
193     fn get_member_type(&self) -> MemberType {
194         self.member
195     }
196 
197     fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> {
198         let expected_len = 8;
199         let len = buf.len();
200         if len != expected_len {
201             return Err(Error::ConvertToPtm(anyhow!(
202                 "Response for GetTpmEstablished cmd is of incorrect length. Got {len} expected {expected_len}."
203             )));
204         }
205         self.set_result_code(u32::from_be_bytes(buf[..4].try_into().unwrap()));
206         self.resp.bit = buf[4];
207         Ok(())
208     }
209 
210     fn set_member_type(&mut self, _mem: MemberType) {}
211 
212     fn set_result_code(&mut self, res: u32) {
213         self.result_code = res
214     }
215 
216     fn get_result_code(&self) -> u32 {
217         self.result_code
218     }
219 }
220 
221 /* INIT Response */
222 
223 #[derive(Debug)]
224 pub struct PtmInit {
225     pub member: MemberType,
226     /* request */
227     pub init_flags: u32,
228     /* response */
229     pub result_code: PtmResult,
230 }
231 
232 impl Default for PtmInit {
233     fn default() -> Self {
234         Self::new()
235     }
236 }
237 
238 impl PtmInit {
239     pub fn new() -> Self {
240         Self {
241             member: MemberType::Request,
242             init_flags: 0,
243             result_code: 0,
244         }
245     }
246 }
247 
248 impl Ptm for PtmInit {
249     fn ptm_to_request(&self) -> Vec<u8> {
250         let mut buf: Vec<u8> = Vec::<u8>::new();
251         buf.extend_from_slice(&self.init_flags.to_be_bytes());
252         buf
253     }
254 
255     fn get_member_type(&self) -> MemberType {
256         self.member
257     }
258 
259     fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> {
260         let expected_len = 4;
261         let len = buf.len();
262         if len != expected_len {
263             return Err(Error::ConvertToPtm(anyhow!(
264                 "Response for Init cmd is of incorrect length. Got {len} expected {expected_len}."
265             )));
266         }
267         self.set_member_type(MemberType::Response);
268         self.set_result_code(u32::from_be_bytes(buf[..].try_into().unwrap()));
269         Ok(())
270     }
271 
272     fn set_member_type(&mut self, mem: MemberType) {
273         self.member = mem
274     }
275 
276     fn set_result_code(&mut self, res: u32) {
277         self.result_code = res
278     }
279 
280     fn get_result_code(&self) -> u32 {
281         self.result_code
282     }
283 }
284 
285 /*
286  * PTM_SET_BUFFERSIZE: Set the buffer size to be used by the tpm.
287  * A 0 on input queries for the current buffer size. Any other
288  * number will try to set the buffer size. The returned number is
289  * the buffer size that will be used, which can be larger than the
290  * requested one, if it was below the minimum, or smaller than the
291  * requested one, if it was above the maximum.
292  *
293  * SET_BUFFERSIZE Response
294  */
295 #[derive(Debug)]
296 pub struct PtmSBSReq {
297     buffersize: u32,
298 }
299 
300 #[derive(Debug)]
301 pub struct PtmSBSResp {
302     bufsize: u32,
303     minsize: u32,
304     maxsize: u32,
305 }
306 
307 #[derive(Debug)]
308 pub struct PtmSetBufferSize {
309     pub mem: MemberType,
310     /* request */
311     pub req: PtmSBSReq,
312     /* response */
313     pub resp: PtmSBSResp,
314     pub result_code: PtmResult,
315 }
316 
317 impl PtmSetBufferSize {
318     pub fn new(req_buffsize: u32) -> Self {
319         Self {
320             mem: MemberType::Request,
321             req: PtmSBSReq {
322                 buffersize: req_buffsize,
323             },
324             resp: PtmSBSResp {
325                 bufsize: 0,
326                 minsize: 0,
327                 maxsize: 0,
328             },
329             result_code: 0,
330         }
331     }
332     pub fn get_bufsize(&self) -> u32 {
333         self.resp.bufsize
334     }
335 }
336 
337 impl Ptm for PtmSetBufferSize {
338     fn ptm_to_request(&self) -> Vec<u8> {
339         let mut buf: Vec<u8> = Vec::<u8>::new();
340         buf.extend_from_slice(&self.req.buffersize.to_be_bytes());
341         buf
342     }
343 
344     fn get_member_type(&self) -> MemberType {
345         self.mem
346     }
347 
348     fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> {
349         let expected_len = 16;
350         let len = buf.len();
351         if len != expected_len {
352             return Err(Error::ConvertToPtm(anyhow!(
353                 "Response for CmdSetBufferSize cmd is of incorrect length. Got {len} expected {expected_len}."
354             )));
355         }
356         self.set_member_type(MemberType::Response);
357         self.set_result_code(u32::from_be_bytes(buf[0..4].try_into().unwrap()));
358 
359         let bufsize = &buf[4..8];
360         self.resp.bufsize = u32::from_be_bytes(bufsize.try_into().unwrap());
361 
362         let minsize = &buf[8..12];
363         self.resp.minsize = u32::from_be_bytes(minsize.try_into().unwrap());
364 
365         let maxsize = &buf[12..16];
366         self.resp.maxsize = u32::from_be_bytes(maxsize.try_into().unwrap());
367 
368         Ok(())
369     }
370 
371     fn set_member_type(&mut self, mem: MemberType) {
372         self.mem = mem
373     }
374 
375     fn set_result_code(&mut self, res: u32) {
376         self.result_code = res
377     }
378 
379     fn get_result_code(&self) -> u32 {
380         self.result_code
381     }
382 }
383 
384 #[cfg(test)]
385 mod tests {
386     use super::*;
387     #[test]
388     fn test_ptmresult() -> Result<()> {
389         let buf: &[u8] = &[0, 0, 0, 1];
390         let mut result_code: PtmResult = 0;
391         result_code.update_ptm_with_response(buf)?;
392         assert_eq!(result_code.get_result_code(), 0x1);
393         Ok(())
394     }
395     #[test]
396     fn test_ptmcap() -> Result<()> {
397         let mut cap: PtmCap = 0x0;
398         let buf: &[u8] = &[0, 0, 0, 0xE, 0, 0, 0xFF, 0xFF];
399         cap.update_ptm_with_response(buf)?;
400         assert_eq!(cap.get_result_code(), 0xE);
401         Ok(())
402     }
403     #[test]
404     fn test_ptmest() -> Result<()> {
405         let mut est: PtmEst = PtmEst::new();
406         let buf: &[u8] = &[0, 0, 0xE, 0, 0xC, 0, 1, 1];
407         est.update_ptm_with_response(buf)?;
408         assert_eq!(est.get_result_code(), 0xE00);
409         assert_eq!(est.resp.bit, 0xC);
410         Ok(())
411     }
412     #[test]
413     /*PtmInit Testing */
414     fn test_ptminit() -> Result<()> {
415         let mut init: PtmInit = PtmInit::new();
416         init.init_flags = 0x1;
417         let buf = init.ptm_to_request();
418         assert_eq!(buf, [0x0, 0x0, 0x0, 0x1]);
419         let response_buf: &[u8] = &[0, 0, 0xE, 0];
420         init.update_ptm_with_response(response_buf)?;
421         assert_eq!(init.get_result_code(), 0xE00);
422         Ok(())
423     }
424     #[test]
425     /* PtmSetBufferSize Testing */
426     fn test_ptmsetbuffersize() -> Result<()> {
427         let mut psbs: PtmSetBufferSize = PtmSetBufferSize::new(1024);
428         // Member type should be Request after initialization
429         assert_eq!(psbs.get_member_type(), MemberType::Request);
430         let buf: &[u8] = &[
431             0, 0x12, 0x34, 0x56, 0, 0, 0, 0xA, 0, 0, 0, 0xB, 0, 0, 0, 0xC,
432         ];
433         psbs.update_ptm_with_response(buf)?;
434         assert_eq!(psbs.get_member_type(), MemberType::Response);
435         assert_eq!(psbs.get_result_code(), 0x123456);
436         assert_eq!(psbs.resp.bufsize, 0xA);
437         assert_eq!(psbs.resp.minsize, 0xB);
438         assert_eq!(psbs.resp.maxsize, 0xC);
439         Ok(())
440     }
441 }
442