1use std::path::{Path, PathBuf};
38use std::sync::Mutex;
39
40use bytes::Bytes;
41use ndn_packet::{Name, NameComponent, tlv_type};
42use ndn_tlv::{TlvReader, TlvWriter};
43use rusqlite::{Connection, OpenFlags, OptionalExtension, params};
44
45use crate::pib::PibError;
46
47const DB_INIT: &str = r#"
54CREATE TABLE IF NOT EXISTS
55 tpmInfo(
56 tpm_locator BLOB
57 );
58
59CREATE TABLE IF NOT EXISTS
60 identities(
61 id INTEGER PRIMARY KEY,
62 identity BLOB NOT NULL,
63 is_default INTEGER DEFAULT 0
64 );
65
66CREATE UNIQUE INDEX IF NOT EXISTS
67 identityIndex ON identities(identity);
68
69CREATE TRIGGER IF NOT EXISTS
70 identity_default_before_insert_trigger
71 BEFORE INSERT ON identities
72 FOR EACH ROW
73 WHEN NEW.is_default=1
74 BEGIN
75 UPDATE identities SET is_default=0;
76 END;
77
78CREATE TRIGGER IF NOT EXISTS
79 identity_default_after_insert_trigger
80 AFTER INSERT ON identities
81 FOR EACH ROW
82 WHEN NOT EXISTS
83 (SELECT id
84 FROM identities
85 WHERE is_default=1)
86 BEGIN
87 UPDATE identities
88 SET is_default=1
89 WHERE identity=NEW.identity;
90 END;
91
92CREATE TRIGGER IF NOT EXISTS
93 identity_default_update_trigger
94 BEFORE UPDATE ON identities
95 FOR EACH ROW
96 WHEN NEW.is_default=1 AND OLD.is_default=0
97 BEGIN
98 UPDATE identities SET is_default=0;
99 END;
100
101CREATE TABLE IF NOT EXISTS
102 keys(
103 id INTEGER PRIMARY KEY,
104 identity_id INTEGER NOT NULL,
105 key_name BLOB NOT NULL,
106 key_bits BLOB NOT NULL,
107 is_default INTEGER DEFAULT 0,
108 FOREIGN KEY(identity_id)
109 REFERENCES identities(id)
110 ON DELETE CASCADE
111 ON UPDATE CASCADE
112 );
113
114CREATE UNIQUE INDEX IF NOT EXISTS
115 keyIndex ON keys(key_name);
116
117CREATE TRIGGER IF NOT EXISTS
118 key_default_before_insert_trigger
119 BEFORE INSERT ON keys
120 FOR EACH ROW
121 WHEN NEW.is_default=1
122 BEGIN
123 UPDATE keys
124 SET is_default=0
125 WHERE identity_id=NEW.identity_id;
126 END;
127
128CREATE TRIGGER IF NOT EXISTS
129 key_default_after_insert_trigger
130 AFTER INSERT ON keys
131 FOR EACH ROW
132 WHEN NOT EXISTS
133 (SELECT id
134 FROM keys
135 WHERE is_default=1
136 AND identity_id=NEW.identity_id)
137 BEGIN
138 UPDATE keys
139 SET is_default=1
140 WHERE key_name=NEW.key_name;
141 END;
142
143CREATE TRIGGER IF NOT EXISTS
144 key_default_update_trigger
145 BEFORE UPDATE ON keys
146 FOR EACH ROW
147 WHEN NEW.is_default=1 AND OLD.is_default=0
148 BEGIN
149 UPDATE keys
150 SET is_default=0
151 WHERE identity_id=NEW.identity_id;
152 END;
153
154CREATE TABLE IF NOT EXISTS
155 certificates(
156 id INTEGER PRIMARY KEY,
157 key_id INTEGER NOT NULL,
158 certificate_name BLOB NOT NULL,
159 certificate_data BLOB NOT NULL,
160 is_default INTEGER DEFAULT 0,
161 FOREIGN KEY(key_id)
162 REFERENCES keys(id)
163 ON DELETE CASCADE
164 ON UPDATE CASCADE
165 );
166
167CREATE UNIQUE INDEX IF NOT EXISTS
168 certIndex ON certificates(certificate_name);
169
170CREATE TRIGGER IF NOT EXISTS
171 cert_default_before_insert_trigger
172 BEFORE INSERT ON certificates
173 FOR EACH ROW
174 WHEN NEW.is_default=1
175 BEGIN
176 UPDATE certificates
177 SET is_default=0
178 WHERE key_id=NEW.key_id;
179 END;
180
181CREATE TRIGGER IF NOT EXISTS
182 cert_default_after_insert_trigger
183 AFTER INSERT ON certificates
184 FOR EACH ROW
185 WHEN NOT EXISTS
186 (SELECT id
187 FROM certificates
188 WHERE is_default=1
189 AND key_id=NEW.key_id)
190 BEGIN
191 UPDATE certificates
192 SET is_default=1
193 WHERE certificate_name=NEW.certificate_name;
194 END;
195
196CREATE TRIGGER IF NOT EXISTS
197 cert_default_update_trigger
198 BEFORE UPDATE ON certificates
199 FOR EACH ROW
200 WHEN NEW.is_default=1 AND OLD.is_default=0
201 BEGIN
202 UPDATE certificates
203 SET is_default=0
204 WHERE key_id=NEW.key_id;
205 END;
206"#;
207
208fn name_wire_encode(name: &Name) -> Vec<u8> {
215 let mut w = TlvWriter::new();
216 w.write_nested(tlv_type::NAME, |w| {
217 for c in name.components() {
218 w.write_tlv(c.typ, &c.value);
219 }
220 });
221 w.finish().to_vec()
222}
223
224fn name_wire_decode(blob: &[u8]) -> Result<Name, PibError> {
227 let mut reader = TlvReader::new(Bytes::copy_from_slice(blob));
228 let (typ, value) = reader
229 .read_tlv()
230 .map_err(|e| PibError::Corrupt(format!("name TLV: {e:?}")))?;
231 if typ != tlv_type::NAME {
232 return Err(PibError::Corrupt(format!(
233 "expected Name TLV (0x07), got 0x{typ:x}"
234 )));
235 }
236 Name::decode(value).map_err(|e| PibError::Corrupt(format!("name body: {e:?}")))
237}
238
239pub struct SqlitePib {
247 conn: Mutex<Connection>,
248 path: PathBuf,
249}
250
251impl SqlitePib {
252 pub fn open(path: impl AsRef<Path>) -> Result<Self, PibError> {
257 let path = path.as_ref().to_path_buf();
258 if let Some(parent) = path.parent() {
259 std::fs::create_dir_all(parent)?;
260 }
261 let conn = Connection::open_with_flags(
262 &path,
263 OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_CREATE,
264 )
265 .map_err(map_sqlite_err)?;
266
267 conn.execute_batch("PRAGMA foreign_keys=ON;")
272 .map_err(map_sqlite_err)?;
273
274 conn.execute_batch(DB_INIT).map_err(map_sqlite_err)?;
277
278 Ok(Self {
279 conn: Mutex::new(conn),
280 path,
281 })
282 }
283
284 pub fn open_default() -> Result<Self, PibError> {
289 let dir = if let Ok(p) = std::env::var("TEST_HOME") {
290 PathBuf::from(p).join(".ndn")
291 } else if let Ok(p) = std::env::var("HOME") {
292 PathBuf::from(p).join(".ndn")
293 } else {
294 std::env::current_dir()?.join(".ndn")
295 };
296 Self::open(dir.join("pib.db"))
297 }
298
299 pub fn path(&self) -> &Path {
301 &self.path
302 }
303
304 pub fn get_tpm_locator(&self) -> Result<Option<String>, PibError> {
310 let conn = self.conn.lock().expect("sqlite mutex poisoned");
311 let row = conn
312 .query_row("SELECT tpm_locator FROM tpmInfo", [], |row| {
313 row.get::<_, Vec<u8>>(0)
314 })
315 .optional()
316 .map_err(map_sqlite_err)?;
317 Ok(row.map(|bytes| String::from_utf8_lossy(&bytes).into_owned()))
318 }
319
320 pub fn set_tpm_locator(&self, locator: &str) -> Result<(), PibError> {
324 let conn = self.conn.lock().expect("sqlite mutex poisoned");
325 let updated = conn
326 .execute(
327 "UPDATE tpmInfo SET tpm_locator=?",
328 params![locator.as_bytes()],
329 )
330 .map_err(map_sqlite_err)?;
331 if updated == 0 {
332 conn.execute(
333 "INSERT INTO tpmInfo (tpm_locator) VALUES (?)",
334 params![locator.as_bytes()],
335 )
336 .map_err(map_sqlite_err)?;
337 }
338 Ok(())
339 }
340
341 pub fn add_identity(&self, identity: &Name) -> Result<(), PibError> {
347 let conn = self.conn.lock().expect("sqlite mutex poisoned");
348 let blob = name_wire_encode(identity);
349 let existing: Option<i64> = conn
350 .query_row(
351 "SELECT id FROM identities WHERE identity=?",
352 params![blob],
353 |row| row.get(0),
354 )
355 .optional()
356 .map_err(map_sqlite_err)?;
357 if existing.is_none() {
358 conn.execute(
359 "INSERT INTO identities (identity) VALUES (?)",
360 params![blob],
361 )
362 .map_err(map_sqlite_err)?;
363 }
364 Ok(())
365 }
366
367 pub fn has_identity(&self, identity: &Name) -> Result<bool, PibError> {
369 let conn = self.conn.lock().expect("sqlite mutex poisoned");
370 let blob = name_wire_encode(identity);
371 Ok(conn
372 .query_row(
373 "SELECT id FROM identities WHERE identity=?",
374 params![blob],
375 |row| row.get::<_, i64>(0),
376 )
377 .optional()
378 .map_err(map_sqlite_err)?
379 .is_some())
380 }
381
382 pub fn delete_identity(&self, identity: &Name) -> Result<(), PibError> {
385 let conn = self.conn.lock().expect("sqlite mutex poisoned");
386 let blob = name_wire_encode(identity);
387 conn.execute("DELETE FROM identities WHERE identity=?", params![blob])
388 .map_err(map_sqlite_err)?;
389 Ok(())
390 }
391
392 pub fn list_identities(&self) -> Result<Vec<Name>, PibError> {
394 let conn = self.conn.lock().expect("sqlite mutex poisoned");
395 let mut stmt = conn
396 .prepare("SELECT identity FROM identities")
397 .map_err(map_sqlite_err)?;
398 let rows = stmt
399 .query_map([], |row| row.get::<_, Vec<u8>>(0))
400 .map_err(map_sqlite_err)?;
401 let mut out = Vec::new();
402 for row in rows {
403 let blob = row.map_err(map_sqlite_err)?;
404 out.push(name_wire_decode(&blob)?);
405 }
406 Ok(out)
407 }
408
409 pub fn set_default_identity(&self, identity: &Name) -> Result<(), PibError> {
413 let conn = self.conn.lock().expect("sqlite mutex poisoned");
414 let blob = name_wire_encode(identity);
415 let updated = conn
416 .execute(
417 "UPDATE identities SET is_default=1 WHERE identity=?",
418 params![blob],
419 )
420 .map_err(map_sqlite_err)?;
421 if updated == 0 {
422 return Err(PibError::KeyNotFound(name_to_string(identity)));
423 }
424 Ok(())
425 }
426
427 pub fn get_default_identity(&self) -> Result<Option<Name>, PibError> {
429 let conn = self.conn.lock().expect("sqlite mutex poisoned");
430 let blob: Option<Vec<u8>> = conn
431 .query_row(
432 "SELECT identity FROM identities WHERE is_default=1",
433 [],
434 |row| row.get(0),
435 )
436 .optional()
437 .map_err(map_sqlite_err)?;
438 Ok(match blob {
439 Some(b) => Some(name_wire_decode(&b)?),
440 None => None,
441 })
442 }
443
444 pub fn add_key(
451 &self,
452 identity: &Name,
453 key_name: &Name,
454 key_bits: &[u8],
455 ) -> Result<(), PibError> {
456 let conn = self.conn.lock().expect("sqlite mutex poisoned");
457 let id_blob = name_wire_encode(identity);
458 let key_blob = name_wire_encode(key_name);
459 let existing: Option<i64> = conn
462 .query_row(
463 "SELECT id FROM identities WHERE identity=?",
464 params![id_blob],
465 |row| row.get(0),
466 )
467 .optional()
468 .map_err(map_sqlite_err)?;
469 if existing.is_none() {
470 conn.execute(
471 "INSERT INTO identities (identity) VALUES (?)",
472 params![id_blob],
473 )
474 .map_err(map_sqlite_err)?;
475 }
476
477 let key_exists: Option<i64> = conn
480 .query_row(
481 "SELECT id FROM keys WHERE key_name=?",
482 params![key_blob],
483 |row| row.get(0),
484 )
485 .optional()
486 .map_err(map_sqlite_err)?;
487 if key_exists.is_some() {
488 conn.execute(
489 "UPDATE keys SET key_bits=? WHERE key_name=?",
490 params![key_bits, key_blob],
491 )
492 .map_err(map_sqlite_err)?;
493 } else {
494 conn.execute(
495 "INSERT INTO keys (identity_id, key_name, key_bits) \
496 VALUES ((SELECT id FROM identities WHERE identity=?), ?, ?)",
497 params![id_blob, key_blob, key_bits],
498 )
499 .map_err(map_sqlite_err)?;
500 }
501 Ok(())
502 }
503
504 pub fn get_key_bits(&self, key_name: &Name) -> Result<Option<Vec<u8>>, PibError> {
506 let conn = self.conn.lock().expect("sqlite mutex poisoned");
507 let blob = name_wire_encode(key_name);
508 conn.query_row(
509 "SELECT key_bits FROM keys WHERE key_name=?",
510 params![blob],
511 |row| row.get(0),
512 )
513 .optional()
514 .map_err(map_sqlite_err)
515 }
516
517 pub fn delete_key(&self, key_name: &Name) -> Result<(), PibError> {
519 let conn = self.conn.lock().expect("sqlite mutex poisoned");
520 let blob = name_wire_encode(key_name);
521 conn.execute("DELETE FROM keys WHERE key_name=?", params![blob])
522 .map_err(map_sqlite_err)?;
523 Ok(())
524 }
525
526 pub fn list_keys(&self, identity: &Name) -> Result<Vec<Name>, PibError> {
528 let conn = self.conn.lock().expect("sqlite mutex poisoned");
529 let blob = name_wire_encode(identity);
530 let mut stmt = conn
531 .prepare(
532 "SELECT key_name FROM keys \
533 JOIN identities ON keys.identity_id=identities.id \
534 WHERE identities.identity=?",
535 )
536 .map_err(map_sqlite_err)?;
537 let rows = stmt
538 .query_map(params![blob], |row| row.get::<_, Vec<u8>>(0))
539 .map_err(map_sqlite_err)?;
540 let mut out = Vec::new();
541 for row in rows {
542 let kb = row.map_err(map_sqlite_err)?;
543 out.push(name_wire_decode(&kb)?);
544 }
545 Ok(out)
546 }
547
548 pub fn set_default_key(&self, key_name: &Name) -> Result<(), PibError> {
550 let conn = self.conn.lock().expect("sqlite mutex poisoned");
551 let blob = name_wire_encode(key_name);
552 let updated = conn
553 .execute(
554 "UPDATE keys SET is_default=1 WHERE key_name=?",
555 params![blob],
556 )
557 .map_err(map_sqlite_err)?;
558 if updated == 0 {
559 return Err(PibError::KeyNotFound(name_to_string(key_name)));
560 }
561 Ok(())
562 }
563
564 pub fn get_default_key(&self, identity: &Name) -> Result<Option<Name>, PibError> {
566 let conn = self.conn.lock().expect("sqlite mutex poisoned");
567 let blob = name_wire_encode(identity);
568 let row: Option<Vec<u8>> = conn
569 .query_row(
570 "SELECT key_name FROM keys \
571 JOIN identities ON keys.identity_id=identities.id \
572 WHERE identities.identity=? AND keys.is_default=1",
573 params![blob],
574 |row| row.get(0),
575 )
576 .optional()
577 .map_err(map_sqlite_err)?;
578 Ok(match row {
579 Some(b) => Some(name_wire_decode(&b)?),
580 None => None,
581 })
582 }
583
584 pub fn add_certificate(
590 &self,
591 key_name: &Name,
592 cert_name: &Name,
593 cert_data: &[u8],
594 ) -> Result<(), PibError> {
595 let conn = self.conn.lock().expect("sqlite mutex poisoned");
596 let key_blob = name_wire_encode(key_name);
597 let cert_blob = name_wire_encode(cert_name);
598 let existing: Option<i64> = conn
599 .query_row(
600 "SELECT id FROM certificates WHERE certificate_name=?",
601 params![cert_blob],
602 |row| row.get(0),
603 )
604 .optional()
605 .map_err(map_sqlite_err)?;
606 if existing.is_some() {
607 conn.execute(
608 "UPDATE certificates SET certificate_data=? WHERE certificate_name=?",
609 params![cert_data, cert_blob],
610 )
611 .map_err(map_sqlite_err)?;
612 } else {
613 conn.execute(
614 "INSERT INTO certificates (key_id, certificate_name, certificate_data) \
615 VALUES ((SELECT id FROM keys WHERE key_name=?), ?, ?)",
616 params![key_blob, cert_blob, cert_data],
617 )
618 .map_err(map_sqlite_err)?;
619 }
620 Ok(())
621 }
622
623 pub fn get_certificate(&self, cert_name: &Name) -> Result<Option<Vec<u8>>, PibError> {
625 let conn = self.conn.lock().expect("sqlite mutex poisoned");
626 let blob = name_wire_encode(cert_name);
627 conn.query_row(
628 "SELECT certificate_data FROM certificates WHERE certificate_name=?",
629 params![blob],
630 |row| row.get(0),
631 )
632 .optional()
633 .map_err(map_sqlite_err)
634 }
635
636 pub fn delete_certificate(&self, cert_name: &Name) -> Result<(), PibError> {
638 let conn = self.conn.lock().expect("sqlite mutex poisoned");
639 let blob = name_wire_encode(cert_name);
640 conn.execute(
641 "DELETE FROM certificates WHERE certificate_name=?",
642 params![blob],
643 )
644 .map_err(map_sqlite_err)?;
645 Ok(())
646 }
647
648 pub fn list_certificates(&self, key_name: &Name) -> Result<Vec<Name>, PibError> {
650 let conn = self.conn.lock().expect("sqlite mutex poisoned");
651 let blob = name_wire_encode(key_name);
652 let mut stmt = conn
653 .prepare(
654 "SELECT certificate_name FROM certificates \
655 JOIN keys ON certificates.key_id=keys.id \
656 WHERE keys.key_name=?",
657 )
658 .map_err(map_sqlite_err)?;
659 let rows = stmt
660 .query_map(params![blob], |row| row.get::<_, Vec<u8>>(0))
661 .map_err(map_sqlite_err)?;
662 let mut out = Vec::new();
663 for row in rows {
664 let cb = row.map_err(map_sqlite_err)?;
665 out.push(name_wire_decode(&cb)?);
666 }
667 Ok(out)
668 }
669
670 pub fn set_default_certificate(&self, cert_name: &Name) -> Result<(), PibError> {
672 let conn = self.conn.lock().expect("sqlite mutex poisoned");
673 let blob = name_wire_encode(cert_name);
674 let updated = conn
675 .execute(
676 "UPDATE certificates SET is_default=1 WHERE certificate_name=?",
677 params![blob],
678 )
679 .map_err(map_sqlite_err)?;
680 if updated == 0 {
681 return Err(PibError::CertNotFound(name_to_string(cert_name)));
682 }
683 Ok(())
684 }
685
686 pub fn get_default_certificate(&self, key_name: &Name) -> Result<Option<Vec<u8>>, PibError> {
688 let conn = self.conn.lock().expect("sqlite mutex poisoned");
689 let blob = name_wire_encode(key_name);
690 conn.query_row(
691 "SELECT certificate_data FROM certificates \
692 JOIN keys ON certificates.key_id=keys.id \
693 WHERE certificates.is_default=1 AND keys.key_name=?",
694 params![blob],
695 |row| row.get(0),
696 )
697 .optional()
698 .map_err(map_sqlite_err)
699 }
700}
701
702fn map_sqlite_err(e: rusqlite::Error) -> PibError {
705 PibError::Corrupt(format!("sqlite: {e}"))
706}
707
708fn name_to_string(name: &Name) -> String {
709 let mut s = String::new();
710 for c in name.components() {
711 s.push('/');
712 for &b in c.value.iter() {
714 if b.is_ascii_graphic() && b != b'/' {
715 s.push(b as char);
716 } else {
717 s.push_str(&format!("%{b:02X}"));
718 }
719 }
720 }
721 if s.is_empty() { "/".into() } else { s }
722}
723
724#[allow(dead_code)]
727fn _force_use(_c: NameComponent) {}
728
729#[cfg(test)]
730mod tests {
731 use super::*;
732 use tempfile::tempdir;
733
734 fn comp(s: &'static str) -> NameComponent {
735 NameComponent::generic(Bytes::from_static(s.as_bytes()))
736 }
737 fn name(parts: &[&'static str]) -> Name {
738 Name::from_components(parts.iter().map(|p| comp(p)))
739 }
740
741 #[test]
742 fn wire_roundtrip_through_name_helpers() {
743 let n = name(&["alice", "KEY", "k1"]);
744 let blob = name_wire_encode(&n);
745 assert_eq!(blob[0], 0x07);
747 let decoded = name_wire_decode(&blob).unwrap();
748 assert_eq!(decoded, n);
749 }
750
751 #[test]
752 fn open_creates_schema() {
753 let dir = tempdir().unwrap();
754 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
755 let conn = pib.conn.lock().unwrap();
757 let tables: Vec<String> = conn
758 .prepare("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
759 .unwrap()
760 .query_map([], |row| row.get(0))
761 .unwrap()
762 .map(|r| r.unwrap())
763 .collect();
764 assert_eq!(
765 tables,
766 vec!["certificates", "identities", "keys", "tpmInfo"]
767 );
768 }
769
770 #[test]
771 fn identity_add_list_delete() {
772 let dir = tempdir().unwrap();
773 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
774 let alice = name(&["alice"]);
775 let bob = name(&["bob"]);
776 pib.add_identity(&alice).unwrap();
777 pib.add_identity(&bob).unwrap();
778 pib.add_identity(&alice).unwrap(); let listed = pib.list_identities().unwrap();
780 assert_eq!(listed.len(), 2);
781 assert!(listed.contains(&alice));
782 assert!(listed.contains(&bob));
783 pib.delete_identity(&alice).unwrap();
784 let listed = pib.list_identities().unwrap();
785 assert_eq!(listed, vec![bob]);
786 }
787
788 #[test]
789 fn first_identity_becomes_default_via_trigger() {
790 let dir = tempdir().unwrap();
791 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
792 let alice = name(&["alice"]);
793 pib.add_identity(&alice).unwrap();
794 let def = pib.get_default_identity().unwrap();
797 assert_eq!(def, Some(alice));
798 }
799
800 #[test]
801 fn set_default_identity_clears_previous() {
802 let dir = tempdir().unwrap();
803 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
804 let alice = name(&["alice"]);
805 let bob = name(&["bob"]);
806 pib.add_identity(&alice).unwrap();
807 pib.add_identity(&bob).unwrap();
808 pib.set_default_identity(&bob).unwrap();
811 assert_eq!(pib.get_default_identity().unwrap(), Some(bob));
812 }
813
814 #[test]
815 fn key_under_identity_with_cert() {
816 let dir = tempdir().unwrap();
817 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
818 let alice = name(&["alice"]);
819 let key1 = name(&["alice", "KEY", "k1"]);
820 let cert1 = name(&["alice", "KEY", "k1", "self", "v=1"]);
821 pib.add_identity(&alice).unwrap();
822 pib.add_key(&alice, &key1, &[0xAA; 32]).unwrap();
823 pib.add_certificate(&key1, &cert1, &[0xCC; 64]).unwrap();
824
825 assert_eq!(pib.get_key_bits(&key1).unwrap().unwrap(), vec![0xAA; 32]);
826 assert_eq!(pib.list_keys(&alice).unwrap(), vec![key1.clone()]);
827 assert_eq!(pib.list_certificates(&key1).unwrap(), vec![cert1.clone()]);
828 assert_eq!(pib.get_default_key(&alice).unwrap(), Some(key1.clone()));
829 assert_eq!(
830 pib.get_default_certificate(&key1).unwrap().unwrap(),
831 vec![0xCC; 64]
832 );
833 }
834
835 #[test]
836 fn delete_identity_cascades_to_keys_and_certs() {
837 let dir = tempdir().unwrap();
838 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
839 let alice = name(&["alice"]);
840 let key1 = name(&["alice", "KEY", "k1"]);
841 let cert1 = name(&["alice", "KEY", "k1", "self", "v=1"]);
842 pib.add_identity(&alice).unwrap();
843 pib.add_key(&alice, &key1, &[0xAA; 32]).unwrap();
844 pib.add_certificate(&key1, &cert1, &[0xCC; 64]).unwrap();
845 pib.delete_identity(&alice).unwrap();
846 assert!(pib.get_key_bits(&key1).unwrap().is_none());
848 assert!(pib.get_certificate(&cert1).unwrap().is_none());
849 }
850
851 #[test]
852 fn tpm_locator_roundtrip() {
853 let dir = tempdir().unwrap();
854 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
855 assert_eq!(pib.get_tpm_locator().unwrap(), None);
856 pib.set_tpm_locator("tpm-file:").unwrap();
857 assert_eq!(pib.get_tpm_locator().unwrap(), Some("tpm-file:".into()));
858 pib.set_tpm_locator("tpm-file:/custom/path").unwrap();
860 assert_eq!(
861 pib.get_tpm_locator().unwrap(),
862 Some("tpm-file:/custom/path".into())
863 );
864 }
865
866 #[test]
867 fn reopen_persists_state() {
868 let dir = tempdir().unwrap();
869 let path = dir.path().join("pib.db");
870 let alice = name(&["alice"]);
871 let key1 = name(&["alice", "KEY", "k1"]);
872 {
873 let pib = SqlitePib::open(&path).unwrap();
874 pib.add_identity(&alice).unwrap();
875 pib.add_key(&alice, &key1, &[0xBB; 32]).unwrap();
876 pib.set_tpm_locator("tpm-file:").unwrap();
877 }
878 let pib = SqlitePib::open(&path).unwrap();
879 assert_eq!(pib.list_identities().unwrap(), vec![alice]);
880 assert_eq!(pib.get_key_bits(&key1).unwrap().unwrap(), vec![0xBB; 32]);
881 assert_eq!(pib.get_tpm_locator().unwrap(), Some("tpm-file:".into()));
882 }
883
884 #[test]
885 fn delete_key_cascades_to_certs() {
886 let dir = tempdir().unwrap();
887 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
888 let alice = name(&["alice"]);
889 let key1 = name(&["alice", "KEY", "k1"]);
890 let cert1 = name(&["alice", "KEY", "k1", "self", "v=1"]);
891 pib.add_identity(&alice).unwrap();
892 pib.add_key(&alice, &key1, &[0; 32]).unwrap();
893 pib.add_certificate(&key1, &cert1, &[0; 64]).unwrap();
894 pib.delete_key(&key1).unwrap();
895 assert!(pib.get_certificate(&cert1).unwrap().is_none());
896 }
897
898 #[test]
899 fn re_add_key_updates_bits() {
900 let dir = tempdir().unwrap();
901 let pib = SqlitePib::open(dir.path().join("pib.db")).unwrap();
902 let alice = name(&["alice"]);
903 let key1 = name(&["alice", "KEY", "k1"]);
904 pib.add_identity(&alice).unwrap();
905 pib.add_key(&alice, &key1, &[0x11; 32]).unwrap();
906 pib.add_key(&alice, &key1, &[0x22; 32]).unwrap();
907 assert_eq!(pib.get_key_bits(&key1).unwrap().unwrap(), vec![0x22; 32]);
908 }
909}