use serde::{ de::{self, Deserialize, Deserializer}, ser::{Serialize, Serializer}, }; use zeroize::Zeroizing; fn base64_config() -> base64::Config { base64::Config::new(base64::CharacterSet::UrlSafe, true /* pad */) } fn base64_encode(bytes: impl AsRef<[u8]>) -> String { base64::encode_config(bytes, base64_config()) } fn base64_decode(b64: impl AsRef<[u8]>) -> Result, base64::DecodeError> { base64::decode_config(b64, base64_config()) } pub fn serialize_base64(bytes: impl AsRef<[u8]>, s: S) -> Result { base64_encode(bytes).serialize(s) } pub fn deserialize_base64<'de, D: Deserializer<'de>>(d: D) -> Result, D::Error> { let base64_str = Zeroizing::new(String::deserialize(d)?); base64_decode(&*base64_str).map_err(|e| { #[cfg(debug_assertions)] let err_msg = e.to_string().to_lowercase(); #[cfg(not(debug_assertions))] let err_msg = "invalid base64"; de::Error::custom(err_msg.strip_suffix(".").unwrap_or(&err_msg)) }) } #[cfg(feature = "pkcs-convert")] pub mod pkcs8 { use yasna::{ models::{ObjectIdentifier, TaggedDerValue}, DERWriter, DERWriterSeq, }; fn write_oids(writer: &mut DERWriterSeq, oids: &[Option<&ObjectIdentifier>]) { for oid in oids { match oid { Some(oid) => writer.next().write_oid(oid), None => writer.next().write_null(), } } } pub fn write_private( oids: &[Option<&ObjectIdentifier>], body_writer: impl FnOnce(&mut DERWriterSeq), ) -> Vec { yasna::construct_der(|writer| { writer.write_sequence(|writer| { writer.next().write_i8(0); // version writer .next() .write_sequence(|writer| write_oids(writer, oids)); let body = yasna::construct_der(|writer| writer.write_sequence(body_writer)); writer .next() .write_tagged_der(&TaggedDerValue::from_octetstring(body)); }) }) } pub fn write_public( oids: &[Option<&ObjectIdentifier>], body_writer: impl FnOnce(DERWriter), ) -> Vec { yasna::construct_der(|writer| { writer.write_sequence(|writer| { writer .next() .write_sequence(|writer| write_oids(writer, oids)); body_writer(writer.next()); }) }) } }