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