tpm.rs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. use super::*;
  2. use std::{
  3. io::{Read, Write},
  4. os::{
  5. raw::c_char,
  6. unix::fs::PermissionsExt,
  7. },
  8. ffi::CStr,
  9. path::Path,
  10. fs::{File, OpenOptions},
  11. sync::{Arc, Mutex},
  12. mem::size_of,
  13. };
  14. use openssl::{
  15. bn::BigNum,
  16. hash::Hasher,
  17. nid::Nid,
  18. };
  19. use tss_esapi_sys::{
  20. TSS2_RC,
  21. TPMT_TK_HASHCHECK,
  22. TPM2_HANDLE,
  23. TPM2_MAX_CAP_BUFFER,
  24. TPM2_CAP
  25. };
  26. use tss_esapi::{
  27. Context,
  28. constants::{
  29. session_type::SessionType,
  30. response_code::Tss2ResponseCode,
  31. tss::{TPM2_RH_NULL, TPM2_PERSISTENT_FIRST},
  32. CapabilityType,
  33. },
  34. tcti_ldr::{TctiNameConf, TabrmdConfig},
  35. interface_types::{
  36. resource_handles::Hierarchy,
  37. algorithm::HashingAlgorithm,
  38. key_bits::RsaKeyBits,
  39. dynamic_handles::Persistent,
  40. },
  41. structures::{
  42. Digest,
  43. HashScheme,
  44. Public,
  45. PublicRsaParameters,
  46. SymmetricDefinition,
  47. SymmetricDefinitionObject,
  48. PublicKeyRsa,
  49. RsaScheme,
  50. RsaExponent,
  51. HashcheckTicket,
  52. Ticket,
  53. SignatureScheme,
  54. RsaDecryptionScheme,
  55. Data,
  56. CapabilityData,
  57. },
  58. attributes::{
  59. object::ObjectAttributes,
  60. },
  61. handles::{KeyHandle, PersistentTpmHandle},
  62. };
  63. impl From<tss_esapi::Error> for Error {
  64. fn from(err: tss_esapi::Error) -> Self {
  65. match err {
  66. tss_esapi::Error::WrapperError(err) => Error::custom(err),
  67. tss_esapi::Error::Tss2Error(err) => {
  68. let rc = err.tss2_rc();
  69. let text = tss2_rc_decode(err);
  70. let string = format!("response code: {}, response text: {}", rc, text);
  71. Error::custom(string)
  72. }
  73. }
  74. }
  75. }
  76. impl<Guard> From<std::sync::PoisonError<Guard>> for Error {
  77. fn from(error: std::sync::PoisonError<Guard>) -> Self {
  78. Error::custom(error.to_string())
  79. }
  80. }
  81. trait ContextExt {
  82. fn persistent_handles(&mut self) -> Result<Vec<PersistentTpmHandle>>;
  83. /// Returns the first free persistent handle available in the TPM.
  84. fn first_free_persistent(&mut self) -> Result<Persistent> {
  85. let mut handles = self.persistent_handles()?;
  86. let handle = handles.pop()
  87. .map_or_else(
  88. || PersistentTpmHandle::try_from(TPM2_PERSISTENT_FIRST),
  89. |v| PersistentTpmHandle::new(TPM2_HANDLE::from(v)+ 1))
  90. .conv_err()?;
  91. Ok(Persistent::Persistent(handle))
  92. }
  93. }
  94. impl ContextExt for Context {
  95. fn persistent_handles(&mut self) -> Result<Vec<PersistentTpmHandle>> {
  96. let capability= CapabilityType::Handles;
  97. let property = TPM2_PERSISTENT_FIRST;
  98. let max = usize::try_from(TPM2_MAX_CAP_BUFFER).unwrap();
  99. let count = (max - size_of::<TPM2_CAP>() - size_of::<u32>()) / size_of::<TPM2_HANDLE>();
  100. let property_count = u32::try_from(count).unwrap();
  101. let mut all_handles = Vec::new();
  102. loop {
  103. let (handles, more) = self.get_capability(capability, property, property_count)
  104. .unwrap();
  105. let list = match handles {
  106. CapabilityData::Handles(list) => list.into_inner(),
  107. _ => panic!("Unexpected capability type returned by TPM: {:?}", handles),
  108. };
  109. for handle in list {
  110. all_handles.push(PersistentTpmHandle::try_from(handle).conv_err()?);
  111. }
  112. if !more {
  113. break;
  114. }
  115. }
  116. Ok(all_handles)
  117. }
  118. }
  119. const COOKIE_LEN: usize = RSA_KEY_BYTES;
  120. struct Cookie([u8; COOKIE_LEN]);
  121. impl Cookie {
  122. fn random() -> Result<Cookie> {
  123. Ok(Cookie(rand_array()?))
  124. }
  125. fn empty() -> Cookie {
  126. Cookie([0; COOKIE_LEN])
  127. }
  128. fn load_or_init<P: AsRef<Path>>(cookie_path: P) -> Result<Cookie> {
  129. let cookie = match OpenOptions::new().read(true).open(&cookie_path) {
  130. Ok(mut file) => {
  131. Cookie::load(&mut file)?
  132. },
  133. Err(error) => {
  134. if std::io::ErrorKind::NotFound != error.kind() {
  135. return Err(Error::from(error));
  136. }
  137. let cookie = Cookie::random()?;
  138. let mut file = OpenOptions::new().write(true).create_new(true).open(&cookie_path)
  139. .conv_err()?;
  140. cookie.save(&mut file)?;
  141. cookie
  142. }
  143. };
  144. Ok(cookie)
  145. }
  146. fn as_slice(&self) -> &[u8] {
  147. self.0.as_slice()
  148. }
  149. fn as_mut_slice(&mut self) -> &mut [u8] {
  150. self.0.as_mut_slice()
  151. }
  152. fn save(&self, to: &mut File) -> Result<()> {
  153. to.write_all(self.as_slice()).conv_err()?;
  154. // Only allow read access from the current user.
  155. let metadata = to.metadata().conv_err()?;
  156. let mut permissions = metadata.permissions();
  157. permissions.set_mode(0o400);
  158. to.set_permissions(permissions).conv_err()?;
  159. Ok(())
  160. }
  161. fn load(from: &mut File) -> Result<Cookie> {
  162. let mut cookie = Cookie::empty();
  163. from.read_exact(cookie.as_mut_slice()).conv_err()?;
  164. Ok(cookie)
  165. }
  166. }
  167. pub(crate) struct TpmCredStore {
  168. context: Arc<Mutex<Context>>,
  169. cookie: Cookie,
  170. }
  171. impl TpmCredStore {
  172. /// The public exponent to use for generated RSA keys.
  173. const RSA_EXPONENT: u32 = 65537; // 2**16 + 1
  174. const RSA_KEY_BITS: RsaKeyBits = RsaKeyBits::Rsa3072;
  175. pub(crate) fn new<P: AsRef<Path>>(
  176. mut context: Context, cookie_path: P
  177. ) -> Result<TpmCredStore> {
  178. let cookie = Cookie::load_or_init(cookie_path)?;
  179. let session = context.start_auth_session(
  180. None,
  181. None,
  182. None,
  183. SessionType::Hmac,
  184. SymmetricDefinition::AES_256_CFB,
  185. HashingAlgorithm::Sha256,
  186. )
  187. .conv_err()?
  188. .ok_or_else(|| Error::custom("Received invalid session handle"))?;
  189. context.set_sessions((Some(session), None, None));
  190. let context = Arc::new(Mutex::new(context));
  191. Ok(TpmCredStore { context, cookie })
  192. }
  193. fn gen_node_creds(&self) -> Result<TpmCreds> {
  194. let template = {
  195. let object_attributes = ObjectAttributes::builder()
  196. .with_fixed_tpm(true)
  197. .with_fixed_parent(true)
  198. .with_sensitive_data_origin(true)
  199. .with_user_with_auth(true)
  200. .with_decrypt(true)
  201. .with_sign_encrypt(true)
  202. .with_restricted(false)
  203. .build()
  204. .conv_err()?;
  205. let name_hashing_algorithm = HashingAlgorithm::Sha256;
  206. let empty = [0u8; 0];
  207. let auth_policy = Digest::try_from(empty.as_slice()).conv_err()?;
  208. let parameters = PublicRsaParameters::new(
  209. SymmetricDefinitionObject::Null,
  210. RsaScheme::Null,
  211. TpmCredStore::RSA_KEY_BITS,
  212. RsaExponent::try_from(TpmCredStore::RSA_EXPONENT).conv_err()?,
  213. );
  214. let unique = PublicKeyRsa::try_from(self.cookie.as_slice())
  215. .conv_err()?;
  216. Public::Rsa {
  217. object_attributes,
  218. name_hashing_algorithm,
  219. auth_policy,
  220. parameters,
  221. unique,
  222. }
  223. };
  224. let result = {
  225. let mut context = self.context.lock().conv_err()?;
  226. context.create_primary(
  227. Hierarchy::Endorsement,
  228. template,
  229. None,
  230. None,
  231. None,
  232. None,
  233. )
  234. .conv_err()?
  235. };
  236. let public = AsymKeyPub::try_from(result.out_public)?;
  237. Ok(TpmCreds { public, handle: result.key_handle , context: self.context.clone() })
  238. }
  239. }
  240. impl TryFrom<Public> for AsymKeyPub {
  241. type Error = Error;
  242. fn try_from(public: Public) -> Result<AsymKeyPub> {
  243. match public {
  244. Public::Rsa { parameters, unique, .. } => {
  245. let exponent_value = parameters.exponent().value();
  246. let exponent = BigNum::from_u32(exponent_value).conv_err()?;
  247. let modulus = BigNum::from_slice(unique.as_slice()).conv_err()?;
  248. let rsa = Rsa::from_public_components(modulus, exponent).conv_err()?;
  249. let pkey = PKey::from_rsa(rsa).conv_err()?;
  250. Ok(AsymKeyPub { pkey, kind: AsymKeyKind::Rsa })
  251. },
  252. _ => Err(Error::custom("Unsupported key type returned by TPM")),
  253. }
  254. }
  255. }
  256. trait NidExt {
  257. fn sha3_256() -> Nid {
  258. Nid::from_raw(1097)
  259. }
  260. fn sha3_384() -> Nid {
  261. Nid::from_raw(1098)
  262. }
  263. fn sha3_512() -> Nid {
  264. Nid::from_raw(1099)
  265. }
  266. }
  267. impl NidExt for Nid {}
  268. trait MessageDigestExt {
  269. fn hash_algo(&self) -> Result<HashingAlgorithm>;
  270. fn hash_scheme(&self) -> Result<HashScheme> {
  271. Ok(HashScheme::new(self.hash_algo()?))
  272. }
  273. }
  274. impl MessageDigestExt for MessageDigest {
  275. fn hash_algo(&self) -> Result<HashingAlgorithm> {
  276. let nid = self.type_();
  277. let algo =
  278. if Nid::SHA1 == nid {
  279. HashingAlgorithm::Sha1
  280. }
  281. else if Nid::SHA256 == nid {
  282. HashingAlgorithm::Sha256
  283. }
  284. else if Nid::SHA384 == nid {
  285. HashingAlgorithm::Sha384
  286. }
  287. else if Nid::SHA512 == nid {
  288. HashingAlgorithm::Sha512
  289. }
  290. else if Nid::sha3_256() == nid {
  291. HashingAlgorithm::Sha3_256
  292. }
  293. else if Nid::sha3_384() == nid {
  294. HashingAlgorithm::Sha3_384
  295. }
  296. else if Nid::sha3_512() == nid {
  297. HashingAlgorithm::Sha3_512
  298. }
  299. else {
  300. return Err(Error::custom(
  301. format!("Unsupported hash algorithm with NID: {:?}", nid)));
  302. };
  303. Ok(algo)
  304. }
  305. }
  306. trait HashcheckTicketExt {
  307. fn null() -> HashcheckTicket;
  308. }
  309. impl HashcheckTicketExt for HashcheckTicket {
  310. /// Returns the NULL Ticket of the hashcheck type, as defined in part 1 of the TPM spec,
  311. /// clause 4.47.
  312. fn null() -> HashcheckTicket {
  313. let tk = TPMT_TK_HASHCHECK {
  314. tag: HashcheckTicket::POSSIBLE_TAGS[0].into(),
  315. digest: Default::default(),
  316. hierarchy: TPM2_RH_NULL,
  317. };
  318. HashcheckTicket::try_from(tk).unwrap()
  319. }
  320. }
  321. pub(crate) struct TpmCreds {
  322. public: AsymKeyPub,
  323. context: Arc<Mutex<Context>>,
  324. handle: KeyHandle,
  325. }
  326. impl Owned for TpmCreds {
  327. fn owner_of_kind(&self, kind: HashKind) -> Principal {
  328. self.public.owner_of_kind(kind)
  329. }
  330. }
  331. impl Verifier for TpmCreds {
  332. fn verify<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I, signature: &[u8]) -> Result<bool> {
  333. self.public.verify(parts, signature)
  334. }
  335. }
  336. impl Encrypter for TpmCreds {
  337. fn encrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
  338. self.public.encrypt(slice)
  339. }
  340. }
  341. impl CredsPub for TpmCreds {}
  342. impl Signer for TpmCreds {
  343. fn sign<'a, I: Iterator<Item=&'a [u8]>>(&self, parts: I) -> Result<Signature> {
  344. let msg_digest = self.public.digest();
  345. let digest = {
  346. let mut hasher = Hasher::new(msg_digest).conv_err()?;
  347. for part in parts {
  348. hasher.update(part).conv_err()?;
  349. }
  350. let bytes = hasher.finish().conv_err()?;
  351. let slice: &[u8] = &bytes;
  352. Digest::try_from(slice).conv_err()?
  353. };
  354. let validation = HashcheckTicket::null();
  355. let scheme = SignatureScheme::RsaSsa { hash_scheme: msg_digest.hash_scheme()? };
  356. let sig = {
  357. let mut context = self.context.lock().conv_err()?;
  358. context.sign(self.handle, digest, scheme, validation)
  359. .conv_err()?
  360. };
  361. let buf = match sig {
  362. tss_esapi::structures::Signature::RsaSsa(inner) => {
  363. let mut buf = [0u8; RSA_KEY_BYTES];
  364. let slice: &[u8] = inner.signature();
  365. buf.as_mut_slice().write_all(slice).conv_err()?;
  366. buf
  367. },
  368. _ => return Err(Error::custom(format!("Unexpected signature type: {:?}", sig))),
  369. };
  370. Ok(Signature::Rsa(buf))
  371. }
  372. }
  373. impl Decrypter for TpmCreds {
  374. fn decrypt(&self, slice: &[u8]) -> Result<Vec<u8>> {
  375. let cipher_text = PublicKeyRsa::try_from(slice).conv_err()?;
  376. let in_scheme = RsaDecryptionScheme::RsaEs;
  377. let empty = [0u8; 0];
  378. let label = Data::try_from(empty.as_slice()).conv_err()?;
  379. let plain_text = {
  380. let mut lock = self.context.lock().conv_err()?;
  381. lock.rsa_decrypt(self.handle, cipher_text, in_scheme, label)?
  382. };
  383. Ok(Vec::from(plain_text.value()))
  384. }
  385. }
  386. impl CredsPriv for TpmCreds {}
  387. impl Creds for TpmCreds {
  388. fn public(&self) -> &AsymKeyPub {
  389. &self.public
  390. }
  391. }
  392. trait TctiNameConfExt {
  393. fn default() -> TctiNameConf;
  394. }
  395. impl TctiNameConfExt for TctiNameConf {
  396. /// Returns a configuration which specifies that Tabrmd should be connected to using the system
  397. /// DBus.
  398. fn default() -> TctiNameConf {
  399. TctiNameConf::Tabrmd(TabrmdConfig::default())
  400. }
  401. }
  402. #[link(name = "tss2-rc")]
  403. extern {
  404. fn Tss2_RC_Decode(rc: TSS2_RC) -> *const c_char;
  405. }
  406. /// Interface for types which can be converted to TSS2 response codes.
  407. trait HasResponseCode {
  408. /// Returns the TSS2 response code associated with this instance.
  409. fn tss2_rc(&self) -> TSS2_RC;
  410. }
  411. /// Returns the error message associated with the given TSS2 response code.
  412. fn tss2_rc_decode<E: HasResponseCode>(err: E) -> &'static str {
  413. let c_str = unsafe {
  414. let ptr = Tss2_RC_Decode(err.tss2_rc());
  415. CStr::from_ptr(ptr)
  416. };
  417. // We're relying on Tss2_RC_Decode to return valid C strings.
  418. c_str.to_str().unwrap()
  419. }
  420. impl HasResponseCode for Tss2ResponseCode {
  421. fn tss2_rc(&self) -> TSS2_RC {
  422. match self {
  423. Tss2ResponseCode::Success => 0,
  424. Tss2ResponseCode::FormatZero(code) => code.0,
  425. Tss2ResponseCode::FormatOne(code) => code.0,
  426. }
  427. }
  428. }
  429. impl HasResponseCode for TSS2_RC {
  430. fn tss2_rc(&self) -> TSS2_RC {
  431. *self
  432. }
  433. }
  434. #[cfg(test)]
  435. mod test {
  436. use super::*;
  437. use tempdir::TempDir;
  438. use std::{
  439. fs::File,
  440. };
  441. use tss_esapi::{
  442. interface_types::{
  443. ecc::EccCurve,
  444. },
  445. structures::{
  446. EccPoint,
  447. EccScheme,
  448. KeyDerivationFunctionScheme,
  449. PublicEccParameters,
  450. }
  451. };
  452. use ctor::ctor;
  453. trait TestContextExt {
  454. fn for_test() -> Result<Context>;
  455. }
  456. impl TestContextExt for Context {
  457. fn for_test() -> Result<Context> {
  458. let config = TabrmdConfig::from_str("bus_type=session").conv_err()?;
  459. Context::new(TctiNameConf::Tabrmd(config)).conv_err()
  460. }
  461. }
  462. #[ctor]
  463. fn ctor() {
  464. env_logger::init();
  465. }
  466. /// Displays the message associated with a TSS2 return code.
  467. //#[test]
  468. fn print_error_message() {
  469. const RC: TSS2_RC = 0x00000101;
  470. let msg = tss2_rc_decode(RC);
  471. println!("{}", msg);
  472. }
  473. #[test]
  474. fn create_context() {
  475. let mut context = Context::for_test().unwrap();
  476. context.self_test(true).unwrap();
  477. }
  478. #[test]
  479. fn create_primary_key() {
  480. let mut context = Context::for_test().unwrap();
  481. let public = {
  482. let object_attributes = ObjectAttributes::builder()
  483. .with_fixed_tpm(true)
  484. .with_fixed_parent(true)
  485. .with_sensitive_data_origin(true)
  486. .with_user_with_auth(true)
  487. .with_decrypt(false)
  488. .with_sign_encrypt(true)
  489. .with_restricted(false)
  490. .build()
  491. .expect("ObjectAttributesBuilder failed");
  492. let name_hashing_algorithm = HashingAlgorithm::Sha256;
  493. let empty = [0u8; 0];
  494. let auth_policy = Digest::try_from(empty.as_slice()).unwrap();
  495. let parameters = PublicEccParameters::new(
  496. SymmetricDefinitionObject::Null,
  497. EccScheme::EcDsa(HashScheme::new(HashingAlgorithm::Sha256)),
  498. EccCurve::NistP256,
  499. KeyDerivationFunctionScheme::Null
  500. );
  501. Public::Ecc {
  502. object_attributes,
  503. name_hashing_algorithm,
  504. auth_policy,
  505. parameters,
  506. unique: EccPoint::default(),
  507. }
  508. };
  509. let session = context.start_auth_session(
  510. None,
  511. None,
  512. None,
  513. SessionType::Hmac,
  514. SymmetricDefinition::AES_256_CFB,
  515. HashingAlgorithm::Sha256,
  516. )
  517. .conv_err()
  518. .expect("Failed to create session")
  519. .expect("Received invalid handle");
  520. context.execute_with_session(Some(session), |ctx| {
  521. let primary = ctx.create_primary(
  522. Hierarchy::Null,
  523. public,
  524. None,
  525. None,
  526. None,
  527. None,
  528. )
  529. .conv_err()
  530. .expect("create_primary failed")
  531. .key_handle;
  532. ctx.flush_context(primary.into()).expect("flush_context failed");
  533. });
  534. }
  535. /// Tests that a TPM Credential Store can be created when a cookie does not already exist.
  536. #[test]
  537. fn tpm_cred_store_new() -> Result<()> {
  538. let dir = TempDir::new("btnode").conv_err()?;
  539. let cookie_path = dir.path().join("cookie.bin");
  540. let store = TpmCredStore::new(Context::for_test()?, &cookie_path)?;
  541. let cookie = File::open(&cookie_path).conv_err()?;
  542. let metadata = cookie.metadata().conv_err()?;
  543. let actual = metadata.permissions().mode();
  544. // Assert that the cookie can only be read by its owner.
  545. assert_eq!(0o400, 0o777 & actual);
  546. drop(store);
  547. dir.close()?;
  548. Ok(())
  549. }
  550. #[test]
  551. fn gen_creds() -> Result<()> {
  552. let dir = TempDir::new("btnode").conv_err()?;
  553. let cookie_path = dir.path().join("cookie.bin");
  554. let store = TpmCredStore::new(Context::for_test()?, &cookie_path)?;
  555. store.gen_node_creds()?;
  556. Ok(())
  557. }
  558. /// Displays the numeric identifiers used by the supported hash algorithms.
  559. fn show_nids() {
  560. fn show_nid(digest: MessageDigest) {
  561. let nid = digest.type_();
  562. println!("{}: {:?}", nid.long_name().unwrap(), nid);
  563. }
  564. show_nid(MessageDigest::sha1());
  565. show_nid(MessageDigest::sha256());
  566. show_nid(MessageDigest::sha384());
  567. show_nid(MessageDigest::sha512());
  568. show_nid(MessageDigest::sha3_256());
  569. show_nid(MessageDigest::sha3_384());
  570. show_nid(MessageDigest::sha3_512());
  571. }
  572. /// Verifies that the NIDs returned by the supported hash algorithms are as expected.
  573. #[test]
  574. fn verify_expected_nids() {
  575. fn assert_eq(digest: MessageDigest, nid: Nid) {
  576. assert_eq!(digest.type_(), nid);
  577. }
  578. assert_eq(MessageDigest::sha1(), Nid::SHA1);
  579. assert_eq(MessageDigest::sha256(), Nid::SHA256);
  580. assert_eq(MessageDigest::sha384(), Nid::SHA384);
  581. assert_eq(MessageDigest::sha512(), Nid::SHA512);
  582. assert_eq(MessageDigest::sha3_256(), Nid::sha3_256());
  583. assert_eq(MessageDigest::sha3_384(), Nid::sha3_384());
  584. assert_eq(MessageDigest::sha3_512(), Nid::sha3_512());
  585. }
  586. fn test_store() -> Result<TpmCredStore> {
  587. let dir = TempDir::new("btnode").conv_err()?;
  588. let cookie_path = dir.path().join("cookie.bin");
  589. let store = TpmCredStore::new(Context::for_test()?, &cookie_path)?;
  590. dir.close()?;
  591. Ok(store)
  592. }
  593. #[test]
  594. fn tpm_sign_verify() -> Result<()> {
  595. let store = test_store()?;
  596. let handle = store.gen_node_creds()?;
  597. let data: [u8; 1024] = rand_array()?;
  598. let parts = [data.as_slice()];
  599. let sig = handle.sign(parts.into_iter())?;
  600. assert!(handle.verify(parts.into_iter(), sig.as_slice())?);
  601. Ok(())
  602. }
  603. #[test]
  604. fn tpm_encrypt_decrypt() -> Result<()> {
  605. let store = test_store()?;
  606. let handle = store.gen_node_creds()?;
  607. let expected: [u8; RSA_KEY_BYTES / 2] = rand_array()?;
  608. let ct = handle.encrypt(expected.as_slice())?;
  609. let actual = handle.decrypt(&ct)?;
  610. assert_eq!(expected.as_slice(), actual);
  611. Ok(())
  612. }
  613. /// Tests that `HashcheckTicket::null` doesn't panic.
  614. #[test]
  615. fn hashcheck_null() {
  616. HashcheckTicket::null();
  617. }
  618. /// Checks that the value of `TpmCredStore::RSA_KEY_BITS` matches the value of `RSA_KEY_BYTES`.
  619. #[test]
  620. fn rsa_key_bits_and_key_bytes_compatible() {
  621. let bytes = match TpmCredStore::RSA_KEY_BITS {
  622. RsaKeyBits::Rsa1024 => 128,
  623. RsaKeyBits::Rsa2048 => 256,
  624. RsaKeyBits::Rsa3072 => 384,
  625. RsaKeyBits::Rsa4096 => 512,
  626. };
  627. assert_eq!(RSA_KEY_BYTES, bytes)
  628. }
  629. fn list_persistent_handles() {
  630. let mut context = Context::for_test().unwrap();
  631. let all_handles = context.persistent_handles().unwrap();
  632. for handle in all_handles.iter() {
  633. println!("{:?}", handle);
  634. }
  635. }
  636. }