Skip to content

Commit 5082f79

Browse files
committed
Split SslCredential into a module
1 parent 6124273 commit 5082f79

2 files changed

Lines changed: 213 additions & 186 deletions

File tree

boring/src/ssl/credential.rs

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
#[cfg(feature = "rpk")]
2+
use crate::cvt_p;
3+
use crate::error::ErrorStack;
4+
use crate::ex_data::Index;
5+
use crate::pkey::{PKeyRef, Private};
6+
use crate::ssl::callbacks;
7+
use crate::ssl::PrivateKeyMethod;
8+
use crate::{cvt_0i, cvt_n};
9+
use crate::{ffi, free_data_box};
10+
use foreign_types::{ForeignType, ForeignTypeRef};
11+
use openssl_macros::corresponds;
12+
use std::any::TypeId;
13+
use std::collections::HashMap;
14+
use std::ffi::{c_int, c_void};
15+
use std::mem;
16+
use std::ptr;
17+
use std::sync::{LazyLock, Mutex};
18+
19+
static SSL_CREDENTIAL_INDEXES: LazyLock<Mutex<HashMap<TypeId, c_int>>> =
20+
LazyLock::new(|| Mutex::new(HashMap::new()));
21+
22+
foreign_type_and_impl_send_sync! {
23+
type CType = ffi::SSL_CREDENTIAL;
24+
fn drop = ffi::SSL_CREDENTIAL_free;
25+
26+
/// A credential.
27+
pub struct SslCredential;
28+
}
29+
30+
impl SslCredential {
31+
/// Create a credential suitable for a handshake using a raw public key.
32+
#[corresponds(SSL_CREDENTIAL_new_raw_public_key)]
33+
#[cfg(feature = "rpk")]
34+
pub fn new_raw_public_key() -> Result<SslCredentialBuilder, ErrorStack> {
35+
unsafe {
36+
Ok(SslCredentialBuilder(Self::from_ptr(cvt_p(
37+
ffi::SSL_CREDENTIAL_new_raw_public_key(),
38+
)?)))
39+
}
40+
}
41+
42+
/// Returns a new extra data index.
43+
///
44+
/// Each invocation of this function is guaranteed to return a distinct index. These can be used
45+
/// to store data in the context that can be retrieved later by callbacks, for example.
46+
#[corresponds(SSL_C_get_ex_new_index)]
47+
pub fn new_ex_index<T>() -> Result<Index<Self, T>, ErrorStack>
48+
where
49+
T: 'static + Sync + Send,
50+
{
51+
unsafe {
52+
ffi::init();
53+
let idx = cvt_n(get_new_ssl_credential_idx(Some(free_data_box::<T>)))?;
54+
Ok(Index::from_raw(idx))
55+
}
56+
}
57+
58+
// FIXME should return a result?
59+
pub(crate) fn cached_ex_index<T>() -> Index<Self, T>
60+
where
61+
T: 'static + Sync + Send,
62+
{
63+
unsafe {
64+
let idx = *SSL_CREDENTIAL_INDEXES
65+
.lock()
66+
.unwrap_or_else(|e| e.into_inner())
67+
.entry(TypeId::of::<T>())
68+
.or_insert_with(|| Self::new_ex_index::<T>().unwrap().as_raw());
69+
Index::from_raw(idx)
70+
}
71+
}
72+
}
73+
74+
impl SslCredentialRef {
75+
/// Returns a reference to the extra data at the specified index.
76+
#[corresponds(SSL_CREDENTIAL_get_ex_data)]
77+
#[must_use]
78+
pub fn ex_data<T>(&self, index: Index<SslCredential, T>) -> Option<&T> {
79+
unsafe {
80+
let data = ffi::SSL_CREDENTIAL_get_ex_data(self.as_ptr(), index.as_raw());
81+
if data.is_null() {
82+
None
83+
} else {
84+
Some(&*(data as *const T))
85+
}
86+
}
87+
}
88+
89+
// Unsafe because SSL contexts are not guaranteed to be unique, we call
90+
// this only from SslCredentialBuilder.
91+
#[corresponds(SSL_CREDENTIAL_get_ex_data)]
92+
pub(crate) unsafe fn ex_data_mut<T>(
93+
&mut self,
94+
index: Index<SslCredential, T>,
95+
) -> Option<&mut T> {
96+
let data = ffi::SSL_CREDENTIAL_get_ex_data(self.as_ptr(), index.as_raw());
97+
if data.is_null() {
98+
None
99+
} else {
100+
Some(&mut *(data as *mut T))
101+
}
102+
}
103+
104+
// Unsafe because SSL contexts are not guaranteed to be unique, we call
105+
// this only from SslCredentialBuilder.
106+
#[corresponds(SSL_CREDENTIAL_set_ex_data)]
107+
pub(crate) unsafe fn replace_ex_data<T>(
108+
&mut self,
109+
index: Index<SslCredential, T>,
110+
data: T,
111+
) -> Option<T> {
112+
if let Some(old) = self.ex_data_mut(index) {
113+
return Some(mem::replace(old, data));
114+
}
115+
116+
unsafe {
117+
let data = Box::into_raw(Box::new(data)) as *mut c_void;
118+
ffi::SSL_CREDENTIAL_set_ex_data(self.as_ptr(), index.as_raw(), data);
119+
}
120+
121+
None
122+
}
123+
}
124+
125+
/// A builder for [`SslCredential`]
126+
pub struct SslCredentialBuilder(SslCredential);
127+
128+
impl SslCredentialBuilder {
129+
/// Sets or overwrites the extra data at the specified index.
130+
///
131+
/// This can be used to provide data to callbacks registered with the context. Use the
132+
/// `SslCredential::new_ex_index` method to create an `Index`.
133+
///
134+
/// Any previous value will be returned and replaced by the new one.
135+
#[corresponds(SSL_CREDENTIAL_set_ex_data)]
136+
pub fn replace_ex_data<T>(&mut self, index: Index<SslCredential, T>, data: T) -> Option<T> {
137+
unsafe { self.0.replace_ex_data(index, data) }
138+
}
139+
140+
// Sets the private key of the credential.
141+
#[corresponds(SSL_CREDENTIAL_set1_private_key)]
142+
pub fn set_private_key(&mut self, private_key: &PKeyRef<Private>) -> Result<(), ErrorStack> {
143+
unsafe {
144+
cvt_0i(ffi::SSL_CREDENTIAL_set1_private_key(
145+
self.0.as_ptr(),
146+
private_key.as_ptr(),
147+
))
148+
.map(|_| ())
149+
}
150+
}
151+
152+
/// Configures a custom private key method on the credential.
153+
///
154+
/// See [`PrivateKeyMethod`] for more details.
155+
#[corresponds(SSL_CREDENTIAL_set_private_key_method)]
156+
pub fn set_private_key_method<M>(&mut self, method: M) -> Result<(), ErrorStack>
157+
where
158+
M: PrivateKeyMethod,
159+
{
160+
unsafe {
161+
self.replace_ex_data(SslCredential::cached_ex_index::<M>(), method);
162+
163+
cvt_0i(ffi::SSL_CREDENTIAL_set_private_key_method(
164+
self.0.as_ptr(),
165+
&ffi::SSL_PRIVATE_KEY_METHOD {
166+
sign: Some(callbacks::raw_sign::<M>),
167+
decrypt: Some(callbacks::raw_decrypt::<M>),
168+
complete: Some(callbacks::raw_complete::<M>),
169+
},
170+
))
171+
.map(|_| ())
172+
}
173+
}
174+
175+
// Sets the SPKI of the raw public key credential.
176+
//
177+
// If `spki` is `None`, the SPKI is extracted from the credential's private key.
178+
#[corresponds(SSL_CREDENTIAL_set1_spki)]
179+
#[cfg(feature = "rpk")]
180+
pub fn set_spki_bytes(&mut self, spki: Option<&[u8]>) -> Result<(), ErrorStack> {
181+
unsafe {
182+
let spki = spki
183+
.map(|spki| {
184+
cvt_p(ffi::CRYPTO_BUFFER_new(
185+
spki.as_ptr(),
186+
spki.len(),
187+
ptr::null_mut(),
188+
))
189+
})
190+
.transpose()?
191+
.unwrap_or(ptr::null_mut());
192+
193+
let ret = cvt_0i(ffi::SSL_CREDENTIAL_set1_spki(self.0.as_ptr(), spki)).map(|_| ());
194+
195+
if !spki.is_null() {
196+
ffi::CRYPTO_BUFFER_free(spki);
197+
}
198+
199+
ret
200+
}
201+
}
202+
203+
#[must_use]
204+
pub fn build(self) -> SslCredential {
205+
self.0
206+
}
207+
}
208+
209+
unsafe fn get_new_ssl_credential_idx(f: ffi::CRYPTO_EX_free) -> c_int {
210+
ffi::SSL_CREDENTIAL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
211+
}

0 commit comments

Comments
 (0)