192f3ab15Sopenharmony_ci//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions. 292f3ab15Sopenharmony_ci 392f3ab15Sopenharmony_ciuse cfg_if::cfg_if; 492f3ab15Sopenharmony_ciuse foreign_types::{ForeignType, ForeignTypeRef}; 592f3ab15Sopenharmony_ciuse libc::c_int; 692f3ab15Sopenharmony_ciuse std::mem; 792f3ab15Sopenharmony_ciuse std::ptr; 892f3ab15Sopenharmony_ci 992f3ab15Sopenharmony_ciuse crate::bn::{BigNum, BigNumRef}; 1092f3ab15Sopenharmony_ciuse crate::ec::EcKeyRef; 1192f3ab15Sopenharmony_ciuse crate::error::ErrorStack; 1292f3ab15Sopenharmony_ciuse crate::pkey::{HasPrivate, HasPublic}; 1392f3ab15Sopenharmony_ciuse crate::util::ForeignTypeRefExt; 1492f3ab15Sopenharmony_ciuse crate::{cvt_n, cvt_p, LenType}; 1592f3ab15Sopenharmony_ciuse openssl_macros::corresponds; 1692f3ab15Sopenharmony_ci 1792f3ab15Sopenharmony_ciforeign_type_and_impl_send_sync! { 1892f3ab15Sopenharmony_ci type CType = ffi::ECDSA_SIG; 1992f3ab15Sopenharmony_ci fn drop = ffi::ECDSA_SIG_free; 2092f3ab15Sopenharmony_ci 2192f3ab15Sopenharmony_ci /// A low level interface to ECDSA. 2292f3ab15Sopenharmony_ci pub struct EcdsaSig; 2392f3ab15Sopenharmony_ci /// A reference to an [`EcdsaSig`]. 2492f3ab15Sopenharmony_ci pub struct EcdsaSigRef; 2592f3ab15Sopenharmony_ci} 2692f3ab15Sopenharmony_ci 2792f3ab15Sopenharmony_ciimpl EcdsaSig { 2892f3ab15Sopenharmony_ci /// Computes a digital signature of the hash value `data` using the private EC key eckey. 2992f3ab15Sopenharmony_ci #[corresponds(ECDSA_do_sign)] 3092f3ab15Sopenharmony_ci pub fn sign<T>(data: &[u8], eckey: &EcKeyRef<T>) -> Result<EcdsaSig, ErrorStack> 3192f3ab15Sopenharmony_ci where 3292f3ab15Sopenharmony_ci T: HasPrivate, 3392f3ab15Sopenharmony_ci { 3492f3ab15Sopenharmony_ci unsafe { 3592f3ab15Sopenharmony_ci assert!(data.len() <= c_int::max_value() as usize); 3692f3ab15Sopenharmony_ci let sig = cvt_p(ffi::ECDSA_do_sign( 3792f3ab15Sopenharmony_ci data.as_ptr(), 3892f3ab15Sopenharmony_ci data.len() as LenType, 3992f3ab15Sopenharmony_ci eckey.as_ptr(), 4092f3ab15Sopenharmony_ci ))?; 4192f3ab15Sopenharmony_ci Ok(EcdsaSig::from_ptr(sig)) 4292f3ab15Sopenharmony_ci } 4392f3ab15Sopenharmony_ci } 4492f3ab15Sopenharmony_ci 4592f3ab15Sopenharmony_ci /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with an ECDSA signature. 4692f3ab15Sopenharmony_ci #[corresponds(ECDSA_SIG_set0)] 4792f3ab15Sopenharmony_ci pub fn from_private_components(r: BigNum, s: BigNum) -> Result<EcdsaSig, ErrorStack> { 4892f3ab15Sopenharmony_ci unsafe { 4992f3ab15Sopenharmony_ci let sig = cvt_p(ffi::ECDSA_SIG_new())?; 5092f3ab15Sopenharmony_ci ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); 5192f3ab15Sopenharmony_ci mem::forget((r, s)); 5292f3ab15Sopenharmony_ci Ok(EcdsaSig::from_ptr(sig)) 5392f3ab15Sopenharmony_ci } 5492f3ab15Sopenharmony_ci } 5592f3ab15Sopenharmony_ci 5692f3ab15Sopenharmony_ci from_der! { 5792f3ab15Sopenharmony_ci /// Decodes a DER-encoded ECDSA signature. 5892f3ab15Sopenharmony_ci #[corresponds(d2i_ECDSA_SIG)] 5992f3ab15Sopenharmony_ci from_der, 6092f3ab15Sopenharmony_ci EcdsaSig, 6192f3ab15Sopenharmony_ci ffi::d2i_ECDSA_SIG 6292f3ab15Sopenharmony_ci } 6392f3ab15Sopenharmony_ci} 6492f3ab15Sopenharmony_ci 6592f3ab15Sopenharmony_ciimpl EcdsaSigRef { 6692f3ab15Sopenharmony_ci to_der! { 6792f3ab15Sopenharmony_ci /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. 6892f3ab15Sopenharmony_ci #[corresponds(i2d_ECDSA_SIG)] 6992f3ab15Sopenharmony_ci to_der, 7092f3ab15Sopenharmony_ci ffi::i2d_ECDSA_SIG 7192f3ab15Sopenharmony_ci } 7292f3ab15Sopenharmony_ci 7392f3ab15Sopenharmony_ci /// Verifies if the signature is a valid ECDSA signature using the given public key. 7492f3ab15Sopenharmony_ci #[corresponds(ECDSA_do_verify)] 7592f3ab15Sopenharmony_ci pub fn verify<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack> 7692f3ab15Sopenharmony_ci where 7792f3ab15Sopenharmony_ci T: HasPublic, 7892f3ab15Sopenharmony_ci { 7992f3ab15Sopenharmony_ci unsafe { 8092f3ab15Sopenharmony_ci assert!(data.len() <= c_int::max_value() as usize); 8192f3ab15Sopenharmony_ci cvt_n(ffi::ECDSA_do_verify( 8292f3ab15Sopenharmony_ci data.as_ptr(), 8392f3ab15Sopenharmony_ci data.len() as LenType, 8492f3ab15Sopenharmony_ci self.as_ptr(), 8592f3ab15Sopenharmony_ci eckey.as_ptr(), 8692f3ab15Sopenharmony_ci )) 8792f3ab15Sopenharmony_ci .map(|x| x == 1) 8892f3ab15Sopenharmony_ci } 8992f3ab15Sopenharmony_ci } 9092f3ab15Sopenharmony_ci 9192f3ab15Sopenharmony_ci /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) 9292f3ab15Sopenharmony_ci #[corresponds(ECDSA_SIG_get0)] 9392f3ab15Sopenharmony_ci pub fn r(&self) -> &BigNumRef { 9492f3ab15Sopenharmony_ci unsafe { 9592f3ab15Sopenharmony_ci let mut r = ptr::null(); 9692f3ab15Sopenharmony_ci ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); 9792f3ab15Sopenharmony_ci BigNumRef::from_const_ptr(r) 9892f3ab15Sopenharmony_ci } 9992f3ab15Sopenharmony_ci } 10092f3ab15Sopenharmony_ci 10192f3ab15Sopenharmony_ci /// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) 10292f3ab15Sopenharmony_ci #[corresponds(ECDSA_SIG_get0)] 10392f3ab15Sopenharmony_ci pub fn s(&self) -> &BigNumRef { 10492f3ab15Sopenharmony_ci unsafe { 10592f3ab15Sopenharmony_ci let mut s = ptr::null(); 10692f3ab15Sopenharmony_ci ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); 10792f3ab15Sopenharmony_ci BigNumRef::from_const_ptr(s) 10892f3ab15Sopenharmony_ci } 10992f3ab15Sopenharmony_ci } 11092f3ab15Sopenharmony_ci} 11192f3ab15Sopenharmony_ci 11292f3ab15Sopenharmony_cicfg_if! { 11392f3ab15Sopenharmony_ci if #[cfg(any(ossl110, libressl273, boringssl))] { 11492f3ab15Sopenharmony_ci use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; 11592f3ab15Sopenharmony_ci } else { 11692f3ab15Sopenharmony_ci #[allow(bad_style)] 11792f3ab15Sopenharmony_ci unsafe fn ECDSA_SIG_set0( 11892f3ab15Sopenharmony_ci sig: *mut ffi::ECDSA_SIG, 11992f3ab15Sopenharmony_ci r: *mut ffi::BIGNUM, 12092f3ab15Sopenharmony_ci s: *mut ffi::BIGNUM, 12192f3ab15Sopenharmony_ci ) -> c_int { 12292f3ab15Sopenharmony_ci if r.is_null() || s.is_null() { 12392f3ab15Sopenharmony_ci return 0; 12492f3ab15Sopenharmony_ci } 12592f3ab15Sopenharmony_ci ffi::BN_clear_free((*sig).r); 12692f3ab15Sopenharmony_ci ffi::BN_clear_free((*sig).s); 12792f3ab15Sopenharmony_ci (*sig).r = r; 12892f3ab15Sopenharmony_ci (*sig).s = s; 12992f3ab15Sopenharmony_ci 1 13092f3ab15Sopenharmony_ci } 13192f3ab15Sopenharmony_ci 13292f3ab15Sopenharmony_ci #[allow(bad_style)] 13392f3ab15Sopenharmony_ci unsafe fn ECDSA_SIG_get0( 13492f3ab15Sopenharmony_ci sig: *const ffi::ECDSA_SIG, 13592f3ab15Sopenharmony_ci pr: *mut *const ffi::BIGNUM, 13692f3ab15Sopenharmony_ci ps: *mut *const ffi::BIGNUM) 13792f3ab15Sopenharmony_ci { 13892f3ab15Sopenharmony_ci if !pr.is_null() { 13992f3ab15Sopenharmony_ci (*pr) = (*sig).r; 14092f3ab15Sopenharmony_ci } 14192f3ab15Sopenharmony_ci if !ps.is_null() { 14292f3ab15Sopenharmony_ci (*ps) = (*sig).s; 14392f3ab15Sopenharmony_ci } 14492f3ab15Sopenharmony_ci } 14592f3ab15Sopenharmony_ci } 14692f3ab15Sopenharmony_ci} 14792f3ab15Sopenharmony_ci 14892f3ab15Sopenharmony_ci#[cfg(test)] 14992f3ab15Sopenharmony_cimod test { 15092f3ab15Sopenharmony_ci use super::*; 15192f3ab15Sopenharmony_ci use crate::ec::EcGroup; 15292f3ab15Sopenharmony_ci use crate::ec::EcKey; 15392f3ab15Sopenharmony_ci use crate::nid::Nid; 15492f3ab15Sopenharmony_ci use crate::pkey::{Private, Public}; 15592f3ab15Sopenharmony_ci 15692f3ab15Sopenharmony_ci fn get_public_key(group: &EcGroup, x: &EcKey<Private>) -> Result<EcKey<Public>, ErrorStack> { 15792f3ab15Sopenharmony_ci EcKey::from_public_key(group, x.public_key()) 15892f3ab15Sopenharmony_ci } 15992f3ab15Sopenharmony_ci 16092f3ab15Sopenharmony_ci #[test] 16192f3ab15Sopenharmony_ci #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] 16292f3ab15Sopenharmony_ci fn sign_and_verify() { 16392f3ab15Sopenharmony_ci let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 16492f3ab15Sopenharmony_ci let private_key = EcKey::generate(&group).unwrap(); 16592f3ab15Sopenharmony_ci let public_key = get_public_key(&group, &private_key).unwrap(); 16692f3ab15Sopenharmony_ci 16792f3ab15Sopenharmony_ci let private_key2 = EcKey::generate(&group).unwrap(); 16892f3ab15Sopenharmony_ci let public_key2 = get_public_key(&group, &private_key2).unwrap(); 16992f3ab15Sopenharmony_ci 17092f3ab15Sopenharmony_ci let data = String::from("hello"); 17192f3ab15Sopenharmony_ci let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); 17292f3ab15Sopenharmony_ci 17392f3ab15Sopenharmony_ci // Signature can be verified using the correct data & correct public key 17492f3ab15Sopenharmony_ci let verification = res.verify(data.as_bytes(), &public_key).unwrap(); 17592f3ab15Sopenharmony_ci assert!(verification); 17692f3ab15Sopenharmony_ci 17792f3ab15Sopenharmony_ci // Signature will not be verified using the incorrect data but the correct public key 17892f3ab15Sopenharmony_ci let verification2 = res 17992f3ab15Sopenharmony_ci .verify(String::from("hello2").as_bytes(), &public_key) 18092f3ab15Sopenharmony_ci .unwrap(); 18192f3ab15Sopenharmony_ci assert!(!verification2); 18292f3ab15Sopenharmony_ci 18392f3ab15Sopenharmony_ci // Signature will not be verified using the correct data but the incorrect public key 18492f3ab15Sopenharmony_ci let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap(); 18592f3ab15Sopenharmony_ci assert!(!verification3); 18692f3ab15Sopenharmony_ci } 18792f3ab15Sopenharmony_ci 18892f3ab15Sopenharmony_ci #[test] 18992f3ab15Sopenharmony_ci #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] 19092f3ab15Sopenharmony_ci fn check_private_components() { 19192f3ab15Sopenharmony_ci let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 19292f3ab15Sopenharmony_ci let private_key = EcKey::generate(&group).unwrap(); 19392f3ab15Sopenharmony_ci let public_key = get_public_key(&group, &private_key).unwrap(); 19492f3ab15Sopenharmony_ci let data = String::from("hello"); 19592f3ab15Sopenharmony_ci let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); 19692f3ab15Sopenharmony_ci 19792f3ab15Sopenharmony_ci let verification = res.verify(data.as_bytes(), &public_key).unwrap(); 19892f3ab15Sopenharmony_ci assert!(verification); 19992f3ab15Sopenharmony_ci 20092f3ab15Sopenharmony_ci let r = res.r().to_owned().unwrap(); 20192f3ab15Sopenharmony_ci let s = res.s().to_owned().unwrap(); 20292f3ab15Sopenharmony_ci 20392f3ab15Sopenharmony_ci let res2 = EcdsaSig::from_private_components(r, s).unwrap(); 20492f3ab15Sopenharmony_ci let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap(); 20592f3ab15Sopenharmony_ci assert!(verification2); 20692f3ab15Sopenharmony_ci } 20792f3ab15Sopenharmony_ci 20892f3ab15Sopenharmony_ci #[test] 20992f3ab15Sopenharmony_ci #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] 21092f3ab15Sopenharmony_ci fn serialize_deserialize() { 21192f3ab15Sopenharmony_ci let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); 21292f3ab15Sopenharmony_ci let private_key = EcKey::generate(&group).unwrap(); 21392f3ab15Sopenharmony_ci let public_key = get_public_key(&group, &private_key).unwrap(); 21492f3ab15Sopenharmony_ci 21592f3ab15Sopenharmony_ci let data = String::from("hello"); 21692f3ab15Sopenharmony_ci let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); 21792f3ab15Sopenharmony_ci 21892f3ab15Sopenharmony_ci let der = res.to_der().unwrap(); 21992f3ab15Sopenharmony_ci let sig = EcdsaSig::from_der(&der).unwrap(); 22092f3ab15Sopenharmony_ci 22192f3ab15Sopenharmony_ci let verification = sig.verify(data.as_bytes(), &public_key).unwrap(); 22292f3ab15Sopenharmony_ci assert!(verification); 22392f3ab15Sopenharmony_ci } 22492f3ab15Sopenharmony_ci} 225