1
//! Hidden service (onion service) client key management functionality
2

            
3
// TODO HS what layer should be responsible for finding and dispatching keys?
4
// I think it should be as high as possible, so keys should be passed into
5
// the hs connector for each connection.  Otherwise there would have to be an
6
// HsKeyProvider trait here, and error handling gets complicated.
7

            
8
use std::fmt::{self, Debug};
9
use std::hash::{Hash, Hasher};
10
use std::sync::Arc;
11

            
12
#[allow(deprecated)]
13
use tor_hscrypto::pk::HsClientIntroAuthKeypair;
14
use tor_hscrypto::pk::{HsClientDescEncKeypair, HsId};
15
use tor_keymgr::{derive_deftly_template_KeySpecifier, CTorPath};
16

            
17
use derive_deftly::Deftly;
18
use derive_more::Constructor;
19
use tor_keymgr::KeySpecifier;
20

            
21
/// Service discovery keys (if any) to use when connecting to a specific onion service.
22
///
23
/// Represents a possibly empty subset of the following keys:
24
///  * `KS_hsc_desc_enc`, [`HsClientDescEncKeypair`]
25
///  * `KS_hsc_intro_auth`, [`HsClientIntroAuthKeypair`]
26
///
27
/// `HsClientSecretKeys` is constructed with a `Builder`:
28
/// use `ClientSecretKeysBuilder::default()`,
29
/// optionally call setters, and then call `build()`.
30
///
31
/// For client connections to share circuits and streams,
32
/// call `build` only once.
33
/// Different calls to `build` yield `HsClientSecretKeys` values
34
/// which won't share HS circuits, streams, or authentication.
35
///
36
/// Conversely, `Clone`s of an `HsClientSecretKeys` *can* share circuits.
37
//
38
/// All [empty](HsClientSecretKeys::is_empty) `HsClientSecretKeys`
39
/// (for example, from [`:none()`](HsClientSecretKeys::none))
40
/// *can* share circuits.
41
//
42
// TODO HS some way to read these from files or something!
43
//
44
// TODO HS: some of our APIs take Option<HsClientSecretKeys>.
45
// But HsClientSecretKeys is can be empty, so we should remove the `Option`.
46
#[derive(Clone, Default)]
47
pub struct HsClientSecretKeys {
48
    /// The actual keys
49
    ///
50
    /// This is compared and hashed by the Arc pointer value.
51
    /// We don't want to implement key comparison by comparing secret key values.
52
    pub(crate) keys: Arc<ClientSecretKeyValues>,
53
}
54

            
55
impl Debug for HsClientSecretKeys {
56
40
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57
40
        // TODO derive this?
58
40
        let mut d = f.debug_tuple("HsClientSecretKeys");
59
40
        d.field(&Arc::as_ptr(&self.keys));
60
40
        self.keys
61
40
            .ks_hsc_desc_enc
62
40
            .as_ref()
63
40
            .map(|_| d.field(&"<desc_enc>"));
64
40
        self.keys
65
40
            .ks_hsc_intro_auth
66
40
            .as_ref()
67
41
            .map(|_| d.field(&"<intro_uath>"));
68
40
        d.finish()
69
40
    }
70
}
71

            
72
impl PartialEq for HsClientSecretKeys {
73
28
    fn eq(&self, other: &Self) -> bool {
74
28
        self.is_empty() && other.is_empty() || Arc::ptr_eq(&self.keys, &other.keys)
75
28
    }
76
}
77
impl Eq for HsClientSecretKeys {}
78
impl Hash for HsClientSecretKeys {
79
    fn hash<H: Hasher>(&self, state: &mut H) {
80
        Arc::as_ptr(&self.keys).hash(state);
81
    }
82
}
83

            
84
impl HsClientSecretKeys {
85
    /// Create a new `HsClientSecretKeys`, for making connections to services
86
    /// that are not running in restricted discovery mode.
87
    ///
88
    /// Creates a `HsClientSecretKeys` which has no actual keys,
89
    /// so will not use a descriptor cookie when decrypting the second layer
90
    /// of descriptor encryption.
91
    pub fn none() -> Self {
92
        Self::default()
93
    }
94

            
95
    /// Tests whether this `HsClientSecretKeys` actually contains any keys
96
54
    pub fn is_empty(&self) -> bool {
97
54
        // TODO derive this.  For now, we deconstruct it to prove we check all the fields.
98
54
        let ClientSecretKeyValues {
99
54
            ks_hsc_desc_enc,
100
54
            ks_hsc_intro_auth,
101
54
        } = &*self.keys;
102
54
        ks_hsc_desc_enc.is_none() && ks_hsc_intro_auth.is_none()
103
54
    }
104
}
105

            
106
/// Client secret key values
107
///
108
/// Skip the whole builder pattern derivation, etc. - the types are just the same
109
type ClientSecretKeyValues = HsClientSecretKeysBuilder;
110

            
111
/// Builder for `HsClientSecretKeys`
112
#[derive(Default, Debug)]
113
pub struct HsClientSecretKeysBuilder {
114
    /// Possibly, a key that is used to decrypt a descriptor.
115
    pub(crate) ks_hsc_desc_enc: Option<HsClientDescEncKeypair>,
116

            
117
    /// Possibly, a key that is used to authenticate while introducing.
118
    #[allow(deprecated)]
119
    pub(crate) ks_hsc_intro_auth: Option<HsClientIntroAuthKeypair>,
120
}
121

            
122
// TODO derive these setters
123
//
124
// TODO HS is this what we want for an API?  We need *some* API.
125
// This is a bit like config but we probably don't want to
126
// feed secret key material through config-rs, etc.
127
impl HsClientSecretKeysBuilder {
128
    /// Provide a descriptor decryption key
129
2
    pub fn ks_hsc_desc_enc(&mut self, ks: HsClientDescEncKeypair) -> &mut Self {
130
2
        self.ks_hsc_desc_enc = Some(ks);
131
2
        self
132
2
    }
133
    /// Provide an introduction authentication key
134
    #[deprecated]
135
    #[allow(deprecated)]
136
2
    pub fn ks_hsc_intro_auth(&mut self, ks: HsClientIntroAuthKeypair) -> &mut Self {
137
2
        self.ks_hsc_intro_auth = Some(ks);
138
2
        self
139
2
    }
140

            
141
    /// Convert these
142
12
    pub fn build(self) -> Result<HsClientSecretKeys, tor_config::ConfigBuildError> {
143
12
        Ok(HsClientSecretKeys {
144
12
            keys: Arc::new(self),
145
12
        })
146
12
    }
147
}
148

            
149
#[derive(Deftly, PartialEq, Debug, Constructor)]
150
#[derive_deftly(KeySpecifier)]
151
#[deftly(prefix = "client")]
152
#[deftly(role = "KS_hsc_desc_enc")]
153
#[deftly(summary = "Descriptor decryption key")]
154
#[deftly(ctor_path = "client_desc_enc_keypair_key_specifier_ctor_path")]
155
/// A key for deriving keys for decrypting HS descriptors (KS_hsc_desc_enc).
156
pub struct HsClientDescEncKeypairSpecifier {
157
    /// The hidden service this authorization key is for.
158
    pub(crate) hs_id: HsId,
159
}
160
/// The `CTorPath` of HsClientDescEncKeypairSpecifier
161
fn client_desc_enc_keypair_key_specifier_ctor_path(
162
    spec: &HsClientDescEncKeypairSpecifier,
163
) -> CTorPath {
164
    CTorPath::ClientHsDescEncKey(spec.hs_id)
165
}