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_adhoc_template_KeySpecifier;
16

            
17
use derive_adhoc::Adhoc;
18
use derive_more::Constructor;
19

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

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

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

            
83
impl HsClientSecretKeys {
84
    /// Create a new `HsClientSecretKeys`, for making unauthenticated connections
85
    ///
86
    /// Creates a `HsClientSecretKeys` which has no actual keys,
87
    /// so will make connections to hidden services
88
    /// without any Tor-protocol-level client authentication.
89
    pub fn none() -> Self {
90
        Self::default()
91
    }
92

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

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

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

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

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

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

            
147
#[derive(Adhoc, PartialEq, Debug, Constructor)]
148
#[derive_adhoc(KeySpecifier)]
149
#[adhoc(prefix = "client")]
150
#[adhoc(role = "KS_hsc_desc_enc")]
151
#[adhoc(summary = "Descriptor decryption key")]
152
/// A key for deriving keys for decrypting HS descriptors (KS_hsc_desc_enc).
153
pub struct HsClientDescEncKeypairSpecifier {
154
    /// The hidden service this authorization key is for.
155
    pub(crate) hs_id: HsId,
156
}