#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
use base64ct::{Base64, Encoding};
use der::{Decode, Encode};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Encode,
{
let der_bytes = value.to_der().map_err(serde::ser::Error::custom)?;
if serializer.is_human_readable() {
let encoded = Base64::encode_string(&der_bytes);
serializer.serialize_str(&encoded)
} else {
serializer.serialize_bytes(&der_bytes)
}
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: for<'a> Decode<'a>,
{
let der_bytes = if deserializer.is_human_readable() {
let s = String::deserialize(deserializer)?;
Base64::decode_vec(&s).map_err(serde::de::Error::custom)?
} else {
Vec::<u8>::deserialize(deserializer)?
};
T::from_der(&der_bytes).map_err(serde::de::Error::custom)
}
pub mod option {
use super::{Base64, Decode, Deserialize, Deserializer, Encode, Encoding, Serializer};
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
pub fn serialize<S, T>(value: &Option<T>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Encode,
{
match value {
Some(v) => {
let der_bytes = v.to_der().map_err(serde::ser::Error::custom)?;
if serializer.is_human_readable() {
let encoded = Base64::encode_string(&der_bytes);
serializer.serialize_some(&encoded)
} else {
serializer.serialize_some(&der_bytes)
}
}
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
T: for<'a> Decode<'a>,
{
if deserializer.is_human_readable() {
let opt = Option::<String>::deserialize(deserializer)?;
match opt {
Some(s) => {
let der_bytes = Base64::decode_vec(&s).map_err(serde::de::Error::custom)?;
let v = T::from_der(&der_bytes).map_err(serde::de::Error::custom)?;
Ok(Some(v))
}
None => Ok(None),
}
} else {
let opt = Option::<Vec<u8>>::deserialize(deserializer)?;
match opt {
Some(bytes) => {
let v = T::from_der(&bytes).map_err(serde::de::Error::custom)?;
Ok(Some(v))
}
None => Ok(None),
}
}
}
}
pub mod vec {
use super::{Base64, Decode, Deserialize, Deserializer, Encode, Encoding, Serializer};
use serde::ser::SerializeSeq;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
pub fn serialize<S, T>(values: &[T], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Encode,
{
let is_hr = serializer.is_human_readable();
let mut seq = serializer.serialize_seq(Some(values.len()))?;
for v in values {
let der_bytes = v.to_der().map_err(serde::ser::Error::custom)?;
if is_hr {
let encoded = Base64::encode_string(&der_bytes);
seq.serialize_element(&encoded)?;
} else {
seq.serialize_element(der_bytes.as_slice())?;
}
}
seq.end()
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: Deserializer<'de>,
T: for<'a> Decode<'a>,
{
if deserializer.is_human_readable() {
let strs = Vec::<String>::deserialize(deserializer)?;
let mut out = Vec::with_capacity(strs.len());
for s in strs {
let der_bytes = Base64::decode_vec(&s).map_err(serde::de::Error::custom)?;
let v = T::from_der(&der_bytes).map_err(serde::de::Error::custom)?;
out.push(v);
}
Ok(out)
} else {
let byte_vecs = Vec::<Vec<u8>>::deserialize(deserializer)?;
let mut out = Vec::with_capacity(byte_vecs.len());
for bytes in byte_vecs {
let v = T::from_der(&bytes).map_err(serde::de::Error::custom)?;
out.push(v);
}
Ok(out)
}
}
}
pub mod option_vec {
use super::{Base64, Decode, Deserialize, Deserializer, Encode, Encoding, Serialize, Serializer};
use serde::ser::SerializeSeq;
#[cfg(not(feature = "std"))]
use alloc::{string::String, vec::Vec};
pub fn serialize<S, T>(value: &Option<Vec<T>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
T: Encode,
{
match value {
Some(values) => {
let is_hr = serializer.is_human_readable();
let mut bytes_buf: Vec<Vec<u8>> = Vec::with_capacity(values.len());
let mut str_buf: Vec<String> = Vec::with_capacity(values.len());
for v in values {
let der_bytes = v.to_der().map_err(serde::ser::Error::custom)?;
if is_hr {
str_buf.push(Base64::encode_string(&der_bytes));
} else {
bytes_buf.push(der_bytes);
}
}
if is_hr {
serializer.serialize_some(&str_buf)
} else {
struct Bytes<'a>(&'a [Vec<u8>]);
impl<'a> Serialize for Bytes<'a> {
fn serialize<S2: Serializer>(&self, s: S2) -> Result<S2::Ok, S2::Error> {
let mut seq = s.serialize_seq(Some(self.0.len()))?;
for b in self.0 {
seq.serialize_element(b.as_slice())?;
}
seq.end()
}
}
serializer.serialize_some(&Bytes(&bytes_buf))
}
}
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<Option<Vec<T>>, D::Error>
where
D: Deserializer<'de>,
T: for<'a> Decode<'a>,
{
if deserializer.is_human_readable() {
let opt = Option::<Vec<String>>::deserialize(deserializer)?;
match opt {
Some(strs) => {
let mut out = Vec::with_capacity(strs.len());
for s in strs {
let der_bytes =
Base64::decode_vec(&s).map_err(serde::de::Error::custom)?;
let v = T::from_der(&der_bytes).map_err(serde::de::Error::custom)?;
out.push(v);
}
Ok(Some(out))
}
None => Ok(None),
}
} else {
let opt = Option::<Vec<Vec<u8>>>::deserialize(deserializer)?;
match opt {
Some(byte_vecs) => {
let mut out = Vec::with_capacity(byte_vecs.len());
for bytes in byte_vecs {
let v = T::from_der(&bytes).map_err(serde::de::Error::custom)?;
out.push(v);
}
Ok(Some(out))
}
None => Ok(None),
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use der::asn1::ObjectIdentifier;
const ECDSA_WITH_SHA256_OID: &str = "1.2.840.10045.4.3.2";
const ECDSA_WITH_SHA256_DER: &[u8] =
&[0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02];
const ECDSA_WITH_SHA256_BASE64: &str = "BggqhkjOPQQDAg==";
#[test]
fn json_serialize_matches_hand_computed_base64() {
#[derive(Serialize)]
struct Wrapper {
#[serde(serialize_with = "super::serialize")]
oid: ObjectIdentifier,
}
let oid: ObjectIdentifier = ECDSA_WITH_SHA256_OID.parse().unwrap();
let w = Wrapper { oid };
let json = serde_json::to_string(&w).unwrap();
let expected = format!(r#"{{"oid":"{}"}}"#, ECDSA_WITH_SHA256_BASE64);
assert_eq!(json, expected);
}
#[test]
fn json_deserialize_matches_hand_constructed_value() {
#[derive(Deserialize)]
struct Wrapper {
#[serde(deserialize_with = "super::deserialize")]
oid: ObjectIdentifier,
}
let json = format!(r#"{{"oid":"{}"}}"#, ECDSA_WITH_SHA256_BASE64);
let w: Wrapper = serde_json::from_str(&json).unwrap();
let expected: ObjectIdentifier = ECDSA_WITH_SHA256_OID.parse().unwrap();
assert_eq!(w.oid, expected);
}
#[test]
fn json_round_trip_preserves_der_canonical_form() {
#[derive(Serialize, Deserialize)]
struct Wrapper {
#[serde(with = "super::super::serde_der")]
oid: ObjectIdentifier,
}
let oid: ObjectIdentifier = ECDSA_WITH_SHA256_OID.parse().unwrap();
let original_der = oid.to_der().unwrap();
assert_eq!(original_der.as_slice(), ECDSA_WITH_SHA256_DER);
let w = Wrapper { oid };
let json = serde_json::to_string(&w).unwrap();
let back: Wrapper = serde_json::from_str(&json).unwrap();
let recovered_der = back.oid.to_der().unwrap();
assert_eq!(recovered_der, original_der);
}
#[test]
fn binary_serializer_emits_raw_der_bytes_not_base64() {
use serde::ser::Impossible;
struct BytesCapture {
captured: Vec<u8>,
}
impl Serializer for &mut BytesCapture {
type Ok = ();
type Error = serde::de::value::Error;
type SerializeSeq = Impossible<(), Self::Error>;
type SerializeTuple = Impossible<(), Self::Error>;
type SerializeTupleStruct = Impossible<(), Self::Error>;
type SerializeTupleVariant = Impossible<(), Self::Error>;
type SerializeMap = Impossible<(), Self::Error>;
type SerializeStruct = Impossible<(), Self::Error>;
type SerializeStructVariant = Impossible<(), Self::Error>;
fn is_human_readable(&self) -> bool {
false
}
fn serialize_bytes(self, v: &[u8]) -> Result<(), Self::Error> {
self.captured.extend_from_slice(v);
Ok(())
}
fn serialize_bool(self, _: bool) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_i8(self, _: i8) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_i16(self, _: i16) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_i32(self, _: i32) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_i64(self, _: i64) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_u8(self, _: u8) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_u16(self, _: u16) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_u32(self, _: u32) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_u64(self, _: u64) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_f32(self, _: f32) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_f64(self, _: f64) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_char(self, _: char) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_str(self, _: &str) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_none(self) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_some<T: ?Sized + Serialize>(self, _: &T) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_unit(self) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_unit_struct(self, _: &'static str) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_unit_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_newtype_struct<T: ?Sized + Serialize>(
self,
_: &'static str,
_: &T,
) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_newtype_variant<T: ?Sized + Serialize>(
self,
_: &'static str,
_: u32,
_: &'static str,
_: &T,
) -> Result<(), Self::Error> {
unreachable!()
}
fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
unreachable!()
}
fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
unreachable!()
}
fn serialize_tuple_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
unreachable!()
}
fn serialize_tuple_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
unreachable!()
}
fn serialize_map(self, _: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
unreachable!()
}
fn serialize_struct(
self,
_: &'static str,
_: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
unreachable!()
}
fn serialize_struct_variant(
self,
_: &'static str,
_: u32,
_: &'static str,
_: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
unreachable!()
}
}
let oid: ObjectIdentifier = ECDSA_WITH_SHA256_OID.parse().unwrap();
let mut cap = BytesCapture {
captured: Vec::new(),
};
super::serialize(&oid, &mut cap).unwrap();
assert_eq!(cap.captured, ECDSA_WITH_SHA256_DER);
}
}