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