Skip to content

Commit 42024c4

Browse files
committed
Add decoder wrapper
1 parent 19988eb commit 42024c4

File tree

1 file changed

+310
-9
lines changed

1 file changed

+310
-9
lines changed

openssl/src/encdec.rs

Lines changed: 310 additions & 9 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;
4+
use crate::pkey::{Id, PKey, PKeyRef};
5+
use crate::pkey_ctx::{Selection, SelectionT};
66
use crate::util::c_str;
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,181 @@ 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+
/// Decode the encoded data
183+
#[corresponds(OSSL_DECODER_from_bio)]
184+
#[allow(dead_code)]
185+
fn decode(&mut self, data: &[u8]) -> Result<(), ErrorStack> {
186+
let bio = MemBioSlice::new(data)?;
187+
188+
cvt(unsafe { ffi::OSSL_DECODER_from_bio(self.as_ptr(), bio.as_ptr()) }).map(|_| ())
189+
}
190+
}
191+
192+
#[allow(dead_code)]
193+
pub struct Decoder<'a, T: SelectionT> {
194+
selection: PhantomData<T>,
195+
key_type: Option<Id>,
196+
format: Option<KeyFormat>,
197+
structure: Option<Structure<'a>>,
198+
passphrase: Option<&'a [u8]>,
199+
// TODO: Implement passphrase callback
200+
// passphrase_callback: Option<...>,
201+
}
202+
203+
impl<'a, T: SelectionT> Decoder<'a, T> {
204+
#[allow(dead_code)]
205+
pub fn new() -> Self {
206+
Self {
207+
selection: PhantomData,
208+
key_type: None,
209+
format: None,
210+
structure: None,
211+
passphrase: None,
212+
// TODO: Implement passphrase callback
213+
// passphrase_callback: None,
214+
}
215+
}
216+
217+
#[allow(dead_code)]
218+
pub fn set_key_type(mut self, key_type: Id) -> Self {
219+
self.key_type = Some(key_type);
220+
self
221+
}
222+
223+
#[allow(dead_code)]
224+
pub fn set_format(mut self, format: KeyFormat) -> Self {
225+
self.format = Some(format);
226+
self
227+
}
228+
229+
#[allow(dead_code)]
230+
pub fn set_structure(mut self, structure: Structure<'a>) -> Self {
231+
self.structure = Some(structure);
232+
self
233+
}
234+
235+
#[allow(dead_code)]
236+
pub fn set_passphrase(mut self, passphrase: &'a [u8]) -> Self {
237+
self.passphrase = Some(passphrase);
238+
self
239+
}
240+
241+
// TODO: implement passphrase callback
242+
// #[allow(dead_code)]
243+
// pub fn set_passphrase_callback(mut self, callback: ...) -> Self {
244+
// self.passphrase_callback = Some(callback);
245+
// self
246+
// }
247+
248+
#[allow(dead_code)]
249+
pub fn decode(self, data: &[u8]) -> Result<PKey<T>, ErrorStack> {
250+
let mut pkey_ptr = ptr::null_mut();
251+
let mut ctx = DecoderCtx::new_for_key(
252+
&mut pkey_ptr,
253+
T::SELECTION,
254+
self.format,
255+
self.structure,
256+
self.key_type,
257+
)?;
258+
if let Some(passphrase) = self.passphrase {
259+
ctx.set_passphrase(passphrase)?;
260+
}
261+
// TODO: Implement passphrase callback
262+
// if let Some(passphrase_callback) = ctx.passphrase_callback {
263+
// ctx.set_passphrase_callback(passphrase_callback)?;
264+
// }
265+
ctx.decode(data)?;
266+
Ok(unsafe { PKey::from_ptr(pkey_ptr) })
267+
}
268+
}
269+
111270
foreign_type_and_impl_send_sync! {
112271
type CType = ffi::OSSL_ENCODER_CTX;
113272
fn drop = ffi::OSSL_ENCODER_CTX_free;
@@ -321,13 +480,155 @@ mod test {
321480
}
322481
}
323482

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

327629
mod params {
328630
use super::*;
329631
use crate::dh::Dh;
330-
use crate::pkey::Id;
331632
use crate::pkey::Params;
332633
use crate::pkey_ctx::PkeyCtx;
333634

0 commit comments

Comments
 (0)