From 52c942f4b3d96cff239646d86998b7b898c5e0ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Wanzenb=C3=B6ck?= Date: Mon, 18 Jun 2018 11:39:15 +0200 Subject: [PATCH 1/5] Add methods to access private and public part of DSA keys --- openssl/src/dsa.rs | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index e8d78dcb..684666cf 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -13,7 +13,7 @@ use std::ptr; use bn::BigNumRef; use error::ErrorStack; -use pkey::{HasParams, HasPublic, Private, Public}; +use pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { @@ -83,6 +83,28 @@ where public_key_to_der, ffi::i2d_DSA_PUBKEY } + + /// Returns a reference to the public exponent. + pub fn pub_key(&self) -> &BigNumRef { + unsafe { + let mut pub_key = ptr::null(); + DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); + BigNumRef::from_ptr(pub_key as *mut _) + } + } +} + +impl DsaRef +where + T: HasPrivate, +{ + pub fn priv_key(&self) -> &BigNumRef { + unsafe { + let mut priv_key = ptr::null(); + DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); + BigNumRef::from_ptr(priv_key as *mut _) + } + } } impl DsaRef @@ -211,6 +233,26 @@ cfg_if! { } } +cfg_if! { + if #[cfg(any(ossl110, libressl273))] { + use ffi::DSA_get0_key; + } else { + #[allow(bad_style)] + unsafe fn DSA_get0_pqg( + d: *mut ffi::DSA, + pub_key: *mut *const ffi::BIGNUM, + priv_key: *mut *const ffi::BIGNUM) + { + if !pub_key.is_null() { + *pub_key = (*d).pub_key; + } + if !priv_key.is_null() { + *priv_key = (*d).priv_key; + } + } + } +} + #[cfg(test)] mod test { use super::*; From 4994e75d2cecddcaf192623527afe342fb7fd9f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Wanzenb=C3=B6ck?= Date: Mon, 18 Jun 2018 18:10:02 +0200 Subject: [PATCH 2/5] Add Dsa::from_(private|public)_components Add 2 methods to create a DSA key pair from its raw components. --- CHANGELOG.md | 4 ++ openssl-sys/src/libressl/v273.rs | 16 ++++++ openssl-sys/src/openssl/v110.rs | 11 ++++ openssl/src/dsa.rs | 86 ++++++++++++++++++++++++++++---- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3df00b89..fd61bd94 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Added +* Added `DsaRef::pub_key` and `DsaRef::priv_key`. +* Added `Dsa::from_private_components` and `Dsa::from_public_components`. + ## [v0.10.10] - 2018-06-06 ### Added diff --git a/openssl-sys/src/libressl/v273.rs b/openssl-sys/src/libressl/v273.rs index 74c331f6..456f8872 100644 --- a/openssl-sys/src/libressl/v273.rs +++ b/openssl-sys/src/libressl/v273.rs @@ -47,6 +47,22 @@ extern "C" { q: *mut *const ::BIGNUM, q: *mut *const ::BIGNUM, ); + pub fn DSA_set0_pqg( + d: *mut ::DSA, + p: *mut ::BIGNUM, + q: *mut ::BIGNUM, + q: *mut ::BIGNUM, + ) -> c_int; + pub fn DSA_get0_key( + d: *const ::DSA, + pub_key: *mut *const ::BIGNUM, + priv_key: *mut *const ::BIGNUM, + ); + pub fn DSA_set0_key( + d: *mut ::DSA, + pub_key: *mut ::BIGNUM, + priv_key: *mut ::BIGNUM, + ) -> c_int; pub fn ECDSA_SIG_get0( sig: *const ::ECDSA_SIG, diff --git a/openssl-sys/src/openssl/v110.rs b/openssl-sys/src/openssl/v110.rs index 47d2bee4..493385da 100644 --- a/openssl-sys/src/openssl/v110.rs +++ b/openssl-sys/src/openssl/v110.rs @@ -235,11 +235,22 @@ extern "C" { q: *mut *const ::BIGNUM, q: *mut *const ::BIGNUM, ); + pub fn DSA_set0_pqg( + d: *mut ::DSA, + p: *mut ::BIGNUM, + q: *mut ::BIGNUM, + q: *mut ::BIGNUM, + ) -> c_int; pub fn DSA_get0_key( d: *const ::DSA, pub_key: *mut *const ::BIGNUM, priv_key: *mut *const ::BIGNUM, ); + pub fn DSA_set0_key( + d: *mut ::DSA, + pub_key: *mut ::BIGNUM, + priv_key: *mut ::BIGNUM, + ) -> c_int; pub fn RSA_get0_key( r: *const ::RSA, n: *mut *const ::BIGNUM, diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 684666cf..cd5a2e66 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -10,8 +10,9 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::ptr; +use std::mem; -use bn::BigNumRef; +use bn::{BigNum, BigNumRef, BigNumContext}; use error::ErrorStack; use pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; use {cvt, cvt_p}; @@ -84,7 +85,7 @@ where ffi::i2d_DSA_PUBKEY } - /// Returns a reference to the public exponent. + /// Returns a reference to the public key component of `self`. pub fn pub_key(&self) -> &BigNumRef { unsafe { let mut pub_key = ptr::null(); @@ -98,6 +99,7 @@ impl DsaRef where T: HasPrivate, { + /// Returns a reference to the private key component of `self`. pub fn priv_key(&self) -> &BigNumRef { unsafe { let mut priv_key = ptr::null(); @@ -154,7 +156,7 @@ impl Dsa { /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values. /// These values are used to generate the key pair with [`DSA_generate_key`]. /// - /// The `bits` parameter coresponds to the length of the prime `p`. + /// The `bits` parameter corresponds to the length of the prime `p`. /// /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html /// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html @@ -175,6 +177,31 @@ impl Dsa { Ok(dsa) } } + + /// Create a DSA key pair with the given parameters + /// + /// `p`, `q` and `g` are the common parameters. + /// `priv_key` is the private component of the key pair. + /// The corresponding public component is calculated from the private component. + pub fn from_private_components( + p: BigNum, + q: BigNum, + g: BigNum, + priv_key: BigNum, + ) -> Result, ErrorStack> { + ffi::init(); + unsafe { + let mut bn_ctx = BigNumContext::new()?; + let mut pub_key = BigNum::new()?; + pub_key.mod_exp(&g, &priv_key, &p, &mut bn_ctx)?; + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?; + mem::forget((pub_key, priv_key)); + Ok(dsa) + } + } } impl Dsa { @@ -201,6 +228,27 @@ impl Dsa { Dsa, ffi::d2i_DSA_PUBKEY } + + /// Create a new DSA key with only public components. + /// + /// `p`, `q` and `g` are the common parameters. + /// `pub_key` is the public component of the key. + pub fn from_public_components( + p: BigNum, + q: BigNum, + g: BigNum, + pub_key: BigNum, + ) -> Result, ErrorStack> { + ffi::init(); + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?; + mem::forget(pub_key); + Ok(dsa) + } + } } impl fmt::Debug for Dsa { @@ -211,7 +259,7 @@ impl fmt::Debug for Dsa { cfg_if! { if #[cfg(any(ossl110, libressl273))] { - use ffi::DSA_get0_pqg; + use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; } else { #[allow(bad_style)] unsafe fn DSA_get0_pqg( @@ -230,13 +278,7 @@ cfg_if! { *g = (*d).g; } } - } -} -cfg_if! { - if #[cfg(any(ossl110, libressl273))] { - use ffi::DSA_get0_key; - } else { #[allow(bad_style)] unsafe fn DSA_get0_pqg( d: *mut ffi::DSA, @@ -250,6 +292,30 @@ cfg_if! { *priv_key = (*d).priv_key; } } + + #[allow(bad_style)] + unsafe fn DSA_set0_key( + d: *mut ffi::DSA, + pub_key: *mut ffi::BIGNUM, + priv_key: *mut ffi::BIGNUM) -> c_int + { + (*d).pub_key = *pub_key; + (*d).priv_key = *priv_key; + 1 + } + + #[allow(bad_style)] + unsafe fn DSA_set0_pqg( + d: *mut ffi::DSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM) -> c_int + { + (*d).p = *p; + (*d).q = *q; + (*d).g = *g; + 1 + } } } From 0390aba73b0e832d523c97fa9317c198e67d7a3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Wanzenb=C3=B6ck?= Date: Mon, 18 Jun 2018 18:12:34 +0200 Subject: [PATCH 3/5] Add tests for DSA key pairs --- openssl/src/dsa.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index cd5a2e66..28feccb4 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -322,9 +322,81 @@ cfg_if! { #[cfg(test)] mod test { use super::*; + use sign::{Signer, Verifier}; + use hash::MessageDigest; + use pkey::PKey; #[test] pub fn test_generate() { Dsa::generate(1024).unwrap(); } + + #[test] + fn test_pubkey_generation() { + let dsa = Dsa::generate(1024).unwrap(); + let p = dsa.p(); + let g = dsa.g(); + let priv_key = dsa.priv_key(); + let pub_key = dsa.pub_key(); + let mut ctx = BigNumContext::new().unwrap(); + let mut calc = BigNum::new().unwrap(); + calc.mod_exp(g, priv_key, p, &mut ctx).unwrap(); + assert_eq!(&calc, pub_key) + } + + #[test] + fn test_priv_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let priv_key = BigNum::from_u32(15).unwrap(); + + let dsa = Dsa::from_private_components(p, q, g, priv_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + } + + #[test] + fn test_pub_key_from_parts() { + let p = BigNum::from_u32(283).unwrap(); + let q = BigNum::from_u32(47).unwrap(); + let g = BigNum::from_u32(60).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); + + Dsa::from_private_components(p, q, g, pub_key).unwrap(); + } + + #[test] + fn test_signature() { + const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let dsa_ref = Dsa::generate(1024).unwrap(); + + let p = dsa_ref.p(); + let q = dsa_ref.q(); + let g = dsa_ref.g(); + + let pub_key = dsa_ref.pub_key(); + let priv_key = dsa_ref.priv_key(); + + let priv_key = Dsa::from_private_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(priv_key).unwrap()).unwrap(); + let priv_key = PKey::from_dsa(priv_key).unwrap(); + + let pub_key = Dsa::from_public_components( + BigNumRef::to_owned(p).unwrap(), + BigNumRef::to_owned(q).unwrap(), + BigNumRef::to_owned(g).unwrap(), + BigNumRef::to_owned(pub_key).unwrap()).unwrap(); + let pub_key = PKey::from_dsa(pub_key).unwrap(); + + let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); + signer.update(TEST_DATA).unwrap(); + + let signature = signer.sign_to_vec().unwrap(); + let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); + verifier.update(TEST_DATA).unwrap(); + assert!(verifier.verify(&signature[..]).unwrap()); + } } From c624427e31ed4a99210beb5815a955715e338991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Wanzenb=C3=B6ck?= Date: Mon, 18 Jun 2018 20:32:34 +0200 Subject: [PATCH 4/5] Fix fallback implementation of DSA utility methods --- openssl/src/dsa.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 28feccb4..40018dfe 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -280,7 +280,7 @@ cfg_if! { } #[allow(bad_style)] - unsafe fn DSA_get0_pqg( + unsafe fn DSA_get0_key( d: *mut ffi::DSA, pub_key: *mut *const ffi::BIGNUM, priv_key: *mut *const ffi::BIGNUM) @@ -299,8 +299,8 @@ cfg_if! { pub_key: *mut ffi::BIGNUM, priv_key: *mut ffi::BIGNUM) -> c_int { - (*d).pub_key = *pub_key; - (*d).priv_key = *priv_key; + (*d).pub_key = pub_key; + (*d).priv_key = priv_key; 1 } @@ -311,9 +311,9 @@ cfg_if! { q: *mut ffi::BIGNUM, g: *mut ffi::BIGNUM) -> c_int { - (*d).p = *p; - (*d).q = *q; - (*d).g = *g; + (*d).p = p; + (*d).q = q; + (*d).g = g; 1 } } From 339d09fbf34176989a9089b715c89fd1d9be158f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20Wanzenb=C3=B6ck?= Date: Sat, 23 Jun 2018 18:16:32 +0200 Subject: [PATCH 5/5] Simplify DSA from private components --- openssl/src/dsa.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 40018dfe..53b0eb19 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -12,7 +12,7 @@ use std::fmt; use std::ptr; use std::mem; -use bn::{BigNum, BigNumRef, BigNumContext}; +use bn::{BigNum, BigNumRef}; use error::ErrorStack; use pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; use {cvt, cvt_p}; @@ -182,18 +182,16 @@ impl Dsa { /// /// `p`, `q` and `g` are the common parameters. /// `priv_key` is the private component of the key pair. - /// The corresponding public component is calculated from the private component. + /// `pub_key` is the public component of the key. Can be computed via `g^(priv_key) mod p` pub fn from_private_components( p: BigNum, q: BigNum, g: BigNum, priv_key: BigNum, + pub_key: BigNum, ) -> Result, ErrorStack> { ffi::init(); unsafe { - let mut bn_ctx = BigNumContext::new()?; - let mut pub_key = BigNum::new()?; - pub_key.mod_exp(&g, &priv_key, &p, &mut bn_ctx)?; let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, q, g)); @@ -322,6 +320,7 @@ cfg_if! { #[cfg(test)] mod test { use super::*; + use bn::BigNumContext; use sign::{Signer, Verifier}; use hash::MessageDigest; use pkey::PKey; @@ -350,9 +349,14 @@ mod test { let q = BigNum::from_u32(47).unwrap(); let g = BigNum::from_u32(60).unwrap(); let priv_key = BigNum::from_u32(15).unwrap(); + let pub_key = BigNum::from_u32(207).unwrap(); - let dsa = Dsa::from_private_components(p, q, g, priv_key).unwrap(); + let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap(); assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); } #[test] @@ -362,7 +366,11 @@ mod test { let g = BigNum::from_u32(60).unwrap(); let pub_key = BigNum::from_u32(207).unwrap(); - Dsa::from_private_components(p, q, g, pub_key).unwrap(); + let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap(); + assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); + assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); + assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); + assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); } #[test] @@ -381,7 +389,8 @@ mod test { BigNumRef::to_owned(p).unwrap(), BigNumRef::to_owned(q).unwrap(), BigNumRef::to_owned(g).unwrap(), - BigNumRef::to_owned(priv_key).unwrap()).unwrap(); + BigNumRef::to_owned(priv_key).unwrap(), + BigNumRef::to_owned(pub_key).unwrap()).unwrap(); let priv_key = PKey::from_dsa(priv_key).unwrap(); let pub_key = Dsa::from_public_components(