├── .gitignore ├── Makefile ├── README.markdown ├── mod_tcpcrypt.c ├── modules.mk └── test ├── apache-config ├── iptables.sh ├── tcpcrypt.php ├── tcpcrypt.sh └── test_mod_tcpcrypt.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .libs 2 | *.la 3 | *.lai 4 | *.o 5 | *.so 6 | *.lo 7 | *.slo 8 | 9 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | APXS=apxs2 2 | APACHECTL=sudo /etc/init.d/apache2 3 | CFLAGS=-Wc,-g -Wc,-Wall 4 | LIBS=-ltcpcrypt 5 | 6 | install: 7 | $(APXS) $(CFLAGS) $(INCLUDES) $(LIBS) -cia mod_tcpcrypt.c 8 | 9 | # cleanup 10 | clean: 11 | -rm -f mod_tcpcrypt.o mod_tcpcrypt.lo mod_tcpcrypt.slo mod_tcpcrypt.la 12 | 13 | # simple test 14 | configtest: 15 | -cp test/test-tcpcrypt-site /etc/apache2/sites-available/ 16 | -sudo a2ensite test-tcpcrypt-site 17 | 18 | test: configtest reload req 19 | 20 | req: 21 | curl http://localhost:7777/tcpcrypt.sh 22 | 23 | # install and activate shared object by reloading Apache to 24 | # force a reload of the shared object file 25 | reload: install restart 26 | 27 | # the general Apache start/restart/stop 28 | # procedures 29 | start: 30 | $(APACHECTL) start 31 | restart: 32 | $(APACHECTL) restart 33 | stop: 34 | $(APACHECTL) stop 35 | 36 | iptables-on: 37 | iptables -I INPUT -p tcp -m tcp --dport 80 -j NFQUEUE --queue-num 666 38 | iptables -I OUTPUT -p tcp -m tcp --sport 80 -j NFQUEUE --queue-num 666 39 | 40 | iptables-off: 41 | iptables -D INPUT -p tcp -m tcp --dport 80 -j NFQUEUE --queue-num 666 42 | iptables -D OUTPUT -p tcp -m tcp --sport 80 -j NFQUEUE --queue-num 666 43 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | mod_tcpcrypt for Apache 2 | ======================= 3 | 4 | This module exposes the [tcpcrypt](http://tcpcrypt.org) session ID of the 5 | current Apache HTTP connection to scripts and Web apps running on Apache. 6 | 7 | The `TCP_CRYPT_SESSID` environment variable contains the tcpcrypt session ID 8 | if a tcpcrypt connection was established; otherwise, the env var is unset. For 9 | example, a PHP script can access the tcpcrypt session ID as 10 | `$_SERVER['TCP_CRYPT_SESSID']`. 11 | 12 | If both ends of a tcpcrypt connection see the same session ID, then an attacker 13 | cannot eavesdrop on or undetectably tamper with traffic--i.e., there has not 14 | been a man-in-the-middle attack. Also, session IDs are (with overwhelming 15 | probability) unique over all time, even if one end of a connection is 16 | malicious. Thus tcpcrypt session IDs can be used to mutually authenticate a 17 | connection and all of the data passed over it. See section 4 of the [tcpcrypt 18 | paper](http://tcpcrypt.org/tcpcrypt.pdf) for more info on using tcpcrypt 19 | session IDs for authentication. 20 | 21 | The tcpcrypt team is currently working on more examples of using tcpcrypt for 22 | HTTP authentication. [Subscribe to 23 | tcpcrypt-dev](https://mailman.stanford.edu/mailman/listinfo/tcpcrypt-dev) to 24 | follow our progress or contribute. 25 | 26 | 27 | Installation 28 | ============ 29 | 30 | You'll need Apache 2.2 and apxs2, the Apache tool for installing modules. On 31 | Ubuntu and Debian, `apt-get install apache2-dev` should suffice. 32 | 33 | Set the Makefile's `TCPCRYPT` variable to the path containing the [tcpcrypt 34 | code](http://github.com/sorbo/tcpcrypt). Build tcpcrypt's `libtcpcrypt.so` 35 | (see instructions for tcpcrypt). 36 | 37 | Now, from this `mod_tcpcrypt` directory, run `make install` as root to build 38 | and install the module. 39 | 40 | 41 | Configuration 42 | ------------- 43 | 44 | Right now, `mod_tcpcrypt` adds the `TCP_CRYPT_SESSID` env var to **every** 45 | request. This will change soon, but for now, no configuration is needed other 46 | than installing the module. 47 | 48 | **IPv6 note:** Tcpcrypt doesn't really work with IPv6 (yet). If Apache is 49 | listening on an IPv6 address (check `netstat` for "tcp6"), mod_tcpcrypt will 50 | probably work for IPv4 clients (who will appear to Apache as having 51 | IPv4-compatible IPv6 addresses). If you're having problems and don't actually 52 | care about IPv6, then change all of your Apache config Listen directives to 53 | specify an IPv4 address (e.g., `Listen 80 -> `Listen 0.0.0.0:80`). 54 | 55 | 56 | Accessing TCP_CRYPT_SESSID in scripts/Web apps 57 | ============================================== 58 | 59 | The sockopt is just exposed as a normal environment variable. Here are a few 60 | language-specific examples. 61 | 62 | * PHP: `$_SERVER['TCP_CRYPT_SESSID']` 63 | * Python: `import os` and then `os.getenv('TCP_CRYPT_SESSID')` 64 | * Ruby: `ENV['TCP_CRYPT_SESSID']` 65 | 66 | 67 | Warnings 68 | ======== 69 | 70 | This module has only been tested on Linux (Debian Squeeze amd64). Currently not 71 | recommended for production use. 72 | 73 | 74 | More info 75 | ========= 76 | 77 | For general info about tcpcrypt, see [tcpcrypt.org](http://tcpcrypt.org). The 78 | tcpcrypt code is at 79 | [http://github.com/sorbo/tcpcrypt](http://github.com/sorbo/tcpcrypt). 80 | 81 | For more info about how to use tcpcrypt session IDs to authenticate 82 | connections, see section 4 of the [tcpcrypt 83 | paper](http://tcpcrypt.org/tcpcrypt.pdf). -------------------------------------------------------------------------------- /mod_tcpcrypt.c: -------------------------------------------------------------------------------- 1 | #define CORE_PRIVATE 2 | #include 3 | #include "httpd.h" 4 | #include "http_config.h" 5 | #include "http_protocol.h" 6 | #include "http_connection.h" // pre_connection hook 7 | #include "http_request.h" // fixups hook 8 | #include "http_log.h" 9 | #include "ap_config.h" 10 | #include 11 | 12 | 13 | /* WARNING: Tcpcrypt doesn't really work with IPv6 (yet). If Apache is 14 | listening on an IPv6 address (check `netstat` for "tcp6"), mod_tcpcrypt will 15 | probably work for IPv4 clients (who will appear to Apache as having 16 | IPv4-compatible IPv6 addresses). If you're having problems and don't 17 | actually care about IPv6, then change all of your Apache config Listen 18 | directives to specify an IPv4 address (e.g., `Listen 80 -> `Listen 19 | 0.0.0.0:80`). */ 20 | 21 | /* TODO(sqs): find a cleaner way of getting access to socketdes */ 22 | struct fake_apr_socket_t { 23 | apr_pool_t *pool; 24 | int socketdes; 25 | int type; 26 | int protocol; 27 | }; 28 | 29 | static void tcpcrypt_register_hooks(apr_pool_t *p); 30 | static int get_tcpcrypt_sockopts(conn_rec *c, void *csd); 31 | static int set_tcpcrypt_env(request_rec *r); 32 | 33 | module AP_MODULE_DECLARE_DATA tcpcrypt_module = { 34 | STANDARD20_MODULE_STUFF, 35 | NULL, /* create per-dir config structures */ 36 | NULL, /* merge per-dir config structures */ 37 | NULL, /* create per-server config structures */ 38 | NULL, /* merge per-server config structures */ 39 | NULL, /* table of config file commands */ 40 | tcpcrypt_register_hooks /* register hooks */ 41 | }; 42 | 43 | static int get_tcpcrypt_sockopts(conn_rec *c, void *csd) { 44 | unsigned char buf[1024]; 45 | unsigned char *b = (unsigned char *)buf; 46 | char *tc_sessid, *s; 47 | unsigned int len; 48 | struct fake_apr_socket_t *sock; 49 | 50 | sock = (struct fake_apr_socket_t *)csd; 51 | 52 | len = sizeof(buf); 53 | 54 | if (tcpcrypt_getsockopt(sock->socketdes, IPPROTO_TCP, TCP_CRYPT_SESSID, 55 | buf, &len) == -1) { 56 | ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, 57 | "tcpcrypt_getsockopt error for TCP_CRYPT_SESSID: " 58 | "%s (%d) [fd=%d]", 59 | strerror(errno), errno, sock->socketdes); 60 | return DECLINED; 61 | } 62 | 63 | if (len) { 64 | tc_sessid = apr_palloc(c->pool, len*2 + 1); 65 | tc_sessid[0] = '\0'; 66 | assert(tc_sessid); 67 | s = tc_sessid; 68 | while (len--) { 69 | sprintf(s, "%.2X", *b++); 70 | s += 2; 71 | } 72 | 73 | ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, 74 | "mod_tcpcrypt: got TCP_CRYPT_SESSID=%s " 75 | "[fd=%d, type=%d, protocol=%d] ", 76 | tc_sessid[0] ? tc_sessid : "", 77 | sock->socketdes, sock->type, sock->protocol); 78 | apr_table_addn(c->notes, "TCP_CRYPT_SESSID", tc_sessid); 79 | } 80 | 81 | return DECLINED; 82 | } 83 | 84 | static int set_tcpcrypt_env(request_rec *r) 85 | { 86 | const char *tc_sessid = apr_table_get(r->connection->notes, "TCP_CRYPT_SESSID"); 87 | 88 | if (tc_sessid && tc_sessid[0]) { 89 | apr_table_set(r->subprocess_env, "TCP_CRYPT_SESSID", tc_sessid); 90 | } 91 | 92 | return OK; 93 | } 94 | 95 | static void tcpcrypt_register_hooks(apr_pool_t *p) 96 | { 97 | ap_hook_pre_connection(get_tcpcrypt_sockopts, NULL, NULL, APR_HOOK_MIDDLE); 98 | ap_hook_fixups(set_tcpcrypt_env, NULL, NULL, APR_HOOK_FIRST); 99 | } 100 | 101 | 102 | -------------------------------------------------------------------------------- /modules.mk: -------------------------------------------------------------------------------- 1 | mod_tcpcrypt.la: mod_tcpcrypt.slo 2 | $(SH_LINK) -rpath $(libexecdir) -module -avoid-version mod_tcpcrypt.lo 3 | DISTCLEAN_TARGETS = modules.mk 4 | shared = mod_tcpcrypt.la 5 | -------------------------------------------------------------------------------- /test/apache-config: -------------------------------------------------------------------------------- 1 | 2 | ServerName test-tcpcrypt.mutualauth.org 3 | DocumentRoot /var/www/test-tcpcrypt.mutualauth.org 4 | 5 | Options +ExecCGI 6 | AddHandler cgi-script .sh 7 | 8 | 9 | LogLevel debug 10 | 11 | 12 | LoadModule tcpcrypt_module modules/mod_tcpcrypt.so 13 | 14 | -------------------------------------------------------------------------------- /test/iptables.sh: -------------------------------------------------------------------------------- 1 | opt=$1 2 | iptables $opt INPUT -p tcp --sport 80 -i lo -j NFQUEUE --queue-num 666 3 | iptables $opt OUTPUT -p tcp --dport 80 -o lo -j NFQUEUE --queue-num 666 4 | iptables $opt INPUT -p tcp --dport 80 -i lo -j NFQUEUE --queue-num 666 5 | iptables $opt OUTPUT -p tcp --sport 80 -o lo -j NFQUEUE --queue-num 666 6 | 7 | -------------------------------------------------------------------------------- /test/tcpcrypt.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /test/tcpcrypt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo Content-Type: text/plain 4 | echo 5 | echo REMOTE_ADDR = ${REMOTE_ADDR} 6 | echo TCP_CRYPT_SESSID = ${TCP_CRYPT_SESSID:=''} 7 | -------------------------------------------------------------------------------- /test/test_mod_tcpcrypt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | testname=$1 3 | url=$2 4 | curlout=/tmp/curlout-$$ 5 | 6 | 7 | case $testname in 8 | on) 9 | echo -n Testing mod_tcpcrypt with server tcpcryptd running... 10 | curl --tcp-nodelay --limit-rate 30 $url > $curlout 2>/dev/null & 11 | sleep 0.5 12 | sessid=$(tcnetstat | tail -n 1 | rev | cut -d ' ' -f 1 | rev) 13 | wait 14 | grep "${sessid/[^\w\d]/}" $curlout && \ 15 | echo "PASS" && exit 0 16 | echo "FAIL" 17 | echo Got 18 | cat $curlout 19 | exit 1 20 | ;; 21 | off) 22 | echo -n Testing mod_tcpcrypt with server tcpcryptd off... 23 | curl $url > $curlout 2>/dev/null 24 | grep "TCP_CRYPT_SESSID = " $curlout && \ 25 | echo "PASS" && exit 0 26 | echo "FAIL" 27 | echo got 28 | cat $curlout 29 | exit 1 30 | ;; 31 | esac 32 | # TODO: test with server tcpcryptd on, client tcpcryptd off 33 | --------------------------------------------------------------------------------