1#![recursion_limit = "1024"]
10
11#[macro_use]
12extern crate enum_primitive_derive;
13#[macro_use]
14extern crate error_chain;
15#[macro_use]
16extern crate log;
17extern crate num_traits;
18extern crate try_from;
19
20mod errors;
21pub mod utils;
22
23#[allow(non_snake_case, non_camel_case_types, dead_code)]
24#[allow(non_upper_case_globals, improper_ctypes)]
25mod sys {
26 use std::default::Default;
27 use std::mem;
28 use std::ptr;
29 use try_from::TryFrom;
30
31 include!("bindings.rs");
32
33 pub const TSS2_ERROR_LEVEL_MASK: TSS2_RC = 0xFF << TSS2_RC_LEVEL_SHIFT;
35 pub const TSS2_TPM_ERROR_LEVEL: TSS2_RC = 0 << TSS2_RC_LEVEL_SHIFT;
36 pub const TSS2_APP_ERROR_LEVEL: TSS2_RC = 5 << TSS2_RC_LEVEL_SHIFT;
37 pub const TSS2_FEATURE_ERROR_LEVEL: TSS2_RC = 6 << TSS2_RC_LEVEL_SHIFT;
38 pub const TSS2_ESAPI_ERROR_LEVEL: TSS2_RC = 7 << TSS2_RC_LEVEL_SHIFT;
39 pub const TSS2_SYS_ERROR_LEVEL: TSS2_RC = 8 << TSS2_RC_LEVEL_SHIFT;
40 pub const TSS2_SYS_PART2_ERROR_LEVEL: TSS2_RC = 9 << TSS2_RC_LEVEL_SHIFT;
41 pub const TSS2_TCTI_ERROR_LEVEL: TSS2_RC = 10 << TSS2_RC_LEVEL_SHIFT;
42 pub const TSS2_RESMGRTPM_ERROR_LEVEL: TSS2_RC = 11 << TSS2_RC_LEVEL_SHIFT;
43 pub const TSS2_RESMGR_ERROR_LEVEL: TSS2_RC = 12 << TSS2_RC_LEVEL_SHIFT;
44 pub const TSS2_DRIVER_ERROR_LEVEL: TSS2_RC = 13 << TSS2_RC_LEVEL_SHIFT;
45
46 pub const MAX_TPM_PROPERTIES: UINT32 = 127;
55
56 macro_rules! tpm2b_new(
61 ($kind:ty) => (
62 impl $kind {
63 pub fn new() -> $kind {
64 let mut field: $kind = Default::default();
65 unsafe {
66 (*field.b.as_mut()).size =
67 (mem::size_of::<$kind>() - mem::size_of::<UINT16>()) as u16;
68 }
69 field
70 }
71 }
72 )
73 );
74
75 tpm2b_new!(TPM2B_NAME);
76 tpm2b_new!(TPM2B_NV_PUBLIC);
77 tpm2b_new!(TPM2B_MAX_NV_BUFFER);
78
79 macro_rules! tpm2b_try_from(
82 ($kind:ty, $lifetime:tt, $from:ty) => (
83 impl<$lifetime> TryFrom<$from> for $kind {
84 type Err = super::Error;
85
86 fn try_from(data: $from) -> Result<$kind, Self::Err> {
87 let max = mem::size_of::<$kind>() - mem::size_of::<UINT16>();
88 ensure!(max >= data.len(),
89 super::ErrorKind::BadSize(format!("supplied data was {} bytes which \
90 is larger than the available {} bytes",
91 data.len(),
92 max)));
93
94 let mut field: $kind = Default::default();
95 unsafe {
96 let mut thing = field.t.as_mut();
97 thing.size = data.len() as u16;
99 ptr::copy(data.as_ptr(), thing.buffer.as_mut_ptr(), data.len());
101 }
102 Ok(field)
103 }
104 }
105 )
106 );
107
108 tpm2b_try_from!(TPM2B_AUTH, 'a, &'a[u8]);
111
112 tpm2b_try_from!(TPM2B_MAX_NV_BUFFER, 'a, &'a[u8]);
114
115 impl TPMS_AUTH_COMMAND {
116 pub fn new() -> Self {
117 TPMS_AUTH_COMMAND { sessionHandle: TPM_RS_PW, ..Default::default() }
119 }
120
121 pub fn password(mut self, passwd: &Option<String>) -> super::Result<Self> {
122 if let &Some(ref pass) = passwd {
123 self.hmac = TPM2B_AUTH::try_from(pass.as_bytes())?;
124 }
125
126 Ok(self)
127 }
128 }
129
130 macro_rules! nv_attrs(
131 ($field:expr, $save:ident, $val:path) => (
132 if $field {
133 $save.bindgen_union_field += $val;
134 }
135 )
136 );
137
138 impl From<super::NvAttributes> for TPMA_NV {
139 fn from(attrs: super::NvAttributes) -> Self {
140 let mut built = TPMA_NV::default();
141
142 nv_attrs!(attrs.ppread, built, TPMA_NV_TPMA_NV_PPREAD);
143 nv_attrs!(attrs.ppwrite, built, TPMA_NV_TPMA_NV_PPWRITE);
144 nv_attrs!(attrs.owner_read, built, TPMA_NV_TPMA_NV_OWNERREAD);
145 nv_attrs!(attrs.owner_write, built, TPMA_NV_TPMA_NV_OWNERWRITE);
146 nv_attrs!(attrs.auth_read, built, TPMA_NV_TPMA_NV_AUTHREAD);
147 nv_attrs!(attrs.auth_write, built, TPMA_NV_TPMA_NV_AUTHWRITE);
148 nv_attrs!(attrs.policy_read, built, TPMA_NV_TPMA_NV_POLICYREAD);
149 nv_attrs!(attrs.policy_write, built, TPMA_NV_TPMA_NV_POLICYWRITE);
150 nv_attrs!(attrs.policy_delete, built, TPMA_NV_TPMA_NV_POLICY_DELETE);
151 nv_attrs!(attrs.read_locked, built, TPMA_NV_TPMA_NV_READLOCKED);
152 nv_attrs!(attrs.write_locked, built, TPMA_NV_TPMA_NV_WRITELOCKED);
153 nv_attrs!(attrs.written, built, TPMA_NV_TPMA_NV_WRITTEN);
154 nv_attrs!(attrs.write_all, built, TPMA_NV_TPMA_NV_WRITEALL);
155 nv_attrs!(attrs.write_define, built, TPMA_NV_TPMA_NV_WRITEDEFINE);
156 nv_attrs!(attrs.read_stclear, built, TPMA_NV_TPMA_NV_READ_STCLEAR);
157 nv_attrs!(attrs.write_stclear, built, TPMA_NV_TPMA_NV_WRITE_STCLEAR);
158 nv_attrs!(attrs.clear_stclear, built, TPMA_NV_TPMA_NV_CLEAR_STCLEAR);
159 nv_attrs!(attrs.global_lock, built, TPMA_NV_TPMA_NV_GLOBALLOCK);
160 nv_attrs!(attrs.no_da, built, TPMA_NV_TPMA_NV_NO_DA);
161 nv_attrs!(attrs.orderly, built, TPMA_NV_TPMA_NV_ORDERLY);
162 nv_attrs!(attrs.platform_create, built, TPMA_NV_TPMA_NV_PLATFORMCREATE);
163
164 built
165 }
166 }
167
168 const TPM_RC_7BIT_ERROR_MASK: TSS2_RC = 0x7f;
170 const TPM_RC_6BIT_ERROR_MASK: TSS2_RC = 0x3f;
171 const TPM_RC_PARAMETER_MASK: TSS2_RC = 0xf00;
172 const TPM_RC_HANDLE_MASK: TSS2_RC = 0x700;
173 const TPM_RC_SESSION_MASK: TSS2_RC = 0x700;
174
175 const TPM_RC_FORMAT_ONE: u8 = 7;
177
178 fn is_bit_set(rc: TSS2_RC, pos: u8) -> bool {
179 ((1 << pos) & rc) > 0
180 }
181
182 pub trait ErrorCodes {
183 fn is_format_one(self) -> bool;
184 fn get_code_fmt1(self) -> Self;
185 fn get_code_ver1(self) -> Self;
186 }
187
188 impl ErrorCodes for TSS2_RC {
189 fn is_format_one(self) -> bool {
190 is_bit_set(self, TPM_RC_FORMAT_ONE)
191 }
192
193 fn get_code_fmt1(self) -> TSS2_RC {
194 (self & TPM_RC_6BIT_ERROR_MASK) + RC_FMT1
195 }
196
197 fn get_code_ver1(self) -> TSS2_RC {
198 (self & TPM_RC_7BIT_ERROR_MASK) + RC_VER1
199 }
200 }
201}
202
203pub use errors::*;
204pub use errors::tpm::ErrorKind as TpmErrorKind;
205use num_traits::{FromPrimitive, ToPrimitive};
206use std::cmp;
207use std::default::Default;
208use std::ffi::{CStr, CString};
209use std::fmt;
210use std::io;
211use std::mem;
212use std::ptr;
213use sys::ErrorCodes;
214use try_from::TryFrom;
215
216fn malloc<T>(size: usize) -> *mut T {
217 let mut alloc: Vec<u8> = Vec::with_capacity(size);
219 let ptr = alloc.as_mut_ptr() as *mut T;
220 mem::forget(alloc);
221 ptr
222}
223
224fn free<T>(mem: *mut T, size: usize) {
225 unsafe { mem::drop(Vec::from_raw_parts(mem, 0, size)) }
226}
227
228macro_rules! tss_tpm_err(
229 ($kind:path) => ( Err(ErrorKind::Tpm($kind).into()) )
230);
231
232macro_rules! tss_tcti_err(
233 ($kind:path) => ( Err(ErrorKind::Tcti($kind).into()) )
234);
235
236fn tss_err(err: sys::TSS2_RC) -> Result<()> {
237 match err {
239 sys::TPM_RC_SUCCESS => Ok(()),
241 val => {
243 match val & sys::TSS2_ERROR_LEVEL_MASK {
244 sys::TSS2_TPM_ERROR_LEVEL |
245 sys::TSS2_SYS_PART2_ERROR_LEVEL => {
246 match val.is_format_one() {
247 true => {
248 match val.get_code_fmt1() {
250 sys::TPM_RC_ASYMMETRIC => {
251 tss_tpm_err!(errors::tpm::ErrorKind::Asymmetric)
252 }
253 sys::TPM_RC_ATTRIBUTES => {
254 tss_tpm_err!(errors::tpm::ErrorKind::Attributes)
255 }
256 sys::TPM_RC_HASH => tss_tpm_err!(errors::tpm::ErrorKind::Hash),
257 sys::TPM_RC_VALUE => tss_tpm_err!(errors::tpm::ErrorKind::Value),
258 sys::TPM_RC_HIERARCHY => {
259 tss_tpm_err!(errors::tpm::ErrorKind::Hierarchy)
260 }
261 sys::TPM_RC_KEY_SIZE => {
262 tss_tpm_err!(errors::tpm::ErrorKind::KeySize)
263 }
264 sys::TPM_RC_MGF => tss_tpm_err!(errors::tpm::ErrorKind::Mgf),
265 sys::TPM_RC_MODE => tss_tpm_err!(errors::tpm::ErrorKind::Mode),
266 sys::TPM_RC_TYPE => tss_tpm_err!(errors::tpm::ErrorKind::Type),
267 sys::TPM_RC_HANDLE => tss_tpm_err!(errors::tpm::ErrorKind::Handle),
268 sys::TPM_RC_KDF => tss_tpm_err!(errors::tpm::ErrorKind::Kdf),
269 sys::TPM_RC_RANGE => tss_tpm_err!(errors::tpm::ErrorKind::Range),
270 sys::TPM_RC_AUTH_FAIL => {
271 tss_tpm_err!(errors::tpm::ErrorKind::AuthFail)
272 }
273 sys::TPM_RC_NONCE => tss_tpm_err!(errors::tpm::ErrorKind::Nonce),
274 sys::TPM_RC_PP => {
275 tss_tpm_err!(errors::tpm::ErrorKind::PhysicalPresence)
276 }
277 sys::TPM_RC_SCHEME => tss_tpm_err!(errors::tpm::ErrorKind::Scheme),
278 sys::TPM_RC_SIZE => tss_tpm_err!(errors::tpm::ErrorKind::Size),
279 sys::TPM_RC_SYMMETRIC => {
280 tss_tpm_err!(errors::tpm::ErrorKind::Symmetric)
281 }
282 sys::TPM_RC_TAG => tss_tpm_err!(errors::tpm::ErrorKind::Tag),
283 sys::TPM_RC_SELECTOR => {
284 tss_tpm_err!(errors::tpm::ErrorKind::Selector)
285 }
286 sys::TPM_RC_INSUFFICIENT => {
287 tss_tpm_err!(errors::tpm::ErrorKind::Insufficient)
288 }
289 sys::TPM_RC_SIGNATURE => {
290 tss_tpm_err!(errors::tpm::ErrorKind::Signature)
291 }
292 sys::TPM_RC_KEY => tss_tpm_err!(errors::tpm::ErrorKind::Key),
293 sys::TPM_RC_POLICY_FAIL => {
294 tss_tpm_err!(errors::tpm::ErrorKind::PolicyFail)
295 }
296 sys::TPM_RC_BAD_AUTH => {
297 tss_tpm_err!(errors::tpm::ErrorKind::BadAuth)
298 }
299 err => {
300 Err(ErrorKind::Tpm(errors::tpm::ErrorKind::FormatOne(err))
301 .into())
302 }
303 }
304 }
305 false => {
306 match val.get_code_ver1() {
308 sys::TPM_RC_INITIALIZE => {
309 tss_tpm_err!(errors::tpm::ErrorKind::Initialize)
310 }
311 sys::TPM_RC_FAILURE => {
312 tss_tpm_err!(errors::tpm::ErrorKind::Failure)
313 }
314 sys::TPM_RC_DISABLED => {
315 tss_tpm_err!(errors::tpm::ErrorKind::Disabled)
316 }
317 sys::TPM_RC_EXCLUSIVE => {
318 tss_tpm_err!(errors::tpm::ErrorKind::Exclusive)
319 }
320 sys::TPM_RC_NV_AUTHORIZATION => {
321 tss_tpm_err!(errors::tpm::ErrorKind::NvAuthorization)
322 }
323 sys::TPM_RC_NV_DEFINED => {
324 tss_tpm_err!(errors::tpm::ErrorKind::NvDefined)
325 }
326 sys::TPM_RC_NV_LOCKED => {
327 tss_tpm_err!(errors::tpm::ErrorKind::NvLocked)
328 }
329 sys::TPM_RC_NV_SPACE => {
330 tss_tpm_err!(errors::tpm::ErrorKind::NvSpace)
331 }
332 sys::TPM_RC_NV_UNAVAILABLE => {
333 tss_tpm_err!(errors::tpm::ErrorKind::NvUnavailable)
334 }
335 sys::TPM_RC_REBOOT => tss_tpm_err!(errors::tpm::ErrorKind::Reboot),
336 err => {
337 Err(ErrorKind::Tpm(errors::tpm::ErrorKind::FormatZero(err))
338 .into())
339 }
340 }
341 }
342 }
343 }
344 sys::TSS2_APP_ERROR_LEVEL => Err(ErrorKind::AppError(err).into()),
345 sys::TSS2_FEATURE_ERROR_LEVEL => Err(ErrorKind::FeatureError(err).into()),
346 sys::TSS2_ESAPI_ERROR_LEVEL => Err(ErrorKind::EsapiError(err).into()),
347 sys::TSS2_TCTI_ERROR_LEVEL |
348 sys::TSS2_SYS_ERROR_LEVEL => {
349 match val & !sys::TSS2_ERROR_LEVEL_MASK {
351 sys::TSS2_BASE_RC_GENERAL_FAILURE => {
352 tss_tcti_err!(errors::tcti::ErrorKind::GenFail)
353 }
354 sys::TSS2_BASE_RC_IO_ERROR => {
355 tss_tcti_err!(errors::tcti::ErrorKind::IoError)
356 }
357 err => {
358 Err(ErrorKind::Tcti(errors::tcti::ErrorKind::NotWrapped(err)).into())
359 }
360 }
361 }
362 sys::TSS2_RESMGRTPM_ERROR_LEVEL => Err(ErrorKind::ResMgrTpmError(err).into()),
363 sys::TSS2_RESMGR_ERROR_LEVEL => Err(ErrorKind::ResMgrError(err).into()),
364 sys::TSS2_DRIVER_ERROR_LEVEL => Err(ErrorKind::DriverError(err).into()),
365 _ => Err(ErrorKind::Unknown(err).into()),
366 }
367 }
368 }
369}
370
371struct CmdAuths {
373 inner: sys::TSS2_SYS_CMD_AUTHS,
374 _ptr: Box<*mut sys::TPMS_AUTH_COMMAND>,
375 _data: Vec<sys::TPMS_AUTH_COMMAND>,
376}
377
378impl CmdAuths {
379 pub fn new(mut cmds: Vec<sys::TPMS_AUTH_COMMAND>) -> Result<Self> {
380 ensure!(cmds.len() <= sys::MAX_SESSION_NUM as usize,
382 ErrorKind::Msg("Too many auth commands supplied".into()));
383
384 let mut cmds_ptr = Box::new(cmds.as_mut_ptr());
385
386 let inner = sys::TSS2_SYS_CMD_AUTHS {
387 cmdAuthsCount: cmds.len() as u8,
388 cmdAuths: &mut *cmds_ptr,
389 };
390
391 Ok(CmdAuths {
392 inner: inner,
393 _ptr: cmds_ptr,
394 _data: cmds,
395 })
396 }
397}
398
399impl From<sys::TPMS_AUTH_COMMAND> for CmdAuths {
400 fn from(cmd: sys::TPMS_AUTH_COMMAND) -> Self {
401 CmdAuths::new(vec![cmd]).unwrap()
402 }
403}
404
405struct RespAuths {
407 inner: sys::TSS2_SYS_RSP_AUTHS,
408 _ptr: Box<*mut sys::TPMS_AUTH_RESPONSE>,
409 _data: Vec<sys::TPMS_AUTH_RESPONSE>,
410}
411
412impl RespAuths {
413 pub fn new(mut resps: Vec<sys::TPMS_AUTH_RESPONSE>) -> Result<Self> {
414 ensure!(resps.len() < u8::max_value() as usize,
415 ErrorKind::Msg("Too many auth responses supplied".into()));
416
417 let mut resps_ptr = Box::new(resps.as_mut_ptr());
418
419 let inner = sys::TSS2_SYS_RSP_AUTHS {
420 rspAuthsCount: resps.len() as u8,
421 rspAuths: &mut *resps_ptr,
422 };
423
424 Ok(RespAuths {
425 inner: inner,
426 _ptr: resps_ptr,
427 _data: resps,
428 })
429 }
430}
431
432impl From<sys::TPMS_AUTH_RESPONSE> for RespAuths {
433 fn from(resp: sys::TPMS_AUTH_RESPONSE) -> Self {
434 RespAuths::new(vec![resp]).unwrap()
435 }
436}
437
438
439#[allow(non_camel_case_types)]
441#[derive(Clone, Copy, Debug, Eq, PartialEq, Primitive)]
442pub enum TpmAlgorithm {
443 RSA = sys::ALG_RSA_VALUE as isize,
444 SHA1 = sys::ALG_SHA1_VALUE as isize,
445 HMAC = sys::ALG_HMAC_VALUE as isize,
446 AES = sys::ALG_AES_VALUE as isize,
447 MGF1 = sys::ALG_MGF1_VALUE as isize,
448 KEYEDHASH = sys::ALG_KEYEDHASH_VALUE as isize,
449 XOR = sys::ALG_XOR_VALUE as isize,
450 SHA256 = sys::ALG_SHA256_VALUE as isize,
451 SHA384 = sys::ALG_SHA384_VALUE as isize,
452 SHA512 = sys::ALG_SHA512_VALUE as isize,
453 NULL = sys::ALG_NULL_VALUE as isize,
454 SM3_256 = sys::ALG_SM3_256_VALUE as isize,
455 SM4 = sys::ALG_SM4_VALUE as isize,
456 RSASSA = sys::ALG_RSASSA_VALUE as isize,
457 RSAES = sys::ALG_RSAES_VALUE as isize,
458 RSAPSS = sys::ALG_RSAPSS_VALUE as isize,
459 OAEP = sys::ALG_OAEP_VALUE as isize,
460 ECDSA = sys::ALG_ECDSA_VALUE as isize,
461 ECDH = sys::ALG_ECDH_VALUE as isize,
462 ECDAA = sys::ALG_ECDAA_VALUE as isize,
463 SM2 = sys::ALG_SM2_VALUE as isize,
464 ECSCHNORR = sys::ALG_ECSCHNORR_VALUE as isize,
465 ECMQV = sys::ALG_ECMQV_VALUE as isize,
466 KDF1_SP800_56A = sys::ALG_KDF1_SP800_56A_VALUE as isize,
467 KDF2 = sys::ALG_KDF2_VALUE as isize,
468 KDF1_SP800_108 = sys::ALG_KDF1_SP800_108_VALUE as isize,
469 ECC = sys::ALG_ECC_VALUE as isize,
470 SYMCIPHER = sys::ALG_SYMCIPHER_VALUE as isize,
471 CAMELLIA = sys::ALG_CAMELLIA_VALUE as isize,
472 CTR = sys::ALG_CTR_VALUE as isize,
473 OFB = sys::ALG_OFB_VALUE as isize,
474 CBC = sys::ALG_CBC_VALUE as isize,
475 CFB = sys::ALG_CFB_VALUE as isize,
476 ECB = sys::ALG_ECB_VALUE as isize,
477}
478
479#[derive(Clone, Debug, Default, Eq, PartialEq)]
480pub struct NvAttributes {
481 pub ppread: bool,
482 pub ppwrite: bool,
483 pub owner_read: bool,
484 pub owner_write: bool,
485 pub auth_read: bool,
486 pub auth_write: bool,
487 pub policy_read: bool,
488 pub policy_write: bool,
489 pub policy_delete: bool,
490 pub read_locked: bool,
491 pub write_locked: bool,
492 pub written: bool,
493 pub write_all: bool,
494 pub write_define: bool,
495 pub read_stclear: bool,
496 pub write_stclear: bool,
497 pub clear_stclear: bool,
498 pub global_lock: bool,
499 pub no_da: bool,
500 pub orderly: bool,
501 pub platform_create: bool,
502}
503
504impl From<sys::TPMA_NV> for NvAttributes {
505 fn from(nv: sys::TPMA_NV) -> Self {
506 let nv_attrs = unsafe { nv.__bindgen_anon_1.as_ref() };
508
509 NvAttributes {
510 ppread: nv_attrs.TPMA_NV_PPREAD() > 0,
511 ppwrite: nv_attrs.TPMA_NV_PPWRITE() > 0,
512 owner_read: nv_attrs.TPMA_NV_OWNERREAD() > 0,
513 owner_write: nv_attrs.TPMA_NV_OWNERWRITE() > 0,
514 auth_read: nv_attrs.TPMA_NV_AUTHREAD() > 0,
515 auth_write: nv_attrs.TPMA_NV_AUTHWRITE() > 0,
516 policy_read: nv_attrs.TPMA_NV_POLICYREAD() > 0,
517 policy_write: nv_attrs.TPMA_NV_POLICYWRITE() > 0,
518 policy_delete: nv_attrs.TPMA_NV_POLICY_DELETE() > 0,
519 read_locked: nv_attrs.TPMA_NV_READLOCKED() > 0,
520 write_locked: nv_attrs.TPMA_NV_WRITELOCKED() > 0,
521 written: nv_attrs.TPMA_NV_WRITTEN() > 0,
522 write_all: nv_attrs.TPMA_NV_WRITEALL() > 0,
523 write_define: nv_attrs.TPMA_NV_WRITEDEFINE() > 0,
524 read_stclear: nv_attrs.TPMA_NV_READ_STCLEAR() > 0,
525 write_stclear: nv_attrs.TPMA_NV_WRITE_STCLEAR() > 0,
526 clear_stclear: nv_attrs.TPMA_NV_CLEAR_STCLEAR() > 0,
527 global_lock: nv_attrs.TPMA_NV_GLOBALLOCK() > 0,
528 no_da: nv_attrs.TPMA_NV_NO_DA() > 0,
529 orderly: nv_attrs.TPMA_NV_ORDERLY() > 0,
530 platform_create: nv_attrs.TPMA_NV_PLATFORMCREATE() > 0,
531 }
532 }
533}
534
535#[derive(Debug)]
536pub struct NvRamArea<'ctx> {
537 pub index: u32,
538 pub size: u16,
539 pub hash: TpmAlgorithm,
540 pub attrs: NvAttributes,
541 ctx: &'ctx Context,
542 pos: u64,
543}
544
545impl<'ctx> NvRamArea<'ctx> {
546 pub fn get(ctx: &Context, index: u32) -> Result<NvRamArea> {
548 let mut nv_name = sys::TPM2B_NAME::new();
549 let mut nv_public = sys::TPM2B_NV_PUBLIC::default();
550
551 trace!("Tss2_Sys_NV_ReadPublic({:?}, {}, 0, buffer, 0, name, 0)",
552 ctx,
553 index);
554 tss_err(unsafe {
555 sys::Tss2_Sys_NV_ReadPublic(ctx.inner,
556 index as sys::TPMI_RH_NV_INDEX,
557 ptr::null(),
558 &mut nv_public,
559 &mut nv_name,
560 ptr::null_mut())
561 })?;
562
563 let nv = unsafe { nv_public.t.as_ref() }.nvPublic;
564
565 let hash = TpmAlgorithm::from_u32(nv.nameAlg as u32)
566 .ok_or_else(|| ErrorKind::Msg("invalid TPM algorithm".into()))?;
567
568 Ok(NvRamArea {
569 index: nv.nvIndex,
570 size: nv.dataSize,
571 hash: hash,
572 attrs: NvAttributes::from(nv.attributes),
573 ctx: ctx,
574 pos: 0,
575 })
576 }
577
578 pub fn define<'a>(ctx: &'ctx Context,
580 index: u32,
581 size: u16,
582 hash: TpmAlgorithm,
583 attrs: NvAttributes,
584 nv_passwd: Option<&'a str>)
585 -> Result<NvRamArea<'ctx>> {
586
587 let mut nv = sys::TPM2B_NV_PUBLIC::new();
588
589 let nvpub = sys::TPMS_NV_PUBLIC {
591 nvIndex: index,
592 nameAlg: hash.to_u16().unwrap(),
593 attributes: attrs.into(),
594 authPolicy: sys::TPM2B_DIGEST::default(),
595 dataSize: size,
596 };
597 unsafe {
598 (*nv.t.as_mut()).nvPublic = nvpub;
599 }
600
601 let cmd = sys::TPMS_AUTH_COMMAND::new().password(&ctx.passwd)?;
603 let session_data = CmdAuths::from(cmd);
605
606 let mut auth = match nv_passwd {
608 Some(pass) => sys::TPM2B_AUTH::try_from(pass.as_bytes())?,
609 None => sys::TPM2B_AUTH::default(),
610 };
611
612 let resp = sys::TPMS_AUTH_RESPONSE::default();
614 let mut session_out = RespAuths::from(resp);
615
616 trace!("Tss2_Sys_NV_DefineSpace({:?}, {:?}, {:?}, NULL index passwd, {:?}, SESSION_OUT)",
617 ctx,
618 ctx.auth_type,
619 session_data.inner,
620 nv);
621 tss_err(unsafe {
622 sys::Tss2_Sys_NV_DefineSpace(ctx.inner,
623 ctx.auth_type.to_u32().unwrap(),
624 &session_data.inner,
625 &mut auth,
626 &mut nv,
627 &mut session_out.inner)
628 })?;
629
630
631
632 Ok(NvRamArea {
633 index: nvpub.nvIndex,
634 size: nvpub.dataSize,
635 hash: hash,
636 attrs: NvAttributes::from(nvpub.attributes),
637 ctx: ctx,
638 pos: 0,
639 })
640 }
641
642 pub fn undefine(self) -> Result<()> {
644 let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.ctx.passwd)?;
646 let session_data = CmdAuths::from(cmd);
648
649 trace!("Tss2_Sys_NV_UndefineSpace({:?}, {:?}, 0x{:08X}, {:?}, NULL)",
650 self.ctx,
651 self.ctx.auth_type,
652 self.index,
653 session_data.inner);
654 tss_err(unsafe {
655 sys::Tss2_Sys_NV_UndefineSpace(self.ctx.inner,
656 self.ctx
657 .auth_type
658 .to_u32()
659 .unwrap(),
660 self.index,
661 &session_data.inner,
662 ptr::null_mut())
663 })
664 }
665
666 pub fn readlock(&self) -> Result<()> {
668 let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.ctx.passwd)?;
670 let session_data = CmdAuths::from(cmd);
672
673 trace!("Tss2_Sys_NV_ReadLock({:?}, {:?}, 0x{:08X}, {:?}, NULL)",
674 self.ctx,
675 self.ctx.auth_type,
676 self.index,
677 session_data.inner);
678 tss_err(unsafe {
679 sys::Tss2_Sys_NV_ReadLock(self.ctx.inner,
680 self.ctx
681 .auth_type
682 .to_u32()
683 .unwrap(),
684 self.index,
685 &session_data.inner,
686 ptr::null_mut())
687 })
688 }
689
690 fn write_chunk(&self,
691 session_data: &CmdAuths,
692 session_out: &mut RespAuths,
693 offset: u16,
694 data: &[u8])
695 -> Result<()> {
696 let mut buf = sys::TPM2B_MAX_NV_BUFFER::try_from(data)?;
697
698 trace!("Tss2_Sys_NV_Write({:?}, {:?}, {}, {:?}, {:?}, {}, SESSION_OUT)",
699 self.ctx,
700 self.ctx.auth_type,
701 self.index,
702 session_data.inner,
703 data,
704 offset);
705 tss_err(unsafe {
706 sys::Tss2_Sys_NV_Write(self.ctx.inner,
707 self.ctx
708 .auth_type
709 .to_u32()
710 .unwrap(),
711 self.index,
712 &session_data.inner,
713 &mut buf,
714 offset,
715 &mut session_out.inner)
716 })
717 }
718
719 fn read_chunk(&self,
720 session_data: &CmdAuths,
721 session_out: &mut RespAuths,
722 offset: u16,
723 read_req: u16)
724 -> Result<sys::TPM2B_MAX_NV_BUFFER> {
725
726 let mut buf = sys::TPM2B_MAX_NV_BUFFER::new();
727
728 let read_size = cmp::min(sys::MAX_NV_BUFFER_SIZE as u16, read_req);
729
730 trace!("Tss2_Sys_NV_Read({:?}, {:?}, {}, {:?}, {}, {}, buf, SESSION_OUT)",
731 self.ctx,
732 self.ctx.auth_type,
733 self.index,
734 session_data.inner,
735 read_size,
736 offset);
737
738 tss_err(unsafe {
739 sys::Tss2_Sys_NV_Read(self.ctx.inner,
740 self.ctx
741 .auth_type
742 .to_u32()
743 .unwrap(),
744 self.index,
745 &session_data.inner,
746 read_size,
747 offset,
748 &mut buf,
749 &mut session_out.inner)
750 })?;
751
752 Ok(buf)
753 }
754}
755
756impl<'ctx> fmt::Display for NvRamArea<'ctx> {
757 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
758 writeln!(f,
759 "NVRAM index : 0x{:08X} ({})",
760 self.index,
761 self.index)?;
762 writeln!(f, "Size : {} (0x{:X})", self.size, self.size)?;
763 writeln!(f,
764 "Hash algo : {:?} (0x{:02X})",
765 self.hash,
766 self.hash as u16)?;
767 writeln!(f, "Auth policy : {}", "FIXME: unknown")?;
768 writeln!(f, "Attributes :")?;
769 writeln!(f, " PPREAD : {}", self.attrs.ppread)?;
770 writeln!(f, " PPWRITE : {}", self.attrs.ppwrite)?;
771 writeln!(f, " OwnerRead : {}", self.attrs.owner_read)?;
772 writeln!(f, " OwnerWrite : {}", self.attrs.owner_write)?;
773 writeln!(f, " AuthRead : {}", self.attrs.auth_read)?;
774 writeln!(f, " AuthWrite : {}", self.attrs.auth_write)?;
775 writeln!(f, " PolicyRead : {}", self.attrs.policy_read)?;
776 writeln!(f, " PolicyWrit : {}", self.attrs.policy_write)?;
777 writeln!(f, " PolicyDelete : {}", self.attrs.policy_write)?;
778 writeln!(f, " ReadLocked : {}", self.attrs.read_locked)?;
779 writeln!(f, " WriteLocked : {}", self.attrs.write_locked)?;
780 writeln!(f, " Written : {}", self.attrs.written)?;
781 writeln!(f, " WriteAll : {}", self.attrs.write_all)?;
782 writeln!(f, " WriteDefine : {}", self.attrs.write_define)?;
783 writeln!(f, " ReadSTClear : {}", self.attrs.read_stclear)?;
784 writeln!(f, " WriteSTClear : {}", self.attrs.write_stclear)?;
785 writeln!(f, " ClearSTClear : {}", self.attrs.clear_stclear)?;
786 writeln!(f, " GlobalLock : {}", self.attrs.global_lock)?;
787 writeln!(f, " NoDA : {}", self.attrs.no_da)?;
788 writeln!(f, " Orderly : {}", self.attrs.orderly)?;
789 writeln!(f, " PlatformCreate : {}", self.attrs.platform_create)?;
790 Ok(())
791 }
792}
793
794impl<'a> io::Write for NvRamArea<'a> {
795 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
796 ensure!((self.pos as usize + buf.len()) <= self.size as usize,
797 io::Error::new(io::ErrorKind::InvalidInput,
798 format!("offset {} + write size {} greater \
799 than NVRAM area size {}",
800 self.pos,
801 buf.len(),
802 self.size)));
803 let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.ctx.passwd)
805 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
806 let session_data = CmdAuths::from(cmd);
808 let mut session_out = RespAuths::from(sys::TPMS_AUTH_RESPONSE::default());
809
810 let chunk_size = sys::MAX_NV_BUFFER_SIZE;
811 for chunk in buf.chunks(chunk_size as usize) {
812 self.write_chunk(&session_data, &mut session_out, self.pos as u16, chunk)
813 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
814 self.pos += chunk.len() as u64;
815 }
816
817 Ok(buf.len())
818 }
819
820 fn flush(&mut self) -> io::Result<()> {
821 Ok(())
822 }
823}
824
825impl<'a> io::Seek for NvRamArea<'a> {
826 fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
827 let (base, offset) = match pos {
828 io::SeekFrom::Start(val) => {
829 self.pos = val;
830 return Ok(val);
831 }
832 io::SeekFrom::End(val) => (self.size as u64, val),
833 io::SeekFrom::Current(val) => (self.pos as u64, val),
834 };
835
836 let new_pos = if offset > 0 {
837 base.checked_add(offset as u64)
838 } else {
839 base.checked_sub((offset.wrapping_neg()) as u64)
840 };
841
842 match new_pos {
843 Some(n) if n <= self.size as u64 => {
844 self.pos = n;
845 Ok(n)
846 }
847 Some(n) => {
848 Err(io::Error::new(io::ErrorKind::InvalidInput,
849 format!("unable to seek to {}, which is past end \
850 of NVRAM area at {}",
851 n,
852 self.size)))
853 }
854 None => {
855 Err(io::Error::new(io::ErrorKind::InvalidInput,
856 "invalid seek to a negative or overflow position"))
857 }
858 }
859 }
860}
861
862impl<'a> io::Read for NvRamArea<'a> {
863 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
864 let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.ctx.passwd)
866 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
867 let session_data = CmdAuths::from(cmd);
869 let mut session_out = RespAuths::from(sys::TPMS_AUTH_RESPONSE::default());
870
871 let mut total = 0;
872 let mut to_read = self.size - self.pos as u16;
873 trace!("reading {} bytes from index 0x{:08X}", to_read, self.index);
874 while to_read > 0 {
875 let chunk = self.read_chunk(&session_data, &mut session_out, self.pos as u16, to_read)
876 .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
877 let chunk_size = unsafe { chunk.t.as_ref().size };
878 let mut chunk_slice = &unsafe { chunk.t.as_ref().buffer }[..chunk_size as usize];
879 let n = io::Read::read(&mut chunk_slice, buf)?;
880 trace!("read {} bytes from index 0x{:08X} at pos {}",
881 chunk_size,
882 self.index,
883 self.pos);
884 if n == 0 {
885 break;
886 }
887 self.pos += n as u64;
888 to_read -= n as u16;
889 total += n;
890 }
891
892 Ok(total as usize)
893 }
894}
895
896#[derive(Clone, Debug)]
897pub enum Startup {
898 Clear,
899 State,
900}
901
902#[derive(Clone, Copy, Debug, Eq, PartialEq, Primitive)]
903pub enum HierarchyAuth {
904 Owner = sys::TPM_RH_OWNER as isize,
905 Endorsement = sys::TPM_RH_ENDORSEMENT as isize,
906 Lockout = sys::TPM_RH_LOCKOUT as isize,
907}
908
909#[derive(Clone, Copy, Debug, Eq, PartialEq, Primitive)]
910pub enum AuthType {
911 Owner = sys::TPM_RH_OWNER as isize,
912 Platform = sys::TPM_RH_PLATFORM as isize,
913}
914
915#[derive(Clone, Debug)]
916enum Capabilities {
917 VariableProperties,
918}
919
920struct TpmProperties {
921 index: usize,
922 caps: sys::TPMU_CAPABILITIES,
923}
924
925impl Iterator for TpmProperties {
926 type Item = sys::TPMS_TAGGED_PROPERTY;
927
928 fn next(&mut self) -> Option<Self::Item> {
929 let inner = unsafe { self.caps.tpmProperties.as_ref() };
930
931 if self.index < inner.count as usize {
932 let i = self.index;
933 self.index += 1;
934 inner.tpmProperty.get(i).cloned()
935 } else {
936 None
937 }
938 }
939}
940
941#[derive(Debug)]
942pub struct Context {
943 inner: *mut sys::TSS2_SYS_CONTEXT,
944 size: usize,
945 _tcti: TctiContext, passwd: Option<String>, auth_type: AuthType,
948}
949
950impl Drop for Context {
951 fn drop(&mut self) {
952 trace!("Tss2_Sys_Finalize({:?})", self);
953 unsafe {
954 sys::Tss2_Sys_Finalize(self.inner);
955 }
956 trace!("Context free({:?})", self.inner);
957 free(self.inner, self.size);
958 }
959}
960
961impl Context {
962 fn _new_context(tcti: TctiContext) -> Result<Context> {
963 let mut abi = sys::TSS2_ABI_VERSION {
964 tssCreator: sys::TSSWG_INTEROP,
965 tssFamily: sys::TSS_SAPI_FIRST_FAMILY,
966 tssLevel: sys::TSS_SAPI_FIRST_LEVEL,
967 tssVersion: sys::TSS_SAPI_FIRST_VERSION,
968 };
969
970 let alloc_size = unsafe { sys::Tss2_Sys_GetContextSize(0) };
971 ensure!(alloc_size != 0, "Invalid context size");
972
973 let ptr = malloc::<sys::TSS2_SYS_CONTEXT>(alloc_size);
974
975 trace!("Tss2_Sys_Initialize({:?}, {:?}, {:?}, {:?})",
976 ptr,
977 alloc_size,
978 tcti.inner,
979 abi);
980 tss_err(unsafe { sys::Tss2_Sys_Initialize(ptr, alloc_size, tcti.inner, &mut abi) })?;
981
982 Ok(Context {
983 inner: ptr,
984 size: alloc_size,
985 _tcti: tcti,
986 passwd: None,
987 auth_type: AuthType::Owner,
988 })
989 }
990
991 #[cfg(feature = "tcti-device")]
992 pub fn device(dev: Option<&str>) -> Result<Context> {
993 let tcti = TctiContext::device(dev)?;
994 Self::_new_context(tcti)
995 }
996
997 #[cfg(feature = "tcti-socket")]
998 pub fn socket(host: Option<&str>, port: Option<u16>) -> Result<Context> {
999 let tcti = TctiContext::socket(host, port)?;
1000 Self::_new_context(tcti)
1001 }
1002
1003 pub fn password<T: ToString>(&mut self, auth_type: AuthType, passwd: T) {
1005 self.passwd = Some(passwd.to_string());
1006 self.auth_type = auth_type;
1007 }
1008
1009 pub fn startup(&self, action: Startup) -> Result<()> {
1010 let action = match action {
1011 Startup::State => sys::TPM_SU_STATE,
1012 Startup::Clear => sys::TPM_SU_CLEAR,
1013 };
1014
1015 trace!("Tss2_Sys_Startup({:?}, {:?})", self, action);
1016 tss_err(unsafe { sys::Tss2_Sys_Startup(self.inner, action as u16) })?;
1017 Ok(())
1018 }
1019
1020 fn get_cap(&self, req: Capabilities) -> Result<sys::TPMU_CAPABILITIES> {
1021
1022 let (cap, prop, count) = match req {
1023 Capabilities::VariableProperties => {
1024 (sys::TPM_CAP_TPM_PROPERTIES, sys::PT_VAR, sys::MAX_TPM_PROPERTIES)
1025 }
1026 };
1027
1028 let mut more_data: sys::TPMI_YES_NO = unsafe { mem::zeroed() };
1029 let mut cap_data: sys::TPMS_CAPABILITY_DATA = unsafe { mem::zeroed() };
1030
1031 trace!("Tss2_Sys_GetCapability({:?}, NULL, ({:?}) {}, {}, {}, more_data, cap, NULL)",
1032 self,
1033 req,
1034 cap,
1035 prop,
1036 count);
1037 tss_err(unsafe {
1038 sys::Tss2_Sys_GetCapability(self.inner,
1039 ptr::null(),
1040 cap,
1041 prop,
1042 count,
1043 &mut more_data,
1044 &mut cap_data,
1045 ptr::null_mut())
1046 })?;
1047
1048 Ok(cap_data.data)
1049 }
1050
1051 fn get_variable_properties(&self) -> Result<TpmProperties> {
1052 let caps = self.get_cap(Capabilities::VariableProperties)?;
1053
1054 Ok(TpmProperties {
1055 index: 0,
1056 caps: caps,
1057 })
1058 }
1059
1060 pub fn is_owned(&self) -> Result<bool> {
1062 let props = self.get_variable_properties()?;
1066
1067 Ok(props.filter_map(|p| {
1068 if p.property == sys::TPM_PT_PERMANENT {
1069 Some(unsafe {mem::transmute::<_, sys::TPMA_PERMANENT__bindgen_ty_1>(p.value) })
1070 } else {
1071 None
1072 }
1073 }).map(|p| {
1074 p.ownerAuthSet() > 0 && p.endorsementAuthSet() > 0 && p.lockoutAuthSet() > 0
1076 }).all(|p| p)
1077 )
1078 }
1079
1080 pub fn take_ownership(&self, auth_type: HierarchyAuth, passwd: &str) -> Result<()> {
1082 let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.passwd)?;
1084 let session_data = CmdAuths::from(cmd);
1086
1087 let mut new_auth = sys::TPM2B_AUTH::try_from(passwd.as_bytes())?;
1089
1090 trace!("Tss2_Sys_HierarchyChangeAuth({:?}, {:?}, SESSION_DATA, NEW_AUTH, NULL)",
1091 self,
1092 auth_type);
1093 tss_err(unsafe {
1094 sys::Tss2_Sys_HierarchyChangeAuth(self.inner,
1095 auth_type.to_u32().unwrap(),
1096 &session_data.inner,
1097 &mut new_auth,
1098 ptr::null_mut())
1099 })?;
1100 Ok(())
1101 }
1102}
1103
1104#[derive(Debug)]
1105struct TctiContext {
1106 inner: *mut sys::TSS2_TCTI_CONTEXT,
1107 size: usize,
1108}
1109
1110impl Drop for TctiContext {
1111 fn drop(&mut self) {
1112 trace!("TctiContext free({:?})", self);
1125 free(self.inner, self.size);
1126 }
1127}
1128
1129impl TctiContext {
1130 #[cfg(feature = "tcti-device")]
1131 fn device(dev: Option<&str>) -> Result<TctiContext> {
1132 let dev_path = match dev {
1134 Some(dev) => CString::new(dev)?,
1135 None => CString::new("/dev/tpm0")?,
1136 };
1137
1138 let config = sys::TCTI_DEVICE_CONF {
1139 device_path: dev_path.as_ptr(),
1140 logCallback: None,
1141 logData: ptr::null_mut(),
1142 };
1143
1144 let mut alloc_size: usize = 0;
1145
1146 tss_err(unsafe { sys::InitDeviceTcti(ptr::null_mut(), &mut alloc_size, &config) })?;
1147
1148 let ptr = malloc::<sys::TSS2_TCTI_CONTEXT>(alloc_size);
1149
1150 trace!("InitDeviceTcti({:?}, {:?}, {:?})", ptr, alloc_size, config);
1151 tss_err(unsafe { sys::InitDeviceTcti(ptr, &mut alloc_size, &config) })?;
1152
1153 Ok(TctiContext {
1154 inner: ptr,
1155 size: alloc_size,
1156 })
1157 }
1158
1159 #[cfg(feature = "tcti-socket")]
1160 fn socket(host: Option<&str>, port: Option<u16>) -> Result<TctiContext> {
1161 let host = match host {
1162 Some(name) => CString::new(name)?,
1163 None => {
1164 let def = unsafe { CStr::from_bytes_with_nul_unchecked(sys::DEFAULT_HOSTNAME) };
1165 def.to_owned()
1166 }
1167 };
1168
1169 let port = match port {
1170 Some(num) => num,
1171 None => sys::DEFAULT_SIMULATOR_TPM_PORT as u16,
1172 };
1173
1174 let config = sys::TCTI_SOCKET_CONF {
1175 hostname: host.as_ptr(),
1176 port: port,
1177 logCallback: None,
1178 logBufferCallback: None,
1179 logData: ptr::null_mut(),
1180 };
1181
1182 let mut alloc_size: usize = 0;
1183
1184 tss_err(unsafe { sys::InitSocketTcti(ptr::null_mut(), &mut alloc_size, &config, 0) })?;
1185
1186 let ptr = malloc::<sys::TSS2_TCTI_CONTEXT>(alloc_size);
1187
1188 trace!("InitSocketTcti({:?}, {:?}, {:?}, 0)",
1189 ptr,
1190 alloc_size,
1191 config);
1192 tss_err(unsafe { sys::InitSocketTcti(ptr, &mut alloc_size, &config, 0) })?;
1193
1194 Ok(TctiContext {
1195 inner: ptr,
1196 size: alloc_size,
1197 })
1198 }
1199}