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)] |
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)] |
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)] |
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)] |
93 | 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)] |
103 | 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, boringssl))] { |
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 | |
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_EC" , ignore)] |
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_EC" , ignore)] |
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_EC" , ignore)] |
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 | |