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
|
//! Authentication for RpcConn.
use serde::{Deserialize, Serialize};
use tor_rpc_connect::auth::cookie::{Cookie, CookieAuthMac, CookieAuthNonce};
use crate::msgs::{ObjectId, request::Request};
use super::{ConnectError, RpcConn};
/// Arguments to an `auth:authenticate` request.
#[derive(Serialize, Debug)]
struct AuthParams<'a> {
/// The authentication scheme we are using.
scheme: &'a str,
}
/// Response to an `auth:authenticate` or `auth:cookie_continue` request.
#[derive(Deserialize, Debug)]
struct AuthenticatedReply {
/// A session object that we use to access the rest of Arti's functionality.
session: ObjectId,
}
/// Arguments to an `auth:cookie_begin` request.
#[derive(Serialize, Debug)]
struct CookieBeginParams {
/// Client-selected nonce; used while the server is proving knowledge of the cookie.
client_nonce: CookieAuthNonce,
}
/// Response to an `auth:cookie_begin` request.
#[derive(Deserialize, Debug)]
struct CookieBeginReply {
/// Temporary ID to use while authenticating.
cookie_auth: ObjectId,
/// Address that the server thinks it's listening on.
server_addr: String,
/// MAC returned by the server to prove knowledge of the cookie.
server_mac: CookieAuthMac,
/// Server-selected nonce to use while we prove knowledge of the cookie.
server_nonce: CookieAuthNonce,
}
/// Arguments to an `auth:cookie_begin` request.
#[derive(Serialize, Debug)]
struct CookieContinueParams {
/// Make to prove our knowledge of the cookie.
client_mac: CookieAuthMac,
}
impl RpcConn {
/// Try to negotiate "inherent" authentication, using the provided scheme name.
///
/// (Inherent authentication is available whenever the client proves that they
/// are authorized through being able to connect to Arti at all. Examples
/// include connecting to a unix domain socket, and an in-process Arti implementation.)
pub(crate) fn authenticate_inherent(
&self,
scheme_name: &str,
) -> Result<ObjectId, ConnectError> {
let r: Request<AuthParams> = Request::new(
ObjectId::connection_id(),
"auth:authenticate",
AuthParams {
scheme: scheme_name,
},
);
let authenticated: AuthenticatedReply = self
.execute_internal(&r.encode()?)?
.map_err(ConnectError::AuthenticationFailed)?;
Ok(authenticated.session)
}
/// Try to negotiate "cookie" authentication, using the provided cookie and server address.
pub(crate) fn authenticate_cookie(
&self,
cookie: &Cookie,
server_addr: &str,
) -> Result<ObjectId, ConnectError> {
// This protocol is documented in `rpc-cookie-sketch.md`.
let client_nonce = CookieAuthNonce::new(&mut rand::rng());
let cookie_begin: Request<CookieBeginParams> = Request::new(
ObjectId::connection_id(),
"auth:cookie_begin",
CookieBeginParams {
client_nonce: client_nonce.clone(),
},
);
let reply: CookieBeginReply = self
.execute_internal(&cookie_begin.encode()?)?
.map_err(ConnectError::AuthenticationFailed)?;
if server_addr != reply.server_addr {
return Err(ConnectError::ServerAddressMismatch {
ours: server_addr.into(),
theirs: reply.server_addr,
});
}
let expected_server_mac =
cookie.server_mac(&client_nonce, &reply.server_nonce, server_addr);
if reply.server_mac != expected_server_mac {
return Err(ConnectError::CookieMismatch);
}
let client_mac = cookie.client_mac(&client_nonce, &reply.server_nonce, server_addr);
let cookie_auth_obj = reply.cookie_auth.clone();
let cookie_continue = Request::new(
cookie_auth_obj.clone(),
"auth:cookie_continue",
CookieContinueParams { client_mac },
);
let authenticated: AuthenticatedReply = self
.execute_internal(&cookie_continue.encode()?)?
.map_err(ConnectError::AuthenticationFailed)?;
// Drop the cookie_auth_obj: we don't need it now that we have authenticated.
self.release_obj(cookie_auth_obj)?;
Ok(authenticated.session)
}
}
|