hammer2 - further crypto cleanup
[dragonfly.git] / sbin / hammer2 / network.h
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
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
41 /***************************************************************************
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  *
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).
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
87
88 #define HAMMER2_CRYPTO_CHUNK_SIZE               HAMMER2_MSG_ALIGN
89 #define HAMMER2_MAX_IV_SIZE                     32
90
91 #define HAMMER2_CRYPTO_GCM_IV_FIXED_SIZE        4
92 #define HAMMER2_CRYPTO_GCM_IV_SIZE              12
93 #define HAMMER2_CRYPTO_GCM_KEY_SIZE             32
94 #define HAMMER2_CRYPTO_GCM_TAG_SIZE             16
95
96 #define HAMMER2_CRYPTO_ALGO_GCM_IDX             0
97
98 #define HAMMER2_CRYPTO_ALGO                     HAMMER2_CRYPTO_ALGO_GCM_IDX
99
100
101
102
103 /***************************************************************************
104  *                              LOW LEVEL MESSAGING                        *
105  ***************************************************************************
106  *
107  * hammer2_msg - A standalone copy of a message, typically referenced by
108  *               or embedded in other structures, or used with I/O queues.
109  *
110  * These structures are strictly temporary, so they do not have to be
111  * particularly optimized for size.  All possible message headers are
112  * directly embedded (any), and the message may contain a reference
113  * to allocated auxillary data.  The structure is recycled quite often
114  * by a connection.
115  *
116  * This structure is typically not used for storing persistent message
117  * state (see hammer2_persist for that).
118  */
119 struct hammer2_iocom;
120 struct hammer2_persist;
121 struct hammer2_state;
122 struct hammer2_router;
123 struct hammer2_address;
124 struct hammer2_msg;
125
126 TAILQ_HEAD(hammer2_state_queue, hammer2_state);
127 TAILQ_HEAD(hammer2_msg_queue, hammer2_msg);
128 TAILQ_HEAD(hammer2_address_queue, hammer2_address);
129 RB_HEAD(hammer2_state_tree, hammer2_state);
130 RB_HEAD(hammer2_router_tree, hammer2_router);
131
132 struct h2span_link;
133 struct h2span_relay;
134 struct h2span_connect;
135
136 struct hammer2_state {
137         RB_ENTRY(hammer2_state) rbnode;         /* indexed by msgid */
138         TAILQ_ENTRY(hammer2_state) source_entry;/* if routed */
139         TAILQ_ENTRY(hammer2_state) target_entry;/* if routed */
140         struct hammer2_iocom *iocom;
141         struct hammer2_address_t *source_addr;  /* if routed */
142         struct hammer2_address_t *target_addr;  /* if routed */
143         uint32_t        txcmd;                  /* mostly for CMDF flags */
144         uint32_t        rxcmd;                  /* mostly for CMDF flags */
145         uint64_t        spanid;                 /* routing id */
146         uint64_t        msgid;                  /* {spanid,msgid} uniq */
147         int             flags;
148         int             error;
149         struct hammer2_msg *msg;
150         void (*func)(struct hammer2_msg *);
151         union {
152                 void *any;
153                 struct h2span_link *link;
154                 struct h2span_connect *conn;
155                 struct h2span_relay *relay;
156         } any;
157 };
158
159 struct hammer2_address {
160         TAILQ_ENTRY(hammer2_address) entry;     /* on-iocom */
161         struct hammer2_iocom *iocom;            /* related iocom */
162         struct hammer2_state_queue sourceq;     /* states on source queue */
163         struct hammer2_state_queue targetq;     /* states on target queue */
164         uint16_t        id;
165 };
166
167 #define HAMMER2_STATE_INSERTED  0x0001
168 #define HAMMER2_STATE_DYNAMIC   0x0002
169 #define HAMMER2_STATE_NODEID    0x0004          /* manages a node id */
170
171 struct hammer2_msg {
172         TAILQ_ENTRY(hammer2_msg) qentry;
173         struct hammer2_router *router;
174         struct hammer2_state *state;
175         size_t          hdr_size;
176         size_t          aux_size;
177         char            *aux_data;
178         hammer2_msg_any_t any;
179 };
180
181 typedef struct hammer2_state hammer2_state_t;
182 typedef struct hammer2_address hammer2_address_t;
183 typedef struct hammer2_msg hammer2_msg_t;
184 typedef struct hammer2_msg_queue hammer2_msg_queue_t;
185
186 int hammer2_state_cmp(hammer2_state_t *state1, hammer2_state_t *state2);
187 RB_PROTOTYPE(hammer2_state_tree, hammer2_state, rbnode, hammer2_state_cmp);
188
189 /*
190  * hammer2_ioq - An embedded component of hammer2_connect, holds state
191  * for the buffering and parsing of incoming and outgoing messages.
192  *
193  * cdx - beg  - processed buffer data, encrypted or decrypted
194  * end - cdn  - unprocessed buffer data not yet encrypted or decrypted
195  */
196 struct hammer2_ioq {
197         enum { HAMMER2_MSGQ_STATE_HEADER1,
198                HAMMER2_MSGQ_STATE_HEADER2,
199                HAMMER2_MSGQ_STATE_AUXDATA1,
200                HAMMER2_MSGQ_STATE_AUXDATA2,
201                HAMMER2_MSGQ_STATE_ERROR } state;
202         size_t          fifo_beg;               /* buffered data */
203         size_t          fifo_cdx;               /* cdx-beg processed */
204         size_t          fifo_cdn;               /* end-cdn unprocessed */
205         size_t          fifo_end;
206         size_t          hbytes;                 /* header size */
207         size_t          abytes;                 /* aux_data size */
208         int             error;
209         int             seq;                    /* salt sequencer */
210         int             msgcount;
211         EVP_CIPHER_CTX  ctx;
212         char            iv[HAMMER2_MAX_IV_SIZE]; /* encrypt or decrypt iv[] */
213         hammer2_msg_t   *msg;
214         hammer2_msg_queue_t msgq;
215         char            buf[HAMMER2_MSGBUF_SIZE]; /* staging buffer */
216 };
217
218 typedef struct hammer2_ioq hammer2_ioq_t;
219
220 #define HAMMER2_IOQ_ERROR_SYNC          1       /* bad magic / out of sync */
221 #define HAMMER2_IOQ_ERROR_EOF           2       /* unexpected EOF */
222 #define HAMMER2_IOQ_ERROR_SOCK          3       /* read() error on socket */
223 #define HAMMER2_IOQ_ERROR_FIELD         4       /* invalid field */
224 #define HAMMER2_IOQ_ERROR_HCRC          5       /* core header crc bad */
225 #define HAMMER2_IOQ_ERROR_XCRC          6       /* ext header crc bad */
226 #define HAMMER2_IOQ_ERROR_ACRC          7       /* aux data crc bad */
227 #define HAMMER2_IOQ_ERROR_STATE         8       /* bad state */
228 #define HAMMER2_IOQ_ERROR_NOPEER        9       /* bad socket peer */
229 #define HAMMER2_IOQ_ERROR_NORKEY        10      /* no remote keyfile found */
230 #define HAMMER2_IOQ_ERROR_NOLKEY        11      /* no local keyfile found */
231 #define HAMMER2_IOQ_ERROR_KEYXCHGFAIL   12      /* key exchange failed */
232 #define HAMMER2_IOQ_ERROR_KEYFMT        13      /* key file format problem */
233 #define HAMMER2_IOQ_ERROR_BADURANDOM    14      /* /dev/urandom is bad */
234 #define HAMMER2_IOQ_ERROR_MSGSEQ        15      /* message sequence error */
235 #define HAMMER2_IOQ_ERROR_EALREADY      16      /* ignore this message */
236 #define HAMMER2_IOQ_ERROR_TRANS         17      /* state transaction issue */
237 #define HAMMER2_IOQ_ERROR_IVWRAP        18      /* IVs exhaused */
238 #define HAMMER2_IOQ_ERROR_MACFAIL       19      /* MAC of encryption algorithm failed */
239 #define HAMMER2_IOQ_ERROR_ALGO          20      /* Misc. encryption algorithm error */
240
241 #define HAMMER2_IOQ_MAXIOVEC    16
242
243 /*
244  * hammer2_router - governs the routing of a message.  Passed into
245  *                  hammer2_msg_write.
246  *
247  * The router is either connected to an iocom (socket) directly, or
248  * connected to a SPAN transaction (h2span_link structure for outgoing)
249  * or to a SPAN transaction (h2span_relay structure for incoming).
250  */
251 struct hammer2_router {
252         RB_ENTRY(hammer2_router) rbnode;        /* indexed by spanid */
253         struct hammer2_iocom *iocom;
254         struct h2span_link   *link;             /* may be NULL */
255         struct h2span_relay  *relay;            /* may be NULL */
256         void    (*signal_callback)(struct hammer2_router *);
257         void    (*rcvmsg_callback)(struct hammer2_msg *);
258         void    (*altmsg_callback)(struct hammer2_iocom *);
259         struct hammer2_state_tree staterd_tree; /* active messages */
260         struct hammer2_state_tree statewr_tree; /* active messages */
261         hammer2_msg_queue_t txmsgq;             /* tx msgq from remote */
262         uint64_t        spanid;                 /* for routing */
263         int     flags;
264         int     refs;                           /* refs prevent destruction */
265 };
266
267 #define HAMMER2_ROUTER_CONNECTED        0x0001  /* on global RB tree */
268 #define HAMMER2_ROUTER_DELETED          0x0002  /* parent structure destroyed */
269
270 typedef struct hammer2_router hammer2_router_t;
271
272 int hammer2_router_cmp(hammer2_router_t *router1, hammer2_router_t *router2);
273 RB_PROTOTYPE(hammer2_router_tree, hammer2_router, rbnode, hammer2_router_cmp);
274
275 /*
276  * hammer2_iocom - governs a messaging stream connection
277  */
278 struct hammer2_iocom {
279         hammer2_ioq_t   ioq_rx;
280         hammer2_ioq_t   ioq_tx;
281         hammer2_msg_queue_t freeq;              /* free msgs hdr only */
282         hammer2_msg_queue_t freeq_aux;          /* free msgs w/aux_data */
283         struct hammer2_address_queue  addrq;    /* source/target addrs */
284         int     sock_fd;                        /* comm socket or pipe */
285         int     alt_fd;                         /* thread signal, tty, etc */
286         int     wakeupfds[2];                   /* pipe wakes up iocom thread */
287         int     flags;
288         int     rxmisc;
289         int     txmisc;
290         struct hammer2_router *router;
291         pthread_mutex_t mtx;                    /* mutex for state*tree/rmsgq */
292 };
293
294 typedef struct hammer2_iocom hammer2_iocom_t;
295
296 #define HAMMER2_IOCOMF_EOF      0x00000001      /* EOF or ERROR on desc */
297 #define HAMMER2_IOCOMF_RREQ     0x00000002      /* request read-data event */
298 #define HAMMER2_IOCOMF_WREQ     0x00000004      /* request write-avail event */
299 #define HAMMER2_IOCOMF_RWORK    0x00000008      /* immediate work pending */
300 #define HAMMER2_IOCOMF_WWORK    0x00000010      /* immediate work pending */
301 #define HAMMER2_IOCOMF_PWORK    0x00000020      /* immediate work pending */
302 #define HAMMER2_IOCOMF_ARWORK   0x00000040      /* immediate work pending */
303 #define HAMMER2_IOCOMF_AWWORK   0x00000080      /* immediate work pending */
304 #define HAMMER2_IOCOMF_SWORK    0x00000100      /* immediate work pending */
305 #define HAMMER2_IOCOMF_CRYPTED  0x00000200      /* encrypt enabled */
306
307
308
309
310
311
312
313 /*
314  * Crypto algorithm table and related typedefs.
315  */
316
317 typedef int (*algo_init_fn)(hammer2_ioq_t *, char *, int, char *, int, int);
318 typedef int (*algo_enc_fn)(hammer2_ioq_t *, char *, char *, int, int *);
319 typedef int (*algo_dec_fn)(hammer2_ioq_t *, char *, char *, int, int *);
320
321 struct crypto_algo {
322         const char      *name;
323         int             keylen;
324         int             taglen;
325         algo_init_fn    init;
326         algo_enc_fn     enc_chunk;
327         algo_dec_fn     dec_chunk;
328 };