mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-24 12:23:32 +01:00
Refactor link handshake cell type implementations to use trunnel
Unit tests still pass.
This commit is contained in:
parent
4d1a0ece5c
commit
b29c1530c7
@ -24,6 +24,7 @@
|
||||
#include "connection.h"
|
||||
#include "connection_or.h"
|
||||
#include "control.h"
|
||||
#include "link_handshake.h"
|
||||
#include "relay.h"
|
||||
#include "router.h"
|
||||
#include "routerlist.h"
|
||||
@ -1740,13 +1741,14 @@ channel_tls_process_netinfo_cell(cell_t *cell, channel_tls_t *chan)
|
||||
STATIC void
|
||||
channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
{
|
||||
tor_x509_cert_t *link_cert = NULL;
|
||||
tor_x509_cert_t *id_cert = NULL;
|
||||
tor_x509_cert_t *auth_cert = NULL;
|
||||
uint8_t *ptr;
|
||||
#define MAX_CERT_TYPE_WANTED OR_CERT_TYPE_AUTH_1024
|
||||
tor_x509_cert_t *certs[MAX_CERT_TYPE_WANTED + 1];
|
||||
int n_certs, i;
|
||||
certs_cell_t *cc = NULL;
|
||||
|
||||
int send_netinfo = 0;
|
||||
|
||||
memset(certs, 0, sizeof(certs));
|
||||
tor_assert(cell);
|
||||
tor_assert(chan);
|
||||
tor_assert(chan->conn);
|
||||
@ -1776,63 +1778,41 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
if (cell->circ_id)
|
||||
ERR("It had a nonzero circuit ID");
|
||||
|
||||
n_certs = cell->payload[0];
|
||||
ptr = cell->payload + 1;
|
||||
if (certs_cell_parse(&cc, cell->payload, cell->payload_len) < 0)
|
||||
ERR("It couldn't be parsed.");
|
||||
|
||||
n_certs = cc->n_certs;
|
||||
|
||||
for (i = 0; i < n_certs; ++i) {
|
||||
uint8_t cert_type;
|
||||
uint16_t cert_len;
|
||||
if (cell->payload_len < 3)
|
||||
goto truncated;
|
||||
if (ptr > cell->payload + cell->payload_len - 3) {
|
||||
goto truncated;
|
||||
}
|
||||
cert_type = *ptr;
|
||||
cert_len = ntohs(get_uint16(ptr+1));
|
||||
if (cell->payload_len < 3 + cert_len)
|
||||
goto truncated;
|
||||
if (ptr > cell->payload + cell->payload_len - cert_len - 3) {
|
||||
goto truncated;
|
||||
}
|
||||
if (cert_type == OR_CERT_TYPE_TLS_LINK ||
|
||||
cert_type == OR_CERT_TYPE_ID_1024 ||
|
||||
cert_type == OR_CERT_TYPE_AUTH_1024) {
|
||||
tor_x509_cert_t *cert = tor_x509_cert_decode(ptr + 3, cert_len);
|
||||
if (!cert) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received undecodable certificate in CERTS cell from %s:%d",
|
||||
safe_str(chan->conn->base_.address),
|
||||
chan->conn->base_.port);
|
||||
certs_cell_cert_t *c = certs_cell_get_certs(cc, i);
|
||||
|
||||
uint16_t cert_type = c->cert_type;
|
||||
uint16_t cert_len = c->cert_len;
|
||||
uint8_t *cert_body = certs_cell_cert_getarray_body(c);
|
||||
|
||||
if (cert_type > MAX_CERT_TYPE_WANTED)
|
||||
continue;
|
||||
|
||||
tor_x509_cert_t *cert = tor_x509_cert_decode(cert_body, cert_len);
|
||||
if (!cert) {
|
||||
log_fn(LOG_PROTOCOL_WARN, LD_PROTOCOL,
|
||||
"Received undecodable certificate in CERTS cell from %s:%d",
|
||||
safe_str(chan->conn->base_.address),
|
||||
chan->conn->base_.port);
|
||||
} else {
|
||||
if (certs[cert_type]) {
|
||||
tor_x509_cert_free(cert);
|
||||
ERR("Duplicate x509 certificate");
|
||||
} else {
|
||||
if (cert_type == OR_CERT_TYPE_TLS_LINK) {
|
||||
if (link_cert) {
|
||||
tor_x509_cert_free(cert);
|
||||
ERR("Too many TLS_LINK certificates");
|
||||
}
|
||||
link_cert = cert;
|
||||
} else if (cert_type == OR_CERT_TYPE_ID_1024) {
|
||||
if (id_cert) {
|
||||
tor_x509_cert_free(cert);
|
||||
ERR("Too many ID_1024 certificates");
|
||||
}
|
||||
id_cert = cert;
|
||||
} else if (cert_type == OR_CERT_TYPE_AUTH_1024) {
|
||||
if (auth_cert) {
|
||||
tor_x509_cert_free(cert);
|
||||
ERR("Too many AUTH_1024 certificates");
|
||||
}
|
||||
auth_cert = cert;
|
||||
} else {
|
||||
tor_x509_cert_free(cert);
|
||||
}
|
||||
certs[cert_type] = cert;
|
||||
}
|
||||
}
|
||||
ptr += 3 + cert_len;
|
||||
continue;
|
||||
|
||||
truncated:
|
||||
ERR("It ends in the middle of a certificate");
|
||||
}
|
||||
|
||||
tor_x509_cert_t *id_cert = certs[OR_CERT_TYPE_ID_1024];
|
||||
tor_x509_cert_t *auth_cert = certs[OR_CERT_TYPE_AUTH_1024];
|
||||
tor_x509_cert_t *link_cert = certs[OR_CERT_TYPE_TLS_LINK];
|
||||
|
||||
if (chan->conn->handshake_state->started_here) {
|
||||
int severity;
|
||||
if (! (id_cert && link_cert))
|
||||
@ -1881,7 +1861,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
safe_str(chan->conn->base_.address), chan->conn->base_.port);
|
||||
|
||||
chan->conn->handshake_state->id_cert = id_cert;
|
||||
id_cert = NULL;
|
||||
certs[OR_CERT_TYPE_ID_1024] = NULL;
|
||||
|
||||
if (!public_server_mode(get_options())) {
|
||||
/* If we initiated the connection and we are not a public server, we
|
||||
@ -1908,7 +1888,7 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
|
||||
chan->conn->handshake_state->id_cert = id_cert;
|
||||
chan->conn->handshake_state->auth_cert = auth_cert;
|
||||
id_cert = auth_cert = NULL;
|
||||
certs[OR_CERT_TYPE_ID_1024] = certs[OR_CERT_TYPE_AUTH_1024] = NULL;
|
||||
}
|
||||
|
||||
chan->conn->handshake_state->received_certs_cell = 1;
|
||||
@ -1922,9 +1902,10 @@ channel_tls_process_certs_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
}
|
||||
|
||||
err:
|
||||
tor_x509_cert_free(id_cert);
|
||||
tor_x509_cert_free(link_cert);
|
||||
tor_x509_cert_free(auth_cert);
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH(certs); ++i) {
|
||||
tor_x509_cert_free(certs[i]);
|
||||
}
|
||||
certs_cell_free(cc);
|
||||
#undef ERR
|
||||
}
|
||||
|
||||
@ -1943,7 +1924,7 @@ STATIC void
|
||||
channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
{
|
||||
int n_types, i, use_type = -1;
|
||||
uint8_t *cp;
|
||||
auth_challenge_cell_t *ac = NULL;
|
||||
|
||||
tor_assert(cell);
|
||||
tor_assert(chan);
|
||||
@ -1956,7 +1937,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
safe_str(chan->conn->base_.address), \
|
||||
chan->conn->base_.port, (s)); \
|
||||
connection_or_close_for_error(chan->conn, 0); \
|
||||
return; \
|
||||
goto done; \
|
||||
} while (0)
|
||||
|
||||
if (chan->conn->base_.state != OR_CONN_STATE_OR_HANDSHAKING_V3)
|
||||
@ -1969,19 +1950,17 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
ERR("We already received one");
|
||||
if (!(chan->conn->handshake_state->received_certs_cell))
|
||||
ERR("We haven't gotten a CERTS cell yet");
|
||||
if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2)
|
||||
ERR("It was too short");
|
||||
if (cell->circ_id)
|
||||
ERR("It had a nonzero circuit ID");
|
||||
|
||||
n_types = ntohs(get_uint16(cell->payload + OR_AUTH_CHALLENGE_LEN));
|
||||
if (cell->payload_len < OR_AUTH_CHALLENGE_LEN + 2 + 2*n_types)
|
||||
ERR("It looks truncated");
|
||||
if (auth_challenge_cell_parse(&ac, cell->payload, cell->payload_len) < 0)
|
||||
ERR("It was not well-formed.");
|
||||
|
||||
n_types = ac->n_methods;
|
||||
|
||||
/* Now see if there is an authentication type we can use */
|
||||
cp = cell->payload+OR_AUTH_CHALLENGE_LEN + 2;
|
||||
for (i = 0; i < n_types; ++i, cp += 2) {
|
||||
uint16_t authtype = ntohs(get_uint16(cp));
|
||||
for (i = 0; i < n_types; ++i) {
|
||||
uint16_t authtype = auth_challenge_cell_get_methods(ac, i);
|
||||
if (authtype == AUTHTYPE_RSA_SHA256_TLSSECRET)
|
||||
use_type = authtype;
|
||||
}
|
||||
@ -1992,7 +1971,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
/* If we're not a public server then we don't want to authenticate on a
|
||||
connection we originated, and we already sent a NETINFO cell when we
|
||||
got the CERTS cell. We have nothing more to do. */
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (use_type >= 0) {
|
||||
@ -2006,7 +1985,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
log_warn(LD_OR,
|
||||
"Couldn't send authenticate cell");
|
||||
connection_or_close_for_error(chan->conn, 0);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
log_info(LD_OR,
|
||||
@ -2019,9 +1998,12 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
if (connection_or_send_netinfo(chan->conn) < 0) {
|
||||
log_warn(LD_OR, "Couldn't send netinfo cell");
|
||||
connection_or_close_for_error(chan->conn, 0);
|
||||
return;
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
auth_challenge_cell_free(ac);
|
||||
|
||||
#undef ERR
|
||||
}
|
||||
|
||||
@ -2038,7 +2020,7 @@ channel_tls_process_auth_challenge_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
STATIC void
|
||||
channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
{
|
||||
uint8_t expected[V3_AUTH_FIXED_PART_LEN];
|
||||
uint8_t expected[V3_AUTH_FIXED_PART_LEN+256];
|
||||
const uint8_t *auth;
|
||||
int authlen;
|
||||
|
||||
@ -2094,11 +2076,13 @@ channel_tls_process_authenticate_cell(var_cell_t *cell, channel_tls_t *chan)
|
||||
if (authlen < V3_AUTH_BODY_LEN + 1)
|
||||
ERR("Authenticator was too short");
|
||||
|
||||
if (connection_or_compute_authenticate_cell_body(
|
||||
chan->conn, expected, sizeof(expected), NULL, 1) < 0)
|
||||
ssize_t bodylen =
|
||||
connection_or_compute_authenticate_cell_body(
|
||||
chan->conn, expected, sizeof(expected), NULL, 1);
|
||||
if (bodylen < 0 || bodylen != V3_AUTH_FIXED_PART_LEN)
|
||||
ERR("Couldn't compute expected AUTHENTICATE cell body");
|
||||
|
||||
if (tor_memneq(expected, auth, sizeof(expected)))
|
||||
if (tor_memneq(expected, auth, bodylen))
|
||||
ERR("Some field in the AUTHENTICATE cell body was not as expected");
|
||||
|
||||
{
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "entrynodes.h"
|
||||
#include "geoip.h"
|
||||
#include "main.h"
|
||||
#include "link_handshake.h"
|
||||
#include "networkstatus.h"
|
||||
#include "nodelist.h"
|
||||
#include "reasons.h"
|
||||
@ -2279,28 +2280,37 @@ connection_or_send_certs_cell(or_connection_t *conn)
|
||||
int
|
||||
connection_or_send_auth_challenge_cell(or_connection_t *conn)
|
||||
{
|
||||
var_cell_t *cell;
|
||||
uint8_t *cp;
|
||||
uint8_t challenge[OR_AUTH_CHALLENGE_LEN];
|
||||
var_cell_t *cell = NULL;
|
||||
int r = -1;
|
||||
tor_assert(conn->base_.state == OR_CONN_STATE_OR_HANDSHAKING_V3);
|
||||
|
||||
if (! conn->handshake_state)
|
||||
return -1;
|
||||
|
||||
if (crypto_rand((char*)challenge, OR_AUTH_CHALLENGE_LEN) < 0)
|
||||
return -1;
|
||||
cell = var_cell_new(OR_AUTH_CHALLENGE_LEN + 4);
|
||||
auth_challenge_cell_t *ac = auth_challenge_cell_new();
|
||||
|
||||
if (crypto_rand((char*)ac->challenge, sizeof(ac->challenge)) < 0)
|
||||
goto done;
|
||||
|
||||
auth_challenge_cell_add_methods(ac, AUTHTYPE_RSA_SHA256_TLSSECRET);
|
||||
auth_challenge_cell_set_n_methods(ac,
|
||||
auth_challenge_cell_getlen_methods(ac));
|
||||
|
||||
cell = var_cell_new(auth_challenge_cell_encoded_len(ac));
|
||||
ssize_t len = auth_challenge_cell_encode(cell->payload, cell->payload_len,
|
||||
ac);
|
||||
if (len != cell->payload_len)
|
||||
goto done;
|
||||
cell->command = CELL_AUTH_CHALLENGE;
|
||||
memcpy(cell->payload, challenge, OR_AUTH_CHALLENGE_LEN);
|
||||
cp = cell->payload + OR_AUTH_CHALLENGE_LEN;
|
||||
set_uint16(cp, htons(1)); /* We recognize one authentication type. */
|
||||
set_uint16(cp+2, htons(AUTHTYPE_RSA_SHA256_TLSSECRET));
|
||||
|
||||
connection_or_write_var_cell_to_buf(cell, conn);
|
||||
var_cell_free(cell);
|
||||
memwipe(challenge, 0, sizeof(challenge));
|
||||
r = 0;
|
||||
|
||||
return 0;
|
||||
done:
|
||||
var_cell_free(cell);
|
||||
auth_challenge_cell_free(ac);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Compute the main body of an AUTHENTICATE cell that a client can use
|
||||
@ -2327,19 +2337,18 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
crypto_pk_t *signing_key,
|
||||
int server)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
auth1_t *auth = NULL;
|
||||
auth_ctx_t *ctx = auth_ctx_new();
|
||||
int result;
|
||||
|
||||
/* assert state is reasonable XXXX */
|
||||
|
||||
if (outlen < V3_AUTH_FIXED_PART_LEN ||
|
||||
(!server && outlen < V3_AUTH_BODY_LEN))
|
||||
return -1;
|
||||
ctx->is_ed = 0;
|
||||
|
||||
ptr = out;
|
||||
auth = auth1_new();
|
||||
|
||||
/* Type: 8 bytes. */
|
||||
memcpy(ptr, "AUTH0001", 8);
|
||||
ptr += 8;
|
||||
memcpy(auth1_getarray_type(auth), "AUTH0001", 8);
|
||||
|
||||
{
|
||||
const tor_x509_cert_t *id_cert=NULL, *link_cert=NULL;
|
||||
@ -2359,12 +2368,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
server_id = server ? my_id : their_id;
|
||||
|
||||
/* Client ID digest: 32 octets. */
|
||||
memcpy(ptr, client_id, 32);
|
||||
ptr += 32;
|
||||
memcpy(auth->cid, client_id, 32);
|
||||
|
||||
/* Server ID digest: 32 octets. */
|
||||
memcpy(ptr, server_id, 32);
|
||||
ptr += 32;
|
||||
memcpy(auth->sid, server_id, 32);
|
||||
}
|
||||
|
||||
{
|
||||
@ -2378,12 +2385,10 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
}
|
||||
|
||||
/* Server log digest : 32 octets */
|
||||
crypto_digest_get_digest(server_d, (char*)ptr, 32);
|
||||
ptr += 32;
|
||||
crypto_digest_get_digest(server_d, (char*)auth->slog, 32);
|
||||
|
||||
/* Client log digest : 32 octets */
|
||||
crypto_digest_get_digest(client_d, (char*)ptr, 32);
|
||||
ptr += 32;
|
||||
crypto_digest_get_digest(client_d, (char*)auth->clog, 32);
|
||||
}
|
||||
|
||||
{
|
||||
@ -2396,49 +2401,79 @@ connection_or_compute_authenticate_cell_body(or_connection_t *conn,
|
||||
freecert = tor_tls_get_peer_cert(conn->tls);
|
||||
cert = freecert;
|
||||
}
|
||||
if (!cert)
|
||||
return -1;
|
||||
memcpy(ptr, tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
|
||||
if (!cert) {
|
||||
log_warn(LD_OR, "Unable to find cert when making AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(auth->scert,
|
||||
tor_x509_cert_get_cert_digests(cert)->d[DIGEST_SHA256], 32);
|
||||
|
||||
if (freecert)
|
||||
tor_x509_cert_free(freecert);
|
||||
ptr += 32;
|
||||
}
|
||||
|
||||
/* HMAC of clientrandom and serverrandom using master key : 32 octets */
|
||||
tor_tls_get_tlssecrets(conn->tls, ptr);
|
||||
ptr += 32;
|
||||
|
||||
tor_assert(ptr - out == V3_AUTH_FIXED_PART_LEN);
|
||||
|
||||
if (server)
|
||||
return V3_AUTH_FIXED_PART_LEN; // ptr-out
|
||||
tor_tls_get_tlssecrets(conn->tls, auth->tlssecrets);
|
||||
|
||||
/* 8 octets were reserved for the current time, but we're trying to get out
|
||||
* of the habit of sending time around willynilly. Fortunately, nothing
|
||||
* checks it. That's followed by 16 bytes of nonce. */
|
||||
crypto_rand((char*)ptr, 24);
|
||||
ptr += 24;
|
||||
crypto_rand((char*)auth->rand, 24);
|
||||
|
||||
tor_assert(ptr - out == V3_AUTH_BODY_LEN);
|
||||
|
||||
if (!signing_key)
|
||||
return V3_AUTH_BODY_LEN; // ptr - out
|
||||
|
||||
{
|
||||
int siglen;
|
||||
char d[32];
|
||||
crypto_digest256(d, (char*)out, ptr-out, DIGEST_SHA256);
|
||||
siglen = crypto_pk_private_sign(signing_key,
|
||||
(char*)ptr, outlen - (ptr-out),
|
||||
d, 32);
|
||||
if (siglen < 0)
|
||||
return -1;
|
||||
|
||||
ptr += siglen;
|
||||
tor_assert(ptr <= out+outlen);
|
||||
return (int)(ptr - out);
|
||||
ssize_t len;
|
||||
if ((len = auth1_encode(out, outlen, auth, ctx)) < 0) {
|
||||
log_warn(LD_OR, "Unable to encode signed part of AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (server) {
|
||||
auth1_t *tmp = NULL;
|
||||
ssize_t len2 = auth1_parse(&tmp, out, len, ctx);
|
||||
if (!tmp) {
|
||||
log_warn(LD_OR, "Unable to parse signed part of AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
result = (int) (tmp->end_of_fixed_part - out);
|
||||
auth1_free(tmp);
|
||||
if (len2 != len) {
|
||||
log_warn(LD_OR, "Mismatched length when re-parsing AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (signing_key) {
|
||||
auth1_setlen_sig(auth, crypto_pk_keysize(signing_key));
|
||||
|
||||
char d[32];
|
||||
crypto_digest256(d, (char*)out, len, DIGEST_SHA256);
|
||||
int siglen = crypto_pk_private_sign(signing_key,
|
||||
(char*)auth1_getarray_sig(auth),
|
||||
auth1_getlen_sig(auth),
|
||||
d, 32);
|
||||
if (siglen < 0) {
|
||||
log_warn(LD_OR, "Unable to sign AUTH1 data.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auth1_setlen_sig(auth, siglen);
|
||||
|
||||
len = auth1_encode(out, outlen, auth, ctx);
|
||||
if (len < 0) {
|
||||
log_warn(LD_OR, "Unable to encode signed AUTH1 data.");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
result = (int) len;
|
||||
goto done;
|
||||
|
||||
err:
|
||||
result = -1;
|
||||
done:
|
||||
auth1_free(auth);
|
||||
auth_ctx_free(ctx);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Send an AUTHENTICATE cell on the connection <b>conn</b>. Return 0 on
|
||||
|
Loading…
Reference in New Issue
Block a user