1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions.
use crate::ffi;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::{c_int, size_t};
use std::mem;
use std::ptr;
use crate::bn::{BigNum, BigNumRef};
use crate::ec::EcKeyRef;
use crate::error::ErrorStack;
use crate::pkey::{HasPrivate, HasPublic};
use crate::{cvt_n, cvt_p};
foreign_type_and_impl_send_sync! {
type CType = ffi::ECDSA_SIG;
fn drop = ffi::ECDSA_SIG_free;
/// A low level interface to ECDSA
///
/// OpenSSL documentation at [`ECDSA_sign`]
///
/// [`ECDSA_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_sign.html
pub struct EcdsaSig;
}
impl EcdsaSig {
/// Computes a digital signature of the hash value `data` using the private EC key eckey.
///
/// OpenSSL documentation at [`ECDSA_do_sign`]
///
/// [`ECDSA_do_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_sign.html
pub fn sign<T>(data: &[u8], eckey: &EcKeyRef<T>) -> Result<EcdsaSig, ErrorStack>
where
T: HasPrivate,
{
unsafe {
assert!(data.len() <= c_int::max_value() as usize);
let sig = cvt_p(ffi::ECDSA_do_sign(
data.as_ptr(),
data.len() as size_t,
eckey.as_ptr(),
))?;
Ok(EcdsaSig::from_ptr(sig as *mut _))
}
}
/// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with a
/// ECDSA signature.
///
/// OpenSSL documentation at [`ECDSA_SIG_set0`]
///
/// [`ECDSA_SIG_set0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html
pub fn from_private_components(r: BigNum, s: BigNum) -> Result<EcdsaSig, ErrorStack> {
unsafe {
let sig = cvt_p(ffi::ECDSA_SIG_new())?;
ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr());
mem::forget((r, s));
Ok(EcdsaSig::from_ptr(sig as *mut _))
}
}
from_der! {
/// Decodes a DER-encoded ECDSA signature.
///
/// This corresponds to [`d2i_ECDSA_SIG`].
///
/// [`d2i_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_ECDSA_SIG.html
from_der,
EcdsaSig,
ffi::d2i_ECDSA_SIG,
::libc::c_long
}
}
impl EcdsaSigRef {
to_der! {
/// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure.
///
/// This corresponds to [`i2d_ECDSA_SIG`].
///
/// [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html
to_der,
ffi::i2d_ECDSA_SIG
}
/// Verifies if the signature is a valid ECDSA signature using the given public key.
///
/// OpenSSL documentation at [`ECDSA_do_verify`]
///
/// [`ECDSA_do_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_verify.html
pub fn verify<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack>
where
T: HasPublic,
{
unsafe {
assert!(data.len() <= c_int::max_value() as usize);
cvt_n(ffi::ECDSA_do_verify(
data.as_ptr(),
data.len() as size_t,
self.as_ptr(),
eckey.as_ptr(),
))
.map(|x| x == 1)
}
}
/// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2)
///
/// OpenSSL documentation at [`ECDSA_SIG_get0`]
///
/// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html
pub fn r(&self) -> &BigNumRef {
unsafe {
let mut r = ptr::null();
ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut());
BigNumRef::from_ptr(r as *mut _)
}
}
/// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2)
///
/// OpenSSL documentation at [`ECDSA_SIG_get0`]
///
/// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html
pub fn s(&self) -> &BigNumRef {
unsafe {
let mut s = ptr::null();
ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s);
BigNumRef::from_ptr(s as *mut _)
}
}
}
use crate::ffi::{ECDSA_SIG_get0, ECDSA_SIG_set0};