Skip to content

Commit

Permalink
elliptic-curve: add hex serde (de)serializer for PublicKey (#967)
Browse files Browse the repository at this point in the history
This commit changes the `Serializer` and `Deserializer` impls on the
`PublicKey` type to work more like the ones on other types in this crate
and its downstream dependencies:

- Use binary DER serialization with binary formats (what it does today)
- Use an upper-case hex serialization of the DER in conjunction with
  "human readable" formats

Though richer formats exist for this use case (such as `JwkEcKey` which
is an existing implementation of JWK), hex-serialized DER is relatively
easy to work with, and can be decoded easily with online tools such as
https://lapo.it/asn1js/

Note that the `Deserialize` impl for `PublicKey` never worked with
human-readable formats as it was attempting to deserialize to `&[u8]`,
which doesn't work with formats like JSON or TOML because they need an
intermediate decoding step and therefore require deserialization to
`Vec<u8>`. So this isn't a breaking change from the `Deserialize` side.

Fixes RustCrypto/elliptic-curves#536
  • Loading branch information
tarcieri authored Mar 17, 2022
1 parent c385ff2 commit ad0572f
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 12 deletions.
2 changes: 1 addition & 1 deletion elliptic-curve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ sha3 = "0.10"

[features]
default = ["arithmetic"]
alloc = ["der/alloc", "sec1/alloc", "zeroize/alloc"] # todo: use weak activation for `group`/`sec1` alloc when available
alloc = ["base16ct/alloc", "der/alloc", "sec1/alloc", "zeroize/alloc"] # todo: use weak activation for `group`/`sec1` alloc when available
arithmetic = ["ff", "group"]
bits = ["arithmetic", "ff/bits"]
dev = ["arithmetic", "hex-literal", "pem", "pkcs8"]
Expand Down
31 changes: 20 additions & 11 deletions elliptic-curve/src/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ use {
use alloc::string::{String, ToString};

#[cfg(all(feature = "pem", feature = "serde"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
use serde::{de, ser, Deserialize, Serialize};

/// Elliptic curve public keys.
Expand Down Expand Up @@ -353,8 +352,8 @@ where
}
}

#[cfg(all(feature = "pem", feature = "serde"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
#[cfg(all(feature = "alloc", feature = "serde"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "serde"))))]
impl<C> Serialize for PublicKey<C>
where
C: Curve + AlgorithmParameters + ProjectiveArithmetic,
Expand All @@ -365,15 +364,18 @@ where
where
S: ser::Serializer,
{
self.to_public_key_der()
.map_err(ser::Error::custom)?
.as_ref()
.serialize(serializer)
let der = self.to_public_key_der().map_err(ser::Error::custom)?;

if serializer.is_human_readable() {
base16ct::upper::encode_string(der.as_ref()).serialize(serializer)
} else {
der.as_ref().serialize(serializer)
}
}
}

#[cfg(all(feature = "pem", feature = "serde"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "serde"))))]
#[cfg(all(feature = "alloc", feature = "serde"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "serde"))))]
impl<'de, C> Deserialize<'de> for PublicKey<C>
where
C: Curve + AlgorithmParameters + ProjectiveArithmetic,
Expand All @@ -386,8 +388,15 @@ where
{
use de::Error;

<&[u8]>::deserialize(deserializer)
.and_then(|bytes| Self::from_public_key_der(bytes).map_err(D::Error::custom))
if deserializer.is_human_readable() {
let der_bytes = base16ct::mixed::decode_vec(<&str>::deserialize(deserializer)?)
.map_err(D::Error::custom)?;
Self::from_public_key_der(&der_bytes)
} else {
let der_bytes = <&[u8]>::deserialize(deserializer)?;
Self::from_public_key_der(der_bytes)
}
.map_err(D::Error::custom)
}
}

Expand Down

0 comments on commit ad0572f

Please sign in to comment.