Skip to main content

variant_ssl/
ecdsa.rs

1//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions.
2
3use foreign_types::{ForeignType, ForeignTypeRef};
4use libc::c_int;
5use std::fmt;
6use std::mem;
7use std::ptr;
8
9use crate::bn::{BigNum, BigNumRef};
10use crate::ec::EcKeyRef;
11use crate::error::ErrorStack;
12use crate::pkey::{HasPrivate, HasPublic};
13use crate::util::ForeignTypeRefExt;
14use crate::{cvt_n, cvt_p, LenType};
15use openssl_macros::corresponds;
16
17foreign_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
27impl 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 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
65impl fmt::Debug for EcdsaSig {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        f.debug_struct("EcdsaSig")
68            .field("r", &self.r())
69            .field("s", &self.s())
70            .finish()
71    }
72}
73
74impl EcdsaSigRef {
75    to_der! {
76        /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure.
77        #[corresponds(i2d_ECDSA_SIG)]
78        to_der,
79        ffi::i2d_ECDSA_SIG
80    }
81
82    /// Verifies if the signature is a valid ECDSA signature using the given public key.
83    #[corresponds(ECDSA_do_verify)]
84    pub fn verify<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack>
85    where
86        T: HasPublic,
87    {
88        unsafe {
89            assert!(data.len() <= c_int::MAX as usize);
90            cvt_n(ffi::ECDSA_do_verify(
91                data.as_ptr(),
92                data.len() as LenType,
93                self.as_ptr(),
94                eckey.as_ptr(),
95            ))
96            .map(|x| x == 1)
97        }
98    }
99
100    /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2)
101    #[corresponds(ECDSA_SIG_get0)]
102    pub fn r(&self) -> &BigNumRef {
103        unsafe {
104            let mut r = ptr::null();
105            ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut());
106            BigNumRef::from_const_ptr(r)
107        }
108    }
109
110    /// Returns internal components: `s` of an `EcdsaSig`. (See X9.62 or FIPS 186-2)
111    #[corresponds(ECDSA_SIG_get0)]
112    pub fn s(&self) -> &BigNumRef {
113        unsafe {
114            let mut s = ptr::null();
115            ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s);
116            BigNumRef::from_const_ptr(s)
117        }
118    }
119}
120
121impl fmt::Debug for EcdsaSigRef {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        f.debug_struct("EcdsaSig")
124            .field("r", &self.r())
125            .field("s", &self.s())
126            .finish()
127    }
128}
129
130use ffi::{ECDSA_SIG_get0, ECDSA_SIG_set0};
131
132#[cfg(test)]
133mod test {
134    use super::*;
135    use crate::ec::EcGroup;
136    use crate::ec::EcKey;
137    use crate::nid::Nid;
138    use crate::pkey::{Private, Public};
139
140    fn get_public_key(group: &EcGroup, x: &EcKey<Private>) -> Result<EcKey<Public>, ErrorStack> {
141        EcKey::from_public_key(group, x.public_key())
142    }
143
144    #[test]
145    #[cfg_attr(osslconf = "OPENSSL_NO_EC", ignore)]
146    fn sign_and_verify() {
147        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
148        let private_key = EcKey::generate(&group).unwrap();
149        let public_key = get_public_key(&group, &private_key).unwrap();
150
151        let private_key2 = EcKey::generate(&group).unwrap();
152        let public_key2 = get_public_key(&group, &private_key2).unwrap();
153
154        let data = String::from("hello");
155        let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
156
157        // Signature can be verified using the correct data & correct public key
158        let verification = res.verify(data.as_bytes(), &public_key).unwrap();
159        assert!(verification);
160
161        // Signature will not be verified using the incorrect data but the correct public key
162        let verification2 = res
163            .verify(String::from("hello2").as_bytes(), &public_key)
164            .unwrap();
165        assert!(!verification2);
166
167        // Signature will not be verified using the correct data but the incorrect public key
168        let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap();
169        assert!(!verification3);
170    }
171
172    #[test]
173    #[cfg_attr(osslconf = "OPENSSL_NO_EC", ignore)]
174    fn check_private_components() {
175        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
176        let private_key = EcKey::generate(&group).unwrap();
177        let public_key = get_public_key(&group, &private_key).unwrap();
178        let data = String::from("hello");
179        let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
180
181        let verification = res.verify(data.as_bytes(), &public_key).unwrap();
182        assert!(verification);
183
184        let r = res.r().to_owned().unwrap();
185        let s = res.s().to_owned().unwrap();
186
187        let res2 = EcdsaSig::from_private_components(r, s).unwrap();
188        let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap();
189        assert!(verification2);
190    }
191
192    #[test]
193    #[cfg_attr(osslconf = "OPENSSL_NO_EC", ignore)]
194    fn serialize_deserialize() {
195        let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
196        let private_key = EcKey::generate(&group).unwrap();
197        let public_key = get_public_key(&group, &private_key).unwrap();
198
199        let data = String::from("hello");
200        let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
201
202        let der = res.to_der().unwrap();
203        let sig = EcdsaSig::from_der(&der).unwrap();
204
205        let verification = sig.verify(data.as_bytes(), &public_key).unwrap();
206        assert!(verification);
207    }
208}