217 lines
6.0 KiB
Rust
217 lines
6.0 KiB
Rust
//! Digital Signatures
|
|
//!
|
|
//! DSA ensures a message originated from a known sender, and was not modified.
|
|
//! DSA uses asymetrical keys and an algorithm to output a signature of the message
|
|
//! using the private key that can be validated with the public key but not be generated
|
|
//! without the private key.
|
|
|
|
use ffi;
|
|
use foreign_types::{ForeignType, ForeignTypeRef};
|
|
use libc::c_int;
|
|
use std::fmt;
|
|
use std::ptr;
|
|
|
|
use {cvt, cvt_p};
|
|
use bn::BigNumRef;
|
|
use error::ErrorStack;
|
|
use pkey::{HasParams, HasPublic, Private, Public};
|
|
|
|
generic_foreign_type_and_impl_send_sync! {
|
|
type CType = ffi::DSA;
|
|
fn drop = ffi::DSA_free;
|
|
|
|
/// Object representing DSA keys.
|
|
///
|
|
/// A DSA object contains the parameters p, q, and g. There is a private
|
|
/// and public key. The values p, g, and q are:
|
|
///
|
|
/// * `p`: DSA prime parameter
|
|
/// * `q`: DSA sub-prime parameter
|
|
/// * `g`: DSA base parameter
|
|
///
|
|
/// These values are used to calculate a pair of asymetrical keys used for
|
|
/// signing.
|
|
///
|
|
/// OpenSSL documentation at [`DSA_new`]
|
|
///
|
|
/// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html
|
|
///
|
|
/// # Examples
|
|
///
|
|
/// ```
|
|
/// use openssl::dsa::Dsa;
|
|
/// use openssl::error::ErrorStack;
|
|
/// use openssl::pkey::Private;
|
|
///
|
|
/// fn create_dsa() -> Result<Dsa<Private>, ErrorStack> {
|
|
/// let sign = Dsa::generate(2048)?;
|
|
/// Ok(sign)
|
|
/// }
|
|
/// # fn main() {
|
|
/// # create_dsa();
|
|
/// # }
|
|
/// ```
|
|
pub struct Dsa<T>;
|
|
/// Reference to [`Dsa`].
|
|
///
|
|
/// [`Dsa`]: struct.Dsa.html
|
|
pub struct DsaRef<T>;
|
|
}
|
|
|
|
impl<T> DsaRef<T>
|
|
where
|
|
T: HasPublic,
|
|
{
|
|
to_pem! {
|
|
/// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure.
|
|
///
|
|
/// The output will have a header of `-----BEGIN PUBLIC KEY-----`.
|
|
///
|
|
/// This corresponds to [`PEM_write_bio_DSA_PUBKEY`].
|
|
///
|
|
/// [`PEM_write_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSA_PUBKEY.html
|
|
public_key_to_pem,
|
|
ffi::PEM_write_bio_DSA_PUBKEY
|
|
}
|
|
|
|
to_der! {
|
|
/// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure.
|
|
///
|
|
/// This corresponds to [`i2d_DSA_PUBKEY`].
|
|
///
|
|
/// [`i2d_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DSA_PUBKEY.html
|
|
public_key_to_der,
|
|
ffi::i2d_DSA_PUBKEY
|
|
}
|
|
}
|
|
|
|
impl<T> DsaRef<T>
|
|
where
|
|
T: HasParams,
|
|
{
|
|
/// Returns the maximum size of the signature output by `self` in bytes.
|
|
///
|
|
/// OpenSSL documentation at [`DSA_size`]
|
|
///
|
|
/// [`DSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_size.html
|
|
pub fn size(&self) -> u32 {
|
|
unsafe { ffi::DSA_size(self.as_ptr()) as u32 }
|
|
}
|
|
|
|
/// Returns the DSA prime parameter of `self`.
|
|
pub fn p(&self) -> &BigNumRef {
|
|
unsafe {
|
|
let p = compat::pqg(self.as_ptr())[0];
|
|
BigNumRef::from_ptr(p as *mut _)
|
|
}
|
|
}
|
|
|
|
/// Returns the DSA sub-prime parameter of `self`.
|
|
pub fn q(&self) -> &BigNumRef {
|
|
unsafe {
|
|
let q = compat::pqg(self.as_ptr())[1];
|
|
BigNumRef::from_ptr(q as *mut _)
|
|
}
|
|
}
|
|
|
|
/// Returns the DSA base parameter of `self`.
|
|
pub fn g(&self) -> &BigNumRef {
|
|
unsafe {
|
|
let g = compat::pqg(self.as_ptr())[2];
|
|
BigNumRef::from_ptr(g as *mut _)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dsa<Private> {
|
|
/// Generate a DSA key pair.
|
|
///
|
|
/// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values.
|
|
/// These values are used to generate the key pair with [`DSA_generate_key`].
|
|
///
|
|
/// The `bits` parameter coresponds to the length of the prime `p`.
|
|
///
|
|
/// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html
|
|
/// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html
|
|
pub fn generate(bits: u32) -> Result<Dsa<Private>, ErrorStack> {
|
|
ffi::init();
|
|
unsafe {
|
|
let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?);
|
|
cvt(ffi::DSA_generate_parameters_ex(
|
|
dsa.0,
|
|
bits as c_int,
|
|
ptr::null(),
|
|
0,
|
|
ptr::null_mut(),
|
|
ptr::null_mut(),
|
|
ptr::null_mut(),
|
|
))?;
|
|
cvt(ffi::DSA_generate_key(dsa.0))?;
|
|
Ok(dsa)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Dsa<Public> {
|
|
from_pem! {
|
|
/// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key.
|
|
///
|
|
/// The input should have a header of `-----BEGIN PUBLIC KEY-----`.
|
|
///
|
|
/// This corresponds to [`PEM_read_bio_DSA_PUBKEY`].
|
|
///
|
|
/// [`PEM_read_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DSA_PUBKEY.html
|
|
public_key_from_pem,
|
|
Dsa<Public>,
|
|
ffi::PEM_read_bio_DSA_PUBKEY
|
|
}
|
|
|
|
from_der! {
|
|
/// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key.
|
|
///
|
|
/// This corresponds to [`d2i_DSA_PUBKEY`].
|
|
///
|
|
/// [`d2i_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_DSA_PUBKEY.html
|
|
public_key_from_der,
|
|
Dsa<Public>,
|
|
ffi::d2i_DSA_PUBKEY
|
|
}
|
|
}
|
|
|
|
impl<T> fmt::Debug for Dsa<T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "DSA")
|
|
}
|
|
}
|
|
|
|
#[cfg(ossl110)]
|
|
mod compat {
|
|
use std::ptr;
|
|
use ffi::{self, BIGNUM, DSA};
|
|
|
|
pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] {
|
|
let (mut p, mut q, mut g) = (ptr::null(), ptr::null(), ptr::null());
|
|
ffi::DSA_get0_pqg(d, &mut p, &mut q, &mut g);
|
|
[p, q, g]
|
|
}
|
|
}
|
|
|
|
#[cfg(ossl10x)]
|
|
mod compat {
|
|
use ffi::{BIGNUM, DSA};
|
|
|
|
pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] {
|
|
[(*d).p, (*d).q, (*d).g]
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
pub fn test_generate() {
|
|
Dsa::generate(1024).unwrap();
|
|
}
|
|
}
|