1 // Copyright 2015-2017 Brian Smith.
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 AUTHORS DISCLAIM ALL WARRANTIES
8 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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 //! Key Agreement: ECDH, including X25519.
16 //!
17 //! # Example
18 //!
19 //! Note that this example uses X25519, but ECDH using NIST P-256/P-384 is done
20 //! exactly the same way, just substituting
21 //! `agreement::ECDH_P256`/`agreement::ECDH_P384` for `agreement::X25519`.
22 //!
23 //! ```
24 //! use ring::{agreement, rand};
25 //!
26 //! let rng = rand::SystemRandom::new();
27 //!
28 //! let my_private_key = agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?;
29 //!
30 //! // Make `my_public_key` a byte slice containing my public key. In a real
31 //! // application, this would be sent to the peer in an encoded protocol
32 //! // message.
33 //! let my_public_key = my_private_key.compute_public_key()?;
34 //!
35 //! let peer_public_key = {
36 //!     // In a real application, the peer public key would be parsed out of a
37 //!     // protocol message. Here we just generate one.
38 //!     let peer_public_key = {
39 //!         let peer_private_key =
40 //!             agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng)?;
41 //!         peer_private_key.compute_public_key()?
42 //!     };
43 //!
44 //!     agreement::UnparsedPublicKey::new(&agreement::X25519, peer_public_key)
45 //! };
46 //!
47 //! agreement::agree_ephemeral(
48 //!     my_private_key,
49 //!     &peer_public_key,
50 //!     ring::error::Unspecified,
51 //!     |_key_material| {
52 //!         // In a real application, we'd apply a KDF to the key material and the
53 //!         // public keys (as recommended in RFC 7748) and then derive session
54 //!         // keys from the result. We omit all that here.
55 //!         Ok(())
56 //!     },
57 //! )?;
58 //!
59 //! # Ok::<(), ring::error::Unspecified>(())
60 //! ```
61 
62 // The "NSA Guide" steps here are from from section 3.1, "Ephemeral Unified
63 // Model."
64 
65 use crate::{cpu, debug, ec, error, rand};
66 
67 pub use crate::ec::{
68     curve25519::x25519::X25519,
69     suite_b::ecdh::{ECDH_P256, ECDH_P384},
70 };
71 
72 /// A key agreement algorithm.
73 pub struct Algorithm {
74     pub(crate) curve: &'static ec::Curve,
75     pub(crate) ecdh: fn(
76         out: &mut [u8],
77         private_key: &ec::Seed,
78         peer_public_key: untrusted::Input,
79     ) -> Result<(), error::Unspecified>,
80 }
81 
82 derive_debug_via_field!(Algorithm, curve);
83 
84 impl Eq for Algorithm {}
85 impl PartialEq for Algorithm {
eq(&self, other: &Algorithm) -> bool86     fn eq(&self, other: &Algorithm) -> bool {
87         self.curve.id == other.curve.id
88     }
89 }
90 
91 /// An ephemeral private key for use (only) with `agree_ephemeral`. The
92 /// signature of `agree_ephemeral` ensures that an `EphemeralPrivateKey` can be
93 /// used for at most one key agreement.
94 pub struct EphemeralPrivateKey {
95     private_key: ec::Seed,
96     algorithm: &'static Algorithm,
97 }
98 
99 derive_debug_via_field!(
100     EphemeralPrivateKey,
101     stringify!(EphemeralPrivateKey),
102     algorithm
103 );
104 
105 impl EphemeralPrivateKey {
106     /// Generate a new ephemeral private key for the given algorithm.
generate( alg: &'static Algorithm, rng: &dyn rand::SecureRandom, ) -> Result<Self, error::Unspecified>107     pub fn generate(
108         alg: &'static Algorithm,
109         rng: &dyn rand::SecureRandom,
110     ) -> Result<Self, error::Unspecified> {
111         let cpu_features = cpu::features();
112 
113         // NSA Guide Step 1.
114         //
115         // This only handles the key generation part of step 1. The rest of
116         // step one is done by `compute_public_key()`.
117         let private_key = ec::Seed::generate(&alg.curve, rng, cpu_features)?;
118         Ok(Self {
119             private_key,
120             algorithm: alg,
121         })
122     }
123 
124     /// Computes the public key from the private key.
125     #[inline(always)]
compute_public_key(&self) -> Result<PublicKey, error::Unspecified>126     pub fn compute_public_key(&self) -> Result<PublicKey, error::Unspecified> {
127         // NSA Guide Step 1.
128         //
129         // Obviously, this only handles the part of Step 1 between the private
130         // key generation and the sending of the public key to the peer. `out`
131         // is what should be sent to the peer.
132         self.private_key
133             .compute_public_key()
134             .map(|public_key| PublicKey {
135                 algorithm: self.algorithm,
136                 bytes: public_key,
137             })
138     }
139 
140     /// The algorithm for the private key.
141     #[inline]
algorithm(&self) -> &'static Algorithm142     pub fn algorithm(&self) -> &'static Algorithm {
143         self.algorithm
144     }
145 
146     #[cfg(test)]
bytes(&self) -> &[u8]147     pub fn bytes(&self) -> &[u8] {
148         self.private_key.bytes_less_safe()
149     }
150 }
151 
152 /// A public key for key agreement.
153 #[derive(Clone)]
154 pub struct PublicKey {
155     algorithm: &'static Algorithm,
156     bytes: ec::PublicKey,
157 }
158 
159 impl AsRef<[u8]> for PublicKey {
as_ref(&self) -> &[u8]160     fn as_ref(&self) -> &[u8] {
161         self.bytes.as_ref()
162     }
163 }
164 
165 impl core::fmt::Debug for PublicKey {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>166     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
167         f.debug_struct("PublicKey")
168             .field("algorithm", &self.algorithm)
169             .field("bytes", &debug::HexStr(self.as_ref()))
170             .finish()
171     }
172 }
173 
174 impl PublicKey {
175     /// The algorithm for the public key.
176     #[inline]
algorithm(&self) -> &'static Algorithm177     pub fn algorithm(&self) -> &'static Algorithm {
178         self.algorithm
179     }
180 }
181 
182 /// An unparsed, possibly malformed, public key for key agreement.
183 pub struct UnparsedPublicKey<B: AsRef<[u8]>> {
184     algorithm: &'static Algorithm,
185     bytes: B,
186 }
187 
188 impl<B: Copy> Copy for UnparsedPublicKey<B> where B: AsRef<[u8]> {}
189 
190 impl<B: Clone> Clone for UnparsedPublicKey<B>
191 where
192     B: AsRef<[u8]>,
193 {
clone(&self) -> Self194     fn clone(&self) -> Self {
195         Self {
196             algorithm: self.algorithm,
197             bytes: self.bytes.clone(),
198         }
199     }
200 }
201 
202 impl<B: core::fmt::Debug> core::fmt::Debug for UnparsedPublicKey<B>
203 where
204     B: AsRef<[u8]>,
205 {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>206     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
207         f.debug_struct("UnparsedPublicKey")
208             .field("algorithm", &self.algorithm)
209             .field("bytes", &debug::HexStr(self.bytes.as_ref()))
210             .finish()
211     }
212 }
213 
214 impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
215     /// Constructs a new `UnparsedPublicKey`.
new(algorithm: &'static Algorithm, bytes: B) -> Self216     pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self {
217         Self { algorithm, bytes }
218     }
219 
220     /// TODO: doc
221     #[inline]
algorithm(&self) -> &'static Algorithm222     pub fn algorithm(&self) -> &'static Algorithm {
223         self.algorithm
224     }
225 
226     /// TODO: doc
227     #[inline]
bytes(&self) -> &B228     pub fn bytes(&self) -> &B {
229         &self.bytes
230     }
231 }
232 
233 /// Performs a key agreement with an ephemeral private key and the given public
234 /// key.
235 ///
236 /// `my_private_key` is the ephemeral private key to use. Since it is moved, it
237 /// will not be usable after calling `agree_ephemeral`, thus guaranteeing that
238 /// the key is used for only one key agreement.
239 ///
240 /// `peer_public_key` is the peer's public key. `agree_ephemeral` will return
241 /// `Err(error_value)` if it does not match `my_private_key's` algorithm/curve.
242 /// `agree_ephemeral` verifies that it is encoded in the standard form for the
243 /// algorithm and that the key is *valid*; see the algorithm's documentation for
244 /// details on how keys are to be encoded and what constitutes a valid key for
245 /// that algorithm.
246 ///
247 /// `error_value` is the value to return if an error occurs before `kdf` is
248 /// called, e.g. when decoding of the peer's public key fails or when the public
249 /// key is otherwise invalid.
250 ///
251 /// After the key agreement is done, `agree_ephemeral` calls `kdf` with the raw
252 /// key material from the key agreement operation and then returns what `kdf`
253 /// returns.
254 #[inline]
agree_ephemeral<B: AsRef<[u8]>, F, R, E>( my_private_key: EphemeralPrivateKey, peer_public_key: &UnparsedPublicKey<B>, error_value: E, kdf: F, ) -> Result<R, E> where F: FnOnce(&[u8]) -> Result<R, E>,255 pub fn agree_ephemeral<B: AsRef<[u8]>, F, R, E>(
256     my_private_key: EphemeralPrivateKey,
257     peer_public_key: &UnparsedPublicKey<B>,
258     error_value: E,
259     kdf: F,
260 ) -> Result<R, E>
261 where
262     F: FnOnce(&[u8]) -> Result<R, E>,
263 {
264     let peer_public_key = UnparsedPublicKey {
265         algorithm: peer_public_key.algorithm,
266         bytes: peer_public_key.bytes.as_ref(),
267     };
268     agree_ephemeral_(my_private_key, peer_public_key, error_value, kdf)
269 }
270 
agree_ephemeral_<F, R, E>( my_private_key: EphemeralPrivateKey, peer_public_key: UnparsedPublicKey<&[u8]>, error_value: E, kdf: F, ) -> Result<R, E> where F: FnOnce(&[u8]) -> Result<R, E>,271 fn agree_ephemeral_<F, R, E>(
272     my_private_key: EphemeralPrivateKey,
273     peer_public_key: UnparsedPublicKey<&[u8]>,
274     error_value: E,
275     kdf: F,
276 ) -> Result<R, E>
277 where
278     F: FnOnce(&[u8]) -> Result<R, E>,
279 {
280     // NSA Guide Prerequisite 1.
281     //
282     // The domain parameters are hard-coded. This check verifies that the
283     // peer's public key's domain parameters match the domain parameters of
284     // this private key.
285     if peer_public_key.algorithm != my_private_key.algorithm {
286         return Err(error_value);
287     }
288 
289     let alg = &my_private_key.algorithm;
290 
291     // NSA Guide Prerequisite 2, regarding which KDFs are allowed, is delegated
292     // to the caller.
293 
294     // NSA Guide Prerequisite 3, "Prior to or during the key-agreement process,
295     // each party shall obtain the identifier associated with the other party
296     // during the key-agreement scheme," is delegated to the caller.
297 
298     // NSA Guide Step 1 is handled by `EphemeralPrivateKey::generate()` and
299     // `EphemeralPrivateKey::compute_public_key()`.
300 
301     let mut shared_key = [0u8; ec::ELEM_MAX_BYTES];
302     let shared_key = &mut shared_key[..alg.curve.elem_scalar_seed_len];
303 
304     // NSA Guide Steps 2, 3, and 4.
305     //
306     // We have a pretty liberal interpretation of the NIST's spec's "Destroy"
307     // that doesn't meet the NSA requirement to "zeroize."
308     (alg.ecdh)(
309         shared_key,
310         &my_private_key.private_key,
311         untrusted::Input::from(peer_public_key.bytes),
312     )
313     .map_err(|_| error_value)?;
314 
315     // NSA Guide Steps 5 and 6.
316     //
317     // Again, we have a pretty liberal interpretation of the NIST's spec's
318     // "Destroy" that doesn't meet the NSA requirement to "zeroize."
319     kdf(shared_key)
320 }
321