summaryrefslogtreecommitdiff
path: root/sbin/isakmpd/apps
diff options
context:
space:
mode:
authorHakan Olsson <ho@cvs.openbsd.org>2001-08-15 12:31:41 +0000
committerHakan Olsson <ho@cvs.openbsd.org>2001-08-15 12:31:41 +0000
commit15f376e0ffd6cd5bed12a1222d04f52774910dd4 (patch)
treedaa76b5d17cf9ddaf568771872b3bc1d4ec1dcfd /sbin/isakmpd/apps
parentcf2c55efac4edd0ddee07ecc3ea939a000d05fdb (diff)
A small utility to convert between OpenSSL(1) and DNSSEC key formats.
Diffstat (limited to 'sbin/isakmpd/apps')
-rw-r--r--sbin/isakmpd/apps/keyconv/Makefile51
-rw-r--r--sbin/isakmpd/apps/keyconv/base64.c314
-rw-r--r--sbin/isakmpd/apps/keyconv/keyconv.c762
3 files changed, 1127 insertions, 0 deletions
diff --git a/sbin/isakmpd/apps/keyconv/Makefile b/sbin/isakmpd/apps/keyconv/Makefile
new file mode 100644
index 00000000000..70e7880a19d
--- /dev/null
+++ b/sbin/isakmpd/apps/keyconv/Makefile
@@ -0,0 +1,51 @@
+# $Id: Makefile,v 1.1 2001/08/15 12:31:40 ho Exp $
+
+#
+# Copyright (c) 2000 Håkan Olsson. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+PROG= keyconv
+SRCS= keyconv.c base64.c
+BINDIR= /usr/sbin
+
+TOPSRC= ${.CURDIR}/../..
+TOPOBJ!= cd ${TOPSRC}; printf "all:\n\t@pwd\n" |${MAKE} -f-
+OS!= awk '/^OS=/ { print $$2 }' ${.CURDIR}/../../Makefile
+.PATH: ${TOPSRC} ${TOPSRC}/sysdep/${OS} ${TOPOBJ}
+CFLAGS+= -I${TOPSRC} -I${TOPSRC}/sysdep/${OS} -I${TOPOBJ} -Wall
+CFLAGS+= -I/usr/local/include
+LDADD+= -lcrypto ${LIBLWRES}
+DPADD+= ${LIBCRYPTO}
+NOMAN= yes
+
+.include "${TOPSRC}/sysdep/${OS}/Makefile.sysdep"
+# Override LIBSYSDEPDIR definition from Makefile.sysdep
+LIBSYSDEPDIR= ${TOPSRC}/sysdep/common/libsysdep
+
+.include <bsd.prog.mk>
+
+# Mainly during devel
+realclean: clean
+ rm -f ${.CURDIR}/*.{pem,private,key}
diff --git a/sbin/isakmpd/apps/keyconv/base64.c b/sbin/isakmpd/apps/keyconv/base64.c
new file mode 100644
index 00000000000..0449fa899b3
--- /dev/null
+++ b/sbin/isakmpd/apps/keyconv/base64.c
@@ -0,0 +1,314 @@
+/* $Id: base64.c,v 1.1 2001/08/15 12:31:40 ho Exp $ */
+/* $OpenBSD: base64.c,v 1.1 2001/08/15 12:31:40 ho Exp $ */
+
+/*
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#if !defined(LINT) && !defined(CODECENTER)
+static const char rcsid[] = "$ISC: base64.c,v 8.6 1999/01/08 19:25:18 vixie Exp $";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int
+b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int
+b64_pton(src, target, targsize)
+ char const *src;
+ u_char *target;
+ size_t targsize;
+{
+ int tarindex, state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if ((size_t)tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if ((size_t)tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ for ((void)NULL; ch != '\0'; ch = *src++)
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/sbin/isakmpd/apps/keyconv/keyconv.c b/sbin/isakmpd/apps/keyconv/keyconv.c
new file mode 100644
index 00000000000..4dab4190595
--- /dev/null
+++ b/sbin/isakmpd/apps/keyconv/keyconv.c
@@ -0,0 +1,762 @@
+/* $Id: keyconv.c,v 1.1 2001/08/15 12:31:40 ho Exp $ */
+
+/*
+ * Copyright (c) 2000 Hakan Olsson. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <dns/keyvalues.h>
+#include <lwres/lwres.h>
+#include <lwres/netdb.h>
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+#include <openssl/dh.h>
+#include <openssl/pem.h>
+
+/* base64.c prototypes */
+int b64_pton (const char *, u_char *, size_t);
+int b64_ntop (const u_char *, size_t, char *, size_t);
+
+#define OPENSSL_DEFAULT_EXT ".pem"
+#define DNSSEC_DEFAULT_EXT ".private"
+
+/* DNSSEC private key format version */
+#define MAJOR_VERSION 1
+#define MINOR_VERSION 2
+
+char *progname;
+
+/* For DH calc. */
+BIGNUM bn_b2, bn_oakley1, bn_oakley2, bn_oakley5;
+
+void
+usage_exit (void)
+{
+ fprintf (stderr, "Usage: %s infile outfile\n\n", progname);
+ fprintf (stderr, "Extension of infile / outfile gives mode of operation.\n");
+ fprintf (stderr, "Recognized extensions = %s %s\n\n", OPENSSL_DEFAULT_EXT,
+ DNSSEC_DEFAULT_EXT);
+ fprintf (stderr, "Example:\n");
+ fprintf (stderr, " %s test%s test%s\n", progname, DNSSEC_DEFAULT_EXT,
+ OPENSSL_DEFAULT_EXT);
+ fprintf (stderr, " - converts from DNSSEC to OPENSSL format.\n");
+ exit (1);
+}
+
+/*
+ * Ok, I dont have the patience to do everything "by the book" here, so
+ * I'll use some shortcuts...
+ */
+
+static const char *dns_tags[] =
+{
+ "Private-key-format:", "Algorithm:", "Modulus:", "PublicExponent:",
+ "PrivateExponent:", "Prime1:", "Prime2:", "Exponent1:", "Exponent2:",
+ "Coefficient:", "Generator(g):", "Prime(p):", "Private_value(x):",
+ "Public_value(y):", "Subprime(q):", "Base(g):", "Key:",
+ NULL
+};
+
+/* Must match the above */
+enum DNS_TAGS
+{ TAG_VERSION, TAG_ALGORITHM, TAG_MODULUS, TAG_PUBEXP, TAG_PRIVEXP,
+ TAG_PRIME1, TAG_PRIME2, TAG_EXP1, TAG_EXP2, TAG_COEFF, TAG_GENERATOR,
+ TAG_PRIME, TAG_PRIVVAL, TAG_PUBVAL, TAG_SUBPRIME, TAG_BASE, TAG_KEY };
+
+#define MAX_LINE 4096
+
+char *
+hex2bin (char *h, int *len)
+{
+ static char b[MAX_LINE];
+ const char hex[] = "0123456789abcdef0123456789ABCDEF";
+ u_int8_t c;
+ char *n;
+ int p;
+
+ for (p = 0; p < strlen (h); p += 2)
+ {
+ n = strchr (hex, *(h + p));
+ if (!n)
+ {
+ printf ("D1: %d (%c)\n", *(h+p), *(h+p));
+ fprintf (stderr, "hex2bin: bad input data!\n");
+ exit (1);
+ }
+ c = ((char)(n - hex) & 0xF) << 4;
+ n = strchr (hex, *(h + p + 1));
+ if (!n)
+ {
+ printf ("D2: %d (%c)\n", *(h+p+1), *(h+p+1));
+ fprintf (stderr, "hex2bin: bad input data!\n");
+ exit (1);
+ }
+ c |= ((char)(n - hex)) & 0xF;
+ *(b + (p/2)) = (char)c;
+ }
+ *(b + (p/2)) = (char)0;
+ *len = p/2;
+ return b;
+}
+
+void
+init_DH_constants (void)
+{
+#define MODP_768 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"\
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"\
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"\
+ "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
+
+#define MODP_1024 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
+ "FFFFFFFFFFFFFFFF"
+
+#define MODP_1536 \
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
+
+ int len;
+ char *t;
+
+ BN_init (&bn_b2);
+ BN_init (&bn_oakley1);
+ BN_init (&bn_oakley2);
+ BN_init (&bn_oakley5);
+ BN_set_word (&bn_b2, 2);
+ t = hex2bin (MODP_768, &len); BN_bin2bn (t, len, &bn_oakley1);
+ t = hex2bin (MODP_1024, &len); BN_bin2bn (t, len, &bn_oakley2);
+ t = hex2bin (MODP_1536, &len); BN_bin2bn (t, len, &bn_oakley5);
+}
+
+int
+convert_dns_to_openssl (char *file_in, char *file_out)
+{
+ FILE *ii, *oo;
+ char line[MAX_LINE], data[MAX_LINE], *valuestr;
+ DH *dh;
+ RSA *rsa;
+ DSA *dsa;
+ BIGNUM *bn;
+ int lineno = 0, algorithm = 0, m, n, dh_code;
+ enum DNS_TAGS found;
+ u_int32_t bitfield = 0;
+
+ /* Try to open input file */
+ ii = fopen (file_in, "r");
+ if (!ii)
+ {
+ fprintf (stderr, "Cannot open input file %.100s for reading\n", file_in);
+ return 1;
+ }
+
+ /* Avoid compiler noises. */
+ dh = NULL; rsa = NULL; dsa = NULL; bn = NULL;
+
+ while (fgets (line, MAX_LINE, ii) != NULL)
+ {
+ lineno ++;
+
+ /* Try to find a matching field in the *.private file (dnssec-keygen) */
+ for (m = 0, found = -1; found == -1 && dns_tags[m]; m++)
+ if (strncasecmp (line, dns_tags[m], strlen (dns_tags[m])) == 0)
+ found = m;
+
+ if (found == -1)
+ {
+ fprintf (stderr, "Unrecognized input line %d\n", lineno);
+ fprintf (stderr, " --> %s", line);
+ continue;
+ }
+
+ valuestr = line + strlen (dns_tags[found]) + 1;
+
+ if (found == TAG_VERSION)
+ {
+ if (sscanf (valuestr, "v%d.%d", &m, &n) != 2)
+ {
+ fprintf (stderr, "Invalid/unknown version string (%.100s).\n",
+ valuestr);
+ return 1;
+ }
+ if (m > MAJOR_VERSION || (m == MAJOR_VERSION && n > MINOR_VERSION))
+ {
+ fprintf (stderr, "Cannot parse file formats above v%d.%d. "
+ "This is v%d.%d.\n", MAJOR_VERSION, MINOR_VERSION, m,
+ n);
+ return 1;
+ }
+ continue;
+ }
+
+ if (found == TAG_ALGORITHM)
+ {
+ algorithm = strtol (valuestr, NULL, 10);
+ switch (algorithm)
+ {
+ case DNS_KEYALG_RSAMD5:
+ rsa = RSA_new ();
+ rsa->flags &= ~(RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE);
+ break;
+ case DNS_KEYALG_DH:
+ dh = DH_new();
+ dh->flags &= ~DH_FLAG_CACHE_MONT_P;
+ break;
+ case DNS_KEYALG_DSA:
+ dsa = DSA_new();
+ dsa->flags &= ~DSA_FLAG_CACHE_MONT_P;
+ break;
+ default:
+ fprintf (stderr, "Invalid algorithm %d\n", algorithm);
+ return 1;
+ }
+ continue;
+ }
+
+ switch (algorithm)
+ {
+ case DNS_KEYALG_RSAMD5:
+ if (found > TAG_COEFF)
+ {
+ fprintf (stderr, "Invalid keyword for RSA, line %d\n", lineno);
+ continue;
+ }
+ break;
+ case DNS_KEYALG_DH:
+ if (found < TAG_GENERATOR || found > TAG_PUBVAL)
+ {
+ fprintf (stderr, "Invalid keyword for DH, line %d\n", lineno);
+ continue;
+ }
+ break;
+ case DNS_KEYALG_DSA:
+ if (found < TAG_PRIME || found > TAG_BASE)
+ {
+ fprintf (stderr, "Invalid keyword for DSA, line %d\n", lineno);
+ continue;
+ }
+ break;
+ default:
+ /* We should never reach this unless the file format is invalid. */
+ fprintf (stderr, "Invalid file format, no algorithm specified.\n");
+ return 1;
+ }
+
+ /* Ok, now we just have to deal with the fields as they appear. */
+
+ if (bitfield & (1 << found))
+ {
+ fprintf (stderr, "Duplicate \"%s\" field, line %d - ignored\n",
+ dns_tags[found], lineno);
+ continue; /* XXX return 1; ? */
+ }
+ bitfield |= (1 << found);
+
+ m = b64_pton (valuestr, data, MAX_LINE);
+ bn = BN_bin2bn (data, m, NULL);
+ if (!bn)
+ {
+ fprintf (stderr,
+ "BN_bin2bn() failed for field \"%s\", line %d.\n",
+ dns_tags[found], lineno);
+ return 1;
+ }
+
+ switch (found)
+ {
+ case TAG_MODULUS: /* RSA modulus */
+ rsa->n = bn;
+ break;
+ case TAG_PUBEXP: /* RSA public exponent */
+ rsa->e = bn;
+ break;
+ case TAG_PRIVEXP: /* RSA private exponent */
+ rsa->d = bn;
+ break;
+ case TAG_PRIME1: /* RSA prime 1 */
+ rsa->p = bn;
+ break;
+ case TAG_PRIME2: /* RSA prime 2 */
+ rsa->q = bn;
+ break;
+ case TAG_EXP1: /* RSA exponent 1 */
+ rsa->dmp1 = bn;
+ break;
+ case TAG_EXP2: /* RSA exponent 2 */
+ rsa->dmq1 = bn;
+ break;
+ case TAG_COEFF: /* RSA coefficient */
+ rsa->iqmp = bn;
+ break;
+
+ case TAG_GENERATOR: /* DH generator(g) */
+ dh->g = bn;
+ break;
+
+ case TAG_PRIME: /* DH/DSA prime(p) */
+ if (algorithm == DNS_KEYALG_DH)
+ dh->p = bn;
+ else
+ dsa->p = bn;
+ break;
+
+ case TAG_PUBVAL: /* DH/DSA private-value(x) */
+ if (algorithm == DNS_KEYALG_DH)
+ dh->pub_key = bn;
+ else
+ dsa->pub_key = bn;
+ break;
+
+ case TAG_PRIVVAL: /* DH/DSA public-value(y) */
+ if (algorithm == DNS_KEYALG_DH)
+ dh->priv_key = bn;
+ else
+ dsa->priv_key = bn;
+ break;
+
+ case TAG_SUBPRIME: /* DSA Subprime(q) */
+ dsa->q = bn;
+ break;
+ case TAG_BASE: /* DSA Base(g) */
+ dsa->g = bn;
+ break;
+
+ default:
+ break;
+ }
+ }
+ fclose (ii);
+
+ /* Check results */
+ switch (algorithm)
+ {
+ case DNS_KEYALG_RSAMD5:
+ m = (RSA_check_key (rsa) < 1 ? 0 : 1);
+ break;
+ case DNS_KEYALG_DH:
+ dh_code = 0;
+ m = DH_check (dh, &dh_code);
+ break;
+ case DNS_KEYALG_DSA:
+ /* No check available. */
+ default:
+ m = -1;
+ break;
+ }
+
+ if (m == 1)
+ fprintf (stderr, "Key succeeded validation check.\n");
+ else if (m == 0)
+ {
+ fprintf (stderr, "Key failed validation check.\n");
+ return 1;
+ }
+
+ oo = fopen (file_out, "w");
+ if (!oo)
+ fprintf (stderr, "Cannot open output file %.100s\n", file_out);
+ else
+ fprintf (stderr, "Writing output file \"%s\".\n", file_out);
+
+ /* Write result and cleanup */
+ switch (algorithm)
+ {
+ case DNS_KEYALG_RSAMD5:
+ if (oo)
+ PEM_write_RSAPrivateKey (oo, rsa, NULL, NULL, 0, NULL, NULL);
+ RSA_free (rsa);
+ break;
+
+ case DNS_KEYALG_DH:
+ if (oo)
+ PEM_write_DHparams (oo, dh);
+ DH_free (dh);
+ break;
+
+ case DNS_KEYALG_DSA:
+ if (oo)
+ PEM_write_DSAPrivateKey (oo, dsa, NULL, NULL, 0, NULL, NULL);
+ DSA_free (dsa);
+ break;
+
+ default:
+ break;
+ }
+
+ if (oo)
+ fclose (oo);
+ return 0;
+}
+
+char *
+bn_to_b64 (const BIGNUM *bn)
+{
+ static char b64data[MAX_LINE];
+ char data[MAX_LINE];
+ int dlen, blen;
+
+ if (!bn)
+ {
+ blen = 0;
+ goto out;
+ }
+
+ dlen = BN_bn2bin (bn, data);
+ blen = b64_ntop (data, dlen, b64data, MAX_LINE);
+
+ out:
+ b64data[blen] = (char) 0;
+ return b64data;
+}
+
+void
+write_RSA_public_key (char *fname, RSA *rsa)
+{
+ FILE *out;
+ int e_bytes, mod_bytes, dlen, blen;
+ char data[MAX_LINE], b64buf[MAX_LINE];
+
+ out = fopen (fname, "w");
+ if (!out)
+ {
+ fprintf (stderr, "Couldn't open public key file for writing.\n");
+ return;
+ }
+
+ fprintf (stderr, "Writing output file \"%.100s\".\n", fname);
+ dlen = 0;
+
+ e_bytes = BN_num_bytes (rsa->e);
+ mod_bytes = BN_num_bytes (rsa->n);
+
+ fprintf (out, ";name IN KEY %d %d %d ", DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_IPSEC, DNS_KEYALG_RSAMD5);
+
+ if (e_bytes <= 0xFF)
+ data[dlen++] = (char)e_bytes;
+ else
+ {
+ data[dlen++] = (char)0;
+ data[dlen++] = (char)(e_bytes >> 8);
+ data[dlen++] = (char)(e_bytes & 0xFF);
+ }
+ dlen += BN_bn2bin (rsa->e, data + dlen);
+ dlen += BN_bn2bin (rsa->n, data + dlen);
+
+ blen = b64_ntop (data, dlen, b64buf, MAX_LINE);
+ b64buf[blen] = (char)0;
+
+ fprintf (out, "%s\n", b64buf);
+ fclose (out);
+}
+
+void
+write_DSA_public_key (char *fname, DSA *dsa)
+{
+ FILE *out;
+ int p_bytes, dlen, blen, p;
+ char data[MAX_LINE], b64buf[MAX_LINE];
+
+ out = fopen (fname, "w");
+ if (!out)
+ {
+ fprintf (stderr, "Couldn't open public key file for writing.\n");
+ return;
+ }
+
+ fprintf (stderr, "Writing output file \"%.100s\".\n", fname);
+
+ p_bytes = BN_num_bytes (dsa->p);
+ if (((p_bytes - 64) / 8) > 8)
+ {
+ fprintf (stderr, "Invalid DSA key.\n");
+ fclose (out);
+ return;
+ }
+
+ dlen = blen = 0;
+ *(data + dlen++) = (p_bytes - 64) / 8;
+
+ /* Fields in DSA public key are zero-padded (left) */
+#define PAD_ADD(var,len) \
+ for (p = 0; p < (len - BN_num_bytes (var)); p++) \
+ *(data + dlen++) = (char)0; \
+ BN_bn2bin (var, data + dlen); \
+ dlen += BN_num_bytes (var)
+
+ PAD_ADD (dsa->q, SHA_DIGEST_LENGTH);
+ PAD_ADD (dsa->p, p_bytes);
+ PAD_ADD (dsa->g, p_bytes);
+ PAD_ADD (dsa->pub_key, p_bytes);
+
+ blen = b64_ntop (data, dlen, b64buf, MAX_LINE);
+ b64buf[blen] = (char)0;
+
+ fprintf (out, ";name IN KEY %d %d %d %s\n", DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_IPSEC, DNS_KEYALG_DSA, b64buf);
+ fclose (out);
+}
+
+void
+write_DH_public_key (char *fname, DH *dh)
+{
+ FILE *out;
+ int dlen, blen, p, g;
+ char data[MAX_LINE], b64buf[MAX_LINE];
+
+ out = fopen (fname, "w");
+ if (!out)
+ {
+ fprintf (stderr, "Couldn't open public key file for writing.\n");
+ return;
+ }
+
+ fprintf (stderr, "Writing output file \"%.100s\".\n", fname);
+
+ dlen = p = g = 0;
+ if (BN_cmp (dh->g, &bn_b2) == 0)
+ {
+ p = 1;
+ if (BN_cmp (dh->p, &bn_oakley1) == 0)
+ *(data + dlen++) = (char)1;
+ else if (BN_cmp (dh->p, &bn_oakley2) == 0)
+ *(data + dlen++) = (char)2;
+ else if (BN_cmp (dh->p, &bn_oakley5) == 0)
+ *(data + dlen++) = (char)5;
+ else
+ p = 0;
+ }
+
+ if (p == 0)
+ {
+ p = BN_num_bytes (dh->p);
+ g = BN_num_bytes (dh->g);
+ dlen += BN_bn2bin (dh->p, data + dlen);
+ if (g > 0)
+ dlen += BN_bn2bin (dh->p, data + dlen);
+ }
+
+ dlen += BN_bn2bin (dh->pub_key, data + dlen);
+
+ blen = b64_ntop (data, dlen, b64buf, MAX_LINE);
+ b64buf[blen] = (char)0;
+
+ fprintf (out, ";name IN KEY %d %d %d %s\n", DNS_KEYOWNER_ENTITY,
+ DNS_KEYPROTO_IPSEC, DNS_KEYALG_DH, b64buf);
+
+ fclose (out);
+}
+
+int
+convert_openssl_to_dns (char *file_in, char *file_out)
+{
+ FILE *ii, *oo;
+ RSA *rsa;
+ DSA *dsa;
+ DH *dh;
+ enum DNS_TAGS tag;
+ char *pubname;
+
+ rsa = NULL;
+ dsa = NULL;
+ dh = NULL;
+
+ ii = fopen (file_in, "r");
+ if (!ii)
+ {
+ fprintf (stderr, "Cannot open input file %.100s for reading\n", file_in);
+ return 1;
+ }
+
+ /* Try to load PEM */
+ rsa = PEM_read_RSAPrivateKey (ii, NULL, NULL, NULL);
+ if (!rsa)
+ {
+ rewind (ii);
+ dsa = PEM_read_DSAPrivateKey (ii, NULL, NULL, NULL);
+ if (!dsa)
+ {
+ rewind (ii);
+ dh = PEM_read_DHparams (ii, NULL, NULL, NULL);
+ if (!dh)
+ {
+ fprintf (stderr, "Unrecognized infile format.\n");
+ fclose (ii);
+ return 1;
+ }
+ }
+ }
+ fclose (ii);
+
+ oo = fopen (file_out, "w");
+ if (!oo)
+ {
+ fprintf (stderr, "Cannot open output file %.100s\n", file_out);
+ return 1;
+ }
+
+ pubname = strdup (file_out);
+ sprintf (pubname + strlen (pubname) - 7, "key");
+
+ fprintf (stderr, "Writing output file \"%s\".\n", file_out);
+ fprintf (oo, "%s v%d.%d\n", dns_tags[TAG_VERSION], MAJOR_VERSION,
+ MINOR_VERSION);
+
+ /* XXX Algorithm dependent validation checks? */
+
+ if (rsa)
+ {
+ /* Write private key */
+ fprintf (oo, "%s %d (%s)\n", dns_tags[TAG_ALGORITHM],
+ DNS_KEYALG_RSAMD5, "RSA");
+ tag = TAG_MODULUS;
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->n));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->e));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->d));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->p));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->q));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->dmp1));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->dmq1));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (rsa->iqmp));
+
+ write_RSA_public_key (pubname, rsa);
+ }
+ else if (dsa)
+ {
+ /* DSA_print_fp (stdout, dsa, 2); */
+
+ fprintf (oo, "%s %d (%s)\n", dns_tags[TAG_ALGORITHM],
+ DNS_KEYALG_DSA, "DSA");
+ tag = TAG_PRIME;
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dsa->p));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dsa->priv_key));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dsa->pub_key));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dsa->q));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dsa->g));
+
+ write_DSA_public_key (pubname, dsa);
+ }
+ else if (dh)
+ {
+ /*
+ * OpenSSL never stored private and public key values, so
+ * we have to regenerate them from p and g.
+ */
+ if (DH_generate_key (dh) == 0)
+ {
+ fprintf (stderr, "DH key generation failed\n");
+ fclose (oo);
+ unlink (file_out);
+ return 1;
+ }
+
+ fprintf (oo, "%s %d (%s)\n", dns_tags[TAG_ALGORITHM],
+ DNS_KEYALG_DH, "DH");
+ tag = TAG_GENERATOR;
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dh->g));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dh->p));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dh->priv_key));
+ fprintf (oo, "%s %s\n", dns_tags[tag++], bn_to_b64 (dh->pub_key));
+
+ write_DH_public_key (pubname, dh);
+ }
+ else
+ {
+ fprintf (stderr, "PEM_read_PrivateKey() read unknown data.\n");
+ fclose (oo);
+ unlink (file_out);
+ return 1;
+ }
+
+ fclose (oo);
+ return 0;
+}
+
+int
+main (int argc, char **argv)
+{
+ char *p;
+ int ret, dns_to_openssl = -1;
+
+ progname = argv[0];
+
+ if (argc != 3)
+ usage_exit ();
+
+ /* Check input syntax */
+ for (p = argv[1] + strlen (argv[1]); p > argv[1] && *p != '.'; p--) ;
+ if (*p != '.')
+ usage_exit ();
+
+ if (strlen (p) == 4 && strcasecmp (p, OPENSSL_DEFAULT_EXT) == 0)
+ dns_to_openssl = 0;
+ else if (strlen (p) == 8 && strcasecmp (p, DNSSEC_DEFAULT_EXT) == 0)
+ dns_to_openssl = 1;
+ else
+ usage_exit ();
+
+ /* Check second argument */
+ for (p = argv[2] + strlen (argv[2]); p > argv[2] && *p != '.'; p--) ;
+ if (*p != '.')
+ usage_exit ();
+
+ if (dns_to_openssl)
+ {
+ if (strlen (p) != 4 || strcasecmp (p, OPENSSL_DEFAULT_EXT) != 0)
+ usage_exit ();
+ }
+ else
+ if (strlen (p) != 8 || strcasecmp (p, DNSSEC_DEFAULT_EXT) != 0)
+ usage_exit ();
+
+ init_DH_constants ();
+
+ /* Convert. */
+ if (dns_to_openssl)
+ ret = convert_dns_to_openssl (argv[1], argv[2]);
+ else
+ ret = convert_openssl_to_dns (argv[1], argv[2]);
+
+ if (ret)
+ fprintf (stderr, "Operation failed.\n");
+
+ return 0;
+}