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}