Skip to main content

rama_boring/
dsa.rs

1//! Digital Signatures
2//!
3//! DSA ensures a message originated from a known sender, and was not modified.
4//! DSA uses asymetrical keys and an algorithm to output a signature of the message
5//! using the private key that can be validated with the public key but not be generated
6//! without the private key.
7
8use crate::ffi;
9use crate::libc_types::c_uint;
10use foreign_types::{ForeignType, ForeignTypeRef};
11use openssl_macros::corresponds;
12use std::fmt;
13use std::mem;
14use std::ptr;
15
16use crate::bn::{BigNum, BigNumRef};
17use crate::error::ErrorStack;
18use crate::pkey::{HasParams, HasPrivate, HasPublic, Private, Public};
19use crate::{cvt, cvt_p};
20
21generic_foreign_type_and_impl_send_sync! {
22    type CType = ffi::DSA;
23    fn drop = ffi::DSA_free;
24
25    /// Object representing DSA keys.
26    ///
27    /// A DSA object contains the parameters p, q, and g.  There is a private
28    /// and public key.  The values p, g, and q are:
29    ///
30    /// * `p`: DSA prime parameter
31    /// * `q`: DSA sub-prime parameter
32    /// * `g`: DSA base parameter
33    ///
34    /// These values are used to calculate a pair of asymetrical keys used for
35    /// signing.
36    ///
37    /// OpenSSL documentation at [`DSA_new`]
38    ///
39    /// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html
40    ///
41    /// # Examples
42    ///
43    /// ```
44    /// use rama_boring::dsa::Dsa;
45    /// use rama_boring::error::ErrorStack;
46    /// use rama_boring::pkey::Private;
47    ///
48    /// fn create_dsa() -> Result<Dsa<Private>, ErrorStack> {
49    ///     let sign = Dsa::generate(2048)?;
50    ///     Ok(sign)
51    /// }
52    /// # fn main() {
53    /// #    create_dsa();
54    /// # }
55    /// ```
56    pub struct Dsa<T>;
57    /// Reference to [`Dsa`].
58    ///
59    /// [`Dsa`]: struct.Dsa.html
60    pub struct DsaRef<T>;
61}
62
63impl<T> Clone for Dsa<T> {
64    fn clone(&self) -> Dsa<T> {
65        (**self).to_owned()
66    }
67}
68
69impl<T> ToOwned for DsaRef<T> {
70    type Owned = Dsa<T>;
71
72    fn to_owned(&self) -> Dsa<T> {
73        unsafe {
74            ffi::DSA_up_ref(self.as_ptr());
75            Dsa::from_ptr(self.as_ptr())
76        }
77    }
78}
79
80impl<T> DsaRef<T>
81where
82    T: HasPublic,
83{
84    to_pem! {
85        /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure.
86        ///
87        /// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
88        #[corresponds(PEM_write_bio_DSA_PUBKEY)]
89        public_key_to_pem,
90        ffi::PEM_write_bio_DSA_PUBKEY
91    }
92
93    to_der! {
94        /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
95        #[corresponds(i2d_DSA_PUBKEY)]
96        public_key_to_der,
97        ffi::i2d_DSA_PUBKEY
98    }
99
100    /// Returns a reference to the public key component of `self`.
101    #[must_use]
102    pub fn pub_key(&self) -> &BigNumRef {
103        unsafe {
104            let mut pub_key = ptr::null();
105            DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut());
106            BigNumRef::from_ptr(pub_key.cast_mut())
107        }
108    }
109}
110
111impl<T> DsaRef<T>
112where
113    T: HasPrivate,
114{
115    private_key_to_pem! {
116        /// Serializes the private key to a PEM-encoded DSAPrivateKey structure.
117        ///
118        /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`.
119        #[corresponds(PEM_write_bio_DSAPrivateKey)]
120        private_key_to_pem,
121        /// Serializes the private key to a PEM-encoded encrypted DSAPrivateKey structure.
122        ///
123        /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`.
124        #[corresponds(PEM_write_bio_DSAPrivateKey)]
125        private_key_to_pem_passphrase,
126        ffi::PEM_write_bio_DSAPrivateKey
127    }
128
129    /// Returns a reference to the private key component of `self`.
130    #[must_use]
131    pub fn priv_key(&self) -> &BigNumRef {
132        unsafe {
133            let mut priv_key = ptr::null();
134            DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key);
135            BigNumRef::from_ptr(priv_key.cast_mut())
136        }
137    }
138}
139
140impl<T> DsaRef<T>
141where
142    T: HasParams,
143{
144    /// Returns the maximum size of the signature output by `self` in bytes.
145    #[corresponds(DSA_size)]
146    #[must_use]
147    pub fn size(&self) -> u32 {
148        unsafe { ffi::DSA_size(self.as_ptr()) as u32 }
149    }
150
151    /// Returns the DSA prime parameter of `self`.
152    #[must_use]
153    pub fn p(&self) -> &BigNumRef {
154        unsafe {
155            let mut p = ptr::null();
156            DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut());
157            BigNumRef::from_ptr(p.cast_mut())
158        }
159    }
160
161    /// Returns the DSA sub-prime parameter of `self`.
162    #[must_use]
163    pub fn q(&self) -> &BigNumRef {
164        unsafe {
165            let mut q = ptr::null();
166            DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut());
167            BigNumRef::from_ptr(q.cast_mut())
168        }
169    }
170
171    /// Returns the DSA base parameter of `self`.
172    #[must_use]
173    pub fn g(&self) -> &BigNumRef {
174        unsafe {
175            let mut g = ptr::null();
176            DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g);
177            BigNumRef::from_ptr(g.cast_mut())
178        }
179    }
180}
181
182impl Dsa<Private> {
183    /// Generate a DSA key pair.
184    ///
185    /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values.
186    /// These values are used to generate the key pair with [`DSA_generate_key`].
187    ///
188    /// The `bits` parameter corresponds to the length of the prime `p`.
189    ///
190    /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html
191    /// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html
192    pub fn generate(bits: u32) -> Result<Dsa<Private>, ErrorStack> {
193        ffi::init();
194        unsafe {
195            let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
196            cvt(ffi::DSA_generate_parameters_ex(
197                dsa.0,
198                c_uint::from(bits),
199                ptr::null(),
200                0,
201                ptr::null_mut(),
202                ptr::null_mut(),
203                ptr::null_mut(),
204            ))?;
205            cvt(ffi::DSA_generate_key(dsa.0))?;
206            Ok(dsa)
207        }
208    }
209
210    /// Create a DSA key pair with the given parameters
211    ///
212    /// `p`, `q` and `g` are the common parameters.
213    /// `priv_key` is the private component of the key pair.
214    /// `pub_key` is the public component of the key. Can be computed via `g^(priv_key) mod p`
215    pub fn from_private_components(
216        p: BigNum,
217        q: BigNum,
218        g: BigNum,
219        priv_key: BigNum,
220        pub_key: BigNum,
221    ) -> Result<Dsa<Private>, ErrorStack> {
222        ffi::init();
223        unsafe {
224            let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
225            cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?;
226            mem::forget((p, q, g));
227            cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?;
228            mem::forget((pub_key, priv_key));
229            Ok(dsa)
230        }
231    }
232}
233
234impl Dsa<Public> {
235    from_pem! {
236        /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key.
237        ///
238        /// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
239        #[corresponds(PEM_read_bio_DSA_PUBKEY)]
240        public_key_from_pem,
241        Dsa<Public>,
242        ffi::PEM_read_bio_DSA_PUBKEY
243    }
244
245    from_der! {
246        /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key.
247        #[corresponds(d2i_DSA_PUBKEY)]
248        public_key_from_der,
249        Dsa<Public>,
250        ffi::d2i_DSA_PUBKEY,
251        crate::libc_types::c_long
252    }
253
254    /// Create a new DSA key with only public components.
255    ///
256    /// `p`, `q` and `g` are the common parameters.
257    /// `pub_key` is the public component of the key.
258    pub fn from_public_components(
259        p: BigNum,
260        q: BigNum,
261        g: BigNum,
262        pub_key: BigNum,
263    ) -> Result<Dsa<Public>, ErrorStack> {
264        ffi::init();
265        unsafe {
266            let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
267            cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?;
268            mem::forget((p, q, g));
269            cvt(DSA_set0_key(dsa.0, pub_key.into_ptr(), ptr::null_mut()))?;
270            Ok(dsa)
271        }
272    }
273}
274
275impl<T> fmt::Debug for Dsa<T> {
276    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277        write!(f, "DSA")
278    }
279}
280
281use crate::ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg};
282
283#[cfg(test)]
284mod test {
285    use super::*;
286    use crate::bn::BigNumContext;
287
288    #[test]
289    pub fn test_generate() {
290        Dsa::generate(1024).unwrap();
291    }
292
293    #[test]
294    fn test_pubkey_generation() {
295        let dsa = Dsa::generate(1024).unwrap();
296        let p = dsa.p();
297        let g = dsa.g();
298        let priv_key = dsa.priv_key();
299        let pub_key = dsa.pub_key();
300        let mut ctx = BigNumContext::new().unwrap();
301        let mut calc = BigNum::new().unwrap();
302        calc.mod_exp(g, priv_key, p, &mut ctx).unwrap();
303        assert_eq!(&calc, pub_key);
304    }
305
306    #[test]
307    fn test_priv_key_from_parts() {
308        let p = BigNum::from_u32(283).unwrap();
309        let q = BigNum::from_u32(47).unwrap();
310        let g = BigNum::from_u32(60).unwrap();
311        let priv_key = BigNum::from_u32(15).unwrap();
312        let pub_key = BigNum::from_u32(207).unwrap();
313
314        let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap();
315        assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap());
316        assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap());
317        assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap());
318        assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap());
319        assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap());
320    }
321
322    #[test]
323    fn test_pub_key_from_parts() {
324        let p = BigNum::from_u32(283).unwrap();
325        let q = BigNum::from_u32(47).unwrap();
326        let g = BigNum::from_u32(60).unwrap();
327        let pub_key = BigNum::from_u32(207).unwrap();
328
329        let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap();
330        assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap());
331        assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap());
332        assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap());
333        assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap());
334    }
335
336    #[test]
337    #[allow(clippy::redundant_clone)]
338    fn clone() {
339        let key = Dsa::generate(2048).unwrap();
340        drop(key.clone());
341    }
342}