Skip to content

Commit

Permalink
serialization methods
Browse files Browse the repository at this point in the history
  • Loading branch information
Geal committed Feb 8, 2025
1 parent c06cc0a commit 8dabc87
Show file tree
Hide file tree
Showing 7 changed files with 205 additions and 7 deletions.
2 changes: 1 addition & 1 deletion biscuit-auth/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ homepage = "https://github.com/biscuit-auth/biscuit"
repository = "https://github.com/biscuit-auth/biscuit-rust"

[features]
default = ["regex-full", "datalog-macro"]
default = ["regex-full", "datalog-macro", "pem"]
regex-full = ["regex/perf", "regex/unicode"]
wasm = ["wasm-bindgen", "getrandom/wasm-bindgen"]
# used by biscuit-wasm to serialize errors to JSON
Expand Down
65 changes: 63 additions & 2 deletions biscuit-auth/src/crypto/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use std::{convert::TryInto, hash::Hash, ops::Drop};
use zeroize::Zeroize;

/// pair of cryptographic keys used to sign a token's block
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct KeyPair {
pub(super) kp: ed25519_dalek::SigningKey,
}
Expand Down Expand Up @@ -89,6 +89,27 @@ impl KeyPair {
.map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Ok(KeyPair { kp })
}

#[cfg(feature = "pem")]
pub fn to_private_key_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>, error::Format> {
use ed25519_dalek::pkcs8::EncodePrivateKey;
let kp = self
.kp
.to_pkcs8_der()
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp.to_bytes())
}

#[cfg(feature = "pem")]
pub fn to_private_key_pem(&self) -> Result<zeroize::Zeroizing<String>, error::Format> {
use ed25519_dalek::pkcs8::EncodePrivateKey;
use p256::pkcs8::LineEnding;
let kp = self
.kp
.to_pkcs8_pem(LineEnding::LF)
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp)
}
}

impl std::default::Default for KeyPair {
Expand All @@ -98,7 +119,7 @@ impl std::default::Default for KeyPair {
}

/// the private part of a [KeyPair]
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct PrivateKey(pub(crate) ed25519_dalek::SecretKey);

impl PrivateKey {
Expand Down Expand Up @@ -140,6 +161,25 @@ impl PrivateKey {
Ok(PrivateKey(kp.to_bytes()))
}

#[cfg(feature = "pem")]
pub fn to_private_key_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>, error::Format> {
use ed25519_dalek::pkcs8::EncodePrivateKey;
let kp = ed25519_dalek::SigningKey::from_bytes(&self.0)
.to_pkcs8_der()
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp.to_bytes())
}

#[cfg(feature = "pem")]
pub fn to_private_key_pem(&self) -> Result<zeroize::Zeroizing<String>, error::Format> {
use ed25519_dalek::pkcs8::EncodePrivateKey;
use p256::pkcs8::LineEnding;
let kp = ed25519_dalek::SigningKey::from_bytes(&self.0)
.to_pkcs8_pem(LineEnding::LF)
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp)
}

/// returns the matching public key
pub fn public(&self) -> PublicKey {
PublicKey(SigningKey::from_bytes(&self.0).verifying_key())
Expand Down Expand Up @@ -255,6 +295,27 @@ impl PublicKey {
Ok(PublicKey(pubkey))
}

#[cfg(feature = "pem")]
pub fn to_public_key_der(&self) -> Result<Vec<u8>, error::Format> {
use ed25519_dalek::pkcs8::EncodePublicKey;
let kp = self
.0
.to_public_key_der()
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp.to_vec())
}

#[cfg(feature = "pem")]
pub fn to_public_key_pem(&self) -> Result<String, error::Format> {
use ed25519_dalek::pkcs8::EncodePublicKey;
use p256::pkcs8::LineEnding;
let kp = self
.0
.to_public_key_pem(LineEnding::LF)
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp)
}

pub(crate) fn write(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ed25519/{}", hex::encode(&self.to_bytes()))
}
Expand Down
72 changes: 70 additions & 2 deletions biscuit-auth/src/crypto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use std::hash::Hash;
use std::str::FromStr;

/// pair of cryptographic keys used to sign a token's block
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub enum KeyPair {
Ed25519(ed25519::KeyPair),
P256(p256::KeyPair),
Expand Down Expand Up @@ -95,6 +95,22 @@ impl KeyPair {
}
}

#[cfg(feature = "pem")]
pub fn to_private_key_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>, error::Format> {
match self {
KeyPair::Ed25519(key) => key.to_private_key_der(),
KeyPair::P256(key) => key.to_private_key_der(),
}
}

#[cfg(feature = "pem")]
pub fn to_private_key_pem(&self) -> Result<zeroize::Zeroizing<String>, error::Format> {
match self {
KeyPair::Ed25519(key) => key.to_private_key_pem(),
KeyPair::P256(key) => key.to_private_key_pem(),
}
}

pub fn private(&self) -> PrivateKey {
match self {
KeyPair::Ed25519(key) => PrivateKey::Ed25519(key.private()),
Expand Down Expand Up @@ -124,7 +140,7 @@ impl std::default::Default for KeyPair {
}

/// the private part of a [KeyPair]
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq)]
pub enum PrivateKey {
Ed25519(ed25519::PrivateKey),
P256(p256::PrivateKey),
Expand Down Expand Up @@ -207,6 +223,22 @@ impl PrivateKey {
}
}

#[cfg(feature = "pem")]
pub fn to_private_key_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>, error::Format> {
match self {
PrivateKey::Ed25519(key) => key.to_private_key_der(),
PrivateKey::P256(key) => key.to_private_key_der(),
}
}

#[cfg(feature = "pem")]
pub fn to_private_key_pem(&self) -> Result<zeroize::Zeroizing<String>, error::Format> {
match self {
PrivateKey::Ed25519(key) => key.to_private_key_pem(),
PrivateKey::P256(key) => key.to_private_key_pem(),
}
}

/// returns the matching public key
pub fn public(&self) -> PublicKey {
match self {
Expand Down Expand Up @@ -302,6 +334,22 @@ impl PublicKey {
}
}

#[cfg(feature = "pem")]
pub fn to_public_key_der(&self) -> Result<Vec<u8>, error::Format> {
match self {
PublicKey::Ed25519(key) => key.to_public_key_der(),
PublicKey::P256(key) => key.to_public_key_der(),
}
}

#[cfg(feature = "pem")]
pub fn to_public_key_pem(&self) -> Result<String, error::Format> {
match self {
PublicKey::Ed25519(key) => key.to_public_key_pem(),
PublicKey::P256(key) => key.to_public_key_pem(),
}
}

pub fn verify_signature(
&self,
data: &[u8],
Expand Down Expand Up @@ -780,4 +828,24 @@ mod tests {
.parse::<PrivateKey>()
.unwrap_err();
}

#[cfg(feature = "pem")]
#[test]
fn ed25519_der() {
let ed25519_kp = KeyPair::new_with_algorithm(Algorithm::Ed25519);
let der_kp = ed25519_kp.to_private_key_der().unwrap();

let deser = KeyPair::from_private_key_der(&der_kp, Algorithm::Ed25519).unwrap();
assert_eq!(ed25519_kp, deser);

let ed25519_priv = ed25519_kp.private();
let der_priv = ed25519_priv.to_private_key_der().unwrap();
let deser_priv = PrivateKey::from_private_key_der(&der_priv, Algorithm::Ed25519).unwrap();
assert_eq!(ed25519_priv, deser_priv);

let ed25519_pub = ed25519_kp.public();
let der_pub = ed25519_pub.to_public_key_der().unwrap();
let deser_pub = PublicKey::from_public_key_der(&der_pub, Algorithm::Ed25519).unwrap();
assert_eq!(ed25519_pub, deser_pub);
}
}
67 changes: 65 additions & 2 deletions biscuit-auth/src/crypto/p256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use p256::NistP256;
use std::hash::Hash;

/// pair of cryptographic keys used to sign a token's block
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct KeyPair {
kp: SigningKey,
}
Expand Down Expand Up @@ -83,6 +83,27 @@ impl KeyPair {
.map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Ok(KeyPair { kp })
}

#[cfg(feature = "pem")]
pub fn to_private_key_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>, error::Format> {
use p256::pkcs8::EncodePrivateKey;
let kp = self
.kp
.to_pkcs8_der()
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp.to_bytes())
}

#[cfg(feature = "pem")]
pub fn to_private_key_pem(&self) -> Result<zeroize::Zeroizing<String>, error::Format> {
use p256::pkcs8::EncodePrivateKey;
use p256::pkcs8::LineEnding;
let kp = self
.kp
.to_pkcs8_pem(LineEnding::LF)
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp)
}
}

impl std::default::Default for KeyPair {
Expand All @@ -92,7 +113,7 @@ impl std::default::Default for KeyPair {
}

/// the private part of a [KeyPair]
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct PrivateKey(SigningKey);

impl PrivateKey {
Expand Down Expand Up @@ -144,6 +165,27 @@ impl PrivateKey {
Ok(PrivateKey(kp))
}

#[cfg(feature = "pem")]
pub fn to_private_key_der(&self) -> Result<zeroize::Zeroizing<Vec<u8>>, error::Format> {
use p256::pkcs8::EncodePrivateKey;
let kp = self
.0
.to_pkcs8_der()
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp.to_bytes())
}

#[cfg(feature = "pem")]
pub fn to_private_key_pem(&self) -> Result<zeroize::Zeroizing<String>, error::Format> {
use p256::pkcs8::EncodePrivateKey;
use p256::pkcs8::LineEnding;
let kp = self
.0
.to_pkcs8_pem(LineEnding::LF)
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp)
}

/// returns the matching public key
pub fn public(&self) -> PublicKey {
PublicKey(*(&self.0).verifying_key())
Expand Down Expand Up @@ -208,6 +250,27 @@ impl PublicKey {
Ok(PublicKey(pubkey))
}

#[cfg(feature = "pem")]
pub fn to_public_key_der(&self) -> Result<Vec<u8>, error::Format> {
use p256::pkcs8::EncodePublicKey;
let kp = self
.0
.to_public_key_der()
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp.to_vec())
}

#[cfg(feature = "pem")]
pub fn to_public_key_pem(&self) -> Result<String, error::Format> {
use p256::pkcs8::EncodePublicKey;
use p256::pkcs8::LineEnding;
let kp = self
.0
.to_public_key_pem(LineEnding::LF)
.map_err(|e| error::Format::PKCS8(e.to_string()))?;
Ok(kp)
}

pub fn from_proto(key: &schema::PublicKey) -> Result<Self, error::Format> {
if key.algorithm != schema::public_key::Algorithm::Ed25519 as i32 {
return Err(error::Format::DeserializationError(format!(
Expand Down
3 changes: 3 additions & 0 deletions biscuit-auth/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ pub enum Format {
UnknownExternalKey,
#[error("the symbol id was not in the table")]
UnknownSymbol(u64),
#[cfg(feature = "pem")]
#[error("PKCS8 serialization error")]
PKCS8(String),
}

/// Signature errors
Expand Down
1 change: 1 addition & 0 deletions biscuit-capi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ repository = "https://github.com/biscuit-auth/biscuit-rust"
biscuit-auth = { version = "6.0.0-alpha.1", path = "../biscuit-auth", features = [
"datalog-macro",
"serde-error",
"pem",
] }
libc = { version = "0.2", optional = true }
rand = "0.8"
Expand Down
2 changes: 2 additions & 0 deletions biscuit-capi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub enum ErrorKind {
AlreadySealed,
Execution,
UnexpectedQueryResult,
FormatPKCS8,
}

#[no_mangle]
Expand Down Expand Up @@ -160,6 +161,7 @@ pub extern "C" fn error_kind() -> ErrorKind {
ErrorKind::FormatUnknownExternalKey
}
Token::Format(Format::UnknownSymbol(_)) => ErrorKind::FormatUnknownSymbol,
Token::Format(Format::PKCS8(_)) => ErrorKind::FormatPKCS8,
Token::AppendOnSealed => ErrorKind::AppendOnSealed,
Token::AlreadySealed => ErrorKind::AlreadySealed,
Token::Language(_) => ErrorKind::LanguageError,
Expand Down

0 comments on commit 8dabc87

Please sign in to comment.