2 * Copyright (c) 2011-2012 The DragonFly Project. All rights reserved.
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>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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.
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
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 */
41 /***************************************************************************
43 ***************************************************************************
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:
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
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.
60 * (3) Additional configuration and additional random data.
62 * - The hammer2 message header magic for endian detect
64 * - The hammer2 protocol version. The two sides agree on the
67 * - All unused fields (junk*) are filled with random data.
69 * This structure must be exactly 512 bytes and expects to use 256-byte
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 */
85 typedef struct hammer2_handshake hammer2_handshake_t;
88 * NOTE: HAMMER2_MSG_ALIGN (64) must be a multiple of HAMMER2_AES_KEY_SIZE.
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
96 /***************************************************************************
97 * LOW LEVEL MESSAGING *
98 ***************************************************************************
100 * hammer2_msg - A standalone copy of a message, typically referenced by
101 * or embedded in other structures, or used with I/O queues.
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
109 * This structure is typically not used for storing persistent message
110 * state (see hammer2_persist for that).
112 struct hammer2_iocom;
113 struct hammer2_persist;
114 struct hammer2_state;
115 struct hammer2_address;
118 TAILQ_HEAD(hammer2_state_queue, hammer2_state);
119 TAILQ_HEAD(hammer2_msg_queue, hammer2_msg);
120 TAILQ_HEAD(hammer2_address_queue, hammer2_address);
121 RB_HEAD(hammer2_state_tree, hammer2_state);
124 struct h2span_connect;
126 struct hammer2_state {
127 RB_ENTRY(hammer2_state) rbnode; /* indexed by msgid */
128 TAILQ_ENTRY(hammer2_state) source_entry;/* if routed */
129 TAILQ_ENTRY(hammer2_state) target_entry;/* if routed */
130 struct hammer2_iocom *iocom;
131 struct hammer2_address_t *source_addr; /* if routed */
132 struct hammer2_address_t *target_addr; /* if routed */
133 uint32_t txcmd; /* mostly for CMDF flags */
134 uint32_t rxcmd; /* mostly for CMDF flags */
135 uint64_t spanid; /* routing id */
136 uint64_t msgid; /* {spanid,msgid} uniq */
139 struct hammer2_msg *msg;
140 void (*func)(struct hammer2_state *, struct hammer2_msg *);
143 struct h2span_link *link;
144 struct h2span_connect *conn;
145 struct h2span_relay *relay;
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 */
157 #define HAMMER2_STATE_INSERTED 0x0001
158 #define HAMMER2_STATE_DYNAMIC 0x0002
159 #define HAMMER2_STATE_NODEID 0x0004 /* manages a node id */
162 TAILQ_ENTRY(hammer2_msg) qentry;
163 struct hammer2_state *state;
167 hammer2_msg_any_t any;
170 typedef struct hammer2_state hammer2_state_t;
171 typedef struct hammer2_address hammer2_address_t;
172 typedef struct hammer2_msg hammer2_msg_t;
173 typedef struct hammer2_msg_queue hammer2_msg_queue_t;
175 int hammer2_state_cmp(hammer2_state_t *state1, hammer2_state_t *state2);
176 RB_PROTOTYPE(hammer2_state_tree, hammer2_state, rbnode, hammer2_state_cmp);
179 * hammer2_ioq - An embedded component of hammer2_connect, holds state
180 * for the buffering and parsing of incoming and outgoing messages.
183 enum { HAMMER2_MSGQ_STATE_HEADER1,
184 HAMMER2_MSGQ_STATE_HEADER2,
185 HAMMER2_MSGQ_STATE_AUXDATA1,
186 HAMMER2_MSGQ_STATE_AUXDATA2,
187 HAMMER2_MSGQ_STATE_ERROR } state;
188 int fifo_beg; /* buffered data */
189 int fifo_cdx; /* encrypt/decrypt index */
191 size_t hbytes; /* header size */
192 size_t abytes; /* aux_data size */
193 size_t already; /* aux_data already decrypted */
195 int seq; /* salt sequencer */
198 char iv[HAMMER2_AES_KEY_SIZE]; /* encrypt or decrypt iv[] */
200 hammer2_msg_queue_t msgq;
201 char buf[HAMMER2_MSGBUF_SIZE]; /* staging buffer */
204 typedef struct hammer2_ioq hammer2_ioq_t;
206 #define HAMMER2_IOQ_ERROR_SYNC 1 /* bad magic / out of sync */
207 #define HAMMER2_IOQ_ERROR_EOF 2 /* unexpected EOF */
208 #define HAMMER2_IOQ_ERROR_SOCK 3 /* read() error on socket */
209 #define HAMMER2_IOQ_ERROR_FIELD 4 /* invalid field */
210 #define HAMMER2_IOQ_ERROR_HCRC 5 /* core header crc bad */
211 #define HAMMER2_IOQ_ERROR_XCRC 6 /* ext header crc bad */
212 #define HAMMER2_IOQ_ERROR_ACRC 7 /* aux data crc bad */
213 #define HAMMER2_IOQ_ERROR_STATE 8 /* bad state */
214 #define HAMMER2_IOQ_ERROR_NOPEER 9 /* bad socket peer */
215 #define HAMMER2_IOQ_ERROR_NORKEY 10 /* no remote keyfile found */
216 #define HAMMER2_IOQ_ERROR_NOLKEY 11 /* no local keyfile found */
217 #define HAMMER2_IOQ_ERROR_KEYXCHGFAIL 12 /* key exchange failed */
218 #define HAMMER2_IOQ_ERROR_KEYFMT 13 /* key file format problem */
219 #define HAMMER2_IOQ_ERROR_BADURANDOM 14 /* /dev/urandom is bad */
220 #define HAMMER2_IOQ_ERROR_MSGSEQ 15 /* message sequence error */
221 #define HAMMER2_IOQ_ERROR_EALREADY 16 /* ignore this message */
222 #define HAMMER2_IOQ_ERROR_TRANS 17 /* state transaction issue */
224 #define HAMMER2_IOQ_MAXIOVEC 16
227 * hammer2_iocom - governs a messaging stream connection
229 struct hammer2_iocom {
230 hammer2_ioq_t ioq_rx;
231 hammer2_ioq_t ioq_tx;
232 hammer2_msg_queue_t freeq; /* free msgs hdr only */
233 hammer2_msg_queue_t freeq_aux; /* free msgs w/aux_data */
234 struct hammer2_address_queue addrq; /* source/target addrs */
235 void (*state_callback)(struct hammer2_iocom *);
236 void (*rcvmsg_callback)(struct hammer2_iocom *,
237 struct hammer2_msg *);
238 void (*altmsg_callback)(struct hammer2_iocom *);
239 int sock_fd; /* comm socket or pipe */
240 int alt_fd; /* thread signal, tty, etc */
241 int wakeupfds[2]; /* pipe wakes up iocom thread */
245 char sess[HAMMER2_AES_KEY_SIZE]; /* aes_256_cbc key */
246 struct hammer2_state_tree staterd_tree; /* active messages */
247 struct hammer2_state_tree statewr_tree; /* active messages */
248 hammer2_msg_queue_t txmsgq; /* tx msgq from remote */
249 pthread_mutex_t mtx; /* mutex for state*tree/rmsgq */
252 typedef struct hammer2_iocom hammer2_iocom_t;
254 #define HAMMER2_IOCOMF_EOF 0x00000001 /* EOF or ERROR on desc */
255 #define HAMMER2_IOCOMF_RREQ 0x00000002 /* request read-data event */
256 #define HAMMER2_IOCOMF_WREQ 0x00000004 /* request write-avail event */
257 #define HAMMER2_IOCOMF_RWORK 0x00000008 /* immediate work pending */
258 #define HAMMER2_IOCOMF_WWORK 0x00000010 /* immediate work pending */
259 #define HAMMER2_IOCOMF_PWORK 0x00000020 /* immediate work pending */
260 #define HAMMER2_IOCOMF_ARWORK 0x00000040 /* immediate work pending */
261 #define HAMMER2_IOCOMF_AWWORK 0x00000080 /* immediate work pending */
262 #define HAMMER2_IOCOMF_SWORK 0x00000100 /* immediate work pending */
263 #define HAMMER2_IOCOMF_CRYPTED 0x00000200 /* encrypt enabled */