//! Digital Signatures //! //! DSA ensures a message originated from a known sender, and was not modified. //! DSA uses asymmetrical keys and an algorithm to output a signature of the message //! using the private key that can be validated with the public key but not be generated //! without the private key. use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::mem; use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DSA; fn drop = ffi::DSA_free; /// Object representing DSA keys. /// /// A DSA object contains the parameters p, q, and g. There is a private /// and public key. The values p, g, and q are: /// /// * `p`: DSA prime parameter /// * `q`: DSA sub-prime parameter /// * `g`: DSA base parameter /// /// These values are used to calculate a pair of asymmetrical keys used for /// signing. /// /// OpenSSL documentation at [`DSA_new`] /// /// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html /// /// # Examples /// /// ``` /// use openssl::dsa::Dsa; /// use openssl::error::ErrorStack; /// use openssl::pkey::Private; /// /// fn create_dsa() -> Result, ErrorStack> { /// let sign = Dsa::generate(2048)?; /// Ok(sign) /// } /// # fn main() { /// # create_dsa(); /// # } /// ``` pub struct Dsa; /// Reference to [`Dsa`]. /// /// [`Dsa`]: struct.Dsa.html pub struct DsaRef; } impl Clone for Dsa { fn clone(&self) -> Dsa { (**self).to_owned() } } impl ToOwned for DsaRef { type Owned = Dsa; fn to_owned(&self) -> Dsa { unsafe { ffi::DSA_up_ref(self.as_ptr()); Dsa::from_ptr(self.as_ptr()) } } } impl DsaRef where T: HasPublic, { to_pem! { /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. #[corresponds(PEM_write_bio_DSA_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_DSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. #[corresponds(i2d_DSA_PUBKEY)] public_key_to_der, ffi::i2d_DSA_PUBKEY } /// Returns a reference to the public key component of `self`. #[corresponds(DSA_get0_key)] 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_const_ptr(pub_key) } } } impl DsaRef where T: HasPrivate, { private_key_to_pem! { /// Serializes the private key to a PEM-encoded DSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. #[corresponds(PEM_write_bio_DSAPrivateKey)] private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted DSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. #[corresponds(PEM_write_bio_DSAPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_DSAPrivateKey } /// Returns a reference to the private key component of `self`. #[corresponds(DSA_get0_key)] 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_const_ptr(priv_key) } } } impl DsaRef where T: HasParams, { /// Returns the maximum size of the signature output by `self` in bytes. #[corresponds(DSA_size)] pub fn size(&self) -> u32 { unsafe { ffi::DSA_size(self.as_ptr()) as u32 } } /// Returns the DSA prime parameter of `self`. #[corresponds(DSA_get0_pqg)] pub fn p(&self) -> &BigNumRef { unsafe { let mut p = ptr::null(); DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_const_ptr(p) } } /// Returns the DSA sub-prime parameter of `self`. #[corresponds(DSA_get0_pqg)] pub fn q(&self) -> &BigNumRef { unsafe { let mut q = ptr::null(); DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); BigNumRef::from_const_ptr(q) } } /// Returns the DSA base parameter of `self`. #[corresponds(DSA_get0_pqg)] pub fn g(&self) -> &BigNumRef { unsafe { let mut g = ptr::null(); DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); BigNumRef::from_const_ptr(g) } } } #[cfg(boringssl)] type BitType = libc::c_uint; #[cfg(not(boringssl))] type BitType = c_int; impl Dsa { /// Generate a DSA key pair. /// /// 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 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 pub fn generate(bits: u32) -> Result, ErrorStack> { ffi::init(); unsafe { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(ffi::DSA_generate_parameters_ex( dsa.0, bits as BitType, ptr::null(), 0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ))?; cvt(ffi::DSA_generate_key(dsa.0))?; 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. /// `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 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 { from_pem! { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. #[corresponds(PEM_read_bio_DSA_PUBKEY)] public_key_from_pem, Dsa, ffi::PEM_read_bio_DSA_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. #[corresponds(d2i_DSA_PUBKEY)] public_key_from_der, 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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "DSA") } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; } else { #[allow(bad_style)] unsafe fn DSA_get0_pqg( d: *mut ffi::DSA, p: *mut *const ffi::BIGNUM, q: *mut *const ffi::BIGNUM, g: *mut *const ffi::BIGNUM) { if !p.is_null() { *p = (*d).p; } if !q.is_null() { *q = (*d).q; } if !g.is_null() { *g = (*d).g; } } #[allow(bad_style)] unsafe fn DSA_get0_key( 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; } } #[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 } } } foreign_type_and_impl_send_sync! { type CType = ffi::DSA_SIG; fn drop = ffi::DSA_SIG_free; /// Object representing DSA signature. /// /// DSA signatures consist of two components: `r` and `s`. /// /// # Examples /// /// ``` /// use std::convert::TryInto; /// /// use openssl::bn::BigNum; /// use openssl::dsa::{Dsa, DsaSig}; /// use openssl::hash::MessageDigest; /// use openssl::pkey::PKey; /// use openssl::sign::{Signer, Verifier}; /// /// const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; /// let dsa_ref = Dsa::generate(1024).unwrap(); /// /// let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap(); /// let priv_key: PKey<_> = dsa_ref.try_into().unwrap(); /// /// let mut signer = if let Ok(signer) = Signer::new(MessageDigest::sha256(), &priv_key) { /// signer /// } else { /// // DSA signing is not supported (eg. BoringSSL) /// return; /// }; /// /// signer.update(TEST_DATA).unwrap(); /// /// let signature = signer.sign_to_vec().unwrap(); /// // Parse DER-encoded DSA signature /// let signature = DsaSig::from_der(&signature).unwrap(); /// /// // Extract components `r` and `s` /// let r = BigNum::from_slice(&signature.r().to_vec()).unwrap(); /// let s = BigNum::from_slice(&signature.s().to_vec()).unwrap(); /// /// // Construct new DSA signature from components /// let signature = DsaSig::from_private_components(r, s).unwrap(); /// /// // Serialize DSA signature to DER /// let signature = signature.to_der().unwrap(); /// /// let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); /// verifier.update(TEST_DATA).unwrap(); /// assert!(verifier.verify(&signature[..]).unwrap()); /// ``` pub struct DsaSig; /// Reference to a [`DsaSig`]. pub struct DsaSigRef; } impl DsaSig { /// Returns a new `DsaSig` by setting the `r` and `s` values associated with an DSA signature. #[corresponds(DSA_SIG_set0)] pub fn from_private_components(r: BigNum, s: BigNum) -> Result { unsafe { let sig = cvt_p(ffi::DSA_SIG_new())?; DSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); mem::forget((r, s)); Ok(DsaSig::from_ptr(sig)) } } from_der! { /// Decodes a DER-encoded DSA signature. #[corresponds(d2i_DSA_SIG)] from_der, DsaSig, ffi::d2i_DSA_SIG } } impl fmt::Debug for DsaSig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DsaSig") .field("r", self.r()) .field("s", self.s()) .finish() } } impl DsaSigRef { to_der! { /// Serializes the DSA signature into a DER-encoded `DSASignature` structure. #[corresponds(i2d_DSA_SIG)] to_der, ffi::i2d_DSA_SIG } /// Returns internal component `r` of an `DsaSig`. #[corresponds(DSA_SIG_get0)] pub fn r(&self) -> &BigNumRef { unsafe { let mut r = ptr::null(); DSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); BigNumRef::from_const_ptr(r) } } /// Returns internal component `s` of an `DsaSig`. #[corresponds(DSA_SIG_get0)] pub fn s(&self) -> &BigNumRef { unsafe { let mut s = ptr::null(); DSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); BigNumRef::from_const_ptr(s) } } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{DSA_SIG_set0, DSA_SIG_get0}; } else { #[allow(bad_style)] unsafe fn DSA_SIG_set0( sig: *mut ffi::DSA_SIG, r: *mut ffi::BIGNUM, s: *mut ffi::BIGNUM, ) -> c_int { if r.is_null() || s.is_null() { return 0; } ffi::BN_clear_free((*sig).r); ffi::BN_clear_free((*sig).s); (*sig).r = r; (*sig).s = s; 1 } #[allow(bad_style)] unsafe fn DSA_SIG_get0( sig: *const ffi::DSA_SIG, pr: *mut *const ffi::BIGNUM, ps: *mut *const ffi::BIGNUM) { if !pr.is_null() { (*pr) = (*sig).r; } if !ps.is_null() { (*ps) = (*sig).s; } } } } #[cfg(test)] mod test { use super::*; use crate::bn::BigNumContext; #[cfg(not(boringssl))] use crate::hash::MessageDigest; #[cfg(not(boringssl))] use crate::pkey::PKey; #[cfg(not(boringssl))] use crate::sign::{Signer, Verifier}; #[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 pub_key = BigNum::from_u32(207).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] 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(); 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] #[cfg(not(boringssl))] 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(), BigNumRef::to_owned(pub_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()); } #[test] #[cfg(not(boringssl))] fn test_signature_der() { use std::convert::TryInto; const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let dsa_ref = Dsa::generate(1024).unwrap(); let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap(); let priv_key: PKey<_> = dsa_ref.try_into().unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); signer.update(TEST_DATA).unwrap(); let signature = signer.sign_to_vec().unwrap(); eprintln!("{:?}", signature); let signature = DsaSig::from_der(&signature).unwrap(); let r = BigNum::from_slice(&signature.r().to_vec()).unwrap(); let s = BigNum::from_slice(&signature.s().to_vec()).unwrap(); let signature = DsaSig::from_private_components(r, s).unwrap(); let signature = signature.to_der().unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); verifier.update(TEST_DATA).unwrap(); assert!(verifier.verify(&signature[..]).unwrap()); } #[test] #[allow(clippy::redundant_clone)] fn clone() { let key = Dsa::generate(2048).unwrap(); drop(key.clone()); } #[test] fn dsa_sig_debug() { let sig = DsaSig::from_der(&[ 48, 46, 2, 21, 0, 135, 169, 24, 58, 153, 37, 175, 248, 200, 45, 251, 112, 238, 238, 89, 172, 177, 182, 166, 237, 2, 21, 0, 159, 146, 151, 237, 187, 8, 82, 115, 14, 183, 103, 12, 203, 46, 161, 208, 251, 167, 123, 131, ]) .unwrap(); let s = format!("{:?}", sig); assert_eq!(s, "DsaSig { r: 774484690634577222213819810519929266740561094381, s: 910998676210681457251421818099943952372231273347 }"); } }