1use super::algorithm::{Hash, KeyDerivation, RawKeyAgreement};
7use super::key::Id;
8#[cfg(feature = "operations")]
9use super::status::{Error, Result, Status};
10#[cfg(feature = "operations")]
11use core::convert::TryFrom;
12
13#[derive(Debug, Clone, Copy)]
15pub struct Operation<'a> {
16 pub inputs: Inputs<'a>,
18 pub capacity: Option<usize>,
20}
21
22#[derive(Debug, Clone, Copy)]
24pub enum Inputs<'a> {
25 Hkdf {
27 hash_alg: Hash,
29 salt: Option<Input<'a>>,
32 secret: InputSecret<'a>,
36 info: Input<'a>,
38 },
39 Tls12Prf {
41 hash_alg: Hash,
43 seed: Input<'a>,
45 secret: InputSecret<'a>,
49 label: Input<'a>,
51 },
52 Tls12PskToMs {
54 hash_alg: Hash,
56 seed: Input<'a>,
58 secret: InputSecret<'a>,
63 label: Input<'a>,
65 },
66}
67
68#[cfg(feature = "operations")]
70#[derive(Debug, Clone, Copy)]
71enum DerivationStep {
72 Secret,
74 Label,
76 Salt,
80 Info,
82 Seed,
84}
85
86#[cfg(feature = "operations")]
87impl From<DerivationStep> for psa_crypto_sys::psa_key_derivation_step_t {
88 fn from(derivation_step: DerivationStep) -> Self {
89 match derivation_step {
90 DerivationStep::Secret => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_SECRET,
91 DerivationStep::Label => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_LABEL,
92 DerivationStep::Salt => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_SALT,
93 DerivationStep::Info => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_INFO,
95 DerivationStep::Seed => psa_crypto_sys::PSA_KEY_DERIVATION_INPUT_SEED,
96 }
97 }
98}
99
100#[cfg(feature = "interface")]
101impl From<Inputs<'_>> for psa_crypto_sys::psa_algorithm_t {
102 fn from(key_derivation_with_inputs: Inputs) -> Self {
103 key_derivation_with_inputs.key_derivation().into()
104 }
105}
106
107impl Inputs<'_> {
108 pub fn key_derivation(&self) -> KeyDerivation {
110 match self {
111 Inputs::Hkdf { hash_alg, .. } => KeyDerivation::Hkdf {
112 hash_alg: *hash_alg,
113 },
114 Inputs::Tls12Prf { hash_alg, .. } => KeyDerivation::Tls12Prf {
115 hash_alg: *hash_alg,
116 },
117 Inputs::Tls12PskToMs { hash_alg, .. } => KeyDerivation::Tls12PskToMs {
118 hash_alg: *hash_alg,
119 },
120 }
121 }
122
123 #[cfg(feature = "operations")]
124 pub(crate) fn apply_inputs_to_op(
125 &self,
126 op: &mut psa_crypto_sys::psa_key_derivation_operation_t,
127 ) -> Result<()> {
128 match self {
129 Inputs::Hkdf {
130 salt, secret, info, ..
131 } => {
132 if let Some(salt) = salt {
133 Inputs::apply_input_step_to_op(op, DerivationStep::Salt, salt)?;
134 }
135 Inputs::apply_input_secret_step_to_op(op, secret)?;
136 Inputs::apply_input_step_to_op(op, DerivationStep::Info, info)
137 }
138 Inputs::Tls12Prf {
139 seed,
140 secret,
141 label,
142 ..
143 }
144 | Inputs::Tls12PskToMs {
145 seed,
146 secret,
147 label,
148 ..
149 } => {
150 Inputs::apply_input_step_to_op(op, DerivationStep::Seed, seed)?;
151 Inputs::apply_input_secret_step_to_op(op, secret)?;
152 Inputs::apply_input_step_to_op(op, DerivationStep::Label, label)
153 }
154 }
155 }
156
157 #[cfg(feature = "operations")]
158 fn apply_input_step_to_op(
159 op: &mut psa_crypto_sys::psa_key_derivation_operation_t,
160 step: DerivationStep,
161 input: &Input,
162 ) -> Result<()> {
163 match input {
164 Input::Bytes(bytes) => Status::from(unsafe {
165 psa_crypto_sys::psa_key_derivation_input_bytes(
166 op,
167 step.into(),
168 bytes.as_ptr(),
169 bytes.len(),
170 )
171 })
172 .to_result(),
173 Input::Key(key_id) => Status::from(unsafe {
174 psa_crypto_sys::psa_key_derivation_input_key(op, step.into(), key_id.0)
175 })
176 .to_result(),
177 }
178 }
179
180 #[cfg(feature = "operations")]
181 fn apply_input_secret_step_to_op(
182 op: &mut psa_crypto_sys::psa_key_derivation_operation_t,
183 secret: &InputSecret,
184 ) -> Result<()> {
185 match secret {
186 InputSecret::Input(input) => {
187 Inputs::apply_input_step_to_op(op, DerivationStep::Secret, input)
188 }
189 InputSecret::KeyAgreement {
190 private_key,
191 peer_key,
192 ..
193 } => Status::from(unsafe {
194 psa_crypto_sys::psa_key_derivation_key_agreement(
195 op,
196 DerivationStep::Secret.into(),
197 private_key.0,
198 (**peer_key).as_ptr(),
199 peer_key.len(),
200 )
201 })
202 .to_result(),
203 }
204 }
205}
206
207#[derive(Debug, Clone, Copy)]
209pub enum Input<'a> {
210 Bytes(&'a [u8]),
212 Key(Id),
214}
215
216#[derive(Debug, Clone, Copy)]
218pub enum InputSecret<'a> {
219 Input(Input<'a>),
221 KeyAgreement {
223 alg: RawKeyAgreement,
225 private_key: Id,
227 peer_key: &'a [u8],
230 },
231}
232
233impl<'a> From<Input<'a>> for InputSecret<'a> {
234 fn from(input: Input<'a>) -> Self {
235 InputSecret::<'a>::Input(input)
236 }
237}
238
239#[cfg(feature = "operations")]
240impl TryFrom<Operation<'_>> for psa_crypto_sys::psa_key_derivation_operation_t {
241 type Error = Error;
242
243 fn try_from(operation: Operation) -> Result<Self> {
244 let mut op = psa_crypto_sys::psa_key_derivation_operation_init();
245 let mut setup_deriv_op = || -> Result<()> {
246 let mut key_derivation_alg: psa_crypto_sys::psa_algorithm_t =
247 operation.inputs.key_derivation().into();
248
249 let secret = match operation.inputs {
251 Inputs::Hkdf { secret, .. }
252 | Inputs::Tls12Prf { secret, .. }
253 | Inputs::Tls12PskToMs { secret, .. } => secret,
254 };
255 if let InputSecret::KeyAgreement { alg, .. } = secret {
256 key_derivation_alg = unsafe {
257 psa_crypto_sys::PSA_ALG_KEY_AGREEMENT(alg.into(), key_derivation_alg)
258 };
259 }
260
261 Status::from(unsafe {
262 psa_crypto_sys::psa_key_derivation_setup(&mut op, key_derivation_alg)
263 })
264 .to_result()?;
265 operation.inputs.apply_inputs_to_op(&mut op)
266 };
267 if let Err(error) = setup_deriv_op() {
268 Operation::abort(op)?;
269 return Err(error);
270 }
271
272 if let Some(capacity) = operation.capacity {
273 Status::from(unsafe {
275 psa_crypto_sys::psa_key_derivation_set_capacity(&mut op, capacity)
276 })
277 .to_result()?;
278 }
279 Ok(op)
280 }
281}
282
283impl Operation<'_> {
284 #[cfg(feature = "operations")]
286 pub(crate) fn abort(mut op: psa_crypto_sys::psa_key_derivation_operation_t) -> Result<()> {
287 Status::from(unsafe { psa_crypto_sys::psa_key_derivation_abort(&mut op) }).to_result()
288 }
289}