Skip to content

Commit 836e9da

Browse files
committed
Add decoder wrapper
1 parent e376828 commit 836e9da

File tree

1 file changed

+329
-10
lines changed

1 file changed

+329
-10
lines changed

openssl/src/encdec.rs

Lines changed: 329 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
1-
use crate::bio::MemBio;
1+
use crate::bio::{MemBio, MemBioSlice};
22
use crate::cipher::CipherRef;
33
use crate::error::ErrorStack;
4-
use crate::pkey::PKeyRef;
5-
use crate::pkey_ctx::Selection;
6-
use crate::util::c_str;
4+
use crate::pkey::{Id, PKey, PKeyRef};
5+
use crate::pkey_ctx::{Selection, SelectionT};
6+
use crate::util::{c_str, invoke_passwd_cb, CallbackState};
77
use crate::{cvt, cvt_p};
88
use foreign_types::{ForeignType, ForeignTypeRef};
99
use openssl_macros::corresponds;
1010
use std::ffi::{CStr, CString};
11+
use std::marker::PhantomData;
1112
use std::ptr;
1213

1314
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -91,23 +92,199 @@ foreign_type_and_impl_send_sync! {
9192

9293
/// A context object which can perform decode operations.
9394
pub struct DecoderCtx;
94-
/// A reference to a [`DecoderCtx`].
95+
/// A reference to a `DecoderCtx`.
9596
pub struct DecoderCtxRef;
9697
}
9798

9899
impl DecoderCtx {
99-
/// Creates a new decoder context using the provided key.
100-
#[corresponds(OSSL_DECODER_CTX_new)]
100+
#[corresponds(OSSL_DECODER_CTX_new_for_pkey)]
101101
#[inline]
102102
#[allow(dead_code)]
103-
pub fn new() -> Result<Self, ErrorStack> {
103+
fn new_for_key(
104+
pkey: *mut *mut ffi::EVP_PKEY,
105+
selection: Selection,
106+
input: Option<KeyFormat>,
107+
structure: Option<Structure<'_>>,
108+
key_type: Option<Id>,
109+
) -> Result<Self, ErrorStack> {
110+
let input_ptr = input
111+
.map(|i| {
112+
let input: &CStr = i.into();
113+
input.as_ptr()
114+
})
115+
.unwrap_or_else(ptr::null);
116+
let structure_ptr = structure
117+
.map(|s| {
118+
let structure: &CStr = s.into();
119+
structure.as_ptr()
120+
})
121+
.unwrap_or_else(ptr::null);
122+
let key_type_ptr = key_type
123+
.and_then(|k| k.try_into().ok())
124+
.map(|k: &CStr| k.as_ptr())
125+
.unwrap_or_else(ptr::null);
104126
unsafe {
105-
let ptr = cvt_p(ffi::OSSL_DECODER_CTX_new())?;
127+
let ptr = cvt_p(ffi::OSSL_DECODER_CTX_new_for_pkey(
128+
pkey,
129+
input_ptr,
130+
structure_ptr,
131+
key_type_ptr,
132+
selection.into(),
133+
ptr::null_mut(),
134+
ptr::null(),
135+
))?;
106136
Ok(DecoderCtx::from_ptr(ptr))
107137
}
108138
}
109139
}
110140

141+
impl DecoderCtxRef {
142+
/// Select which parts of the key to decode.
143+
#[corresponds(OSSL_DECODER_CTX_set_selection)]
144+
#[allow(dead_code)]
145+
fn set_selection(&mut self, selection: Selection) -> Result<(), ErrorStack> {
146+
cvt(unsafe { ffi::OSSL_DECODER_CTX_set_selection(self.as_ptr(), selection.into()) })
147+
.map(|_| ())
148+
}
149+
150+
/// Set the input type for the encoded data.
151+
#[corresponds(OSSL_DECODER_CTX_set_input_type)]
152+
#[allow(dead_code)]
153+
fn set_input_type(&mut self, input: KeyFormat) -> Result<(), ErrorStack> {
154+
let input: &CStr = input.into();
155+
cvt(unsafe { ffi::OSSL_DECODER_CTX_set_input_type(self.as_ptr(), input.as_ptr()) })
156+
.map(|_| ())
157+
}
158+
159+
/// Set the input structure for the encoded data.
160+
#[corresponds(OSSL_DECODER_CTX_set_input_structure)]
161+
#[allow(dead_code)]
162+
fn set_input_structure(&mut self, structure: Structure<'_>) -> Result<(), ErrorStack> {
163+
let structure: &CStr = structure.into();
164+
cvt(unsafe { ffi::OSSL_DECODER_CTX_set_input_structure(self.as_ptr(), structure.as_ptr()) })
165+
.map(|_| ())
166+
}
167+
168+
/// Set the passphrase to decrypt the encoded data.
169+
#[corresponds(OSSL_DECODER_CTX_set_passphrase)]
170+
#[allow(dead_code)]
171+
fn set_passphrase(&mut self, passphrase: &[u8]) -> Result<(), ErrorStack> {
172+
cvt(unsafe {
173+
ffi::OSSL_DECODER_CTX_set_passphrase(
174+
self.as_ptr(),
175+
passphrase.as_ptr().cast(),
176+
passphrase.len(),
177+
)
178+
})
179+
.map(|_| ())
180+
}
181+
182+
/// Set the passphrase to decrypt the encoded data.
183+
#[corresponds(OSSL_DECODER_CTX_set_passphrase)]
184+
#[allow(dead_code)]
185+
unsafe fn set_passphrase_callback<F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>>(
186+
&mut self,
187+
callback: *mut CallbackState<F>,
188+
) -> Result<(), ErrorStack> {
189+
cvt(unsafe {
190+
ffi::OSSL_DECODER_CTX_set_pem_password_cb(
191+
self.as_ptr(),
192+
Some(invoke_passwd_cb::<F>),
193+
callback as *mut _,
194+
)
195+
})
196+
.map(|_| ())
197+
}
198+
199+
/// Decode the encoded data
200+
#[corresponds(OSSL_DECODER_from_bio)]
201+
#[allow(dead_code)]
202+
fn decode(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
203+
let bio = MemBioSlice::new(data)?;
204+
205+
cvt(unsafe { ffi::OSSL_DECODER_from_bio(self.as_ptr(), bio.as_ptr()) }).map(|_| ())
206+
}
207+
}
208+
209+
#[allow(dead_code)]
210+
pub(crate) struct Decoder<'a, T: SelectionT> {
211+
selection: PhantomData<T>,
212+
key_type: Option<Id>,
213+
format: Option<KeyFormat>,
214+
structure: Option<Structure<'a>>,
215+
passphrase: Option<&'a [u8]>,
216+
passphrase_callback: Option<Box<dyn FnOnce(&mut [u8]) -> Result<usize, ErrorStack> + 'a>>,
217+
}
218+
219+
impl<'a, T: SelectionT> Decoder<'a, T> {
220+
#[allow(dead_code)]
221+
pub(crate) fn new() -> Self {
222+
Self {
223+
selection: PhantomData,
224+
key_type: None,
225+
format: None,
226+
structure: None,
227+
passphrase: None,
228+
passphrase_callback: None,
229+
}
230+
}
231+
232+
#[allow(dead_code)]
233+
pub fn set_key_type(mut self, key_type: Id) -> Self {
234+
self.key_type = Some(key_type);
235+
self
236+
}
237+
238+
#[allow(dead_code)]
239+
pub fn set_format(mut self, format: KeyFormat) -> Self {
240+
self.format = Some(format);
241+
self
242+
}
243+
244+
#[allow(dead_code)]
245+
pub fn set_structure(mut self, structure: Structure<'a>) -> Self {
246+
self.structure = Some(structure);
247+
self
248+
}
249+
250+
#[allow(dead_code)]
251+
pub fn set_passphrase(mut self, passphrase: &'a [u8]) -> Self {
252+
self.passphrase = Some(passphrase);
253+
self
254+
}
255+
256+
#[allow(dead_code)]
257+
pub fn set_passphrase_callback<F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack> + 'a>(
258+
mut self,
259+
callback: F,
260+
) -> Self {
261+
self.passphrase_callback = Some(Box::new(callback));
262+
self
263+
}
264+
265+
#[allow(dead_code)]
266+
pub fn decode(self, data: &[u8]) -> Result<PKey<T>, ErrorStack> {
267+
let mut pkey_ptr = ptr::null_mut();
268+
let mut passphrase_callback_state;
269+
let mut ctx = DecoderCtx::new_for_key(
270+
&mut pkey_ptr,
271+
T::SELECTION,
272+
self.format,
273+
self.structure,
274+
self.key_type,
275+
)?;
276+
if let Some(passphrase) = self.passphrase {
277+
ctx.set_passphrase(passphrase)?;
278+
}
279+
if let Some(passphrase_callback) = self.passphrase_callback {
280+
passphrase_callback_state = CallbackState::new(passphrase_callback);
281+
unsafe { ctx.set_passphrase_callback(&mut passphrase_callback_state)? };
282+
}
283+
ctx.decode(data)?;
284+
Ok(unsafe { PKey::from_ptr(pkey_ptr) })
285+
}
286+
}
287+
111288
foreign_type_and_impl_send_sync! {
112289
type CType = ffi::OSSL_ENCODER_CTX;
113290
fn drop = ffi::OSSL_ENCODER_CTX_free;
@@ -321,13 +498,155 @@ mod test {
321498
}
322499
}
323500

501+
mod decoder {
502+
use super::*;
503+
504+
mod params {
505+
use super::*;
506+
use crate::pkey::Params;
507+
508+
#[test]
509+
fn test_dh_pem() {
510+
Decoder::<Params>::new()
511+
.set_key_type(Id::DH)
512+
.set_format(KeyFormat::Pem)
513+
.set_structure(Structure::TypeSpecific)
514+
.decode(include_bytes!("../test/dhparams.pem"))
515+
.unwrap()
516+
.dh()
517+
.unwrap();
518+
}
519+
520+
#[test]
521+
fn test_dh_der() {
522+
Decoder::<Params>::new()
523+
.set_key_type(Id::DH)
524+
.set_format(KeyFormat::Der)
525+
.set_structure(Structure::TypeSpecific)
526+
.decode(include_bytes!("../test/dhparams.der"))
527+
.unwrap()
528+
.dh()
529+
.unwrap();
530+
}
531+
}
532+
mod public {
533+
use super::*;
534+
use crate::pkey::Public;
535+
536+
#[test]
537+
fn test_rsa_pem() {
538+
Decoder::<Public>::new()
539+
.set_key_type(Id::RSA)
540+
.set_format(KeyFormat::Pem)
541+
.set_structure(Structure::SubjectPublicKeyInfo)
542+
.decode(include_bytes!("../test/rsa.pem.pub"))
543+
.unwrap()
544+
.rsa()
545+
.unwrap();
546+
}
547+
548+
#[test]
549+
fn test_rsa_pem_pkcs1() {
550+
Decoder::<Public>::new()
551+
.set_key_type(Id::RSA)
552+
.set_format(KeyFormat::Pem)
553+
.set_structure(Structure::PKCS1)
554+
.decode(include_bytes!("../test/pkcs1.pem.pub"))
555+
.unwrap()
556+
.rsa()
557+
.unwrap();
558+
}
559+
560+
#[test]
561+
fn test_rsa_der() {
562+
Decoder::<Public>::new()
563+
.set_key_type(Id::RSA)
564+
.set_format(KeyFormat::Der)
565+
.set_structure(Structure::SubjectPublicKeyInfo)
566+
.decode(include_bytes!("../test/key.der.pub"))
567+
.unwrap()
568+
.rsa()
569+
.unwrap();
570+
}
571+
572+
#[test]
573+
fn test_rsa_der_pkcs1() {
574+
Decoder::<Public>::new()
575+
.set_key_type(Id::RSA)
576+
.set_format(KeyFormat::Der)
577+
.set_structure(Structure::PKCS1)
578+
.decode(include_bytes!("../test/pkcs1.der.pub"))
579+
.unwrap()
580+
.rsa()
581+
.unwrap();
582+
}
583+
}
584+
mod private {
585+
use super::*;
586+
use crate::pkey::Private;
587+
588+
#[test]
589+
fn test_rsa_pem() {
590+
Decoder::<Private>::new()
591+
.set_key_type(Id::RSA)
592+
.set_format(KeyFormat::Pem)
593+
.set_structure(Structure::PKCS1)
594+
.decode(include_bytes!("../test/rsa.pem"))
595+
.unwrap()
596+
.rsa()
597+
.unwrap();
598+
}
599+
600+
#[test]
601+
fn test_rsa_pem_passphrase() {
602+
Decoder::<Private>::new()
603+
.set_key_type(Id::RSA)
604+
.set_format(KeyFormat::Pem)
605+
.set_structure(Structure::PKCS1)
606+
.set_passphrase(b"mypass")
607+
.decode(include_bytes!("../test/rsa-encrypted.pem"))
608+
.unwrap()
609+
.rsa()
610+
.unwrap();
611+
}
612+
613+
#[test]
614+
fn test_rsa_pem_callback() {
615+
let mut password_queried = false;
616+
Decoder::<Private>::new()
617+
.set_key_type(Id::RSA)
618+
.set_format(KeyFormat::Pem)
619+
.set_structure(Structure::PKCS1)
620+
.set_passphrase_callback(|password| {
621+
password_queried = true;
622+
password[..6].copy_from_slice(b"mypass");
623+
Ok(6)
624+
})
625+
.decode(include_bytes!("../test/rsa-encrypted.pem"))
626+
.unwrap();
627+
assert!(password_queried);
628+
}
629+
630+
#[test]
631+
fn test_rsa_der() {
632+
Decoder::<Private>::new()
633+
.set_key_type(Id::RSA)
634+
.set_format(KeyFormat::Der)
635+
.set_structure(Structure::PKCS1)
636+
.decode(include_bytes!("../test/key.der"))
637+
.unwrap()
638+
.rsa()
639+
.unwrap();
640+
}
641+
}
642+
}
643+
324644
mod encoder {
325645
use super::*;
326646

327647
mod params {
328648
use super::*;
329649
use crate::dh::Dh;
330-
use crate::pkey::Id;
331650
use crate::pkey::Params;
332651
use crate::pkey_ctx::PkeyCtx;
333652

0 commit comments

Comments
 (0)