/rust/registry/src/index.crates.io-1949cf8c6b5b557f/openssl-0.10.62/src/dh.rs
Line | Count | Source |
1 | | //! Diffie-Hellman key agreement. |
2 | | |
3 | | use cfg_if::cfg_if; |
4 | | use foreign_types::{ForeignType, ForeignTypeRef}; |
5 | | use std::mem; |
6 | | use std::ptr; |
7 | | |
8 | | use crate::bn::{BigNum, BigNumRef}; |
9 | | use crate::error::ErrorStack; |
10 | | use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; |
11 | | use crate::{cvt, cvt_p}; |
12 | | use openssl_macros::corresponds; |
13 | | |
14 | | generic_foreign_type_and_impl_send_sync! { |
15 | | type CType = ffi::DH; |
16 | | fn drop = ffi::DH_free; |
17 | | |
18 | | pub struct Dh<T>; |
19 | | |
20 | | pub struct DhRef<T>; |
21 | | } |
22 | | |
23 | | impl<T> DhRef<T> |
24 | | where |
25 | | T: HasParams, |
26 | | { |
27 | | to_pem! { |
28 | | /// Serializes the parameters into a PEM-encoded PKCS#3 DHparameter structure. |
29 | | /// |
30 | | /// The output will have a header of `-----BEGIN DH PARAMETERS-----`. |
31 | | #[corresponds(PEM_write_bio_DHparams)] |
32 | | params_to_pem, |
33 | | ffi::PEM_write_bio_DHparams |
34 | | } |
35 | | |
36 | | to_der! { |
37 | | /// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure. |
38 | | #[corresponds(i2d_DHparams)] |
39 | | params_to_der, |
40 | | ffi::i2d_DHparams |
41 | | } |
42 | | |
43 | | /// Validates DH parameters for correctness |
44 | | #[corresponds(DH_check_key)] |
45 | 0 | pub fn check_key(&self) -> Result<bool, ErrorStack> { |
46 | | unsafe { |
47 | 0 | let mut codes = 0; |
48 | 0 | cvt(ffi::DH_check(self.as_ptr(), &mut codes))?; |
49 | 0 | Ok(codes == 0) |
50 | | } |
51 | 0 | } |
52 | | } |
53 | | |
54 | | impl Dh<Params> { |
55 | 0 | pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh<Params>, ErrorStack> { |
56 | 0 | Self::from_pqg(p, Some(q), g) |
57 | 0 | } |
58 | | |
59 | | /// Creates a DH instance based upon the given primes and generator params. |
60 | | #[corresponds(DH_set0_pqg)] |
61 | 0 | pub fn from_pqg( |
62 | 0 | prime_p: BigNum, |
63 | 0 | prime_q: Option<BigNum>, |
64 | 0 | generator: BigNum, |
65 | 0 | ) -> Result<Dh<Params>, ErrorStack> { |
66 | | unsafe { |
67 | 0 | let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); |
68 | 0 | cvt(DH_set0_pqg( |
69 | 0 | dh.0, |
70 | 0 | prime_p.as_ptr(), |
71 | 0 | prime_q.as_ref().map_or(ptr::null_mut(), |q| q.as_ptr()), |
72 | 0 | generator.as_ptr(), |
73 | 0 | ))?; |
74 | 0 | mem::forget((prime_p, prime_q, generator)); |
75 | 0 | Ok(dh) |
76 | | } |
77 | 0 | } |
78 | | |
79 | | /// Sets the public key on the DH object. |
80 | 0 | pub fn set_public_key(self, pub_key: BigNum) -> Result<Dh<Public>, ErrorStack> { |
81 | | unsafe { |
82 | 0 | let dh_ptr = self.0; |
83 | 0 | cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), ptr::null_mut()))?; |
84 | 0 | mem::forget((self, pub_key)); |
85 | 0 | Ok(Dh::from_ptr(dh_ptr)) |
86 | | } |
87 | 0 | } |
88 | | |
89 | | /// Sets the private key on the DH object and recomputes the public key. |
90 | 0 | pub fn set_private_key(self, priv_key: BigNum) -> Result<Dh<Private>, ErrorStack> { |
91 | | unsafe { |
92 | 0 | let dh_ptr = self.0; |
93 | 0 | cvt(DH_set0_key(dh_ptr, ptr::null_mut(), priv_key.as_ptr()))?; |
94 | 0 | mem::forget(priv_key); |
95 | | |
96 | 0 | cvt(ffi::DH_generate_key(dh_ptr))?; |
97 | 0 | mem::forget(self); |
98 | 0 | Ok(Dh::from_ptr(dh_ptr)) |
99 | | } |
100 | 0 | } |
101 | | |
102 | | /// Sets the public and private keys on the DH object. |
103 | 0 | pub fn set_key(self, pub_key: BigNum, priv_key: BigNum) -> Result<Dh<Private>, ErrorStack> { |
104 | | unsafe { |
105 | 0 | let dh_ptr = self.0; |
106 | 0 | cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), priv_key.as_ptr()))?; |
107 | 0 | mem::forget((self, pub_key, priv_key)); |
108 | 0 | Ok(Dh::from_ptr(dh_ptr)) |
109 | | } |
110 | 0 | } |
111 | | |
112 | | /// Generates DH params based on the given `prime_len` and a fixed `generator` value. |
113 | | #[corresponds(DH_generate_parameters_ex)] |
114 | 0 | pub fn generate_params(prime_len: u32, generator: u32) -> Result<Dh<Params>, ErrorStack> { |
115 | | unsafe { |
116 | 0 | let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); |
117 | 0 | cvt(ffi::DH_generate_parameters_ex( |
118 | 0 | dh.0, |
119 | 0 | prime_len as i32, |
120 | 0 | generator as i32, |
121 | 0 | ptr::null_mut(), |
122 | 0 | ))?; |
123 | 0 | Ok(dh) |
124 | | } |
125 | 0 | } |
126 | | |
127 | | /// Generates a public and a private key based on the DH params. |
128 | | #[corresponds(DH_generate_key)] |
129 | 0 | pub fn generate_key(self) -> Result<Dh<Private>, ErrorStack> { |
130 | | unsafe { |
131 | 0 | let dh_ptr = self.0; |
132 | 0 | cvt(ffi::DH_generate_key(dh_ptr))?; |
133 | 0 | mem::forget(self); |
134 | 0 | Ok(Dh::from_ptr(dh_ptr)) |
135 | | } |
136 | 0 | } |
137 | | |
138 | | from_pem! { |
139 | | /// Deserializes a PEM-encoded PKCS#3 DHpararameters structure. |
140 | | /// |
141 | | /// The input should have a header of `-----BEGIN DH PARAMETERS-----`. |
142 | | #[corresponds(PEM_read_bio_DHparams)] |
143 | | params_from_pem, |
144 | | Dh<Params>, |
145 | | ffi::PEM_read_bio_DHparams |
146 | | } |
147 | | |
148 | | from_der! { |
149 | | /// Deserializes a DER-encoded PKCS#3 DHparameters structure. |
150 | | #[corresponds(d2i_DHparams)] |
151 | | params_from_der, |
152 | | Dh<Params>, |
153 | | ffi::d2i_DHparams |
154 | | } |
155 | | |
156 | | /// Requires OpenSSL 1.0.2 or newer. |
157 | | #[corresponds(DH_get_1024_160)] |
158 | | #[cfg(any(ossl102, ossl110))] |
159 | 0 | pub fn get_1024_160() -> Result<Dh<Params>, ErrorStack> { |
160 | | unsafe { |
161 | 0 | ffi::init(); |
162 | 0 | cvt_p(ffi::DH_get_1024_160()).map(|p| Dh::from_ptr(p)) |
163 | | } |
164 | 0 | } |
165 | | |
166 | | /// Requires OpenSSL 1.0.2 or newer. |
167 | | #[corresponds(DH_get_2048_224)] |
168 | | #[cfg(any(ossl102, ossl110))] |
169 | 0 | pub fn get_2048_224() -> Result<Dh<Params>, ErrorStack> { |
170 | | unsafe { |
171 | 0 | ffi::init(); |
172 | 0 | cvt_p(ffi::DH_get_2048_224()).map(|p| Dh::from_ptr(p)) |
173 | | } |
174 | 0 | } |
175 | | |
176 | | /// Requires OpenSSL 1.0.2 or newer. |
177 | | #[corresponds(DH_get_2048_256)] |
178 | | #[cfg(any(ossl102, ossl110))] |
179 | 0 | pub fn get_2048_256() -> Result<Dh<Params>, ErrorStack> { |
180 | | unsafe { |
181 | 0 | ffi::init(); |
182 | 0 | cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) |
183 | | } |
184 | 0 | } |
185 | | } |
186 | | |
187 | | impl<T> Dh<T> |
188 | | where |
189 | | T: HasParams, |
190 | | { |
191 | | /// Returns the prime `p` from the DH instance. |
192 | | #[corresponds(DH_get0_pqg)] |
193 | 0 | pub fn prime_p(&self) -> &BigNumRef { |
194 | 0 | let mut p = ptr::null(); |
195 | | unsafe { |
196 | 0 | DH_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); |
197 | 0 | BigNumRef::from_ptr(p as *mut _) |
198 | | } |
199 | 0 | } |
200 | | |
201 | | /// Returns the prime `q` from the DH instance. |
202 | | #[corresponds(DH_get0_pqg)] |
203 | 0 | pub fn prime_q(&self) -> Option<&BigNumRef> { |
204 | 0 | let mut q = ptr::null(); |
205 | | unsafe { |
206 | 0 | DH_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); |
207 | 0 | if q.is_null() { |
208 | 0 | None |
209 | | } else { |
210 | 0 | Some(BigNumRef::from_ptr(q as *mut _)) |
211 | | } |
212 | | } |
213 | 0 | } |
214 | | |
215 | | /// Returns the generator from the DH instance. |
216 | | #[corresponds(DH_get0_pqg)] |
217 | 0 | pub fn generator(&self) -> &BigNumRef { |
218 | 0 | let mut g = ptr::null(); |
219 | | unsafe { |
220 | 0 | DH_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); |
221 | 0 | BigNumRef::from_ptr(g as *mut _) |
222 | | } |
223 | 0 | } |
224 | | } |
225 | | |
226 | | impl<T> DhRef<T> |
227 | | where |
228 | | T: HasPublic, |
229 | | { |
230 | | /// Returns the public key from the DH instance. |
231 | | #[corresponds(DH_get0_key)] |
232 | 0 | pub fn public_key(&self) -> &BigNumRef { |
233 | 0 | let mut pub_key = ptr::null(); |
234 | | unsafe { |
235 | 0 | DH_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); |
236 | 0 | BigNumRef::from_ptr(pub_key as *mut _) |
237 | | } |
238 | 0 | } |
239 | | } |
240 | | |
241 | | impl<T> DhRef<T> |
242 | | where |
243 | | T: HasPrivate, |
244 | | { |
245 | | /// Computes a shared secret from the own private key and the given `public_key`. |
246 | | #[corresponds(DH_compute_key)] |
247 | 0 | pub fn compute_key(&self, public_key: &BigNumRef) -> Result<Vec<u8>, ErrorStack> { |
248 | | unsafe { |
249 | 0 | let key_len = ffi::DH_size(self.as_ptr()); |
250 | 0 | let mut key = vec![0u8; key_len as usize]; |
251 | 0 | cvt(ffi::DH_compute_key( |
252 | 0 | key.as_mut_ptr(), |
253 | 0 | public_key.as_ptr(), |
254 | 0 | self.as_ptr(), |
255 | 0 | ))?; |
256 | 0 | Ok(key) |
257 | | } |
258 | 0 | } |
259 | | |
260 | | /// Returns the private key from the DH instance. |
261 | | #[corresponds(DH_get0_key)] |
262 | 0 | pub fn private_key(&self) -> &BigNumRef { |
263 | 0 | let mut priv_key = ptr::null(); |
264 | | unsafe { |
265 | 0 | DH_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); |
266 | 0 | BigNumRef::from_ptr(priv_key as *mut _) |
267 | | } |
268 | 0 | } |
269 | | } |
270 | | |
271 | | cfg_if! { |
272 | | if #[cfg(any(ossl110, libressl270, boringssl))] { |
273 | | use ffi::{DH_set0_pqg, DH_get0_pqg, DH_get0_key, DH_set0_key}; |
274 | | } else { |
275 | | #[allow(bad_style)] |
276 | | unsafe fn DH_set0_pqg( |
277 | | dh: *mut ffi::DH, |
278 | | p: *mut ffi::BIGNUM, |
279 | | q: *mut ffi::BIGNUM, |
280 | | g: *mut ffi::BIGNUM, |
281 | | ) -> ::libc::c_int { |
282 | | (*dh).p = p; |
283 | | (*dh).q = q; |
284 | | (*dh).g = g; |
285 | | 1 |
286 | | } |
287 | | |
288 | | #[allow(bad_style)] |
289 | | unsafe fn DH_get0_pqg( |
290 | | dh: *mut ffi::DH, |
291 | | p: *mut *const ffi::BIGNUM, |
292 | | q: *mut *const ffi::BIGNUM, |
293 | | g: *mut *const ffi::BIGNUM, |
294 | | ) { |
295 | | if !p.is_null() { |
296 | | *p = (*dh).p; |
297 | | } |
298 | | if !q.is_null() { |
299 | | *q = (*dh).q; |
300 | | } |
301 | | if !g.is_null() { |
302 | | *g = (*dh).g; |
303 | | } |
304 | | } |
305 | | |
306 | | #[allow(bad_style)] |
307 | | unsafe fn DH_set0_key( |
308 | | dh: *mut ffi::DH, |
309 | | pub_key: *mut ffi::BIGNUM, |
310 | | priv_key: *mut ffi::BIGNUM, |
311 | | ) -> ::libc::c_int { |
312 | | (*dh).pub_key = pub_key; |
313 | | (*dh).priv_key = priv_key; |
314 | | 1 |
315 | | } |
316 | | |
317 | | #[allow(bad_style)] |
318 | | unsafe fn DH_get0_key( |
319 | | dh: *mut ffi::DH, |
320 | | pub_key: *mut *const ffi::BIGNUM, |
321 | | priv_key: *mut *const ffi::BIGNUM, |
322 | | ) { |
323 | | if !pub_key.is_null() { |
324 | | *pub_key = (*dh).pub_key; |
325 | | } |
326 | | if !priv_key.is_null() { |
327 | | *priv_key = (*dh).priv_key; |
328 | | } |
329 | | } |
330 | | } |
331 | | } |
332 | | |
333 | | #[cfg(test)] |
334 | | mod tests { |
335 | | use crate::bn::BigNum; |
336 | | use crate::dh::Dh; |
337 | | use crate::ssl::{SslContext, SslMethod}; |
338 | | |
339 | | #[test] |
340 | | #[cfg(ossl102)] |
341 | | fn test_dh_rfc5114() { |
342 | | let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); |
343 | | let dh2 = Dh::get_2048_224().unwrap(); |
344 | | ctx.set_tmp_dh(&dh2).unwrap(); |
345 | | let dh3 = Dh::get_2048_256().unwrap(); |
346 | | ctx.set_tmp_dh(&dh3).unwrap(); |
347 | | } |
348 | | |
349 | | #[test] |
350 | | fn test_dh_params() { |
351 | | let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); |
352 | | let prime_p = BigNum::from_hex_str( |
353 | | "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\ |
354 | | 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\ |
355 | | 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\ |
356 | | 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\ |
357 | | 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\ |
358 | | C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", |
359 | | ).unwrap(); |
360 | | let prime_q = BigNum::from_hex_str( |
361 | | "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\ |
362 | | 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\ |
363 | | 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\ |
364 | | 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\ |
365 | | 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\ |
366 | | B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", |
367 | | ).unwrap(); |
368 | | let generator = BigNum::from_hex_str( |
369 | | "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", |
370 | | ) |
371 | | .unwrap(); |
372 | | let dh = Dh::from_params( |
373 | | prime_p.to_owned().unwrap(), |
374 | | generator.to_owned().unwrap(), |
375 | | prime_q.to_owned().unwrap(), |
376 | | ) |
377 | | .unwrap(); |
378 | | ctx.set_tmp_dh(&dh).unwrap(); |
379 | | |
380 | | assert_eq!(dh.prime_p(), &prime_p); |
381 | | assert_eq!(dh.prime_q().unwrap(), &prime_q); |
382 | | assert_eq!(dh.generator(), &generator); |
383 | | } |
384 | | |
385 | | #[test] |
386 | | #[cfg(ossl102)] |
387 | | fn test_dh_stored_restored() { |
388 | | let dh1 = Dh::get_2048_256().unwrap(); |
389 | | let key1 = dh1.generate_key().unwrap(); |
390 | | |
391 | | let dh2 = Dh::get_2048_256().unwrap(); |
392 | | let key2 = dh2 |
393 | | .set_private_key(key1.private_key().to_owned().unwrap()) |
394 | | .unwrap(); |
395 | | |
396 | | assert_eq!(key1.public_key(), key2.public_key()); |
397 | | assert_eq!(key1.private_key(), key2.private_key()); |
398 | | } |
399 | | |
400 | | #[test] |
401 | | #[cfg(ossl102)] |
402 | | fn test_set_keys() { |
403 | | let dh1 = Dh::get_2048_256().unwrap(); |
404 | | let key1 = dh1.generate_key().unwrap(); |
405 | | |
406 | | let dh2 = Dh::get_2048_256().unwrap(); |
407 | | let key2 = dh2 |
408 | | .set_public_key(key1.public_key().to_owned().unwrap()) |
409 | | .unwrap(); |
410 | | |
411 | | assert_eq!(key1.public_key(), key2.public_key()); |
412 | | |
413 | | let dh3 = Dh::get_2048_256().unwrap(); |
414 | | let key3 = dh3 |
415 | | .set_key( |
416 | | key1.public_key().to_owned().unwrap(), |
417 | | key1.private_key().to_owned().unwrap(), |
418 | | ) |
419 | | .unwrap(); |
420 | | assert_eq!(key1.public_key(), key3.public_key()); |
421 | | assert_eq!(key1.private_key(), key3.private_key()); |
422 | | } |
423 | | |
424 | | #[test] |
425 | | fn test_dh_from_pem() { |
426 | | let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); |
427 | | let params = include_bytes!("../test/dhparams.pem"); |
428 | | let dh = Dh::params_from_pem(params).unwrap(); |
429 | | ctx.set_tmp_dh(&dh).unwrap(); |
430 | | } |
431 | | |
432 | | #[test] |
433 | | fn test_dh_from_der() { |
434 | | let params = include_bytes!("../test/dhparams.pem"); |
435 | | let dh = Dh::params_from_pem(params).unwrap(); |
436 | | let der = dh.params_to_der().unwrap(); |
437 | | Dh::params_from_der(&der).unwrap(); |
438 | | } |
439 | | |
440 | | #[test] |
441 | | #[cfg(ossl102)] |
442 | | fn test_dh_generate_key_compute_key() { |
443 | | let dh1 = Dh::get_2048_224().unwrap().generate_key().unwrap(); |
444 | | let dh2 = Dh::get_2048_224().unwrap().generate_key().unwrap(); |
445 | | |
446 | | let shared_a = dh1.compute_key(dh2.public_key()).unwrap(); |
447 | | let shared_b = dh2.compute_key(dh1.public_key()).unwrap(); |
448 | | |
449 | | assert_eq!(shared_a, shared_b); |
450 | | } |
451 | | |
452 | | #[test] |
453 | | fn test_dh_generate_params_generate_key_compute_key() { |
454 | | let dh_params1 = Dh::generate_params(512, 2).unwrap(); |
455 | | let dh_params2 = Dh::from_pqg( |
456 | | dh_params1.prime_p().to_owned().unwrap(), |
457 | | None, |
458 | | dh_params1.generator().to_owned().unwrap(), |
459 | | ) |
460 | | .unwrap(); |
461 | | |
462 | | let dh1 = dh_params1.generate_key().unwrap(); |
463 | | let dh2 = dh_params2.generate_key().unwrap(); |
464 | | |
465 | | let shared_a = dh1.compute_key(dh2.public_key()).unwrap(); |
466 | | let shared_b = dh2.compute_key(dh1.public_key()).unwrap(); |
467 | | |
468 | | assert_eq!(shared_a, shared_b); |
469 | | } |
470 | | |
471 | | #[test] |
472 | | fn test_dh_check_key() { |
473 | | let dh1 = Dh::generate_params(512, 2).unwrap(); |
474 | | let p = BigNum::from_hex_str("04").unwrap(); |
475 | | let g = BigNum::from_hex_str("02").unwrap(); |
476 | | let dh2 = Dh::from_pqg(p, None, g).unwrap(); |
477 | | assert!(dh1.check_key().unwrap()); |
478 | | assert!(matches!(dh2.check_key(), Ok(false) | Err(_))); |
479 | | } |
480 | | } |