| 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 | |
| 95 | ||
| 62efe6ec | 96 | /*************************************************************************** |
| 9ab15106 MD |
97 | * LOW LEVEL MESSAGING * |
| 98 | *************************************************************************** | |
| 99 | * | |
| 100 | * hammer2_msg - A standalone copy of a message, typically referenced by | |
| 101 | * or embedded in other structures, or used with I/O queues. | |
| 102 | * | |
| 103 | * These structures are strictly temporary, so they do not have to be | |
| 104 | * particularly optimized for size. All possible message headers are | |
| 105 | * directly embedded (any), and the message may contain a reference | |
| 106 | * to allocated auxillary data. The structure is recycled quite often | |
| 107 | * by a connection. | |
| 108 | * | |
| 109 | * This structure is typically not used for storing persistent message | |
| 4a2e0eae | 110 | * state (see hammer2_persist for that). |
| 9ab15106 | 111 | */ |
| 4a2e0eae MD |
112 | struct hammer2_iocom; |
| 113 | struct hammer2_persist; | |
| 8c280d5d MD |
114 | struct hammer2_state; |
| 115 | struct hammer2_address; | |
| 116 | struct hammer2_msg; | |
| 4a2e0eae | 117 | |
| 8c280d5d | 118 | TAILQ_HEAD(hammer2_state_queue, hammer2_state); |
| 78476205 | 119 | TAILQ_HEAD(hammer2_msg_queue, hammer2_msg); |
| 8c280d5d | 120 | TAILQ_HEAD(hammer2_address_queue, hammer2_address); |
| 78476205 MD |
121 | RB_HEAD(hammer2_state_tree, hammer2_state); |
| 122 | ||
| 8c280d5d MD |
123 | struct h2span_link; |
| 124 | struct h2span_connect; | |
| 125 | ||
| 78476205 MD |
126 | struct hammer2_state { |
| 127 | RB_ENTRY(hammer2_state) rbnode; /* indexed by msgid */ | |
| 8c280d5d MD |
128 | TAILQ_ENTRY(hammer2_state) source_entry;/* if routed */ |
| 129 | TAILQ_ENTRY(hammer2_state) target_entry;/* if routed */ | |
| 4a2e0eae | 130 | struct hammer2_iocom *iocom; |
| 8c280d5d MD |
131 | struct hammer2_address_t *source_addr; /* if routed */ |
| 132 | struct hammer2_address_t *target_addr; /* if routed */ | |
| 78476205 MD |
133 | uint32_t txcmd; /* mostly for CMDF flags */ |
| 134 | uint32_t rxcmd; /* mostly for CMDF flags */ | |
| 8c280d5d MD |
135 | uint64_t spanid; /* routing id */ |
| 136 | uint64_t msgid; /* {spanid,msgid} uniq */ | |
| 9ab15106 | 137 | int flags; |
| 78476205 MD |
138 | int error; |
| 139 | struct hammer2_msg *msg; | |
| 29ead430 | 140 | void (*func)(struct hammer2_msg *); |
| 8c280d5d MD |
141 | union { |
| 142 | void *any; | |
| 143 | struct h2span_link *link; | |
| 144 | struct h2span_connect *conn; | |
| 145 | struct h2span_relay *relay; | |
| 146 | } any; | |
| 147 | }; | |
| 148 | ||
| 149 | struct hammer2_address { | |
| 150 | TAILQ_ENTRY(hammer2_address) entry; /* on-iocom */ | |
| 151 | struct hammer2_iocom *iocom; /* related iocom */ | |
| 152 | struct hammer2_state_queue sourceq; /* states on source queue */ | |
| 153 | struct hammer2_state_queue targetq; /* states on target queue */ | |
| 154 | uint16_t id; | |
| 9ab15106 MD |
155 | }; |
| 156 | ||
| 78476205 MD |
157 | #define HAMMER2_STATE_INSERTED 0x0001 |
| 158 | #define HAMMER2_STATE_DYNAMIC 0x0002 | |
| 8c280d5d | 159 | #define HAMMER2_STATE_NODEID 0x0004 /* manages a node id */ |
| 9ab15106 | 160 | |
| 78476205 MD |
161 | struct hammer2_msg { |
| 162 | TAILQ_ENTRY(hammer2_msg) qentry; | |
| 29ead430 | 163 | struct hammer2_router *router; |
| 78476205 MD |
164 | struct hammer2_state *state; |
| 165 | size_t hdr_size; | |
| 166 | size_t aux_size; | |
| 167 | char *aux_data; | |
| 1b195a98 | 168 | hammer2_msg_any_t any; |
| 78476205 MD |
169 | }; |
| 170 | ||
| 171 | typedef struct hammer2_state hammer2_state_t; | |
| 8c280d5d | 172 | typedef struct hammer2_address hammer2_address_t; |
| 78476205 | 173 | typedef struct hammer2_msg hammer2_msg_t; |
| 9ab15106 MD |
174 | typedef struct hammer2_msg_queue hammer2_msg_queue_t; |
| 175 | ||
| 78476205 MD |
176 | int hammer2_state_cmp(hammer2_state_t *state1, hammer2_state_t *state2); |
| 177 | RB_PROTOTYPE(hammer2_state_tree, hammer2_state, rbnode, hammer2_state_cmp); | |
| 9ab15106 MD |
178 | |
| 179 | /* | |
| 180 | * hammer2_ioq - An embedded component of hammer2_connect, holds state | |
| 181 | * for the buffering and parsing of incoming and outgoing messages. | |
| 182 | */ | |
| 183 | struct hammer2_ioq { | |
| 184 | enum { HAMMER2_MSGQ_STATE_HEADER1, | |
| 185 | HAMMER2_MSGQ_STATE_HEADER2, | |
| 186 | HAMMER2_MSGQ_STATE_AUXDATA1, | |
| 187 | HAMMER2_MSGQ_STATE_AUXDATA2, | |
| 188 | HAMMER2_MSGQ_STATE_ERROR } state; | |
| 189 | int fifo_beg; /* buffered data */ | |
| 5cf97ec5 | 190 | int fifo_cdx; /* encrypt/decrypt index */ |
| 9ab15106 | 191 | int fifo_end; |
| 78476205 MD |
192 | size_t hbytes; /* header size */ |
| 193 | size_t abytes; /* aux_data size */ | |
| 194 | size_t already; /* aux_data already decrypted */ | |
| 9ab15106 MD |
195 | int error; |
| 196 | int seq; /* salt sequencer */ | |
| 197 | int msgcount; | |
| 5cf97ec5 MD |
198 | EVP_CIPHER_CTX ctx; |
| 199 | char iv[HAMMER2_AES_KEY_SIZE]; /* encrypt or decrypt iv[] */ | |
| 9ab15106 MD |
200 | hammer2_msg_t *msg; |
| 201 | hammer2_msg_queue_t msgq; | |
| 5cf97ec5 | 202 | char buf[HAMMER2_MSGBUF_SIZE]; /* staging buffer */ |
| 9ab15106 MD |
203 | }; |
| 204 | ||
| 205 | typedef struct hammer2_ioq hammer2_ioq_t; | |
| 206 | ||
| 62efe6ec MD |
207 | #define HAMMER2_IOQ_ERROR_SYNC 1 /* bad magic / out of sync */ |
| 208 | #define HAMMER2_IOQ_ERROR_EOF 2 /* unexpected EOF */ | |
| 209 | #define HAMMER2_IOQ_ERROR_SOCK 3 /* read() error on socket */ | |
| 210 | #define HAMMER2_IOQ_ERROR_FIELD 4 /* invalid field */ | |
| 211 | #define HAMMER2_IOQ_ERROR_HCRC 5 /* core header crc bad */ | |
| 212 | #define HAMMER2_IOQ_ERROR_XCRC 6 /* ext header crc bad */ | |
| 213 | #define HAMMER2_IOQ_ERROR_ACRC 7 /* aux data crc bad */ | |
| 214 | #define HAMMER2_IOQ_ERROR_STATE 8 /* bad state */ | |
| 215 | #define HAMMER2_IOQ_ERROR_NOPEER 9 /* bad socket peer */ | |
| 216 | #define HAMMER2_IOQ_ERROR_NORKEY 10 /* no remote keyfile found */ | |
| 217 | #define HAMMER2_IOQ_ERROR_NOLKEY 11 /* no local keyfile found */ | |
| 218 | #define HAMMER2_IOQ_ERROR_KEYXCHGFAIL 12 /* key exchange failed */ | |
| 219 | #define HAMMER2_IOQ_ERROR_KEYFMT 13 /* key file format problem */ | |
| 220 | #define HAMMER2_IOQ_ERROR_BADURANDOM 14 /* /dev/urandom is bad */ | |
| 5cf97ec5 | 221 | #define HAMMER2_IOQ_ERROR_MSGSEQ 15 /* message sequence error */ |
| 78476205 MD |
222 | #define HAMMER2_IOQ_ERROR_EALREADY 16 /* ignore this message */ |
| 223 | #define HAMMER2_IOQ_ERROR_TRANS 17 /* state transaction issue */ | |
| 9ab15106 MD |
224 | |
| 225 | #define HAMMER2_IOQ_MAXIOVEC 16 | |
| 226 | ||
| 227 | /* | |
| 29ead430 MD |
228 | * hammer2_router - governs the routing of a message. Passed into |
| 229 | * hammer2_msg_write. | |
| 230 | * | |
| 231 | * The router is either connected to an iocom (socket) directly, or | |
| 232 | * connected to a SPAN transaction (h2span_link structure). | |
| 233 | */ | |
| 234 | struct hammer2_router { | |
| 235 | struct hammer2_iocom *iocom; | |
| 236 | struct h2span_link *link; /* non-NULL if indirect */ | |
| 237 | void (*signal_callback)(struct hammer2_router *); | |
| 238 | void (*rcvmsg_callback)(struct hammer2_msg *); | |
| 239 | void (*altmsg_callback)(struct hammer2_iocom *); | |
| 240 | struct hammer2_state_tree staterd_tree; /* active messages */ | |
| 241 | struct hammer2_state_tree statewr_tree; /* active messages */ | |
| 242 | hammer2_msg_queue_t txmsgq; /* tx msgq from remote */ | |
| 243 | int refs; /* refs prevent destruction */ | |
| 244 | }; | |
| 245 | ||
| 246 | typedef struct hammer2_router hammer2_router_t; | |
| 247 | ||
| 248 | /* | |
| 9ab15106 MD |
249 | * hammer2_iocom - governs a messaging stream connection |
| 250 | */ | |
| 251 | struct hammer2_iocom { | |
| 252 | hammer2_ioq_t ioq_rx; | |
| 253 | hammer2_ioq_t ioq_tx; | |
| 254 | hammer2_msg_queue_t freeq; /* free msgs hdr only */ | |
| 255 | hammer2_msg_queue_t freeq_aux; /* free msgs w/aux_data */ | |
| 8c280d5d | 256 | struct hammer2_address_queue addrq; /* source/target addrs */ |
| 9ab15106 MD |
257 | int sock_fd; /* comm socket or pipe */ |
| 258 | int alt_fd; /* thread signal, tty, etc */ | |
| 7dc0f844 | 259 | int wakeupfds[2]; /* pipe wakes up iocom thread */ |
| 9ab15106 | 260 | int flags; |
| 62efe6ec MD |
261 | int rxmisc; |
| 262 | int txmisc; | |
| 5cf97ec5 | 263 | char sess[HAMMER2_AES_KEY_SIZE]; /* aes_256_cbc key */ |
| 29ead430 | 264 | struct hammer2_router router; |
| 7dc0f844 | 265 | pthread_mutex_t mtx; /* mutex for state*tree/rmsgq */ |
| 9ab15106 MD |
266 | }; |
| 267 | ||
| 268 | typedef struct hammer2_iocom hammer2_iocom_t; | |
| 269 | ||
| 270 | #define HAMMER2_IOCOMF_EOF 0x00000001 /* EOF or ERROR on desc */ | |
| 271 | #define HAMMER2_IOCOMF_RREQ 0x00000002 /* request read-data event */ | |
| 272 | #define HAMMER2_IOCOMF_WREQ 0x00000004 /* request write-avail event */ | |
| 7dc0f844 MD |
273 | #define HAMMER2_IOCOMF_RWORK 0x00000008 /* immediate work pending */ |
| 274 | #define HAMMER2_IOCOMF_WWORK 0x00000010 /* immediate work pending */ | |
| 275 | #define HAMMER2_IOCOMF_PWORK 0x00000020 /* immediate work pending */ | |
| 276 | #define HAMMER2_IOCOMF_ARWORK 0x00000040 /* immediate work pending */ | |
| 277 | #define HAMMER2_IOCOMF_AWWORK 0x00000080 /* immediate work pending */ | |
| 5903497c MD |
278 | #define HAMMER2_IOCOMF_SWORK 0x00000100 /* immediate work pending */ |
| 279 | #define HAMMER2_IOCOMF_CRYPTED 0x00000200 /* encrypt enabled */ |