1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
use core::future::Future;
use crate::ember::{
Certificate283k1Data, CertificateData, MessageDigest, PrivateKeyData, PublicKey283k1Data,
PublicKeyData, Signature283k1Data, SignatureData,
};
use crate::error::Error;
use crate::frame::parameters::cbke::{
calculate_smacs, calculate_smacs283k1, clear_temporary_data_maybe_store_link_key,
clear_temporary_data_maybe_store_link_key283k1, dsa_sign, dsa_verify, dsa_verify283k1,
generate_cbke_keys, generate_cbke_keys283k1, get_certificate, get_certificate283k1,
save_preinstalled_cbke_data283k1, set_preinstalled_cbke_data,
};
use crate::transport::Transport;
use crate::types::ByteSizedVec;
/// The `Cbke` trait provides an interface for the Certificate Based Key Exchange features.
pub trait Cbke {
// TODO: Where is `ezspGenerateKeysRetrieveCert()` defined?
/// Calculates the SMAC verification keys for both the initiator and responder roles of
/// CBKE using the passed parameters and the stored public/private key pair previously
/// generated with `ezspGenerateKeysRetrieveCert()`.
/// It also stores the unverified link key data in temporary storage on the NCP until the key
/// establishment is complete.
fn calculate_smacs(
&mut self,
am_initiator: bool,
partner_certificate: CertificateData,
partner_ephemeral_public_key: PublicKeyData,
) -> impl Future<Output = Result<(), Error>> + Send;
// TODO: Where is `ezspGenerateKeysRetrieveCert283k1()` defined?
/// Calculates the SMAC verification keys for both the initiator and responder roles of
/// CBKE for the 283k1 ECC curve using the passed parameters and the stored public/private
/// key pair previously generated with `ezspGenerateKeysRetrieveCert283k1()`.
///
/// It also stores the unverified link key data in temporary storage on the NCP until the
/// key establishment is complete.
fn calculate_smacs283k1(
&mut self,
am_initiator: bool,
partner_certificate: Certificate283k1Data,
partner_ephemeral_public_key: PublicKey283k1Data,
) -> impl Future<Output = Result<(), Error>> + Send;
/// Clears the temporary data associated with CBKE and the key establishment,
/// most notably the ephemeral public/private key pair.
///
/// If storeLinKey is true it moves the unverified link key stored in temporary storage
/// into the link key table. Otherwise, it discards the key.
fn clear_temporary_data_maybe_store_link_key(
&mut self,
store_link_key: bool,
) -> impl Future<Output = Result<(), Error>> + Send;
/// Clears the temporary data associated with CBKE and the key establishment,
/// most notably the ephemeral public/private key pair.
///
/// If storeLinKey is true it moves the unverified link key stored in temporary storage
/// into the link key table. Otherwise, it discards the key.
fn clear_temporary_data_maybe_store_link_key283k1(
&mut self,
store_link_key: bool,
) -> impl Future<Output = Result<(), Error>> + Send;
/// Calculate the Digital Signature Algorithm (DSA) signature of the passed message.
///
/// # Deprecated
///
/// This functionality has been replaced by a single bit in the `EmberApsFrame`,
/// `EMBER_APS_OPTION_DSA_SIGN`.
///
/// Devices wishing to send signed messages should use that as it requires fewer function calls
/// and message buffering.
/// The dsaSignHandler response is still called when `EMBER_APS_OPTION_DSA_SIGN` is used.
/// However, this function is still supported.
///
/// # Usage
///
/// This function begins the process of signing the passed message contained within the
/// `message` array.
/// If no other ECC operation is going on, it will immediately return with
/// [`Status::OperationInProgress`](crate::ember::Status::OperationInProgress) to indicate the
/// start of ECC operation.
/// It will delay a period of time to let APS retries take place, but then it will shut down the
/// radio and consume the CPU processing until the signing is complete.
/// This may take up to 1 second. The signed message will be returned in the dsaSignHandler
/// response.
///
/// # Note
///
/// Note that the last byte of the `message` passed to this function has special significance.
///
/// As the typical use case for DSA signing is to sign the ZCL payload of a `DRLC` Report Event
/// Status message in SE 1.0, there is often both a signed portion (ZCL payload) and an unsigned
/// portion (ZCL header).
///
/// The last byte in the content of messageToSign is therefore used as a special indicator to
/// signify how many bytes of leading data in the array should be excluded from consideration
/// during the signing process.
///
/// If the signature needs to cover the entire array (all bytes except last one), the caller
/// should ensure that the last byte of messageContents is `0x00`.
///
/// When the signature operation is complete, this final byte will be replaced by the signature
/// type indicator (0x01 for ECDSA signatures), and the actual signature will be appended to
/// the original contents after this byte.
#[deprecated]
fn dsa_sign(
&mut self,
message: ByteSizedVec<u8>,
) -> impl Future<Output = Result<(), Error>> + Send;
/// Verify that signature of the associated message digest was signed by the private key of the associated certificate.
fn dsa_verify(
&mut self,
digest: MessageDigest,
signer_certificate: CertificateData,
received_sig: SignatureData,
) -> impl Future<Output = Result<(), Error>> + Send;
/// Verify that signature of the associated message digest was signed by the private key of the associated certificate.
fn dsa_verify283k1(
&mut self,
digest: MessageDigest,
signer_certificate: Certificate283k1Data,
received_sig: Signature283k1Data,
) -> impl Future<Output = Result<(), Error>> + Send;
/// This call starts the generation of the ECC Ephemeral Public/Private key pair.
///
/// When complete it stores the private key.
/// The results are returned via [`GenerateCbkeKeys`](crate::frame::parameters::cbke::handler::GenerateCbkeKeys).
fn generate_cbke_keys(&mut self) -> impl Future<Output = Result<(), Error>> + Send;
/// This call starts the generation of the ECC 283k1 curve Ephemeral Public/Private key pair.
///
/// When complete it stores the private key.
/// The results are returned via [`GenerateCbkeKeys283k1`](crate::frame::parameters::cbke::handler::GenerateCbkeKeys283k1).
fn generate_cbke_keys283k1(&mut self) -> impl Future<Output = Result<(), Error>> + Send;
/// Retrieves the certificate installed on the NCP.
fn get_certificate(&mut self) -> impl Future<Output = Result<CertificateData, Error>> + Send;
/// Retrieves the 283k certificate installed on the NCP.
fn get_certificate283k1(
&mut self,
) -> impl Future<Output = Result<Certificate283k1Data, Error>> + Send;
/// Sets the device's 283k1 curve CA public key, local certificate,
/// and static private key on the NCP associated with this node.
fn save_preinstalled_cbke_data283k1(
&mut self,
) -> impl Future<Output = Result<(), Error>> + Send;
/// Sets the device's CA public key, local certificate,
/// and static private key on the NCP associated with this node.
fn set_preinstalled_cbke_data(
&mut self,
ca_public: PublicKeyData,
my_cert: CertificateData,
my_key: PrivateKeyData,
) -> impl Future<Output = Result<(), Error>> + Send;
}
impl<T> Cbke for T
where
T: Transport,
{
async fn calculate_smacs(
&mut self,
am_initiator: bool,
partner_certificate: CertificateData,
partner_ephemeral_public_key: PublicKeyData,
) -> Result<(), Error> {
self.communicate(calculate_smacs::Command::new(
am_initiator,
partner_certificate,
partner_ephemeral_public_key,
))
.await?
.try_into()
}
async fn calculate_smacs283k1(
&mut self,
am_initiator: bool,
partner_certificate: Certificate283k1Data,
partner_ephemeral_public_key: PublicKey283k1Data,
) -> Result<(), Error> {
self.communicate(calculate_smacs283k1::Command::new(
am_initiator,
partner_certificate,
partner_ephemeral_public_key,
))
.await?
.try_into()
}
async fn clear_temporary_data_maybe_store_link_key(
&mut self,
store_link_key: bool,
) -> Result<(), Error> {
self.communicate(clear_temporary_data_maybe_store_link_key::Command::new(
store_link_key,
))
.await?
.try_into()
}
async fn clear_temporary_data_maybe_store_link_key283k1(
&mut self,
store_link_key: bool,
) -> Result<(), Error> {
self.communicate(
clear_temporary_data_maybe_store_link_key283k1::Command::new(store_link_key),
)
.await?
.try_into()
}
async fn dsa_sign(&mut self, message: ByteSizedVec<u8>) -> Result<(), Error> {
self.communicate(dsa_sign::Command::new(message))
.await
.map(drop)
}
async fn dsa_verify(
&mut self,
digest: MessageDigest,
signer_certificate: CertificateData,
received_sig: SignatureData,
) -> Result<(), Error> {
self.communicate(dsa_verify::Command::new(
digest,
signer_certificate,
received_sig,
))
.await?
.try_into()
}
async fn dsa_verify283k1(
&mut self,
digest: MessageDigest,
signer_certificate: Certificate283k1Data,
received_sig: Signature283k1Data,
) -> Result<(), Error> {
self.communicate(dsa_verify283k1::Command::new(
digest,
signer_certificate,
received_sig,
))
.await?
.try_into()
}
async fn generate_cbke_keys(&mut self) -> Result<(), Error> {
self.communicate(generate_cbke_keys::Command)
.await?
.try_into()
}
async fn generate_cbke_keys283k1(&mut self) -> Result<(), Error> {
self.communicate(generate_cbke_keys283k1::Command)
.await?
.try_into()
}
async fn get_certificate(&mut self) -> Result<CertificateData, Error> {
self.communicate(get_certificate::Command).await?.try_into()
}
async fn get_certificate283k1(&mut self) -> Result<Certificate283k1Data, Error> {
self.communicate(get_certificate283k1::Command)
.await?
.try_into()
}
async fn save_preinstalled_cbke_data283k1(&mut self) -> Result<(), Error> {
self.communicate(save_preinstalled_cbke_data283k1::Command)
.await?
.try_into()
}
async fn set_preinstalled_cbke_data(
&mut self,
ca_public: PublicKeyData,
my_cert: CertificateData,
my_key: PrivateKeyData,
) -> Result<(), Error> {
self.communicate(set_preinstalled_cbke_data::Command::new(
ca_public, my_cert, my_key,
))
.await?
.try_into()
}
}