#![allow(non_snake_case)]
use crate::{error::Format, format::schema};
use super::error;
#[cfg(feature = "pem")]
use ed25519_dalek::pkcs8::DecodePrivateKey;
use ed25519_dalek::*;
use nom::Finish;
use rand_core::{CryptoRng, RngCore};
#[cfg(feature = "pem")]
use std::path::Path;
use std::{convert::TryInto, fmt::Display, hash::Hash, ops::Drop, str::FromStr};
use zeroize::Zeroize;
#[derive(Debug)]
pub struct KeyPair {
pub(crate) kp: ed25519_dalek::SigningKey,
}
impl KeyPair {
pub fn new() -> Self {
Self::new_with_rng(&mut rand::rngs::OsRng)
}
pub fn new_with_rng<T: RngCore + CryptoRng>(rng: &mut T) -> Self {
let kp = ed25519_dalek::SigningKey::generate(rng);
KeyPair { kp }
}
pub fn from(key: &PrivateKey) -> Self {
KeyPair {
kp: ed25519_dalek::SigningKey::from_bytes(&key.0),
}
}
#[cfg(feature = "pem")]
pub fn from_private_key_der(bytes: &[u8]) -> Result<Self, error::Format> {
let kp = SigningKey::from_pkcs8_der(bytes)
.map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Ok(KeyPair { kp })
}
#[cfg(feature = "pem")]
pub fn from_private_key_pem(str: &str) -> Result<Self, error::Format> {
let kp = SigningKey::from_pkcs8_pem(str)
.map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Ok(KeyPair { kp })
}
#[cfg(feature = "pem")]
pub fn from_private_key_der_file(path: impl AsRef<Path>) -> Result<Self, error::Format> {
let kp = SigningKey::read_pkcs8_der_file(path)
.map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Ok(KeyPair { kp })
}
#[cfg(feature = "pem")]
pub fn from_private_key_pem_file(path: impl AsRef<Path>) -> Result<Self, error::Format> {
let kp = SigningKey::read_pkcs8_pem_file(path)
.map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Ok(KeyPair { kp })
}
pub fn private(&self) -> PrivateKey {
let secret = self.kp.to_bytes();
PrivateKey(secret)
}
pub fn public(&self) -> PublicKey {
PublicKey(self.kp.verifying_key())
}
}
impl std::default::Default for KeyPair {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct PrivateKey(pub(crate) ed25519_dalek::SecretKey);
impl PrivateKey {
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
pub fn to_bytes_hex(&self) -> String {
hex::encode(self.to_bytes())
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, error::Format> {
let bytes: [u8; 32] = bytes
.try_into()
.map_err(|_| Format::InvalidKeySize(bytes.len()))?;
Ok(PrivateKey(bytes))
}
pub fn from_bytes_hex(str: &str) -> Result<Self, error::Format> {
let bytes = hex::decode(str).map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Self::from_bytes(&bytes)
}
pub fn public(&self) -> PublicKey {
PublicKey(SigningKey::from_bytes(&self.0).verifying_key())
}
}
impl std::clone::Clone for PrivateKey {
fn clone(&self) -> Self {
PrivateKey::from_bytes(&self.to_bytes()).unwrap()
}
}
impl Drop for PrivateKey {
fn drop(&mut self) {
self.0.zeroize();
}
}
#[derive(Debug, Clone, Copy, Eq)]
pub struct PublicKey(pub(crate) ed25519_dalek::VerifyingKey);
impl PublicKey {
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
pub fn to_bytes_hex(&self) -> String {
hex::encode(self.to_bytes())
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, error::Format> {
let bytes: [u8; 32] = bytes
.try_into()
.map_err(|_| Format::InvalidKeySize(bytes.len()))?;
ed25519_dalek::VerifyingKey::from_bytes(&bytes)
.map(PublicKey)
.map_err(|s| s.to_string())
.map_err(Format::InvalidKey)
}
pub fn from_bytes_hex(str: &str) -> Result<Self, error::Format> {
let bytes = hex::decode(str).map_err(|e| error::Format::InvalidKey(e.to_string()))?;
Self::from_bytes(&bytes)
}
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!(
"deserialization error: unexpected key algorithm {}",
key.algorithm
)));
}
PublicKey::from_bytes(&key.key)
}
pub fn to_proto(&self) -> schema::PublicKey {
schema::PublicKey {
algorithm: schema::public_key::Algorithm::Ed25519 as i32,
key: self.to_bytes().to_vec(),
}
}
pub fn print(&self) -> String {
self.to_string()
}
}
impl PartialEq for PublicKey {
fn eq(&self, other: &Self) -> bool {
self.0.to_bytes() == other.0.to_bytes()
}
}
impl Hash for PublicKey {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(crate::format::schema::public_key::Algorithm::Ed25519 as i32).hash(state);
self.0.to_bytes().hash(state);
}
}
impl FromStr for PublicKey {
type Err = error::Token;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (_, bytes) = biscuit_parser::parser::public_key(s)
.finish()
.map_err(biscuit_parser::error::LanguageError::from)?;
Ok(PublicKey::from_bytes(&bytes)?)
}
}
impl Display for PublicKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "ed25519/{}", hex::encode(&self.to_bytes()))
}
}
#[derive(Clone, Debug)]
pub struct Block {
pub(crate) data: Vec<u8>,
pub(crate) next_key: PublicKey,
pub signature: ed25519_dalek::Signature,
pub external_signature: Option<ExternalSignature>,
}
#[derive(Clone, Debug)]
pub struct ExternalSignature {
pub(crate) public_key: PublicKey,
pub(crate) signature: ed25519_dalek::Signature,
}
#[derive(Clone, Debug)]
pub struct Token {
pub root: PublicKey,
pub blocks: Vec<Block>,
pub next: TokenNext,
}
#[derive(Clone, Debug)]
pub enum TokenNext {
Secret(PrivateKey),
Seal(ed25519_dalek::Signature),
}
pub fn sign(
keypair: &KeyPair,
next_key: &KeyPair,
message: &[u8],
) -> Result<Signature, error::Token> {
let mut to_sign = message.to_vec();
to_sign.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
to_sign.extend(&next_key.public().to_bytes());
let signature = keypair
.kp
.try_sign(&to_sign)
.map_err(|s| s.to_string())
.map_err(error::Signature::InvalidSignatureGeneration)
.map_err(error::Format::Signature)?;
Ok(signature)
}
pub fn verify_block_signature(block: &Block, public_key: &PublicKey) -> Result<(), error::Format> {
let mut to_verify = block.data.to_vec();
if let Some(signature) = block.external_signature.as_ref() {
to_verify.extend_from_slice(&signature.signature.to_bytes());
}
to_verify.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
to_verify.extend(&block.next_key.to_bytes());
public_key
.0
.verify_strict(&to_verify, &block.signature)
.map_err(|s| s.to_string())
.map_err(error::Signature::InvalidSignature)
.map_err(error::Format::Signature)?;
if let Some(external_signature) = block.external_signature.as_ref() {
let mut to_verify = block.data.to_vec();
to_verify
.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
to_verify.extend(&public_key.to_bytes());
external_signature
.public_key
.0
.verify_strict(&to_verify, &external_signature.signature)
.map_err(|s| s.to_string())
.map_err(error::Signature::InvalidSignature)
.map_err(error::Format::Signature)?;
}
Ok(())
}
impl Token {
#[allow(dead_code)]
pub fn new<T: RngCore + CryptoRng>(
keypair: &KeyPair,
next_key: &KeyPair,
message: &[u8],
) -> Result<Self, error::Token> {
let signature = sign(keypair, next_key, message)?;
let block = Block {
data: message.to_vec(),
next_key: next_key.public(),
signature,
external_signature: None,
};
Ok(Token {
root: keypair.public(),
blocks: vec![block],
next: TokenNext::Secret(next_key.private()),
})
}
#[allow(dead_code)]
pub fn append<T: RngCore + CryptoRng>(
&self,
next_key: &KeyPair,
message: &[u8],
external_signature: Option<ExternalSignature>,
) -> Result<Self, error::Token> {
let keypair = match self.next.keypair() {
Err(error::Token::AlreadySealed) => Err(error::Token::AppendOnSealed),
other => other,
}?;
let signature = sign(&keypair, next_key, message)?;
let block = Block {
data: message.to_vec(),
next_key: next_key.public(),
signature,
external_signature,
};
let mut t = Token {
root: self.root,
blocks: self.blocks.clone(),
next: TokenNext::Secret(next_key.private()),
};
t.blocks.push(block);
Ok(t)
}
#[allow(dead_code)]
pub fn verify(&self, root: PublicKey) -> Result<(), error::Token> {
let mut current_pub = root;
for block in &self.blocks {
verify_block_signature(block, ¤t_pub)?;
current_pub = block.next_key;
}
match &self.next {
TokenNext::Secret(private) => {
if current_pub != private.public() {
return Err(error::Format::Signature(error::Signature::InvalidSignature(
"the last public key does not match the private key".to_string(),
))
.into());
}
}
TokenNext::Seal(signature) => {
let mut to_verify = Vec::new();
for block in &self.blocks {
to_verify.extend(&block.data);
to_verify.extend(&block.next_key.to_bytes());
}
current_pub
.0
.verify_strict(&to_verify, signature)
.map_err(|s| s.to_string())
.map_err(error::Signature::InvalidSignature)
.map_err(error::Format::Signature)?;
}
}
Ok(())
}
}
impl TokenNext {
pub fn keypair(&self) -> Result<KeyPair, error::Token> {
match &self {
TokenNext::Seal(_) => Err(error::Token::AlreadySealed),
TokenNext::Secret(private) => Ok(KeyPair::from(private)),
}
}
pub fn is_sealed(&self) -> bool {
match &self {
TokenNext::Seal(_) => true,
TokenNext::Secret(_) => false,
}
}
}
#[cfg(test)]
mod tests {
}