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 byteorder::{BigEndian, ReadBytesExt}; 14 use std::convert::TryInto; 15 use thiserror::Error; 16 17 pub const TPM_CRB_BUFFER_MAX: usize = 3968; // 0x1_000 - 0x80 18 pub const TPM_SUCCESS: u32 = 0x0; 19 20 /* 21 * Structures required to process Request and Responses of Control commands 22 * used by control channel over UNIX socket interface 23 * 24 * All messages contain big-endian data. 25 * 26 * Reference: https://github.com/stefanberger/swtpm/blob/master/man/man3/swtpm_ioctls.pod 27 */ 28 #[derive(Debug, Clone, Copy)] 29 pub enum Commands { 30 CmdGetCapability = 1, 31 CmdInit, 32 CmdShutdown, 33 CmdGetTpmEstablished, 34 CmdSetLocality, 35 CmdHashStart, 36 CmdHashData, 37 CmdHashEnd, 38 CmdCancelTpmCmd, 39 CmdStoreVolatile, 40 CmdResetTpmEstablished, 41 CmdGetStateBlob, 42 CmdSetStateBlob, 43 CmdStop, 44 CmdGetConfig, 45 CmdSetDatafd, 46 CmdSetBufferSize, 47 } 48 49 #[derive(Error, Debug)] 50 pub enum Error { 51 #[error("Failed converting buf to PTM : {0}")] 52 ConvertToPtm(#[source] anyhow::Error), 53 } 54 type Result<T> = anyhow::Result<T, Error>; 55 56 #[derive(PartialEq, Eq, Copy, Clone, Debug)] 57 pub enum MemberType { 58 Request, 59 Response, 60 Error, 61 Cap, 62 } 63 64 pub trait Ptm { 65 // Get Member Type 66 fn get_member_type(&self) -> MemberType; 67 68 // Set Member Type 69 fn set_member_type(&mut self, mem: MemberType); 70 71 // Convert PTM Request to bytes to be sent to tpm 72 fn ptm_to_request(&self) -> Vec<u8>; 73 74 // Update PTM from tpm's reponse 75 fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()>; 76 77 // Update tpm result 78 fn set_result_code(&mut self, res: u32); 79 80 fn get_result_code(&self) -> u32; 81 } 82 83 /* 84 * Every response for a tpm Control Command execution must hold tpm return 85 * code (PtmResult) as its first element. 86 * Based on the type of input Control Command additional data could be 87 * appended to the response. 88 */ 89 pub type PtmResult = u32; 90 91 impl Ptm for PtmResult { 92 fn ptm_to_request(&self) -> Vec<u8> { 93 let buf: Vec<u8> = Vec::<u8>::new(); 94 buf 95 } 96 97 fn get_member_type(&self) -> MemberType { 98 MemberType::Response 99 } 100 101 fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> { 102 if buf.len() < 4 { 103 return Err(Error::ConvertToPtm(anyhow!( 104 "PtmRes buffer is of insufficient length. Buffer length should be atleast 4" 105 ))); 106 } 107 108 *self = u32::from_be_bytes(buf[0..4].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 let buf: Vec<u8> = Vec::<u8>::new(); 130 buf 131 } 132 133 fn get_member_type(&self) -> MemberType { 134 MemberType::Cap 135 } 136 137 fn update_ptm_with_response(&mut self, mut buf: &[u8]) -> Result<()> { 138 let buf_len = buf.len(); 139 if buf_len != 8 { 140 return Err(Error::ConvertToPtm(anyhow!( 141 "Response for GetCapability cmd is of incorrect length: {:?}. Response buffer should be 8 bytes long", 142 buf_len))); 143 } 144 *self = buf.read_u64::<BigEndian>().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 Reponse */ 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 let buf: Vec<u8> = Vec::<u8>::new(); 191 buf 192 } 193 194 fn get_member_type(&self) -> MemberType { 195 self.member 196 } 197 198 fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> { 199 if buf.len() < 5 { 200 return Err(Error::ConvertToPtm(anyhow!( 201 "Response for GetTpmEstablished cmd is of incorrect length. Response buffer should be 5 bytes long" 202 ))); 203 } 204 let mut res = &buf[0..4]; 205 self.set_result_code(res.read_u32::<BigEndian>().unwrap()); 206 let bit = &buf[4]; 207 self.resp.bit = *bit; 208 Ok(()) 209 } 210 211 fn set_member_type(&mut self, _mem: MemberType) {} 212 213 fn set_result_code(&mut self, res: u32) { 214 self.result_code = res 215 } 216 217 fn get_result_code(&self) -> u32 { 218 self.result_code 219 } 220 } 221 222 /* INIT Response */ 223 224 #[derive(Debug)] 225 pub struct PtmInit { 226 pub member: MemberType, 227 /* request */ 228 pub init_flags: u32, 229 /* response */ 230 pub result_code: PtmResult, 231 } 232 233 impl Default for PtmInit { 234 fn default() -> Self { 235 Self::new() 236 } 237 } 238 239 impl PtmInit { 240 pub fn new() -> Self { 241 Self { 242 member: MemberType::Request, 243 init_flags: 0, 244 result_code: 0, 245 } 246 } 247 } 248 249 impl Ptm for PtmInit { 250 fn ptm_to_request(&self) -> Vec<u8> { 251 let mut buf: Vec<u8> = Vec::<u8>::new(); 252 buf.extend_from_slice(&self.init_flags.to_be_bytes()); 253 buf 254 } 255 256 fn get_member_type(&self) -> MemberType { 257 self.member 258 } 259 260 fn update_ptm_with_response(&mut self, buf: &[u8]) -> Result<()> { 261 if buf.len() != 4 { 262 return Err(Error::ConvertToPtm(anyhow!( 263 "Response for Init cmd is of incorrect length. Response buffer should be 4 bytes long" 264 ))); 265 } 266 self.set_member_type(MemberType::Response); 267 let mut res = &buf[0..4]; 268 self.set_result_code(res.read_u32::<BigEndian>().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 if buf.len() != 16 { 350 return Err(Error::ConvertToPtm(anyhow!( 351 "Response for CmdSetBufferSize cmd is of incorrect length. Response buffer should be 16 bytes long" 352 ))); 353 } 354 self.set_member_type(MemberType::Response); 355 let mut res = &buf[0..4]; 356 self.set_result_code(res.read_u32::<BigEndian>().unwrap()); 357 358 let mut bufsize = &buf[4..8]; 359 self.resp.bufsize = bufsize.read_u32::<BigEndian>().unwrap(); 360 361 let mut minsize = &buf[8..12]; 362 self.resp.minsize = minsize.read_u32::<BigEndian>().unwrap(); 363 364 let mut maxsize = &buf[12..16]; 365 self.resp.maxsize = maxsize.read_u32::<BigEndian>().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