1 // Copyright 2023 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! Bluetooth Core, Vol 2, Part C, 4.2.5
16
17 use super::features;
18 use crate::lmp::procedure::Context;
19 use crate::num_hci_command_packets;
20 use crate::packets::{hci, lmp};
21
22 use hci::LMPFeaturesPage1Bits::SecureConnectionsHostSupport;
23 use hci::LMPFeaturesPage2Bits::SecureConnectionsControllerSupport;
24
initiate(ctx: &impl Context)25 pub async fn initiate(ctx: &impl Context) {
26 // TODO: handle turn off
27 let _ = ctx.receive_hci_command::<hci::SetConnectionEncryption>().await;
28 ctx.send_hci_event(
29 hci::SetConnectionEncryptionStatusBuilder {
30 num_hci_command_packets,
31 status: hci::ErrorCode::Success,
32 }
33 .build(),
34 );
35
36 // TODO: handle failure
37 let _ = ctx
38 .send_accepted_lmp_packet(
39 lmp::EncryptionModeReqBuilder { transaction_id: 0, encryption_mode: 0x1 }.build(),
40 )
41 .await;
42
43 // TODO: handle failure
44 let _ = ctx
45 .send_accepted_lmp_packet(
46 lmp::EncryptionKeySizeReqBuilder { transaction_id: 0, key_size: 16 }.build(),
47 )
48 .await;
49
50 // TODO: handle failure
51 let _ = ctx
52 .send_accepted_lmp_packet(
53 lmp::StartEncryptionReqBuilder { transaction_id: 0, random_number: [0; 16] }.build(),
54 )
55 .await;
56
57 let aes_ccm = features::supported_on_both_page1(ctx, SecureConnectionsHostSupport).await
58 && features::supported_on_both_page2(ctx, SecureConnectionsControllerSupport).await;
59
60 ctx.send_hci_event(
61 hci::EncryptionChangeBuilder {
62 status: hci::ErrorCode::Success,
63 connection_handle: ctx.peer_handle(),
64 encryption_enabled: if aes_ccm {
65 hci::EncryptionEnabled::BrEdrAesCcm
66 } else {
67 hci::EncryptionEnabled::On
68 },
69 }
70 .build(),
71 );
72 }
73
respond(ctx: &impl Context)74 pub async fn respond(ctx: &impl Context) {
75 // TODO: handle
76 let _ = ctx.receive_lmp_packet::<lmp::EncryptionModeReq>().await;
77 ctx.send_lmp_packet(
78 lmp::AcceptedBuilder { transaction_id: 0, accepted_opcode: lmp::Opcode::EncryptionModeReq }
79 .build(),
80 );
81
82 let _ = ctx.receive_lmp_packet::<lmp::EncryptionKeySizeReq>().await;
83 ctx.send_lmp_packet(
84 lmp::AcceptedBuilder {
85 transaction_id: 0,
86 accepted_opcode: lmp::Opcode::EncryptionKeySizeReq,
87 }
88 .build(),
89 );
90
91 let _ = ctx.receive_lmp_packet::<lmp::StartEncryptionReq>().await;
92 ctx.send_lmp_packet(
93 lmp::AcceptedBuilder {
94 transaction_id: 0,
95 accepted_opcode: lmp::Opcode::StartEncryptionReq,
96 }
97 .build(),
98 );
99
100 let aes_ccm = features::supported_on_both_page1(ctx, SecureConnectionsHostSupport).await
101 && features::supported_on_both_page2(ctx, SecureConnectionsControllerSupport).await;
102
103 ctx.send_hci_event(
104 hci::EncryptionChangeBuilder {
105 status: hci::ErrorCode::Success,
106 connection_handle: ctx.peer_handle(),
107 encryption_enabled: if aes_ccm {
108 hci::EncryptionEnabled::BrEdrAesCcm
109 } else {
110 hci::EncryptionEnabled::On
111 },
112 }
113 .build(),
114 );
115 }
116
117 #[cfg(test)]
118 mod tests {
119 use super::initiate;
120 use super::respond;
121 use crate::lmp::procedure::Context;
122 use crate::lmp::test::{sequence, TestContext};
123
124 use crate::packets::hci::LMPFeaturesPage1Bits::SecureConnectionsHostSupport;
125 use crate::packets::hci::LMPFeaturesPage2Bits::SecureConnectionsControllerSupport;
126
127 #[test]
accept_encryption()128 fn accept_encryption() {
129 let context = TestContext::new();
130 let procedure = respond;
131
132 include!("../../../test/ENC/BV-01-C.in");
133 }
134
135 #[test]
initiate_encryption()136 fn initiate_encryption() {
137 let context = TestContext::new();
138 let procedure = initiate;
139
140 include!("../../../test/ENC/BV-05-C.in");
141 }
142
143 #[test]
accept_aes_ccm_encryption_request()144 fn accept_aes_ccm_encryption_request() {
145 let context = TestContext::new()
146 .with_page_1_feature(SecureConnectionsHostSupport)
147 .with_page_2_feature(SecureConnectionsControllerSupport)
148 .with_peer_page_1_feature(SecureConnectionsHostSupport)
149 .with_peer_page_2_feature(SecureConnectionsControllerSupport);
150 let procedure = respond;
151
152 include!("../../../test/ENC/BV-26-C.in");
153 }
154
155 #[test]
initiate_aes_ccm_encryption()156 fn initiate_aes_ccm_encryption() {
157 let context = TestContext::new()
158 .with_page_1_feature(SecureConnectionsHostSupport)
159 .with_page_2_feature(SecureConnectionsControllerSupport)
160 .with_peer_page_1_feature(SecureConnectionsHostSupport)
161 .with_peer_page_2_feature(SecureConnectionsControllerSupport);
162 let procedure = initiate;
163
164 include!("../../../test/ENC/BV-34-C.in");
165 }
166 }
167