Skip to main content

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