1use crate::error::TwineCodecError;
9
10use twine_rs_macros::Tlv;
11
12pub enum VersionThreshold {
13 ProtocolVersion2,
15
16 ProtocolVersion3,
18
19 ProtocolVersion4,
21
22 ProtocolVersion5,
24}
25
26bitfield::bitfield! {
27 #[derive(Clone, Copy, Eq, PartialEq, Tlv)]
28 #[tlv(tlv_type = 0x0C, tlv_length = 4, derive_inner)]
29 pub struct SecurityPolicy(u32);
30 impl Debug;
31
32 u16, get_rotation_time, set_rotation_time: 31, 16;
33
34 get_obtain_network_key_enabled, set_obtain_network_key_enabled: 15;
40
41 get_native_commissioning_enabled, set_native_commissioning_enabled: 14;
47
48 get_legacy_routers_enabled, set_legacy_routers_enabled: 13;
55
56 get_external_commissioner_enabled, set_external_commissioning_enabled: 12;
63
64 get_b_bit, set_b_bit: 11;
70
71 get_commercial_commissioning_mode_disabled, set_commercial_commissioning_mode_disabled: 10;
77
78 get_autonomous_enrollment_disabled, set_autonomous_enrollment_disabled: 9;
84
85 get_network_key_provisioning_disabled, set_network_key_provisioning_disabled: 8;
91
92 get_to_ble_link_disabled, set_to_ble_link_disabled: 7;
96
97 get_non_ccm_routers_disabled, set_non_ccm_routers_disabled: 6;
104 u8, get_reserved_bits, set_reserved_bits: 5, 3;
105 u8, get_version_threshold, set_version_threshold: 2, 0;
106}
107
108impl SecurityPolicy {
109 const TYPE_NAME: &str = "SecurityPolicy";
110
111 pub fn rotation_time_hours(&self) -> u16 {
112 self.get_rotation_time()
113 }
114
115 pub fn obtain_network_key_enabled(&self) -> bool {
116 self.get_obtain_network_key_enabled()
117 }
118
119 pub fn native_commissioning_enabled(&self) -> bool {
120 self.get_native_commissioning_enabled()
121 }
122
123 pub fn legacy_routers_enabled(&self) -> bool {
124 self.get_legacy_routers_enabled()
125 }
126
127 pub fn external_commissioner_enabled(&self) -> bool {
128 self.get_external_commissioner_enabled()
129 }
130
131 pub fn commercial_commissioning_mode_enabled(&self) -> bool {
132 !self.get_commercial_commissioning_mode_disabled()
133 }
134
135 pub fn autonomous_enrollment_enabled(&self) -> bool {
136 !self.get_autonomous_enrollment_disabled()
137 }
138
139 pub fn network_key_provisioning_enabled(&self) -> bool {
140 !self.get_network_key_provisioning_disabled()
141 }
142
143 pub fn to_ble_link_enabled(&self) -> bool {
144 !self.get_to_ble_link_disabled()
145 }
146
147 pub fn non_ccm_routers_enabled(&self) -> bool {
148 !self.get_non_ccm_routers_disabled()
149 }
150
151 pub fn version_threshold(&self) -> Result<VersionThreshold, u8> {
155 let threshold = self.get_version_threshold();
156 let r_bit = self.get_legacy_routers_enabled();
157 match (threshold, r_bit) {
158 (_, true) => Ok(VersionThreshold::ProtocolVersion2),
159 (0, false) => Ok(VersionThreshold::ProtocolVersion3),
160 (1, false) => Ok(VersionThreshold::ProtocolVersion4),
161 (2, false) => Ok(VersionThreshold::ProtocolVersion5),
162 _ => Err(threshold),
163 }
164 }
165}
166
167impl Default for SecurityPolicy {
168 fn default() -> Self {
169 let mut policy = SecurityPolicy(0);
170 policy.set_rotation_time(672);
171 policy.set_obtain_network_key_enabled(true);
172 policy.set_native_commissioning_enabled(true);
173 policy.set_legacy_routers_enabled(true);
174 policy.set_external_commissioning_enabled(true);
175 policy.set_commercial_commissioning_mode_disabled(true);
176 policy.set_autonomous_enrollment_disabled(true);
177 policy.set_network_key_provisioning_disabled(true);
178 policy.set_to_ble_link_disabled(true);
179 policy.set_non_ccm_routers_disabled(true);
180 policy.set_reserved_bits(0x07);
181 policy.set_version_threshold(VersionThreshold::ProtocolVersion2 as u8);
182
183 policy
184 }
185}
186
187impl core::fmt::Display for SecurityPolicy {
188 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
189 let rotation_time = self.rotation_time_hours();
190
191 write!(f, "{} ", rotation_time)?;
193
194 if self.obtain_network_key_enabled() {
196 write!(f, "o")?;
197 }
198
199 if self.native_commissioning_enabled() {
200 write!(f, "n")?;
201 }
202
203 if self.legacy_routers_enabled() {
204 write!(f, "r")?;
205 }
206
207 if self.external_commissioner_enabled() {
208 write!(f, "c")?;
209 }
210
211 if self.commercial_commissioning_mode_enabled() {
212 write!(f, "C")?;
213 }
214
215 if self.autonomous_enrollment_enabled() {
216 write!(f, "e")?;
217 }
218
219 if self.network_key_provisioning_enabled() {
220 write!(f, "p")?;
221 }
222
223 if self.to_ble_link_enabled() {
224 write!(f, "L")?;
225 }
226
227 if self.non_ccm_routers_enabled() {
228 write!(f, "R")?;
229 }
230
231 let ver = self.get_version_threshold();
233 write!(f, " {}", ver)
234 }
235}
236
237#[derive(Default)]
238pub struct SecurityPolicyBuilder {
239 obtain_network_key_enabled: Option<bool>,
240 native_commissioning_enabled: Option<bool>,
241 legacy_routers_enabled: Option<bool>,
242 external_commissioner_enabled: Option<bool>,
243 commercial_commissioning_mode_disabled: Option<bool>,
244 autonomous_enrollment_disabled: Option<bool>,
245 network_key_provisioning_disabled: Option<bool>,
246 to_ble_link_disabled: Option<bool>,
247 non_ccm_routers_disabled: Option<bool>,
248 version_threshold: Option<VersionThreshold>,
249 rotation_time_hours: Option<u16>,
250}
251
252impl SecurityPolicyBuilder {
253 #[cfg(test)]
254 pub fn with_disabled_policy() -> Self {
255 SecurityPolicyBuilder {
256 obtain_network_key_enabled: Some(false),
257 native_commissioning_enabled: Some(false),
258 legacy_routers_enabled: Some(false),
259 external_commissioner_enabled: Some(false),
260 commercial_commissioning_mode_disabled: Some(true),
261 autonomous_enrollment_disabled: Some(true),
262 network_key_provisioning_disabled: Some(true),
263 to_ble_link_disabled: Some(true),
264 non_ccm_routers_disabled: Some(true),
265 version_threshold: Some(VersionThreshold::ProtocolVersion3),
266 rotation_time_hours: Some(672),
267 }
268 }
269
270 pub fn with_default_policy() -> Self {
271 SecurityPolicyBuilder {
272 obtain_network_key_enabled: Some(true),
273 native_commissioning_enabled: Some(true),
274 legacy_routers_enabled: Some(true),
275 external_commissioner_enabled: Some(true),
276 commercial_commissioning_mode_disabled: Some(true),
277 autonomous_enrollment_disabled: Some(true),
278 network_key_provisioning_disabled: Some(true),
279 to_ble_link_disabled: Some(true),
280 non_ccm_routers_disabled: Some(true),
281 version_threshold: Some(VersionThreshold::ProtocolVersion2),
282 rotation_time_hours: Some(672),
283 }
284 }
285
286 pub fn enable_obtain_network_key(mut self) -> Self {
287 self.obtain_network_key_enabled = Some(true);
288 self
289 }
290
291 pub fn disable_obtain_network_key(mut self) -> Self {
292 self.obtain_network_key_enabled = Some(false);
293 self
294 }
295
296 pub fn enable_native_commissioning(mut self) -> Self {
297 self.native_commissioning_enabled = Some(true);
298 self
299 }
300
301 pub fn disable_native_commissioning(mut self) -> Self {
302 self.native_commissioning_enabled = Some(false);
303 self
304 }
305
306 pub fn enable_legacy_routers(mut self) -> Self {
307 self.legacy_routers_enabled = Some(true);
308 self
309 }
310
311 pub fn disable_legacy_routers(mut self) -> Self {
312 self.legacy_routers_enabled = Some(false);
313 self
314 }
315
316 pub fn enable_external_commissioner(mut self) -> Self {
317 self.external_commissioner_enabled = Some(true);
318 self
319 }
320
321 pub fn disable_external_commissioner(mut self) -> Self {
322 self.external_commissioner_enabled = Some(false);
323 self
324 }
325
326 pub fn enable_commercial_commissioning(mut self) -> Self {
327 self.commercial_commissioning_mode_disabled = Some(false);
328 self
329 }
330
331 pub fn disable_commercial_commissioning(mut self) -> Self {
332 self.commercial_commissioning_mode_disabled = Some(true);
333 self
334 }
335
336 pub fn enable_autonomous_enrollment(mut self) -> Self {
337 self.autonomous_enrollment_disabled = Some(false);
338 self
339 }
340
341 pub fn disable_autonomous_enrollment(mut self) -> Self {
342 self.autonomous_enrollment_disabled = Some(true);
343 self
344 }
345
346 pub fn enable_network_key_provisioning(mut self) -> Self {
347 self.network_key_provisioning_disabled = Some(false);
348 self
349 }
350
351 pub fn disable_network_key_provisioning(mut self) -> Self {
352 self.network_key_provisioning_disabled = Some(true);
353 self
354 }
355
356 pub fn enable_to_ble_link(mut self) -> Self {
357 self.to_ble_link_disabled = Some(false);
358 self
359 }
360
361 pub fn disable_to_ble_link(mut self) -> Self {
362 self.to_ble_link_disabled = Some(true);
363 self
364 }
365
366 pub fn enable_non_ccm_routers(mut self) -> Self {
367 self.non_ccm_routers_disabled = Some(false);
368 self
369 }
370
371 pub fn disable_non_ccm_routers(mut self) -> Self {
372 self.non_ccm_routers_disabled = Some(true);
373 self
374 }
375
376 pub fn version_threshold(mut self, threshold: VersionThreshold) -> Self {
377 self.version_threshold = Some(threshold);
378 self
379 }
380
381 pub fn rotation_time_hours(mut self, hours: u16) -> Self {
382 self.rotation_time_hours = Some(hours);
383 self
384 }
385
386 pub fn build(self) -> Result<SecurityPolicy, TwineCodecError> {
387 if self.obtain_network_key_enabled.is_none()
388 || self.native_commissioning_enabled.is_none()
389 || self.legacy_routers_enabled.is_none()
390 || self.external_commissioner_enabled.is_none()
391 || self.commercial_commissioning_mode_disabled.is_none()
392 || self.autonomous_enrollment_disabled.is_none()
393 || self.network_key_provisioning_disabled.is_none()
394 || self.to_ble_link_disabled.is_none()
395 || self.non_ccm_routers_disabled.is_none()
396 || self.version_threshold.is_none()
397 || self.rotation_time_hours.is_none()
398 {
399 return Err(TwineCodecError::TypeBuildError(SecurityPolicy::TYPE_NAME));
400 }
401
402 let mut policy = SecurityPolicy::default();
403
404 if let Some(rotation_time) = self.rotation_time_hours {
405 policy.set_rotation_time(rotation_time);
406 }
407
408 if let Some(o_bit) = self.obtain_network_key_enabled {
409 policy.set_obtain_network_key_enabled(o_bit);
410 }
411
412 if let Some(n_bit) = self.native_commissioning_enabled {
413 policy.set_native_commissioning_enabled(n_bit);
414 }
415
416 if let Some(r_bit) = self.legacy_routers_enabled {
417 policy.set_legacy_routers_enabled(r_bit);
418 }
419
420 if let Some(c_bit) = self.external_commissioner_enabled {
421 policy.set_external_commissioning_enabled(c_bit);
422 }
423
424 if let Some(ccm_bit) = self.commercial_commissioning_mode_disabled {
425 policy.set_commercial_commissioning_mode_disabled(ccm_bit);
426 }
427
428 if let Some(ae_bit) = self.autonomous_enrollment_disabled {
429 policy.set_autonomous_enrollment_disabled(ae_bit);
430 }
431
432 if let Some(np_bit) = self.network_key_provisioning_disabled {
433 policy.set_network_key_provisioning_disabled(np_bit);
434 }
435
436 if let Some(ble_bit) = self.to_ble_link_disabled {
437 policy.set_to_ble_link_disabled(ble_bit);
438 }
439
440 if let Some(non_ccm_bit) = self.non_ccm_routers_disabled {
441 policy.set_non_ccm_routers_disabled(non_ccm_bit);
442 }
443
444 policy.set_reserved_bits(0x07);
445
446 if let Some(version_threshold) = self.version_threshold {
447 match version_threshold {
448 VersionThreshold::ProtocolVersion2 => {
449 policy.set_legacy_routers_enabled(true);
450 policy.set_version_threshold(0);
451 }
452 VersionThreshold::ProtocolVersion3 => {
453 policy.set_legacy_routers_enabled(false);
454 policy.set_version_threshold(0);
455 }
456 VersionThreshold::ProtocolVersion4 => {
457 policy.set_legacy_routers_enabled(false);
458 policy.set_version_threshold(1);
459 }
460 VersionThreshold::ProtocolVersion5 => {
461 policy.set_legacy_routers_enabled(false);
462 policy.set_version_threshold(2);
463 }
464 }
465 }
466
467 Ok(policy)
468 }
469}
470
471#[cfg(test)]
472mod tests {
473 use super::*;
474
475 #[test]
476 fn default_policy() {
477 let test = SecurityPolicyBuilder::with_default_policy()
478 .build()
479 .expect("Failed to build default policy");
480 let expected = SecurityPolicy(0x02A0_F7F8);
481 assert_eq!(expected, test);
482 assert_eq!(std::format!("{}", test), "672 onrc 0");
483
484 let test = SecurityPolicy::default();
485 assert_eq!(expected, test);
486 assert_eq!(std::format!("{}", test), "672 onrc 0");
487 }
488
489 #[test]
490 fn disabled_policy() {
491 let _ = env_logger::builder().is_test(true).try_init();
492 let test = SecurityPolicyBuilder::with_disabled_policy()
493 .build()
494 .expect("Failed to build disabled policy");
495 log::debug!("Disabled Policy: {:04x?}", test.0);
496
497 let expected = SecurityPolicy(0x02A0_07F8);
498 assert_eq!(expected, test);
499 }
500
501 #[test]
502 fn o_bit() {
503 let policy = SecurityPolicyBuilder::with_disabled_policy()
504 .enable_obtain_network_key()
505 .build()
506 .expect("Failed to build policy with O bit enabled");
507 assert!(policy.obtain_network_key_enabled());
508 assert_eq!(std::format!("{}", policy), "672 o 0");
509
510 let inner = policy.0;
511 assert_eq!(inner & 0x0000_8000, 0x0000_8000);
512
513 let policy = SecurityPolicyBuilder::with_disabled_policy()
514 .disable_obtain_network_key()
515 .build()
516 .expect("Failed to build policy with o bit enabled");
517 assert!(!policy.obtain_network_key_enabled());
518
519 let inner = policy.0;
520 assert_eq!(inner & 0x0000_8000, 0);
521 }
522
523 #[test]
524 fn n_bit() {
525 let n_bit_mask = 0x0000_4000;
526 let policy = SecurityPolicyBuilder::with_disabled_policy()
527 .enable_native_commissioning()
528 .build()
529 .expect("Failed to build policy with n bit enabled");
530 assert!(policy.native_commissioning_enabled());
531 assert_eq!(std::format!("{}", policy), "672 n 0");
532
533 let inner = policy.0;
534 assert_eq!(inner & n_bit_mask, n_bit_mask);
535
536 let policy = SecurityPolicyBuilder::with_disabled_policy()
537 .disable_native_commissioning()
538 .build()
539 .expect("Failed to build policy with n bit disabled");
540 assert!(!policy.native_commissioning_enabled());
541
542 let inner = policy.0;
543 assert_eq!(inner & n_bit_mask, 0);
544 }
545
546 #[test]
547 fn r_bit() {
548 let r_bit_mask = 0x0000_2000;
549 let policy = SecurityPolicyBuilder::with_disabled_policy()
550 .version_threshold(VersionThreshold::ProtocolVersion2)
551 .build()
552 .expect("Failed to build policy with r bit enabled");
553 assert!(policy.legacy_routers_enabled());
554 assert_eq!(std::format!("{}", policy), "672 r 0");
555
556 let inner = policy.0;
557 assert_eq!(inner & r_bit_mask, r_bit_mask);
558
559 let policy = SecurityPolicyBuilder::with_disabled_policy()
560 .disable_legacy_routers()
561 .build()
562 .expect("Failed to build policy with r bit disabled");
563 assert!(!policy.legacy_routers_enabled());
564
565 let inner = policy.0;
566 assert_eq!(inner & r_bit_mask, 0);
567 }
568
569 #[test]
570 fn c_bit() {
571 let c_bit_mask = 0x0000_1000;
572 let policy = SecurityPolicyBuilder::with_disabled_policy()
573 .enable_external_commissioner()
574 .build()
575 .expect("Failed to build policy with c bit enabled");
576 assert!(policy.external_commissioner_enabled());
577 assert_eq!(std::format!("{}", policy), "672 c 0");
578
579 let inner = policy.0;
580 assert_eq!(inner & c_bit_mask, c_bit_mask);
581
582 let policy = SecurityPolicyBuilder::with_disabled_policy()
583 .disable_external_commissioner()
584 .build()
585 .expect("Failed to build policy with c bit disabled");
586 assert!(!policy.external_commissioner_enabled());
587
588 let inner = policy.0;
589 assert_eq!(inner & c_bit_mask, 0);
590 }
591
592 #[test]
593 fn ccm_bit() {
594 let ccm_bit_mask = 0x0000_0400;
595 let policy = SecurityPolicyBuilder::with_disabled_policy()
596 .enable_commercial_commissioning()
597 .build()
598 .expect("Failed to build policy with ccm bit enabled");
599 assert!(policy.commercial_commissioning_mode_enabled());
600 assert_eq!(std::format!("{}", policy), "672 C 0");
601
602 let inner = policy.0;
603 assert_eq!(inner & ccm_bit_mask, 0);
604
605 let policy = SecurityPolicyBuilder::with_disabled_policy()
606 .disable_commercial_commissioning()
607 .build()
608 .expect("Failed to build policy with ccm bit disabled");
609 assert!(!policy.commercial_commissioning_mode_enabled());
610
611 let inner = policy.0;
612 assert_eq!(inner & ccm_bit_mask, ccm_bit_mask);
613 }
614
615 #[test]
616 fn ae_bit() {
617 let ae_bit_mask = 0x0000_0200;
618 let policy = SecurityPolicyBuilder::with_disabled_policy()
619 .enable_autonomous_enrollment()
620 .build()
621 .expect("Failed to build policy with ae bit enabled");
622 assert!(policy.autonomous_enrollment_enabled());
623 assert_eq!(std::format!("{}", policy), "672 e 0");
624
625 let inner = policy.0;
626 assert_eq!(inner & ae_bit_mask, 0);
627
628 let policy = SecurityPolicyBuilder::with_disabled_policy()
629 .disable_autonomous_enrollment()
630 .build()
631 .expect("Failed to build policy with ae bit disabled");
632 assert!(!policy.autonomous_enrollment_enabled());
633
634 let inner = policy.0;
635 assert_eq!(inner & ae_bit_mask, ae_bit_mask);
636 }
637
638 #[test]
639 fn np_bit() {
640 let np_bit_mask = 0x0000_0100;
641 let policy = SecurityPolicyBuilder::with_disabled_policy()
642 .enable_network_key_provisioning()
643 .build()
644 .expect("Failed to build policy with np bit enabled");
645 assert!(policy.network_key_provisioning_enabled());
646 assert_eq!(std::format!("{}", policy), "672 p 0");
647
648 let inner = policy.0;
649 assert_eq!(inner & np_bit_mask, 0);
650
651 let policy = SecurityPolicyBuilder::with_disabled_policy()
652 .disable_network_key_provisioning()
653 .build()
654 .expect("Failed to build policy with np bit disabled");
655 assert!(!policy.network_key_provisioning_enabled());
656
657 let inner = policy.0;
658 assert_eq!(inner & np_bit_mask, np_bit_mask);
659 }
660
661 #[test]
662 fn ncr_bit() {
663 let ncr_bit_mask = 0x0000_0040;
664 let policy = SecurityPolicyBuilder::with_disabled_policy()
665 .enable_non_ccm_routers()
666 .build()
667 .expect("Failed to build policy with ncr bit enabled");
668 assert!(policy.non_ccm_routers_enabled());
669 assert_eq!(std::format!("{}", policy), "672 R 0");
670
671 let inner = policy.0;
672 assert_eq!(inner & ncr_bit_mask, 0);
673
674 let policy = SecurityPolicyBuilder::with_disabled_policy()
675 .disable_non_ccm_routers()
676 .build()
677 .expect("Failed to build policy with ncr bit disabled");
678 assert!(!policy.non_ccm_routers_enabled());
679
680 let inner = policy.0;
681 assert_eq!(inner & ncr_bit_mask, ncr_bit_mask);
682 }
683
684 #[test]
685 fn version_threshold() {
686 let policy = SecurityPolicyBuilder::with_disabled_policy()
687 .version_threshold(VersionThreshold::ProtocolVersion4)
688 .build()
689 .expect("Failed to build policy with Protocol Version 4 threshold");
690 assert!(!policy.legacy_routers_enabled());
691
692 assert!(matches!(
693 policy.version_threshold(),
694 Ok(VersionThreshold::ProtocolVersion4)
695 ));
696
697 assert_eq!(std::format!("{}", policy), "672 1");
698 assert_eq!(policy.0 & 0x0000_0003, 1);
699 }
700
701 #[test]
702 fn display_security_policy() {
703 let _ = env_logger::builder().is_test(true).try_init();
704
705 let policy = SecurityPolicy::default();
706 assert_eq!(std::format!("{}", policy), "672 onrc 0");
707
708 let policy = SecurityPolicyBuilder::default()
709 .disable_obtain_network_key()
710 .disable_native_commissioning()
711 .disable_legacy_routers()
712 .disable_external_commissioner()
713 .enable_commercial_commissioning()
714 .disable_autonomous_enrollment()
715 .disable_network_key_provisioning()
716 .disable_to_ble_link()
717 .disable_non_ccm_routers()
718 .version_threshold(VersionThreshold::ProtocolVersion4)
719 .rotation_time_hours(672)
720 .build()
721 .inspect_err(|e| log::trace!("Failed to build security policy: {e:?}"));
722
723 let policy = policy.expect("Failed to build security policy");
724
725 log::debug!("Policy: {policy:?}");
726 assert!(!policy.obtain_network_key_enabled());
727 assert_eq!(std::format!("{}", policy), "672 C 1");
728 }
729}