use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
#[cfg(not(boringssl))]
use libc::c_int;
use std::fmt;
use std::mem;
use std::ptr;
use crate::bn::{BigNum, BigNumRef};
use crate::error::ErrorStack;
use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public};
use crate::util::ForeignTypeRefExt;
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;
generic_foreign_type_and_impl_send_sync! {
type CType = ffi::DSA;
fn drop = ffi::DSA_free;
pub struct Dsa<T>;
pub struct DsaRef<T>;
}
impl<T> Clone for Dsa<T> {
fn clone(&self) -> Dsa<T> {
(**self).to_owned()
}
}
impl<T> ToOwned for DsaRef<T> {
type Owned = Dsa<T>;
fn to_owned(&self) -> Dsa<T> {
unsafe {
ffi::DSA_up_ref(self.as_ptr());
Dsa::from_ptr(self.as_ptr())
}
}
}
impl<T> DsaRef<T>
where
T: HasPublic,
{
to_pem! {
#[corresponds(PEM_write_bio_DSA_PUBKEY)]
public_key_to_pem,
ffi::PEM_write_bio_DSA_PUBKEY
}
to_der! {
#[corresponds(i2d_DSA_PUBKEY)]
public_key_to_der,
ffi::i2d_DSA_PUBKEY
}
#[corresponds(DSA_get0_key)]
pub fn pub_key(&self) -> &BigNumRef {
unsafe {
let mut pub_key = ptr::null();
DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut());
BigNumRef::from_const_ptr(pub_key)
}
}
}
impl<T> DsaRef<T>
where
T: HasPrivate,
{
private_key_to_pem! {
#[corresponds(PEM_write_bio_DSAPrivateKey)]
private_key_to_pem,
#[corresponds(PEM_write_bio_DSAPrivateKey)]
private_key_to_pem_passphrase,
ffi::PEM_write_bio_DSAPrivateKey
}
to_der! {
#[corresponds(i2d_DSAPrivateKey)]
private_key_to_der,
ffi::i2d_DSAPrivateKey
}
#[corresponds(DSA_get0_key)]
pub fn priv_key(&self) -> &BigNumRef {
unsafe {
let mut priv_key = ptr::null();
DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key);
BigNumRef::from_const_ptr(priv_key)
}
}
}
impl<T> DsaRef<T>
where
T: HasParams,
{
#[corresponds(DSA_size)]
pub fn size(&self) -> u32 {
unsafe { ffi::DSA_size(self.as_ptr()) as u32 }
}
#[corresponds(DSA_get0_pqg)]
pub fn p(&self) -> &BigNumRef {
unsafe {
let mut p = ptr::null();
DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut());
BigNumRef::from_const_ptr(p)
}
}
#[corresponds(DSA_get0_pqg)]
pub fn q(&self) -> &BigNumRef {
unsafe {
let mut q = ptr::null();
DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut());
BigNumRef::from_const_ptr(q)
}
}
#[corresponds(DSA_get0_pqg)]
pub fn g(&self) -> &BigNumRef {
unsafe {
let mut g = ptr::null();
DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g);
BigNumRef::from_const_ptr(g)
}
}
}
#[cfg(boringssl)]
type BitType = libc::c_uint;
#[cfg(not(boringssl))]
type BitType = c_int;
impl Dsa<Params> {
#[corresponds(DSA_set0_pqg)]
pub fn from_pqg(p: BigNum, q: BigNum, g: BigNum) -> Result<Dsa<Params>, ErrorStack> {
unsafe {
let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?;
mem::forget((p, q, g));
Ok(dsa)
}
}
#[corresponds(DSA_generate_parameters_ex)]
pub fn generate_params(bits: u32) -> Result<Dsa<Params>, ErrorStack> {
ffi::init();
unsafe {
let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
cvt(ffi::DSA_generate_parameters_ex(
dsa.0,
bits as BitType,
ptr::null(),
0,
ptr::null_mut(),
ptr::null_mut(),
ptr::null_mut(),
))?;
Ok(dsa)
}
}
#[corresponds(DSA_generate_key)]
pub fn generate_key(self) -> Result<Dsa<Private>, ErrorStack> {
unsafe {
let dsa_ptr = self.0;
cvt(ffi::DSA_generate_key(dsa_ptr))?;
mem::forget(self);
Ok(Dsa::from_ptr(dsa_ptr))
}
}
}
impl Dsa<Private> {
pub fn generate(bits: u32) -> Result<Dsa<Private>, ErrorStack> {
let params = Dsa::generate_params(bits)?;
params.generate_key()
}
pub fn from_private_components(
p: BigNum,
q: BigNum,
g: BigNum,
priv_key: BigNum,
pub_key: BigNum,
) -> Result<Dsa<Private>, ErrorStack> {
ffi::init();
unsafe {
let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?;
mem::forget((p, q, g));
cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?;
mem::forget((pub_key, priv_key));
Ok(dsa)
}
}
}
impl Dsa<Public> {
from_pem! {
#[corresponds(PEM_read_bio_DSA_PUBKEY)]
public_key_from_pem,
Dsa<Public>,
ffi::PEM_read_bio_DSA_PUBKEY
}
from_der! {
#[corresponds(d2i_DSA_PUBKEY)]
public_key_from_der,
Dsa<Public>,
ffi::d2i_DSA_PUBKEY
}
pub fn from_public_components(
p: BigNum,
q: BigNum,
g: BigNum,
pub_key: BigNum,
) -> Result<Dsa<Public>, ErrorStack> {
ffi::init();
unsafe {
let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?;
mem::forget((p, q, g));
cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?;
mem::forget(pub_key);
Ok(dsa)
}
}
}
impl<T> fmt::Debug for Dsa<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "DSA")
}
}
cfg_if! {
if #[cfg(any(ossl110, libressl273, boringssl))] {
use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg};
} else {
#[allow(bad_style)]
unsafe fn DSA_get0_pqg(
d: *mut ffi::DSA,
p: *mut *const ffi::BIGNUM,
q: *mut *const ffi::BIGNUM,
g: *mut *const ffi::BIGNUM)
{
if !p.is_null() {
*p = (*d).p;
}
if !q.is_null() {
*q = (*d).q;
}
if !g.is_null() {
*g = (*d).g;
}
}
#[allow(bad_style)]
unsafe fn DSA_get0_key(
d: *mut ffi::DSA,
pub_key: *mut *const ffi::BIGNUM,
priv_key: *mut *const ffi::BIGNUM)
{
if !pub_key.is_null() {
*pub_key = (*d).pub_key;
}
if !priv_key.is_null() {
*priv_key = (*d).priv_key;
}
}
#[allow(bad_style)]
unsafe fn DSA_set0_key(
d: *mut ffi::DSA,
pub_key: *mut ffi::BIGNUM,
priv_key: *mut ffi::BIGNUM) -> c_int
{
(*d).pub_key = pub_key;
(*d).priv_key = priv_key;
1
}
#[allow(bad_style)]
unsafe fn DSA_set0_pqg(
d: *mut ffi::DSA,
p: *mut ffi::BIGNUM,
q: *mut ffi::BIGNUM,
g: *mut ffi::BIGNUM) -> c_int
{
(*d).p = p;
(*d).q = q;
(*d).g = g;
1
}
}
}
foreign_type_and_impl_send_sync! {
type CType = ffi::DSA_SIG;
fn drop = ffi::DSA_SIG_free;
pub struct DsaSig;
pub struct DsaSigRef;
}
impl DsaSig {
#[corresponds(DSA_SIG_set0)]
pub fn from_private_components(r: BigNum, s: BigNum) -> Result<Self, ErrorStack> {
unsafe {
let sig = cvt_p(ffi::DSA_SIG_new())?;
DSA_SIG_set0(sig, r.as_ptr(), s.as_ptr());
mem::forget((r, s));
Ok(DsaSig::from_ptr(sig))
}
}
from_der! {
#[corresponds(d2i_DSA_SIG)]
from_der,
DsaSig,
ffi::d2i_DSA_SIG
}
}
impl fmt::Debug for DsaSig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("DsaSig")
.field("r", self.r())
.field("s", self.s())
.finish()
}
}
impl DsaSigRef {
to_der! {
#[corresponds(i2d_DSA_SIG)]
to_der,
ffi::i2d_DSA_SIG
}
#[corresponds(DSA_SIG_get0)]
pub fn r(&self) -> &BigNumRef {
unsafe {
let mut r = ptr::null();
DSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut());
BigNumRef::from_const_ptr(r)
}
}
#[corresponds(DSA_SIG_get0)]
pub fn s(&self) -> &BigNumRef {
unsafe {
let mut s = ptr::null();
DSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s);
BigNumRef::from_const_ptr(s)
}
}
}
cfg_if! {
if #[cfg(any(ossl110, libressl273, boringssl))] {
use ffi::{DSA_SIG_set0, DSA_SIG_get0};
} else {
#[allow(bad_style)]
unsafe fn DSA_SIG_set0(
sig: *mut ffi::DSA_SIG,
r: *mut ffi::BIGNUM,
s: *mut ffi::BIGNUM,
) -> c_int {
if r.is_null() || s.is_null() {
return 0;
}
ffi::BN_clear_free((*sig).r);
ffi::BN_clear_free((*sig).s);
(*sig).r = r;
(*sig).s = s;
1
}
#[allow(bad_style)]
unsafe fn DSA_SIG_get0(
sig: *const ffi::DSA_SIG,
pr: *mut *const ffi::BIGNUM,
ps: *mut *const ffi::BIGNUM)
{
if !pr.is_null() {
(*pr) = (*sig).r;
}
if !ps.is_null() {
(*ps) = (*sig).s;
}
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::bn::BigNumContext;
#[cfg(not(boringssl))]
use crate::hash::MessageDigest;
#[cfg(not(boringssl))]
use crate::pkey::PKey;
#[cfg(not(boringssl))]
use crate::sign::{Signer, Verifier};
#[test]
pub fn test_generate() {
Dsa::generate(1024).unwrap();
}
#[test]
fn test_pubkey_generation() {
let dsa = Dsa::generate(1024).unwrap();
let p = dsa.p();
let g = dsa.g();
let priv_key = dsa.priv_key();
let pub_key = dsa.pub_key();
let mut ctx = BigNumContext::new().unwrap();
let mut calc = BigNum::new().unwrap();
calc.mod_exp(g, priv_key, p, &mut ctx).unwrap();
assert_eq!(&calc, pub_key)
}
#[test]
fn test_priv_key_from_parts() {
let p = BigNum::from_u32(283).unwrap();
let q = BigNum::from_u32(47).unwrap();
let g = BigNum::from_u32(60).unwrap();
let priv_key = BigNum::from_u32(15).unwrap();
let pub_key = BigNum::from_u32(207).unwrap();
let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap();
assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap());
assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap());
assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap());
assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap());
assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap());
}
#[test]
fn test_pub_key_from_parts() {
let p = BigNum::from_u32(283).unwrap();
let q = BigNum::from_u32(47).unwrap();
let g = BigNum::from_u32(60).unwrap();
let pub_key = BigNum::from_u32(207).unwrap();
let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap();
assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap());
assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap());
assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap());
assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap());
}
#[test]
fn test_params() {
let params = Dsa::generate_params(1024).unwrap();
let p = params.p().to_owned().unwrap();
let q = params.q().to_owned().unwrap();
let g = params.g().to_owned().unwrap();
let key = params.generate_key().unwrap();
let params2 = Dsa::from_pqg(
key.p().to_owned().unwrap(),
key.q().to_owned().unwrap(),
key.g().to_owned().unwrap(),
)
.unwrap();
assert_eq!(p, *params2.p());
assert_eq!(q, *params2.q());
assert_eq!(g, *params2.g());
}
#[test]
#[cfg(not(boringssl))]
fn test_signature() {
const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let dsa_ref = Dsa::generate(1024).unwrap();
let p = dsa_ref.p();
let q = dsa_ref.q();
let g = dsa_ref.g();
let pub_key = dsa_ref.pub_key();
let priv_key = dsa_ref.priv_key();
let priv_key = Dsa::from_private_components(
BigNumRef::to_owned(p).unwrap(),
BigNumRef::to_owned(q).unwrap(),
BigNumRef::to_owned(g).unwrap(),
BigNumRef::to_owned(priv_key).unwrap(),
BigNumRef::to_owned(pub_key).unwrap(),
)
.unwrap();
let priv_key = PKey::from_dsa(priv_key).unwrap();
let pub_key = Dsa::from_public_components(
BigNumRef::to_owned(p).unwrap(),
BigNumRef::to_owned(q).unwrap(),
BigNumRef::to_owned(g).unwrap(),
BigNumRef::to_owned(pub_key).unwrap(),
)
.unwrap();
let pub_key = PKey::from_dsa(pub_key).unwrap();
let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap();
signer.update(TEST_DATA).unwrap();
let signature = signer.sign_to_vec().unwrap();
let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap();
verifier.update(TEST_DATA).unwrap();
assert!(verifier.verify(&signature[..]).unwrap());
}
#[test]
#[cfg(not(boringssl))]
fn test_signature_der() {
use std::convert::TryInto;
const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let dsa_ref = Dsa::generate(1024).unwrap();
let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap();
let priv_key: PKey<_> = dsa_ref.try_into().unwrap();
let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap();
signer.update(TEST_DATA).unwrap();
let signature = signer.sign_to_vec().unwrap();
eprintln!("{:?}", signature);
let signature = DsaSig::from_der(&signature).unwrap();
let r = BigNum::from_slice(&signature.r().to_vec()).unwrap();
let s = BigNum::from_slice(&signature.s().to_vec()).unwrap();
let signature = DsaSig::from_private_components(r, s).unwrap();
let signature = signature.to_der().unwrap();
let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap();
verifier.update(TEST_DATA).unwrap();
assert!(verifier.verify(&signature[..]).unwrap());
}
#[test]
#[allow(clippy::redundant_clone)]
fn clone() {
let key = Dsa::generate(2048).unwrap();
drop(key.clone());
}
#[test]
fn dsa_sig_debug() {
let sig = DsaSig::from_der(&[
48, 46, 2, 21, 0, 135, 169, 24, 58, 153, 37, 175, 248, 200, 45, 251, 112, 238, 238, 89,
172, 177, 182, 166, 237, 2, 21, 0, 159, 146, 151, 237, 187, 8, 82, 115, 14, 183, 103,
12, 203, 46, 161, 208, 251, 167, 123, 131,
])
.unwrap();
let s = format!("{:?}", sig);
assert_eq!(s, "DsaSig { r: 774484690634577222213819810519929266740561094381, s: 910998676210681457251421818099943952372231273347 }");
}
}