biscuit_auth/crypto/
mod.rs

1//! cryptographic operations
2//!
3//! Biscuit tokens are based on a chain of Ed25519 signatures.
4//! This provides the fundamental operation for offline delegation: from a message
5//! and a valid signature, it is possible to add a new message and produce a valid
6//! signature for the whole.
7//!
8//! The implementation is based on [ed25519_dalek](https://github.com/dalek-cryptography/ed25519-dalek).
9#![allow(non_snake_case)]
10use crate::{error::Format, format::schema};
11
12use super::error;
13#[cfg(feature = "pem")]
14use ed25519_dalek::pkcs8::DecodePrivateKey;
15use ed25519_dalek::*;
16
17use nom::Finish;
18use rand_core::{CryptoRng, RngCore};
19use std::{convert::TryInto, fmt::Display, hash::Hash, ops::Drop, str::FromStr};
20use zeroize::Zeroize;
21
22/// pair of cryptographic keys used to sign a token's block
23#[derive(Debug)]
24pub struct KeyPair {
25    pub(crate) kp: ed25519_dalek::SigningKey,
26}
27
28impl KeyPair {
29    pub fn new() -> Self {
30        Self::new_with_rng(&mut rand::rngs::OsRng)
31    }
32
33    pub fn new_with_rng<T: RngCore + CryptoRng>(rng: &mut T) -> Self {
34        let kp = ed25519_dalek::SigningKey::generate(rng);
35
36        KeyPair { kp }
37    }
38
39    pub fn from(key: &PrivateKey) -> Self {
40        KeyPair {
41            kp: ed25519_dalek::SigningKey::from_bytes(&key.0),
42        }
43    }
44
45    #[cfg(feature = "pem")]
46    pub fn from_private_key_der(bytes: &[u8]) -> Result<Self, error::Format> {
47        let kp = SigningKey::from_pkcs8_der(bytes)
48            .map_err(|e| error::Format::InvalidKey(e.to_string()))?;
49        Ok(KeyPair { kp })
50    }
51
52    #[cfg(feature = "pem")]
53    pub fn from_private_key_pem(str: &str) -> Result<Self, error::Format> {
54        let kp = SigningKey::from_pkcs8_pem(str)
55            .map_err(|e| error::Format::InvalidKey(e.to_string()))?;
56        Ok(KeyPair { kp })
57    }
58
59    pub fn private(&self) -> PrivateKey {
60        let secret = self.kp.to_bytes();
61        PrivateKey(secret)
62    }
63
64    pub fn public(&self) -> PublicKey {
65        PublicKey(self.kp.verifying_key())
66    }
67}
68
69impl std::default::Default for KeyPair {
70    fn default() -> Self {
71        Self::new()
72    }
73}
74
75/// the private part of a [KeyPair]
76#[derive(Debug)]
77pub struct PrivateKey(pub(crate) ed25519_dalek::SecretKey);
78
79impl PrivateKey {
80    /// serializes to a byte array
81    pub fn to_bytes(&self) -> [u8; 32] {
82        self.0
83    }
84
85    /// serializes to an hex-encoded string
86    pub fn to_bytes_hex(&self) -> String {
87        hex::encode(self.to_bytes())
88    }
89
90    /// deserializes from a byte array
91    pub fn from_bytes(bytes: &[u8]) -> Result<Self, error::Format> {
92        let bytes: [u8; 32] = bytes
93            .try_into()
94            .map_err(|_| Format::InvalidKeySize(bytes.len()))?;
95        Ok(PrivateKey(bytes))
96    }
97
98    /// deserializes from an hex-encoded string
99    pub fn from_bytes_hex(str: &str) -> Result<Self, error::Format> {
100        let bytes = hex::decode(str).map_err(|e| error::Format::InvalidKey(e.to_string()))?;
101        Self::from_bytes(&bytes)
102    }
103
104    /// returns the matching public key
105    pub fn public(&self) -> PublicKey {
106        PublicKey(SigningKey::from_bytes(&self.0).verifying_key())
107    }
108}
109
110impl std::clone::Clone for PrivateKey {
111    fn clone(&self) -> Self {
112        PrivateKey::from_bytes(&self.to_bytes()).unwrap()
113    }
114}
115
116impl Drop for PrivateKey {
117    fn drop(&mut self) {
118        self.0.zeroize();
119    }
120}
121
122/// the public part of a [KeyPair]
123#[derive(Debug, Clone, Copy, Eq)]
124pub struct PublicKey(pub(crate) ed25519_dalek::VerifyingKey);
125
126impl PublicKey {
127    /// serializes to a byte array
128    pub fn to_bytes(&self) -> [u8; 32] {
129        self.0.to_bytes()
130    }
131
132    /// serializes to an hex-encoded string
133    pub fn to_bytes_hex(&self) -> String {
134        hex::encode(self.to_bytes())
135    }
136
137    /// deserializes from a byte array
138    pub fn from_bytes(bytes: &[u8]) -> Result<Self, error::Format> {
139        let bytes: [u8; 32] = bytes
140            .try_into()
141            .map_err(|_| Format::InvalidKeySize(bytes.len()))?;
142
143        ed25519_dalek::VerifyingKey::from_bytes(&bytes)
144            .map(PublicKey)
145            .map_err(|s| s.to_string())
146            .map_err(Format::InvalidKey)
147    }
148
149    /// deserializes from an hex-encoded string
150    pub fn from_bytes_hex(str: &str) -> Result<Self, error::Format> {
151        let bytes = hex::decode(str).map_err(|e| error::Format::InvalidKey(e.to_string()))?;
152        Self::from_bytes(&bytes)
153    }
154
155    pub fn from_proto(key: &schema::PublicKey) -> Result<Self, error::Format> {
156        if key.algorithm != schema::public_key::Algorithm::Ed25519 as i32 {
157            return Err(error::Format::DeserializationError(format!(
158                "deserialization error: unexpected key algorithm {}",
159                key.algorithm
160            )));
161        }
162
163        PublicKey::from_bytes(&key.key)
164    }
165
166    pub fn to_proto(&self) -> schema::PublicKey {
167        schema::PublicKey {
168            algorithm: schema::public_key::Algorithm::Ed25519 as i32,
169            key: self.to_bytes().to_vec(),
170        }
171    }
172
173    pub fn print(&self) -> String {
174        self.to_string()
175    }
176}
177
178impl PartialEq for PublicKey {
179    fn eq(&self, other: &Self) -> bool {
180        self.0.to_bytes() == other.0.to_bytes()
181    }
182}
183
184impl Hash for PublicKey {
185    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
186        (crate::format::schema::public_key::Algorithm::Ed25519 as i32).hash(state);
187        self.0.to_bytes().hash(state);
188    }
189}
190
191impl FromStr for PublicKey {
192    type Err = error::Token;
193
194    fn from_str(s: &str) -> Result<Self, Self::Err> {
195        let (_, bytes) = biscuit_parser::parser::public_key(s)
196            .finish()
197            .map_err(biscuit_parser::error::LanguageError::from)?;
198        Ok(PublicKey::from_bytes(&bytes)?)
199    }
200}
201
202impl Display for PublicKey {
203    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204        write!(f, "ed25519/{}", hex::encode(self.to_bytes()))
205    }
206}
207
208#[derive(Clone, Debug)]
209pub struct Block {
210    pub(crate) data: Vec<u8>,
211    pub(crate) next_key: PublicKey,
212    pub signature: ed25519_dalek::Signature,
213    pub external_signature: Option<ExternalSignature>,
214}
215
216#[derive(Clone, Debug)]
217pub struct ExternalSignature {
218    pub(crate) public_key: PublicKey,
219    pub(crate) signature: ed25519_dalek::Signature,
220}
221
222#[derive(Clone, Debug)]
223pub struct Token {
224    pub root: PublicKey,
225    pub blocks: Vec<Block>,
226    pub next: TokenNext,
227}
228
229#[derive(Clone, Debug)]
230pub enum TokenNext {
231    Secret(PrivateKey),
232    Seal(ed25519_dalek::Signature),
233}
234
235pub fn sign(
236    keypair: &KeyPair,
237    next_key: &KeyPair,
238    message: &[u8],
239) -> Result<Signature, error::Token> {
240    //FIXME: replace with SHA512 hashing
241    let mut to_sign = message.to_vec();
242    to_sign.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
243    to_sign.extend(&next_key.public().to_bytes());
244
245    let signature = keypair
246        .kp
247        .try_sign(&to_sign)
248        .map_err(|s| s.to_string())
249        .map_err(error::Signature::InvalidSignatureGeneration)
250        .map_err(error::Format::Signature)?;
251
252    Ok(signature)
253}
254
255pub fn verify_block_signature(block: &Block, public_key: &PublicKey) -> Result<(), error::Format> {
256    //FIXME: replace with SHA512 hashing
257    let mut to_verify = block.data.to_vec();
258
259    if let Some(signature) = block.external_signature.as_ref() {
260        to_verify.extend_from_slice(&signature.signature.to_bytes());
261    }
262    to_verify.extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
263    to_verify.extend(&block.next_key.to_bytes());
264
265    public_key
266        .0
267        .verify_strict(&to_verify, &block.signature)
268        .map_err(|s| s.to_string())
269        .map_err(error::Signature::InvalidSignature)
270        .map_err(error::Format::Signature)?;
271
272    if let Some(external_signature) = block.external_signature.as_ref() {
273        let mut to_verify = block.data.to_vec();
274        to_verify
275            .extend(&(crate::format::schema::public_key::Algorithm::Ed25519 as i32).to_le_bytes());
276        to_verify.extend(&public_key.to_bytes());
277
278        external_signature
279            .public_key
280            .0
281            .verify_strict(&to_verify, &external_signature.signature)
282            .map_err(|s| s.to_string())
283            .map_err(error::Signature::InvalidSignature)
284            .map_err(error::Format::Signature)?;
285    }
286
287    Ok(())
288}
289
290impl Token {
291    #[allow(dead_code)]
292    pub fn new<T: RngCore + CryptoRng>(
293        keypair: &KeyPair,
294        next_key: &KeyPair,
295        message: &[u8],
296    ) -> Result<Self, error::Token> {
297        let signature = sign(keypair, next_key, message)?;
298
299        let block = Block {
300            data: message.to_vec(),
301            next_key: next_key.public(),
302            signature,
303            external_signature: None,
304        };
305
306        Ok(Token {
307            root: keypair.public(),
308            blocks: vec![block],
309            next: TokenNext::Secret(next_key.private()),
310        })
311    }
312
313    #[allow(dead_code)]
314    pub fn append<T: RngCore + CryptoRng>(
315        &self,
316        next_key: &KeyPair,
317        message: &[u8],
318        external_signature: Option<ExternalSignature>,
319    ) -> Result<Self, error::Token> {
320        let keypair = match self.next.keypair() {
321            Err(error::Token::AlreadySealed) => Err(error::Token::AppendOnSealed),
322            other => other,
323        }?;
324
325        let signature = sign(&keypair, next_key, message)?;
326
327        let block = Block {
328            data: message.to_vec(),
329            next_key: next_key.public(),
330            signature,
331            external_signature,
332        };
333
334        let mut t = Token {
335            root: self.root,
336            blocks: self.blocks.clone(),
337            next: TokenNext::Secret(next_key.private()),
338        };
339
340        t.blocks.push(block);
341
342        Ok(t)
343    }
344
345    #[allow(dead_code)]
346    pub fn verify(&self, root: PublicKey) -> Result<(), error::Token> {
347        //FIXME: try batched signature verification
348        let mut current_pub = root;
349
350        for block in &self.blocks {
351            verify_block_signature(block, &current_pub)?;
352            current_pub = block.next_key;
353        }
354
355        match &self.next {
356            TokenNext::Secret(private) => {
357                if current_pub != private.public() {
358                    return Err(error::Format::Signature(error::Signature::InvalidSignature(
359                        "the last public key does not match the private key".to_string(),
360                    ))
361                    .into());
362                }
363            }
364            TokenNext::Seal(signature) => {
365                //FIXME: replace with SHA512 hashing
366                let mut to_verify = Vec::new();
367                for block in &self.blocks {
368                    to_verify.extend(&block.data);
369                    to_verify.extend(&block.next_key.to_bytes());
370                }
371
372                current_pub
373                    .0
374                    .verify_strict(&to_verify, signature)
375                    .map_err(|s| s.to_string())
376                    .map_err(error::Signature::InvalidSignature)
377                    .map_err(error::Format::Signature)?;
378            }
379        }
380
381        Ok(())
382    }
383}
384
385impl TokenNext {
386    pub fn keypair(&self) -> Result<KeyPair, error::Token> {
387        match &self {
388            TokenNext::Seal(_) => Err(error::Token::AlreadySealed),
389            TokenNext::Secret(private) => Ok(KeyPair::from(private)),
390        }
391    }
392
393    pub fn is_sealed(&self) -> bool {
394        match &self {
395            TokenNext::Seal(_) => true,
396            TokenNext::Secret(_) => false,
397        }
398    }
399}
400
401#[cfg(test)]
402mod tests {
403    /*
404    use super::*;
405    use rand::prelude::*;
406    use rand_core::SeedableRng;
407
408    #[test]
409    fn basic_signature() {
410        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
411
412        let message = b"hello world";
413        let keypair = KeyPair::new_with_rng(&mut rng);
414
415        let signature = keypair.sign(&mut rng, message);
416
417        assert!(verify(&keypair.public, message, &signature));
418
419        assert!(!verify(&keypair.public, b"AAAA", &signature));
420    }
421
422    #[test]
423    fn three_messages() {
424        //let mut rng: OsRng = OsRng::new().unwrap();
425        //keep the same values in tests
426        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
427
428        let message1 = b"hello";
429        let keypair1 = KeyPair::new_with_rng(&mut rng);
430
431        let token1 = Token::new(&mut rng, &keypair1, &message1[..]);
432
433        assert_eq!(token1.verify(), Ok(()), "cannot verify first token");
434
435        println!("will derive a second token");
436
437        let message2 = b"world";
438        let keypair2 = KeyPair::new_with_rng(&mut rng);
439
440        let token2 = token1.append(&mut rng, &keypair2, &message2[..]);
441
442        assert_eq!(token2.verify(), Ok(()), "cannot verify second token");
443
444        println!("will derive a third token");
445
446        let message3 = b"!!!";
447        let keypair3 = KeyPair::new_with_rng(&mut rng);
448
449        let token3 = token2.append(&mut rng, &keypair3, &message3[..]);
450
451        assert_eq!(token3.verify(), Ok(()), "cannot verify third token");
452    }
453
454    #[test]
455    fn change_message() {
456        //let mut rng: OsRng = OsRng::new().unwrap();
457        //keep the same values in tests
458        let mut rng: StdRng = SeedableRng::seed_from_u64(0);
459
460        let message1 = b"hello";
461        let keypair1 = KeyPair::new_with_rng(&mut rng);
462
463        let token1 = Token::new(&mut rng, &keypair1, &message1[..]);
464
465        assert_eq!(token1.verify(), Ok(()), "cannot verify first token");
466
467        println!("will derive a second token");
468
469        let message2 = b"world";
470        let keypair2 = KeyPair::new_with_rng(&mut rng);
471
472        let mut token2 = token1.append(&mut rng, &keypair2, &message2[..]);
473
474        token2.messages[1] = Vec::from(&b"you"[..]);
475
476        assert_eq!(
477            token2.verify(),
478            Err(error::Signature::InvalidSignature),
479            "second token should not be valid"
480        );
481
482        println!("will derive a third token");
483
484        let message3 = b"!!!";
485        let keypair3 = KeyPair::new_with_rng(&mut rng);
486
487        let token3 = token2.append(&mut rng, &keypair3, &message3[..]);
488
489        assert_eq!(
490            token3.verify(),
491            Err(error::Signature::InvalidSignature),
492            "cannot verify third token"
493        );
494    }*/
495}