Line data Source code
1 : #ifndef HEADER_fd_src_discof_failover_fd_failover_proto_h 2 : #define HEADER_fd_src_discof_failover_fd_failover_proto_h 3 : 4 : /* Failover protocol messages and pure session transitions */ 5 : 6 : #include "../../util/fd_util_base.h" 7 : #include "../../ballet/sha512/fd_sha512.h" 8 : #include "../../disco/keyguard/fd_keyguard.h" 9 : 10 : /* Protocol version */ 11 0 : #define FD_FAILOVER_VERSION (1U) 12 : 13 : /* The default port for a handoff. */ 14 0 : #define FD_FAILOVER_DEFAULT_PORT ((ushort)8010) 15 : 16 : /* Message types */ 17 0 : #define FD_FAILOVER_MSG_HELLO (0U) 18 0 : #define FD_FAILOVER_MSG_HANDOFF_REQUEST (1U) 19 0 : #define FD_FAILOVER_MSG_DEMOTED (2U) 20 0 : #define FD_FAILOVER_MSG_PROMOTE_ACK (3U) 21 0 : #define FD_FAILOVER_MSG_PROMOTE_REJECTED (4U) 22 0 : #define FD_FAILOVER_MSG_HANDOFF_RESULT (5U) 23 0 : #define FD_FAILOVER_MSG_KEEPALIVE (6U) 24 : #define FD_FAILOVER_MSG_CNT (7U) 25 : 26 : /* Sentinel for a slot field with no value */ 27 0 : #define FD_FAILOVER_SLOT_NULL (ULONG_MAX) 28 : 29 : /* Consensus payload formats */ 30 0 : #define FD_FAILOVER_MODE_ALPENGLOW (1U) 31 : 32 : /* Session states for authenticated TCP sessions. */ 33 0 : #define FD_FAILOVER_SESSION_LISTENING (0UL) /* Accept candidates until one authenticates. */ 34 0 : #define FD_FAILOVER_SESSION_DIALING (1UL) /* Wait for outbound TCP to connect. */ 35 0 : #define FD_FAILOVER_SESSION_HELLO (2UL) /* Complete TLS and exchange HELLO. */ 36 0 : #define FD_FAILOVER_SESSION_PAIRED (3UL) /* Exchange messages with the authenticated peer. */ 37 0 : #define FD_FAILOVER_SESSION_BACKOFF (4UL) /* Wait before the next dial attempt. */ 38 : #define FD_FAILOVER_SESSION_CNT (5UL) 39 : 40 : /* HELLO pairing outcomes */ 41 0 : #define FD_FAILOVER_HELLO_OK (0) 42 0 : #define FD_FAILOVER_HELLO_ERR_VERSION (1) 43 0 : #define FD_FAILOVER_HELLO_ERR_STAKED (2) 44 0 : #define FD_FAILOVER_HELLO_ERR_SELF (3) 45 0 : #define FD_FAILOVER_HELLO_ERR_BOTH_HOLD (4) 46 0 : #define FD_FAILOVER_HELLO_ERR_HOLDS (5) 47 0 : #define FD_FAILOVER_HELLO_ERR_BOOT_ID (6) 48 0 : #define FD_FAILOVER_HELLO_ERR_MODE (7) 49 0 : #define FD_FAILOVER_HELLO_ERR_PROOF (8) 50 : 51 : /* Upper bound on the vote history payload in alpenglow mode, 52 : FD_VOTOR_HIST_SER_MAX is 5274 bytes. */ 53 0 : #define FD_FAILOVER_ALPENGLOW_STATE_MAX (6144UL) 54 0 : #define FD_FAILOVER_STATE_MAX (FD_FAILOVER_ALPENGLOW_STATE_MAX) 55 : 56 : /* Wire protocol message bodies. Little endian, packed, fixed layout. */ 57 : struct __attribute__((packed)) fd_failover_hello { 58 : ushort version; /* FD_FAILOVER_VERSION */ 59 : uchar staked_pubkey[ 32 ]; /* the identity this pair hands off */ 60 : uchar holds; /* 1 when this host runs staked_pubkey at pairing, else 0 */ 61 : uchar mode; /* FD_FAILOVER_MODE_* consensus */ 62 : ulong boot_id; /* random nonzero value per boot to distinguish restarts */ 63 : uchar commit[ 20 ]; /* FD commit hash */ 64 : }; 65 : typedef struct fd_failover_hello fd_failover_hello_t; 66 : FD_STATIC_ASSERT( sizeof(fd_failover_hello_t)==64UL, wire_layout ); 67 : 68 : /* Pre-TLS admission */ 69 0 : #define FD_FAILOVER_ADMISSION_MAGIC (0x314d44414c494146UL) 70 0 : #define FD_FAILOVER_ADMISSION_MAX (2048UL) 71 : #define FD_FAILOVER_CLIENT_HELLO_MAX (1024UL) 72 : 73 : struct __attribute__((packed)) fd_failover_admission_start { 74 : ulong magic; 75 : fd_failover_hello_t hello; 76 : uchar nonce[ 32 ]; 77 : ushort client_hello_sz; 78 : }; 79 : typedef struct fd_failover_admission_start fd_failover_admission_start_t; 80 : FD_STATIC_ASSERT( sizeof(fd_failover_admission_start_t)==106UL, admission_start_layout ); 81 : 82 : struct __attribute__((packed)) fd_failover_admission_challenge { 83 : ulong magic; 84 : fd_failover_hello_t hello; 85 : uchar nonce[ 32 ]; 86 : }; 87 : typedef struct fd_failover_admission_challenge fd_failover_admission_challenge_t; 88 : FD_STATIC_ASSERT( sizeof(fd_failover_admission_challenge_t)==104UL, admission_challenge_layout ); 89 : 90 : struct __attribute__((packed)) fd_failover_admission_response { 91 : ushort server_flight_sz; 92 : uchar proof[ 64 ]; 93 : }; 94 : typedef struct fd_failover_admission_response fd_failover_admission_response_t; 95 : FD_STATIC_ASSERT( sizeof(fd_failover_admission_response_t)==66UL, admission_response_layout ); 96 : 97 0 : #define FD_FAILOVER_SERVER_FLIGHT_MAX (FD_FAILOVER_ADMISSION_MAX-sizeof(fd_failover_admission_response_t)) 98 : 99 : struct __attribute__((packed)) fd_failover_demoted { 100 : ulong handoff_id; /* the handoff id from the HANDOFF_REQUEST */ 101 : ulong target_boot_id; /* peer boot_id the handoff is for */ 102 : ulong last_vote_slot; /* tip of the final history */ 103 : uchar mode; /* FD_FAILOVER_MODE_* encoding */ 104 : ushort state_len; /* size of the final history that follows this struct */ 105 : }; 106 : typedef struct fd_failover_demoted fd_failover_demoted_t; 107 : FD_STATIC_ASSERT( sizeof(fd_failover_demoted_t)==27UL, wire_layout ); 108 : 109 : #define FD_FAILOVER_DEMOTED_PAYLOAD_MAX (sizeof(fd_failover_demoted_t)+FD_FAILOVER_STATE_MAX) 110 : 111 : struct __attribute__((packed)) fd_failover_promote_ack { 112 : ulong handoff_id; 113 : }; 114 : typedef struct fd_failover_promote_ack fd_failover_promote_ack_t; 115 : FD_STATIC_ASSERT( sizeof(fd_failover_promote_ack_t)==8UL, wire_layout ); 116 : 117 : struct __attribute__((packed)) fd_failover_promote_rejected { 118 : ulong handoff_id; 119 : uchar reason; /* FD_FAILOVER_REJECT_* */ 120 : }; 121 : typedef struct fd_failover_promote_rejected fd_failover_promote_rejected_t; 122 : FD_STATIC_ASSERT( sizeof(fd_failover_promote_rejected_t)==9UL, wire_layout ); 123 : 124 : struct __attribute__((packed)) fd_failover_handoff_request { 125 : ulong handoff_id; 126 : ulong target_boot_id; 127 : ulong replay_slot; /* replay slot of the machine asking for the identity, FD_FAILOVER_SLOT_NULL before replay starts */ 128 : }; 129 : typedef struct fd_failover_handoff_request fd_failover_handoff_request_t; 130 : FD_STATIC_ASSERT( sizeof(fd_failover_handoff_request_t)==24UL, wire_layout ); 131 : 132 : /* Ends the exchange, result is an admin control result. */ 133 : struct __attribute__((packed)) fd_failover_handoff_result { 134 : ulong handoff_id; 135 : ulong result; 136 : }; 137 : typedef struct fd_failover_handoff_result fd_failover_handoff_result_t; 138 : FD_STATIC_ASSERT( sizeof(fd_failover_handoff_result_t)==16UL, wire_layout ); 139 : 140 : /* PROMOTE_REJECTED reasons */ 141 0 : #define FD_FAILOVER_REJECT_NONE (0U) 142 0 : #define FD_FAILOVER_REJECT_BUSY (1U) 143 0 : #define FD_FAILOVER_REJECT_HOLDS_IDENTITY (2U) 144 0 : #define FD_FAILOVER_REJECT_REPLAY_BEHIND (3U) 145 0 : #define FD_FAILOVER_REJECT_ADOPTION_MISMATCH (4U) 146 0 : #define FD_FAILOVER_REJECT_ADOPTION_FAILED (5U) 147 0 : #define FD_FAILOVER_REJECT_SWITCH_FAILED (6U) 148 0 : #define FD_FAILOVER_REJECT_CNT (7U) 149 : 150 : FD_PROTOTYPES_BEGIN 151 : 152 : /* Checks a peer's HELLO against ours and returns FD_FAILOVER_HELLO_OK or 153 : the first fatal error. The checks are symmetric on both nodes. */ 154 : int 155 : fd_failover_hello_check( fd_failover_hello_t const * self, 156 : fd_failover_hello_t const * peer ); 157 : 158 : /* Admission hash covers exact packed wire bytes and the prepared TLS 159 : record. response_hash binds the listener proof to the client proof 160 : and the server's prepared TLS flight, including its ephemeral key. */ 161 : void 162 : fd_failover_admission_hash( fd_failover_admission_start_t const * start, 163 : uchar const * client_hello, 164 : fd_failover_admission_challenge_t const * challenge, 165 : uchar out[ 32 ] ); 166 : 167 : void 168 : fd_failover_response_hash( uchar const transcript[ 32 ], 169 : uchar const client_proof[ 64 ], 170 : uchar const * server_flight, 171 : ushort server_flight_sz, 172 : uchar out[ 32 ] ); 173 : 174 : void 175 : fd_failover_proof_msg( uchar out[ FD_KEYGUARD_FAILOVER_PROOF_SZ ], 176 : int server, 177 : uchar const transcript[ 32 ] ); 178 : 179 : /* Validate a handoff request or response. */ 180 : int 181 : fd_failover_handoff_request_decode( fd_failover_handoff_request_t * out, 182 : uchar const * payload, 183 : ulong payload_sz ); 184 : 185 : int 186 : fd_failover_handoff_result_decode( fd_failover_handoff_result_t * out, 187 : uchar const * payload, 188 : ulong payload_sz ); 189 : 190 : /* Writes a DEMOTED payload. */ 191 : ulong 192 : fd_failover_demoted_encode( uchar * out, 193 : ulong handoff_id, 194 : ulong target_boot_id, 195 : ulong last_vote_slot, 196 : uchar const * state, 197 : ulong state_sz ); 198 : 199 : /* Validates a DEMOTED header. */ 200 : int 201 : fd_failover_demoted_decode( fd_failover_demoted_t * out, 202 : uchar const * payload, 203 : ulong payload_sz ); 204 : 205 : /* Write a PROMOTE_ACK or PROMOTE_REJECTED payload. */ 206 : ulong 207 : fd_failover_promote_ack_encode( uchar * out, 208 : ulong handoff_id ); 209 : 210 : ulong 211 : fd_failover_promote_rejected_encode( uchar * out, 212 : ulong handoff_id, 213 : uchar reason ); 214 : 215 : /* Validate a PROMOTE_ACK or PROMOTE_REJECTED payload. */ 216 : int 217 : fd_failover_promote_ack_decode( fd_failover_promote_ack_t * out, 218 : uchar const * payload, 219 : ulong payload_sz ); 220 : 221 : int 222 : fd_failover_promote_rejected_decode( fd_failover_promote_rejected_t * out, 223 : uchar const * payload, 224 : ulong payload_sz ); 225 : 226 : FD_PROTOTYPES_END 227 : 228 : #endif /* HEADER_fd_src_discof_failover_fd_failover_proto_h */