297 lines
8.3 KiB
Text
297 lines
8.3 KiB
Text
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
|
|
|
<html>
|
|
<head>
|
|
<title>Independent Verification of IPSec Functionality in FreeBSD</title>
|
|
</head>
|
|
|
|
<body text="#000000" bgcolor="#FFFFFF">
|
|
|
|
<h1>Independent Verification of IPsec Functionality Under FreeBSD 3.0</h1>
|
|
|
|
<p align="center"><i>You installed IPsec and it seems to be working.
|
|
How do you know? I describe a method for experimentally verifying
|
|
that IPsec is working</i></p>
|
|
|
|
<h2>The Problem</h2>
|
|
|
|
<p>First, let's assume you have <a href="#Installing IPsec">installed
|
|
<i>IPsec</i></a>. How do you know its <a href="#Caveat">working</a>?
|
|
Sure, your connection won't work if its misconfigured, and it will work
|
|
when you finally get it right. <i>Netstat</i> will list it. But can you
|
|
independently confirm it?</p>
|
|
|
|
<h2>The Solution</h2>
|
|
|
|
<p>First, some crypto-relevent info theory:</p>
|
|
|
|
<ol>
|
|
<li>
|
|
<p>Encrypted data is uniformly distributed, ie, has maximal entropy
|
|
per symbol.</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>Raw, uncompressed data is typically redundant, i.e., has
|
|
sub-maximal entropy.</p>
|
|
</li>
|
|
</ol>
|
|
|
|
<p>Suppose you could measure the entropy of the data to- and from- your
|
|
network interface. Then you could see the difference between unencrypted
|
|
data and encrypted data. This would be true even if some of the data
|
|
in "encrypted mode" was not encrypted ---as the outermost IP header must
|
|
be, if the packet is to be routable.</p>
|
|
|
|
<h4><a name="MUST"></a>MUST</h4>
|
|
|
|
<p>Ueli Maurer's "Universal Statistical Test for Random Bit Generators"
|
|
("MUST") quickly measures the entropy of a sample. It uses a
|
|
compression-like algorithm. <a href="#Maurer's Universal Statistical
|
|
Test">The code is given below for a variant which measures successive
|
|
(~quarter megabyte) chunks of a file</a>.</p>
|
|
|
|
<h4><a NAME="Tcpdump"></a>Tcpdump</h4>
|
|
|
|
<p>We also need a way to capture the raw network data. A program called
|
|
"<i>tcpdump</i>" lets you do this, if you have enabled the <i>Berkeley
|
|
Packet Filter</i> interface in your <a
|
|
href="#usr/src/sys/i386/conf/KERNELNAME">kernel's config file</a>.</p>
|
|
|
|
<p>The command</p>
|
|
|
|
<blockquote><b>tcpdump</b> <b>-c</b> 4000 <b>-s</b> 10000 <b>-w</b>
|
|
<i>dumpfile.bin</i></blockquote>
|
|
|
|
<p>will capture 4000 raw packets to <i>dumpfile.bin</i>. Up to 10,000
|
|
bytes per packet will be captured in this example.</p>
|
|
|
|
<h2>The Experiment</h2>
|
|
|
|
<p>Here's the experiment. Open a window to an IPsec host and another
|
|
window to an insecure host.</p>
|
|
|
|
<p>Now start <a href="#Tcpdump">capturing packets</a>.</p>
|
|
|
|
<p>In the "secure" window, run the unix command "yes", which will stream
|
|
the "y" character. After a while, stop this. Switch to the insecure
|
|
window, and repeat. After a while, stop.</p>
|
|
|
|
<p>Now run <a href="#Maurer's Universal Statistical Test">MUST</a> on the
|
|
captured packets. You should see something like the the following.
|
|
The important thing to note is that the secure connection has 93% (6.7)
|
|
of the expected value (7.18), and the "normal" connection has 29% (2.1)
|
|
of the expected value.</p>
|
|
|
|
|
|
<pre>% tcpdump -c 4000 -s 10000 -w ipsecdemo.bin
|
|
% uliscan ipsecdemo.bin
|
|
|
|
Uliscan 21 Dec 98
|
|
L=8 256 258560
|
|
Measuring file ipsecdemo.bin
|
|
Init done
|
|
Expected value for L=8 is 7.1836656
|
|
6.9396 --------------------------------------------------------
|
|
6.6177 -----------------------------------------------------
|
|
6.4100 ---------------------------------------------------
|
|
2.1101 -----------------
|
|
2.0838 -----------------
|
|
2.0983 -----------------</pre>
|
|
|
|
<h2><a NAME="Caveat"></a>Caveat</h2>
|
|
|
|
<p>This experiment shows that IPsec <i>does</i> seem to be distributing the
|
|
payload data <i>uniformly</i>, as encryption should. However, the
|
|
experiment described here <i>can not </i>detect many possible flaws in a
|
|
system (none of which do I have any evidence for). These include poor
|
|
key generation or exchange, data or keys being visible to others, use of
|
|
weak algorithms, kernel subversion, etc. Study the source; know the
|
|
code.</p>
|
|
|
|
<h2><a NAME="IPsec"></a>IPsec -Definition</h2>
|
|
|
|
<p>Internet Protocol security extensions to IP v 4; required for IP v6. A
|
|
protocol for negotiating encryption and authentication at the IP
|
|
(host-to-host) level. SSL secures only one application socket; SSH
|
|
secures only a login; PGP secures only a specified file or
|
|
message. IPsec encrypts everything between two hosts.</p>
|
|
|
|
<h2><a NAME="Installing IPsec"></a>Installing IPsec</h2>
|
|
|
|
<p>Starting from the BSD 3.0 stable release,</p>
|
|
|
|
<ol>
|
|
<li>
|
|
<p>install IPsec v0.04, rebuild, reinstall</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>run the administration tools (e.g, <i>ipsecadm</i>) and distribute
|
|
keys (or use <i>Photuris</i> for key exchange)</p>
|
|
</li>
|
|
|
|
<li>
|
|
<p>set the routes (<i>rt</i>) up appropriately</p>
|
|
</li>
|
|
</ol>
|
|
|
|
<p>You may want to make an "ipsec_setup" script containing the
|
|
<i>ipsecadm</i> and <i>rt</i> commands which establish your IPsec
|
|
tunnel. You can run this script automatically at boottime from your
|
|
<i>/etc/rc.local</i> The ipsec_setup script will have to contain at
|
|
least two <i>ipsecadm</i> commands and one <i>rt</i> command to be
|
|
useful.</p>
|
|
|
|
<h2><a NAME="KERNELNAME"></a>usr/src/sys/i386/conf/KERNELNAME</h2>
|
|
|
|
<p>This needs to be present in the kernel config file in order to run
|
|
IPsec. After adding it, run <i>config</i>, etc. and rebuild and
|
|
reinstall.</p>
|
|
|
|
<pre># The `bpfilter' pseudo-device enables the Berkeley Packet Filter. Be
|
|
# aware of the legal and administrative consequences of enabling this
|
|
# option. Heh heh. The number of devices determines the maximum number of
|
|
# simultaneous BPF clients programs runnable.
|
|
pseudo-device bpfilter 2 #Berkeley packet filter
|
|
|
|
# IPSEC
|
|
options IPSEC
|
|
options "MD5"
|
|
pseudo-device enc 1</pre>
|
|
|
|
<h2><a name="must"></a>Maurer's Universal Statistical Test (for block
|
|
size=8 bits)</h2>
|
|
|
|
<pre><![ CDATA [/*
|
|
ULISCAN.c ---blocksize of 8
|
|
|
|
1 Oct 98
|
|
1 Dec 98
|
|
21 Dec 98 uliscan.c derived from ueli8.c
|
|
|
|
This version has // comments removed for Sun cc
|
|
|
|
This implements Ueli M Maurer's "Universal Statistical Test for Random
|
|
Bit Generators" using L=8
|
|
|
|
Accepts a filename on the command line; writes its results, with other
|
|
info, to stdout.
|
|
|
|
Handles input file exhaustion gracefully.
|
|
|
|
Ref: J. Cryptology v 5 no 2, 1992 pp 89-105
|
|
also on the web somewhere, which is where I found it.
|
|
|
|
-David Honig
|
|
honig@sprynet.com
|
|
|
|
Usage:
|
|
ULISCAN filename
|
|
outputs to stdout
|
|
*/
|
|
|
|
#define L 8
|
|
#define V (1<<L)
|
|
#define Q (10*V)
|
|
#define K (100 *Q)
|
|
#define MAXSAMP (Q + K)
|
|
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
int main(argc, argv)
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
FILE *fptr;
|
|
int i,j;
|
|
int b, c;
|
|
int table[V];
|
|
double sum = 0.0;
|
|
int iproduct = 1;
|
|
int run;
|
|
|
|
extern double log(/* double x */);
|
|
|
|
printf("Uliscan 21 Dec 98 \nL=%d %d %d \n", L, V, MAXSAMP);
|
|
|
|
if (argc < 2) {
|
|
printf("Usage: Uliscan filename\n");
|
|
exit(-1);
|
|
} else {
|
|
printf("Measuring file %s\n", argv[1]);
|
|
}
|
|
|
|
fptr = fopen(argv[1],"rb");
|
|
|
|
if (fptr == NULL) {
|
|
printf("Can't find %s\n", argv[1]);
|
|
exit(-1);
|
|
}
|
|
|
|
for (i = 0; i < V; i++) {
|
|
table[i] = 0;
|
|
}
|
|
|
|
for (i = 0; i < Q; i++) {
|
|
b = fgetc(fptr);
|
|
table[b] = i;
|
|
}
|
|
|
|
printf("Init done\n");
|
|
|
|
printf("Expected value for L=8 is 7.1836656\n");
|
|
|
|
run = 1;
|
|
|
|
while (run) {
|
|
sum = 0.0;
|
|
iproduct = 1;
|
|
|
|
if (run)
|
|
for (i = Q; run && i < Q + K; i++) {
|
|
j = i;
|
|
b = fgetc(fptr);
|
|
|
|
if (b < 0)
|
|
run = 0;
|
|
|
|
if (run) {
|
|
if (table[b] > j)
|
|
j += K;
|
|
|
|
sum += log((double)(j-table[b]));
|
|
|
|
table[b] = i;
|
|
}
|
|
}
|
|
|
|
if (!run)
|
|
printf("Premature end of file; read %d blocks.\n", i - Q);
|
|
|
|
sum = (sum/((double)(i - Q))) / log(2.0);
|
|
printf("%4.4f ", sum);
|
|
|
|
for (i = 0; i < (int)(sum*8.0 + 0.50); i++)
|
|
printf("-");
|
|
|
|
printf("\n");
|
|
|
|
/* refill initial table */
|
|
if (0) {
|
|
for (i = 0; i < Q; i++) {
|
|
b = fgetc(fptr);
|
|
if (b < 0) {
|
|
run = 0;
|
|
} else {
|
|
table[b] = i;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}]]></pre>
|
|
</body>
|
|
</html>
|
|
|
|
|