svn commit: r248837 - user/andre/tcp-ao/sys/netinet
Andre Oppermann
andre at FreeBSD.org
Thu Mar 28 17:06:09 UTC 2013
Author: andre
Date: Thu Mar 28 17:06:08 2013
New Revision: 248837
URL: http://svnweb.freebsd.org/changeset/base/248837
Log:
Add peer and key handling for listen and connected sockets as
well as the setsockopt() key interface.
When TCP-AO is activated on a TCP socket a tcp_ao control block
is allocated and attached to the tcpcb. An arbitrary number of
peer addresses and keys can be added. On accepting of a new
incoming connection only the peers keys are copied to the new
socket. On outbound connecting sockets only the keys for the
peer address will be kept.
Some parts are not fully implemented yet and other may change
again.
Sponsored by: Juniper Networks
Modified:
user/andre/tcp-ao/sys/netinet/tcp_ao.c
user/andre/tcp-ao/sys/netinet/tcp_ao.h
user/andre/tcp-ao/sys/netinet/tcp_usrreq.c
user/andre/tcp-ao/sys/netinet/tcp_var.h
Modified: user/andre/tcp-ao/sys/netinet/tcp_ao.c
==============================================================================
--- user/andre/tcp-ao/sys/netinet/tcp_ao.c Thu Mar 28 17:04:59 2013 (r248836)
+++ user/andre/tcp-ao/sys/netinet/tcp_ao.c Thu Mar 28 17:06:08 2013 (r248837)
@@ -55,6 +55,260 @@
* The code below is skeleton code and not functional yet.
*/
+MALLOC_DEFINE(M_TCPAO, "tcp_ao", "TCP-AO peer and key structures");
+
+int
+tcp_ao_ctl(struct tcpcb *tp, struct tcp_ao_sopt *tao, int tao_len)
+{
+ srtuct tcp_ao_cb *c;
+ struct tcp_ao_peer *p;
+ struct tcp_ao_key *k;
+ int error;
+
+ switch (tao->tao_peer.sa_family) {
+ case AF_INET:
+ if (tao->tao_peer.sa_len != sizeof(struct sockaddr_in))
+ error = EINVAL;
+ break;
+ case AF_INET6:
+ if (tao->tao_peer.sa_len != sizeof(struct sockaddr_in6))
+ error = EINVAL;
+ break;
+ default:
+ error = EINVAL;
+ }
+ if (error)
+ goto out;
+
+ c = tp->t_ao;
+
+ switch (tao->tao_cmd) {
+ case TAO_CMD_ADD:
+ switch (tao->tao_algo) {
+ case TAO_ALGO_MD5SIG:
+ case TAO_ALGO_HMAC-SHA-1-96:
+ case TAO_ALGO_AES-128-CMAC-96:
+ break;
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+ /* Insert or overwrite */
+ if ((p = tcp_ao_peer_add(c, tao)) == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (tp->t_state > TCPS_LISTEN &&
+ p->tap_activekey == tao->tao_keyidx) {
+ error = EINVAL;
+ break;
+ }
+ if ((k = tcp_ao_key_add(p, tao, taolen - sizeof(*tao)) == NULL) {
+ error = EINVAL;
+ }
+ break;
+
+ case TAO_CMD_DELIDX:
+ /* Can't remove active index */
+ if ((p = tcp_ao_peer_find(c, tao)) == NULL) {
+ error = EINVAL;
+ break;
+ }
+ if (tp->t_state > TCPS_LISTEN &&
+ p->tap_activekey == tao->tao_keyidx) {
+ error = EINVAL;
+ break;
+ }
+ if (tcp_ao_key_del(p, tao->tao_keyidx) != 0) {
+ error = ENOENT;
+ }
+ break;
+
+ case TAO_CMD_DELPEER:
+ if (tp->t_state > TCPS_LISTEN)
+ break;
+
+ if ((p = tcp_ao_peer_find(c, tao)) == NULL) {
+ error = EINVAL;
+ break;
+ }
+ tcp_ao_peer_del(c, p);
+ break;
+
+ case TAO_CMD_FLUSH:
+ if (tp->t_state > TCPS_LISTEN)
+ break;
+
+ tcp_ao_peer_flush(c);
+ break;
+
+ default:
+ error = EINVAL;
+ goto out;
+ }
+
+out:
+ return (error);
+}
+
+struct tcp_ao_peer *
+tcp_ao_peer_find(struct tcp_ao_cb *tac, struct sockaddr *sa)
+{
+ struct tcp_ao_peer *p;
+
+ LIST_FOREACH(p, tac->tac_peers, tap_entry) {
+ if (p->tap_peer.sa_family == sa->sa_family &&
+ !bcmp(p->tap_peer.sa_data, sa->sa_data,
+ min(p->tap_peer.sa.len, sa->sa_len)))
+ return (p);
+ }
+ return (NULL);
+}
+
+struct tcp_ao_peer *
+tcp_ao_peer_add(struct tcp_ao_cb *tac, struct tcp_ao_sopt *tao)
+{
+ struct tcp_ao_peer *p;
+
+ if ((p = tcp_ao_peer_find(tac, tao->tao_peer)) == NULL) {
+ if ((p = malloc(sizeof(*p), M_TCPAO, M_NOWAIT)) == NULL)
+ return (p);
+ p->tap_flags = 0;
+ bcopy(tao->tao_peer, p->tac_peer, tao->tao_peer.sa_len);
+ SLIST_INIT(&p->tak_keys);
+ }
+
+ LIST_INSERT_HEAD(&tap->tap_peers, p);
+ return (p);
+}
+
+int
+tcp_ao_peer_del(struct tcp_ao_cb *tac, struct tcp_ao_peer *tap)
+{
+
+ tcp_ao_key_flush(tap);
+ LIST_REMOVE(tap, tap_list);
+ free(tap, M_TCPAO);
+ return (0);
+}
+
+void
+tcp_ao_peer_flush(struct tcp_ao_cb *tac)
+{
+ struct tcp_ao_peer *p, *p2;
+
+ SLIST_FOREACH_SAFE(p, tac->tac_peers, entries, p2) {
+ tcp_ao_key_flush(p);
+ free(p, M_TCPAO);
+ }
+ LIST_INIT(&tac->tac_peers);
+}
+
+struct tcp_ao_key *
+tcp_ao_key_find(struct tcp_ao_peer *tap, uint8_t idx)
+{
+ struct tcp_ao_key *k;
+
+ SLIST_FOREACH(k, &tap->tap_keys, entry) {
+ if (k->keyidx == idx)
+ return (k);
+ }
+ return (NULL);
+}
+
+struct tcp_ao_key *
+tcp_ao_key_add(struct tcp_ao_peer *tap, struct tcp_so_sopt *tao, uint8_t keylen)
+{
+ struct tcp_ao_key *k;
+
+ if ((k = tcp_ao_key_find(tap, tao->tao_keyidx)) != NULL) {
+ SLIST_REMOVE(&tap->tap_keys, k, entry, entry);
+ free(k, M_TCPAO);
+ }
+ if ((k = malloc(sizeof(*k) + keylen, M_TCPAO, M_NOWAIT)) == NULL)
+ return (k);
+
+ k->keyidx = tao->tao_keyidx;
+ k->keyflags = 0;
+ k->keyalgo = tao->tao_keyalgo;
+ k->keylen = keylen;
+ bcopy(tao->tao_key, k->key, k->keylen);
+
+ SLIST_INSERT_HEAD(&tap->tap_keys, k);
+ return (k);
+}
+
+int
+struct tcp_ao_key_del(struct tcp_ao_peer *tap, uint8_t keyidx)
+{
+ struct tcp_ao_key *k, *k2;
+
+ SLIST_FOREACH_SAFE(k, &tap->tap_keys, entries, k2) {
+ if (k->keyidx == keyidx) {
+ SLIST_REMOVE(&tap->tap_keys, entries, entries);
+ free(k, M_TCPAO);
+ return (0);
+ }
+ }
+ return (ENOENT);
+}
+
+void
+tcp_ao_key_flush(struct tcp_ao_peer *tap)
+{
+ struct tcp_ao_key *k, *k2;
+
+ SLIST_FOREACH_SAFE(k, &tap->tap_keys, entries, k2)
+ free(k, M_TCPAO);
+ SLIST_INIT(&tap->tap_keys);
+}
+
+int
+tcp_ao_peer_clone(struct tcpcb *tp1, struct tcpcb *tp2, struct sockaddr *sa)
+{
+ struct tcp_ao_peer *p1, *p2;
+ struct tcp_ao_key *k1, *k2;
+
+ if ((p1 = tcp_ao_peer_find(tp1->t_ao, sa)) == NULL)
+ return (0);
+
+ if (tcp_ao_cb_alloc(tp2) != 0)
+ return (ENOMEM);
+
+ bcopy(p1, p2, malloc(sizeof(*p2));
+ SLIST_INIT(&p2->tak_keys);
+ SLIST_FOREACH(k1, &p1->tap_keys, entry) {
+ if ((k2 = malloc(sizeof(*k2) + k1->keylen, M_TCPAO, M_NOWAIT)) == NULL)
+ return (ENOMEM);
+ bcopy(k1, k2, k1->keylen);
+ SLIST_INSERT_HEAD(&p2->tap_keys, k2);
+ }
+ return (0);
+}
+
+struct tcp_ao_cb *
+tcp_ao_cb_alloc(void)
+{
+ struct tcp_ao_cb *c;
+
+ if ((c = malloc(sizeof(*c), M_TCPAO, M_ZERO|M_NOWAIT)) == NULL)
+ return (NULL);
+ LIST_INIT(&c->tac_peers);
+ return (c);
+}
+
+void
+tcp_ao_cb_free(struct tcpcb *tp)
+{
+ struct tcp_ao_cb *c;
+
+ c = tp->t_ao;
+ tp->t_ao = NULL;
+ tcp_ao_peer_flush(c);
+ free(c, M_TCPAO);
+}
+
/*
* There two types of key derivation in TCP-AO.
* One is to create the session key from the imported master key.
Modified: user/andre/tcp-ao/sys/netinet/tcp_ao.h
==============================================================================
--- user/andre/tcp-ao/sys/netinet/tcp_ao.h Thu Mar 28 17:04:59 2013 (r248836)
+++ user/andre/tcp-ao/sys/netinet/tcp_ao.h Thu Mar 28 17:06:08 2013 (r248837)
@@ -64,20 +64,23 @@
* once stable.
*/
+MALLOC_DECLARE(M_TCPAO);
+
/*
* TCP-AO key interface struct passed to setsockopt().
* Per peer structures referenced from tcp_ao_sopt.
* The commands normally apply to a particular keyidx and peer combination.
*/
-struct tcp_ao_ssopt {
+struct tcp_ao_sopt {
uint16_t tao_cmd; /* command, add, remove key */
uint16_t tao_flags; /* flags */
uint8_t tao_keyidx; /* key index per peer */
uint8_t tao_algo; /* MAC algorithm */
struct sockaddr_storage
tao_peer; /* this key applies to ... */
- uint8_t tao_key[]; /* key string */
+ uint8_t tao_key[]; /* base64 key string */
};
+#define TAO_KEY_MAXLEN 128 /* base64 encoded */
/*
* Commands for the tao_cmd field.
@@ -99,3 +102,37 @@ struct tcp_ao_ssopt {
#define TAO_ALGO_HMAC-SHA-1-96 2 /* RFC5926, Section 2.2 */
#define TAO_ALGO_AES-128-CMAC-96 3 /* RFC5926, Section 2.2 */
+/*
+ * In kernel storage of the key information.
+ */
+struct tcp_ao_cb {
+ int tac_algo;
+ union {
+ uint8_t md5[MD5_DIGEST_LENGTH];
+ uint8_t hmac[SHA1_DIGEST_LENGTH];
+ uint8_t cmac[AES_CMAC_LENGTH];
+ } tac_skey, tac_rkey;
+ LIST_HEAD(tac_peer, tcp_ao_peer) tac_peers;
+};
+
+struct tcp_ao_peer {
+ LIST_ENTRY(tcp_ao_peer) tap_entry;
+ uint16_t tap_flags;
+ union {
+ sockaddr sa;
+ sockaddr_in sin4;
+ sockaddr_in6 sin6;
+ } tap_peer;
+ uint8_t tap_activekey;
+ SLIST_HEAD() tap_keys;
+};
+
+struct tcp_ao_key {
+ SLIST_ENTRY(tcp_ao_key) entry;
+ uint8_t keyidx;
+ uint8_t keyflags;
+ uint8_t keyalgo;
+ uint8_t keylen;
+ uint8_t key[]; /* after base64_decode */
+};
+
Modified: user/andre/tcp-ao/sys/netinet/tcp_usrreq.c
==============================================================================
--- user/andre/tcp-ao/sys/netinet/tcp_usrreq.c Thu Mar 28 17:04:59 2013 (r248836)
+++ user/andre/tcp-ao/sys/netinet/tcp_usrreq.c Thu Mar 28 17:06:08 2013 (r248837)
@@ -1308,6 +1308,7 @@ tcp_ctloutput(struct socket *so, struct
u_int ui;
struct inpcb *inp;
struct tcpcb *tp;
+ void *x;
struct tcp_info ti;
char buf[TCP_CA_NAME_MAX];
struct cc_algo *algo;
@@ -1357,6 +1358,21 @@ tcp_ctloutput(struct socket *so, struct
tp->t_flags &= ~TF_SIGNATURE;
goto unlock_and_done;
#endif /* TCP_SIGNATURE */
+ case TCP_AO:
+ INP_WUNLOCK(inp);
+ if (sopt->sopt_valsize <= sizeof(struct tcp_ao_sopt) +
+ TAO_KEY_MAXLEN)
+ return (EINVAL);
+ if ((x = malloc(sopt->sopt_valsize, M_TEMP, M_WAITOK)) == NULL)
+ return (ENOMEM);
+ error = sooptcopyin(sopt, x, sopt->sopt_valsize,
+ sizeof(struct tcp_ao_sopt));
+ if (error)
+ return (error);
+
+ INP_WLOCK_RECHECK(inp);
+ error = tcp_ao_ctl(tp, x, sopt->sopt_valsize);
+ goto unlock_and_done;
case TCP_NODELAY:
case TCP_NOOPT:
@@ -1552,7 +1568,11 @@ unlock_and_done:
error = sooptcopyout(sopt, &optval, sizeof optval);
break;
#endif
-
+ case TCO_AO:
+ optval = (tp->t_flags & TF_AO) ? 1 : 0;
+ INP_WUNLOCK(inp);
+ error = sooptcopyout(sopt, &optval, sizeof optval);
+ break;
case TCP_NODELAY:
optval = tp->t_flags & TF_NODELAY;
INP_WUNLOCK(inp);
Modified: user/andre/tcp-ao/sys/netinet/tcp_var.h
==============================================================================
--- user/andre/tcp-ao/sys/netinet/tcp_var.h Thu Mar 28 17:04:59 2013 (r248836)
+++ user/andre/tcp-ao/sys/netinet/tcp_var.h Thu Mar 28 17:06:08 2013 (r248837)
@@ -208,8 +208,10 @@ struct tcpcb {
u_int t_keepintvl; /* interval between keepalives */
u_int t_keepcnt; /* number of keepalives before close */
+ struct tcp_ao_inp *t_ao; /* TCP-AO control functions */
+
uint32_t t_ispare[8]; /* 5 UTO, 3 TBD */
- void *t_pspare2[4]; /* 4 TBD */
+ void *t_pspare2[3]; /* 3 TBD */
uint64_t _pad[6]; /* 6 TBD (1-2 CC/RTT?) */
};
More information about the svn-src-user
mailing list