tss_esapi/context/tpm_commands/non_volatile_storage.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 context::handle_manager::HandleDropAction,
5 handles::{AuthHandle, NvIndexHandle, ObjectHandle},
6 interface_types::reserved_handles::{NvAuth, Provision},
7 structures::{Auth, MaxNvBuffer, Name, NvPublic},
8 tss2_esys::{
9 Esys_NV_DefineSpace, Esys_NV_Extend, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadPublic,
10 Esys_NV_UndefineSpace, Esys_NV_UndefineSpaceSpecial, Esys_NV_Write,
11 },
12 Context, Result, ReturnCode,
13};
14use log::error;
15use std::convert::{TryFrom, TryInto};
16use std::ptr::null_mut;
17
18impl Context {
19 /// Allocates an index in the non volatile storage.
20 ///
21 /// # Details
22 /// This method will instruct the TPM to reserve space for an NV index
23 /// with the attributes defined in the provided parameters.
24 ///
25 /// Please beware
26 /// that this method requires an authorization session handle to be present.
27 ///
28 /// # Arguments
29 /// * `nv_auth` - The [Provision] used for authorization.
30 /// * `auth` - The authorization value.
31 /// * `public_info` - The public parameters of the NV area.
32 ///
33 /// # Returns
34 /// A [NvIndexHandle] associated with the NV memory that
35 /// was defined.
36 ///
37 /// # Example
38 /// ```rust
39 /// # use tss_esapi::{
40 /// # Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
41 /// # structures::SymmetricDefinition,
42 /// # };
43 /// use tss_esapi::{
44 /// handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
45 /// interface_types::{algorithm::HashingAlgorithm, reserved_handles::Provision},
46 /// };
47 /// # // Create context
48 /// # let mut context =
49 /// # Context::new(
50 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
51 /// # ).expect("Failed to create Context");
52 /// #
53 /// # let session = context
54 /// # .start_auth_session(
55 /// # None,
56 /// # None,
57 /// # None,
58 /// # SessionType::Hmac,
59 /// # SymmetricDefinition::AES_256_CFB,
60 /// # HashingAlgorithm::Sha256,
61 /// # )
62 /// # .expect("Failed to create session")
63 /// # .expect("Received invalid handle");
64 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
65 /// # .with_decrypt(true)
66 /// # .with_encrypt(true)
67 /// # .build();
68 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
69 /// # .expect("Failed to set attributes on session");
70 /// # context.set_sessions((Some(session), None, None));
71 /// #
72 /// let nv_index = NvIndexTpmHandle::new(0x01500022)
73 /// .expect("Failed to create NV index tpm handle");
74 ///
75 /// // Create NV index attributes
76 /// let owner_nv_index_attributes = NvIndexAttributes::builder()
77 /// .with_owner_write(true)
78 /// .with_owner_read(true)
79 /// .build()
80 /// .expect("Failed to create owner nv index attributes");
81 ///
82 /// // Create owner nv public.
83 /// let owner_nv_public = NvPublic::builder()
84 /// .with_nv_index(nv_index)
85 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
86 /// .with_index_attributes(owner_nv_index_attributes)
87 /// .with_data_area_size(32)
88 /// .build()
89 /// .expect("Failed to build NvPublic for owner");
90 ///
91 /// // Define the NV space.
92 /// let owner_nv_index_handle = context
93 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
94 /// .expect("Call to nv_define_space failed");
95 ///
96 /// # context
97 /// # .nv_undefine_space(Provision::Owner, owner_nv_index_handle)
98 /// # .expect("Call to nv_undefine_space failed");
99 /// ```
100 pub fn nv_define_space(
101 &mut self,
102 nv_auth: Provision,
103 auth: Option<Auth>,
104 public_info: NvPublic,
105 ) -> Result<NvIndexHandle> {
106 let mut nv_handle = ObjectHandle::None.into();
107 ReturnCode::ensure_success(
108 unsafe {
109 Esys_NV_DefineSpace(
110 self.mut_context(),
111 AuthHandle::from(nv_auth).into(),
112 self.required_session_1()?,
113 self.optional_session_2(),
114 self.optional_session_3(),
115 &auth.unwrap_or_default().into(),
116 &public_info.try_into()?,
117 &mut nv_handle,
118 )
119 },
120 |ret| {
121 error!("Error when defining NV space: {:#010X}", ret);
122 },
123 )?;
124
125 self.handle_manager
126 .add_handle(nv_handle.into(), HandleDropAction::Close)?;
127 Ok(NvIndexHandle::from(nv_handle))
128 }
129
130 /// Deletes an index in the non volatile storage.
131 ///
132 /// # Details
133 /// The method will instruct the TPM to remove a
134 /// nv index.
135 ///
136 /// Please beware that this method requires an authorization
137 /// session handle to be present.
138 ///
139 /// # Arguments
140 /// * `nv_auth` - The [Provision] used for authorization.
141 /// * `nv_index_handle`- The [NvIndexHandle] associated with
142 /// the nv area that is to be removed.
143 ///
144 /// # Example
145 /// ```rust
146 /// # use tss_esapi::{
147 /// # Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
148 /// # structures::SymmetricDefinition,
149 /// # handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
150 /// # interface_types::algorithm::HashingAlgorithm,
151 /// # };
152 /// use tss_esapi::interface_types::reserved_handles::Provision;
153 /// # // Create context
154 /// # let mut context =
155 /// # Context::new(
156 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
157 /// # ).expect("Failed to create Context");
158 /// #
159 /// # let session = context
160 /// # .start_auth_session(
161 /// # None,
162 /// # None,
163 /// # None,
164 /// # SessionType::Hmac,
165 /// # SymmetricDefinition::AES_256_CFB,
166 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
167 /// # )
168 /// # .expect("Failed to create session")
169 /// # .expect("Received invalid handle");
170 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
171 /// # .with_decrypt(true)
172 /// # .with_encrypt(true)
173 /// # .build();
174 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
175 /// # .expect("Failed to set attributes on session");
176 /// # context.set_sessions((Some(session), None, None));
177 /// # let nv_index = NvIndexTpmHandle::new(0x01500023)
178 /// # .expect("Failed to create NV index tpm handle");
179 /// #
180 /// # // Create NV index attributes
181 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
182 /// # .with_owner_write(true)
183 /// # .with_owner_read(true)
184 /// # .build()
185 /// # .expect("Failed to create owner nv index attributes");
186 /// #
187 /// # // Create owner nv public.
188 /// # let owner_nv_public = NvPublic::builder()
189 /// # .with_nv_index(nv_index)
190 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
191 /// # .with_index_attributes(owner_nv_index_attributes)
192 /// # .with_data_area_size(32)
193 /// # .build()
194 /// # .expect("Failed to build NvPublic for owner");
195 /// #
196 /// // Define the NV space.
197 /// let owner_nv_index_handle = context
198 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
199 /// .expect("Call to nv_define_space failed");
200 ///
201 /// context
202 /// .nv_undefine_space(Provision::Owner, owner_nv_index_handle)
203 /// .expect("Call to nv_undefine_space failed");
204 /// ```
205 pub fn nv_undefine_space(
206 &mut self,
207 nv_auth: Provision,
208 nv_index_handle: NvIndexHandle,
209 ) -> Result<()> {
210 ReturnCode::ensure_success(
211 unsafe {
212 Esys_NV_UndefineSpace(
213 self.mut_context(),
214 AuthHandle::from(nv_auth).into(),
215 nv_index_handle.into(),
216 self.required_session_1()?,
217 self.optional_session_2(),
218 self.optional_session_3(),
219 )
220 },
221 |ret| {
222 error!("Error when undefining NV space: {:#010X}", ret);
223 },
224 )?;
225
226 self.handle_manager.set_as_closed(nv_index_handle.into())
227 }
228
229 /// Deletes an index in the non volatile storage.
230 ///
231 /// # Details
232 /// The method will instruct the TPM to remove a
233 /// nv index that was defined with TPMA_NV_POLICY_DELETE.
234 ///
235 /// Please beware that this method requires both a policy and
236 /// authorization session handle to be present.
237 ///
238 /// # Arguments
239 /// * `nv_auth` - The [Provision] used for authorization.
240 /// * `nv_index_handle`- The [NvIndexHandle] associated with
241 /// the nv area that is to be removed.
242 ///
243 /// # Example
244 /// ```rust
245 /// # use tss_esapi::{
246 /// # Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
247 /// # structures::SymmetricDefinition, constants::CommandCode,
248 /// # handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
249 /// # interface_types::algorithm::HashingAlgorithm, structures::Digest,
250 /// # interface_types::session_handles::PolicySession,
251 /// # };
252 /// # use std::convert::TryFrom;
253 /// use tss_esapi::interface_types::reserved_handles::Provision;
254 /// use tss_esapi::interface_types::session_handles::AuthSession;
255 /// # // Create context
256 /// # let mut context =
257 /// # Context::new(
258 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
259 /// # ).expect("Failed to create Context");
260 /// #
261 /// # // Create a trial session to generate policy digest
262 /// # let session = context
263 /// # .start_auth_session(
264 /// # None,
265 /// # None,
266 /// # None,
267 /// # SessionType::Trial,
268 /// # SymmetricDefinition::AES_256_CFB,
269 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
270 /// # )
271 /// # .expect("Failed to create session")
272 /// # .expect("Received invalid handle");
273 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
274 /// # .with_decrypt(true)
275 /// # .with_encrypt(true)
276 /// # .build();
277 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
278 /// # .expect("Failed to set attributes on session");
279 /// #
280 /// # // Create a trial policy session that allows undefine with NvUndefineSpaceSpecial
281 /// # let policy_session = PolicySession::try_from(session).expect("Failed to get policy session");
282 /// # context.policy_command_code(policy_session, CommandCode::NvUndefineSpaceSpecial).expect("Failed to create trial policy");
283 /// # let digest = context.policy_get_digest(policy_session).expect("Failed to get policy digest");
284 /// #
285 /// # let nv_index = NvIndexTpmHandle::new(0x01500023)
286 /// # .expect("Failed to create NV index tpm handle");
287 /// #
288 /// # // Create NV index attributes
289 /// # let nv_index_attributes = NvIndexAttributes::builder()
290 /// # .with_pp_read(true)
291 /// # .with_platform_create(true)
292 /// # .with_policy_delete(true)
293 /// # .with_policy_write(true)
294 /// # .build()
295 /// # .expect("Failed to create nv index attributes");
296 /// #
297 /// # // Create nv public.
298 /// # let nv_public = NvPublic::builder()
299 /// # .with_nv_index(nv_index)
300 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
301 /// # .with_index_attributes(nv_index_attributes)
302 /// # .with_index_auth_policy(digest)
303 /// # .with_data_area_size(32)
304 /// # .build()
305 /// # .expect("Failed to build NvPublic");
306 /// #
307 /// // Define the NV space.
308 /// let index_handle = context.execute_with_session(Some(AuthSession::Password), |context| {
309 /// context
310 /// .nv_define_space(Provision::Platform, None, nv_public)
311 /// .expect("Call to nv_define_space failed")
312 /// });
313 ///
314 /// # // Setup auth policy session
315 /// # let session = context
316 /// # .start_auth_session(
317 /// # None,
318 /// # None,
319 /// # None,
320 /// # SessionType::Policy,
321 /// # SymmetricDefinition::AES_256_CFB,
322 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
323 /// # )
324 /// # .expect("Failed to create policy session")
325 /// # .expect("Received invalid handle");
326 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
327 /// # .with_decrypt(true)
328 /// # .with_encrypt(true)
329 /// # .build();
330 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
331 /// # .expect("Failed to set attributes on session");
332 /// #
333 /// # // Define a policy command code that allows undefine with NvUndefineSpaceSpecial
334 /// # let policy_session = PolicySession::try_from(session).expect("Failed to get policy session");
335 /// # context.policy_command_code(policy_session, CommandCode::NvUndefineSpaceSpecial).expect("Failed to create policy");
336 /// #
337 /// // Undefine the NV space with a policy session and default auth session
338 /// context.execute_with_sessions((
339 /// Some(session),
340 /// Some(AuthSession::Password),
341 /// None,
342 /// ), |context| {
343 /// context
344 /// .nv_undefine_space_special(Provision::Platform, index_handle)
345 /// .expect("Call to nv_undefine_space_special failed");
346 /// }
347 /// );
348 /// ```
349 pub fn nv_undefine_space_special(
350 &mut self,
351 nv_auth: Provision,
352 nv_index_handle: NvIndexHandle,
353 ) -> Result<()> {
354 ReturnCode::ensure_success(
355 unsafe {
356 Esys_NV_UndefineSpaceSpecial(
357 self.mut_context(),
358 nv_index_handle.into(),
359 AuthHandle::from(nv_auth).into(),
360 self.required_session_1()?,
361 self.optional_session_2(),
362 self.optional_session_3(),
363 )
364 },
365 |ret| {
366 error!("Error when undefining NV space: {:#010X}", ret);
367 },
368 )?;
369
370 self.handle_manager.set_as_closed(nv_index_handle.into())
371 }
372
373 /// Reads the public part of an nv index.
374 ///
375 /// # Details
376 /// This method is used to read the public
377 /// area and name of a nv index.
378 ///
379 /// # Arguments
380 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
381 /// for which the public part is to be read.
382 /// # Returns
383 /// A tuple containing the public area and the name of an nv index.
384 ///
385 /// # Example
386 /// ```rust
387 /// # use tss_esapi::{
388 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
389 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
390 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
391 /// # };
392 /// use tss_esapi::{
393 /// interface_types::reserved_handles::Provision,
394 /// };
395 ///
396 /// # // Create context
397 /// # let mut context =
398 /// # Context::new(
399 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
400 /// # ).expect("Failed to create Context");
401 /// #
402 /// # let session = context
403 /// # .start_auth_session(
404 /// # None,
405 /// # None,
406 /// # None,
407 /// # SessionType::Hmac,
408 /// # SymmetricDefinition::AES_256_CFB,
409 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
410 /// # )
411 /// # .expect("Failed to create session")
412 /// # .expect("Received invalid handle");
413 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
414 /// # .with_decrypt(true)
415 /// # .with_encrypt(true)
416 /// # .build();
417 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
418 /// # .expect("Failed to set attributes on session");
419 /// # context.set_sessions((Some(session), None, None));
420 /// #
421 /// # let nv_index = NvIndexTpmHandle::new(0x01500024)
422 /// # .expect("Failed to create NV index tpm handle");
423 /// #
424 /// # // Create NV index attributes
425 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
426 /// # .with_owner_write(true)
427 /// # .with_owner_read(true)
428 /// # .build()
429 /// # .expect("Failed to create owner nv index attributes");
430 /// #
431 /// // Create owner nv public.
432 /// let owner_nv_public = NvPublic::builder()
433 /// .with_nv_index(nv_index)
434 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
435 /// .with_index_attributes(owner_nv_index_attributes)
436 /// .with_data_area_size(32)
437 /// .build()
438 /// .expect("Failed to build NvPublic for owner");
439 ///
440 /// let nv_index_handle = context
441 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
442 /// .expect("Call to nv_define_space failed");
443 ///
444 /// // Holds the result in order to ensure that the
445 /// // NV space gets undefined.
446 /// let nv_read_public_result = context.nv_read_public(nv_index_handle);
447 ///
448 /// context
449 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
450 /// .expect("Call to nv_undefine_space failed");
451 ///
452 /// // Process result
453 /// let (read_nv_public, _name) = nv_read_public_result
454 /// .expect("Call to nv_read_public failed");
455 ///
456 /// assert_eq!(owner_nv_public, read_nv_public);
457 /// ```
458 pub fn nv_read_public(&mut self, nv_index_handle: NvIndexHandle) -> Result<(NvPublic, Name)> {
459 let mut nv_public_ptr = null_mut();
460 let mut nv_name_ptr = null_mut();
461 ReturnCode::ensure_success(
462 unsafe {
463 Esys_NV_ReadPublic(
464 self.mut_context(),
465 nv_index_handle.into(),
466 self.optional_session_1(),
467 self.optional_session_2(),
468 self.optional_session_3(),
469 &mut nv_public_ptr,
470 &mut nv_name_ptr,
471 )
472 },
473 |ret| {
474 error!("Error when reading NV public: {:#010X}", ret);
475 },
476 )?;
477
478 Ok((
479 NvPublic::try_from(Context::ffi_data_to_owned(nv_public_ptr)?)?,
480 Name::try_from(Context::ffi_data_to_owned(nv_name_ptr)?)?,
481 ))
482 }
483
484 /// Writes data to the NV memory associated with a nv index.
485 ///
486 /// # Details
487 /// This method is used to write a value to
488 /// the nv memory in the TPM.
489 ///
490 /// Please beware that this method requires an authorization
491 /// session handle to be present.
492 ///
493 /// # Arguments
494 /// * `auth_handle` - Handle indicating the source of authorization value.
495 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
496 /// where data is to be written.
497 /// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
498 /// * `offset` - The octet offset into the NV area.
499 ///
500 /// # Example
501 /// ```rust
502 /// # use tss_esapi::{
503 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
504 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
505 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
506 /// # };
507 /// use tss_esapi::{
508 /// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
509 /// };
510 /// use std::convert::TryFrom;
511 ///
512 /// # // Create context
513 /// # let mut context =
514 /// # Context::new(
515 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
516 /// # ).expect("Failed to create Context");
517 /// #
518 /// # let session = context
519 /// # .start_auth_session(
520 /// # None,
521 /// # None,
522 /// # None,
523 /// # SessionType::Hmac,
524 /// # SymmetricDefinition::AES_256_CFB,
525 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
526 /// # )
527 /// # .expect("Failed to create session")
528 /// # .expect("Received invalid handle");
529 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
530 /// # .with_decrypt(true)
531 /// # .with_encrypt(true)
532 /// # .build();
533 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
534 /// # .expect("Failed to set attributes on session");
535 /// # context.set_sessions((Some(session), None, None));
536 /// #
537 /// # let nv_index = NvIndexTpmHandle::new(0x01500025)
538 /// # .expect("Failed to create NV index tpm handle");
539 /// #
540 /// # // Create NV index attributes
541 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
542 /// # .with_owner_write(true)
543 /// # .with_owner_read(true)
544 /// # .build()
545 /// # .expect("Failed to create owner nv index attributes");
546 /// #
547 /// # // Create owner nv public.
548 /// # let owner_nv_public = NvPublic::builder()
549 /// # .with_nv_index(nv_index)
550 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
551 /// # .with_index_attributes(owner_nv_index_attributes)
552 /// # .with_data_area_size(32)
553 /// # .build()
554 /// # .expect("Failed to build NvPublic for owner");
555 ///
556 /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7])
557 /// .expect("Failed to create MaxNvBuffer from vec");
558 ///
559 /// let nv_index_handle = context
560 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
561 /// .expect("Call to nv_define_space failed");
562 ///
563 /// // Use owner authorization
564 /// let nv_write_result = context.nv_write(NvAuth::Owner, nv_index_handle, data, 0);
565 ///
566 /// context
567 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
568 /// .expect("Call to nv_undefine_space failed");
569 ///
570 /// // Process result
571 /// nv_write_result.expect("Call to nv_write failed");
572 /// ```
573 pub fn nv_write(
574 &mut self,
575 auth_handle: NvAuth,
576 nv_index_handle: NvIndexHandle,
577 data: MaxNvBuffer,
578 offset: u16,
579 ) -> Result<()> {
580 ReturnCode::ensure_success(
581 unsafe {
582 Esys_NV_Write(
583 self.mut_context(),
584 AuthHandle::from(auth_handle).into(),
585 nv_index_handle.into(),
586 self.required_session_1()?,
587 self.optional_session_2(),
588 self.optional_session_3(),
589 &data.into(),
590 offset,
591 )
592 },
593 |ret| {
594 error!("Error when writing NV: {:#010X}", ret);
595 },
596 )
597 }
598
599 /// Increment monotonic counter index
600 ///
601 /// # Details
602 /// This method is used to increment monotonic counter
603 /// in the TPM.
604 ///
605 /// Please beware that this method requires an authorization
606 /// session handle to be present.
607 ///
608 /// # Arguments
609 /// * `auth_handle` - Handle indicating the source of authorization value.
610 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
611 /// where data is to be written.
612 /// ```rust
613 /// # use tss_esapi::{
614 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
615 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
616 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
617 /// # constants::nv_index_type::NvIndexType,
618 /// # };
619 /// use tss_esapi::{
620 /// interface_types::reserved_handles::{Provision, NvAuth}
621 /// };
622 ///
623 /// # // Create context
624 /// # let mut context =
625 /// # Context::new(
626 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
627 /// # ).expect("Failed to create Context");
628 /// #
629 /// # let session = context
630 /// # .start_auth_session(
631 /// # None,
632 /// # None,
633 /// # None,
634 /// # SessionType::Hmac,
635 /// # SymmetricDefinition::AES_256_CFB,
636 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
637 /// # )
638 /// # .expect("Failed to create session")
639 /// # .expect("Received invalid handle");
640 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
641 /// # .with_decrypt(true)
642 /// # .with_encrypt(true)
643 /// # .build();
644 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
645 /// # .expect("Failed to set attributes on session");
646 /// # context.set_sessions((Some(session), None, None));
647 /// #
648 /// # let nv_index = NvIndexTpmHandle::new(0x01500026)
649 /// # .expect("Failed to create NV index tpm handle");
650 /// #
651 /// # // Create NV index attributes
652 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
653 /// # .with_owner_write(true)
654 /// # .with_owner_read(true)
655 /// # .with_nv_index_type(NvIndexType::Counter)
656 /// # .build()
657 /// # .expect("Failed to create owner nv index attributes");
658 /// #
659 /// # // Create owner nv public.
660 /// # let owner_nv_public = NvPublic::builder()
661 /// # .with_nv_index(nv_index)
662 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
663 /// # .with_index_attributes(owner_nv_index_attributes)
664 /// # .with_data_area_size(8)
665 /// # .build()
666 /// # .expect("Failed to build NvPublic for owner");
667 /// #
668 /// let nv_index_handle = context
669 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
670 /// .expect("Call to nv_define_space failed");
671 ///
672 /// let nv_increment_result = context.nv_increment(NvAuth::Owner, nv_index_handle);
673 ///
674 /// context
675 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
676 /// .expect("Call to nv_undefine_space failed");
677 ///
678 /// // Process result
679 /// nv_increment_result.expect("Call to nv_increment failed");
680 /// ```
681 pub fn nv_increment(
682 &mut self,
683 auth_handle: NvAuth,
684 nv_index_handle: NvIndexHandle,
685 ) -> Result<()> {
686 ReturnCode::ensure_success(
687 unsafe {
688 Esys_NV_Increment(
689 self.mut_context(),
690 AuthHandle::from(auth_handle).into(),
691 nv_index_handle.into(),
692 self.required_session_1()?,
693 self.optional_session_2(),
694 self.optional_session_3(),
695 )
696 },
697 |ret| error!("Error when incrementing NV: {:#010X}", ret),
698 )
699 }
700
701 /// Extends data to the NV memory associated with a nv index.
702 ///
703 /// # Details
704 /// This method is used to extend a value to the nv memory in the TPM.
705 ///
706 /// Please beware that this method requires an authorization session handle to be present.
707 ///
708 /// Any NV index (that is not already used) can be defined as an extend type. However various specifications define
709 /// indexes that have specific purposes or are reserved, for example the TCG PC Client Platform Firmware Profile
710 /// Specification Section 3.3.6 defines indexes within the 0x01c40200-0x01c402ff range for instance measurements.
711 /// Section 2.2 of TCG Registry of Reserved TPM 2.0 Handles and Localities provides additional context for specific
712 /// NV index ranges.
713 ///
714 /// # Arguments
715 /// * `auth_handle` - Handle indicating the source of authorization value.
716 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
717 /// which will be extended by data hashed with the previous data.
718 /// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
719 ///
720 /// # Example
721 /// ```rust
722 /// # use tss_esapi::{
723 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
724 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
725 /// # structures::{SymmetricDefinition, NvPublic},
726 /// # constants::SessionType, constants::nv_index_type::NvIndexType,
727 /// # };
728 /// use tss_esapi::{
729 /// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
730 /// };
731 ///
732 /// # // Create context
733 /// # let mut context =
734 /// # Context::new(
735 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
736 /// # ).expect("Failed to create Context");
737 /// #
738 /// # let session = context
739 /// # .start_auth_session(
740 /// # None,
741 /// # None,
742 /// # None,
743 /// # SessionType::Hmac,
744 /// # SymmetricDefinition::AES_256_CFB,
745 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
746 /// # )
747 /// # .expect("Failed to create session")
748 /// # .expect("Received invalid handle");
749 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
750 /// # .with_decrypt(true)
751 /// # .with_encrypt(true)
752 /// # .build();
753 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
754 /// # .expect("Failed to set attributes on session");
755 /// # context.set_sessions((Some(session), None, None));
756 /// #
757 /// # let nv_index = NvIndexTpmHandle::new(0x01500028)
758 /// # .expect("Failed to create NV index tpm handle");
759 /// #
760 /// // Create NV index attributes
761 /// let owner_nv_index_attributes = NvIndexAttributes::builder()
762 /// .with_owner_write(true)
763 /// .with_owner_read(true)
764 /// .with_orderly(true)
765 /// .with_nv_index_type(NvIndexType::Extend)
766 /// .build()
767 /// .expect("Failed to create owner nv index attributes");
768 ///
769 /// // Create owner nv public.
770 /// let owner_nv_public = NvPublic::builder()
771 /// .with_nv_index(nv_index)
772 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
773 /// .with_index_attributes(owner_nv_index_attributes)
774 /// .with_data_area_size(32)
775 /// .build()
776 /// .expect("Failed to build NvPublic for owner");
777 ///
778 /// let nv_index_handle = context
779 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
780 /// .expect("Call to nv_define_space failed");
781 ///
782 /// let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
783 /// let result = context.nv_extend(NvAuth::Owner, nv_index_handle, data);
784 ///
785 /// # context
786 /// # .nv_undefine_space(Provision::Owner, nv_index_handle)
787 /// # .expect("Call to nv_undefine_space failed");
788 /// ```
789 pub fn nv_extend(
790 &mut self,
791 auth_handle: NvAuth,
792 nv_index_handle: NvIndexHandle,
793 data: MaxNvBuffer,
794 ) -> Result<()> {
795 ReturnCode::ensure_success(
796 unsafe {
797 Esys_NV_Extend(
798 self.mut_context(),
799 AuthHandle::from(auth_handle).into(),
800 nv_index_handle.into(),
801 self.required_session_1()?,
802 self.optional_session_2(),
803 self.optional_session_3(),
804 &data.into(),
805 )
806 },
807 |ret| error!("Error when extending NV: {:#010X}", ret),
808 )
809 }
810
811 // Missing function: NV_SetBits
812 // Missing function: NV_WriteLock
813 // Missing function: NV_GlobalWriteLock
814
815 /// Reads data from the nv index.
816 ///
817 /// # Details
818 /// This method is used to read a value from an area in
819 /// NV memory of the TPM.
820 ///
821 /// Please beware that this method requires an authorization
822 /// session handle to be present.
823 ///
824 /// # Arguments
825 /// * `auth_handle` - Handle indicating the source of authorization value.
826 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
827 /// where data is to be written.
828 /// * `size` - The number of octets to read.
829 /// * `offset`- Octet offset into the NV area.
830 ///
831 /// # Example
832 /// ```rust
833 /// # use tss_esapi::{
834 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
835 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
836 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
837 /// # };
838 /// use tss_esapi::{
839 /// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
840 /// };
841 /// use std::convert::TryFrom;
842 ///
843 /// # // Create context
844 /// # let mut context =
845 /// # Context::new(
846 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
847 /// # ).expect("Failed to create Context");
848 /// #
849 /// # let session = context
850 /// # .start_auth_session(
851 /// # None,
852 /// # None,
853 /// # None,
854 /// # SessionType::Hmac,
855 /// # SymmetricDefinition::AES_256_CFB,
856 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
857 /// # )
858 /// # .expect("Failed to create session")
859 /// # .expect("Received invalid handle");
860 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
861 /// # .with_decrypt(true)
862 /// # .with_encrypt(true)
863 /// # .build();
864 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
865 /// # .expect("Failed to set attributes on session");
866 /// # context.set_sessions((Some(session), None, None));
867 /// #
868 /// # let nv_index = NvIndexTpmHandle::new(0x01500027)
869 /// # .expect("Failed to create NV index tpm handle");
870 /// #
871 /// # // Create NV index attributes
872 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
873 /// # .with_owner_write(true)
874 /// # .with_owner_read(true)
875 /// # .build()
876 /// # .expect("Failed to create owner nv index attributes");
877 /// #
878 /// # // Create owner nv public.
879 /// # let owner_nv_public = NvPublic::builder()
880 /// # .with_nv_index(nv_index)
881 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
882 /// # .with_index_attributes(owner_nv_index_attributes)
883 /// # .with_data_area_size(32)
884 /// # .build()
885 /// # .expect("Failed to build NvPublic for owner");
886 /// #
887 /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7])
888 /// .expect("Failed to create MaxNvBuffer from vec");
889 ///
890 /// let nv_index_handle = context
891 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
892 /// .expect("Call to nv_define_space failed");
893 ///
894 /// // Write data using owner authorization
895 /// let nv_write_result = context.nv_write(NvAuth::Owner, nv_index_handle, data.clone(), 0);
896 ///
897 /// // Read data using owner authorization
898 /// let data_len = u16::try_from(data.len()).expect("Failed to retrieve length of data");
899 /// let nv_read_result = context
900 /// .nv_read(NvAuth::Owner, nv_index_handle, data_len, 0);
901 ///
902 /// context
903 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
904 /// .expect("Call to nv_undefine_space failed");
905 ///
906 /// // Process result
907 /// nv_write_result.expect("Call to nv_write failed");
908 /// let read_data = nv_read_result.expect("Call to nv_read failed");
909 /// assert_eq!(data, read_data);
910 /// ```
911 pub fn nv_read(
912 &mut self,
913 auth_handle: NvAuth,
914 nv_index_handle: NvIndexHandle,
915 size: u16,
916 offset: u16,
917 ) -> Result<MaxNvBuffer> {
918 let mut data_ptr = null_mut();
919 ReturnCode::ensure_success(
920 unsafe {
921 Esys_NV_Read(
922 self.mut_context(),
923 AuthHandle::from(auth_handle).into(),
924 nv_index_handle.into(),
925 self.required_session_1()?,
926 self.optional_session_2(),
927 self.optional_session_3(),
928 size,
929 offset,
930 &mut data_ptr,
931 )
932 },
933 |ret| {
934 error!("Error when reading NV: {:#010X}", ret);
935 },
936 )?;
937 MaxNvBuffer::try_from(Context::ffi_data_to_owned(data_ptr)?)
938 }
939
940 // Missing function: NV_ReadLock
941 // Missing function: NV_ChangeAuth
942 // Missing function: NV_Certify
943}