aboutsummaryrefslogtreecommitdiff
path: root/crates/tor-hsservice/src/svc.rs
blob: 6f8d868a9b258222ce26ed6b128befcc41329b02 (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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//! Principal types for onion services.

mod netdir;

use std::{
    collections::HashMap,
    sync::{Arc, Mutex},
    time::Instant,
};

use tor_circmgr::hspool::HsCircPool;
use tor_config::ReconfigureError;
use tor_error::Bug;
use tor_hscrypto::pk::HsBlindIdKey;
use tor_keymgr::KeyMgr;
use tor_linkspec::RelayIds;
use tor_llcrypto::pk::curve25519;
use tor_netdir::NetDirProvider;
use tor_rtcompat::Runtime;

use crate::OnionServiceStatus;
use crate::StartupError;

pub(crate) mod ipt_establish;
pub(crate) mod publish;
pub(crate) mod rend_handshake;

/// Convenience alias for link specifiers of an intro point
pub(crate) type LinkSpecs = Vec<tor_linkspec::EncodedLinkSpec>;

/// Convenient type alias for an ntor public key
// TODO HSS maybe this should be `tor_proto::crypto::handshake::ntor::NtorPublicKey`?
type NtorPublicKey = curve25519::PublicKey;

/// A handle to an instance of an onion service.
//
// TODO HSS: Write more.
//
// (APIs should return Arc<OnionService>)
//
// NOTE: This might not need to be parameterized on Runtime; if we can avoid it
// without too much trouble,  we should.
pub struct OnionService<R: Runtime> {
    /// The mutable implementation details of this onion service.
    inner: Mutex<SvcInner<R>>,
}

/// Implementation details for an onion service.
struct SvcInner<R: Runtime> {
    /// Configuration information about this service.
    ///
    /// TODO HSS: Authorized client public keys might be here, or they might be in a
    /// separate structure.
    config: crate::OnionServiceConfig,

    /// A netdir provider to use in finding our directories and choosing our
    /// introduction points.
    netdir_provider: Arc<dyn NetDirProvider>,

    /// A keymgr used to look up our keys and store new medium-term keys.
    keymgr: Arc<KeyMgr>,

    /// A circuit pool to use in making circuits to our introduction points,
    /// HsDirs, and rendezvous points.
    //
    // TODO hss: Maybe we can make a trait that only gives a minimal "build a
    // circuit" API from CircMgr, so that we can have this be a dyn reference
    // too?
    circmgr: Arc<HsCircPool<R>>,

    /// Authentication information for descriptor encryption.
    ///
    /// (Our protocol defines two kinds of client authentication: in the first
    /// type, we encrypt the descriptor to client public keys.  In the second,
    /// we require authentictaion as part of the `INTRODUCE2` message. Only the
    /// first type has ever been implemented.)
    encryption_auth: Option<DescEncryptionAuth>,

    /// Private keys in actual use for this onion service.
    //
    // TODO hss: This will need heavy refactoring.
    //
    // TODO hss: There's a separate blinded ID, certificate, and signing key
    // for each active time period.
    keys: (),

    /// Status for each active introduction point for this onion service.
    //
    // TODO HSS: This might want to be a generational arena, and might want to be
    // use a different map for each descriptor epoch. Feel free to refactor!
    intro_points: Vec<IntroPointState>,

    /// Status for our onion service descriptor
    desc_status: DescUploadHistory,
}

/// Information about encryption-based authentication.

struct DescEncryptionAuth {
    /// A list of the public keys for which we should encrypt our
    /// descriptor.
    //
    // TODO HSS: maybe this should instead be a place to find the keys, so that
    // we can reload them on change?
    //
    // TODO HSS: maybe this should instead be part of our configuration
    keys: Vec<curve25519::PublicKey>,
}

/// Current history and status for our descriptor uploads.
///
// TODO HSS: Remember, there are *multiple simultaneous variants* of our
// descriptor. we will probably need to make this structure different.
struct DescUploadHistory {
    /// When did we last rebuild our descriptors?
    last_rebuilt: Instant,

    /// Each current descriptor that we need to try to maintain and upload.
    descriptors: HashMap<HsBlindIdKey, String>,

    /// Status of uploading each descriptor to each HsDir.
    //
    // Note that is possible that multiple descriptors will need to be uploaded
    // to the same HsDir.  When this happens, we MUST use separate circuits to
    // upload them.
    target_status: HashMap<HsBlindIdKey, HashMap<RelayIds, RetryState>>,
}

/// State of uploading a single descriptor
struct RetryState {
    // TODO HSS: implement this as needed.
}

/// State of a current introduction point.
struct IntroPointState {
    // TODO HSS: use diziet's structures  from `hssvc-ipt-algorithms.md` once those are more settled.
}

impl<R: Runtime> OnionService<R> {
    /// Create (but do not launch) a new onion service.
    pub fn new(config: (), netdir_provider: (), circmgr: ()) -> Self {
        todo!(); // TODO hss
    }

    /// Change the configuration of this onion service.
    ///
    /// (Not everything can be changed here. At the very least we'll need to say
    /// that the identity of a service is fixed. We might want to make the
    /// storage  backing this, and the anonymity status, unchangeable.)
    pub fn reconfigure(&self, new_config: ()) -> Result<(), ReconfigureError> {
        todo!() // TODO hss
    }

    /// Tell this onion service about some new short-term keys it can use.
    pub fn add_keys(&self, keys: ()) -> Result<(), Bug> {
        todo!() // TODO hss
    }

    /// Return the current status of this onion service.
    pub fn status(&self) -> OnionServiceStatus {
        todo!() // TODO hss
    }
    // TODO hss let's also have a function that gives you a stream of Status
    // changes?  Or use a publish-based watcher?

    /// Tell this onion service to begin running.
    //
    // TODO HSS: Probably return an `impl Stream<RendRequest>`.
    pub fn launch(&self) -> Result<(), StartupError> {
        todo!() // TODO hss

        // This needs to launch at least the following tasks:
        //
        // - If we decide to use separate disk-based key provisioning, a task to
        //   monitor our keys directory.
        // - If we own our identity key, a task to generate per-period sub-keys as
        //   needed.
        // - A task to make sure that we have enough introduction point circuits
        //   at all times, and launch new ones as needed.
        // - A task to see whether we have an up-to-date descriptor uploaded for
        //   each supported time period to every HsDir listed for us in the
        //   current directory, and if not, regenerate and upload our descriptor
        //   as needed.
        // - A task to receive introduction requests from our introduction
        //   points, decide whether to answer them, and if so launch a new
        //   rendezvous task to:
        //    - finish the cryptographic handshake
        //    - build a circuit to the rendezvous point
        //    - Send the RENDEZVOUS1 reply
        //    - Add a virtual hop to the rendezvous circuit
        //    - Launch a new task to handle BEGIN requests on the rendezvous
        //      circuit, using our StreamHandler.
    }

    /// Tell  this onion service to stop running.  
    ///
    /// It can be restarted with launch().
    ///
    /// You can also shut down an onion service completely by dropping the last
    /// Clone of it.
    pub fn stop(&self) {
        todo!() // TODO hss
    }
}