1use 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 pub struct Dsa<T>;
57 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 #[corresponds(PEM_write_bio_DSA_PUBKEY)]
89 public_key_to_pem,
90 ffi::PEM_write_bio_DSA_PUBKEY
91 }
92
93 to_der! {
94 #[corresponds(i2d_DSA_PUBKEY)]
96 public_key_to_der,
97 ffi::i2d_DSA_PUBKEY
98 }
99
100 #[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 #[corresponds(PEM_write_bio_DSAPrivateKey)]
120 private_key_to_pem,
121 #[corresponds(PEM_write_bio_DSAPrivateKey)]
125 private_key_to_pem_passphrase,
126 ffi::PEM_write_bio_DSAPrivateKey
127 }
128
129 #[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 #[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 #[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 #[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 #[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 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 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 #[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 #[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 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}