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
use std::collections::BTreeMap;
use crate::{
error,
AvailableHeaders,
Error,
HeaderMap,
JsonValue,
Result,
Verifier,
};
pub struct Message {
pub header : HeaderMap,
pub payload : Vec<u8>,
}
impl Message {
pub fn decode_parts(header: &[u8], payload: &[u8]) -> Result<Self> {
let header = base64::decode_config(header, base64::URL_SAFE_NO_PAD)?;
let payload = base64::decode_config(payload, base64::URL_SAFE_NO_PAD)?;
let header: BTreeMap<String, JsonValue> = serde_json::from_slice(&header)?;
Ok(Self{header, payload})
}
}
pub fn split_encoded_parts(data: &[u8]) -> Result<CompactSerializedParts> {
let mut parts = data.splitn(4, |&c| c == b'.');
let header = parts.next().ok_or_else(|| error::InvalidMessage("encoded message does not contain a header".to_string()))?;
let payload = parts.next().ok_or_else(|| error::InvalidMessage("encoded message does not contain a payload".to_string()))?;
let signature = parts.next().ok_or_else(|| error::InvalidMessage("encoded message does not contain a signature".to_string()))?;
if parts.next().is_some() {
return Err(Error::from(error::InvalidMessage("encoded message contains an additional field after the signature".to_string())));
}
Ok(CompactSerializedParts{header, payload, signature})
}
pub fn decode_and_verify(data: &[u8], mut verifier: impl Verifier) -> Result<Message> {
let parts = split_encoded_parts(data)?;
let (message, signature) = parts.decode()?;
verifier.verify(AvailableHeaders::ProtectedOnly(&message.header), parts.header, parts.payload, &signature)?;
Ok(message)
}
pub struct CompactSerializedParts<'a> {
pub header: &'a [u8],
pub payload: &'a [u8],
pub signature: &'a [u8],
}
impl<'a> CompactSerializedParts<'a> {
pub fn decode(&self) -> Result<(Message, Vec<u8>)> {
let message = Message::decode_parts(self.header, self.payload)?;
let signature = base64::decode_config(self.signature, base64::URL_SAFE_NO_PAD)?;
Ok((message, signature))
}
}