summaryrefslogtreecommitdiffstats
path: root/vendor/pasetors/src/common.rs
blob: b95583f621f6fc038fb33152fc564daf267bf9c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::errors::Error;
use crate::token::private::Purpose;
use crate::token::UntrustedToken;
use crate::version::private::Version;
use alloc::string::String;
use alloc::vec::Vec;
use ct_codecs::{Base64UrlSafeNoPadding, Decoder, Encoder};
use subtle::ConstantTimeEq;

/// Encode bytes with Base64 URL-safe and no padding.
pub(crate) fn encode_b64<T: AsRef<[u8]>>(bytes: T) -> Result<String, Error> {
    let inlen = bytes.as_ref().len();
    let mut buf = vec![0u8; Base64UrlSafeNoPadding::encoded_len(inlen)?];

    let ret: String = Base64UrlSafeNoPadding::encode_to_str(&mut buf, bytes)?.into();

    Ok(ret)
}

/// Decode string with Base64 URL-safe and no padding.
pub(crate) fn decode_b64<T: AsRef<[u8]>>(encoded: T) -> Result<Vec<u8>, Error> {
    let inlen = encoded.as_ref().len();
    // We can use encoded len here, even if it returns more than needed,
    // because ct-codecs allows this.
    let mut buf = vec![0u8; Base64UrlSafeNoPadding::encoded_len(inlen)?];

    let ret: Vec<u8> = Base64UrlSafeNoPadding::decode(&mut buf, encoded, None)?.into();

    Ok(ret)
}

/// If a footer is present, this is validated against the supplied.
pub(crate) fn validate_footer_untrusted_token<T: Purpose<V>, V: Version>(
    token: &UntrustedToken<T, V>,
    footer: Option<&[u8]>,
) -> Result<(), Error> {
    // A known footer was supplied for comparison.
    if let Some(known_footer) = footer {
        if token.untrusted_footer().is_empty() {
            // If one was supplied, one must exist in the untrusted.
            return Err(Error::TokenValidation);
        }

        if !bool::from(known_footer.ct_eq(token.untrusted_footer())) {
            return Err(Error::TokenValidation);
        }
    }

    Ok(())
}

#[cfg(test)]
pub(crate) mod tests {
    use alloc::string::String;
    use alloc::vec::Vec;
    use serde::{Deserialize, Serialize};
    use serde_json::Value;

    #[allow(non_snake_case)]
    #[derive(Serialize, Deserialize, Debug)]
    pub(crate) struct TestFile {
        pub(crate) name: String,
        pub(crate) tests: Vec<PasetoTest>,
    }

    #[allow(non_snake_case)]
    #[derive(Serialize, Deserialize, Debug)]
    pub(crate) struct PasetoTest {
        pub(crate) name: String,
        #[serde(rename(deserialize = "expect-fail"))]
        pub(crate) expect_fail: bool,
        pub(crate) key: Option<String>,
        pub(crate) nonce: Option<String>,
        #[serde(rename(deserialize = "public-key"))]
        pub(crate) public_key: Option<String>,
        #[serde(rename(deserialize = "secret-key"))]
        pub(crate) secret_key: Option<String>,
        #[serde(rename(deserialize = "secret-key-seed"))]
        pub(crate) secret_key_seed: Option<String>,
        #[serde(rename(deserialize = "public-key-pem"))]
        pub(crate) public_key_pem: Option<String>,
        #[serde(rename(deserialize = "secret-key-pem"))]
        pub(crate) secret_key_pem: Option<String>,
        pub(crate) token: String,
        pub(crate) payload: Option<Value>,
        pub(crate) footer: String,
        #[serde(rename(deserialize = "implicit-assertion"))]
        pub(crate) implicit_assertion: String,
    }

    #[allow(non_snake_case)]
    #[derive(Serialize, Deserialize, Debug)]
    pub(crate) struct Payload {
        pub(crate) data: String,
        pub(crate) exp: String,
    }
}