/rust/registry/src/index.crates.io-6f17d22bba15001f/openssl-0.10.62/src/ecdsa.rs
Line | Count | Source (jump to first uncovered line) |
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 | 0 | pub fn sign<T>(data: &[u8], eckey: &EcKeyRef<T>) -> Result<EcdsaSig, ErrorStack> |
31 | 0 | where |
32 | 0 | T: HasPrivate, |
33 | 0 | { |
34 | 0 | unsafe { |
35 | 0 | assert!(data.len() <= c_int::max_value() as usize); |
36 | 0 | let sig = cvt_p(ffi::ECDSA_do_sign( |
37 | 0 | data.as_ptr(), |
38 | 0 | data.len() as LenType, |
39 | 0 | eckey.as_ptr(), |
40 | 0 | ))?; |
41 | 0 | Ok(EcdsaSig::from_ptr(sig)) |
42 | | } |
43 | 0 | } |
44 | | |
45 | | /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with an ECDSA signature. |
46 | | #[corresponds(ECDSA_SIG_set0)] |
47 | 0 | pub fn from_private_components(r: BigNum, s: BigNum) -> Result<EcdsaSig, ErrorStack> { |
48 | | unsafe { |
49 | 0 | let sig = cvt_p(ffi::ECDSA_SIG_new())?; |
50 | 0 | ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); |
51 | 0 | mem::forget((r, s)); |
52 | 0 | Ok(EcdsaSig::from_ptr(sig)) |
53 | | } |
54 | 0 | } |
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 | 0 | pub fn verify<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack> |
76 | 0 | where |
77 | 0 | T: HasPublic, |
78 | 0 | { |
79 | 0 | unsafe { |
80 | 0 | assert!(data.len() <= c_int::max_value() as usize); |
81 | 0 | cvt_n(ffi::ECDSA_do_verify( |
82 | 0 | data.as_ptr(), |
83 | 0 | data.len() as LenType, |
84 | 0 | self.as_ptr(), |
85 | 0 | eckey.as_ptr(), |
86 | 0 | )) |
87 | 0 | .map(|x| x == 1) |
88 | 0 | } |
89 | 0 | } |
90 | | |
91 | | /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) |
92 | | #[corresponds(ECDSA_SIG_get0)] |
93 | 0 | pub fn r(&self) -> &BigNumRef { |
94 | 0 | unsafe { |
95 | 0 | let mut r = ptr::null(); |
96 | 0 | ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); |
97 | 0 | BigNumRef::from_const_ptr(r) |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | | /// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) |
102 | | #[corresponds(ECDSA_SIG_get0)] |
103 | 0 | pub fn s(&self) -> &BigNumRef { |
104 | 0 | unsafe { |
105 | 0 | let mut s = ptr::null(); |
106 | 0 | ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); |
107 | 0 | BigNumRef::from_const_ptr(s) |
108 | 0 | } |
109 | 0 | } |
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 | | } |