From: Nick Mathewson Date: Wed, 28 May 2025 19:53:34 +0000 (-0400) Subject: relay_crypto: Implement support for CGO. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8bdb2f03f7cf43a797bb7f8c8e2d3c83e8136e80;p=thirdparty%2Ftor.git relay_crypto: Implement support for CGO. --- diff --git a/src/core/crypto/relay_crypto.c b/src/core/crypto/relay_crypto.c index e6e9e6d8e5..ea3a0cebc2 100644 --- a/src/core/crypto/relay_crypto.c +++ b/src/core/crypto/relay_crypto.c @@ -22,12 +22,11 @@ #include "core/or/or_circuit_st.h" #include "core/or/origin_circuit_st.h" -/* TODO CGO: This file will be largely incorrect when we have - * CGO crypto. */ - // XXXX: Remove this definition once I'm done refactoring. #define pvt_crypto crypto_crypt_path_private_field +#define CGO_AES_BITS 128 + /** Return the sendme tag within the crypto object, * along with its length. * @@ -41,8 +40,80 @@ relay_crypto_get_sendme_tag(relay_crypto_t *crypto, size_t *len_out) { tor_assert(crypto); - *len_out = DIGEST_LEN; - return crypto->c.tor1.sendme_digest; + switch (crypto->kind) { + case RCK_TOR1: + *len_out = DIGEST_LEN; + return crypto->c.tor1.sendme_digest; + case RCK_CGO: + *len_out = CGO_TAG_LEN; + return crypto->c.cgo.last_tag; + } + tor_assert_unreached(); +} + +/** + * Handle a single layer of client-side backward encryption + * with crypto of an arbitary type. + */ +static inline bool +relay_crypt_client_backward(relay_crypto_t *crypto, cell_t *cell) +{ + switch (crypto->kind) { + case RCK_TOR1: + return tor1_crypt_client_backward(&crypto->c.tor1, cell); + case RCK_CGO: { + const uint8_t *tag = NULL; + cgo_crypt_client_backward(crypto->c.cgo.back, cell, &tag); + if (tag != NULL) { + memcpy(crypto->c.cgo.last_tag, tag, CGO_TAG_LEN); + return true; + } else { + return false; + } + } + } + tor_assert_unreached(); +} + +/** + * Handle a relay-side forward encryption + * with crypto of an arbitary type. + */ +static inline bool +relay_crypt_relay_forward(relay_crypto_t *crypto, cell_t *cell) +{ + switch (crypto->kind) { + case RCK_TOR1: + return tor1_crypt_relay_forward(&crypto->c.tor1, cell); + case RCK_CGO: { + const uint8_t *tag = NULL; + cgo_crypt_relay_forward(crypto->c.cgo.fwd, cell, &tag); + if (tag != NULL) { + memcpy(crypto->c.cgo.last_tag, tag, CGO_TAG_LEN); + return true; + } else { + return false; + } + } + } + tor_assert_unreached(); +} + +/** + * Handle relay-side backward encryption with crypto of an arbitary type. + */ +static inline void +relay_crypt_relay_backward(relay_crypto_t *crypto, cell_t *cell) +{ + switch (crypto->kind) { + case RCK_TOR1: + tor1_crypt_relay_backward(&crypto->c.tor1, cell); + break; + case RCK_CGO: { + cgo_crypt_relay_backward(crypto->c.cgo.back, cell); + break; + } + } } /** Do the appropriate en/decryptions for cell arriving on @@ -86,8 +157,7 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, do { /* Remember: cpath is in forward order, that is, first hop first. */ tor_assert(thishop); - bool rec = tor1_crypt_client_backward( - &thishop->pvt_crypto.c.tor1, cell); + bool rec = relay_crypt_client_backward(&thishop->pvt_crypto, cell); if (rec) { *recognized = 1; *layer_hint = thishop; @@ -101,13 +171,13 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, } else { /* We're in the middle. Encrypt one layer. */ relay_crypto_t *crypto = &TO_OR_CIRCUIT(circ)->crypto; - tor1_crypt_relay_backward(&crypto->c.tor1, cell); + relay_crypt_relay_backward(crypto, cell); } } else /* cell_direction == CELL_DIRECTION_OUT */ { /* We're in the middle. Decrypt one layer. */ relay_crypto_t *crypto = &TO_OR_CIRCUIT(circ)->crypto; - bool rec = tor1_crypt_relay_forward(&crypto->c.tor1, cell); + bool rec = relay_crypt_relay_forward(crypto, cell); if (rec) { *recognized = 1; return 0; @@ -116,6 +186,39 @@ relay_decrypt_cell(circuit_t *circ, cell_t *cell, return 0; } +/** Originate a client cell with a relay_crypt_t of arbitrary type. */ +static inline void +relay_crypt_client_originate(relay_crypto_t *crypto, cell_t *cell) +{ + switch (crypto->kind) { + case RCK_TOR1: + tor1_crypt_client_originate(&crypto->c.tor1, cell); + break; + case RCK_CGO: { + const uint8_t *tag = NULL; + cgo_crypt_client_originate(crypto->c.cgo.fwd, cell, &tag); + tor_assert(tag); + memcpy(crypto->c.cgo.last_tag, tag, CGO_TAG_LEN); + break; + } + } +} + +/** Perform forward-direction client encryption with a relay_crypt_t + * of arbitrary type. */ +static inline void +relay_crypt_client_forward(relay_crypto_t *crypto, cell_t *cell) +{ + switch (crypto->kind) { + case RCK_TOR1: + tor1_crypt_client_forward(&crypto->c.tor1, cell); + break; + case RCK_CGO: + cgo_crypt_client_forward(crypto->c.cgo.fwd, cell); + break; + } +} + /** * Encrypt a cell cell that we are creating, and sending outbound on * circ until the hop corresponding to layer_hint. @@ -130,11 +233,11 @@ relay_encrypt_cell_outbound(cell_t *cell, { crypt_path_t *thishop = layer_hint; - tor1_crypt_client_originate(&thishop->pvt_crypto.c.tor1, cell); + relay_crypt_client_originate(&thishop->pvt_crypto, cell); thishop = thishop->prev; while (thishop != circ->cpath->prev) { - tor1_crypt_client_forward(&thishop->pvt_crypto.c.tor1, cell); + relay_crypt_client_forward(&thishop->pvt_crypto, cell); thishop = thishop->prev; } } @@ -150,7 +253,19 @@ void relay_encrypt_cell_inbound(cell_t *cell, or_circuit_t *or_circ) { - tor1_crypt_relay_originate(&or_circ->crypto.c.tor1, cell); + relay_crypto_t *crypto = &or_circ->crypto; + switch (crypto->kind) { + case RCK_TOR1: + tor1_crypt_relay_originate(&crypto->c.tor1, cell); + break; + case RCK_CGO: { + const uint8_t *tag = NULL; + cgo_crypt_relay_originate(crypto->c.cgo.back, cell, &tag); + tor_assert(tag); + memcpy(&crypto->c.cgo.last_tag, tag, CGO_TAG_LEN); + break; + } + } } /** @@ -160,7 +275,43 @@ relay_encrypt_cell_inbound(cell_t *cell, void relay_crypto_clear(relay_crypto_t *crypto) { - tor1_crypt_clear(&crypto->c.tor1); + switch (crypto->kind) { + case RCK_TOR1: + tor1_crypt_clear(&crypto->c.tor1); + break; + case RCK_CGO: + cgo_crypt_free(crypto->c.cgo.fwd); + cgo_crypt_free(crypto->c.cgo.back); + break; + } +} + +static int +cgo_pair_init(cgo_pair_t *pair, bool is_relay, + const uint8_t *key_material, size_t key_data_len) +{ + memset(pair, 0, sizeof(*pair)); + const int aes_bits = CGO_AES_BITS; + const size_t single_cgo_len = cgo_key_material_len(aes_bits); + if (BUG(key_data_len != single_cgo_len * 2)) { + return -1; + } + + cgo_mode_t fwd_mode, back_mode; + if (is_relay) { + fwd_mode = CGO_MODE_RELAY_FORWARD; + back_mode = CGO_MODE_RELAY_BACKWARD; + } else { + fwd_mode = CGO_MODE_CLIENT_FORWARD; + back_mode = CGO_MODE_CLIENT_BACKWARD; + } + + pair->fwd = cgo_crypt_new(fwd_mode, aes_bits, + key_material, single_cgo_len); + pair->back = cgo_crypt_new(back_mode, aes_bits, + key_material + single_cgo_len, single_cgo_len); + + return 0; } /** Initialize crypto from the key material in key_data. @@ -199,6 +350,14 @@ relay_crypto_init(relay_crypto_alg_t alg, crypto->kind = RCK_TOR1; return tor1_crypt_init(&crypto->c.tor1, key_data, key_data_len, true, true); + case RELAY_CRYPTO_ALG_CGO_CLIENT: + crypto->kind = RCK_CGO; + return cgo_pair_init(&crypto->c.cgo, false, + (const uint8_t *)key_data, key_data_len); + case RELAY_CRYPTO_ALG_CGO_RELAY: + crypto->kind = RCK_CGO; + return cgo_pair_init(&crypto->c.cgo, true, + (const uint8_t *)key_data, key_data_len); } tor_assert_unreached(); } @@ -217,6 +376,9 @@ relay_crypto_key_material_len(relay_crypto_alg_t alg) case RELAY_CRYPTO_ALG_TOR1_HSC: case RELAY_CRYPTO_ALG_TOR1_HSS: return tor1_key_material_len(true); + case RELAY_CRYPTO_ALG_CGO_CLIENT: + case RELAY_CRYPTO_ALG_CGO_RELAY: + return cgo_key_material_len(CGO_AES_BITS) * 2; } return -1; } @@ -225,5 +387,11 @@ relay_crypto_key_material_len(relay_crypto_alg_t alg) void relay_crypto_assert_ok(const relay_crypto_t *crypto) { - tor1_crypt_assert_ok(&crypto->c.tor1); + switch (crypto->kind) { + case RCK_TOR1: + tor1_crypt_assert_ok(&crypto->c.tor1); + break; + case RCK_CGO: + break; + } } diff --git a/src/core/crypto/relay_crypto.h b/src/core/crypto/relay_crypto.h index dd84292793..5cb29af673 100644 --- a/src/core/crypto/relay_crypto.h +++ b/src/core/crypto/relay_crypto.h @@ -24,6 +24,10 @@ typedef enum relay_crypto_alg_t { * the shared virtual HS hop created with an INTRODUCE/RENVEZVOUS * handshake. */ RELAY_CRYPTO_ALG_TOR1_HSS, + /** CGO crypto, as used at a client */ + RELAY_CRYPTO_ALG_CGO_CLIENT, + /** CGO crypto, as used at a relay */ + RELAY_CRYPTO_ALG_CGO_RELAY, } relay_crypto_alg_t; /** Largest possible return value for relay_crypto_key_material_len. */ diff --git a/src/core/crypto/relay_crypto_st.h b/src/core/crypto/relay_crypto_st.h index 54e8eb0592..a7fcbcb081 100644 --- a/src/core/crypto/relay_crypto_st.h +++ b/src/core/crypto/relay_crypto_st.h @@ -17,12 +17,23 @@ typedef enum relay_crypto_kind_t { RCK_TOR1, + RCK_CGO, } relay_crypto_kind_t; +typedef struct cgo_pair_t { + // NOTE: Using pointers here is a bit awkward; we may want to refactor + // eventually. + cgo_crypt_t *fwd; + cgo_crypt_t *back; + /* The last tag that we got when originating or recognizing a message */ + uint8_t last_tag[CGO_TAG_LEN]; +} cgo_pair_t; + struct relay_crypto_t { relay_crypto_kind_t kind; union { struct tor1_crypt_t tor1; + cgo_pair_t cgo; } c; };