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