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