rust_cryptoauthlib/hw_impl/
ecdh.rs1use std::ptr;
2
3use super::{
4 AtcaDeviceType, AtcaStatus, AteccDevice, EcdhParams, EcdhResult, EcdhSource, EcdhTarget,
5 OutputProtectionState, WriteConfig,
6};
7
8use super::{
9 ATCA_ATECC_PUB_KEY_SIZE, ATCA_ATECC_SLOTS_COUNT, ATCA_ECDH_KEY_SIZE, ATCA_SHA2_256_DIGEST_SIZE,
10};
11
12impl AteccDevice {
13 pub(crate) fn ecdh(
15 &self,
16 parameters: EcdhParams,
17 peer_public_key: &[u8],
18 ) -> Result<EcdhResult, AtcaStatus> {
19 if self.check_that_configuration_is_not_locked(true) {
20 return Err(AtcaStatus::AtcaNotLocked);
21 }
22
23 let key_id: u16 = self.parse_ecdh_input_parameters(¶meters, peer_public_key.len())?;
24
25 let mode: u8 = parameters.key_source.clone() as u8
26 | parameters.out_target.clone() as u8
27 | ((parameters.out_encrypt as u8) << 0x01);
28
29 let mut out_data: Vec<u8> = vec![0x00; ATCA_ECDH_KEY_SIZE];
30 let out_data_ptr: *mut u8 = match parameters.out_target {
31 EcdhTarget::Output => out_data.as_mut_ptr(),
32 EcdhTarget::Compatibility => match self.slots[key_id as usize]
33 .config
34 .ecc_key_attr
35 .ecdh_secret_out
36 {
37 false => out_data.as_mut_ptr(),
38 _ => ptr::null_mut(),
39 },
40 _ => ptr::null_mut(),
41 };
42
43 let mut out_nonce: Vec<u8> = vec![0x00; ATCA_ECDH_KEY_SIZE];
44 let out_nonce_ptr: *mut u8 = match parameters.out_target {
45 EcdhTarget::Output => out_nonce.as_mut_ptr(),
46 _ => ptr::null_mut(),
47 };
48
49 let result = AtcaStatus::from(unsafe {
50 let _guard = self
51 .api_mutex
52 .lock()
53 .expect("Could not lock atcab API mutex");
54 cryptoauthlib_sys::atcab_ecdh_base(
55 mode,
56 key_id,
57 peer_public_key.as_ptr(),
58 out_data_ptr,
59 out_nonce_ptr,
60 )
61 });
62
63 match result {
64 AtcaStatus::AtcaSuccess => {
65 let output = EcdhResult {
66 pms: if out_data_ptr.is_null() {
67 None
68 } else {
69 out_data.resize(ATCA_ECDH_KEY_SIZE, 0x00);
70 Some(out_data)
71 },
72 out_nonce: if out_nonce_ptr.is_null() {
73 None
74 } else {
75 out_nonce.resize(ATCA_SHA2_256_DIGEST_SIZE, 0x00);
76 Some(out_nonce)
77 },
78 };
79 Ok(output)
80 }
81 _ => Err(result),
82 }
83 } fn parse_ecdh_slot(&self, parameters: &EcdhParams) -> Result<u16, AtcaStatus> {
88 let mut slot: u16 = 0x0000;
89
90 if (parameters.key_source == EcdhSource::Slot)
91 || (parameters.out_target == EcdhTarget::Slot)
92 {
93 match parameters.slot_id {
94 Some(val) => {
95 if val < ATCA_ATECC_SLOTS_COUNT {
96 if (parameters.out_target == EcdhTarget::Slot)
97 && (self.slots[val as usize].config.write_config != WriteConfig::Always)
98 {
99 return Err(AtcaStatus::AtcaBadParam);
100 }
101 if (parameters.key_source == EcdhSource::Slot)
102 && !self.slots[val as usize].config.ecc_key_attr.ecdh_operation
103 {
104 return Err(AtcaStatus::AtcaInvalidId);
105 }
106 slot = val as u16;
107 } else {
108 return Err(AtcaStatus::AtcaInvalidId);
109 }
110 }
111 None => return Err(AtcaStatus::AtcaBadParam),
112 }
113 } else if parameters.slot_id.is_some() {
114 return Err(AtcaStatus::AtcaBadParam);
115 }
116
117 Ok(slot)
118 } fn parse_ecdh_input_parameters(
122 &self,
123 parameters: &EcdhParams,
124 peer_public_key_length: usize,
125 ) -> Result<u16, AtcaStatus> {
126 let mut slot: u16 = 0x0000;
127 let device_type = self.get_device_type();
128
129 if (device_type != AtcaDeviceType::ATECC508A) && (device_type != AtcaDeviceType::ATECC608A)
130 {
131 return Err(AtcaStatus::AtcaBadOpcode);
132 }
133
134 let mut bad_param: bool = (device_type == AtcaDeviceType::ATECC508A)
135 && ((parameters.key_source != EcdhSource::Slot)
136 || (parameters.out_target != EcdhTarget::Compatibility)
137 || parameters.out_encrypt);
138
139 bad_param = bad_param
140 || ((parameters.key_source == EcdhSource::Slot)
141 && (parameters.out_target == EcdhTarget::Slot));
142
143 if !bad_param {
144 slot = self.parse_ecdh_slot(parameters)?;
145
146 if (device_type == AtcaDeviceType::ATECC608A) && self.chip_options.io_key_enabled {
147 let ecdh_out_to_n_plus_1: bool = self.slots[slot as usize]
148 .config
149 .ecc_key_attr
150 .ecdh_secret_out;
151
152 match self.chip_options.ecdh_output_protection {
153 OutputProtectionState::ClearTextAllowed => {
154 if parameters.out_encrypt {
155 match parameters.out_target {
156 EcdhTarget::Compatibility => {
157 if ecdh_out_to_n_plus_1 {
158 bad_param = true;
159 }
160 }
161 EcdhTarget::Slot | EcdhTarget::TempKey => bad_param = true,
162 _ => (),
163 }
164 }
165 }
166 OutputProtectionState::EncryptedOutputOnly => match parameters.out_target {
167 EcdhTarget::Compatibility => {
168 if !parameters.out_encrypt || ecdh_out_to_n_plus_1 {
169 bad_param = true;
170 }
171 }
172 EcdhTarget::Slot | EcdhTarget::TempKey => {
173 if parameters.out_encrypt {
174 bad_param = true;
175 }
176 }
177 EcdhTarget::Output => {
178 if !parameters.out_encrypt {
179 bad_param = true;
180 }
181 }
182 },
183 OutputProtectionState::ForbiddenOutputOutsideChip => {
184 match parameters.out_target {
185 EcdhTarget::Compatibility => {
186 if parameters.out_encrypt && ecdh_out_to_n_plus_1 {
187 bad_param = true;
188 }
189 }
190 EcdhTarget::Slot | EcdhTarget::TempKey => {
191 if parameters.out_encrypt {
192 bad_param = true;
193 }
194 }
195 EcdhTarget::Output => bad_param = true,
196 }
197 }
198 _ => bad_param = true,
199 }
200 }
201 }
202
203 if bad_param {
204 return Err(AtcaStatus::AtcaBadParam);
205 }
206
207 if peer_public_key_length != ATCA_ATECC_PUB_KEY_SIZE {
208 return Err(AtcaStatus::AtcaInvalidSize);
209 }
210
211 Ok(slot)
212 } }