/rust/registry/src/index.crates.io-6f17d22bba15001f/openssl-0.10.62/src/pkey_ctx.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! The asymmetric encryption context. |
2 | | //! |
3 | | //! # Examples |
4 | | //! |
5 | | //! Encrypt data with RSA |
6 | | //! |
7 | | //! ``` |
8 | | //! use openssl::rsa::Rsa; |
9 | | //! use openssl::pkey::PKey; |
10 | | //! use openssl::pkey_ctx::PkeyCtx; |
11 | | //! |
12 | | //! let key = Rsa::generate(4096).unwrap(); |
13 | | //! let key = PKey::from_rsa(key).unwrap(); |
14 | | //! |
15 | | //! let mut ctx = PkeyCtx::new(&key).unwrap(); |
16 | | //! ctx.encrypt_init().unwrap(); |
17 | | //! |
18 | | //! let data = b"Some Crypto Text"; |
19 | | //! let mut ciphertext = vec![]; |
20 | | //! ctx.encrypt_to_vec(data, &mut ciphertext).unwrap(); |
21 | | //! ``` |
22 | | |
23 | | #![cfg_attr( |
24 | | not(boringssl), |
25 | | doc = r#"\ |
26 | | Generate a CMAC key |
27 | | |
28 | | ``` |
29 | | use openssl::pkey_ctx::PkeyCtx; |
30 | | use openssl::pkey::Id; |
31 | | use openssl::cipher::Cipher; |
32 | | |
33 | | let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap(); |
34 | | ctx.keygen_init().unwrap(); |
35 | | ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap(); |
36 | | ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap(); |
37 | | let cmac_key = ctx.keygen().unwrap(); |
38 | | ```"# |
39 | | )] |
40 | | |
41 | | //! |
42 | | //! Sign and verify data with RSA |
43 | | //! |
44 | | //! ``` |
45 | | //! use openssl::pkey_ctx::PkeyCtx; |
46 | | //! use openssl::pkey::PKey; |
47 | | //! use openssl::rsa::Rsa; |
48 | | //! |
49 | | //! // Generate a random RSA key. |
50 | | //! let key = Rsa::generate(4096).unwrap(); |
51 | | //! let key = PKey::from_rsa(key).unwrap(); |
52 | | //! |
53 | | //! let text = b"Some Crypto Text"; |
54 | | //! |
55 | | //! // Create the signature. |
56 | | //! let mut ctx = PkeyCtx::new(&key).unwrap(); |
57 | | //! ctx.sign_init().unwrap(); |
58 | | //! let mut signature = vec![]; |
59 | | //! ctx.sign_to_vec(text, &mut signature).unwrap(); |
60 | | //! |
61 | | //! // Verify the signature. |
62 | | //! let mut ctx = PkeyCtx::new(&key).unwrap(); |
63 | | //! ctx.verify_init().unwrap(); |
64 | | //! let valid = ctx.verify(text, &signature).unwrap(); |
65 | | //! assert!(valid); |
66 | | //! ``` |
67 | | #[cfg(not(boringssl))] |
68 | | use crate::cipher::CipherRef; |
69 | | use crate::error::ErrorStack; |
70 | | use crate::md::MdRef; |
71 | | use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private}; |
72 | | use crate::rsa::Padding; |
73 | | use crate::sign::RsaPssSaltlen; |
74 | | use crate::{cvt, cvt_p}; |
75 | | use foreign_types::{ForeignType, ForeignTypeRef}; |
76 | | #[cfg(not(boringssl))] |
77 | | use libc::c_int; |
78 | | use openssl_macros::corresponds; |
79 | | use std::convert::TryFrom; |
80 | | use std::ptr; |
81 | | |
82 | | /// HKDF modes of operation. |
83 | | #[cfg(any(ossl111, libressl360))] |
84 | | pub struct HkdfMode(c_int); |
85 | | |
86 | | #[cfg(any(ossl111, libressl360))] |
87 | | impl HkdfMode { |
88 | | /// This is the default mode. Calling [`derive`][PkeyCtxRef::derive] on a [`PkeyCtxRef`] set up |
89 | | /// for HKDF will perform an extract followed by an expand operation in one go. The derived key |
90 | | /// returned will be the result after the expand operation. The intermediate fixed-length |
91 | | /// pseudorandom key K is not returned. |
92 | | pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND); |
93 | | |
94 | | /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the extract operation. |
95 | | /// The value returned will be the intermediate fixed-length pseudorandom key K. |
96 | | /// |
97 | | /// The digest, key and salt values must be set before a key is derived or an error occurs. |
98 | | pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY); |
99 | | |
100 | | /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the expand operation. |
101 | | /// The input key should be set to the intermediate fixed-length pseudorandom key K returned |
102 | | /// from a previous extract operation. |
103 | | /// |
104 | | /// The digest, key and info values must be set before a key is derived or an error occurs. |
105 | | pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY); |
106 | | } |
107 | | |
108 | | generic_foreign_type_and_impl_send_sync! { |
109 | | type CType = ffi::EVP_PKEY_CTX; |
110 | | fn drop = ffi::EVP_PKEY_CTX_free; |
111 | | |
112 | | /// A context object which can perform asymmetric cryptography operations. |
113 | | pub struct PkeyCtx<T>; |
114 | | /// A reference to a [`PkeyCtx`]. |
115 | | pub struct PkeyCtxRef<T>; |
116 | | } |
117 | | |
118 | | impl<T> PkeyCtx<T> { |
119 | | /// Creates a new pkey context using the provided key. |
120 | | #[corresponds(EVP_PKEY_CTX_new)] |
121 | | #[inline] |
122 | 0 | pub fn new(pkey: &PKeyRef<T>) -> Result<Self, ErrorStack> { |
123 | | unsafe { |
124 | 0 | let ptr = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; |
125 | 0 | Ok(PkeyCtx::from_ptr(ptr)) |
126 | | } |
127 | 0 | } |
128 | | } |
129 | | |
130 | | impl PkeyCtx<()> { |
131 | | /// Creates a new pkey context for the specified algorithm ID. |
132 | | #[corresponds(EVP_PKEY_new_id)] |
133 | | #[inline] |
134 | 0 | pub fn new_id(id: Id) -> Result<Self, ErrorStack> { |
135 | | unsafe { |
136 | 0 | let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?; |
137 | 0 | Ok(PkeyCtx::from_ptr(ptr)) |
138 | | } |
139 | 0 | } |
140 | | } |
141 | | |
142 | | impl<T> PkeyCtxRef<T> |
143 | | where |
144 | | T: HasPublic, |
145 | | { |
146 | | /// Prepares the context for encryption using the public key. |
147 | | #[corresponds(EVP_PKEY_encrypt_init)] |
148 | | #[inline] |
149 | 0 | pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> { |
150 | 0 | unsafe { |
151 | 0 | cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?; |
152 | | } |
153 | | |
154 | 0 | Ok(()) |
155 | 0 | } |
156 | | |
157 | | /// Prepares the context for signature verification using the public key. |
158 | | #[corresponds(EVP_PKEY_verify_init)] |
159 | | #[inline] |
160 | 0 | pub fn verify_init(&mut self) -> Result<(), ErrorStack> { |
161 | 0 | unsafe { |
162 | 0 | cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?; |
163 | | } |
164 | | |
165 | 0 | Ok(()) |
166 | 0 | } |
167 | | |
168 | | /// Prepares the context for signature recovery using the public key. |
169 | | #[corresponds(EVP_PKEY_verify_recover_init)] |
170 | | #[inline] |
171 | 0 | pub fn verify_recover_init(&mut self) -> Result<(), ErrorStack> { |
172 | 0 | unsafe { |
173 | 0 | cvt(ffi::EVP_PKEY_verify_recover_init(self.as_ptr()))?; |
174 | | } |
175 | | |
176 | 0 | Ok(()) |
177 | 0 | } |
178 | | |
179 | | /// Encrypts data using the public key. |
180 | | /// |
181 | | /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be |
182 | | /// returned. |
183 | | #[corresponds(EVP_PKEY_encrypt)] |
184 | | #[inline] |
185 | 0 | pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
186 | 0 | let mut written = to.as_ref().map_or(0, |b| b.len()); |
187 | 0 | unsafe { |
188 | 0 | cvt(ffi::EVP_PKEY_encrypt( |
189 | 0 | self.as_ptr(), |
190 | 0 | to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
191 | 0 | &mut written, |
192 | 0 | from.as_ptr(), |
193 | 0 | from.len(), |
194 | 0 | ))?; |
195 | | } |
196 | | |
197 | 0 | Ok(written) |
198 | 0 | } |
199 | | |
200 | | /// Like [`Self::encrypt`] but appends ciphertext to a [`Vec`]. |
201 | 0 | pub fn encrypt_to_vec(&mut self, from: &[u8], out: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
202 | 0 | let base = out.len(); |
203 | 0 | let len = self.encrypt(from, None)?; |
204 | 0 | out.resize(base + len, 0); |
205 | 0 | let len = self.encrypt(from, Some(&mut out[base..]))?; |
206 | 0 | out.truncate(base + len); |
207 | 0 | Ok(len) |
208 | 0 | } |
209 | | |
210 | | /// Verifies the signature of data using the public key. |
211 | | /// |
212 | | /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error |
213 | | /// occurred. |
214 | | /// |
215 | | /// # Note |
216 | | /// |
217 | | /// This verifies the signature of the *raw* data. It is more common to compute and verify the signature of the |
218 | | /// cryptographic hash of an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do |
219 | | /// that. |
220 | | #[corresponds(EVP_PKEY_verify)] |
221 | | #[inline] |
222 | 0 | pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result<bool, ErrorStack> { |
223 | 0 | unsafe { |
224 | 0 | let r = ffi::EVP_PKEY_verify( |
225 | 0 | self.as_ptr(), |
226 | 0 | sig.as_ptr(), |
227 | 0 | sig.len(), |
228 | 0 | data.as_ptr(), |
229 | 0 | data.len(), |
230 | 0 | ); |
231 | 0 | // `EVP_PKEY_verify` is not terribly consistent about how it, |
232 | 0 | // reports errors. It does not clearly distinguish between 0 and |
233 | 0 | // -1, and may put errors on the stack in both cases. If there's |
234 | 0 | // errors on the stack, we return `Err()`, else we return |
235 | 0 | // `Ok(false)`. |
236 | 0 | if r <= 0 { |
237 | 0 | let errors = ErrorStack::get(); |
238 | 0 | if !errors.errors().is_empty() { |
239 | 0 | return Err(errors); |
240 | 0 | } |
241 | 0 | } |
242 | | |
243 | 0 | Ok(r == 1) |
244 | | } |
245 | 0 | } |
246 | | |
247 | | /// Recovers the original data signed by the private key. You almost |
248 | | /// always want `verify` instead. |
249 | | /// |
250 | | /// Returns the number of bytes written to `to`, or the number of bytes |
251 | | /// that would be written, if `to` is `None. |
252 | | #[corresponds(EVP_PKEY_verify_recover)] |
253 | | #[inline] |
254 | 0 | pub fn verify_recover( |
255 | 0 | &mut self, |
256 | 0 | sig: &[u8], |
257 | 0 | to: Option<&mut [u8]>, |
258 | 0 | ) -> Result<usize, ErrorStack> { |
259 | 0 | let mut written = to.as_ref().map_or(0, |b| b.len()); |
260 | 0 | unsafe { |
261 | 0 | cvt(ffi::EVP_PKEY_verify_recover( |
262 | 0 | self.as_ptr(), |
263 | 0 | to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
264 | 0 | &mut written, |
265 | 0 | sig.as_ptr(), |
266 | 0 | sig.len(), |
267 | 0 | ))?; |
268 | | } |
269 | | |
270 | 0 | Ok(written) |
271 | 0 | } |
272 | | } |
273 | | |
274 | | impl<T> PkeyCtxRef<T> |
275 | | where |
276 | | T: HasPrivate, |
277 | | { |
278 | | /// Prepares the context for decryption using the private key. |
279 | | #[corresponds(EVP_PKEY_decrypt_init)] |
280 | | #[inline] |
281 | 0 | pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> { |
282 | 0 | unsafe { |
283 | 0 | cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?; |
284 | | } |
285 | | |
286 | 0 | Ok(()) |
287 | 0 | } |
288 | | |
289 | | /// Prepares the context for signing using the private key. |
290 | | #[corresponds(EVP_PKEY_sign_init)] |
291 | | #[inline] |
292 | 0 | pub fn sign_init(&mut self) -> Result<(), ErrorStack> { |
293 | 0 | unsafe { |
294 | 0 | cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?; |
295 | | } |
296 | | |
297 | 0 | Ok(()) |
298 | 0 | } |
299 | | |
300 | | /// Sets the peer key used for secret derivation. |
301 | | #[corresponds(EVP_PKEY_derive_set_peer)] |
302 | 0 | pub fn derive_set_peer<U>(&mut self, key: &PKeyRef<U>) -> Result<(), ErrorStack> |
303 | 0 | where |
304 | 0 | U: HasPublic, |
305 | 0 | { |
306 | 0 | unsafe { |
307 | 0 | cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), key.as_ptr()))?; |
308 | | } |
309 | | |
310 | 0 | Ok(()) |
311 | 0 | } |
312 | | |
313 | | /// Decrypts data using the private key. |
314 | | /// |
315 | | /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be |
316 | | /// returned. |
317 | | #[corresponds(EVP_PKEY_decrypt)] |
318 | | #[inline] |
319 | 0 | pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
320 | 0 | let mut written = to.as_ref().map_or(0, |b| b.len()); |
321 | 0 | unsafe { |
322 | 0 | cvt(ffi::EVP_PKEY_decrypt( |
323 | 0 | self.as_ptr(), |
324 | 0 | to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
325 | 0 | &mut written, |
326 | 0 | from.as_ptr(), |
327 | 0 | from.len(), |
328 | 0 | ))?; |
329 | | } |
330 | | |
331 | 0 | Ok(written) |
332 | 0 | } |
333 | | |
334 | | /// Like [`Self::decrypt`] but appends plaintext to a [`Vec`]. |
335 | 0 | pub fn decrypt_to_vec(&mut self, from: &[u8], out: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
336 | 0 | let base = out.len(); |
337 | 0 | let len = self.decrypt(from, None)?; |
338 | 0 | out.resize(base + len, 0); |
339 | 0 | let len = self.decrypt(from, Some(&mut out[base..]))?; |
340 | 0 | out.truncate(base + len); |
341 | 0 | Ok(len) |
342 | 0 | } |
343 | | |
344 | | /// Signs the contents of `data`. |
345 | | /// |
346 | | /// If `sig` is set to `None`, an upper bound on the number of bytes required for the output buffer will be |
347 | | /// returned. |
348 | | /// |
349 | | /// # Note |
350 | | /// |
351 | | /// This computes the signature of the *raw* bytes of `data`. It is more common to sign the cryptographic hash of |
352 | | /// an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do that. |
353 | | #[corresponds(EVP_PKEY_sign)] |
354 | | #[inline] |
355 | 0 | pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
356 | 0 | let mut written = sig.as_ref().map_or(0, |b| b.len()); |
357 | 0 | unsafe { |
358 | 0 | cvt(ffi::EVP_PKEY_sign( |
359 | 0 | self.as_ptr(), |
360 | 0 | sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
361 | 0 | &mut written, |
362 | 0 | data.as_ptr(), |
363 | 0 | data.len(), |
364 | 0 | ))?; |
365 | | } |
366 | | |
367 | 0 | Ok(written) |
368 | 0 | } |
369 | | |
370 | | /// Like [`Self::sign`] but appends the signature to a [`Vec`]. |
371 | 0 | pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
372 | 0 | let base = sig.len(); |
373 | 0 | let len = self.sign(data, None)?; |
374 | 0 | sig.resize(base + len, 0); |
375 | 0 | let len = self.sign(data, Some(&mut sig[base..]))?; |
376 | 0 | sig.truncate(base + len); |
377 | 0 | Ok(len) |
378 | 0 | } |
379 | | } |
380 | | |
381 | | impl<T> PkeyCtxRef<T> { |
382 | | /// Prepares the context for shared secret derivation. |
383 | | #[corresponds(EVP_PKEY_derive_init)] |
384 | | #[inline] |
385 | 0 | pub fn derive_init(&mut self) -> Result<(), ErrorStack> { |
386 | 0 | unsafe { |
387 | 0 | cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?; |
388 | | } |
389 | | |
390 | 0 | Ok(()) |
391 | 0 | } |
392 | | |
393 | | /// Prepares the context for key generation. |
394 | | #[corresponds(EVP_PKEY_keygen_init)] |
395 | | #[inline] |
396 | 0 | pub fn keygen_init(&mut self) -> Result<(), ErrorStack> { |
397 | 0 | unsafe { |
398 | 0 | cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?; |
399 | | } |
400 | | |
401 | 0 | Ok(()) |
402 | 0 | } |
403 | | |
404 | | /// Sets which algorithm was used to compute the digest used in a |
405 | | /// signature. With RSA signatures this causes the signature to be wrapped |
406 | | /// in a `DigestInfo` structure. This is almost always what you want with |
407 | | /// RSA signatures. |
408 | | #[corresponds(EVP_PKEY_CTX_set_signature_md)] |
409 | | #[inline] |
410 | 0 | pub fn set_signature_md(&self, md: &MdRef) -> Result<(), ErrorStack> { |
411 | 0 | unsafe { |
412 | 0 | cvt(ffi::EVP_PKEY_CTX_set_signature_md( |
413 | 0 | self.as_ptr(), |
414 | 0 | md.as_ptr(), |
415 | 0 | ))?; |
416 | | } |
417 | 0 | Ok(()) |
418 | 0 | } |
419 | | |
420 | | /// Returns the RSA padding mode in use. |
421 | | /// |
422 | | /// This is only useful for RSA keys. |
423 | | #[corresponds(EVP_PKEY_CTX_get_rsa_padding)] |
424 | | #[inline] |
425 | 0 | pub fn rsa_padding(&self) -> Result<Padding, ErrorStack> { |
426 | 0 | let mut pad = 0; |
427 | 0 | unsafe { |
428 | 0 | cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))?; |
429 | | } |
430 | | |
431 | 0 | Ok(Padding::from_raw(pad)) |
432 | 0 | } |
433 | | |
434 | | /// Sets the RSA padding mode. |
435 | | /// |
436 | | /// This is only useful for RSA keys. |
437 | | #[corresponds(EVP_PKEY_CTX_set_rsa_padding)] |
438 | | #[inline] |
439 | 0 | pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { |
440 | 0 | unsafe { |
441 | 0 | cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( |
442 | 0 | self.as_ptr(), |
443 | 0 | padding.as_raw(), |
444 | 0 | ))?; |
445 | | } |
446 | | |
447 | 0 | Ok(()) |
448 | 0 | } |
449 | | |
450 | | /// Sets the RSA PSS salt length. |
451 | | /// |
452 | | /// This is only useful for RSA keys. |
453 | | #[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)] |
454 | | #[inline] |
455 | 0 | pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { |
456 | 0 | unsafe { |
457 | 0 | cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( |
458 | 0 | self.as_ptr(), |
459 | 0 | len.as_raw(), |
460 | 0 | )) |
461 | 0 | .map(|_| ()) |
462 | 0 | } |
463 | 0 | } |
464 | | |
465 | | /// Sets the RSA MGF1 algorithm. |
466 | | /// |
467 | | /// This is only useful for RSA keys. |
468 | | #[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)] |
469 | | #[inline] |
470 | 0 | pub fn set_rsa_mgf1_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { |
471 | 0 | unsafe { |
472 | 0 | cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( |
473 | 0 | self.as_ptr(), |
474 | 0 | md.as_ptr(), |
475 | 0 | ))?; |
476 | | } |
477 | | |
478 | 0 | Ok(()) |
479 | 0 | } |
480 | | |
481 | | /// Sets the RSA OAEP algorithm. |
482 | | /// |
483 | | /// This is only useful for RSA keys. |
484 | | #[corresponds(EVP_PKEY_CTX_set_rsa_oaep_md)] |
485 | | #[cfg(any(ossl102, libressl310, boringssl))] |
486 | | #[inline] |
487 | 0 | pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { |
488 | 0 | unsafe { |
489 | 0 | cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( |
490 | 0 | self.as_ptr(), |
491 | 0 | md.as_ptr() as *mut _, |
492 | 0 | ))?; |
493 | | } |
494 | | |
495 | 0 | Ok(()) |
496 | 0 | } |
497 | | |
498 | | /// Sets the RSA OAEP label. |
499 | | /// |
500 | | /// This is only useful for RSA keys. |
501 | | #[corresponds(EVP_PKEY_CTX_set0_rsa_oaep_label)] |
502 | | #[cfg(any(ossl102, libressl310, boringssl))] |
503 | 0 | pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { |
504 | | use crate::LenType; |
505 | 0 | let len = LenType::try_from(label.len()).unwrap(); |
506 | 0 |
|
507 | 0 | unsafe { |
508 | 0 | let p = ffi::OPENSSL_malloc(label.len() as _); |
509 | 0 | ptr::copy_nonoverlapping(label.as_ptr(), p as *mut _, label.len()); |
510 | 0 |
|
511 | 0 | let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( |
512 | 0 | self.as_ptr(), |
513 | 0 | p as *mut _, |
514 | 0 | len, |
515 | 0 | )); |
516 | 0 | if r.is_err() { |
517 | 0 | ffi::OPENSSL_free(p); |
518 | 0 | } |
519 | 0 | r?; |
520 | | } |
521 | | |
522 | 0 | Ok(()) |
523 | 0 | } |
524 | | |
525 | | /// Sets the cipher used during key generation. |
526 | | #[cfg(not(boringssl))] |
527 | | #[corresponds(EVP_PKEY_CTX_ctrl)] |
528 | | #[inline] |
529 | 0 | pub fn set_keygen_cipher(&mut self, cipher: &CipherRef) -> Result<(), ErrorStack> { |
530 | 0 | unsafe { |
531 | 0 | cvt(ffi::EVP_PKEY_CTX_ctrl( |
532 | 0 | self.as_ptr(), |
533 | 0 | -1, |
534 | 0 | ffi::EVP_PKEY_OP_KEYGEN, |
535 | 0 | ffi::EVP_PKEY_CTRL_CIPHER, |
536 | 0 | 0, |
537 | 0 | cipher.as_ptr() as *mut _, |
538 | 0 | ))?; |
539 | | } |
540 | | |
541 | 0 | Ok(()) |
542 | 0 | } |
543 | | |
544 | | /// Sets the key MAC key used during key generation. |
545 | | #[cfg(not(boringssl))] |
546 | | #[corresponds(EVP_PKEY_CTX_ctrl)] |
547 | | #[inline] |
548 | 0 | pub fn set_keygen_mac_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { |
549 | 0 | let len = c_int::try_from(key.len()).unwrap(); |
550 | 0 |
|
551 | 0 | unsafe { |
552 | 0 | cvt(ffi::EVP_PKEY_CTX_ctrl( |
553 | 0 | self.as_ptr(), |
554 | 0 | -1, |
555 | 0 | ffi::EVP_PKEY_OP_KEYGEN, |
556 | 0 | ffi::EVP_PKEY_CTRL_SET_MAC_KEY, |
557 | 0 | len, |
558 | 0 | key.as_ptr() as *mut _, |
559 | 0 | ))?; |
560 | | } |
561 | | |
562 | 0 | Ok(()) |
563 | 0 | } |
564 | | |
565 | | /// Sets the digest used for HKDF derivation. |
566 | | /// |
567 | | /// Requires OpenSSL 1.1.0 or newer. |
568 | | #[corresponds(EVP_PKEY_CTX_set_hkdf_md)] |
569 | | #[cfg(any(ossl110, boringssl, libressl360))] |
570 | | #[inline] |
571 | 0 | pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { |
572 | 0 | unsafe { |
573 | 0 | cvt(ffi::EVP_PKEY_CTX_set_hkdf_md( |
574 | 0 | self.as_ptr(), |
575 | 0 | digest.as_ptr(), |
576 | 0 | ))?; |
577 | | } |
578 | | |
579 | 0 | Ok(()) |
580 | 0 | } |
581 | | |
582 | | /// Sets the HKDF mode of operation. |
583 | | /// |
584 | | /// Defaults to [`HkdfMode::EXTRACT_THEN_EXPAND`]. |
585 | | /// |
586 | | /// WARNING: Although this API calls it a "mode", HKDF-Extract and HKDF-Expand are distinct |
587 | | /// operations with distinct inputs and distinct kinds of keys. Callers should not pass input |
588 | | /// secrets for one operation into the other. |
589 | | /// |
590 | | /// Requires OpenSSL 1.1.1 or newer. |
591 | | #[corresponds(EVP_PKEY_CTX_set_hkdf_mode)] |
592 | | #[cfg(any(ossl111, libressl360))] |
593 | | #[inline] |
594 | 0 | pub fn set_hkdf_mode(&mut self, mode: HkdfMode) -> Result<(), ErrorStack> { |
595 | 0 | unsafe { |
596 | 0 | cvt(ffi::EVP_PKEY_CTX_set_hkdf_mode(self.as_ptr(), mode.0))?; |
597 | | } |
598 | | |
599 | 0 | Ok(()) |
600 | 0 | } |
601 | | |
602 | | /// Sets the input material for HKDF generation as the "key". |
603 | | /// |
604 | | /// Which input is the key depends on the "mode" (see [`set_hkdf_mode`][Self::set_hkdf_mode]). |
605 | | /// If [`HkdfMode::EXTRACT_THEN_EXPAND`] or [`HkdfMode::EXTRACT_ONLY`], this function specifies |
606 | | /// the input keying material (IKM) for HKDF-Extract. If [`HkdfMode::EXPAND_ONLY`], it instead |
607 | | /// specifies the pseudorandom key (PRK) for HKDF-Expand. |
608 | | /// |
609 | | /// Requires OpenSSL 1.1.0 or newer. |
610 | | #[corresponds(EVP_PKEY_CTX_set1_hkdf_key)] |
611 | | #[cfg(any(ossl110, boringssl, libressl360))] |
612 | | #[inline] |
613 | 0 | pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { |
614 | 0 | #[cfg(not(boringssl))] |
615 | 0 | let len = c_int::try_from(key.len()).unwrap(); |
616 | 0 | #[cfg(boringssl)] |
617 | 0 | let len = key.len(); |
618 | 0 |
|
619 | 0 | unsafe { |
620 | 0 | cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key( |
621 | 0 | self.as_ptr(), |
622 | 0 | key.as_ptr(), |
623 | 0 | len, |
624 | 0 | ))?; |
625 | | } |
626 | | |
627 | 0 | Ok(()) |
628 | 0 | } |
629 | | |
630 | | /// Sets the salt value for HKDF generation. |
631 | | /// |
632 | | /// If performing HKDF-Expand only, this parameter is ignored. |
633 | | /// |
634 | | /// Requires OpenSSL 1.1.0 or newer. |
635 | | #[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)] |
636 | | #[cfg(any(ossl110, boringssl, libressl360))] |
637 | | #[inline] |
638 | 0 | pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> { |
639 | 0 | #[cfg(not(boringssl))] |
640 | 0 | let len = c_int::try_from(salt.len()).unwrap(); |
641 | 0 | #[cfg(boringssl)] |
642 | 0 | let len = salt.len(); |
643 | 0 |
|
644 | 0 | unsafe { |
645 | 0 | cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt( |
646 | 0 | self.as_ptr(), |
647 | 0 | salt.as_ptr(), |
648 | 0 | len, |
649 | 0 | ))?; |
650 | | } |
651 | | |
652 | 0 | Ok(()) |
653 | 0 | } |
654 | | |
655 | | /// Appends info bytes for HKDF generation. |
656 | | /// |
657 | | /// If performing HKDF-Extract only, this parameter is ignored. |
658 | | /// |
659 | | /// Requires OpenSSL 1.1.0 or newer. |
660 | | #[corresponds(EVP_PKEY_CTX_add1_hkdf_info)] |
661 | | #[cfg(any(ossl110, boringssl, libressl360))] |
662 | | #[inline] |
663 | 0 | pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> { |
664 | 0 | #[cfg(not(boringssl))] |
665 | 0 | let len = c_int::try_from(info.len()).unwrap(); |
666 | 0 | #[cfg(boringssl)] |
667 | 0 | let len = info.len(); |
668 | 0 |
|
669 | 0 | unsafe { |
670 | 0 | cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info( |
671 | 0 | self.as_ptr(), |
672 | 0 | info.as_ptr(), |
673 | 0 | len, |
674 | 0 | ))?; |
675 | | } |
676 | | |
677 | 0 | Ok(()) |
678 | 0 | } |
679 | | |
680 | | /// Derives a shared secret between two keys. |
681 | | /// |
682 | | /// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned. |
683 | | #[corresponds(EVP_PKEY_derive)] |
684 | 0 | pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result<usize, ErrorStack> { |
685 | 0 | let mut len = buf.as_ref().map_or(0, |b| b.len()); |
686 | 0 | unsafe { |
687 | 0 | cvt(ffi::EVP_PKEY_derive( |
688 | 0 | self.as_ptr(), |
689 | 0 | buf.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), |
690 | 0 | &mut len, |
691 | 0 | ))?; |
692 | | } |
693 | | |
694 | 0 | Ok(len) |
695 | 0 | } |
696 | | |
697 | | /// Like [`Self::derive`] but appends the secret to a [`Vec`]. |
698 | 0 | pub fn derive_to_vec(&mut self, buf: &mut Vec<u8>) -> Result<usize, ErrorStack> { |
699 | 0 | let base = buf.len(); |
700 | 0 | let len = self.derive(None)?; |
701 | 0 | buf.resize(base + len, 0); |
702 | 0 | let len = self.derive(Some(&mut buf[base..]))?; |
703 | 0 | buf.truncate(base + len); |
704 | 0 | Ok(len) |
705 | 0 | } |
706 | | |
707 | | /// Generates a new public/private keypair. |
708 | | #[corresponds(EVP_PKEY_keygen)] |
709 | | #[inline] |
710 | 0 | pub fn keygen(&mut self) -> Result<PKey<Private>, ErrorStack> { |
711 | 0 | unsafe { |
712 | 0 | let mut key = ptr::null_mut(); |
713 | 0 | cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?; |
714 | 0 | Ok(PKey::from_ptr(key)) |
715 | | } |
716 | 0 | } |
717 | | } |
718 | | |
719 | | #[cfg(test)] |
720 | | mod test { |
721 | | use super::*; |
722 | | #[cfg(not(boringssl))] |
723 | | use crate::cipher::Cipher; |
724 | | use crate::ec::{EcGroup, EcKey}; |
725 | | use crate::hash::{hash, MessageDigest}; |
726 | | use crate::md::Md; |
727 | | use crate::nid::Nid; |
728 | | use crate::pkey::PKey; |
729 | | use crate::rsa::Rsa; |
730 | | use crate::sign::Verifier; |
731 | | |
732 | | #[test] |
733 | | fn rsa() { |
734 | | let key = include_bytes!("../test/rsa.pem"); |
735 | | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
736 | | let pkey = PKey::from_rsa(rsa).unwrap(); |
737 | | |
738 | | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
739 | | ctx.encrypt_init().unwrap(); |
740 | | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
741 | | |
742 | | let pt = "hello world".as_bytes(); |
743 | | let mut ct = vec![]; |
744 | | ctx.encrypt_to_vec(pt, &mut ct).unwrap(); |
745 | | |
746 | | ctx.decrypt_init().unwrap(); |
747 | | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
748 | | |
749 | | let mut out = vec![]; |
750 | | ctx.decrypt_to_vec(&ct, &mut out).unwrap(); |
751 | | |
752 | | assert_eq!(pt, out); |
753 | | } |
754 | | |
755 | | #[test] |
756 | | #[cfg(any(ossl102, libressl310, boringssl))] |
757 | | fn rsa_oaep() { |
758 | | let key = include_bytes!("../test/rsa.pem"); |
759 | | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
760 | | let pkey = PKey::from_rsa(rsa).unwrap(); |
761 | | |
762 | | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
763 | | ctx.encrypt_init().unwrap(); |
764 | | ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); |
765 | | ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); |
766 | | ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); |
767 | | |
768 | | let pt = "hello world".as_bytes(); |
769 | | let mut ct = vec![]; |
770 | | ctx.encrypt_to_vec(pt, &mut ct).unwrap(); |
771 | | |
772 | | ctx.decrypt_init().unwrap(); |
773 | | ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); |
774 | | ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); |
775 | | ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); |
776 | | |
777 | | let mut out = vec![]; |
778 | | ctx.decrypt_to_vec(&ct, &mut out).unwrap(); |
779 | | |
780 | | assert_eq!(pt, out); |
781 | | } |
782 | | |
783 | | #[test] |
784 | | fn rsa_sign() { |
785 | | let key = include_bytes!("../test/rsa.pem"); |
786 | | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
787 | | let pkey = PKey::from_rsa(rsa).unwrap(); |
788 | | |
789 | | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
790 | | ctx.sign_init().unwrap(); |
791 | | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
792 | | ctx.set_signature_md(Md::sha384()).unwrap(); |
793 | | |
794 | | let msg = b"hello world"; |
795 | | let digest = hash(MessageDigest::sha384(), msg).unwrap(); |
796 | | let mut signature = vec![]; |
797 | | ctx.sign_to_vec(&digest, &mut signature).unwrap(); |
798 | | |
799 | | let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); |
800 | | verifier.update(msg).unwrap(); |
801 | | assert!(matches!(verifier.verify(&signature), Ok(true))); |
802 | | } |
803 | | |
804 | | #[test] |
805 | | fn rsa_sign_pss() { |
806 | | let key = include_bytes!("../test/rsa.pem"); |
807 | | let rsa = Rsa::private_key_from_pem(key).unwrap(); |
808 | | let pkey = PKey::from_rsa(rsa).unwrap(); |
809 | | |
810 | | let mut ctx = PkeyCtx::new(&pkey).unwrap(); |
811 | | ctx.sign_init().unwrap(); |
812 | | ctx.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); |
813 | | ctx.set_signature_md(Md::sha384()).unwrap(); |
814 | | ctx.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)).unwrap(); |
815 | | |
816 | | let msg = b"hello world"; |
817 | | let digest = hash(MessageDigest::sha384(), msg).unwrap(); |
818 | | let mut signature = vec![]; |
819 | | ctx.sign_to_vec(&digest, &mut signature).unwrap(); |
820 | | |
821 | | let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); |
822 | | verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); |
823 | | verifier |
824 | | .set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)) |
825 | | .unwrap(); |
826 | | verifier.update(msg).unwrap(); |
827 | | assert!(matches!(verifier.verify(&signature), Ok(true))); |
828 | | } |
829 | | |
830 | | #[test] |
831 | | fn derive() { |
832 | | let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); |
833 | | let key1 = EcKey::generate(&group).unwrap(); |
834 | | let key1 = PKey::from_ec_key(key1).unwrap(); |
835 | | let key2 = EcKey::generate(&group).unwrap(); |
836 | | let key2 = PKey::from_ec_key(key2).unwrap(); |
837 | | |
838 | | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
839 | | ctx.derive_init().unwrap(); |
840 | | ctx.derive_set_peer(&key2).unwrap(); |
841 | | |
842 | | let mut buf = vec![]; |
843 | | ctx.derive_to_vec(&mut buf).unwrap(); |
844 | | } |
845 | | |
846 | | #[test] |
847 | | #[cfg(not(boringssl))] |
848 | | fn cmac_keygen() { |
849 | | let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap(); |
850 | | ctx.keygen_init().unwrap(); |
851 | | ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap(); |
852 | | ctx.set_keygen_mac_key(&hex::decode("9294727a3638bb1c13f48ef8158bfc9d").unwrap()) |
853 | | .unwrap(); |
854 | | ctx.keygen().unwrap(); |
855 | | } |
856 | | |
857 | | #[test] |
858 | | #[cfg(any(ossl110, boringssl, libressl360))] |
859 | | fn hkdf() { |
860 | | let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); |
861 | | ctx.derive_init().unwrap(); |
862 | | ctx.set_hkdf_md(Md::sha256()).unwrap(); |
863 | | ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap()) |
864 | | .unwrap(); |
865 | | ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap()) |
866 | | .unwrap(); |
867 | | ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap()) |
868 | | .unwrap(); |
869 | | let mut out = [0; 42]; |
870 | | ctx.derive(Some(&mut out)).unwrap(); |
871 | | |
872 | | assert_eq!( |
873 | | &out[..], |
874 | | hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") |
875 | | .unwrap() |
876 | | ); |
877 | | } |
878 | | |
879 | | #[test] |
880 | | #[cfg(any(ossl111, libressl360))] |
881 | | fn hkdf_expand() { |
882 | | let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); |
883 | | ctx.derive_init().unwrap(); |
884 | | ctx.set_hkdf_mode(HkdfMode::EXPAND_ONLY).unwrap(); |
885 | | ctx.set_hkdf_md(Md::sha256()).unwrap(); |
886 | | ctx.set_hkdf_key( |
887 | | &hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") |
888 | | .unwrap(), |
889 | | ) |
890 | | .unwrap(); |
891 | | ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap()) |
892 | | .unwrap(); |
893 | | let mut out = [0; 42]; |
894 | | ctx.derive(Some(&mut out)).unwrap(); |
895 | | |
896 | | assert_eq!( |
897 | | &out[..], |
898 | | hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") |
899 | | .unwrap() |
900 | | ); |
901 | | } |
902 | | |
903 | | #[test] |
904 | | #[cfg(any(ossl111, libressl360))] |
905 | | fn hkdf_extract() { |
906 | | let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); |
907 | | ctx.derive_init().unwrap(); |
908 | | ctx.set_hkdf_mode(HkdfMode::EXTRACT_ONLY).unwrap(); |
909 | | ctx.set_hkdf_md(Md::sha256()).unwrap(); |
910 | | ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap()) |
911 | | .unwrap(); |
912 | | ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap()) |
913 | | .unwrap(); |
914 | | let mut out = vec![]; |
915 | | ctx.derive_to_vec(&mut out).unwrap(); |
916 | | |
917 | | assert_eq!( |
918 | | &out[..], |
919 | | hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") |
920 | | .unwrap() |
921 | | ); |
922 | | } |
923 | | |
924 | | #[test] |
925 | | fn verify_fail() { |
926 | | let key1 = Rsa::generate(4096).unwrap(); |
927 | | let key1 = PKey::from_rsa(key1).unwrap(); |
928 | | |
929 | | let data = b"Some Crypto Text"; |
930 | | |
931 | | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
932 | | ctx.sign_init().unwrap(); |
933 | | let mut signature = vec![]; |
934 | | ctx.sign_to_vec(data, &mut signature).unwrap(); |
935 | | |
936 | | let bad_data = b"Some Crypto text"; |
937 | | |
938 | | ctx.verify_init().unwrap(); |
939 | | let valid = ctx.verify(bad_data, &signature); |
940 | | assert!(matches!(valid, Ok(false) | Err(_))); |
941 | | assert!(ErrorStack::get().errors().is_empty()); |
942 | | } |
943 | | |
944 | | #[test] |
945 | | fn verify_fail_ec() { |
946 | | let key1 = |
947 | | EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap(); |
948 | | let key1 = PKey::from_ec_key(key1).unwrap(); |
949 | | |
950 | | let data = b"Some Crypto Text"; |
951 | | let mut ctx = PkeyCtx::new(&key1).unwrap(); |
952 | | ctx.verify_init().unwrap(); |
953 | | assert!(matches!(ctx.verify(data, &[0; 64]), Ok(false) | Err(_))); |
954 | | assert!(ErrorStack::get().errors().is_empty()); |
955 | | } |
956 | | |
957 | | #[test] |
958 | | fn test_verify_recover() { |
959 | | let key = Rsa::generate(2048).unwrap(); |
960 | | let key = PKey::from_rsa(key).unwrap(); |
961 | | |
962 | | let digest = [ |
963 | | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, |
964 | | 24, 25, 26, 27, 28, 29, 30, 31, |
965 | | ]; |
966 | | |
967 | | let mut ctx = PkeyCtx::new(&key).unwrap(); |
968 | | ctx.sign_init().unwrap(); |
969 | | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
970 | | ctx.set_signature_md(Md::sha256()).unwrap(); |
971 | | let mut signature = vec![]; |
972 | | ctx.sign_to_vec(&digest, &mut signature).unwrap(); |
973 | | |
974 | | // Attempt recovery of just the digest. |
975 | | let mut ctx = PkeyCtx::new(&key).unwrap(); |
976 | | ctx.verify_recover_init().unwrap(); |
977 | | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
978 | | ctx.set_signature_md(Md::sha256()).unwrap(); |
979 | | let length = ctx.verify_recover(&signature, None).unwrap(); |
980 | | let mut result_buf = vec![0; length]; |
981 | | let length = ctx |
982 | | .verify_recover(&signature, Some(&mut result_buf)) |
983 | | .unwrap(); |
984 | | assert_eq!(length, digest.len()); |
985 | | // result_buf contains the digest |
986 | | assert_eq!(result_buf[..length], digest); |
987 | | |
988 | | // Attempt recovery of teh entire DigestInfo |
989 | | let mut ctx = PkeyCtx::new(&key).unwrap(); |
990 | | ctx.verify_recover_init().unwrap(); |
991 | | ctx.set_rsa_padding(Padding::PKCS1).unwrap(); |
992 | | let length = ctx.verify_recover(&signature, None).unwrap(); |
993 | | let mut result_buf = vec![0; length]; |
994 | | let length = ctx |
995 | | .verify_recover(&signature, Some(&mut result_buf)) |
996 | | .unwrap(); |
997 | | // 32-bytes of SHA256 digest + the ASN.1 DigestInfo structure == 51 bytes |
998 | | assert_eq!(length, 51); |
999 | | // The digest is the end of the DigestInfo structure. |
1000 | | assert_eq!(result_buf[length - digest.len()..length], digest); |
1001 | | } |
1002 | | } |