xref: /aosp_15_r20/external/boringssl/src/rust/bssl-crypto/src/ecdsa.rs (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
1 /* Copyright (c) 2024, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14  */
15 
16 //! Elliptic Curve Digital Signature Algorithm.
17 //!
18 //! The module implements ECDSA for the NIST curves P-256 and P-384.
19 //!
20 //! ```
21 //! use bssl_crypto::{ecdsa, ec::P256};
22 //!
23 //! let key = ecdsa::PrivateKey::<P256>::generate();
24 //! // Publish your public key.
25 //! let public_key_bytes = key.to_der_subject_public_key_info();
26 //!
27 //! // Sign and publish some message.
28 //! let signed_message = b"hello world";
29 //! let mut sig = key.sign(signed_message);
30 //!
31 //! // Anyone with the public key can verify it.
32 //! let public_key = ecdsa::PublicKey::<P256>::from_der_subject_public_key_info(
33 //!     public_key_bytes.as_ref()).unwrap();
34 //! assert!(public_key.verify(signed_message, sig.as_slice()).is_ok());
35 //! ```
36 
37 use crate::{ec, sealed, with_output_vec, Buffer, FfiSlice, InvalidSignatureError};
38 use alloc::vec::Vec;
39 use core::marker::PhantomData;
40 
41 /// An ECDSA public key over the given curve.
42 pub struct PublicKey<C: ec::Curve> {
43     point: ec::Point,
44     marker: PhantomData<C>,
45 }
46 
47 impl<C: ec::Curve> PublicKey<C> {
48     /// Parse a public key in uncompressed X9.62 format. (This is the common
49     /// format for elliptic curve points beginning with an 0x04 byte.)
from_x962_uncompressed(x962: &[u8]) -> Option<Self>50     pub fn from_x962_uncompressed(x962: &[u8]) -> Option<Self> {
51         let point = ec::Point::from_x962_uncompressed(C::group(sealed::Sealed), x962)?;
52         Some(Self {
53             point,
54             marker: PhantomData,
55         })
56     }
57 
58     /// Serialize this key as uncompressed X9.62 format.
to_x962_uncompressed(&self) -> Buffer59     pub fn to_x962_uncompressed(&self) -> Buffer {
60         self.point.to_x962_uncompressed()
61     }
62 
63     /// Parse a public key in SubjectPublicKeyInfo format.
64     /// (This is found in, e.g., X.509 certificates.)
from_der_subject_public_key_info(spki: &[u8]) -> Option<Self>65     pub fn from_der_subject_public_key_info(spki: &[u8]) -> Option<Self> {
66         let point = ec::Point::from_der_subject_public_key_info(C::group(sealed::Sealed), spki)?;
67         Some(Self {
68             point,
69             marker: PhantomData,
70         })
71     }
72 
73     /// Serialize this key in SubjectPublicKeyInfo format.
to_der_subject_public_key_info(&self) -> Buffer74     pub fn to_der_subject_public_key_info(&self) -> Buffer {
75         self.point.to_der_subject_public_key_info()
76     }
77 
78     /// Verify `signature` as a valid signature of a digest of `signed_msg`
79     /// with this public key. SHA-256 will be used to produce the digest if the
80     /// curve of this public key is P-256. SHA-384 will be used to produce the
81     /// digest if the curve of this public key is P-384.
verify(&self, signed_msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignatureError>82     pub fn verify(&self, signed_msg: &[u8], signature: &[u8]) -> Result<(), InvalidSignatureError> {
83         let digest = C::hash(signed_msg);
84         let result = self.point.with_point_as_ec_key(|ec_key| unsafe {
85             // Safety: `ec_key` is valid per `with_point_as_ec_key`.
86             bssl_sys::ECDSA_verify(
87                 /*type=*/ 0,
88                 digest.as_slice().as_ffi_ptr(),
89                 digest.len(),
90                 signature.as_ffi_ptr(),
91                 signature.len(),
92                 ec_key,
93             )
94         });
95         if result == 1 {
96             Ok(())
97         } else {
98             Err(InvalidSignatureError)
99         }
100     }
101 }
102 
103 /// An ECDH private key over the given curve.
104 pub struct PrivateKey<C: ec::Curve> {
105     key: ec::Key,
106     marker: PhantomData<C>,
107 }
108 
109 impl<C: ec::Curve> PrivateKey<C> {
110     /// Generate a random private key.
generate() -> Self111     pub fn generate() -> Self {
112         Self {
113             key: ec::Key::generate(C::group(sealed::Sealed)),
114             marker: PhantomData,
115         }
116     }
117 
118     /// Parse a `PrivateKey` from a zero-padded, big-endian representation of the secret scalar.
from_big_endian(scalar: &[u8]) -> Option<Self>119     pub fn from_big_endian(scalar: &[u8]) -> Option<Self> {
120         let key = ec::Key::from_big_endian(C::group(sealed::Sealed), scalar)?;
121         Some(Self {
122             key,
123             marker: PhantomData,
124         })
125     }
126 
127     /// Return the private key as zero-padded, big-endian bytes.
to_big_endian(&self) -> Buffer128     pub fn to_big_endian(&self) -> Buffer {
129         self.key.to_big_endian()
130     }
131 
132     /// Parse an ECPrivateKey structure (from RFC 5915). The key must be on the
133     /// specified curve.
from_der_ec_private_key(der: &[u8]) -> Option<Self>134     pub fn from_der_ec_private_key(der: &[u8]) -> Option<Self> {
135         let key = ec::Key::from_der_ec_private_key(C::group(sealed::Sealed), der)?;
136         Some(Self {
137             key,
138             marker: PhantomData,
139         })
140     }
141 
142     /// Serialize this private key as an ECPrivateKey structure (from RFC 5915).
to_der_ec_private_key(&self) -> Buffer143     pub fn to_der_ec_private_key(&self) -> Buffer {
144         self.key.to_der_ec_private_key()
145     }
146 
147     /// Parse a PrivateKeyInfo structure (from RFC 5208), commonly called
148     /// "PKCS#8 format". The key must be on the specified curve.
from_der_private_key_info(der: &[u8]) -> Option<Self>149     pub fn from_der_private_key_info(der: &[u8]) -> Option<Self> {
150         let key = ec::Key::from_der_private_key_info(C::group(sealed::Sealed), der)?;
151         Some(Self {
152             key,
153             marker: PhantomData,
154         })
155     }
156 
157     /// Serialize this private key as a PrivateKeyInfo structure (from RFC 5208),
158     /// commonly called "PKCS#8 format".
to_der_private_key_info(&self) -> Buffer159     pub fn to_der_private_key_info(&self) -> Buffer {
160         self.key.to_der_private_key_info()
161     }
162 
163     /// Serialize the _public_ part of this key in uncompressed X9.62 format.
to_x962_uncompressed(&self) -> Buffer164     pub fn to_x962_uncompressed(&self) -> Buffer {
165         self.key.to_x962_uncompressed()
166     }
167 
168     /// Serialize this key in SubjectPublicKeyInfo format.
to_der_subject_public_key_info(&self) -> Buffer169     pub fn to_der_subject_public_key_info(&self) -> Buffer {
170         self.key.to_der_subject_public_key_info()
171     }
172 
173     /// Return the public key corresponding to this private key.
to_public_key(&self) -> PublicKey<C>174     pub fn to_public_key(&self) -> PublicKey<C> {
175         PublicKey {
176             point: self.key.to_point(),
177             marker: PhantomData,
178         }
179     }
180 
181     /// Sign a digest of `to_be_signed` using this key and return the signature.
182     /// SHA-256 will be used to produce the digest if the curve of this public
183     /// key is P-256. SHA-384 will be used to produce the digest if the curve
184     /// of this public key is P-384.
sign(&self, to_be_signed: &[u8]) -> Vec<u8>185     pub fn sign(&self, to_be_signed: &[u8]) -> Vec<u8> {
186         // Safety: `self.key` is valid by construction.
187         let max_size = unsafe { bssl_sys::ECDSA_size(self.key.as_ffi_ptr()) };
188         // No curve can be empty.
189         assert_ne!(max_size, 0);
190 
191         let digest = C::hash(to_be_signed);
192 
193         unsafe {
194             with_output_vec(max_size, |out_buf| {
195                 let mut out_len: core::ffi::c_uint = 0;
196                 // Safety: `out_buf` points to at least `max_size` bytes,
197                 // as required.
198                 let result = {
199                     bssl_sys::ECDSA_sign(
200                         /*type=*/ 0,
201                         digest.as_slice().as_ffi_ptr(),
202                         digest.len(),
203                         out_buf,
204                         &mut out_len,
205                         self.key.as_ffi_ptr(),
206                     )
207                 };
208                 // Signing should never fail unless we're out of memory,
209                 // which this crate doesn't handle.
210                 assert_eq!(result, 1);
211                 let out_len = out_len as usize;
212                 assert!(out_len <= max_size);
213                 // Safety: `out_len` bytes have been written.
214                 out_len
215             })
216         }
217     }
218 }
219 
220 #[cfg(test)]
221 mod test {
222     use super::*;
223     use crate::ec::{P256, P384};
224 
check_curve<C: ec::Curve>()225     fn check_curve<C: ec::Curve>() {
226         let signed_message = b"hello world";
227         let key = PrivateKey::<C>::generate();
228         let mut sig = key.sign(signed_message);
229 
230         let public_key = PublicKey::<C>::from_der_subject_public_key_info(
231             key.to_der_subject_public_key_info().as_ref(),
232         )
233         .unwrap();
234         assert!(public_key.verify(signed_message, sig.as_slice()).is_ok());
235 
236         sig[10] ^= 1;
237         assert!(public_key.verify(signed_message, sig.as_slice()).is_err());
238     }
239 
240     #[test]
p256()241     fn p256() {
242         check_curve::<P256>();
243     }
244 
245     #[test]
p384()246     fn p384() {
247         check_curve::<P384>();
248     }
249 }
250