tss_sapi/
lib.rs

1// Copyright 2017 Star Lab Corp.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#![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    // error values aren't getting pulled from sapi/tss2_common.h
34    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    // values not pulled from sapi/tss2_tpm2_types.h
47    // MAX_TPM_PROPERTIES = (MAX_CAP_DATA / sizeof(TPMS_TAGGED_PROPERTY))
48    // MAX_CAP_DATA = (MAX_CAP_BUFFER - sizeof(TPM_CAP) - sizeof(UINT32)
49    // TPM_CAP = typedef UINT32
50    // MAX_CAP_BUFFER = 1024
51    // TPMS_TAGGED_PROPERTY = struct { TPM_PT, UINT32 };
52    // TPM_PT = typedef UINT32;
53    // MAX_TPM_PROPERTIES = ((1024 - 4 - 4) / (4 + 4) = 127
54    pub const MAX_TPM_PROPERTIES: UINT32 = 127;
55
56    // TPM2B types must be initialized with the size parameter of the t union
57    // set to the size of the buffer in the struct. The struct is made up
58    // of the buffer + a UINT16 (the size). So it should be equal to the size
59    // of the struct minus a UINT16.
60    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    // of the buffer + a UINT16 (the size). So it should be equal to the size
80    // of the struct minus a UINT16.
81    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                        // set the length of incoming data
98                        thing.size = data.len() as u16;
99                        // copy the password into the password struct
100                        ptr::copy(data.as_ptr(), thing.buffer.as_mut_ptr(), data.len());
101                    }
102                    Ok(field)
103                }
104            }
105            )
106        );
107
108    // add try_from() method to TPM2B_AUTH that attempts to convert from
109    // a buffer which is a password
110    tpm2b_try_from!(TPM2B_AUTH, 'a, &'a[u8]);
111
112    // create a new NV buffer from supplied data
113    tpm2b_try_from!(TPM2B_MAX_NV_BUFFER, 'a, &'a[u8]);
114
115    impl TPMS_AUTH_COMMAND {
116        pub fn new() -> Self {
117            // creates TPMS_AUTH_COMMAND initialized to an un"owned" password
118            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    // masks not defined in the spec but defined in tpm2.0-tools/lib/rc-decode.h
169    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    // bit positions for the different fields
176    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    // use a Vec as our allocator
218    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 against the error returned
238    match err {
239        // do nothing for success
240        sys::TPM_RC_SUCCESS => Ok(()),
241        // any error in the valid error range needs to be taken apart by layer
242        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                            // format one codes
249                            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                            // format zero uses "version 1" codes
307                            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                    // get the error code
350                    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
371/// abstract over TPMS_AUTH_COMMAND and its vector TSS2_SYS_CMD_AUTHS
372struct 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        // found this limit in tpm2-tss/sysapi/sysapi/authorizations.c
381        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
405/// abstract over TPMS_AUTH_RESPONSE and its vector TSS2_SYS_RSP_AUTHS
406struct 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/// Provide a handy enum that abstracts TPM algorithms
440#[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        // get the attributes converted
507        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    /// look up an NVRAM area
547    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    /// create an NVRAM area
579    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        // set our members
590        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        // create an auth command with our existing authentication password
602        let cmd = sys::TPMS_AUTH_COMMAND::new().password(&ctx.passwd)?;
603        // populate our session data from the auth command
604        let session_data = CmdAuths::from(cmd);
605
606        // create our NVRAM index password
607        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        // create our session response
613        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    /// delete an NVRAM area
643    pub fn undefine(self) -> Result<()> {
644        // create an auth command with our existing authentication password
645        let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.ctx.passwd)?;
646        // populate our session data from the auth command
647        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    /// read lock an NVRAM area
667    pub fn readlock(&self) -> Result<()> {
668        // create an auth command with our existing authentication password
669        let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.ctx.passwd)?;
670        // populate our session data from the auth command
671        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        // create an auth command with our existing authentication password
804        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        // populate our session data
807        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        // create an auth command with our existing authentication password
865        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        // populate our session data
868        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, // need to keep this for the life of this context
946    passwd: Option<String>, // the current authentication password
947    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    /// set the authentication password we will use
1004    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    /// check if the TPM is owned or not
1061    pub fn is_owned(&self) -> Result<bool> {
1062        // Get the variable TPM properties since this is how we see if the TPM is owned
1063        // filter those to the TPM_PT_PERMANENT ones convert those to the TPMA_PERMANENT
1064        // type which then allows us to check the 3 bits that we need to check
1065        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                // combine all the bits to see if this should be true or false
1075                p.ownerAuthSet() > 0 && p.endorsementAuthSet() > 0 && p.lockoutAuthSet() > 0
1076            }).all(|p| p)
1077           )
1078    }
1079
1080    /// take ownership of the TPM setting the Owner, Endorsement or Lockout passwords to `passwd`
1081    pub fn take_ownership(&self, auth_type: HierarchyAuth, passwd: &str) -> Result<()> {
1082        // create an auth command with our existing authentication password
1083        let cmd = sys::TPMS_AUTH_COMMAND::new().password(&self.passwd)?;
1084        // populate our session data from the auth command
1085        let session_data = CmdAuths::from(cmd);
1086
1087        // create our new password
1088        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        // technically we need to call tss2_tcti_finalize()
1113        // but that is a macro to look up a func pointer on
1114        // the opaque structure so we cannot without some helper
1115        // C code. The finalize step is minor in our use case and I
1116        // am OK with leaking the data until upstream addresses this.
1117        // see: https://github.com/01org/tpm2-tss/issues/490
1118        // see: https://github.com/01org/tpm2-tss/pull/491
1119        //trace!("Tss2_Tcti_Finalize({:?})", self.inner);
1120        //unsafe {
1121        //    sys::Tss2_Tcti_Finalize(self.inner);
1122        //}
1123
1124        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        // if we didn't get a device path default to /dev/tpm0
1133        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}