ring_native_ossl/
agreement.rs1use crate::error::Unspecified;
10use native_ossl::params::ParamBuilder;
11use native_ossl::pkey::{DeriveCtx, KeygenCtx, Pkey, Private, Public};
12use std::ffi::CStr;
13
14use crate::spki::{P256_SPKI_HEADER, P384_SPKI_HEADER, X25519_SPKI_HEADER};
15
16#[derive(Debug)]
20pub struct Algorithm {
21 keygen_name: &'static CStr,
22 group_param: Option<&'static CStr>,
23 spki_header: &'static [u8],
24 raw_key_len: usize,
25}
26
27pub static X25519: Algorithm = Algorithm {
28 keygen_name: c"X25519",
29 group_param: None,
30 spki_header: X25519_SPKI_HEADER,
31 raw_key_len: 32,
32};
33
34pub static ECDH_P256: Algorithm = Algorithm {
35 keygen_name: c"EC",
36 group_param: Some(c"P-256"),
37 spki_header: P256_SPKI_HEADER,
38 raw_key_len: 65,
39};
40
41pub static ECDH_P384: Algorithm = Algorithm {
42 keygen_name: c"EC",
43 group_param: Some(c"P-384"),
44 spki_header: P384_SPKI_HEADER,
45 raw_key_len: 97,
46};
47
48pub struct EphemeralPrivateKey {
52 alg: &'static Algorithm,
53 priv_key: Pkey<Private>,
54 pub_key_bytes: Vec<u8>,
55}
56
57impl EphemeralPrivateKey {
58 pub fn generate(
64 alg: &'static Algorithm,
65 _rng: &dyn crate::rand::SecureRandom,
66 ) -> Result<Self, Unspecified> {
67 let mut ctx = KeygenCtx::new(alg.keygen_name).map_err(|_| Unspecified)?;
68
69 if let Some(group_name) = alg.group_param {
70 let params = ParamBuilder::new()
71 .and_then(|b| b.push_utf8_string(c"group", group_name))
72 .and_then(ParamBuilder::build)
73 .map_err(|_| Unspecified)?;
74 ctx.set_params(¶ms).map_err(|_| Unspecified)?;
75 }
76
77 let priv_key = ctx.generate().map_err(|_| Unspecified)?;
78
79 let spki = priv_key.public_key_to_der().map_err(|_| Unspecified)?;
80 let raw_pub = spki
81 .get(alg.spki_header.len()..)
82 .ok_or(Unspecified)?
83 .to_vec();
84
85 Ok(Self {
86 alg,
87 priv_key,
88 pub_key_bytes: raw_pub,
89 })
90 }
91
92 pub fn compute_public_key(&self) -> Result<PublicKey, Unspecified> {
98 Ok(PublicKey {
99 alg: self.alg,
100 bytes: self.pub_key_bytes.clone(),
101 })
102 }
103
104 #[must_use]
105 pub fn algorithm(&self) -> &'static Algorithm {
106 self.alg
107 }
108}
109
110impl std::fmt::Debug for EphemeralPrivateKey {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 f.debug_struct("EphemeralPrivateKey")
113 .field("alg", &self.alg)
114 .finish_non_exhaustive()
115 }
116}
117
118#[derive(Debug)]
122pub struct PublicKey {
123 alg: &'static Algorithm,
124 bytes: Vec<u8>,
125}
126
127impl PublicKey {
128 #[must_use]
129 pub fn algorithm(&self) -> &'static Algorithm {
130 self.alg
131 }
132}
133
134impl AsRef<[u8]> for PublicKey {
135 fn as_ref(&self) -> &[u8] {
136 &self.bytes
137 }
138}
139
140#[derive(Debug)]
144pub struct UnparsedPublicKey<B> {
145 alg: &'static Algorithm,
146 bytes: B,
147}
148
149impl<B: AsRef<[u8]>> UnparsedPublicKey<B> {
150 pub fn new(algorithm: &'static Algorithm, bytes: B) -> Self {
151 Self {
152 alg: algorithm,
153 bytes,
154 }
155 }
156
157 pub fn algorithm(&self) -> &'static Algorithm {
158 self.alg
159 }
160}
161
162impl<B: AsRef<[u8]>> AsRef<[u8]> for UnparsedPublicKey<B> {
163 fn as_ref(&self) -> &[u8] {
164 self.bytes.as_ref()
165 }
166}
167
168#[allow(clippy::needless_pass_by_value)]
180pub fn agree_ephemeral<B, F, R, E>(
181 my_private_key: EphemeralPrivateKey,
182 peer_public_key: &UnparsedPublicKey<B>,
183 error_value: E,
184 kdf: F,
185) -> Result<R, E>
186where
187 B: AsRef<[u8]>,
188 F: FnOnce(&[u8]) -> Result<R, E>,
189{
190 match do_ecdh(
191 &my_private_key.priv_key,
192 my_private_key.alg,
193 peer_public_key,
194 ) {
195 Ok(secret) => kdf(&secret),
196 Err(()) => Err(error_value),
197 }
198}
199
200fn do_ecdh<B>(
201 priv_key: &Pkey<Private>,
202 alg: &'static Algorithm,
203 peer_public_key: &UnparsedPublicKey<B>,
204) -> Result<Vec<u8>, ()>
205where
206 B: AsRef<[u8]>,
207{
208 let peer_bytes = peer_public_key.bytes.as_ref();
209 if peer_bytes.len() != alg.raw_key_len {
210 return Err(());
211 }
212 if alg.group_param.is_some() && peer_bytes.first() != Some(&0x04) {
214 return Err(());
215 }
216
217 let mut spki = alg.spki_header.to_vec();
218 spki.extend_from_slice(peer_bytes);
219
220 let peer_key = Pkey::<Public>::from_der(&spki).map_err(|_| ())?;
221
222 let mut derive = DeriveCtx::new(priv_key).map_err(|_| ())?;
223 derive.set_peer(&peer_key).map_err(|_| ())?;
224
225 let len = derive.derive_len().map_err(|_| ())?;
226 let mut secret = vec![0u8; len];
227 derive.derive(&mut secret).map_err(|_| ())?;
228 Ok(secret)
229}