1 //! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions. 2 3 use cfg_if::cfg_if; 4 use foreign_types::{ForeignType, ForeignTypeRef}; 5 use libc::c_int; 6 use std::mem; 7 use std::ptr; 8 9 use crate::bn::{BigNum, BigNumRef}; 10 use crate::ec::EcKeyRef; 11 use crate::error::ErrorStack; 12 use crate::pkey::{HasPrivate, HasPublic}; 13 use crate::util::ForeignTypeRefExt; 14 use crate::{cvt_n, cvt_p}; 15 16 foreign_type_and_impl_send_sync! { 17 type CType = ffi::ECDSA_SIG; 18 fn drop = ffi::ECDSA_SIG_free; 19 20 /// A low level interface to ECDSA 21 /// 22 /// OpenSSL documentation at [`ECDSA_sign`] 23 /// 24 /// [`ECDSA_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_sign.html 25 pub struct EcdsaSig; 26 /// Reference to [`EcdsaSig`] 27 /// 28 /// [`EcdsaSig`]: struct.EcdsaSig.html 29 pub struct EcdsaSigRef; 30 } 31 32 impl EcdsaSig { 33 /// Computes a digital signature of the hash value `data` using the private EC key eckey. 34 /// 35 /// OpenSSL documentation at [`ECDSA_do_sign`] 36 /// 37 /// [`ECDSA_do_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_sign.html sign<T>(data: &[u8], eckey: &EcKeyRef<T>) -> Result<EcdsaSig, ErrorStack> where T: HasPrivate,38 pub fn sign<T>(data: &[u8], eckey: &EcKeyRef<T>) -> Result<EcdsaSig, ErrorStack> 39 where 40 T: HasPrivate, 41 { 42 unsafe { 43 assert!(data.len() <= c_int::max_value() as usize); 44 let sig = cvt_p(ffi::ECDSA_do_sign( 45 data.as_ptr(), 46 data.len() as c_int, 47 eckey.as_ptr(), 48 ))?; 49 Ok(EcdsaSig::from_ptr(sig)) 50 } 51 } 52 53 /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with a 54 /// ECDSA signature. 55 /// 56 /// OpenSSL documentation at [`ECDSA_SIG_set0`] 57 /// 58 /// [`ECDSA_SIG_set0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html from_private_components(r: BigNum, s: BigNum) -> Result<EcdsaSig, ErrorStack>59 pub fn from_private_components(r: BigNum, s: BigNum) -> Result<EcdsaSig, ErrorStack> { 60 unsafe { 61 let sig = cvt_p(ffi::ECDSA_SIG_new())?; 62 ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); 63 mem::forget((r, s)); 64 Ok(EcdsaSig::from_ptr(sig)) 65 } 66 } 67 68 from_der! { 69 /// Decodes a DER-encoded ECDSA signature. 70 /// 71 /// This corresponds to [`d2i_ECDSA_SIG`]. 72 /// 73 /// [`d2i_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_ECDSA_SIG.html 74 from_der, 75 EcdsaSig, 76 ffi::d2i_ECDSA_SIG 77 } 78 } 79 80 impl EcdsaSigRef { 81 to_der! { 82 /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. 83 /// 84 /// This corresponds to [`i2d_ECDSA_SIG`]. 85 /// 86 /// [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html 87 to_der, 88 ffi::i2d_ECDSA_SIG 89 } 90 91 /// Verifies if the signature is a valid ECDSA signature using the given public key. 92 /// 93 /// OpenSSL documentation at [`ECDSA_do_verify`] 94 /// 95 /// [`ECDSA_do_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_verify.html verify<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack> where T: HasPublic,96 pub fn verify<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack> 97 where 98 T: HasPublic, 99 { 100 unsafe { 101 assert!(data.len() <= c_int::max_value() as usize); 102 cvt_n(ffi::ECDSA_do_verify( 103 data.as_ptr(), 104 data.len() as c_int, 105 self.as_ptr(), 106 eckey.as_ptr(), 107 )) 108 .map(|x| x == 1) 109 } 110 } 111 112 /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) 113 /// 114 /// OpenSSL documentation at [`ECDSA_SIG_get0`] 115 /// 116 /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html r(&self) -> &BigNumRef117 pub fn r(&self) -> &BigNumRef { 118 unsafe { 119 let mut r = ptr::null(); 120 ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); 121 BigNumRef::from_const_ptr(r) 122 } 123 } 124 125 /// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) 126 /// 127 /// OpenSSL documentation at [`ECDSA_SIG_get0`] 128 /// 129 /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html s(&self) -> &BigNumRef130 pub fn s(&self) -> &BigNumRef { 131 unsafe { 132 let mut s = ptr::null(); 133 ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); 134 BigNumRef::from_const_ptr(s) 135 } 136 } 137 } 138 139 cfg_if! { 140 if #[cfg(any(ossl110, libressl273))] { 141 use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; 142 } else { 143 #[allow(bad_style)] 144 unsafe fn ECDSA_SIG_set0( 145 sig: *mut ffi::ECDSA_SIG, 146 r: *mut ffi::BIGNUM, 147 s: *mut ffi::BIGNUM, 148 ) -> c_int { 149 if r.is_null() || s.is_null() { 150 return 0; 151 } 152 ffi::BN_clear_free((*sig).r); 153 ffi::BN_clear_free((*sig).s); 154 (*sig).r = r; 155 (*sig).s = s; 156 1 157 } 158 159 #[allow(bad_style)] 160 unsafe fn ECDSA_SIG_get0( 161 sig: *const ffi::ECDSA_SIG, 162 pr: *mut *const ffi::BIGNUM, 163 ps: *mut *const ffi::BIGNUM) 164 { 165 if !pr.is_null() { 166 (*pr) = (*sig).r; 167 } 168 if !ps.is_null() { 169 (*ps) = (*sig).s; 170 } 171 } 172 } 173 } 174 175 #[cfg(test)] 176 mod test { 177 use super::*; 178 use crate::ec::EcGroup; 179 use crate::ec::EcKey; 180 use crate::nid::Nid; 181 use crate::pkey::{Private, Public}; 182 get_public_key(group: &EcGroup, x: &EcKey<Private>) -> Result<EcKey<Public>, ErrorStack>183 fn get_public_key(group: &EcGroup, x: &EcKey<Private>) -> Result<EcKey<Public>, ErrorStack> { 184 EcKey::from_public_key(group, x.public_key()) 185 } 186 187 #[test] 188 #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] sign_and_verify()189 fn sign_and_verify() { 190 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); 191 let private_key = EcKey::generate(&group).unwrap(); 192 let public_key = get_public_key(&group, &private_key).unwrap(); 193 194 let private_key2 = EcKey::generate(&group).unwrap(); 195 let public_key2 = get_public_key(&group, &private_key2).unwrap(); 196 197 let data = String::from("hello"); 198 let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); 199 200 // Signature can be verified using the correct data & correct public key 201 let verification = res.verify(data.as_bytes(), &public_key).unwrap(); 202 assert!(verification); 203 204 // Signature will not be verified using the incorrect data but the correct public key 205 let verification2 = res 206 .verify(String::from("hello2").as_bytes(), &public_key) 207 .unwrap(); 208 assert!(!verification2); 209 210 // Signature will not be verified using the correct data but the incorrect public key 211 let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap(); 212 assert!(!verification3); 213 } 214 215 #[test] 216 #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] check_private_components()217 fn check_private_components() { 218 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); 219 let private_key = EcKey::generate(&group).unwrap(); 220 let public_key = get_public_key(&group, &private_key).unwrap(); 221 let data = String::from("hello"); 222 let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); 223 224 let verification = res.verify(data.as_bytes(), &public_key).unwrap(); 225 assert!(verification); 226 227 let r = res.r().to_owned().unwrap(); 228 let s = res.s().to_owned().unwrap(); 229 230 let res2 = EcdsaSig::from_private_components(r, s).unwrap(); 231 let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap(); 232 assert!(verification2); 233 } 234 235 #[test] 236 #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] serialize_deserialize()237 fn serialize_deserialize() { 238 let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); 239 let private_key = EcKey::generate(&group).unwrap(); 240 let public_key = get_public_key(&group, &private_key).unwrap(); 241 242 let data = String::from("hello"); 243 let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); 244 245 let der = res.to_der().unwrap(); 246 let sig = EcdsaSig::from_der(&der).unwrap(); 247 248 let verification = sig.verify(data.as_bytes(), &public_key).unwrap(); 249 assert!(verification); 250 } 251 } 252