344 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			344 lines
		
	
	
	
		
			9.3 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| <!--
 | |
|     The FreeBSD Documentation Project
 | |
| 
 | |
|     $FreeBSD$
 | |
| -->
 | |
| 
 | |
| <!DOCTYPE article PUBLIC "-//FreeBSD//DTD DocBook V4.1-Based Extension//EN" [
 | |
| <!ENTITY % articles.ent PUBLIC "-//FreeBSD//ENTITIES DocBook FreeBSD Articles Entity Set//EN">
 | |
| %articles.ent;
 | |
| ]>
 | |
| 
 | |
| <article>
 | |
|   <articleinfo>
 | |
|     <title>Independent Verification of IPsec Functionality in FreeBSD</title>
 | |
| 
 | |
|     <author>
 | |
|       <firstname>David</firstname>
 | |
|       <surname>Honig</surname>
 | |
| 
 | |
|       <affiliation>
 | |
|         <address><email>honig@sprynet.com</email></address>
 | |
|       </affiliation>
 | |
|     </author>
 | |
| 
 | |
|     <pubdate>3 May 1999</pubdate>
 | |
| 
 | |
|     <legalnotice id="trademarks" role="trademarks">
 | |
|       &tm-attrib.freebsd;
 | |
|       &tm-attrib.opengroup;
 | |
|       &tm-attrib.general;
 | |
|     </legalnotice>
 | |
| 
 | |
|     <abstract>
 | |
|       <para>You installed IPsec and it seems to be working. How do you
 | |
|         know?  I describe a method for experimentally verifying that IPsec is
 | |
|         working.</para>
 | |
|     </abstract>
 | |
|   </articleinfo>
 | |
| 
 | |
|   <sect1 id="problem">
 | |
|     <title>The Problem</title>
 | |
| 
 | |
|     <para>First, lets assume you have <link linkend="ipsec-install">
 | |
|       installed <emphasis>IPsec</emphasis></link>.  How do you know
 | |
|       it is <link linkend="caveat">working</link>?  Sure, your
 | |
|       connection will not work if it is misconfigured, and it will work
 | |
|       when you finally get it right.  &man.netstat.1; will list it.
 | |
|       But can you independently confirm it?</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="solution">
 | |
|     <title>The Solution</title>
 | |
| 
 | |
|     <para>First, some crypto-relevant info theory:</para>
 | |
| 
 | |
|     <orderedlist>
 | |
|       <listitem>
 | |
| 	<para>Encrypted data is uniformly distributed, i.e., has maximal
 | |
| 	  entropy per symbol;</para>
 | |
|       </listitem>
 | |
| 
 | |
|       <listitem>
 | |
| 	<para>Raw, uncompressed data is typically redundant, i.e., has
 | |
| 	  sub-maximal entropy.</para>
 | |
|       </listitem>
 | |
|     </orderedlist>
 | |
| 
 | |
|     <para>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 <quote>encrypted mode</quote> was
 | |
|       not encrypted---as the outermost IP header must be if the
 | |
|       packet is to be routable.</para>
 | |
| 
 | |
|     <sect2 id="MUST">
 | |
|       <title>MUST</title>
 | |
| 
 | |
|       <para>Ueli Maurer's <quote>Universal Statistical Test for Random
 | |
| 	Bit Generators</quote>(<ulink
 | |
| 	url="http://www.geocities.com/SiliconValley/Code/4704/universal.pdf">
 | |
| 	<acronym>MUST</acronym></ulink>) quickly measures the entropy
 | |
| 	of a sample.  It uses a compression-like algorithm.  <link
 | |
| 	linkend="code">The code is given below</link> for a variant
 | |
| 	which measures successive (~quarter megabyte) chunks of a
 | |
| 	file.</para>
 | |
|     </sect2>
 | |
| 
 | |
|     <sect2 id="tcpdump">
 | |
|       <title>Tcpdump</title>
 | |
| 
 | |
|       <para>We also need a way to capture the raw network data.  A
 | |
| 	program called &man.tcpdump.1; lets you do this, if you have
 | |
| 	enabled the <emphasis>Berkeley Packet Filter</emphasis>
 | |
| 	interface in your <link linkend="kernel">kernel's config
 | |
| 	file</link>.</para>
 | |
| 
 | |
|       <para>The command:</para>
 | |
| 
 | |
|       <screen><userinput><command>tcpdump</command> -c 4000 -s 10000 -w <replaceable>dumpfile.bin</replaceable></userinput></screen>
 | |
| 
 | |
|       <para>will capture 4000 raw packets to
 | |
|       <replaceable>dumpfile.bin</replaceable>.  Up to 10,000 bytes per
 | |
|       packet will be captured in this example.</para>
 | |
|     </sect2>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="experiment">
 | |
|     <title>The Experiment</title>
 | |
| 
 | |
|     <para>Here is the experiment:</para>
 | |
| 
 | |
|     <procedure>
 | |
|       <step>
 | |
| 	<para>Open a window to an IPsec host and another window to an
 | |
| 	  insecure host.</para>
 | |
|       </step>
 | |
| 
 | |
|       <step>
 | |
| 	<para>Now start <link linkend="tcpdump">capturing
 | |
| 	  packets</link>.</para>
 | |
|       </step>
 | |
| 
 | |
|       <step>
 | |
| 	<para>In the <quote>secure</quote> window, run the &unix;
 | |
| 	  command &man.yes.1;, which will stream the <literal>y</literal>
 | |
| 	  character.  After a while, stop this.  Switch to the
 | |
| 	  insecure window, and repeat.  After a while, stop.</para>
 | |
|       </step>
 | |
| 
 | |
|       <step>
 | |
| 	<para>Now run <link linkend="code">MUST</link> on the
 | |
| 	  captured packets.  You should see something like the
 | |
| 	  following.  The important thing to note is that the secure
 | |
| 	  connection has 93% (6.7) of the expected value (7.18), and
 | |
| 	  the <quote>normal</quote> connection has 29% (2.1) of the
 | |
| 	  expected value.</para>
 | |
| 
 | |
|     <screen>&prompt.user; <userinput>tcpdump -c 4000 -s 10000 -w <replaceable>ipsecdemo.bin</replaceable></userinput>
 | |
| &prompt.user; <userinput>uliscan <replaceable>ipsecdemo.bin</replaceable></userinput>
 | |
| 
 | |
| 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 -----------------</screen>
 | |
|       </step>
 | |
|     </procedure>
 | |
|   </sect1>
 | |
| 
 | |
|     <sect1 id="caveat">
 | |
|       <title>Caveat</title>
 | |
| 
 | |
|     <para>This experiment shows that IPsec <emphasis>does</emphasis>
 | |
|       seem to be distributing the payload data
 | |
|       <emphasis>uniformly</emphasis>, as encryption should.  However,
 | |
|       the experiment described here <emphasis>cannot</emphasis>
 | |
|       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.</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="IPsec">
 | |
|     <title>IPsec---Definition</title>
 | |
| 
 | |
|     <para>Internet Protocol security extensions to IPv4; required for
 | |
|       IPv6.  A protocol for negotiating encryption and authentication
 | |
|       at the IP (host-to-host) level.  SSL secures only one application
 | |
|       socket; <application>SSH</application> secures only a login;
 | |
|       <application>PGP</application> secures only a specified file or
 | |
|       message.  IPsec encrypts everything between two hosts.</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="ipsec-install">
 | |
|     <title>Installing IPsec</title>
 | |
| 
 | |
|     <para>Most of the modern versions of FreeBSD have IPsec support
 | |
|       in their base source.  So you will need to include the
 | |
|       <option>IPSEC</option> option in your kernel config and, after
 | |
|       kernel rebuild and reinstall, configure IPsec connections using
 | |
|       &man.setkey.8; command.</para>
 | |
| 
 | |
|     <para>A comprehensive guide on running IPsec on FreeBSD is
 | |
|       provided in <ulink
 | |
|       url="&url.books.handbook;/ipsec.html">FreeBSD
 | |
|       Handbook</ulink>.</para>
 | |
|   </sect1>
 | |
| 
 | |
|   <sect1 id="kernel">
 | |
|     <title>src/sys/i386/conf/KERNELNAME</title>
 | |
| 
 | |
|     <para>This needs to be present in the kernel config file in order
 | |
|       to capture network data with &man.tcpdump.1;.  Be sure
 | |
|       to run &man.config.8; after adding this, and rebuild and
 | |
|       reinstall.</para>
 | |
| 
 | |
|     <programlisting>device	bpf</programlisting>
 | |
|   </sect1>
 | |
| 
 | |
|     <sect1 id="code">
 | |
|       <title>Maurer's Universal Statistical Test (for block size=8
 | |
|         bits)</title>
 | |
| 
 | |
|         <para>You can find the same code at <ulink
 | |
|           url="http://www.geocities.com/SiliconValley/Code/4704/uliscanc.txt">
 | |
|           this link</ulink>.</para>
 | |
| 
 | |
| <programlisting>/*
 | |
|   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;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }</programlisting>
 | |
|   </sect1>
 | |
| </article>
 |