|
|
|
@ -26,6 +26,16 @@ unsafe impl<F: FormatSpec + ?Sized> std::marker::Sync for FormattedStr<F>{}
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
|
|
|
pub struct FormattedString<F: FormatSpec + ?Sized>(String, PhantomData<F>);
|
|
|
|
|
|
|
|
|
|
impl<'a, F> fmt::Display for &'a FormattedStr<F>
|
|
|
|
|
where F: ?Sized + FormatSpec
|
|
|
|
|
{
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
|
|
|
{
|
|
|
|
|
write!(f, "{}", self.as_str())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Deserialising
|
|
|
|
|
const _:() = {
|
|
|
|
|
use serde::{
|
|
|
|
@ -377,11 +387,58 @@ pub mod formats
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PEMFormat
|
|
|
|
|
{
|
|
|
|
|
#[inline] fn is_allowed(string: &str) -> bool
|
|
|
|
|
{
|
|
|
|
|
lazy_static! {
|
|
|
|
|
static ref ALLOWED_MAP: smallmap::Map<&'static str,()> = defaults::RECOGNISABLE_PEM_ENCODES.iter().map(|&x| (x, ())).collect();
|
|
|
|
|
}
|
|
|
|
|
ALLOWED_MAP.contains_key(&string)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const BEGIN_BLOCK: &'static str = "-----BEGIN ";
|
|
|
|
|
const END_BLOCK: &'static str = "-----END ";
|
|
|
|
|
const END_ANY_BLOCK: &'static str = "-----";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl FormatSpec for PEMFormat
|
|
|
|
|
{
|
|
|
|
|
type Error = PEMFormatError;
|
|
|
|
|
fn validate(_s: &str) -> Result<(), Self::Error> {
|
|
|
|
|
todo!("Learn the PEM ciphertext format");
|
|
|
|
|
fn validate(s: &str) -> Result<(), Self::Error> {
|
|
|
|
|
|
|
|
|
|
macro_rules! enforce {
|
|
|
|
|
($e:expr) => {
|
|
|
|
|
if !$e {
|
|
|
|
|
return Err(PEMFormatError);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let s = s.trim();
|
|
|
|
|
let mut lines = s.lines();
|
|
|
|
|
let begin = lines.next().ok_or(PEMFormatError)?.trim();
|
|
|
|
|
enforce!(begin.starts_with(Self::BEGIN_BLOCK));
|
|
|
|
|
enforce!(begin.ends_with(Self::END_ANY_BLOCK));
|
|
|
|
|
|
|
|
|
|
let val = &begin[Self::BEGIN_BLOCK.len()..];
|
|
|
|
|
let val = &val[..(val.len()-Self::END_ANY_BLOCK.len())];
|
|
|
|
|
enforce!(Self::is_allowed(val));
|
|
|
|
|
|
|
|
|
|
let mut lines = lines.map(|x| x.trim()).fuse();
|
|
|
|
|
while let Some(line) = lines.next()
|
|
|
|
|
{
|
|
|
|
|
if line.starts_with(Self::END_BLOCK) {
|
|
|
|
|
let eval = &line[Self::END_BLOCK.len()..];
|
|
|
|
|
let eval = &eval[..(eval.len()-Self::END_ANY_BLOCK.len())];
|
|
|
|
|
enforce!(eval == val);
|
|
|
|
|
break;
|
|
|
|
|
} else {
|
|
|
|
|
enforce!(Base64Format::validate(line.trim()).is_ok());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
enforce!(lines.next().is_none());
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)]
|
|
|
|
@ -412,7 +469,7 @@ pub mod formats
|
|
|
|
|
while let Some(window) = iter.next()
|
|
|
|
|
{
|
|
|
|
|
let is_last = iter.peek().is_none();
|
|
|
|
|
// eprintln!("Window: {:?} ({})", std::str::from_utf8(window), is_last);
|
|
|
|
|
// eprintln!("Window: {:?} ({})", std::str::from_utf8(window), is_last);
|
|
|
|
|
for byte in window.iter().copied()
|
|
|
|
|
{
|
|
|
|
|
if !(CHARSET[byte as usize] || (is_last && byte == b'=')) {
|
|
|
|
@ -499,6 +556,19 @@ pub mod formats
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn pem_format()
|
|
|
|
|
{
|
|
|
|
|
const PUBKEY: &'static str = r#"-----BEGIN PUBLIC KEY-----
|
|
|
|
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD2vGFdJ+KCK6Ot8sDcaCXk/9D8
|
|
|
|
|
S1InEHi5vGSLdGKJpaRdHhQ08NL5+fv6B9FGKV5KARCYXeW1JGnGNzhRXHhNyOSm
|
|
|
|
|
KNi2T+L84xBCTEazlLnnnvqKGaD95rtjwMmkhsErRMfavqUMThEmVca5fwP30Sqm
|
|
|
|
|
StF6Y2cSO2eUjqTeUQIDAQAB
|
|
|
|
|
-----END PUBLIC KEY-----"#;
|
|
|
|
|
let pem = PEMFormattedStr::new(PUBKEY).expect("PEM format");
|
|
|
|
|
println!("PEM: {}", pem);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|