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