| Commit | Line | Data |
|---|---|---|
| 9ab15106 MD |
1 | /* |
| 2 | * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved. | |
| 3 | * | |
| 4 | * This code is derived from software contributed to The DragonFly Project | |
| 5 | * by Matthew Dillon <dillon@dragonflybsd.org> | |
| 6 | * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> | |
| 7 | * | |
| 8 | * Redistribution and use in source and binary forms, with or without | |
| 9 | * modification, are permitted provided that the following conditions | |
| 10 | * are met: | |
| 11 | * | |
| 12 | * 1. Redistributions of source code must retain the above copyright | |
| 13 | * notice, this list of conditions and the following disclaimer. | |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer in | |
| 16 | * the documentation and/or other materials provided with the | |
| 17 | * distribution. | |
| 18 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 19 | * contributors may be used to endorse or promote products derived | |
| 20 | * from this software without specific, prior written permission. | |
| 21 | * | |
| 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 23 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 24 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 25 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 26 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 27 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 28 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 30 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 31 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 32 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 33 | * SUCH DAMAGE. | |
| 34 | */ | |
| 35 | ||
| 5cf97ec5 MD |
36 | #include <openssl/rsa.h> /* public/private key functions */ |
| 37 | #include <openssl/pem.h> /* public/private key file load */ | |
| 38 | #include <openssl/err.h> | |
| 39 | #include <openssl/evp.h> /* aes_256_cbc functions */ | |
| 40 | ||
| 9ab15106 | 41 | /*************************************************************************** |
| 62efe6ec MD |
42 | * CRYPTO HANDSHAKE * |
| 43 | *************************************************************************** | |
| 44 | * | |
| 45 | * The initial public-key exchange is implementing by transmitting a | |
| 46 | * 512-byte buffer to the other side in a symmetrical fashion. This | |
| 47 | * buffer contains the following: | |
| 48 | * | |
| 5cf97ec5 MD |
49 | * (1) A random session key. 512 bits is specified. We use aes_256_cbc() |
| 50 | * and initialize the key with the first 256 bits and the iv[] with | |
| 51 | * the second. Note that the transmitted and received session | |
| 52 | * keys are XOR'd together to create the session key used for | |
| 53 | * communications (so even if the verifier is compromised the session | |
| 54 | * will still be gobbly gook if the public key has not been completely | |
| 55 | * broken). | |
| 62efe6ec MD |
56 | * |
| 57 | * (2) A verifier to determine that the decode was successful. It encodes | |
| 58 | * an XOR of each group of 4 bytes from the session key. | |
| 59 | * | |
| 60 | * (3) Additional configuration and additional random data. | |
| 61 | * | |
| 62 | * - The hammer2 message header magic for endian detect | |
| 63 | * | |
| 64 | * - The hammer2 protocol version. The two sides agree on the | |
| 65 | * smaller of the two. | |
| 66 | * | |
| 67 | * - All unused fields (junk*) are filled with random data. | |
| 68 | * | |
| 69 | * This structure must be exactly 512 bytes and expects to use 256-byte | |
| 70 | * RSA keys. | |
| 71 | */ | |
| 72 | struct hammer2_handshake { | |
| 73 | char pad1[8]; /* 000 */ | |
| 74 | uint16_t magic; /* 008 HAMMER2_MSGHDR_MAGIC for endian detect */ | |
| 75 | uint16_t version; /* 00A hammer2 protocol version */ | |
| 76 | uint32_t flags; /* 00C protocol extension flags */ | |
| 77 | uint8_t sess[64]; /* 010 512-bit session key */ | |
| 78 | uint8_t verf[16]; /* 050 verifier = ~sess */ | |
| 79 | char quickmsg[32]; /* 060 reason for connecting */ | |
| 80 | char junk080[128]; /* 080-0FF */ | |
| 81 | char pad2[8]; /* 100-107 */ | |
| 82 | char junk100[256-8]; /* 108-1FF */ | |
| 83 | }; | |
| 84 | ||
| 85 | typedef struct hammer2_handshake hammer2_handshake_t; | |
| 86 | ||
| 02454b3e MD |
87 | /* |
| 88 | * NOTE: HAMMER2_MSG_ALIGN (64) must be a multiple of HAMMER2_AES_KEY_SIZE. | |
| 89 | */ | |
| 5cf97ec5 MD |
90 | #define HAMMER2_AES_KEY_SIZE 32 |
| 91 | #define HAMMER2_AES_KEY_MASK (HAMMER2_AES_KEY_SIZE - 1) | |
| 92 | #define HAMMER2_AES_TYPE aes_256_cbc | |
| 93 | #define HAMMER2_AES_TYPE_EVP EVP_aes_256_cbc() | |
| 94 | #define HAMMER2_AES_TYPE_STR #HAMMER2_AES_TYPE | |
| 766ad73f AH |
95 | #define HAMMER2_CRYPTO_IV_SIZE 12 |
| 96 | #define HAMMER2_CRYPTO_IV_FIXED_SIZE 4 | |
| 97 | #define HAMMER2_CRYPTO_CHUNK_SIZE 64 | |
| 98 | #define HAMMER2_CRYPTO_TAG_SIZE 16 | |
| 5cf97ec5 | 99 | |
| 62efe6ec | 100 | /*************************************************************************** |
| 9ab15106 MD |
101 | * LOW LEVEL MESSAGING * |
| 102 | *************************************************************************** | |
| 103 | * | |
| 104 | * hammer2_msg - A standalone copy of a message, typically referenced by | |
| 105 | * or embedded in other structures, or used with I/O queues. | |
| 106 | * | |
| 107 | * These structures are strictly temporary, so they do not have to be | |
| 108 | * particularly optimized for size. All possible message headers are | |
| 109 | * directly embedded (any), and the message may contain a reference | |
| 110 | * to allocated auxillary data. The structure is recycled quite often | |
| 111 | * by a connection. | |
| 112 | * | |
| 113 | * This structure is typically not used for storing persistent message | |
| 4a2e0eae | 114 | * state (see hammer2_persist for that). |
| 9ab15106 | 115 | */ |
| 4a2e0eae MD |
116 | struct hammer2_iocom; |
| 117 | struct hammer2_persist; | |
| 8c280d5d | 118 | struct hammer2_state; |
| 90e8cd1d | 119 | struct hammer2_router; |
| 8c280d5d MD |
120 | struct hammer2_address; |
| 121 | struct hammer2_msg; | |
| 4a2e0eae | 122 | |
| 8c280d5d | 123 | TAILQ_HEAD(hammer2_state_queue, hammer2_state); |
| 78476205 | 124 | TAILQ_HEAD(hammer2_msg_queue, hammer2_msg); |
| 8c280d5d | 125 | TAILQ_HEAD(hammer2_address_queue, hammer2_address); |
| 78476205 | 126 | RB_HEAD(hammer2_state_tree, hammer2_state); |
| 90e8cd1d | 127 | RB_HEAD(hammer2_router_tree, hammer2_router); |
| 78476205 | 128 | |
| 8c280d5d | 129 | struct h2span_link; |
| 90e8cd1d | 130 | struct h2span_relay; |
| 8c280d5d MD |
131 | struct h2span_connect; |
| 132 | ||
| 78476205 MD |
133 | struct hammer2_state { |
| 134 | RB_ENTRY(hammer2_state) rbnode; /* indexed by msgid */ | |
| 8c280d5d MD |
135 | TAILQ_ENTRY(hammer2_state) source_entry;/* if routed */ |
| 136 | TAILQ_ENTRY(hammer2_state) target_entry;/* if routed */ | |
| 4a2e0eae | 137 | struct hammer2_iocom *iocom; |
| 8c280d5d MD |
138 | struct hammer2_address_t *source_addr; /* if routed */ |
| 139 | struct hammer2_address_t *target_addr; /* if routed */ | |
| 78476205 MD |
140 | uint32_t txcmd; /* mostly for CMDF flags */ |
| 141 | uint32_t rxcmd; /* mostly for CMDF flags */ | |
| 8c280d5d MD |
142 | uint64_t spanid; /* routing id */ |
| 143 | uint64_t msgid; /* {spanid,msgid} uniq */ | |
| 9ab15106 | 144 | int flags; |
| 78476205 MD |
145 | int error; |
| 146 | struct hammer2_msg *msg; | |
| 29ead430 | 147 | void (*func)(struct hammer2_msg *); |
| 8c280d5d MD |
148 | union { |
| 149 | void *any; | |
| 150 | struct h2span_link *link; | |
| 151 | struct h2span_connect *conn; | |
| 152 | struct h2span_relay *relay; | |
| 153 | } any; | |
| 154 | }; | |
| 155 | ||
| 156 | struct hammer2_address { | |
| 157 | TAILQ_ENTRY(hammer2_address) entry; /* on-iocom */ | |
| 158 | struct hammer2_iocom *iocom; /* related iocom */ | |
| 159 | struct hammer2_state_queue sourceq; /* states on source queue */ | |
| 160 | struct hammer2_state_queue targetq; /* states on target queue */ | |
| 161 | uint16_t id; | |
| 9ab15106 MD |
162 | }; |
| 163 | ||
| 78476205 MD |
164 | #define HAMMER2_STATE_INSERTED 0x0001 |
| 165 | #define HAMMER2_STATE_DYNAMIC 0x0002 | |
| 8c280d5d | 166 | #define HAMMER2_STATE_NODEID 0x0004 /* manages a node id */ |
| 9ab15106 | 167 | |
| 78476205 MD |
168 | struct hammer2_msg { |
| 169 | TAILQ_ENTRY(hammer2_msg) qentry; | |
| 29ead430 | 170 | struct hammer2_router *router; |
| 78476205 MD |
171 | struct hammer2_state *state; |
| 172 | size_t hdr_size; | |
| 173 | size_t aux_size; | |
| 174 | char *aux_data; | |
| 1b195a98 | 175 | hammer2_msg_any_t any; |
| 78476205 MD |
176 | }; |
| 177 | ||
| 178 | typedef struct hammer2_state hammer2_state_t; | |
| 8c280d5d | 179 | typedef struct hammer2_address hammer2_address_t; |
| 78476205 | 180 | typedef struct hammer2_msg hammer2_msg_t; |
| 9ab15106 MD |
181 | typedef struct hammer2_msg_queue hammer2_msg_queue_t; |
| 182 | ||
| 78476205 MD |
183 | int hammer2_state_cmp(hammer2_state_t *state1, hammer2_state_t *state2); |
| 184 | RB_PROTOTYPE(hammer2_state_tree, hammer2_state, rbnode, hammer2_state_cmp); | |
| 9ab15106 MD |
185 | |
| 186 | /* | |
| 187 | * hammer2_ioq - An embedded component of hammer2_connect, holds state | |
| 188 | * for the buffering and parsing of incoming and outgoing messages. | |
| 3033ecc8 MD |
189 | * |
| 190 | * cdx - beg - processed buffer data, encrypted or decrypted | |
| 191 | * end - cdn - unprocessed buffer data not yet encrypted or decrypted | |
| 9ab15106 MD |
192 | */ |
| 193 | struct hammer2_ioq { | |
| 194 | enum { HAMMER2_MSGQ_STATE_HEADER1, | |
| 195 | HAMMER2_MSGQ_STATE_HEADER2, | |
| 196 | HAMMER2_MSGQ_STATE_AUXDATA1, | |
| 197 | HAMMER2_MSGQ_STATE_AUXDATA2, | |
| 198 | HAMMER2_MSGQ_STATE_ERROR } state; | |
| 3033ecc8 MD |
199 | size_t fifo_beg; /* buffered data */ |
| 200 | size_t fifo_cdx; /* cdx-beg processed */ | |
| 201 | size_t fifo_cdn; /* end-cdn unprocessed */ | |
| 202 | size_t fifo_end; | |
| 78476205 MD |
203 | size_t hbytes; /* header size */ |
| 204 | size_t abytes; /* aux_data size */ | |
| 9ab15106 MD |
205 | int error; |
| 206 | int seq; /* salt sequencer */ | |
| 207 | int msgcount; | |
| 5cf97ec5 MD |
208 | EVP_CIPHER_CTX ctx; |
| 209 | char iv[HAMMER2_AES_KEY_SIZE]; /* encrypt or decrypt iv[] */ | |
| 9ab15106 MD |
210 | hammer2_msg_t *msg; |
| 211 | hammer2_msg_queue_t msgq; | |
| 5cf97ec5 | 212 | char buf[HAMMER2_MSGBUF_SIZE]; /* staging buffer */ |
| 9ab15106 MD |
213 | }; |
| 214 | ||
| 215 | typedef struct hammer2_ioq hammer2_ioq_t; | |
| 216 | ||
| 62efe6ec MD |
217 | #define HAMMER2_IOQ_ERROR_SYNC 1 /* bad magic / out of sync */ |
| 218 | #define HAMMER2_IOQ_ERROR_EOF 2 /* unexpected EOF */ | |
| 219 | #define HAMMER2_IOQ_ERROR_SOCK 3 /* read() error on socket */ | |
| 220 | #define HAMMER2_IOQ_ERROR_FIELD 4 /* invalid field */ | |
| 221 | #define HAMMER2_IOQ_ERROR_HCRC 5 /* core header crc bad */ | |
| 222 | #define HAMMER2_IOQ_ERROR_XCRC 6 /* ext header crc bad */ | |
| 223 | #define HAMMER2_IOQ_ERROR_ACRC 7 /* aux data crc bad */ | |
| 224 | #define HAMMER2_IOQ_ERROR_STATE 8 /* bad state */ | |
| 225 | #define HAMMER2_IOQ_ERROR_NOPEER 9 /* bad socket peer */ | |
| 226 | #define HAMMER2_IOQ_ERROR_NORKEY 10 /* no remote keyfile found */ | |
| 227 | #define HAMMER2_IOQ_ERROR_NOLKEY 11 /* no local keyfile found */ | |
| 228 | #define HAMMER2_IOQ_ERROR_KEYXCHGFAIL 12 /* key exchange failed */ | |
| 229 | #define HAMMER2_IOQ_ERROR_KEYFMT 13 /* key file format problem */ | |
| 230 | #define HAMMER2_IOQ_ERROR_BADURANDOM 14 /* /dev/urandom is bad */ | |
| 5cf97ec5 | 231 | #define HAMMER2_IOQ_ERROR_MSGSEQ 15 /* message sequence error */ |
| 78476205 MD |
232 | #define HAMMER2_IOQ_ERROR_EALREADY 16 /* ignore this message */ |
| 233 | #define HAMMER2_IOQ_ERROR_TRANS 17 /* state transaction issue */ | |
| fd1d02a5 AH |
234 | #define HAMMER2_IOQ_ERROR_IVWRAP 18 /* IVs exhaused */ |
| 235 | #define HAMMER2_IOQ_ERROR_MACFAIL 19 /* MAC of encryption algorithm failed */ | |
| 236 | #define HAMMER2_IOQ_ERROR_ALGO 20 /* Misc. encryption algorithm error */ | |
| 9ab15106 MD |
237 | |
| 238 | #define HAMMER2_IOQ_MAXIOVEC 16 | |
| 239 | ||
| 240 | /* | |
| 29ead430 MD |
241 | * hammer2_router - governs the routing of a message. Passed into |
| 242 | * hammer2_msg_write. | |
| 243 | * | |
| 244 | * The router is either connected to an iocom (socket) directly, or | |
| 90e8cd1d MD |
245 | * connected to a SPAN transaction (h2span_link structure for outgoing) |
| 246 | * or to a SPAN transaction (h2span_relay structure for incoming). | |
| 29ead430 MD |
247 | */ |
| 248 | struct hammer2_router { | |
| 90e8cd1d | 249 | RB_ENTRY(hammer2_router) rbnode; /* indexed by spanid */ |
| 29ead430 | 250 | struct hammer2_iocom *iocom; |
| 90e8cd1d MD |
251 | struct h2span_link *link; /* may be NULL */ |
| 252 | struct h2span_relay *relay; /* may be NULL */ | |
| 29ead430 MD |
253 | void (*signal_callback)(struct hammer2_router *); |
| 254 | void (*rcvmsg_callback)(struct hammer2_msg *); | |
| 255 | void (*altmsg_callback)(struct hammer2_iocom *); | |
| 256 | struct hammer2_state_tree staterd_tree; /* active messages */ | |
| 257 | struct hammer2_state_tree statewr_tree; /* active messages */ | |
| 258 | hammer2_msg_queue_t txmsgq; /* tx msgq from remote */ | |
| 90e8cd1d MD |
259 | uint64_t spanid; /* for routing */ |
| 260 | int flags; | |
| 29ead430 MD |
261 | int refs; /* refs prevent destruction */ |
| 262 | }; | |
| 263 | ||
| 90e8cd1d MD |
264 | #define HAMMER2_ROUTER_CONNECTED 0x0001 /* on global RB tree */ |
| 265 | #define HAMMER2_ROUTER_DELETED 0x0002 /* parent structure destroyed */ | |
| 266 | ||
| 29ead430 MD |
267 | typedef struct hammer2_router hammer2_router_t; |
| 268 | ||
| 90e8cd1d MD |
269 | int hammer2_router_cmp(hammer2_router_t *router1, hammer2_router_t *router2); |
| 270 | RB_PROTOTYPE(hammer2_router_tree, hammer2_router, rbnode, hammer2_router_cmp); | |
| 271 | ||
| 29ead430 | 272 | /* |
| 9ab15106 MD |
273 | * hammer2_iocom - governs a messaging stream connection |
| 274 | */ | |
| 275 | struct hammer2_iocom { | |
| 276 | hammer2_ioq_t ioq_rx; | |
| 277 | hammer2_ioq_t ioq_tx; | |
| 278 | hammer2_msg_queue_t freeq; /* free msgs hdr only */ | |
| 279 | hammer2_msg_queue_t freeq_aux; /* free msgs w/aux_data */ | |
| 8c280d5d | 280 | struct hammer2_address_queue addrq; /* source/target addrs */ |
| 9ab15106 MD |
281 | int sock_fd; /* comm socket or pipe */ |
| 282 | int alt_fd; /* thread signal, tty, etc */ | |
| 7dc0f844 | 283 | int wakeupfds[2]; /* pipe wakes up iocom thread */ |
| 9ab15106 | 284 | int flags; |
| 62efe6ec MD |
285 | int rxmisc; |
| 286 | int txmisc; | |
| 5cf97ec5 | 287 | char sess[HAMMER2_AES_KEY_SIZE]; /* aes_256_cbc key */ |
| 90e8cd1d | 288 | struct hammer2_router *router; |
| 7dc0f844 | 289 | pthread_mutex_t mtx; /* mutex for state*tree/rmsgq */ |
| 9ab15106 MD |
290 | }; |
| 291 | ||
| 292 | typedef struct hammer2_iocom hammer2_iocom_t; | |
| 293 | ||
| 294 | #define HAMMER2_IOCOMF_EOF 0x00000001 /* EOF or ERROR on desc */ | |
| 295 | #define HAMMER2_IOCOMF_RREQ 0x00000002 /* request read-data event */ | |
| 296 | #define HAMMER2_IOCOMF_WREQ 0x00000004 /* request write-avail event */ | |
| 7dc0f844 MD |
297 | #define HAMMER2_IOCOMF_RWORK 0x00000008 /* immediate work pending */ |
| 298 | #define HAMMER2_IOCOMF_WWORK 0x00000010 /* immediate work pending */ | |
| 299 | #define HAMMER2_IOCOMF_PWORK 0x00000020 /* immediate work pending */ | |
| 300 | #define HAMMER2_IOCOMF_ARWORK 0x00000040 /* immediate work pending */ | |
| 301 | #define HAMMER2_IOCOMF_AWWORK 0x00000080 /* immediate work pending */ | |
| 5903497c MD |
302 | #define HAMMER2_IOCOMF_SWORK 0x00000100 /* immediate work pending */ |
| 303 | #define HAMMER2_IOCOMF_CRYPTED 0x00000200 /* encrypt enabled */ |