Skip to content

Commit 0ba0c71

Browse files
authored
Merge pull request #1709 from wiktor-k/add-dsa-sig
Add openssl::dsa::DsaSig
2 parents 9dae5d8 + cca9c7b commit 0ba0c71

File tree

2 files changed

+221
-0
lines changed

2 files changed

+221
-0
lines changed

openssl-sys/src/handwritten/dsa.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@ use libc::*;
22

33
use *;
44

5+
cfg_if! {
6+
if #[cfg(any(ossl110, libressl280))] {
7+
pub enum DSA_SIG {}
8+
} else {
9+
#[repr(C)]
10+
pub struct DSA_SIG {
11+
pub r: *mut BIGNUM,
12+
pub s: *mut BIGNUM,
13+
}
14+
}
15+
}
16+
517
extern "C" {
618
pub fn DSA_new() -> *mut DSA;
719
pub fn DSA_free(dsa: *mut DSA);
@@ -55,4 +67,19 @@ extern "C" {
5567
pub fn DSA_get0_key(d: *const DSA, pub_key: *mut *const BIGNUM, priv_key: *mut *const BIGNUM);
5668
#[cfg(any(ossl110, libressl273))]
5769
pub fn DSA_set0_key(d: *mut DSA, pub_key: *mut BIGNUM, priv_key: *mut BIGNUM) -> c_int;
70+
pub fn d2i_DSA_SIG(
71+
sig: *mut *mut DSA_SIG,
72+
pp: *mut *const c_uchar,
73+
length: c_long,
74+
) -> *mut DSA_SIG;
75+
pub fn i2d_DSA_SIG(a: *const DSA_SIG, pp: *mut *mut c_uchar) -> c_int;
76+
77+
pub fn DSA_SIG_new() -> *mut DSA_SIG;
78+
pub fn DSA_SIG_free(sig: *mut DSA_SIG);
79+
80+
#[cfg(any(ossl110, libressl273))]
81+
pub fn DSA_SIG_get0(sig: *const DSA_SIG, pr: *mut *const BIGNUM, ps: *mut *const BIGNUM);
82+
83+
#[cfg(any(ossl110, libressl273))]
84+
pub fn DSA_SIG_set0(sig: *mut DSA_SIG, pr: *mut BIGNUM, ps: *mut BIGNUM) -> c_int;
5885
}

openssl/src/dsa.rs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,159 @@ cfg_if! {
344344
}
345345
}
346346

347+
foreign_type_and_impl_send_sync! {
348+
type CType = ffi::DSA_SIG;
349+
fn drop = ffi::DSA_SIG_free;
350+
351+
/// Object representing DSA signature.
352+
///
353+
/// DSA signatures consist of two components: `r` and `s`.
354+
///
355+
/// # Examples
356+
///
357+
/// ```
358+
/// use std::convert::TryInto;
359+
///
360+
/// use openssl::bn::BigNum;
361+
/// use openssl::dsa::{Dsa, DsaSig};
362+
/// use openssl::hash::MessageDigest;
363+
/// use openssl::pkey::PKey;
364+
/// use openssl::sign::{Signer, Verifier};
365+
///
366+
/// const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
367+
/// let dsa_ref = Dsa::generate(1024).unwrap();
368+
///
369+
/// let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap();
370+
/// let priv_key: PKey<_> = dsa_ref.try_into().unwrap();
371+
///
372+
/// let mut signer = if let Ok(signer) = Signer::new(MessageDigest::sha256(), &priv_key) {
373+
/// signer
374+
/// } else {
375+
/// // DSA signing is not supported (eg. BoringSSL)
376+
/// return;
377+
/// };
378+
///
379+
/// signer.update(TEST_DATA).unwrap();
380+
///
381+
/// let signature = signer.sign_to_vec().unwrap();
382+
/// // Parse DER-encoded DSA signature
383+
/// let signature = DsaSig::from_der(&signature).unwrap();
384+
///
385+
/// // Extract components `r` and `s`
386+
/// let r = BigNum::from_slice(&signature.r().to_vec()).unwrap();
387+
/// let s = BigNum::from_slice(&signature.s().to_vec()).unwrap();
388+
///
389+
/// // Construct new DSA signature from components
390+
/// let signature = DsaSig::from_private_components(r, s).unwrap();
391+
///
392+
/// // Serialize DSA signature to DER
393+
/// let signature = signature.to_der().unwrap();
394+
///
395+
/// let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap();
396+
/// verifier.update(TEST_DATA).unwrap();
397+
/// assert!(verifier.verify(&signature[..]).unwrap());
398+
/// ```
399+
pub struct DsaSig;
400+
401+
/// Reference to a [`DsaSig`].
402+
pub struct DsaSigRef;
403+
}
404+
405+
impl DsaSig {
406+
/// Returns a new `DsaSig` by setting the `r` and `s` values associated with an DSA signature.
407+
#[corresponds(DSA_SIG_set0)]
408+
pub fn from_private_components(r: BigNum, s: BigNum) -> Result<Self, ErrorStack> {
409+
unsafe {
410+
let sig = cvt_p(ffi::DSA_SIG_new())?;
411+
DSA_SIG_set0(sig, r.as_ptr(), s.as_ptr());
412+
mem::forget((r, s));
413+
Ok(DsaSig::from_ptr(sig))
414+
}
415+
}
416+
417+
from_der! {
418+
/// Decodes a DER-encoded DSA signature.
419+
#[corresponds(d2i_DSA_SIG)]
420+
from_der,
421+
DsaSig,
422+
ffi::d2i_DSA_SIG
423+
}
424+
}
425+
426+
impl fmt::Debug for DsaSig {
427+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428+
f.debug_struct("DsaSig")
429+
.field("r", self.r())
430+
.field("s", self.s())
431+
.finish()
432+
}
433+
}
434+
435+
impl DsaSigRef {
436+
to_der! {
437+
/// Serializes the DSA signature into a DER-encoded `DSASignature` structure.
438+
#[corresponds(i2d_DSA_SIG)]
439+
to_der,
440+
ffi::i2d_DSA_SIG
441+
}
442+
443+
/// Returns internal component `r` of an `DsaSig`.
444+
#[corresponds(DSA_SIG_get0)]
445+
pub fn r(&self) -> &BigNumRef {
446+
unsafe {
447+
let mut r = ptr::null();
448+
DSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut());
449+
BigNumRef::from_const_ptr(r)
450+
}
451+
}
452+
453+
/// Returns internal component `s` of an `DsaSig`.
454+
#[corresponds(DSA_SIG_get0)]
455+
pub fn s(&self) -> &BigNumRef {
456+
unsafe {
457+
let mut s = ptr::null();
458+
DSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s);
459+
BigNumRef::from_const_ptr(s)
460+
}
461+
}
462+
}
463+
464+
cfg_if! {
465+
if #[cfg(any(ossl110, libressl273))] {
466+
use ffi::{DSA_SIG_set0, DSA_SIG_get0};
467+
} else {
468+
#[allow(bad_style)]
469+
unsafe fn DSA_SIG_set0(
470+
sig: *mut ffi::DSA_SIG,
471+
r: *mut ffi::BIGNUM,
472+
s: *mut ffi::BIGNUM,
473+
) -> c_int {
474+
if r.is_null() || s.is_null() {
475+
return 0;
476+
}
477+
ffi::BN_clear_free((*sig).r);
478+
ffi::BN_clear_free((*sig).s);
479+
(*sig).r = r;
480+
(*sig).s = s;
481+
1
482+
}
483+
484+
#[allow(bad_style)]
485+
unsafe fn DSA_SIG_get0(
486+
sig: *const ffi::DSA_SIG,
487+
pr: *mut *const ffi::BIGNUM,
488+
ps: *mut *const ffi::BIGNUM)
489+
{
490+
if !pr.is_null() {
491+
(*pr) = (*sig).r;
492+
}
493+
if !ps.is_null() {
494+
(*ps) = (*sig).s;
495+
}
496+
}
497+
}
498+
}
499+
347500
#[cfg(test)]
348501
mod test {
349502
use super::*;
@@ -444,10 +597,51 @@ mod test {
444597
assert!(verifier.verify(&signature[..]).unwrap());
445598
}
446599

600+
#[test]
601+
#[cfg(not(boringssl))]
602+
fn test_signature_der() {
603+
use std::convert::TryInto;
604+
605+
const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
606+
let dsa_ref = Dsa::generate(1024).unwrap();
607+
608+
let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap();
609+
let priv_key: PKey<_> = dsa_ref.try_into().unwrap();
610+
611+
let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap();
612+
signer.update(TEST_DATA).unwrap();
613+
614+
let signature = signer.sign_to_vec().unwrap();
615+
eprintln!("{:?}", signature);
616+
let signature = DsaSig::from_der(&signature).unwrap();
617+
618+
let r = BigNum::from_slice(&signature.r().to_vec()).unwrap();
619+
let s = BigNum::from_slice(&signature.s().to_vec()).unwrap();
620+
621+
let signature = DsaSig::from_private_components(r, s).unwrap();
622+
let signature = signature.to_der().unwrap();
623+
624+
let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap();
625+
verifier.update(TEST_DATA).unwrap();
626+
assert!(verifier.verify(&signature[..]).unwrap());
627+
}
628+
447629
#[test]
448630
#[allow(clippy::redundant_clone)]
449631
fn clone() {
450632
let key = Dsa::generate(2048).unwrap();
451633
drop(key.clone());
452634
}
635+
636+
#[test]
637+
fn dsa_sig_debug() {
638+
let sig = DsaSig::from_der(&[
639+
48, 46, 2, 21, 0, 135, 169, 24, 58, 153, 37, 175, 248, 200, 45, 251, 112, 238, 238, 89,
640+
172, 177, 182, 166, 237, 2, 21, 0, 159, 146, 151, 237, 187, 8, 82, 115, 14, 183, 103,
641+
12, 203, 46, 161, 208, 251, 167, 123, 131,
642+
])
643+
.unwrap();
644+
let s = format!("{:?}", sig);
645+
assert_eq!(s, "DsaSig { r: 774484690634577222213819810519929266740561094381, s: 910998676210681457251421818099943952372231273347 }");
646+
}
453647
}

0 commit comments

Comments
 (0)