diff options
Diffstat (limited to 'usr.sbin/sasyncd/net.c')
-rw-r--r-- | usr.sbin/sasyncd/net.c | 234 |
1 files changed, 185 insertions, 49 deletions
diff --git a/usr.sbin/sasyncd/net.c b/usr.sbin/sasyncd/net.c index 8cb3dddc0e7..637f3f3258a 100644 --- a/usr.sbin/sasyncd/net.c +++ b/usr.sbin/sasyncd/net.c @@ -1,4 +1,4 @@ -/* $OpenBSD: net.c,v 1.1 2005/03/30 18:44:49 ho Exp $ */ +/* $OpenBSD: net.c,v 1.2 2005/05/22 20:35:48 ho Exp $ */ /* * Copyright (c) 2005 Håkan Olsson. All rights reserved. @@ -36,7 +36,12 @@ #include <netinet/in.h> #include <arpa/inet.h> +#include <openssl/aes.h> +#include <openssl/sha.h> + #include <errno.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> #include <unistd.h> @@ -45,9 +50,7 @@ struct msg { u_int8_t *buf; - u_int8_t *obuf; /* Original buf w/o offset. */ u_int32_t len; - u_int32_t type; int refcnt; }; @@ -57,12 +60,31 @@ struct qmsg { }; int listen_socket; +AES_KEY aes_key[2]; +#define AES_IV_LEN AES_BLOCK_SIZE /* Local prototypes. */ static u_int8_t *net_read(struct syncpeer *, u_int32_t *, u_int32_t *); static int net_set_sa(struct sockaddr *, char *, in_port_t); static void net_check_peers(void *); +static void +dump_buf(int lvl, u_int8_t *b, u_int32_t len, char *title) +{ + u_int32_t i, off, blen = len*2 + 3 + strlen(title); + u_int8_t *buf = calloc(1, blen); + + if (!buf || cfgstate.verboselevel < lvl) + return; + + snprintf(buf, blen, "%s:\n", title); + off = strlen(buf); + for (i = 0; i < len; i++, off+=2) + snprintf(buf + off, blen - off, "%02x", b[i]); + log_msg(lvl, "%s", buf); + free(buf); +} + int net_init(void) { @@ -71,8 +93,19 @@ net_init(void) struct syncpeer *p; int r; - if (net_SSL_init()) + /* The shared key needs to be 128, 192 or 256 bits */ + r = (strlen(cfgstate.sharedkey) - 1) << 3; + if (r != 128 && r != 192 && r != 256) { + fprintf(stderr, "Bad shared key length (%d bits), " + "should be 128, 192 or 256\n", r); return -1; + } + + if (AES_set_encrypt_key(cfgstate.sharedkey, r, &aes_key[0]) || + AES_set_decrypt_key(cfgstate.sharedkey, r, &aes_key[1])) { + fprintf(stderr, "Bad AES shared key\n"); + return -1; + } /* Setup listening socket. */ memset(&sa_storage, 0, sizeof sa_storage); @@ -124,10 +157,6 @@ net_enqueue(struct syncpeer *p, struct msg *m) if (p->socket < 0) return; - if (!p->ssl) - if (net_SSL_connect(p)) - return; - qm = (struct qmsg *)malloc(sizeof *qm); if (!qm) { log_err("malloc()"); @@ -147,23 +176,87 @@ net_enqueue(struct syncpeer *p, struct msg *m) * or to all peers if no peer is specified. */ int -net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, - u_int32_t offset, u_int32_t len) +net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, u_int32_t len) { struct syncpeer *p = p0; struct msg *m; + SHA_CTX ctx; + u_int8_t hash[SHA_DIGEST_LENGTH]; + u_int8_t iv[AES_IV_LEN], tmp_iv[AES_IV_LEN]; + u_int32_t v, padlen = 0; + int i, offset; - m = (struct msg *)malloc(sizeof *m); + m = (struct msg *)calloc(1, sizeof *m); if (!m) { - log_err("malloc()"); + log_err("calloc()"); free(buf); return -1; } - memset(m, 0, sizeof *m); - m->obuf = buf; - m->buf = buf + offset; - m->len = len; - m->type = msgtype; + + /* Generate hash */ + SHA1_Init(&ctx); + SHA1_Update(&ctx, buf, len); + SHA1_Final(hash, &ctx); + dump_buf(5, hash, sizeof hash, "Hash"); + + /* Padding required? */ + i = len % AES_IV_LEN; + if (i) { + u_int8_t *pbuf; + i = AES_IV_LEN - i; + pbuf = realloc(buf, len + i); + if (!pbuf) { + log_err("net_queue: realloc()"); + free(buf); + free(m); + return -1; + } + padlen = i; + while (i > 0) + pbuf[len++] = (u_int8_t)i--; + buf = pbuf; + } + + /* Get random IV */ + for (i = 0; i <= sizeof iv - sizeof v; i += sizeof v) { + v = arc4random(); + memcpy(&iv[i], &v, sizeof v); + } + dump_buf(5, iv, sizeof iv, "IV"); + memcpy(tmp_iv, iv, sizeof tmp_iv); + + /* Encrypt */ + dump_buf(5, buf, len, "Pre-enc"); + AES_cbc_encrypt(buf, buf, len, &aes_key[0], tmp_iv, AES_ENCRYPT); + dump_buf(5, buf, len, "Post-enc"); + + /* Allocate send buffer */ + m->len = len + sizeof iv + sizeof hash + 3 * sizeof(u_int32_t); + m->buf = (u_int8_t *)malloc(m->len); + if (!m->buf) { + free(m); + free(buf); + log_err("net_queue: calloc()"); + return -1; + } + offset = 0; + + /* Fill it (order must match parsing code in net_read()) */ + v = htonl(m->len - sizeof(u_int32_t)); + memcpy(m->buf + offset, &v, sizeof v); + offset += sizeof v; + v = htonl(msgtype); + memcpy(m->buf + offset, &v, sizeof v); + offset += sizeof v; + v = htonl(padlen); + memcpy(m->buf + offset, &v, sizeof v); + offset += sizeof v; + memcpy(m->buf + offset, hash, sizeof hash); + offset += sizeof hash; + memcpy(m->buf + offset, iv, sizeof iv); + offset += sizeof iv; + memcpy(m->buf + offset, buf, len); + free(buf); if (p) net_enqueue(p, m); @@ -173,7 +266,7 @@ net_queue(struct syncpeer *p0, u_int32_t msgtype, u_int8_t *buf, net_enqueue(p, m); if (!m->refcnt) { - free(m->obuf); + free(m->buf); free(m); } @@ -265,7 +358,6 @@ net_handle_messages(fd_set *fds) /* Match! */ found++; p->socket = newsock; - p->ssl = NULL; log_msg(1, "peer \"%s\" connected", p->name); } if (!found) { @@ -324,7 +416,7 @@ net_send_messages(fd_set *fds) struct syncpeer *p; struct qmsg *qm; struct msg *m; - u_int32_t v; + ssize_t r; for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { if (p->socket < 0 || !FD_ISSET(p->socket, fds)) @@ -337,27 +429,25 @@ net_send_messages(fd_set *fds) } m = qm->msg; - log_msg(4, "sending msg %p (qm %p ref %d) to peer %s", m, qm, - m->refcnt, p->name); + log_msg(4, "sending msg %p len %d ref %d to peer %s", m, + m->len, m->refcnt, p->name); - /* Send the message. */ - v = htonl(m->type); - if (net_SSL_write(p, &v, sizeof v)) + /* write message */ + r = write(p->socket, m->buf, m->len); + if (r == -1) + log_err("net_send_messages: write()"); + else if (r < (ssize_t)m->len) { + /* XXX retransmit? */ continue; + } - v = htonl(m->len); - if (net_SSL_write(p, &v, sizeof v)) - continue; - - (void)net_SSL_write(p, m->buf, m->len); - - /* Cleanup. */ + /* cleanup */ SIMPLEQ_REMOVE_HEAD(&p->msgs, next); free(qm); if (--m->refcnt < 1) { log_msg(4, "freeing msg %p", m); - free(m->obuf); + free(m->buf); free(m); } } @@ -367,7 +457,6 @@ net_send_messages(fd_set *fds) void net_disconnect_peer(struct syncpeer *p) { - net_SSL_disconnect(p); if (p->socket > -1) close(p->socket); p->socket = -1; @@ -385,7 +474,7 @@ net_shutdown(void) SIMPLEQ_REMOVE_HEAD(&p->msgs, next); m = qm->msg; if (--m->refcnt < 1) { - free(m->obuf); + free(m->buf); free(m); } free(qm); @@ -399,7 +488,6 @@ net_shutdown(void) if (listen_socket > -1) close(listen_socket); - net_SSL_shutdown(); } /* @@ -409,29 +497,77 @@ net_shutdown(void) static u_int8_t * net_read(struct syncpeer *p, u_int32_t *msgtype, u_int32_t *msglen) { - u_int8_t *msg; - u_int32_t v; + u_int8_t *msg, *blob, *rhash, *iv, hash[SHA_DIGEST_LENGTH]; + u_int32_t v, blob_len; + int padlen = 0, offset = 0, r; + SHA_CTX ctx; - if (net_SSL_read(p, &v, sizeof v)) + /* Read blob length */ + if (read(p->socket, &v, sizeof v) != (ssize_t)sizeof v) return NULL; - *msgtype = ntohl(v); + blob_len = ntohl(v); + if (blob_len < sizeof hash + AES_IV_LEN + 2 * sizeof(u_int32_t)) + return NULL; + *msglen = blob_len - sizeof hash - AES_IV_LEN - 2 * sizeof(u_int32_t); - if (*msgtype > MSG_MAXTYPE) + /* Read message blob */ + blob = (u_int8_t *)malloc(blob_len); + if (!blob) { + log_err("net_read: malloc()"); + return NULL; + } + r = read(p->socket, blob, blob_len); + if (r == -1) { + free(blob); + return NULL; + } else if (r < (ssize_t)blob_len) { + /* XXX wait and read more? */ + fprintf(stderr, "net_read: wanted %d, got %d\n", blob_len, r); + free(blob); return NULL; + } + + offset = 0; + memcpy(&v, blob + offset, sizeof v); + *msgtype = ntohl(v); + offset += sizeof v; - if (net_SSL_read(p, &v, sizeof v)) + if (*msgtype > MSG_MAXTYPE) { + free(blob); return NULL; - *msglen = ntohl(v); + } - /* XXX msglen sanity */ + memcpy(&v, blob + offset, sizeof v); + padlen = ntohl(v); + offset += sizeof v; + rhash = blob + offset; + iv = rhash + sizeof hash; msg = (u_int8_t *)malloc(*msglen); - memset(msg, 0, *msglen); - if (net_SSL_read(p, msg, *msglen)) { - free(msg); + if (!msg) { + free(blob); return NULL; } - + memcpy(msg, iv + AES_IV_LEN, *msglen); + + dump_buf(5, rhash, sizeof hash, "Recv hash"); + dump_buf(5, iv, sizeof iv, "Recv IV"); + dump_buf(5, msg, *msglen, "Pre-decrypt"); + AES_cbc_encrypt(msg, msg, *msglen, &aes_key[1], iv, AES_DECRYPT); + dump_buf(5, msg, *msglen, "Post-decrypt"); + *msglen -= padlen; + + SHA1_Init(&ctx); + SHA1_Update(&ctx, msg, *msglen); + SHA1_Final(hash, &ctx); + dump_buf(5, hash, sizeof hash, "Local hash"); + + if (memcmp(hash, rhash, sizeof hash) != 0) { + free(blob); + log_msg(0, "net_read: bad msg hash (shared key typo?)"); + return NULL; + } + free(blob); return msg; } @@ -487,7 +623,7 @@ net_connect_peers(void) setitimer(ITIMER_REAL, &iv, NULL); for (p = LIST_FIRST(&cfgstate.peerlist); p; p = LIST_NEXT(p, link)) { - if (p->ssl || p->socket > -1) + if (p->socket > -1) continue; memset(sa, 0, sizeof sa_storage); |