disco_rs/
builder.rs

1/*
2    Copyright David Huseby, All Rights Reserved.
3    SPDX-License-Identifier: Apache-2.0
4*/
5use crate::{
6    channel::{Channel, ChannelDuplex, ChannelRole},
7    error::{BuilderError, Error},
8    handshake::HandshakeState,
9    key::{KeyAgreement, KeyGenerator, KeyType},
10    nonce::NonceGenerator,
11    params::Params,
12    prologue::Prologue,
13    session::Session,
14    tag::{Tag, TaggedData},
15    transport::TransportOrder,
16};
17use core::marker::PhantomData;
18use strobe_rs::{SecParam, Strobe};
19
20/// Generates a [`HandshakeState`] and also validates that all of the
21/// prerequisites for the given parameters are satisfied.
22pub struct Builder<K, PG, NG, T, N, P, S, SS>
23where
24    K: KeyType + KeyGenerator<T, P, S> + KeyAgreement<T, P, S, SS>,
25    PG: Prologue,
26    NG: NonceGenerator<T, N>,
27    T: Tag,
28    N: TaggedData<T>,
29    P: TaggedData<T>,
30    S: TaggedData<T>,
31    SS: TaggedData<T>,
32{
33    /// Disco params
34    params: Params<K, T, P, S, SS>,
35    /// Protocol prologue
36    prologue: PG,
37    /// Nonce generator
38    nonce_generator: NG,
39    /// Local static secret key
40    local_static_secret_key: S,
41    /// Local static public key
42    local_static_public_key: P,
43    /// Local ephemeral secret key
44    local_ephemeral_secret_key: S,
45    /// Local ephemeral public key
46    local_ephemeral_public_key: P,
47    /// Remote ephemeral public key
48    remote_static_public_key: P,
49    /// Pre-shared key
50    pre_shared_key: SS,
51    /// Message delivery order
52    msg_order: TransportOrder,
53    // phantom marker
54    _t: PhantomData<T>,
55    _n: PhantomData<N>,
56}
57
58impl<K, PG, NG, T, N, P, S, SS> Builder<K, PG, NG, T, N, P, S, SS>
59where
60    K: KeyType + KeyGenerator<T, P, S> + KeyAgreement<T, P, S, SS>,
61    PG: Prologue,
62    NG: NonceGenerator<T, N>,
63    T: Tag,
64    N: TaggedData<T>,
65    P: TaggedData<T>,
66    S: TaggedData<T>,
67    SS: TaggedData<T>,
68{
69    /// Construct a new builder from DiscoParams
70    pub fn new(params: &Params<K, T, P, S, SS>, nonce_generator: &NG) -> Self {
71        Builder {
72            params: params.clone(),
73            prologue: PG::default(),
74            nonce_generator: nonce_generator.clone(),
75            local_static_secret_key: S::default(),
76            local_static_public_key: P::default(),
77            local_ephemeral_secret_key: S::default(),
78            local_ephemeral_public_key: P::default(),
79            remote_static_public_key: P::default(),
80            pre_shared_key: SS::default(),
81            msg_order: TransportOrder::InOrder,
82            _t: PhantomData,
83            _n: PhantomData,
84        }
85    }
86
87    /// Add prologue byte sequence that both parties want to confirm is identical
88    pub fn with_prologue(mut self, data: &PG) -> Self {
89        self.prologue = data.clone();
90        self
91    }
92
93    /// Add a local static secret key
94    pub fn local_static_secret_key(mut self, key: &S) -> Self {
95        self.local_static_secret_key = key.clone();
96        self
97    }
98
99    /// Add a local static public key
100    pub fn local_static_public_key(mut self, key: &P) -> Self {
101        self.local_static_public_key = key.clone();
102        self
103    }
104
105    /// Add a local ephemeral secret key
106    pub fn local_ephemeral_secret_key(mut self, key: &S) -> Self {
107        self.local_ephemeral_secret_key = key.clone();
108        self
109    }
110
111    /// Add a local ephemeral public key
112    pub fn local_ephemeral_public_key(mut self, key: &P) -> Self {
113        self.local_ephemeral_public_key = key.clone();
114        self
115    }
116
117    /// Add a remote static public key
118    pub fn remote_static_public_key(mut self, key: &P) -> Self {
119        self.remote_static_public_key = key.clone();
120        self
121    }
122
123    /// Add a pre-shared key
124    pub fn pre_shared_key(mut self, key: &SS) -> Self {
125        self.pre_shared_key = key.clone();
126        self
127    }
128
129    /// Create strobe states that can handle out-of-order messages
130    pub fn msg_order(mut self, order: &TransportOrder) -> Self {
131        self.msg_order = *order;
132        self
133    }
134
135    /// Build an initiator disco session
136    pub fn build_initiator(self) -> Result<Session<K, PG, NG, T, N, P, S, SS>, Error> {
137        self.build(&ChannelRole::Initiator)
138    }
139
140    /// Build a responder disco session
141    pub fn build_responder(self) -> Result<Session<K, PG, NG, T, N, P, S, SS>, Error> {
142        self.build(&ChannelRole::Responder)
143    }
144
145    /// Construct the disco session
146    pub fn build(self, role: &ChannelRole) -> Result<Session<K, PG, NG, T, N, P, S, SS>, Error> {
147        if self.local_static_secret_key.get_tag().get_data_length() == 0
148            && self.params.handshake.needs_local_static_key(role)
149        {
150            return Err(Error::Builder(BuilderError::MissingLocalSecretKey));
151        }
152
153        if self.remote_static_public_key.get_tag().get_data_length() == 0
154            && self.params.handshake.needs_remote_static_key(role)
155        {
156            return Err(Error::Builder(BuilderError::MissingRemotePublicKey));
157        }
158
159        if self.pre_shared_key.get_tag().get_data_length() == 0
160            && self.params.handshake.needs_pre_shared_key(role)
161        {
162            return Err(Error::Builder(BuilderError::MissingPreSharedKey));
163        }
164
165        // ยง5.3.1 InitializeSymmetric(protocol_name)
166        let strobe = Strobe::new(format!("{}", self.params).as_bytes(), SecParam::B256);
167
168        // create our handshake state
169        let hs = HandshakeState::new(self.params.handshake, role, &ChannelDuplex::Full);
170
171        // create our channel
172        let channel = Channel::new(&strobe, &hs, &self.nonce_generator, self.msg_order, false);
173
174        Ok(Session::Handshake {
175            params: self.params,
176            channel,
177            prologue: self.prologue,
178            sp: self.local_static_public_key,
179            ss: self.local_static_secret_key,
180            ep: self.local_ephemeral_public_key,
181            es: self.local_ephemeral_secret_key,
182            rs: self.remote_static_public_key,
183            re: P::default(),
184            psk: self.pre_shared_key,
185            prf: [0u8; 32],
186        })
187    }
188}