summaryrefslogtreecommitdiff
path: root/src/libfreeswan
diff options
context:
space:
mode:
Diffstat (limited to 'src/libfreeswan')
-rw-r--r--src/libfreeswan/atosa.3217
-rw-r--r--src/libfreeswan/atosa.c198
-rw-r--r--src/libfreeswan/keyblobtoid.3102
-rw-r--r--src/libfreeswan/keyblobtoid.c146
-rw-r--r--src/libfreeswan/prng.3120
-rw-r--r--src/libfreeswan/prng.c200
-rw-r--r--src/libfreeswan/satoa.c100
7 files changed, 1083 insertions, 0 deletions
diff --git a/src/libfreeswan/atosa.3 b/src/libfreeswan/atosa.3
new file mode 100644
index 000000000..f57fcf1e9
--- /dev/null
+++ b/src/libfreeswan/atosa.3
@@ -0,0 +1,217 @@
+.TH IPSEC_ATOSA 3 "11 June 2001"
+.SH NAME
+ipsec atosa, satoa \- convert IPsec Security Association IDs to and from ASCII
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "const char *atosa(const char *src, size_t srclen,"
+.ti +1c
+.B "struct sa_id *sa);
+.br
+.B "size_t satoa(struct sa_id sa, int format,"
+.ti +1c
+.B "char *dst, size_t dstlen);"
+.sp
+.B "struct sa_id {"
+.ti +1c
+.B "struct in_addr dst;"
+.ti +1c
+.B "ipsec_spi_t spi;"
+.ti +1c
+.B "int proto;"
+.br
+.B "};"
+.SH DESCRIPTION
+These functions are obsolete; see
+.IR ipsec_ttosa (3)
+for their replacements.
+.PP
+.I Atosa
+converts an ASCII Security Association (SA) specifier into an
+.B sa_id
+structure (containing
+a destination-host address
+in network byte order,
+an SPI number in network byte order, and
+a protocol code).
+.I Satoa
+does the reverse conversion, back to an ASCII SA specifier.
+.PP
+An SA is specified in ASCII with a mail-like syntax, e.g.
+.BR esp507@1.2.3.4 .
+An SA specifier contains
+a protocol prefix (currently
+.BR ah ,
+.BR esp ,
+or
+.BR tun ),
+an unsigned integer SPI number,
+and an IP address.
+The SPI number can be decimal or hexadecimal
+(with
+.B 0x
+prefix), as accepted by
+.IR ipsec_atoul (3).
+The IP address can be any form accepted by
+.IR ipsec_atoaddr (3),
+e.g. dotted-decimal address or DNS name.
+.PP
+As a special case, the SA specifier
+.B %passthrough
+signifies the special SA used to indicate that packets should be
+passed through unaltered.
+(At present, this is a synonym for
+.BR tun0x0@0.0.0.0 ,
+but that is subject to change without notice.)
+This form is known to both
+.I atosa
+and
+.IR satoa ,
+so the internal form of
+.B %passthrough
+is never visible.
+.PP
+The
+.B <freeswan.h>
+header file supplies the
+.B sa_id
+structure, as well as a data type
+.B ipsec_spi_t
+which is an unsigned 32-bit integer.
+(There is no consistency between kernel and user on what such a type
+is called, hence the header hides the differences.)
+.PP
+The protocol code uses the same numbers that IP does.
+For user convenience, given the difficulty in acquiring the exact set of
+protocol names used by the kernel,
+.B <freeswan.h>
+defines the names
+.BR SA_ESP ,
+.BR SA_AH ,
+and
+.B SA_IPIP
+to have the same values as the kernel names
+.BR IPPROTO_ESP ,
+.BR IPPROTO_AH ,
+and
+.BR IPPROTO_IPIP .
+.PP
+The
+.I srclen
+parameter of
+.I atosa
+specifies the length of the ASCII string pointed to by
+.IR src ;
+it is an error for there to be anything else
+(e.g., a terminating NUL) within that length.
+As a convenience for cases where an entire NUL-terminated string is
+to be converted,
+a
+.I srclen
+value of
+.B 0
+is taken to mean
+.BR strlen(src) .
+.PP
+The
+.I dstlen
+parameter of
+.I satoa
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant,
+.BR SATOA_BUF ,
+which is the size of a buffer just large enough for worst-case results.
+.PP
+The
+.I format
+parameter of
+.I satoa
+specifies what format is to be used for the conversion.
+The value
+.B 0
+(not the ASCII character
+.BR '0' ,
+but a zero value)
+specifies a reasonable default
+(currently
+lowercase protocol prefix, lowercase hexadecimal SPI, dotted-decimal address).
+The value
+.B d
+causes the SPI to be generated in decimal instead.
+.PP
+.I Atosa
+returns
+.B NULL
+for success and
+a pointer to a string-literal error message for failure;
+see DIAGNOSTICS.
+.I Satoa
+returns
+.B 0
+for a failure, and otherwise
+always returns the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.SH SEE ALSO
+ipsec_atoul(3), ipsec_atoaddr(3), inet(3)
+.SH DIAGNOSTICS
+Fatal errors in
+.I atosa
+are:
+empty input;
+input too small to be a legal SA specifier;
+no
+.B @
+in input;
+unknown protocol prefix;
+conversion error in
+.I atoul
+or
+.IR atoaddr .
+.PP
+Fatal errors in
+.I satoa
+are:
+unknown format; unknown protocol code.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+The
+.B tun
+protocol code is a FreeS/WANism which may eventually disappear.
+.PP
+The restriction of ASCII-to-binary error reports to literal strings
+(so that callers don't need to worry about freeing them or copying them)
+does limit the precision of error reporting.
+.PP
+The ASCII-to-binary error-reporting convention lends itself
+to slightly obscure code,
+because many readers will not think of NULL as signifying success.
+A good way to make it clearer is to write something like:
+.PP
+.RS
+.nf
+.B "const char *error;"
+.sp
+.B "error = atoaddr( /* ... */ );"
+.B "if (error != NULL) {"
+.B " /* something went wrong */"
+.fi
+.RE
diff --git a/src/libfreeswan/atosa.c b/src/libfreeswan/atosa.c
new file mode 100644
index 000000000..7339b4c3e
--- /dev/null
+++ b/src/libfreeswan/atosa.c
@@ -0,0 +1,198 @@
+/*
+ * convert from ASCII form of SA ID to binary
+ * Copyright (C) 1998, 1999 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct satype {
+ char *prefix;
+ size_t prelen; /* strlen(prefix) */
+ int proto;
+} satypes[] = {
+ { "ah", 2, SA_AH },
+ { "esp", 3, SA_ESP },
+ { "tun", 3, SA_IPIP },
+ { "comp", 4, SA_COMP },
+ { NULL, 0, 0, }
+};
+
+/*
+ - atosa - convert ASCII "ah507@10.0.0.1" to SA identifier
+ */
+const char * /* NULL for success, else string literal */
+atosa(src, srclen, sa)
+const char *src;
+size_t srclen; /* 0 means "apply strlen" */
+struct sa_id *sa;
+{
+ const char *at;
+ const char *addr;
+ const char *spi = NULL;
+ struct satype *sat;
+ unsigned long ul;
+ const char *oops;
+# define MINLEN 5 /* ah0@0 is as short as it can get */
+ static char ptname[] = PASSTHROUGHNAME;
+# define PTNLEN (sizeof(ptname)-1) /* -1 for NUL */
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ if (srclen == 0)
+ return "empty string";
+ if (srclen < MINLEN)
+ return "string too short to be SA specifier";
+ if (srclen == PTNLEN && memcmp(src, ptname, PTNLEN) == 0) {
+ src = PASSTHROUGHIS;
+ srclen = strlen(src);
+ }
+
+ at = memchr(src, '@', srclen);
+ if (at == NULL)
+ return "no @ in SA specifier";
+
+ for (sat = satypes; sat->prefix != NULL; sat++)
+ if (sat->prelen < srclen &&
+ strncmp(src, sat->prefix, sat->prelen) == 0) {
+ sa->proto = sat->proto;
+ spi = src + sat->prelen;
+ break; /* NOTE BREAK OUT */
+ }
+ if (sat->prefix == NULL)
+ return "SA specifier lacks valid protocol prefix";
+
+ if (spi >= at)
+ return "no SPI in SA specifier";
+ oops = atoul(spi, at - spi, 13, &ul);
+ if (oops != NULL)
+ return oops;
+ sa->spi = htonl(ul);
+
+ addr = at + 1;
+ oops = atoaddr(addr, srclen - (addr - src), &sa->dst);
+ if (oops != NULL)
+ return oops;
+
+ return NULL;
+}
+
+
+
+#ifdef ATOSA_MAIN
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+void regress(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct sa_id sa;
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {ahnnn@aaa|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ oops = atosa(argv[1], 0, &sa);
+ if (oops != NULL) {
+ fprintf(stderr, "%s: conversion failed: %s\n", argv[0], oops);
+ exit(1);
+ }
+ n = satoa(sa, 0, buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ fprintf(stderr, "%s: reverse conv of `%d'", argv[0], sa.proto);
+ fprintf(stderr, "%lu@", (long unsigned int)sa.spi);
+ fprintf(stderr, "%s", inet_ntoa(sa.dst));
+ fprintf(stderr, " failed: need %ld bytes, have only %ld\n",
+ (long)n, (long)sizeof(buf));
+ exit(1);
+ }
+ printf("%s\n", buf);
+
+ exit(0);
+}
+
+struct rtab {
+ char *input;
+ char *output; /* NULL means error expected */
+} rtab[] = {
+ {"esp257@1.2.3.0", "esp257@1.2.3.0"},
+ {"ah0x20@1.2.3.4", "ah32@1.2.3.4"},
+ {"tun011@111.2.3.99", "tun11@111.2.3.99"},
+ {"", NULL},
+ {"_", NULL},
+ {"ah2.2", NULL},
+ {"goo2@1.2.3.4", NULL},
+ {"esp9@1.2.3.4", "esp9@1.2.3.4"},
+ {"espp9@1.2.3.4", NULL},
+ {"es9@1.2.3.4", NULL},
+ {"ah@1.2.3.4", NULL},
+ {"esp7x7@1.2.3.4", NULL},
+ {"esp77@1.0x2.3.4", NULL},
+ {PASSTHROUGHNAME, PASSTHROUGHNAME},
+ {NULL, NULL}
+};
+
+void
+regress(void)
+{
+ struct rtab *r;
+ int status = 0;
+ struct sa_id sa;
+ char in[100];
+ char buf[100];
+ const char *oops;
+ size_t n;
+
+ for (r = rtab; r->input != NULL; r++) {
+ strcpy(in, r->input);
+ oops = atosa(in, 0, &sa);
+ if (oops != NULL && r->output == NULL)
+ {} /* okay, error expected */
+ else if (oops != NULL) {
+ printf("`%s' atosa failed: %s\n", r->input, oops);
+ status = 1;
+ } else if (r->output == NULL) {
+ printf("`%s' atosa succeeded unexpectedly\n",
+ r->input);
+ status = 1;
+ } else {
+ n = satoa(sa, 'd', buf, sizeof(buf));
+ if (n > sizeof(buf)) {
+ printf("`%s' satoa failed: need %ld\n",
+ r->input, (long)n);
+ status = 1;
+ } else if (strcmp(r->output, buf) != 0) {
+ printf("`%s' gave `%s', expected `%s'\n",
+ r->input, buf, r->output);
+ status = 1;
+ }
+ }
+ }
+ exit(status);
+}
+
+#endif /* ATOSA_MAIN */
diff --git a/src/libfreeswan/keyblobtoid.3 b/src/libfreeswan/keyblobtoid.3
new file mode 100644
index 000000000..8b5bfb0a2
--- /dev/null
+++ b/src/libfreeswan/keyblobtoid.3
@@ -0,0 +1,102 @@
+.TH IPSEC_KEYBLOBTOID 3 "25 March 2002"
+.SH NAME
+ipsec keyblobtoid, splitkeytoid \- generate key IDs from RSA keys
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "size_t keyblobtoid(const unsigned char *blob,"
+.ti +1c
+.B "size_t bloblen, char *dst, size_t dstlen);"
+.br
+.B "size_t splitkeytoid(const unsigned char *e, size_t elen,"
+.ti +1c
+.B "const unsigned char *m, size_t mlen, char *dst,
+.ti +1c
+.B "size_t dstlen);"
+.SH DESCRIPTION
+.I Keyblobtoid
+and
+.I splitkeytoid
+generate
+key IDs
+from RSA keys,
+for use in messages and reporting,
+writing the result to
+.IR dst .
+A
+.I key ID
+is a short ASCII string identifying a key;
+currently it is just the first nine characters of the base64
+encoding of the RFC 2537/3110 ``byte blob'' representation of the key.
+(Beware that no finite key ID can be collision-proof:
+there is always some small chance of two random keys having the
+same ID.)
+.PP
+.I Keyblobtoid
+generates a key ID from a key which is already in the form of an
+RFC 2537/3110 binary key
+.I blob
+(encoded exponent length, exponent, modulus).
+.PP
+.I Splitkeytoid
+generates a key ID from a key given in the form of a separate
+(binary) exponent
+.I e
+and modulus
+.IR m .
+.PP
+The
+.I dstlen
+parameter of either
+specifies the size of the
+.I dst
+parameter;
+under no circumstances are more than
+.I dstlen
+bytes written to
+.IR dst .
+A result which will not fit is truncated.
+.I Dstlen
+can be zero, in which case
+.I dst
+need not be valid and no result is written,
+but the return value is unaffected;
+in all other cases, the (possibly truncated) result is NUL-terminated.
+The
+.I freeswan.h
+header file defines a constant
+.B KEYID_BUF
+which is the size of a buffer large enough for worst-case results.
+.PP
+Both functions return
+.B 0
+for a failure, and otherwise
+always return the size of buffer which would
+be needed to
+accommodate the full conversion result, including terminating NUL;
+it is the caller's responsibility to check this against the size of
+the provided buffer to determine whether truncation has occurred.
+.P
+With keys generated by
+.IR ipsec_rsasigkey (3),
+the first two base64 digits are always the same,
+and the third carries only about one bit of information.
+It's worse with keys using longer fixed exponents,
+e.g. the 24-bit exponent that's common in X.509 certificates.
+However, being able to relate key IDs to the full
+base64 text form of keys by eye is sufficiently useful that this
+waste of space seems justifiable.
+The choice of nine digits is a compromise between bulk and
+probability of collision.
+.SH SEE ALSO
+RFC 3110,
+\fIRSA/SHA-1 SIGs and RSA KEYs in the Domain Name System (DNS)\fR,
+Eastlake, 2001
+(superseding the older but better-known RFC 2537).
+.SH DIAGNOSTICS
+Fatal errors are:
+key too short to supply enough bits to construct a complete key ID
+(almost certainly indicating a garbage key);
+exponent too long for its length to be representable.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
diff --git a/src/libfreeswan/keyblobtoid.c b/src/libfreeswan/keyblobtoid.c
new file mode 100644
index 000000000..89ab5fced
--- /dev/null
+++ b/src/libfreeswan/keyblobtoid.c
@@ -0,0 +1,146 @@
+/*
+ * generate printable key IDs
+ * Copyright (C) 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - keyblobtoid - generate a printable key ID from an RFC 2537/3110 key blob
+ * Current algorithm is just to use first nine base64 digits.
+ */
+size_t
+keyblobtoid(src, srclen, dst, dstlen)
+const unsigned char *src;
+size_t srclen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ char buf[KEYID_BUF];
+ size_t ret;
+# define NDIG 9
+
+ if (srclen < (NDIG*6 + 7)/8) {
+ strcpy(buf, "?len= ?");
+ buf[5] = '0' + srclen;
+ ret = 0;
+ } else {
+ (void) datatot(src, srclen, 64, buf, NDIG+1);
+ ret = NDIG+1;
+ }
+
+ if (dstlen > 0) {
+ if (strlen(buf)+1 > dstlen)
+ *(buf + dstlen - 1) = '\0';
+ strcpy(dst, buf);
+ }
+ return ret;
+}
+
+/*
+ - splitkeytoid - generate a printable key ID from exponent/modulus pair
+ * Just constructs the beginnings of a key blob and calls keyblobtoid().
+ */
+size_t
+splitkeytoid(e, elen, m, mlen, dst, dstlen)
+const unsigned char *e;
+size_t elen;
+const unsigned char *m;
+size_t mlen;
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ unsigned char buf[KEYID_BUF]; /* ample room */
+ unsigned char *bufend = buf + sizeof(buf);
+ unsigned char *p;
+ size_t n;
+
+ p = buf;
+ if (elen <= 255)
+ *p++ = elen;
+ else if ((elen &~ 0xffff) == 0) {
+ *p++ = 0;
+ *p++ = (elen>>8) & 0xff;
+ *p++ = elen & 0xff;
+ } else
+ return 0; /* unrepresentable exponent length */
+
+ n = bufend - p;
+ if (elen < n)
+ n = elen;
+ memcpy(p, e, n);
+ p += n;
+
+ n = bufend - p;
+ if (n > 0) {
+ if (mlen < n)
+ n = mlen;
+ memcpy(p, m, n);
+ p += n;
+ }
+
+ return keyblobtoid(buf, p - buf, dst, dstlen);
+}
+
+
+
+#ifdef KEYBLOBTOID_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ typedef unsigned char uc;
+ uc hexblob[] = "\x01\x03\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52";
+ uc hexe[] = "\x03";
+ uc hexm[] = "\x85\xf2\xd6\x76\x9b\x03\x59\xb6\x21\x52\xef\x85";
+ char b64nine[] = "AQOF8tZ2m";
+ char b64six[] = "AQOF8t";
+ char buf[100];
+ size_t n;
+ char *b = b64nine;
+ size_t bl = strlen(b) + 1;
+ int st = 0;
+
+ n = keyblobtoid(hexblob, strlen(hexblob), buf, sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: keyblobtoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: keyblobtoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ n = splitkeytoid(hexe, strlen(hexe), hexm, strlen(hexm), buf,
+ sizeof(buf));
+ if (n != bl) {
+ fprintf(stderr, "%s: splitkeytoid returned %d not %d\n",
+ argv[0], n, bl);
+ st = 1;
+ }
+ if (strcmp(buf, b) != 0) {
+ fprintf(stderr, "%s: splitkeytoid generated `%s' not `%s'\n",
+ argv[0], buf, b);
+ st = 1;
+ }
+ exit(st);
+}
+
+#endif /* KEYBLOBTOID_MAIN */
diff --git a/src/libfreeswan/prng.3 b/src/libfreeswan/prng.3
new file mode 100644
index 000000000..48c6ceed0
--- /dev/null
+++ b/src/libfreeswan/prng.3
@@ -0,0 +1,120 @@
+.TH IPSEC_PRNG 3 "1 April 2002"
+.SH NAME
+ipsec prng_init \- initialize IPsec pseudorandom-number generator
+.br
+ipsec prng_bytes \- get bytes from IPsec pseudorandom-number generator
+.br
+ipsec prng_final \- close down IPsec pseudorandom-number generator
+.SH SYNOPSIS
+.B "#include <freeswan.h>
+.sp
+.B "void prng_init(struct prng *prng,"
+.ti +1c
+.B "const unsigned char *key, size_t keylen);"
+.br
+.B "void prng_bytes(struct prng *prng, char *dst,"
+.ti +1c
+.B "size_t dstlen);"
+.br
+.B "unsigned long prng_count(struct prng *prng);"
+.br
+.B "void prng_final(struct prng *prng);"
+.SH DESCRIPTION
+.I Prng_init
+initializes a crypto-quality pseudo-random-number generator from a key;
+.I prng_bytes
+obtains pseudo-random bytes from it;
+.I prng_count
+reports the number of bytes extracted from it to date;
+.I prng_final
+closes it down.
+It is the user's responsibility to initialize a PRNG before using it,
+and not to use it again after it is closed down.
+.PP
+.I Prng_init
+initializes,
+or re-initializes,
+the specified
+.I prng
+from the
+.IR key ,
+whose length is given by
+.IR keylen .
+The user must allocate the
+.B "struct prng"
+pointed to by
+.IR prng .
+There is no particular constraint on the length of the key,
+although a key longer than 256 bytes is unnecessary because
+only the first 256 would be used.
+Initialization requires on the order of 3000 integer operations,
+independent of key length.
+.PP
+.I Prng_bytes
+obtains
+.I dstlen
+pseudo-random bytes from the PRNG and puts them in
+.IR buf .
+This is quite fast,
+on the order of 10 integer operations per byte.
+.PP
+.I Prng_count
+reports the number of bytes obtained from the PRNG
+since it was (last) initialized.
+.PP
+.I Prng_final
+closes down a PRNG by
+zeroing its internal memory,
+obliterating all trace of the state used to generate its previous output.
+This requires on the order of 250 integer operations.
+.PP
+The
+.B <freeswan.h>
+header file supplies the definition of the
+.B prng
+structure.
+Examination of its innards is discouraged, as they may change.
+.PP
+The PRNG algorithm
+used by these functions is currently identical to that of RC4(TM).
+This algorithm is cryptographically strong,
+sufficiently unpredictable that even a hostile observer will
+have difficulty determining the next byte of output from past history,
+provided it is initialized from a reasonably large key composed of
+highly random bytes (see
+.IR random (4)).
+The usual run of software pseudo-random-number generators
+(e.g.
+.IR random (3))
+are
+.I not
+cryptographically strong.
+.PP
+The well-known attacks against RC4(TM),
+e.g. as found in 802.11b's WEP encryption system,
+apply only if multiple PRNGs are initialized with closely-related keys
+(e.g., using a counter appended to a base key).
+If such keys are used, the first few hundred pseudo-random bytes
+from each PRNG should be discarded,
+to give the PRNGs a chance to randomize their innards properly.
+No useful attacks are known if the key is well randomized to begin with.
+.SH SEE ALSO
+random(3), random(4)
+.br
+Bruce Schneier,
+\fIApplied Cryptography\fR, 2nd ed., 1996, ISBN 0-471-11709-9,
+pp. 397-8.
+.SH HISTORY
+Written for the FreeS/WAN project by Henry Spencer.
+.SH BUGS
+If an attempt is made to obtain more than 4e9 bytes
+between initializations,
+the PRNG will continue to work but
+.IR prng_count 's
+output will stick at
+.BR 4000000000 .
+Fixing this would require a longer integer type and does
+not seem worth the trouble,
+since you should probably re-initialize before then anyway...
+.PP
+``RC4'' is a trademark of RSA Data Security, Inc.
diff --git a/src/libfreeswan/prng.c b/src/libfreeswan/prng.c
new file mode 100644
index 000000000..347f13f89
--- /dev/null
+++ b/src/libfreeswan/prng.c
@@ -0,0 +1,200 @@
+/*
+ * crypto-class pseudorandom number generator
+ * currently uses same algorithm as RC4(TM), from Schneier 2nd ed p397
+ * Copyright (C) 2002 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+/*
+ - prng_init - initialize PRNG from a key
+ */
+void
+prng_init(prng, key, keylen)
+struct prng *prng;
+const unsigned char *key;
+size_t keylen;
+{
+ unsigned char k[256];
+ int i, j;
+ unsigned const char *p;
+ unsigned const char *keyend = key + keylen;
+ unsigned char t;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = i;
+ p = key;
+ for (i = 0; i <= 255; i++) {
+ k[i] = *p++;
+ if (p >= keyend)
+ p = key;
+ }
+ j = 0;
+ for (i = 0; i <= 255; i++) {
+ j = (j + prng->sbox[i] + k[i]) & 0xff;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ k[i] = 0; /* clear out key memory */
+ }
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0;
+}
+
+/*
+ - prng_bytes - get some pseudorandom bytes from PRNG
+ */
+void
+prng_bytes(prng, dst, dstlen)
+struct prng *prng;
+unsigned char *dst;
+size_t dstlen;
+{
+ int i, j, t;
+ unsigned char *p = dst;
+ size_t remain = dstlen;
+# define MAX 4000000000ul
+
+ while (remain > 0) {
+ i = (prng->i + 1) & 0xff;
+ prng->i = i;
+ j = (prng->j + prng->sbox[i]) & 0xff;
+ prng->j = j;
+ t = prng->sbox[i];
+ prng->sbox[i] = prng->sbox[j];
+ prng->sbox[j] = t;
+ t = (t + prng->sbox[i]) & 0xff;
+ *p++ = prng->sbox[t];
+ remain--;
+ }
+ if (prng->count < MAX - dstlen)
+ prng->count += dstlen;
+ else
+ prng->count = MAX;
+}
+
+/*
+ - prnt_count - how many bytes have been extracted from PRNG so far?
+ */
+unsigned long
+prng_count(prng)
+struct prng *prng;
+{
+ return prng->count;
+}
+
+/*
+ - prng_final - clear out PRNG to ensure nothing left in memory
+ */
+void
+prng_final(prng)
+struct prng *prng;
+{
+ int i;
+
+ for (i = 0; i <= 255; i++)
+ prng->sbox[i] = 0;
+ prng->i = 0;
+ prng->j = 0;
+ prng->count = 0; /* just for good measure */
+}
+
+
+
+#ifdef PRNG_MAIN
+
+#include <stdio.h>
+
+void regress();
+
+int
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: %s {key|-r}\n", argv[0]);
+ exit(2);
+ }
+
+ if (strcmp(argv[1], "-r") == 0) {
+ regress();
+ fprintf(stderr, "regress() returned?!?\n");
+ exit(1);
+ }
+
+ prng_init(&pr, argv[1], strlen(argv[1]));
+ prng_bytes(&pr, buf, 32);
+ printf("0x");
+ for (p = buf, n = 32; n > 0; p++, n--)
+ printf("%02x", *p);
+ printf("\n%lu bytes\n", prng_count(&pr));
+ prng_final(&pr);
+ exit(0);
+}
+
+void
+regress()
+{
+ struct prng pr;
+ unsigned char buf[100];
+ unsigned char *p;
+ size_t n;
+ /* somewhat non-random sample key */
+ unsigned char key[] = "here we go gathering nuts in May";
+ /* first thirty bytes of output from that key */
+ unsigned char good[] = "\x3f\x02\x8e\x4a\x2a\xea\x23\x18\x92\x7c"
+ "\x09\x52\x83\x61\xaa\x26\xce\xbb\x9d\x71"
+ "\x71\xe5\x10\x22\xaf\x60\x54\x8d\x5b\x28";
+ int nzero, none;
+ int show = 0;
+
+ prng_init(&pr, key, strlen(key));
+ prng_bytes(&pr, buf, sizeof(buf));
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--) {
+ if (*p == 0)
+ nzero++;
+ if (*p == 255)
+ none++;
+ }
+ if (nzero > 3 || none > 3) {
+ fprintf(stderr, "suspiciously non-random output!\n");
+ show = 1;
+ }
+ if (memcmp(buf, good, strlen(good)) != 0) {
+ fprintf(stderr, "incorrect output!\n");
+ show = 1;
+ }
+ if (show) {
+ fprintf(stderr, "0x");
+ for (p = buf, n = sizeof(buf); n > 0; p++, n--)
+ fprintf(stderr, "%02x", *p);
+ fprintf(stderr, "\n");
+ exit(1);
+ }
+ if (prng_count(&pr) != sizeof(buf)) {
+ fprintf(stderr, "got %u bytes, but count is %lu\n",
+ sizeof(buf), prng_count(&pr));
+ exit(1);
+ }
+ prng_final(&pr);
+ exit(0);
+}
+
+#endif /* PRNG_MAIN */
diff --git a/src/libfreeswan/satoa.c b/src/libfreeswan/satoa.c
new file mode 100644
index 000000000..09a152727
--- /dev/null
+++ b/src/libfreeswan/satoa.c
@@ -0,0 +1,100 @@
+/*
+ * convert from binary form of SA ID to ASCII
+ * Copyright (C) 1998, 1999, 2001 Henry Spencer.
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/lgpl.txt>.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ * License for more details.
+ */
+#include "internal.h"
+#include "freeswan.h"
+
+static struct typename {
+ char type;
+ char *name;
+} typenames[] = {
+ { SA_AH, "ah" },
+ { SA_ESP, "esp" },
+ { SA_IPIP, "tun" },
+ { SA_COMP, "comp" },
+ { SA_INT, "int" },
+ { 0, NULL }
+};
+
+/*
+ - satoa - convert SA to ASCII "ah507@1.2.3.4"
+ */
+size_t /* space needed for full conversion */
+satoa(sa, format, dst, dstlen)
+struct sa_id sa;
+int format; /* character */
+char *dst; /* need not be valid if dstlen is 0 */
+size_t dstlen;
+{
+ size_t len = 0; /* 0 means not handled yet */
+ int base;
+ struct typename *tn;
+ char buf[30+ADDRTOA_BUF];
+
+ switch (format) {
+ case 0:
+ base = 16; /* temporarily at least */
+ break;
+ case 'd':
+ base = 10;
+ break;
+ default:
+ return 0;
+ break;
+ }
+
+ for (tn = typenames; tn->name != NULL; tn++)
+ if (sa.proto == tn->type)
+ break;
+ if (tn->name == NULL)
+ return 0;
+
+ if (strcmp(tn->name, PASSTHROUGHTYPE) == 0 &&
+ sa.spi == PASSTHROUGHSPI &&
+ sa.dst.s_addr == PASSTHROUGHDST) {
+ strcpy(buf, PASSTHROUGHNAME);
+ len = strlen(buf);
+ } else if (sa.proto == SA_INT && sa.dst.s_addr == 0) {
+ char *p;
+
+ switch (ntohl(sa.spi)) {
+ case SPI_PASS: p = "%pass"; break;
+ case SPI_DROP: p = "%drop"; break;
+ case SPI_REJECT: p = "%reject"; break;
+ case SPI_HOLD: p = "%hold"; break;
+ case SPI_TRAP: p = "%trap"; break;
+ case SPI_TRAPSUBNET: p = "%trapsubnet"; break;
+ default: p = NULL; break;
+ }
+ if (p != NULL) {
+ strcpy(buf, p);
+ len = strlen(buf);
+ }
+ }
+
+ if (len == 0) {
+ strcpy(buf, tn->name);
+ len = strlen(buf);
+ len += ultoa(ntohl(sa.spi), base, buf+len, sizeof(buf)-len);
+ *(buf+len-1) = '@';
+ len += addrtoa(sa.dst, 0, buf+len, sizeof(buf)-len);
+ }
+
+ if (dst != NULL) {
+ if (len > dstlen)
+ *(buf+dstlen-1) = '\0';
+ strcpy(dst, buf);
+ }
+ return len;
+}