summaryrefslogtreecommitdiffstats
path: root/contrib/bind/lib/dst
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1999-11-30 02:43:11 +0000
committerpeter <peter@FreeBSD.org>1999-11-30 02:43:11 +0000
commit4ef23ce6957fc75fc005885496d605fed48213e1 (patch)
tree7828b08c74ef918938b1b853c98f0cb41edac52c /contrib/bind/lib/dst
parent67e0f3ce71726dc4058c2f80a813341a59244dbd (diff)
downloadFreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.zip
FreeBSD-src-4ef23ce6957fc75fc005885496d605fed48213e1.tar.gz
Import bind v8.2.2.p5, minus the crypto for the time being. The bind
package does have BXA export approval, but the licensing strings on the dnssafe code are a bit unpleasant. The crypto is easy to restore and bind will run without it - just without full dnssec support. Obtained from: The Internet Software Consortium (www.isc.org)
Diffstat (limited to 'contrib/bind/lib/dst')
-rw-r--r--contrib/bind/lib/dst/Makefile96
-rw-r--r--contrib/bind/lib/dst/README27
-rw-r--r--contrib/bind/lib/dst/bsafe_link.c1125
-rw-r--r--contrib/bind/lib/dst/cylink_link.c676
-rw-r--r--contrib/bind/lib/dst/dst_api.c1068
-rw-r--r--contrib/bind/lib/dst/dst_internal.h163
-rw-r--r--contrib/bind/lib/dst/eay_dss_link.c624
-rw-r--r--contrib/bind/lib/dst/hmac_link.c493
-rw-r--r--contrib/bind/lib/dst/md5.h101
-rw-r--r--contrib/bind/lib/dst/md5_dgst.c368
-rw-r--r--contrib/bind/lib/dst/md5_locl.h190
-rw-r--r--contrib/bind/lib/dst/prandom.c851
-rw-r--r--contrib/bind/lib/dst/rsaref_link.c754
-rw-r--r--contrib/bind/lib/dst/support.c461
14 files changed, 6997 insertions, 0 deletions
diff --git a/contrib/bind/lib/dst/Makefile b/contrib/bind/lib/dst/Makefile
new file mode 100644
index 0000000..f99813c
--- /dev/null
+++ b/contrib/bind/lib/dst/Makefile
@@ -0,0 +1,96 @@
+# 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.
+
+# $Id: Makefile,v 1.13 1999/03/07 09:33:47 vixie Exp $
+
+# these are only appropriate for BSD 4.4 or derivatives, and are used in
+# development. normal builds will be done in the top level directory and
+# this Makefile will be invoked with a lot of overrides for the following:
+SYSTYPE= bsdos
+DESTDIR =
+DESTLIB = /usr/local/lib
+O=o
+A=a
+CC= cc
+LD= ld
+SHELL= /bin/sh
+CDEBUG= -g
+TOP= ../..
+INCL = ${TOP}/include
+PORTINCL = ${TOP}/port/${SYSTYPE}/include
+LIBBIND = ${TOP}/lib/libbind.${A}
+LIBBINDR = ../${TOP}/lib/libbind_r.${A}
+CFLAGS= ${CDEBUG} -I${PORTINCL} -I${INCL}
+LD_LIBFLAGS= -x -r
+AR= ar cru
+RANLIB= ranlib
+INSTALL= install
+INSTALL_EXEC=
+INSTALL_LIB=-o bin -g bin
+THREADED= threaded
+
+HDRS= md5.h md5_locl.h
+
+SRCS= dst_api.c prandom.c rsaref_link.c support.c bsafe_link.c \
+ cylink_link.c hmac_link.c md5_dgst.c eay_dss_link.c
+
+OBJS= dst_api.${O} prandom.${O} rsaref_link.${O} support.${O} \
+ bsafe_link.${O} cylink_link.${O} hmac_link.${O} md5_dgst.${O} \
+ eay_dss_link.${O}
+
+CRYPTINCL=
+CRYPTFLAGS= -DHMAC_MD5 -DUSE_MD5
+
+all: ${LIBBIND}
+
+${LIBBIND}: ${OBJS}
+ ( cd ${THREADED} ; \
+ ${AR} ${LIBBINDR} ${ARPREF} ${OBJS} ${ARSUFF} ; \
+ ${RANLIB} ${LIBBINDR} )
+ ${AR} ${LIBBIND} ${ARPREF} ${OBJS} ${ARSUFF}
+ ${RANLIB} ${LIBBIND}
+
+.c.${O}:
+ if test ! -d ${THREADED} ; then mkdir ${THREADED} ; fi
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${BOUNDS} ${REENTRANT} ${CRYPTINCL} ${CRYPTFLAGS} -c $*.c -o ${THREADED}/$*.${O}
+ -${LDS} ${LD} ${LD_LIBFLAGS} ${THREADED}/$*.${O} -o a.out && \
+ ${LDS} mv a.out ${THREADED}/$*.${O}
+ ${CC} ${CPPFLAGS} ${CFLAGS} ${CRYPTINCL} ${CRYPTFLAGS} -c $*.c
+ -${LDS} ${LD} ${LD_LIBFLAGS} $*.${O} -o a.out && \
+ ${LDS} mv a.out $*.${O}
+
+$(SRCS):: $(HDRS)
+
+distclean: clean
+
+clean: FRC
+ rm -f .depend a.out core ${LIB} tags
+ rm -f *.${O} *.BAK *.CKP *~
+ rm -f prand_conf.h
+ rm -f ${THREADED}/*.${O}
+ -rmdir ${THREADED}
+
+depend: FRC
+ mkdep -I${INCL} -I${PORTINCL} ${CPPFLAGS} ${SRCS}
+
+links: FRC
+ @set -e; ln -s SRC/*.[ch] SRC/*.pl .
+
+install:
+
+FRC:
+
+# DO NOT DELETE THIS LINE -- mkdep uses it.
+# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
diff --git a/contrib/bind/lib/dst/README b/contrib/bind/lib/dst/README
new file mode 100644
index 0000000..6283e58
--- /dev/null
+++ b/contrib/bind/lib/dst/README
@@ -0,0 +1,27 @@
+This directory in BIND contains the Domain Signature Tools (dst)
+library. It was written by Trusted Information Systems, Inc. and
+integrated into BIND by John Gilmore. It is used as a generic
+crypto library interface by the DNS Security code in BIND.
+
+ Installing Domain Signature Tools Library - dst
+
+1. Assess available crypto libraries:
+
+ if you have DNSSAFE (the default)
+ CRYPTFLAGS must include -DDNSSAFE
+ CRYPTINCL must include -I../dnssafe
+
+ if you have RSAREF
+ CRYPTFLAGS must include -DRSAREF
+ CRYPTINCL must include -I<path to rsa include files>
+
+ if you have BSAFE
+ CRYPTFLAGS must include -DBSAFE
+ CRYPTINCL must include -I<path to bsafe include files>
+
+ if you want HMAC-MD5 support
+ CRYPTFLAGs must include -DHMAC
+
+2. Building BIND as usual will include the dst library routines into
+ libbind.a, and link them into the BIND programs that use crypto
+ support.
diff --git a/contrib/bind/lib/dst/bsafe_link.c b/contrib/bind/lib/dst/bsafe_link.c
new file mode 100644
index 0000000..8b24d99
--- /dev/null
+++ b/contrib/bind/lib/dst/bsafe_link.c
@@ -0,0 +1,1125 @@
+#if defined(BSAFE) || defined(DNSSAFE)
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/bsafe_link.c,v 1.11 1999/10/13 16:39:22 vixie Exp $";
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+/*
+ * This file contains two components
+ * 1. Interface to the BSAFE library to allow compilation of Bind
+ * with TIS/DNSSEC when BSAFE is not available
+ * all calls to BSAFE are contained inside this file.
+ * 2. The glue to connvert RSA KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include "dst_internal.h"
+
+# ifdef __STDC__
+# define PROTOTYPES 1
+# else
+# define PROTOTYPES 0
+# endif
+
+# ifdef BSAFE
+# include <aglobal.h>
+# include <bsafe.h>
+# else
+# include <global.h>
+# include <bsafe2.h>
+# include <bigmaxes.h>
+# endif
+
+#include "port_after.h"
+
+typedef struct bsafekey {
+ char *rk_signer;
+ B_KEY_OBJ rk_Private_Key;
+ B_KEY_OBJ rk_Public_Key;
+} RSA_Key;
+
+#ifndef MAX_RSA_MODULUS_BITS
+#define MAX_RSA_MODULUS_BITS 4096
+#define MAX_RSA_MODULUS_LEN (MAX_RSA_MODULUS_BITS/8)
+#define MAX_RSA_PRIME_LEN (MAX_RSA_MODULUS_LEN/2)
+#endif
+
+#define NULL_SURRENDER (A_SURRENDER_CTX *)NULL_PTR
+#define NULL_RANDOM (B_ALGORITHM_OBJ)NULL_PTR
+
+B_ALGORITHM_METHOD *CHOOSER[] =
+{
+ &AM_MD5,
+ &AM_MD5_RANDOM,
+ &AM_RSA_KEY_GEN,
+ &AM_RSA_ENCRYPT,
+ &AM_RSA_DECRYPT,
+ &AM_RSA_CRT_ENCRYPT,
+ &AM_RSA_CRT_DECRYPT,
+ (B_ALGORITHM_METHOD *) NULL_PTR
+};
+
+static u_char pkcs1[] =
+{
+ 0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86,
+ 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00,
+ 0x04, 0x10
+};
+
+static int dst_bsafe_md5digest(const int mode, B_ALGORITHM_OBJ *digest_obj,
+ const u_char *data, const int len,
+ u_char *digest, const int digest_len);
+
+static int dst_bsafe_key_size(RSA_Key *r_key);
+
+static int dst_bsafe_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len);
+static int dst_bsafe_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len);
+static int dst_bsafe_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len);
+static int dst_bsafe_from_dns_key(DST_KEY *s_key, const u_char *key,
+ const int len);
+static int dst_bsafe_key_to_file_format(const DST_KEY *key, char *buff,
+ const int buff_len);
+static int dst_bsafe_key_from_file_format(DST_KEY *d_key,
+ const char *buff,
+ const int buff_len);
+static int dst_bsafe_generate_keypair(DST_KEY *key, int exp);
+static int dst_bsafe_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+static void *dst_bsafe_free_key_structure(void *key);
+
+/*
+ * dst_bsafe_init() Function to answer set up function pointers for
+ * BSAFE/DNSSAFE related functions
+ */
+int
+dst_bsafe_init()
+{
+ if (dst_t_func[KEY_RSA] != NULL)
+ return (1);
+ dst_t_func[KEY_RSA] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_RSA] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_RSA], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_RSA]->sign = dst_bsafe_sign;
+ dst_t_func[KEY_RSA]->verify = dst_bsafe_verify;
+ dst_t_func[KEY_RSA]->compare = dst_bsafe_compare_keys;
+ dst_t_func[KEY_RSA]->generate = dst_bsafe_generate_keypair;
+ dst_t_func[KEY_RSA]->destroy = dst_bsafe_free_key_structure;
+ dst_t_func[KEY_RSA]->from_dns_key = dst_bsafe_from_dns_key;
+ dst_t_func[KEY_RSA]->to_dns_key = dst_bsafe_to_dns_key;
+ dst_t_func[KEY_RSA]->from_file_fmt = dst_bsafe_key_from_file_format;
+ dst_t_func[KEY_RSA]->to_file_fmt = dst_bsafe_key_to_file_format;
+ return (1);
+}
+
+/*
+ * dst_bsafe_sign
+ * Call BSAFE signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey structure holds context for a sign done in multiple calls.
+ * context the context to use for this computation
+ * data data to be signed.
+ * len length in bytes of data.
+ * priv_key key to use for signing.
+ * signature location to store signature.
+ * sig_len size in bytes of signature field.
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_bsafe_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ u_int sign_len = 0;
+ int status = 0;
+ B_ALGORITHM_OBJ *md5_ctx = NULL;
+ int w_bytes = 0;
+ u_int u_bytes = 0;
+ u_char work_area[NS_MD5RSA_MAX_SIZE];
+
+ if (mode & SIG_MODE_INIT) {
+ md5_ctx = (B_ALGORITHM_OBJ *) malloc(sizeof(B_ALGORITHM_OBJ));
+ if ((status = B_CreateAlgorithmObject(md5_ctx)))
+ return (-1);
+ if ((status = B_SetAlgorithmInfo(*md5_ctx, AI_MD5, NULL)))
+ return (-1);
+ }
+ else if (context)
+ md5_ctx = (B_ALGORITHM_OBJ *) *context;
+ if (md5_ctx == NULL)
+ return (-1);
+
+ w_bytes = dst_bsafe_md5digest(mode, md5_ctx,
+ data, len,work_area, sizeof(work_area));
+ if (w_bytes < 0 || (mode & SIG_MODE_FINAL)) {
+ B_DestroyAlgorithmObject(md5_ctx);
+ SAFE_FREE(md5_ctx);
+ if (w_bytes < 0)
+ return (w_bytes);
+ }
+
+ if (mode & SIG_MODE_FINAL) {
+ RSA_Key *key;
+ int ret = 0;
+ B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ) NULL_PTR;
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (-1);
+ key = (RSA_Key *) dkey->dk_KEY_struct;
+ if (key == NULL || key->rk_Private_Key == NULL)
+ return (-1);
+
+ if ((status = B_CreateAlgorithmObject(&rsaEncryptor)))
+ return (SIGN_FINAL_FAILURE);
+ if ((status = B_SetAlgorithmInfo(rsaEncryptor,
+ AI_PKCS_RSAPrivate,
+ NULL_PTR)))
+
+ ret = SIGN_FINAL_FAILURE;
+ if (ret == 0 &&
+ (status = B_EncryptInit(rsaEncryptor,
+ key->rk_Private_Key,
+ CHOOSER, NULL_SURRENDER)))
+ ret = SIGN_FINAL_FAILURE;
+ if (ret == 0 &&
+ (status = B_EncryptUpdate(rsaEncryptor, signature,
+ &u_bytes, sig_len, pkcs1,
+ sizeof(pkcs1), NULL_PTR,
+ NULL_SURRENDER)))
+ ret = SIGN_FINAL_FAILURE;
+ if (ret == 0 &&
+ (status = B_EncryptUpdate(rsaEncryptor, signature,
+ &u_bytes, sig_len, work_area,
+ w_bytes, NULL_PTR,
+ NULL_SURRENDER)))
+ ret = SIGN_FINAL_FAILURE;
+
+ if (ret == 0 &&
+ (status = B_EncryptFinal(rsaEncryptor, signature + u_bytes,
+ &sign_len, sig_len - u_bytes,
+ NULL_PTR, NULL_SURRENDER)))
+ ret = SIGN_FINAL_FAILURE;
+ B_DestroyAlgorithmObject(&rsaEncryptor);
+ if (ret != 0)
+ return (ret);
+
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) md5_ctx;
+ }
+ return (sign_len);
+}
+
+
+/*
+ * Dst_bsafe_verify
+ * Calls BSAFE verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey structure holds context for a verify done in multiple calls.
+ * context the context to use for this computation
+ * data data signed.
+ * len length in bytes of data.
+ * pub_key key to use for verify.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_bsafe_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ B_ALGORITHM_OBJ *md5_ctx = NULL;
+ u_char digest[DST_HASH_SIZE];
+ u_char work_area[DST_HASH_SIZE + sizeof(pkcs1)];
+ int status = 0, w_bytes = 0;
+ u_int u_bytes = 0;
+
+ if (mode & SIG_MODE_INIT) {
+ md5_ctx = (B_ALGORITHM_OBJ *) malloc(sizeof(B_ALGORITHM_OBJ));
+ if ((status = B_CreateAlgorithmObject(md5_ctx)))
+ return (-1);
+ if ((status = B_SetAlgorithmInfo(*md5_ctx, AI_MD5, NULL)))
+ return (-1);
+ }
+ else if (context)
+ md5_ctx = (B_ALGORITHM_OBJ *) *context;
+ if (md5_ctx == NULL)
+ return (-1);
+
+ w_bytes = dst_bsafe_md5digest(mode, md5_ctx, data, len,
+ digest, sizeof(digest));
+
+ if (w_bytes < 0 || (mode & SIG_MODE_FINAL)) {
+ B_DestroyAlgorithmObject(md5_ctx);
+ SAFE_FREE(md5_ctx);
+ if (w_bytes < 0)
+ return (-1);
+ }
+
+ if (mode & SIG_MODE_FINAL) {
+ RSA_Key *key;
+ int ret = 0;
+ B_ALGORITHM_OBJ rsaEncryptor = (B_ALGORITHM_OBJ) NULL_PTR;
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (-1);
+ key = (RSA_Key *) dkey->dk_KEY_struct;
+ if (key->rk_Public_Key == NULL)
+ return (-2);
+ if (rsaEncryptor == NULL_PTR) {
+ if ((status = B_CreateAlgorithmObject(&rsaEncryptor)))
+ ret = SIGN_FINAL_FAILURE;
+ if (ret == 0 &&
+ (status = B_SetAlgorithmInfo(rsaEncryptor,
+ AI_PKCS_RSAPublic,
+ NULL_PTR)))
+ ret = VERIFY_FINAL_FAILURE;
+ }
+ if (ret == 0 &&
+ (status = B_DecryptInit(rsaEncryptor, key->rk_Public_Key,
+ CHOOSER, NULL_SURRENDER)))
+ ret = VERIFY_FINAL_FAILURE;
+
+ if (ret == 0 &&
+ (status = B_DecryptUpdate(rsaEncryptor, work_area,
+ &u_bytes, 0,
+ (u_char *) signature, sig_len,
+ NULL_PTR, NULL_SURRENDER)))
+ ret = VERIFY_FINAL_FAILURE;
+
+ if (ret == 0 &&
+ (status = B_DecryptFinal(rsaEncryptor, work_area + u_bytes,
+ &u_bytes,
+ sizeof(work_area) - u_bytes,
+ NULL_PTR, NULL_SURRENDER)))
+ ret = VERIFY_FINAL_FAILURE;
+ B_DestroyAlgorithmObject(&rsaEncryptor);
+ /* skip PKCS#1 header in output from Decrypt function */
+ if (ret)
+ return (ret);
+ ret = memcmp(digest, &work_area[sizeof(pkcs1)], w_bytes);
+ if (ret == 0)
+ return(0);
+ else
+ return(VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) md5_ctx;
+ }
+ return (0);
+}
+
+
+/*
+ * dst_bsafe_to_dns_key
+ * Converts key from RSA to DNS distribution format
+ * This function gets in a pointer to the public key and a work area
+ * to write the key into.
+ * Parameters
+ * public KEY structure
+ * out_str buffer to write encoded key into
+ * out_len size of out_str
+ * Return
+ * N >= 0 length of encoded key
+ * n < 0 error
+ */
+
+static int
+dst_bsafe_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+ B_KEY_OBJ public;
+ A_RSA_KEY *pub = NULL;
+ u_char *op = out_str;
+ int n = 0;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= 0 || out_str == NULL)
+ return (-1);
+ public = (B_KEY_OBJ)((RSA_Key *) in_key->dk_KEY_struct)->rk_Public_Key;
+
+ n = B_GetKeyInfo((POINTER *) &pub, public, KI_RSAPublic);
+
+ if (out_len < pub->exponent.len) /* not enough space */
+ return (-1);
+ if (pub->exponent.len < 256) /* key exponent is <= 2040 bits */
+ *op++ = (u_int8_t) pub->exponent.len;
+ else { /* key exponent is > 2040 bits */
+ u_int16_t e = (u_int16_t) pub->exponent.len;
+ *op++ = 0; /* 3 byte lenght field */
+ dst_s_put_int16(op, e);
+ op += sizeof(e);
+ n = 2;
+ }
+ n += pub->exponent.len;
+ memcpy(op, pub->exponent.data, n);
+ op += n;
+ n++;
+
+ if ((out_len - n) > pub->modulus.len) {
+ /*copy exponent */
+ memcpy(op, pub->modulus.data, pub->modulus.len);
+ n += pub->modulus.len;
+ }
+ else
+ n = -1;
+ return (n);
+}
+
+
+/*
+ * dst_bsafe_from_dns_key
+ * Converts from a DNS KEY RR format to an RSA KEY.
+ * Parameters
+ * len Length in bytes of DNS key
+ * key DNS key
+ * name Key name
+ * s_key DST structure that will point to the RSA key this routine
+ * will build.
+ * Return
+ * 0 The input key, s_key or name was null.
+ * 1 Success
+ */
+static int
+dst_bsafe_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+ int bytes;
+ const u_char *key_ptr;
+ RSA_Key *r_key;
+ A_RSA_KEY *public;
+
+ if (s_key == NULL || len < 0 || key == NULL)
+ return (0);
+
+ r_key = (RSA_Key *) s_key->dk_KEY_struct;
+ if (r_key != NULL) /* do not reuse */
+ s_key->dk_func->destroy(r_key);
+
+ if (len == 0)
+ return (1);
+
+ if ((r_key = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+ EREPORT(("dst_bsafe_from_dns_key(): Memory allocation error 1"));
+ return (0);
+ }
+ memset(r_key, 0, sizeof(RSA_Key));
+ s_key->dk_KEY_struct = (void *) r_key;
+ r_key->rk_signer = strdup(s_key->dk_key_name);
+
+ if (B_CreateKeyObject(&r_key->rk_Public_Key) != 0) {
+ EREPORT(("dst_bsafe_from_dns_key(): Memory allocation error 3"));
+ s_key->dk_func->destroy(r_key);
+ return (0);
+ }
+ key_ptr = key;
+ bytes = (int) *key_ptr++; /* length of exponent in bytes */
+ if (bytes == 0) { /* special case for long exponents */
+ bytes = (int) dst_s_get_int16(key_ptr);
+ key_ptr += sizeof(u_int16_t);
+ }
+ if (bytes > MAX_RSA_MODULUS_LEN) {
+ dst_bsafe_free_key_structure(r_key);
+ return (-1);
+ }
+ if ((public = (A_RSA_KEY *) malloc(sizeof(A_RSA_KEY))) == NULL)
+ return (0);
+ memset(public, 0, sizeof(*public));
+ public->exponent.len = bytes;
+ if ((public->exponent.data = (u_char *) malloc(bytes)) == NULL)
+ return (0);
+ memcpy(public->exponent.data, key_ptr, bytes);
+
+ key_ptr += bytes; /* beginning of modulus */
+ bytes = len - bytes - 1; /* length of modulus */
+
+ if (bytes > MAX_RSA_MODULUS_LEN) {
+ dst_bsafe_free_key_structure(r_key);
+ return (-1);
+ }
+ public->modulus.len = bytes;
+ if ((public->modulus.data = (u_char *) malloc(bytes)) == NULL)
+ return (0);
+ memcpy(public->modulus.data, key_ptr, bytes);
+
+ B_SetKeyInfo(r_key->rk_Public_Key, KI_RSAPublic, (POINTER) public);
+
+ s_key->dk_id = (u_int16_t)
+ dst_s_get_int16(&public->modulus.data[public->modulus.len - 3]);
+ s_key->dk_key_size = dst_bsafe_key_size(r_key);
+ SAFE_FREE(public->modulus.data);
+ SAFE_FREE(public->exponent.data);
+ SAFE_FREE(public);
+ return (1);
+}
+
+
+/*
+ * dst_bsafe_key_to_file_format
+ * Encodes an RSA Key into the portable file format.
+ * Parameters
+ * rkey RSA KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input rkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_bsafe_key_to_file_format(const DST_KEY *key, char *buff,
+ const int buff_len)
+{
+ char *bp;
+ int len, b_len;
+ B_KEY_OBJ rkey;
+ A_PKCS_RSA_PRIVATE_KEY *private = NULL;
+
+ if (key == NULL || key->dk_KEY_struct == NULL) /* no output */
+ return (0);
+ if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+ return (-1); /* no OR not enough space in output area */
+
+ rkey = (B_KEY_OBJ)((RSA_Key *) key->dk_KEY_struct)->rk_Private_Key;
+
+ B_GetKeyInfo((POINTER *) &private, rkey, KI_PKCS_RSAPrivate);
+
+ memset(buff, 0, buff_len); /* just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_RSA, "RSA");
+
+ bp = strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Modulus: ",
+ private->modulus.data,
+ private->modulus.len)) <= 0)
+ return (-1);
+
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PublicExponent: ",
+ private->publicExponent.data,
+ private->publicExponent.len)) <= 0)
+ return (-2);
+
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PrivateExponent: ",
+ private->privateExponent.data,
+ private->privateExponent.len)) <= 0)
+ return (-3);
+ bp += len;
+ b_len -= len;
+
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime1: ",
+ private->prime[0].data,
+ private->prime[0].len)) < 0)
+ return (-4);
+ bp += len;
+ b_len -= len;
+
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime2: ",
+ private->prime[1].data,
+ private->prime[1].len)) < 0)
+ return (-5);
+ bp += len;
+ b_len -= len;
+
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent1: ",
+ private->primeExponent[0].data,
+ private->primeExponent[0].len)) < 0)
+ return (-6);
+ bp += len;
+ b_len -= len;
+
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent2: ",
+ private->primeExponent[1].data,
+ private->primeExponent[1].len)) < 0)
+ return (-7);
+ bp += len;
+ b_len -= len;
+
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Coefficient: ",
+ private->coefficient.data,
+ private->coefficient.len)) < 0)
+ return (-8);
+ bp += len;
+ b_len -= len;
+ return (buff_len - b_len);
+}
+
+
+/*
+ * dst_bsafe_key_from_file_format
+ * Converts contents of a private key file into a private RSA key.
+ * Parameters
+ * RSA_Key structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_bsafe_key_from_file_format(DST_KEY *d_key, const char *buff,
+ const int buff_len)
+{
+ int status;
+ char s[RAW_KEY_SIZE];
+ int len, s_len = sizeof(s);
+ int tag = -1;
+ const char *p = buff;
+ RSA_Key *b_key;
+ A_RSA_KEY *public;
+ A_PKCS_RSA_PRIVATE_KEY *private;
+
+ if (d_key == NULL || buff == NULL || buff_len <= 0)
+ return (-1);
+
+ b_key = (RSA_Key *) malloc(sizeof(RSA_Key));
+ public = (A_RSA_KEY *) malloc(sizeof(A_RSA_KEY));
+ private = (A_PKCS_RSA_PRIVATE_KEY *)
+ malloc(sizeof(A_PKCS_RSA_PRIVATE_KEY));
+ if (b_key == NULL || private == NULL || public == NULL) {
+ SAFE_FREE(b_key);
+ SAFE_FREE(public);
+ SAFE_FREE(private);
+ return (-2);
+ }
+ memset(b_key, 0, sizeof(*b_key));
+ memset(public, 0, sizeof(A_RSA_KEY));
+ memset(private, 0, sizeof(A_PKCS_RSA_PRIVATE_KEY));
+ d_key->dk_KEY_struct = (void *) b_key;
+ if (!dst_s_verify_str(&p, "Modulus: "))
+ return (-3);
+ memset(s, 0, s_len);
+ if ((len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)) == 0)
+ return (-4);
+
+ private->modulus.len = len;
+ if ((private->modulus.data = malloc(len)) == NULL)
+ return (-5);
+ memcpy(private->modulus.data, s + s_len - len, len);
+
+ while (*(++p) && p < (const char *) &buff[buff_len]) {
+ if (dst_s_verify_str(&p, "PublicExponent: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)))
+ return (-5);
+ private->publicExponent.len = len;
+ if ((private->publicExponent.data = malloc(len))
+ == NULL)
+ return (-6);
+ memcpy(private->publicExponent.data,
+ s + s_len - len, len);
+ } else if (dst_s_verify_str(&p, "PrivateExponent: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s, s_len)))
+ return (-6);
+ private->privateExponent.len = len;
+ if ((private->privateExponent.data = malloc(len))
+ == NULL)
+ return (-7);
+ memcpy(private->privateExponent.data, s + s_len - len,
+ len);
+ } else if (dst_s_verify_str(&p, "Prime1: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+ MAX_RSA_PRIME_LEN)))
+ return (-7);
+ private->prime[0].len = len;
+ if ((private->prime[0].data = malloc(len)) == NULL)
+ return (-8);
+ memcpy(private->prime[0].data,
+ s + MAX_RSA_PRIME_LEN - len, len);
+ } else if (dst_s_verify_str(&p, "Prime2: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+ MAX_RSA_PRIME_LEN)))
+ return (-8);
+ private->prime[1].len = len;
+ if ((private->prime[1].data = malloc(len)) == NULL)
+ return (-9);
+ memcpy(private->prime[1].data,
+ s + MAX_RSA_PRIME_LEN - len, len);
+ } else if (dst_s_verify_str(&p, "Exponent1: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+ MAX_RSA_PRIME_LEN)))
+ return (-9);
+ private->primeExponent[0].len = len;
+ if ((private->primeExponent[0].data = malloc(len))
+ == NULL)
+ return (-10);
+ memcpy(private->primeExponent[0].data,
+ s + MAX_RSA_PRIME_LEN - len, len);
+ } else if (dst_s_verify_str(&p, "Exponent2: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+ MAX_RSA_PRIME_LEN)))
+ return (-10);
+ private->primeExponent[1].len = len;
+ if ((private->primeExponent[1].data = malloc(len))
+ == NULL)
+ return (-11);
+ memcpy(private->primeExponent[1].data,
+ s + MAX_RSA_PRIME_LEN - len, len);
+ } else if (dst_s_verify_str(&p, "Coefficient: ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, (u_char *)s,
+ MAX_RSA_PRIME_LEN)))
+ return (-11);
+ private->coefficient.len = len;
+ if ((private->coefficient.data = malloc(len)) == NULL)
+ return (-12);
+ memcpy(private->coefficient.data,
+ s + MAX_RSA_PRIME_LEN - len, len);
+ } else {
+ EREPORT(("Decode_RSAKey(): Bad keyword %s\n", p));
+ return (-12);
+ }
+ } /* while p */
+
+ public->modulus.len = private->modulus.len;
+ if ((public->modulus.data = (u_char *) malloc(public->modulus.len)) ==
+ NULL)
+ return (-13);
+ memcpy(public->modulus.data, private->modulus.data,
+ private->modulus.len);
+
+ public->exponent.len = private->publicExponent.len;
+ if ((public->exponent.data = (u_char *) malloc(public->exponent.len))
+ == NULL)
+ return (-14);
+ memcpy(public->exponent.data, private->publicExponent.data,
+ private->publicExponent.len);
+
+ status = B_CreateKeyObject(&(b_key->rk_Public_Key));
+ if (status)
+ return (-1);
+ status = B_SetKeyInfo(b_key->rk_Public_Key, KI_RSAPublic,
+ (POINTER) public);
+ if (status)
+ return (-1);
+
+ status = B_CreateKeyObject(&b_key->rk_Private_Key);
+ if (status)
+ return (-1);
+ status = B_SetKeyInfo(b_key->rk_Private_Key, KI_PKCS_RSAPrivate,
+ (POINTER) private);
+ if (status)
+ return (-1);
+
+ tag = (int)(u_int16_t)
+ dst_s_get_int16(&public->modulus.data[public->modulus.len - 3]);
+ d_key->dk_key_size = dst_bsafe_key_size(b_key);
+
+ SAFE_FREE(private->modulus.data);
+ SAFE_FREE(private->publicExponent.data);
+ SAFE_FREE(private->privateExponent.data);
+ SAFE_FREE(private->prime[0].data);
+ SAFE_FREE(private->prime[1].data);
+ SAFE_FREE(private->primeExponent[0].data);
+ SAFE_FREE(private->primeExponent[1].data);
+ SAFE_FREE(private->coefficient.data);
+ SAFE_FREE(private); /* is this the right thing to do ??? XXXX */
+ SAFE_FREE(public->modulus.data);
+ SAFE_FREE(public->exponent.data);
+ SAFE_FREE(public);
+ return (tag);
+}
+
+
+/*
+ * dst_bsafe_free_key_structure
+ * Frees all dynamicly allocated structures in RSA_Key.
+ */
+
+static void *
+dst_bsafe_free_key_structure(void *key)
+{
+ RSA_Key *r_key = (RSA_Key *) key;
+ if (r_key != NULL) {
+ if (r_key->rk_Private_Key)
+ B_DestroyKeyObject(&r_key->rk_Private_Key);
+ if (r_key->rk_Public_Key)
+ B_DestroyKeyObject(&r_key->rk_Public_Key);
+ SAFE_FREE2(r_key->rk_signer, strlen(r_key->rk_signer));
+ SAFE_FREE(r_key);
+ }
+ return (NULL);
+}
+
+
+/*
+ * dst_bsafe_generate_keypair
+ * Generates unique keys that are hard to predict.
+ * Parameters
+ * key generic Key structure
+ * exp the public exponent
+ * Return
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_bsafe_generate_keypair(DST_KEY *key, int exp)
+{
+ int i, status;
+ B_KEY_OBJ private;
+ B_KEY_OBJ public;
+ B_ALGORITHM_OBJ keypairGenerator;
+ B_ALGORITHM_OBJ randomAlgorithm;
+ A_RSA_KEY_GEN_PARAMS keygenParams;
+ char exponent[4];
+ int exponent_len;
+ RSA_Key *rsa;
+ POINTER randomSeed = NULL_PTR;
+ int randomSeedLen;
+ A_RSA_KEY *pk_access = NULL;
+
+ if (key == NULL || key->dk_alg != KEY_RSA)
+ return (0);
+
+ if ((rsa = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+ EREPORT(("dst_bsafe_generate_keypair: Memory allocation error 3"));
+ return (0);
+ }
+ memset(rsa, 0, sizeof(*rsa));
+
+ if ((status = B_CreateAlgorithmObject(&keypairGenerator)) != 0)
+ return (0);
+
+ keygenParams.modulusBits = key->dk_key_size;
+
+ /* exp = 0 or 1 are special (mean 3 or F4) */
+ if (exp == 0)
+ exp = 3;
+ else if (exp == 1)
+ exp = 65537;
+
+ /* Now encode the exponent and its length */
+ if (exp < 256) {
+ exponent_len = 1;
+ exponent[0] = exp;
+ } else if (exp < (1 << 16)) {
+ exponent_len = 2;
+ exponent[0] = exp >> 8;
+ exponent[1] = exp;
+ } else if (exp < (1 << 24)) {
+ exponent_len = 3;
+ exponent[0] = exp >> 16;
+ exponent[1] = exp >> 8;
+ exponent[2] = exp;
+ } else {
+ exponent_len = 4;
+ exponent[0] = exp >> 24;
+ exponent[1] = exp >> 16;
+ exponent[2] = exp >> 8;
+ exponent[3] = exp;
+ }
+
+ if ((keygenParams.publicExponent.data = (u_char *) malloc(exponent_len))
+ == NULL)
+ return (0);
+ memcpy(keygenParams.publicExponent.data, exponent, exponent_len);
+ keygenParams.publicExponent.len = exponent_len;
+ if ((status = B_SetAlgorithmInfo
+ (keypairGenerator, AI_RSAKeyGen, (POINTER) &keygenParams)) != 0)
+ return (0);
+
+ if ((status = B_GenerateInit(keypairGenerator, CHOOSER,
+ NULL_SURRENDER)) != 0)
+ return (0);
+
+ if ((status = B_CreateKeyObject(&public)) != 0)
+ return (0);
+
+ if ((status = B_CreateKeyObject(&private)) != 0)
+ return (0);
+
+ if ((status = B_CreateAlgorithmObject(&randomAlgorithm)) != 0)
+ return (0);
+
+ if ((status = B_SetAlgorithmInfo(randomAlgorithm, AI_MD5Random,
+ NULL_PTR))
+ != 0)
+ return (0);
+
+ if ((status = B_RandomInit(randomAlgorithm, CHOOSER,
+ NULL_SURRENDER)) != 0)
+ return (0);
+
+ randomSeedLen = 256;
+ if ((randomSeed = malloc(randomSeedLen)) == NULL)
+ return (0);
+ if ((status = (randomSeed == NULL_PTR)) != 0)
+ return (0);
+
+ /* gets random seed from /dev/random if present, generates random
+ * values if it is not present.
+ * first fill the buffer with semi random data
+ * then fill as much as possible with good random data
+ */
+ i = dst_random(DST_RAND_SEMI, randomSeedLen, randomSeed);
+ i += dst_random(DST_RAND_KEY, randomSeedLen, randomSeed);
+
+ if (i <= randomSeedLen) {
+ SAFE_FREE(rsa);
+ return(0);
+ }
+ if ((status = B_RandomUpdate(randomAlgorithm, randomSeed,
+ randomSeedLen, NULL_SURRENDER)) != 0) {
+ SAFE_FREE(rsa);
+ return (0);
+ }
+ SAFE_FREE2(randomSeed, randomSeedLen);
+ if ((status = B_GenerateKeypair(keypairGenerator, public, private,
+ randomAlgorithm, NULL_SURRENDER))
+ != 0) {
+ SAFE_FREE(rsa);
+ return (0);
+ }
+ rsa->rk_signer = strdup(key->dk_key_name);
+ rsa->rk_Private_Key = private;
+ rsa->rk_Public_Key = public;
+ key->dk_KEY_struct = (void *) rsa;
+
+ /* fill in the footprint on generate key */
+ B_GetKeyInfo((POINTER *) &pk_access, public, KI_RSAPublic);
+ key->dk_id = (u_int16_t)
+ dst_s_get_int16(&pk_access->modulus.data[pk_access->modulus.len - 3]);
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_bsafe_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_s_bsafe_itemcmp(ITEM i1, ITEM i2)
+{
+ if (i1.len != i2.len || memcmp (i1.data, i2.data, i1.len))
+ return (1);
+ else
+ return (0);
+}
+
+static int
+dst_bsafe_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ int status, s1 = 0, s2 = 0;
+ RSA_Key *rkey1 = (RSA_Key *) key1->dk_KEY_struct;
+ RSA_Key *rkey2 = (RSA_Key *) key2->dk_KEY_struct;
+ A_RSA_KEY *public1 = NULL, *public2 = NULL;
+ A_PKCS_RSA_PRIVATE_KEY *p1 = NULL, *p2 = NULL;
+
+ if (rkey1 == NULL && rkey2 == NULL)
+ return(0);
+ else if (rkey1 == NULL)
+ return (1);
+ else if (rkey2 == NULL)
+ return (2);
+
+ if (rkey1->rk_Public_Key)
+ B_GetKeyInfo((POINTER *) &public1, rkey1->rk_Public_Key,
+ KI_RSAPublic);
+ if (rkey2->rk_Public_Key)
+ B_GetKeyInfo((POINTER *) &public2, rkey2->rk_Public_Key,
+ KI_RSAPublic);
+ if (public1 == NULL && public2 == NULL)
+ return (0);
+ else if (public1 == NULL || public2 == NULL)
+ return (1);
+
+ status = dst_s_bsafe_itemcmp(public1->modulus, public2->modulus) ||
+ dst_s_bsafe_itemcmp(public1->exponent, public2->exponent);
+
+ if (status)
+ return (status);
+
+ if (rkey1->rk_Private_Key == NULL || rkey2->rk_Private_Key == NULL)
+ /* if neither or only one is private key consider identical */
+ return (status);
+ if (rkey1->rk_Private_Key)
+ s1 = B_GetKeyInfo((POINTER *) &p1, rkey1->rk_Private_Key,
+ KI_PKCS_RSAPrivate);
+ if (rkey2->rk_Private_Key)
+ s2 = B_GetKeyInfo((POINTER *) &p2, rkey2->rk_Private_Key,
+ KI_PKCS_RSAPrivate);
+ if (p1 == NULL || p2 == NULL)
+ return (0);
+
+ status = dst_s_bsafe_itemcmp(p1->modulus, p2->modulus) ||
+ dst_s_bsafe_itemcmp (p1->publicExponent,
+ p2->publicExponent) ||
+ dst_s_bsafe_itemcmp (p1->privateExponent,
+ p2->privateExponent) ||
+ dst_s_bsafe_itemcmp (p1->prime[0], p2->prime[0]) ||
+ dst_s_bsafe_itemcmp (p1->prime[1], p2->prime[1]) ||
+ dst_s_bsafe_itemcmp (p1->primeExponent[0],
+ p2->primeExponent[0])||
+ dst_s_bsafe_itemcmp (p1->primeExponent[1],
+ p2->primeExponent[1])||
+ dst_s_bsafe_itemcmp (p1->coefficient, p2->coefficient);
+ return (status);
+}
+
+
+/*
+ * dst_bsafe_key_size()
+ * Function to calculate how the size of the key in bits
+ */
+static int
+dst_bsafe_key_size(RSA_Key *r_key)
+{
+ int size;
+ A_PKCS_RSA_PRIVATE_KEY *private = NULL;
+
+ if (r_key == NULL)
+ return (-1);
+ if (r_key->rk_Private_Key)
+ B_GetKeyInfo((POINTER *) &private, r_key->rk_Private_Key,
+ KI_PKCS_RSAPrivate);
+ else if (r_key->rk_Public_Key)
+ B_GetKeyInfo((POINTER *) &private, r_key->rk_Public_Key,
+ KI_RSAPublic);
+ size = dst_s_calculate_bits(private->modulus.data,
+ private->modulus.len * 8);
+ return (size);
+}
+
+/*
+ * dst_bsafe_md5digest(): function to digest data using MD5 digest function
+ * if needed
+ */
+static int
+dst_bsafe_md5digest(const int mode, B_ALGORITHM_OBJ *digest_obj,
+ const u_char *data, const int len,
+ u_char *digest, const int digest_len)
+{
+ int status = 0;
+ u_int work_size = 0;
+
+ if (digest_obj == NULL || *digest_obj == NULL) {
+ printf("NO digest obj\n");
+ exit(-33);
+ }
+
+ if ((mode & SIG_MODE_INIT) &&
+ (status = B_DigestInit(*digest_obj, (B_KEY_OBJ) NULL,
+ CHOOSER, NULL_SURRENDER)))
+ return (SIGN_INIT_FAILURE);
+
+ if ((mode & SIG_MODE_UPDATE) && data && (len > 0) &&
+ (status = B_DigestUpdate(*digest_obj, (u_char *) data, len,
+ NULL_SURRENDER)))
+ return (SIGN_UPDATE_FAILURE);
+
+ if (mode & SIG_MODE_FINAL) {
+ if (digest == NULL ||
+ (status = B_DigestFinal(*digest_obj, digest, &work_size,
+ digest_len, NULL_SURRENDER)))
+ return (SIGN_FINAL_FAILURE);
+ return (work_size);
+ }
+ return (0);
+}
+
+/*
+ * just use the standard memory functions for bsafe
+ */
+void
+T_free(POINTER block)
+{
+ free(block);
+}
+
+POINTER
+T_malloc(unsigned int len)
+{
+ return (malloc(len));
+}
+
+int
+T_memcmp(POINTER firstBlock, POINTER secondBlock, unsigned int len)
+{
+ return (memcmp(firstBlock, secondBlock, len));
+}
+
+void
+T_memcpy(POINTER output, POINTER input, unsigned int len)
+{
+ memcpy(output, input, len);
+}
+
+void
+T_memmove(POINTER output, POINTER input, unsigned int len)
+{
+ memmove(output, input, len);
+}
+
+void
+T_memset(POINTER output, int value, unsigned int len)
+{
+ memset(output, value, len);
+}
+
+POINTER
+T_realloc(POINTER block, unsigned int len)
+{
+ return (realloc(block, len));
+}
+
+#else /* BSAFE NOT available */
+int
+dst_bsafe_init()
+{
+ return (0);
+}
+#endif /* BSAFE */
diff --git a/contrib/bind/lib/dst/cylink_link.c b/contrib/bind/lib/dst/cylink_link.c
new file mode 100644
index 0000000..c7cb276
--- /dev/null
+++ b/contrib/bind/lib/dst/cylink_link.c
@@ -0,0 +1,676 @@
+#ifdef CYLINK_DSS
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/cylink_link.c,v 1.7 1999/10/13 16:39:22 vixie Exp $";
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+/*
+ * This file contains two components
+ * 1. Interface to the CYLINK library to allow compilation of Bind
+ * with TIS/DNSSEC when CYLINK is not available
+ * all calls to CYLINK are contained inside this file.
+ * 2. The glue to connvert DSA KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "dst_internal.h"
+#include <toolkit.h>
+
+#include "port_after.h"
+
+typedef struct cylinkkey {
+ char *dk_signer;
+ uchar *dk_p;
+ uchar *dk_q;
+ uchar *dk_g;
+ uchar *dk_x;
+ uchar *dk_y;
+ ushort dk_p_bytes;
+} DSA_Key;
+
+#define NULL_PRIV_KEY(k)(k == NULL || k->dk_p == NULL || k->dk_q == NULL || \
+ k->dk_g == NULL || k->dk_x == NULL)
+#define NULL_PUB_KEY(k)(k == NULL || k->dk_p == NULL || k->dk_q == NULL || \
+ k->dk_g == NULL || k->dk_y == NULL)
+
+static int dst_cylink_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len);
+
+static int dst_cylink_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len);
+
+static int dst_cylink_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len);
+static int dst_cylink_from_dns_key(DST_KEY *s_key, const u_char *key,
+ const int len);
+static int dst_cylink_key_to_file_format(const DST_KEY *key, char *buff,
+ const int buff_len);
+static int dst_cylink_key_from_file_format(DST_KEY *d_key,
+ const char *buff,
+ const int buff_len);
+static void *dst_cylink_free_key_structure(void *key);
+
+static int dst_cylink_generate_keypair(DST_KEY *key, int exp);
+static int dst_cylink_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+
+static void *memcpyend(void *dest, const void *src, size_t n, size_t size);
+
+/*
+ * dst_cylink_init() Function to answer set up function pointers for
+ * CYLINK related functions
+ */
+int
+dst_cylink_init()
+{
+ if (dst_t_func[KEY_DSA] != NULL)
+ return (1);
+ dst_t_func[KEY_DSA] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_DSA] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_DSA], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_DSA]->sign = dst_cylink_sign;
+ dst_t_func[KEY_DSA]->verify = dst_cylink_verify;
+ dst_t_func[KEY_DSA]->compare = dst_cylink_compare_keys;
+ dst_t_func[KEY_DSA]->generate = dst_cylink_generate_keypair;
+ dst_t_func[KEY_DSA]->destroy = dst_cylink_free_key_structure;
+ dst_t_func[KEY_DSA]->from_dns_key = dst_cylink_from_dns_key;
+ dst_t_func[KEY_DSA]->to_dns_key = dst_cylink_to_dns_key;
+ dst_t_func[KEY_DSA]->from_file_fmt = dst_cylink_key_from_file_format;
+ dst_t_func[KEY_DSA]->to_file_fmt = dst_cylink_key_to_file_format;
+ SetDataOrder(1);
+ return (1);
+}
+
+/*
+ * dst_cylink_sign
+ * Call CYLINK signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * algobj structure holds context for a sign done in multiple calls.
+ * context the context to use for this computation
+ * data data to be signed.
+ * len length in bytes of data.
+ * priv_key key to use for signing.
+ * signature location to store signature.
+ * sig_len size in bytes of signature field.
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * N is 41 for DNS
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_cylink_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ int sign_len = 0;
+ int status;
+ SHA_context *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (SHA_context *) malloc(sizeof(SHA_context));
+ else if (context)
+ ctx = (SHA_context *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ SHAInit(ctx);
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+ status = SHAUpdate(ctx, (u_char *) data, len);
+ if (status != SUCCESS)
+ return (SIGN_UPDATE_FAILURE);
+ }
+ if (mode & SIG_MODE_FINAL) {
+ DSA_Key *key;
+ uchar digest[SHA_LENGTH];
+ uchar rand[SHA_LENGTH];
+ uchar r[SHA_LENGTH], s[SHA_LENGTH];
+
+ if (signature == NULL || sig_len < 2 * SHA_LENGTH)
+ return (SIGN_FINAL_FAILURE);
+ if ((status = SHAFinal(ctx, digest)) != SUCCESS)
+ return (SIGN_FINAL_FAILURE);
+ SAFE_FREE(ctx);
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (-1);
+ key = (DSA_Key *) dkey->dk_KEY_struct;
+ if (NULL_PRIV_KEY(key))
+ return (-2);
+ dst_random(DST_RAND_STD, sizeof(rand), rand);
+ status = GenDSSSignature(key->dk_p_bytes, key->dk_p,
+ key->dk_q, key->dk_g, key->dk_x,
+ rand, r, s, digest);
+ if (status != SUCCESS)
+ return (SIGN_FINAL_FAILURE);
+ *signature = (dkey->dk_key_size - 512)/64;
+ sign_len = 1;
+ memcpy(signature + sign_len, r, SHA_LENGTH);
+ sign_len += SHA_LENGTH;
+ memcpy(signature + sign_len, s, SHA_LENGTH);
+ sign_len += SHA_LENGTH;
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/*
+ * Dst_cylink_verify
+ * Calls CYLINK verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey structure holds context for a verify done in multiple calls.
+ * context algorithm specific context for the current context processing
+ * data data signed.
+ * len length in bytes of data.
+ * pub_key key to use for verify.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_cylink_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ int status;
+ SHA_context *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (SHA_context *) malloc(sizeof(SHA_context));
+ else if (context)
+ ctx = (SHA_context *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ SHAInit(ctx);
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+ status = SHAUpdate(ctx, (u_char *) data, len);
+ if (status != SUCCESS)
+ return (VERIFY_UPDATE_FAILURE);
+ }
+ if (mode & SIG_MODE_FINAL) {
+ DSA_Key *key;
+ uchar digest[SHA_LENGTH];
+ uchar r[SHA_LENGTH], s[SHA_LENGTH];
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (-1);
+ key = (DSA_Key *) dkey->dk_KEY_struct;
+ if (NULL_PUB_KEY(key))
+ return (-2);
+ if (signature == NULL || sig_len != (2 * SHA_LENGTH +1))
+ return (SIGN_FINAL_FAILURE);
+ status = SHAFinal(ctx, digest);
+ SAFE_FREE(ctx);
+ if (status != SUCCESS)
+ return (SIGN_FINAL_FAILURE);
+ if (((int)*signature) != ((key->dk_p_bytes -64)/8))
+ return(VERIFY_FINAL_FAILURE);
+
+ memcpy(r, signature +1, SHA_LENGTH);
+ memcpy(s, signature + SHA_LENGTH +1, SHA_LENGTH);
+ status = VerDSSSignature(key->dk_p_bytes, key->dk_p,
+ key->dk_q, key->dk_g, key->dk_y,
+ r, s, digest);
+ if (status != SUCCESS)
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (0);
+}
+
+
+/*
+ * dst_cylink_to_dns_key
+ * Converts key from DSA to DNS distribution format
+ * This function gets in a pointer to the public key and a work area
+ * to write the key into.
+ * Parameters
+ * public KEY structure
+ * out_str buffer to write encoded key into
+ * out_len size of out_str
+ * Return
+ * N >= 0 length of encoded key
+ * n < 0 error
+ */
+
+static int
+dst_cylink_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+ u_char *op = out_str;
+ int t;
+ DSA_Key *key;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= 0 || out_str == NULL)
+ return (-1);
+ key = (DSA_Key *) in_key->dk_KEY_struct;
+
+ t = (key->dk_p_bytes - 64) / 8;
+
+ *op++ = t;
+ memcpy(op, key->dk_q, SHA_LENGTH);
+ op += SHA_LENGTH;
+ memcpy(op, key->dk_p, key->dk_p_bytes);
+ op += key->dk_p_bytes;
+ memcpy(op, key->dk_g, key->dk_p_bytes);
+ op += key->dk_p_bytes;
+ memcpy(op, key->dk_y, key->dk_p_bytes);
+ op += key->dk_p_bytes;
+
+ return (op - out_str);
+}
+
+
+/*
+ * dst_cylink_from_dns_key
+ * Converts from a DNS KEY RR format to an RSA KEY.
+ * Parameters
+ * len Length in bytes of DNS key
+ * key DNS key
+ * name Key name
+ * s_key DST structure that will point to the RSA key this routine
+ * will build.
+ * Return
+ * 0 The input key, s_key or name was null.
+ * 1 Success
+ */
+static int
+dst_cylink_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+ int t;
+ const u_char *key_ptr = key;
+ DSA_Key *d_key;
+
+ if (s_key == NULL || len < 0 || key == NULL)
+ return (0);
+
+ if (len == 0) /* process null key */
+ return (1);
+
+ if (key_ptr == NULL)
+ return (0);
+ t = (int) *key_ptr++; /* length of exponent in bytes */
+
+ if ((3 * (t * 8 + 64) + SHA_LENGTH + 1) != len)
+ return (0);
+
+ if ((d_key = (DSA_Key *) malloc(sizeof(DSA_Key))) == NULL) {
+ EREPORT(("dst_cylink_from_dns_key(): Memory allocation error 1"));
+ return (0);
+ }
+ memset(d_key, 0, sizeof(DSA_Key));
+ s_key->dk_KEY_struct = (void *) d_key;
+ d_key->dk_signer = strdup(s_key->dk_key_name);
+ d_key->dk_p_bytes = 64 + 8 * t;
+
+ if ((d_key->dk_q = (uchar *) malloc(SHA_LENGTH)) == NULL)
+ return (0);
+ memcpy(d_key->dk_q, key_ptr, SHA_LENGTH);
+ key_ptr += SHA_LENGTH;
+
+ if ((d_key->dk_p = (uchar *) malloc(d_key->dk_p_bytes)) == NULL)
+ return (0);
+ memcpy(d_key->dk_p, key_ptr, d_key->dk_p_bytes);
+ key_ptr += d_key->dk_p_bytes;
+
+ if ((d_key->dk_g = (uchar *) malloc(d_key->dk_p_bytes)) == NULL)
+ return (0);
+ memcpy(d_key->dk_g, key_ptr, d_key->dk_p_bytes);
+ key_ptr += d_key->dk_p_bytes;
+
+ if ((d_key->dk_y = (uchar *) malloc(d_key->dk_p_bytes)) == NULL)
+ return (0);
+ memcpy(d_key->dk_y, key_ptr, d_key->dk_p_bytes);
+ key_ptr += d_key->dk_p_bytes;
+
+ s_key->dk_id = dst_s_id_calc(key, len);
+ s_key->dk_key_size = d_key->dk_p_bytes * 8;
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_cylink_key_to_file_format
+ * Encodes an DSA Key into the portable file format.
+ * Parameters
+ * key DSA KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input rkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_cylink_key_to_file_format(const DST_KEY *key, char *buff,
+ const int buff_len)
+{
+ char *bp;
+ int len, b_len;
+ DSA_Key *dkey;
+ u_char num[256]; /* More than long enough for DSA keys */
+
+ if (key == NULL || key->dk_KEY_struct == NULL) /* no output */
+ return (0);
+ if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+ return (-1); /* no OR not enough space in output area */
+
+ dkey = (DSA_Key *) key->dk_KEY_struct;
+
+ memset(buff, 0, buff_len); /* just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_DSA, "DSA");
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->dk_p, dkey->dk_p_bytes);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime(p): ",
+ num, dkey->dk_p_bytes)) <= 0)
+ return (-1);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->dk_q, dkey->dk_p_bytes);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Subprime(q): ",
+ num, SHA_LENGTH)) <= 0)
+ return (-2);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->dk_g, dkey->dk_p_bytes);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Base(g): ",
+ num, dkey->dk_p_bytes)) <= 0)
+ return (-3);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->dk_x, dkey->dk_p_bytes);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Private_value(x): ",
+ num, SHA_LENGTH)) <= 0)
+ return (-4);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->dk_y, dkey->dk_p_bytes);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Public_value(y): ",
+ num, dkey->dk_p_bytes)) <= 0)
+ return (-4);
+
+ bp += len;
+ b_len -= len;
+ return (buff_len - b_len);
+}
+
+
+/**************************************************************************
+ * dst_cylink_key_from_file_format
+ * Converts contents of a private key file into a private DSA key.
+ * Parameters
+ * DSA_Key structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_cylink_key_from_file_format(DST_KEY *d_key, const char *buff,
+ const int buff_len)
+{
+ u_char s[DSS_LENGTH_MAX];
+ u_char dns[1024];
+ int len, s_len = sizeof(s);
+ int foot = -1, dnslen;
+ const char *p = buff;
+ DSA_Key *dsa_key;
+
+ if (d_key == NULL || buff == NULL || buff_len <= 0)
+ return (-1);
+
+ dsa_key = (DSA_Key *) malloc(sizeof(DSA_Key));
+ if (dsa_key == NULL) {
+ return (-2);
+ }
+ memset(dsa_key, 0, sizeof(*dsa_key));
+ d_key->dk_KEY_struct = (void *) dsa_key;
+
+ if (!dst_s_verify_str(&p, "Prime(p): "))
+ return (-3);
+ memset(s, 0, s_len);
+ if ((len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)) == 0)
+ return (-4);
+ dsa_key->dk_p_bytes = len;
+ if ((dsa_key->dk_p = malloc(len)) == NULL)
+ return (-5);
+ memcpy(dsa_key->dk_p, s + s_len - len, len);
+
+ while (*++p && p < (const char *) &buff[buff_len]) {
+ if (dst_s_verify_str(&p, "Subprime(q): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-6);
+ if ((dsa_key->dk_q = malloc(SHA_LENGTH)) == NULL)
+ return (-7);
+ memcpyend(dsa_key->dk_q, s + s_len - len, len,
+ SHA_LENGTH);
+ } else if (dst_s_verify_str(&p, "Base(g): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-8);
+ if ((dsa_key->dk_g = malloc(dsa_key->dk_p_bytes))
+ == NULL)
+ return (-9);
+ memcpyend(dsa_key->dk_g, s + s_len - len, len,
+ dsa_key->dk_p_bytes);
+ } else if (dst_s_verify_str(&p, "Private_value(x): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-10);
+ if ((dsa_key->dk_x = malloc(SHA_LENGTH)) == NULL)
+ return (-11);
+ memcpyend(dsa_key->dk_x, s + s_len - len, len,
+ SHA_LENGTH);
+ } else if (dst_s_verify_str(&p, "Public_value(y): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-10);
+ if ((dsa_key->dk_y = malloc(dsa_key->dk_p_bytes))
+ == NULL)
+ return (-11);
+ memcpyend(dsa_key->dk_y, s + s_len - len, len,
+ dsa_key->dk_p_bytes);
+ } else {
+ EREPORT(("Decode_DSAKey(): Bad keyword %s\n", p));
+ return (-12);
+ }
+ } /* while p */
+
+ d_key->dk_key_size = dsa_key->dk_p_bytes * 8;
+ dnslen = d_key->dk_func->to_dns_key(d_key, dns, sizeof(dns));
+ foot = dst_s_id_calc(dns, dnslen);
+
+ return (foot);
+}
+
+
+/**************************************************************************
+ * dst_cylink_free_key_structure
+ * Frees all dynamicly allocated structures in DSA_Key.
+ */
+
+static void *
+dst_cylink_free_key_structure(void *key)
+{
+ DSA_Key *d_key = (DSA_Key *) key;
+ if (d_key != NULL) {
+ SAFE_FREE(d_key->dk_signer);
+ SAFE_FREE(d_key->dk_p);
+ SAFE_FREE(d_key->dk_q);
+ SAFE_FREE(d_key->dk_g);
+ SAFE_FREE(d_key->dk_x);
+ SAFE_FREE(d_key->dk_y);
+ SAFE_FREE(d_key);
+ }
+ return (NULL);
+}
+
+
+/**************************************************************************
+ * dst_cylink_generate_keypair
+ * Generates unique keys that are hard to predict.
+ * Parameters
+ * key generic Key structure
+ * exp the public exponent
+ * Return
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_cylink_generate_keypair(DST_KEY *key, int nothing)
+{
+ int status, dnslen, n;
+ DSA_Key *dsa;
+ u_char rand[SHA_LENGTH];
+ u_char dns[1024];
+
+ if (key == NULL || key->dk_alg != KEY_DSA)
+ return (0);
+
+ if ((dsa = (DSA_Key *) malloc(sizeof(DSA_Key))) == NULL) {
+ EREPORT(("dst_cylink_generate_keypair: Memory allocation error 3"));
+ return (0);
+ }
+ memset(dsa, 0, sizeof(*dsa));
+
+ dsa->dk_p_bytes = key->dk_key_size / 8;
+ dsa->dk_p = (uchar *) malloc(dsa->dk_p_bytes);
+ dsa->dk_q = (uchar *) malloc(SHA_LENGTH);
+ dsa->dk_g = (uchar *) malloc(dsa->dk_p_bytes);
+ dsa->dk_x = (uchar *) malloc(SHA_LENGTH);
+ dsa->dk_y = (uchar *) malloc(dsa->dk_p_bytes);
+ if (!dsa->dk_p || !dsa->dk_q || !dsa->dk_g || !dsa->dk_x || !dsa->dk_y) {
+ EREPORT(("dst_cylink_generate_keypair: Memory allocation error 4"));
+ return (0);
+ }
+ n = dst_random(DST_RAND_KEY, sizeof(rand), rand);
+ if (n != sizeof(rand))
+ return (0);
+ status = GenDSSParameters(dsa->dk_p_bytes, dsa->dk_p, dsa->dk_q,
+ dsa->dk_g, rand, NULL);
+ if (status != SUCCESS)
+ return (0);
+
+ status = GenDSSKey(dsa->dk_p_bytes, dsa->dk_p, dsa->dk_q, dsa->dk_g,
+ dsa->dk_x, dsa->dk_y, rand);
+ if (status != SUCCESS)
+ return (0);
+ memset(rand, 0, sizeof(rand));
+ key->dk_KEY_struct = (void *) dsa;
+ dnslen = key->dk_func->to_dns_key(key, dns, sizeof(dns));
+ key->dk_id = dst_s_id_calc(dns, dnslen);
+ return (1);
+}
+
+
+/*
+ * dst_cylink_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_cylink_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ int status;
+ DSA_Key *dkey1 = (DSA_Key *) key1->dk_KEY_struct;
+ DSA_Key *dkey2 = (DSA_Key *) key2->dk_KEY_struct;
+
+ if (dkey1 == NULL && dkey2 == NULL)
+ return (0);
+ else if (dkey1 == NULL)
+ return (2);
+ else if (dkey2 == NULL)
+ return(1);
+
+ if (dkey1->dk_p_bytes != dkey2->dk_p_bytes)
+ return (201);
+ status = memcmp(dkey1->dk_p, dkey2->dk_p, dkey1->dk_p_bytes) ||
+ memcmp(dkey1->dk_q, dkey2->dk_q, SHA_LENGTH) ||
+ memcmp(dkey1->dk_g, dkey2->dk_g, dkey1->dk_p_bytes) ||
+ memcmp(dkey1->dk_y, dkey2->dk_y, dkey1->dk_p_bytes);
+ if (status)
+ return (status);
+ if (dkey1->dk_x || dkey2->dk_x) {
+ if (dkey1->dk_x == NULL || dkey2->dk_x == NULL)
+ return (202);
+ return (memcmp(dkey1->dk_x, dkey2->dk_x, dkey1->dk_p_bytes));
+ } else
+ return (0);
+}
+
+static void *
+memcpyend(void *dest, const void *src, size_t n, size_t size) {
+ if (n < size)
+ memset(dest, 0, size - n);
+ memcpy((char *)dest + size - n, src, n);
+ return dest;
+}
+
+#else
+int
+dst_cylink_init()
+{
+ return (0);
+}
+#endif /* CYLINK */
diff --git a/contrib/bind/lib/dst/dst_api.c b/contrib/bind/lib/dst/dst_api.c
new file mode 100644
index 0000000..6dde481
--- /dev/null
+++ b/contrib/bind/lib/dst/dst_api.c
@@ -0,0 +1,1068 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/dst_api.c,v 1.13 1999/10/13 16:39:22 vixie Exp $";
+#endif
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+/*
+ * This file contains the interface between the DST API and the crypto API.
+ * This is the only file that needs to be changed if the crypto system is
+ * changed. Exported functions are:
+ * void dst_init() Initialize the toolkit
+ * int dst_check_algorithm() Function to determines if alg is suppored.
+ * int dst_compare_keys() Function to compare two keys for equality.
+ * int dst_sign_data() Incremental signing routine.
+ * int dst_verify_data() Incremental verify routine.
+ * int dst_generate_key() Function to generate new KEY
+ * DST_KEY *dst_read_key() Function to retrieve private/public KEY.
+ * void dst_write_key() Function to write out a key.
+ * DST_KEY *dst_dnskey_to_key() Function to convert DNS KEY RR to a DST
+ * KEY structure.
+ * int dst_key_to_dnskey() Function to return a public key in DNS
+ * format binary
+ * DST_KEY *dst_buffer_to_key() Converst a data in buffer to KEY
+ * int *dst_key_to_buffer() Writes out DST_KEY key matterial in buffer
+ * void dst_free_key() Releases all memory referenced by key structure
+ */
+
+#include "port_before.h"
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <memory.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+#include "port_after.h"
+
+/* static variables */
+static int done_init = 0;
+dst_func *dst_t_func[DST_MAX_ALGS];
+char *key_file_fmt_str = "Private-key-format: v%s\nAlgorithm: %d (%s)\n";
+char *dst_path = "";
+
+/* internal I/O functions */
+static DST_KEY *dst_s_read_public_key(const char *in_name,
+ const u_int16_t in_id, int in_alg);
+static int dst_s_read_private_key_file(char *name, DST_KEY *pk_key,
+ u_int16_t in_id, int in_alg);
+static int dst_s_write_public_key(const DST_KEY *key);
+static int dst_s_write_private_key(const DST_KEY *key);
+
+/* internal function to set up data structure */
+static DST_KEY *dst_s_get_key_struct(const char *name, const int alg,
+ const int flags, const int protocol,
+ const int bits);
+
+/*
+ * dst_init
+ * This function initializes the Digital Signature Toolkit.
+ * Right now, it just checks the DSTKEYPATH environment variable.
+ * Parameters
+ * none
+ * Returns
+ * none
+ */
+void
+dst_init()
+{
+ char *s;
+ int len;
+
+ if (done_init != 0)
+ return;
+ done_init = 1;
+
+ s = getenv("DSTKEYPATH");
+ len = 0;
+ if (s) {
+ struct stat statbuf;
+
+ len = strlen(s);
+ if (len > PATH_MAX) {
+ EREPORT(("%s is longer than %d characters, ignoring\n",
+ s, PATH_MAX));
+ } else if (stat(s, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
+ EREPORT(("%s is not a valid directory\n", s));
+ } else {
+ dst_path = (char *) malloc(len + 2);
+ memcpy(dst_path, s, len + 1);
+ if (dst_path[strlen(dst_path) - 1] != '/') {
+ dst_path[strlen(dst_path) + 1] = 0;
+ dst_path[strlen(dst_path)] = '/';
+ }
+ }
+ }
+ memset(dst_t_func, 0, sizeof(dst_t_func));
+ /* first one is selected */
+ dst_bsafe_init();
+ dst_rsaref_init();
+ dst_hmac_md5_init();
+ dst_eay_dss_init();
+ dst_cylink_init();
+}
+
+/*
+ * dst_check_algorithm
+ * This function determines if the crypto system for the specified
+ * algorithm is present.
+ * Parameters
+ * alg 1 KEY_RSA
+ * 3 KEY_DSA
+ * 157 KEY_HMAC_MD5
+ * future algorithms TBD and registered with IANA.
+ * Returns
+ * 1 - The algorithm is available.
+ * 0 - The algorithm is not available.
+ */
+int
+dst_check_algorithm(const int alg)
+{
+ return (dst_t_func[alg] != NULL);
+}
+
+/*
+ * dst_s_get_key_struct
+ * This function allocates key structure and fills in some of the
+ * fields of the structure.
+ * Parameters:
+ * name: the name of the key
+ * alg: the algorithm number
+ * flags: the dns flags of the key
+ * protocol: the dns protocol of the key
+ * bits: the size of the key
+ * Returns:
+ * NULL if error
+ * valid pointer otherwise
+ */
+static DST_KEY *
+dst_s_get_key_struct(const char *name, const int alg, const int flags,
+ const int protocol, const int bits)
+{
+ DST_KEY *new_key = NULL;
+
+ if (dst_check_algorithm(alg)) /* make sure alg is available */
+ new_key = (DST_KEY *) malloc(sizeof(*new_key));
+ if (new_key == NULL)
+ return (NULL);
+
+ memset(new_key, 0, sizeof(*new_key));
+ new_key->dk_key_name = strdup(name);
+ new_key->dk_alg = alg;
+ new_key->dk_flags = flags;
+ new_key->dk_proto = protocol;
+ new_key->dk_KEY_struct = NULL;
+ new_key->dk_key_size = bits;
+ new_key->dk_func = dst_t_func[alg];
+ return (new_key);
+}
+
+/*
+ * dst_compare_keys
+ * Compares two keys for equality.
+ * Parameters
+ * key1, key2 Two keys to be compared.
+ * Returns
+ * 0 The keys are equal.
+ * non-zero The keys are not equal.
+ */
+
+int
+dst_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ if (key1 == key2)
+ return (0);
+ if (key1 == NULL || key2 == NULL)
+ return (4);
+ if (key1->dk_alg != key2->dk_alg)
+ return (1);
+ if (key1->dk_key_size != key2->dk_key_size)
+ return (2);
+ if (key1->dk_id != key2->dk_id)
+ return (3);
+ return (key1->dk_func->compare(key1, key2));
+}
+
+
+/*
+ * dst_sign_data
+ * An incremental signing function. Data is signed in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * itself is created (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode A bit mask used to specify operation(s) to be performed.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 Add data to digest
+ * SIG_MODE_FINAL 4 Generate signature
+ * from signature
+ * SIG_MODE_ALL (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL
+ * data Data to be signed.
+ * len The length in bytes of data to be signed.
+ * in_key Contains a private key to sign with.
+ * KEY structures should be handled (created, converted,
+ * compared, stored, freed) by the DST.
+ * signature
+ * The location to which the signature will be written.
+ * sig_len Length of the signature field in bytes.
+ * Return
+ * 0 Successfull INIT or Update operation
+ * >0 success FINAL (sign) operation
+ * <0 failure
+ */
+
+int
+dst_sign_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_sign_data()");
+
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func && in_key->dk_func->sign)
+ return (in_key->dk_func->sign(mode, in_key, context, data, len,
+ signature, sig_len));
+ return (UNKNOWN_KEYALG);
+}
+
+
+/*
+ * dst_verify_data
+ * An incremental verify function. Data is verified in steps.
+ * First the context must be initialized (SIG_MODE_INIT).
+ * Then data is hashed (SIG_MODE_UPDATE). Finally the signature
+ * is verified (SIG_MODE_FINAL). This function can be called
+ * once with INIT, UPDATE and FINAL modes all set, or it can be
+ * called separately with a different mode set for each step. The
+ * UPDATE step can be repeated.
+ * Parameters
+ * mode Operations to perform this time.
+ * SIG_MODE_INIT 1 Initialize digest
+ * SIG_MODE_UPDATE 2 add data to digest
+ * SIG_MODE_FINAL 4 verify signature
+ * SIG_MODE_ALL
+ * (SIG_MODE_INIT,SIG_MODE_UPDATE,SIG_MODE_FINAL)
+ * data Data to pass through the hash function.
+ * len Length of the data in bytes.
+ * in_key Key for verification.
+ * signature Location of signature.
+ * sig_len Length of the signature in bytes.
+ * Returns
+ * 0 Verify success
+ * Non-Zero Verify Failure
+ */
+
+int
+dst_verify_data(const int mode, DST_KEY *in_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ DUMP(data, mode, len, "dst_verify_data()");
+ if (mode & SIG_MODE_FINAL &&
+ (in_key->dk_KEY_struct == NULL || signature == NULL))
+ return (MISSING_KEY_OR_SIGNATURE);
+
+ if (in_key->dk_func == NULL || in_key->dk_func->verify == NULL)
+ return (UNSUPPORTED_KEYALG);
+ return (in_key->dk_func->verify(mode, in_key, context, data, len,
+ signature, sig_len));
+}
+
+
+/*
+ * dst_read_private_key
+ * Access a private key. First the list of private keys that have
+ * already been read in is searched, then the key accessed on disk.
+ * If the private key can be found, it is returned. If the key cannot
+ * be found, a null pointer is returned. The options specify required
+ * key characteristics. If the private key requested does not have
+ * these characteristics, it will not be read.
+ * Parameters
+ * in_keyname The private key name.
+ * in_id The id of the private key.
+ * options DST_FORCE_READ Read from disk - don't use a previously
+ * read key.
+ * DST_CAN_SIGN The key must be useable for signing.
+ * DST_NO_AUTHEN The key must be useable for authentication.
+ * DST_STANDARD Return any key
+ * Returns
+ * NULL If there is no key found in the current directory or
+ * this key has not been loaded before.
+ * !NULL Success - KEY structure returned.
+ */
+
+DST_KEY *
+dst_read_key(const char *in_keyname, const u_int16_t in_id,
+ const int in_alg, const int type)
+{
+ char keyname[PATH_MAX];
+ DST_KEY *dg_key = NULL, *pubkey = NULL;
+
+ if (!dst_check_algorithm(in_alg)) { /* make sure alg is available */
+ EREPORT(("dst_read_private_key(): Algorithm %d not suppored\n",
+ in_alg));
+ return (NULL);
+ }
+ if ((type && (DST_PUBLIC | DST_PRIVATE)) == 0)
+ return (NULL);
+ if (in_keyname == NULL) {
+ EREPORT(("dst_read_private_key(): Null key name passed in\n"));
+ return (NULL);
+ } else
+ strcpy(keyname, in_keyname);
+
+ /* before I read in the public key, check if it is allowed to sign */
+ if ((pubkey = dst_s_read_public_key(keyname, in_id, in_alg)) == NULL)
+ return (NULL);
+
+ if (type == DST_PUBLIC)
+ return pubkey;
+
+ if (!(dg_key = dst_s_get_key_struct(keyname, pubkey->dk_alg,
+ pubkey->dk_flags, pubkey->dk_proto,
+ 0)))
+ return (dg_key);
+ /* Fill in private key and some fields in the general key structure */
+ if (dst_s_read_private_key_file(keyname, dg_key, pubkey->dk_id,
+ pubkey->dk_alg) == 0)
+ dg_key = dst_free_key(dg_key);
+
+ pubkey = dst_free_key(pubkey);
+ return (dg_key);
+}
+
+int
+dst_write_key(const DST_KEY *key, const int type)
+{
+ int pub = 0, priv = 0;
+
+ if (key == NULL)
+ return (0);
+ if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */
+ EREPORT(("dst_write_key(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ if ((type & (DST_PRIVATE|DST_PUBLIC)) == 0)
+ return (0);
+
+ if (type & DST_PUBLIC)
+ if ((pub = dst_s_write_public_key(key)) < 0)
+ return (pub);
+ if (type & DST_PRIVATE)
+ if ((priv = dst_s_write_private_key(key)) < 0)
+ return (priv);
+ return (priv+pub);
+}
+
+/*
+ * dst_write_private_key
+ * Write a private key to disk. The filename will be of the form:
+ * K<key->dk_name>+<key->dk_alg>+<key->dk_id>.<private key suffix>.
+ * If there is already a file with this name, an error is returned.
+ *
+ * Parameters
+ * key A DST managed key structure that contains
+ * all information needed about a key.
+ * Return
+ * >= 0 Correct behavior. Returns length of encoded key value
+ * written to disk.
+ * < 0 error.
+ */
+
+static int
+dst_s_write_private_key(const DST_KEY *key)
+{
+ u_char encoded_block[RAW_KEY_SIZE];
+ char file[PATH_MAX];
+ int len;
+ FILE *fp;
+
+ /* First encode the key into the portable key format */
+ if (key == NULL)
+ return (-1);
+ if (key->dk_KEY_struct == NULL)
+ return (0); /* null key has no private key */
+
+ if (key->dk_func == NULL || key->dk_func->to_file_fmt == NULL) {
+ EREPORT(("dst_write_private_key(): Unsupported operation %d\n",
+ key->dk_alg));
+ return (-5);
+ } else if ((len = key->dk_func->to_file_fmt(key, (char *)encoded_block,
+ sizeof(encoded_block))) <= 0) {
+ EREPORT(("dst_write_private_key(): Failed encoding private RSA bsafe key %d\n", len));
+ return (-8);
+ }
+ /* Now I can create the file I want to use */
+ dst_s_build_filename(file, key->dk_key_name, key->dk_id, key->dk_alg,
+ PRIVATE_KEY, PATH_MAX);
+
+ /* Do not overwrite an existing file */
+ if ((fp = dst_s_fopen(file, "w", 0600)) != NULL) {
+ int nn;
+ if ((nn = fwrite(encoded_block, 1, len, fp)) != len) {
+ EREPORT(("dst_write_private_key(): Write failure on %s %d != %d errno=%d\n",
+ file, out_len, nn, errno));
+ return (-5);
+ }
+ fclose(fp);
+ } else {
+ EREPORT(("dst_write_private_key(): Can not create file %s\n"
+ ,file));
+ return (-6);
+ }
+ memset(encoded_block, 0, len);
+ return (len);
+}
+
+/*
+*
+ * dst_read_public_key
+ * Read a public key from disk and store in a DST key structure.
+ * Parameters
+ * in_name K<in_name><in_id>.<public key suffix> is the
+ * filename of the key file to be read.
+ * Returns
+ * NULL If the key does not exist or no name is supplied.
+ * NON-NULL Initalized key structure if the key exists.
+ */
+
+static DST_KEY *
+dst_s_read_public_key(const char *in_name, const u_int16_t in_id, int in_alg)
+{
+ int flags, proto, alg, len, dlen;
+ int c;
+ char name[PATH_MAX], enckey[RAW_KEY_SIZE], *notspace;
+ u_char deckey[RAW_KEY_SIZE];
+ FILE *fp;
+
+ if (in_name == NULL) {
+ EREPORT(("dst_read_public_key(): No key name given\n"));
+ return (NULL);
+ }
+ if (dst_s_build_filename(name, in_name, in_id, in_alg, PUBLIC_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_public_key(): Cannot make filename from %s, %d, and %s\n",
+ in_name, in_id, PUBLIC_KEY));
+ return (NULL);
+ }
+ /*
+ * Open the file and read it's formatted contents up to key
+ * File format:
+ * domain.name [ttl] [IN] KEY <flags> <protocol> <algorithm> <key>
+ * flags, proto, alg stored as decimal (or hex numbers FIXME).
+ * (FIXME: handle parentheses for line continuation.)
+ */
+ if ((fp = dst_s_fopen(name, "r", 0)) == NULL) {
+ EREPORT(("dst_read_public_key(): Public Key not found %s\n",
+ name));
+ return (NULL);
+ }
+ /* Skip domain name, which ends at first blank */
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ /* Skip blank to get to next field */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+
+ /* Skip optional TTL -- if initial digit, skip whole word. */
+ if (isdigit(c)) {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Skip optional "IN" */
+ if (c == 'I' || c == 'i') {
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ }
+ /* Locate and skip "KEY" */
+ if (c != 'K' && c != 'k') {
+ EREPORT(("\"KEY\" doesn't appear in file: %s", name));
+ return NULL;
+ }
+ while ((c = getc(fp)) != EOF)
+ if (isspace(c))
+ break;
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ ungetc(c, fp); /* return the charcter to the input field */
+ /* Handle hex!! FIXME. */
+
+ if (fscanf(fp, "%d %d %d", &flags, &proto, &alg) != 3) {
+ EREPORT(("dst_read_public_key(): Can not read flag/proto/alg field from %s\n"
+ ,name));
+ return (NULL);
+ }
+ /* read in the key string */
+ fgets(enckey, sizeof(enckey), fp);
+
+ /* If we aren't at end-of-file, something is wrong. */
+ while ((c = getc(fp)) != EOF)
+ if (!isspace(c))
+ break;
+ if (!feof(fp)) {
+ EREPORT(("Key too long in file: %s", name));
+ return NULL;
+ }
+ fclose(fp);
+
+ if ((len = strlen(enckey)) <= 0)
+ return (NULL);
+
+ /* discard \n */
+ enckey[--len] = '\0';
+
+ /* remove leading spaces */
+ for (notspace = (char *) enckey; isspace(*notspace); len--)
+ notspace++;
+
+ dlen = b64_pton(notspace, deckey, sizeof(deckey));
+ if (dlen < 0) {
+ EREPORT(("dst_read_public_key: bad return from b64_pton = %d",
+ dlen));
+ return (NULL);
+ }
+ /* store key and info in a key structure that is returned */
+/* return dst_store_public_key(in_name, alg, proto, 666, flags, deckey,
+ dlen);*/
+ return dst_buffer_to_key(in_name, alg, flags, proto, deckey, dlen);
+}
+
+
+/*
+ * dst_write_public_key
+ * Write a key to disk in DNS format.
+ * Parameters
+ * key Pointer to a DST key structure.
+ * Returns
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_s_write_public_key(const DST_KEY *key)
+{
+ FILE *fp;
+ char filename[PATH_MAX];
+ u_char out_key[RAW_KEY_SIZE];
+ char enc_key[RAW_KEY_SIZE];
+ int len = 0;
+
+ memset(out_key, 0, sizeof(out_key));
+ if (key == NULL) {
+ EREPORT(("dst_write_public_key(): No key specified \n"));
+ return (0);
+ } else if ((len = dst_key_to_dnskey(key, out_key, sizeof(out_key)))< 0)
+ return (0);
+
+ /* Make the filename */
+ if (dst_s_build_filename(filename, key->dk_key_name, key->dk_id,
+ key->dk_alg, PUBLIC_KEY, PATH_MAX) == -1) {
+ EREPORT(("dst_write_public_key(): Cannot make filename from %s, %d, and %s\n",
+ key->dk_key_name, key->dk_id, PUBLIC_KEY));
+ return (0);
+ }
+ /* create public key file */
+ if ((fp = dst_s_fopen(filename, "w+", 0644)) == NULL) {
+ EREPORT(("DST_write_public_key: open of file:%s failed (errno=%d)\n",
+ filename, errno));
+ return (0);
+ }
+ /*write out key first base64 the key data */
+ if (key->dk_flags & DST_EXTEND_FLAG)
+ b64_ntop(&out_key[6], len - 6, enc_key, sizeof(enc_key));
+ else
+ b64_ntop(&out_key[4], len - 4, enc_key, sizeof(enc_key));
+ fprintf(fp, "%s IN KEY %d %d %d %s\n",
+ key->dk_key_name,
+ key->dk_flags, key->dk_proto, key->dk_alg, enc_key);
+ fclose(fp);
+ return (1);
+}
+
+
+/*
+ * dst_dnskey_to_public_key
+ * This function converts the contents of a DNS KEY RR into a DST
+ * key structure.
+ * Paramters
+ * len Length of the RDATA of the KEY RR RDATA
+ * rdata A pointer to the the KEY RR RDATA.
+ * in_name Key name to be stored in key structure.
+ * Returns
+ * NULL Failure
+ * NON-NULL Success. Pointer to key structure.
+ * Caller's responsibility to free() it.
+ */
+
+DST_KEY *
+dst_dnskey_to_key(const char *in_name, const u_char *rdata, const int len)
+{
+ DST_KEY *key_st;
+ int alg ;
+ int start = DST_KEY_START;
+
+ if (rdata == NULL || len <= DST_KEY_ALG) /* no data */
+ return (NULL);
+ alg = (u_int8_t) rdata[DST_KEY_ALG];
+ if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+ EREPORT(("dst_dnskey_to_key(): Algorithm %d not suppored\n",
+ alg));
+ return (NULL);
+ }
+ if ((key_st = dst_s_get_key_struct(in_name, alg, 0, 0, 0)) == NULL)
+ return (NULL);
+
+ if (in_name == NULL)
+ return (NULL);
+ key_st->dk_flags = dst_s_get_int16(rdata);
+ key_st->dk_proto = (u_int16_t) rdata[DST_KEY_PROT];
+ if (key_st->dk_flags & DST_EXTEND_FLAG) {
+ u_int32_t ext_flags;
+ ext_flags = (u_int32_t) dst_s_get_int16(&rdata[DST_EXT_FLAG]);
+ key_st->dk_flags = key_st->dk_flags | (ext_flags << 16);
+ start += 2;
+ }
+ /*
+ * now point to the begining of the data representing the encoding
+ * of the key
+ */
+ if (key_st->dk_func && key_st->dk_func->from_dns_key) {
+ if (key_st->dk_func->from_dns_key(key_st, &rdata[start],
+ len - start) > 0)
+ return (key_st);
+ } else
+ EREPORT(("dst_dnskey_to_public_key(): unsuppored alg %d\n",
+ alg));
+
+ SAFE_FREE(key_st);
+ return (key_st);
+}
+
+
+/*
+ * dst_public_key_to_dnskey
+ * Function to encode a public key into DNS KEY wire format
+ * Parameters
+ * key Key structure to encode.
+ * out_storage Location to write the encoded key to.
+ * out_len Size of the output array.
+ * Returns
+ * <0 Failure
+ * >=0 Number of bytes written to out_storage
+ */
+
+int
+dst_key_to_dnskey(const DST_KEY *key, u_char *out_storage,
+ const int out_len)
+{
+ u_int16_t val;
+ int loc = 0;
+ int enc_len = 0;
+ if (key == NULL)
+ return (-1);
+
+ if (!dst_check_algorithm(key->dk_alg)) { /* make sure alg is available */
+ EREPORT(("dst_key_to_dnskey(): Algorithm %d not suppored\n",
+ key->dk_alg));
+ return (UNSUPPORTED_KEYALG);
+ }
+ memset(out_storage, 0, out_len);
+ val = (u_int16_t)(key->dk_flags & 0xffff);
+ dst_s_put_int16(out_storage, val);
+ loc += 2;
+
+ out_storage[loc++] = (u_char) key->dk_proto;
+ out_storage[loc++] = (u_char) key->dk_alg;
+
+ if (key->dk_flags > 0xffff) { /* Extended flags */
+ val = (u_int16_t)((key->dk_flags >> 16) & 0xffff);
+ dst_s_put_int16(&out_storage[loc], val);
+ loc += 2;
+ }
+ if (key->dk_KEY_struct == NULL)
+ return (loc);
+ if (key->dk_func && key->dk_func->to_dns_key) {
+ enc_len = key->dk_func->to_dns_key(key,
+ (u_char *) &out_storage[loc],
+ out_len - loc);
+ if (enc_len > 0)
+ return (enc_len + loc);
+ else
+ return (-1);
+ } else
+ EREPORT(("dst_key_to_dnskey(): Unsupported ALG %d\n",
+ key->dk_alg));
+ return (-1);
+}
+
+
+/*
+ * dst_buffer_to_key
+ * Function to encode a string of raw data into a DST key
+ * Parameters
+ * alg The algorithm (HMAC only)
+ * key A pointer to the data
+ * keylen The length of the data
+ * Returns
+ * NULL an error occurred
+ * NON-NULL the DST key
+ */
+DST_KEY *
+dst_buffer_to_key(const char *key_name, /* name of the key */
+ const int alg, /* algorithm */
+ const int flags, /* dns flags */
+ const int protocol, /* dns protocol */
+ const u_char *key_buf, /* key in dns wire fmt */
+ const int key_len) /* size of key */
+{
+
+ DST_KEY *dkey = NULL;
+
+ if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+ EREPORT(("dst_buffer_to_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ dkey = dst_s_get_key_struct(key_name, alg, flags,
+ protocol, -1);
+
+ if (dkey == NULL)
+ return (NULL);
+ if (dkey->dk_func != NULL &&
+ dkey->dk_func->from_dns_key != NULL) {
+ if (dkey->dk_func->from_dns_key(dkey, key_buf, key_len) < 0) {
+ EREPORT(("dst_buffer_to_key(): dst_buffer_to_hmac failed\n"));
+ return (dst_free_key(dkey));
+ }
+ return (dkey);
+ }
+ return (NULL);
+}
+
+int
+dst_key_to_buffer(DST_KEY *key, u_char *out_buff, int buf_len)
+{
+ int len;
+ /* this function will extrac the secret of HMAC into a buffer */
+ if(key == NULL)
+ return (0);
+ if(key->dk_func != NULL && key->dk_func != NULL) {
+ len = key->dk_func->to_dns_key(key, out_buff, buf_len);
+ if (len < 0)
+ return (0);
+ return (len);
+ }
+ return (0);
+}
+
+
+/*
+ * dst_s_read_private_key_file
+ * Function reads in private key from a file.
+ * Fills out the KEY structure.
+ * Parameters
+ * name Name of the key to be read.
+ * pk_key Structure that the key is returned in.
+ * in_id Key identifier (tag)
+ * Return
+ * 1 if everthing works
+ * 0 if there is any problem
+ */
+
+static int
+dst_s_read_private_key_file(char *name, DST_KEY *pk_key, u_int16_t in_id,
+ int in_alg)
+{
+ int cnt, alg, len, major, minor, file_major, file_minor;
+ int id;
+ char filename[PATH_MAX];
+ u_char in_buff[RAW_KEY_SIZE], *p;
+ FILE *fp;
+
+ if (name == NULL || pk_key == NULL) {
+ EREPORT(("dst_read_private_key_file(): No key name given\n"));
+ return (0);
+ }
+ /* Make the filename */
+ if (dst_s_build_filename(filename, name, in_id, in_alg, PRIVATE_KEY,
+ PATH_MAX) == -1) {
+ EREPORT(("dst_read_private_key(): Cannot make filename from %s, %d, and %s\n",
+ name, in_id, PRIVATE_KEY));
+ return (0);
+ }
+ /* first check if we can find the key file */
+ if ((fp = dst_s_fopen(filename, "r", 0)) == NULL) {
+ EREPORT(("dst_s_read_private_key_file: Could not open file %s in directory %s\n",
+ filename, dst_path[0] ? dst_path :
+ (char *) getcwd(NULL, PATH_MAX - 1)));
+ return (0);
+ }
+ /* now read the header info from the file */
+ if ((cnt = fread(in_buff, 1, sizeof(in_buff), fp)) < 5) {
+ fclose(fp);
+ EREPORT(("dst_s_read_private_key_file: error reading file %s (empty file)\n",
+ filename));
+ return (0);
+ }
+ /* decrypt key */
+ fclose(fp);
+ if (memcmp(in_buff, "Private-key-format: v", 20) != 0)
+ goto fail;
+ len = cnt;
+ p = in_buff;
+
+ if (!dst_s_verify_str((const char **) &p, "Private-key-format: v")) {
+ EREPORT(("dst_s_read_private_key_file(): Not a Key file/Decrypt failed %s\n", name));
+ goto fail;
+ }
+ /* read in file format */
+ sscanf((char *)p, "%d.%d", &file_major, &file_minor);
+ sscanf(KEY_FILE_FORMAT, "%d.%d", &major, &minor);
+ if (file_major < 1) {
+ EREPORT(("dst_s_read_private_key_file(): Unknown keyfile %d.%d version for %s\n",
+ file_major, file_minor, name));
+ goto fail;
+ } else if (file_major > major || file_minor > minor)
+ EREPORT((
+ "dst_s_read_private_key_file(): Keyfile %s version higher than mine %d.%d MAY FAIL\n",
+ name, file_major, file_minor));
+
+ while (*p++ != '\n') ; /* skip to end of line */
+
+ if (!dst_s_verify_str((const char **) &p, "Algorithm: "))
+ goto fail;
+
+ if (sscanf((char *)p, "%d", &alg) != 1)
+ goto fail;
+ while (*p++ != '\n') ; /* skip to end of line */
+
+ if (pk_key->dk_key_name && !strcmp(pk_key->dk_key_name, name))
+ SAFE_FREE2(pk_key->dk_key_name, strlen(pk_key->dk_key_name));
+ pk_key->dk_key_name = (char *) strdup(name);
+
+ /* allocate and fill in key structure */
+ if (pk_key->dk_func == NULL || pk_key->dk_func->from_file_fmt == NULL)
+ goto fail;
+
+ id = pk_key->dk_func->from_file_fmt(pk_key, (char *)p, &in_buff[len] - p);
+ if (id < 0)
+ goto fail;
+
+ /* Make sure the actual key tag matches the input tag used in the filename
+ */
+ if (id != in_id) {
+ EREPORT(("dst_s_read_private_key_file(): actual tag of key read %d != input tag used to build filename %d.\n", id, in_id));
+ goto fail;
+ }
+ pk_key->dk_id = (u_int16_t) id;
+ pk_key->dk_alg = alg;
+ memset(in_buff, 0, cnt);
+ return (1);
+
+ fail:
+ memset(in_buff, 0, cnt);
+ return (0);
+}
+
+
+/*
+ * dst_generate_key
+ * Generate and store a public/private keypair.
+ * Keys will be stored in formatted files.
+ * Parameters
+ * name Name of the new key. Used to create key files
+ * K<name>+<alg>+<id>.public and K<name>+<alg>+<id>.private.
+ * bits Size of the new key in bits.
+ * exp What exponent to use:
+ * 0 use exponent 3
+ * non-zero use Fermant4
+ * flags The default value of the DNS Key flags.
+ * The DNS Key RR Flag field is defined in RFC 2065,
+ * section 3.3. The field has 16 bits.
+ * protocol
+ * Default value of the DNS Key protocol field.
+ * The DNS Key protocol field is defined in RFC 2065,
+ * section 3.4. The field has 8 bits.
+ * alg What algorithm to use. Currently defined:
+ * KEY_RSA 1
+ * KEY_DSA 3
+ * KEY_HMAC 157
+ * out_id The key tag is returned.
+ *
+ * Return
+ * NULL Failure
+ * non-NULL the generated key pair
+ * Caller frees the result, and its dk_name pointer.
+ */
+DST_KEY *
+dst_generate_key(const char *name, const int bits, const int exp,
+ const int flags, const int protocol, const int alg)
+{
+ DST_KEY *new_key = NULL;
+ int res;
+ if (name == NULL)
+ return (NULL);
+
+ if (!dst_check_algorithm(alg)) { /* make sure alg is available */
+ EREPORT(("dst_generate_key(): Algorithm %d not suppored\n", alg));
+ return (NULL);
+ }
+
+ new_key = dst_s_get_key_struct(name, alg, flags, protocol, bits);
+ if (new_key == NULL)
+ return (NULL);
+ if (bits == 0) /* null key we are done */
+ return (new_key);
+ if (new_key->dk_func == NULL || new_key->dk_func->generate == NULL) {
+ EREPORT(("dst_generate_key_pair():Unsupported algorithm %d\n",
+ alg));
+ return (dst_free_key(new_key));
+ }
+ if ((res = new_key->dk_func->generate(new_key, exp)) <= 0) {
+ EREPORT(("dst_generate_key_pair(): Key generation failure %s %d %d %d\n",
+ new_key->dk_key_name, new_key->dk_alg,
+ new_key->dk_key_size, exp));
+ return (dst_free_key(new_key));
+ }
+ return (new_key);
+}
+
+
+/*
+ * dst_free_key
+ * Release all data structures pointed to by a key structure.
+ * Parameters
+ * f_key Key structure to be freed.
+ */
+
+DST_KEY *
+dst_free_key(DST_KEY *f_key)
+{
+
+ if (f_key == NULL)
+ return (f_key);
+ if (f_key->dk_func && f_key->dk_func->destroy)
+ f_key->dk_KEY_struct =
+ f_key->dk_func->destroy(f_key->dk_KEY_struct);
+ else {
+ EREPORT(("dst_free_key(): Unknown key alg %d\n",
+ f_key->dk_alg));
+ free(f_key->dk_KEY_struct); /* SHOULD NOT happen */
+ }
+ if (f_key->dk_KEY_struct) {
+ free(f_key->dk_KEY_struct);
+ f_key->dk_KEY_struct = NULL;
+ }
+ if (f_key->dk_key_name)
+ SAFE_FREE(f_key->dk_key_name);
+ SAFE_FREE(f_key);
+ return (NULL);
+}
+
+/*
+ * dst_sig_size
+ * Return the maximim size of signature from the key specified in bytes
+ * Parameters
+ * key
+ * Returns
+ * bytes
+ */
+int
+dst_sig_size(DST_KEY *key) {
+ switch (key->dk_alg) {
+ case KEY_HMAC_MD5:
+ return (16);
+ case KEY_HMAC_SHA1:
+ return (20);
+ case KEY_RSA:
+ return (key->dk_key_size + 7) / 8;
+ case KEY_DSA:
+ return (40);
+ default:
+ EREPORT(("dst_sig_size(): Unknown key alg %d\n", key->dk_alg));
+ return -1;
+ }
+}
+
+/*
+ * dst_random
+ * function that multiplexes number of random number generators
+ * Parameters
+ * mode: select the random number generator
+ * wanted is how many bytes of random data are requested
+ * outran is a buffer of size at least wanted for the output data
+ *
+ * Returns
+ * number of bytes written to outran
+ */
+int
+dst_random(const int mode, int wanted, u_char *outran)
+{
+ u_int32_t *buff = NULL, *bp = NULL;
+ int i;
+ if (wanted <= 0 || outran == NULL)
+ return (0);
+
+ switch (mode) {
+ case DST_RAND_SEMI:
+ bp = buff = (u_int32_t *) malloc(wanted+sizeof(u_int32_t));
+ for (i = 0; i < wanted; i+= sizeof(u_int32_t), bp++) {
+ *bp = dst_s_quick_random(i);
+ }
+ memcpy(outran, buff, wanted);
+ SAFE_FREE(buff);
+ return (wanted);
+ case DST_RAND_STD:
+ return (dst_s_semi_random(outran, wanted));
+ case DST_RAND_KEY:
+ return (dst_s_random(outran, wanted));
+ case DST_RAND_DSS:
+ default:
+ /* need error case here XXX OG */
+ return (0);
+ }
+}
+
diff --git a/contrib/bind/lib/dst/dst_internal.h b/contrib/bind/lib/dst/dst_internal.h
new file mode 100644
index 0000000..66bfed4
--- /dev/null
+++ b/contrib/bind/lib/dst/dst_internal.h
@@ -0,0 +1,163 @@
+#ifndef DST_INTERNAL_H
+#define DST_INTERNAL_H
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+#include <limits.h>
+#include <sys/param.h>
+#if (!defined(BSD)) || (BSD < 199306)
+# include <sys/bitypes.h>
+#else
+# include <sys/types.h>
+#endif
+
+#ifndef PATH_MAX
+# ifdef POSIX_PATH_MAX
+# define PATH_MAX POSIX_PATH_MAX
+# else
+# define PATH_MAX 255 /* this is the value of POSIX_PATH_MAX */
+# endif
+#endif
+
+typedef struct dst_key {
+ char *dk_key_name; /* name of the key */
+ int dk_key_size; /* this is the size of the key in bits */
+ int dk_proto; /* what protocols this key can be used for */
+ int dk_alg; /* algorithm number from key record */
+ u_int32_t dk_flags; /* and the flags of the public key */
+ u_int16_t dk_id; /* identifier of the key */
+ void *dk_KEY_struct; /* pointer to key in crypto pkg fmt */
+ struct dst_func *dk_func; /* point to cryptto pgk specific function table */
+} DST_KEY;
+#define HAS_DST_KEY
+
+#include <isc/dst.h>
+/*
+ * define what crypto systems are supported for RSA,
+ * BSAFE is prefered over RSAREF; only one can be set at any time
+ */
+#if defined(BSAFE) && defined(RSAREF)
+# error "Cannot have both BSAFE and RSAREF defined"
+#endif
+
+/* Declare dst_lib specific constants */
+#define KEY_FILE_FORMAT "1.2"
+
+/* suffixes for key file names */
+#define PRIVATE_KEY "private"
+#define PUBLIC_KEY "key"
+
+/* error handling */
+#ifdef REPORT_ERRORS
+#define EREPORT(str) printf str
+#else
+#define EREPORT(str)
+#endif
+
+/* use our own special macro to FRRE memory */
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(a) if(a != NULL){memset(a,0, sizeof(*a)); free(a); a=NULL;}
+#define SAFE_FREE2(a,s) if (a != NULL && s > 0){memset(a,0, s);free(a); a=NULL;}
+#endif
+
+typedef struct dst_func {
+ int (*sign)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ u_int8_t *signature, const int sig_len);
+ int (*verify)(const int mode, DST_KEY *key, void **context,
+ const u_int8_t *data, const int len,
+ const u_int8_t *signature, const int sig_len);
+ int (*compare)(const DST_KEY *key1, const DST_KEY *key2);
+ int (*generate)(DST_KEY *key, int parms);
+ void *(*destroy)(void *key);
+ /* conversion functions */
+ int (*to_dns_key)(const DST_KEY *key, u_int8_t *out,
+ const int out_len);
+ int (*from_dns_key)(DST_KEY *key, const u_int8_t *str,
+ const int str_len);
+ int (*to_file_fmt)(const DST_KEY *key, char *out,
+ const int out_len);
+ int (*from_file_fmt)(DST_KEY *key, const char *out,
+ const int out_len);
+
+} dst_func;
+
+extern dst_func *dst_t_func[DST_MAX_ALGS];
+extern char *key_file_fmt_str;
+extern char *dst_path;
+
+#ifndef DST_HASH_SIZE
+#define DST_HASH_SIZE 20 /* RIPEMD160 and SHA-1 are 20 bytes MD5 is 16 */
+#endif
+
+int dst_bsafe_init();
+
+int dst_rsaref_init();
+
+int dst_hmac_md5_init();
+
+int dst_cylink_init();
+
+int dst_eay_dss_init();
+
+/* support functions */
+/* base64 to bignum conversion routines */
+int dst_s_conv_bignum_u8_to_b64( char *out_buf, const int out_len,
+ const char *header,
+ const u_int8_t *bin_data,
+ const int bin_len);
+int dst_s_conv_bignum_b64_to_u8( const char **buf, u_int8_t *loc,
+ const int loclen) ;
+/* from higher level support routines */
+int dst_s_calculate_bits( const u_int8_t *str, const int max_bits);
+int dst_s_verify_str( const char **buf, const char *str);
+
+
+/* conversion between dns names and key file names */
+size_t dst_s_filename_length( const char *name, const char *suffix);
+int dst_s_build_filename( char *filename, const char *name,
+ u_int16_t id, int alg, const char *suffix,
+ size_t filename_length);
+
+FILE *dst_s_fopen (const char *filename, const char *mode, int perm);
+
+/* from file prandom.c */
+int dst_s_random( u_int8_t *output, int size);
+int dst_s_semi_random( u_int8_t *output, int size);
+u_int32_t dst_s_quick_random( int inc);
+void dst_s_quick_random_set( u_int32_t val, u_int32_t cnt);
+
+/*
+ * read and write network byte order into u_int?_t
+ * all of these should be retired
+ */
+u_int16_t dst_s_get_int16( const u_int8_t *buf);
+void dst_s_put_int16( u_int8_t *buf, const u_int16_t val);
+
+u_int32_t dst_s_get_int32( const u_int8_t *buf);
+void dst_s_put_int32( u_int8_t *buf, const u_int32_t val);
+
+#ifdef DUMP
+# undef DUMP
+# define DUMP(a,b,c,d) dst_s_dump(a,b,c,d)
+#else
+# define DUMP(a,b,c,d)
+#endif
+
+
+#endif /* DST_INTERNAL_H */
diff --git a/contrib/bind/lib/dst/eay_dss_link.c b/contrib/bind/lib/dst/eay_dss_link.c
new file mode 100644
index 0000000..b060bf0
--- /dev/null
+++ b/contrib/bind/lib/dst/eay_dss_link.c
@@ -0,0 +1,624 @@
+#ifdef EAY_DSS
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/eay_dss_link.c,v 1.4 1999/10/13 16:39:23 vixie Exp $";
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+/*
+ * This file contains two components
+ * 1. Interface to the EAY libcrypto library to allow compilation of Bind
+ * with TIS/DNSSEC when EAY libcrypto is not available
+ * all calls to libcrypto are contained inside this file.
+ * 2. The glue to connvert DSA KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "dst_internal.h"
+
+#include "crypto.h"
+#include "bn.h"
+#include "dsa.h"
+#include "sha.h"
+
+#include "port_after.h"
+
+static int dst_eay_dss_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len);
+
+static int dst_eay_dss_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len);
+
+static int dst_eay_dss_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len);
+static int dst_eay_dss_from_dns_key(DST_KEY *s_key, const u_char *key,
+ const int len);
+static int dst_eay_dss_key_to_file_format(const DST_KEY *key, u_char *buff,
+ const int buff_len);
+static int dst_eay_dss_key_from_file_format(DST_KEY *d_key,
+ const u_char *buff,
+ const int buff_len);
+static void *dst_eay_dss_free_key_structure(void *key);
+
+static int dst_eay_dss_generate_keypair(DST_KEY *key, int exp);
+static int dst_eay_dss_compare_keys(const DST_KEY *key1, const DST_KEY *key2);
+
+/*
+ * dst_eay_dss_init() Function to answer set up function pointers for
+ * EAY DSS related functions
+ */
+int
+dst_eay_dss_init()
+{
+ if (dst_t_func[KEY_DSA] != NULL)
+ return (1);
+ dst_t_func[KEY_DSA] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_DSA] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_DSA], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_DSA]->sign = dst_eay_dss_sign;
+ dst_t_func[KEY_DSA]->verify = dst_eay_dss_verify;
+ dst_t_func[KEY_DSA]->compare = dst_eay_dss_compare_keys;
+ dst_t_func[KEY_DSA]->generate = dst_eay_dss_generate_keypair;
+ dst_t_func[KEY_DSA]->destroy = dst_eay_dss_free_key_structure;
+ dst_t_func[KEY_DSA]->from_dns_key = dst_eay_dss_from_dns_key;
+ dst_t_func[KEY_DSA]->to_dns_key = dst_eay_dss_to_dns_key;
+ dst_t_func[KEY_DSA]->from_file_fmt = dst_eay_dss_key_from_file_format;
+ dst_t_func[KEY_DSA]->to_file_fmt = dst_eay_dss_key_to_file_format;
+ return (1);
+}
+
+/*
+ * dst_eay_dss_sign
+ * Call EAY DSS signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * algobj structure holds context for a sign done in multiple calls.
+ * context the context to use for this computation
+ * data data to be signed.
+ * len length in bytes of data.
+ * priv_key key to use for signing.
+ * signature location to store signature.
+ * sig_len size in bytes of signature field.
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * N is 41 for DNS
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_eay_dss_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ int sign_len = 0;
+ int status;
+ SHA_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (SHA_CTX *) malloc(sizeof(SHA_CTX));
+ else if (context)
+ ctx = (SHA_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ SHA1_Init(ctx);
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+ SHA1_Update(ctx, (u_char *) data, len);
+ }
+ if (mode & SIG_MODE_FINAL) {
+ DSA *key;
+ u_char digest[SHA_DIGEST_LENGTH];
+ u_char rand[SHA_DIGEST_LENGTH];
+ u_char r[SHA_DIGEST_LENGTH], s[SHA_DIGEST_LENGTH];
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (-1);
+ key = dkey->dk_KEY_struct;
+ if (key == NULL)
+ return(-2);
+ SHA1_Final(digest, ctx);
+ status = DSA_sign(0, digest, SHA_DIGEST_LENGTH,
+ signature, &sign_len, key);
+ if (status != 0)
+ return (SIGN_FINAL_FAILURE);
+
+ *signature = (dkey->dk_key_size - 512)/64;
+ sign_len = 1;
+ memcpy(signature + sign_len, r, SHA_DIGEST_LENGTH);
+ sign_len += SHA_DIGEST_LENGTH;
+ memcpy(signature + sign_len, s, SHA_DIGEST_LENGTH);
+ sign_len += SHA_DIGEST_LENGTH;
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/*
+ * dst_eay_dss_verify
+ * Calls EAY DSS verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey structure holds context for a verify done in multiple calls.
+ * context algorithm specific context for the current context processing
+ * data data signed.
+ * len length in bytes of data.
+ * pub_key key to use for verify.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_eay_dss_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ int status;
+ SHA_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (SHA_CTX *) malloc(sizeof(SHA_CTX));
+ else if (context)
+ ctx = (SHA_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (mode & SIG_MODE_INIT)
+ SHA1_Init(ctx);
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0)) {
+ SHA1_Update(ctx, (u_char *) data, len);
+ }
+ if (mode & SIG_MODE_FINAL) {
+ DSA *key;
+ u_char digest[SHA_DIGEST_LENGTH];
+ u_char r[SHA_DIGEST_LENGTH], s[SHA_DIGEST_LENGTH];
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (-1);
+ key = (DSA *) dkey->dk_KEY_struct;
+ if (key = NULL)
+ return (-2);
+ if (signature == NULL || sig_len != (2 * SHA_DIGEST_LENGTH +1))
+ return (SIGN_FINAL_FAILURE);
+ SHA1_Final(digest, ctx);
+ SAFE_FREE(ctx);
+ if (status != 0)
+ return (SIGN_FINAL_FAILURE);
+ if (((int)*signature) != ((BN_num_bytes(key->p) -64)/8))
+ return(VERIFY_FINAL_FAILURE);
+
+ memcpy(r, signature +1, SHA_DIGEST_LENGTH);
+ memcpy(s, signature + SHA_DIGEST_LENGTH +1, SHA_DIGEST_LENGTH);
+ status = DSA_verify(0, digest, SHA_DIGEST_LENGTH,
+ (u_char *)signature, sig_len, key);
+ if (status != 0)
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (0);
+}
+
+
+/*
+ * dst_eay_dss_to_dns_key
+ * Converts key from DSA to DNS distribution format
+ * This function gets in a pointer to the public key and a work area
+ * to write the key into.
+ * Parameters
+ * public KEY structure
+ * out_str buffer to write encoded key into
+ * out_len size of out_str
+ * Return
+ * N >= 0 length of encoded key
+ * n < 0 error
+ */
+
+static int
+dst_eay_dss_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+ u_char *op = out_str;
+ int t;
+ DSA *key;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= 0 || out_str == NULL)
+ return (-1);
+ key = (DSA *) in_key->dk_KEY_struct;
+
+ t = (BN_num_bytes(key->p) - 64) / 8;
+
+ *op++ = t;
+ BN_bn2bin(key->q, op);
+ op += BN_num_bytes(key->q);
+ BN_bn2bin(key->p, op);
+ op += BN_num_bytes(key->p);
+ BN_bn2bin(key->g, op);
+ op += BN_num_bytes(key->g);
+ BN_bn2bin(key->pub_key, op);
+ op += BN_num_bytes(key->pub_key);
+
+ return (op - out_str);
+}
+
+
+/*
+ * dst_eay_dss_from_dns_key
+ * Converts from a DNS KEY RR format to an RSA KEY.
+ * Parameters
+ * len Length in bytes of DNS key
+ * key DNS key
+ * name Key name
+ * s_key DST structure that will point to the RSA key this routine
+ * will build.
+ * Return
+ * 0 The input key, s_key or name was null.
+ * 1 Success
+ */
+static int
+dst_eay_dss_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+ int t;
+ u_char *key_ptr = (u_char *)key;
+ DSA *d_key;
+ int p_bytes;
+
+ if (s_key == NULL || len < 0 || key == NULL)
+ return (0);
+
+ if (len == 0) /* process null key */
+ return (1);
+
+ if (key_ptr == NULL)
+ return (0);
+ t = (int) *key_ptr++; /* length of exponent in bytes */
+ p_bytes = 64 + 8 * t;
+
+ if ((3 * (t * 8 + 64) + SHA_DIGEST_LENGTH + 1) != len)
+ return (0);
+
+ if ((d_key = (DSA *) malloc(sizeof(DSA))) == NULL) {
+ EREPORT(("dst_eay_dss_from_dns_key(): Memory allocation error 1"));
+ return (0);
+ }
+ memset(d_key, 0, sizeof(DSA));
+ s_key->dk_KEY_struct = (void *) d_key;
+
+ d_key->q = BN_bin2bn(key_ptr, SHA_DIGEST_LENGTH, NULL);
+ key_ptr += SHA_DIGEST_LENGTH;
+
+ d_key->p = BN_bin2bn(key_ptr, p_bytes, NULL);
+ key_ptr += p_bytes;
+
+ d_key->g = BN_bin2bn(key_ptr, p_bytes, NULL);
+ key_ptr += p_bytes;
+
+ d_key->pub_key = BN_bin2bn(key_ptr, p_bytes, NULL);
+ key_ptr += p_bytes;
+
+ s_key->dk_id = dst_s_id_calc(key, len);
+ s_key->dk_key_size = p_bytes * 8;
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_eay_dss_key_to_file_format
+ * Encodes an DSA Key into the portable file format.
+ * Parameters
+ * key DSA KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input rkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_eay_dss_key_to_file_format(const DST_KEY *key, u_char *buff,
+ const int buff_len)
+{
+ u_char *bp;
+ int len, b_len;
+ DSA *dkey;
+ char num[256]; /* More than long enough for DSA keys */
+
+ if (key == NULL || key->dk_KEY_struct == NULL) /* no output */
+ return (0);
+ if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+ return (-1); /* no OR not enough space in output area */
+
+ dkey = (DSA *) key->dk_KEY_struct;
+
+ memset(buff, 0, buff_len); /* just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_DSA, "DSA");
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->p, BN_num_bytes(dkey->p));
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime(p): ", num,
+ BN_num_bytes(dkey->p))) <= 0)
+ return (-1);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->q, BN_num_bytes(dkey->q));
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Subprime(q): ", num,
+ BN_num_bytes(dkey->q))) <= 0)
+ return (-2);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->g, BN_num_bytes(dkey->g));
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Base(g): ", num,
+ BN_num_bytes(dkey->g))) <= 0)
+ return (-3);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->priv_key, BN_num_bytes(dkey->priv_key));
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Private_value(x): ",
+ num,
+ BN_num_bytes(dkey->priv_key)))
+ <= 0)
+ return (-4);
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ memcpy(num, dkey->pub_key, BN_num_bytes(dkey->pub_key));
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Public_value(y): ",
+ num,
+ BN_num_bytes(dkey->pub_key)))
+ <= 0)
+ return (-5);
+
+ bp += len;
+ b_len -= len;
+ return (buff_len - b_len);
+}
+
+
+/**************************************************************************
+ * dst_eay_dss_key_from_file_format
+ * Converts contents of a private key file into a private DSA key.
+ * Parameters
+ * d_key structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_eay_dss_key_from_file_format(DST_KEY *d_key, const u_char *buff,
+ const int buff_len)
+{
+ char s[128];
+ char dns[1024];
+ int len, s_len = sizeof(s);
+ int foot = -1, dnslen;
+ const char *p = buff;
+ DSA *dsa_key;
+
+ if (d_key == NULL || buff == NULL || buff_len <= 0)
+ return (-1);
+
+ dsa_key = (DSA *) malloc(sizeof(DSA));
+ if (dsa_key == NULL) {
+ return (-2);
+ }
+ memset(dsa_key, 0, sizeof(*dsa_key));
+ d_key->dk_KEY_struct = (void *) dsa_key;
+
+ if (!dst_s_verify_str(&p, "Prime(p): "))
+ return (-3);
+ memset(s, 0, s_len);
+ if ((len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)) == 0)
+ return (-4);
+ dsa_key->p = BN_bin2bn (s, len, NULL);
+ if (dsa_key->p == NULL)
+ return(-5);
+
+ while (*++p && p < (const char *) &buff[buff_len]) {
+ if (dst_s_verify_str(&p, "Subprime(q): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-6);
+ dsa_key->q = BN_bin2bn (s, len, NULL);
+ if (dsa_key->q == NULL)
+ return (-7);
+ } else if (dst_s_verify_str(&p, "Base(g): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-8);
+ dsa_key->g = BN_bin2bn (s, len, NULL);
+ if (dsa_key->g == NULL)
+ return (-9);
+ } else if (dst_s_verify_str(&p, "Private_value(x): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-10);
+ dsa_key->priv_key = BN_bin2bn (s, len, NULL);
+ if (dsa_key->priv_key == NULL)
+ return (-11);
+ } else if (dst_s_verify_str(&p, "Public_value(y): ")) {
+ if (!(len = dst_s_conv_bignum_b64_to_u8(&p, s, s_len)))
+ return (-12);
+ dsa_key->pub_key = BN_bin2bn (s, len, NULL);
+ if (dsa_key->pub_key == NULL)
+ return (-13);
+ } else {
+ EREPORT(("Decode_DSAKey(): Bad keyword %s\n", p));
+ return (-14);
+ }
+ } /* while p */
+
+ d_key->dk_key_size = BN_num_bytes(dsa_key->p);
+ dnslen = d_key->dk_func->to_dns_key(d_key, dns, sizeof(dns));
+ foot = dst_s_id_calc(dns, dnslen);
+
+ return (foot);
+}
+
+
+/**************************************************************************
+ * dst_eay_dss_free_key_structure
+ * Frees all dynamicly allocated structures in DSA.
+ */
+
+static void *
+dst_eay_dss_free_key_structure(void *key)
+{
+ DSA *d_key = (DSA *) key;
+ if (d_key != NULL) {
+ BN_free(d_key->p);
+ BN_free(d_key->q);
+ BN_free(d_key->g);
+ if (d_key->pub_key)
+ BN_free(d_key->pub_key);
+ if (d_key->priv_key)
+ BN_free(d_key->priv_key);
+ SAFE_FREE(d_key);
+ }
+ return (NULL);
+}
+
+
+/**************************************************************************
+ * dst_eay_dss_generate_keypair
+ * Generates unique keys that are hard to predict.
+ * Parameters
+ * key generic Key structure
+ * exp the public exponent
+ * Return
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_eay_dss_generate_keypair(DST_KEY *key, int nothing)
+{
+ int status, dnslen, n;
+ DSA *dsa;
+ u_char rand[SHA_DIGEST_LENGTH];
+ char dns[1024];
+
+ if (key == NULL || key->dk_alg != KEY_DSA)
+ return (0);
+
+ if ((dsa = (DSA *) malloc(sizeof(DSA))) == NULL) {
+ EREPORT(("dst_eay_dss_generate_keypair: Memory allocation error 3"));
+ return (0);
+ }
+ memset(dsa, 0, sizeof(*dsa));
+
+ n = dst_random(DST_RAND_KEY, sizeof(rand), rand);
+ if (n != sizeof(rand))
+ return (0);
+ dsa = DSA_generate_parameters(key->dk_key_size, rand, 20, NULL, NULL,
+ NULL, NULL);
+
+ if (!dsa) {
+ EREPORT(("dst_eay_dss_generate_keypair: Generate Parameters failed"));
+ return (0);
+ }
+ if (DSA_generate_key(dsa) == 0) {
+ EREPORT(("dst_eay_dss_generate_keypair: Generate Key failed"));
+ return(0);
+ }
+ key->dk_KEY_struct = (void *) dsa;
+ dnslen = key->dk_func->to_dns_key(key, dns, sizeof(dns));
+ key->dk_id = dst_s_id_calc(dns, dnslen);
+ return (1);
+}
+
+
+/*
+ * dst_eay_dss_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_eay_dss_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ int status;
+ DSA *dkey1 = (DSA *) key1->dk_KEY_struct;
+ DSA *dkey2 = (DSA *) key2->dk_KEY_struct;
+
+ if (dkey1 == NULL && dkey2 == NULL)
+ return (0);
+ else if (dkey1 == NULL)
+ return (2);
+ else if (dkey2 == NULL)
+ return(1);
+
+ status = BN_cmp(dkey1->p, dkey2->p) ||
+ BN_cmp(dkey1->q, dkey2->q) ||
+ BN_cmp(dkey1->g, dkey2->g) ||
+ BN_cmp(dkey1->pub_key, dkey2->pub_key);
+
+ if (status)
+ return (status);
+
+ if (dkey1->priv_key || dkey2->priv_key) {
+ if (dkey1->priv_key == NULL || dkey2->priv_key == NULL)
+ return (202);
+ return (BN_cmp(dkey1->priv_key, dkey2->priv_key));
+ } else
+ return (0);
+}
+#else
+int
+dst_eay_dss_init()
+{
+ return (0);
+}
+#endif /* EAY_DSS */
diff --git a/contrib/bind/lib/dst/hmac_link.c b/contrib/bind/lib/dst/hmac_link.c
new file mode 100644
index 0000000..1f96bca
--- /dev/null
+++ b/contrib/bind/lib/dst/hmac_link.c
@@ -0,0 +1,493 @@
+#ifdef HMAC_MD5
+#ifndef LINT
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/hmac_link.c,v 1.8 1999/10/15 21:30:07 vixie Exp $";
+#endif
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+
+/*
+ * This file contains an implementation of the HMAC-MD5 algorithm.
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+#ifdef USE_MD5
+# include "md5.h"
+# ifndef _MD5_H_
+# define _MD5_H_ 1 /* make sure we do not include rsaref md5.h file */
+# endif
+#endif
+
+#include "port_after.h"
+
+
+#define HMAC_LEN 64
+#define HMAC_IPAD 0x36
+#define HMAC_OPAD 0x5c
+#define MD5_LEN 16
+
+
+typedef struct hmackey {
+ u_char hk_ipad[64], hk_opad[64];
+} HMAC_Key;
+
+
+/**************************************************************************
+ * dst_hmac_md5_sign
+ * Call HMAC signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * priv_key key to use for signing.
+ * context the context to be used in this digest
+ * data data to be signed.
+ * len length in bytes of data.
+ * signature location to store signature.
+ * sig_len size of the signature location
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_sign(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ int sign_len = 0;
+ MD5_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, (u_char *)data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ if (signature == NULL || sig_len < MD5_LEN)
+ return (SIGN_FINAL_FAILURE);
+ MD5Final(signature, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, signature, MD5_LEN);
+ MD5Final(signature, ctx);
+ sign_len = MD5_LEN;
+ SAFE_FREE(ctx);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_verify()
+ * Calls HMAC verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * dkey key to use for verify.
+ * data data signed.
+ * len length in bytes of data.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_hmac_md5_verify(const int mode, DST_KEY *d_key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ HMAC_Key *key;
+ MD5_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = (MD5_CTX *) malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (MD5_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if (d_key == NULL || d_key->dk_KEY_struct == NULL)
+ return (-1);
+
+ key = (HMAC_Key *) d_key->dk_KEY_struct;
+ if (mode & SIG_MODE_INIT) {
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_ipad, HMAC_LEN);
+ }
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0))
+ MD5Update(ctx, (u_char *)data, len);
+
+ if (mode & SIG_MODE_FINAL) {
+ u_char digest[MD5_LEN];
+ if (signature == NULL || key == NULL || sig_len != MD5_LEN)
+ return (VERIFY_FINAL_FAILURE);
+ MD5Final(digest, ctx);
+
+ /* perform outer MD5 */
+ MD5Init(ctx);
+ MD5Update(ctx, key->hk_opad, HMAC_LEN);
+ MD5Update(ctx, digest, MD5_LEN);
+ MD5Final(digest, ctx);
+
+ SAFE_FREE(ctx);
+ if (memcmp(digest, signature, MD5_LEN) != 0)
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (0);
+}
+
+
+/**************************************************************************
+ * dst_buffer_to_hmac_md5
+ * Converts key from raw data to an HMAC Key
+ * This function gets in a pointer to the data
+ * Parameters
+ * hkey the HMAC key to be filled in
+ * key the key in raw format
+ * keylen the length of the key
+ * Return
+ * 0 Success
+ * <0 Failure
+ */
+static int
+dst_buffer_to_hmac_md5(DST_KEY *dkey, const u_char *key, const int keylen)
+{
+ int i;
+ HMAC_Key *hkey = NULL;
+ MD5_CTX ctx;
+ int local_keylen = keylen;
+
+ if (dkey == NULL || key == NULL || keylen < 0)
+ return (-1);
+
+ if ((hkey = (HMAC_Key *) malloc(sizeof(HMAC_Key))) == NULL)
+ return (-2);
+
+ memset(hkey->hk_ipad, 0, sizeof(hkey->hk_ipad));
+ memset(hkey->hk_opad, 0, sizeof(hkey->hk_opad));
+
+ /* if key is longer than HMAC_LEN bytes reset it to key=MD5(key) */
+ if (keylen > HMAC_LEN) {
+ u_char tk[MD5_LEN];
+ MD5Init(&ctx);
+ MD5Update(&ctx, (u_char *)key, keylen);
+ MD5Final(tk, &ctx);
+ memset((void *) &ctx, 0, sizeof(ctx));
+ key = tk;
+ local_keylen = MD5_LEN;
+ }
+ /* start out by storing key in pads */
+ memcpy(hkey->hk_ipad, key, local_keylen);
+ memcpy(hkey->hk_opad, key, local_keylen);
+
+ /* XOR key with hk_ipad and opad values */
+ for (i = 0; i < HMAC_LEN; i++) {
+ hkey->hk_ipad[i] ^= HMAC_IPAD;
+ hkey->hk_opad[i] ^= HMAC_OPAD;
+ }
+ dkey->dk_key_size = local_keylen;
+ dkey->dk_KEY_struct = (void *) hkey;
+ return (1);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_to_file_format
+ * Encodes an HMAC Key into the portable file format.
+ * Parameters
+ * hkey HMAC KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input hkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_hmac_md5_key_to_file_format(const DST_KEY *dkey, char *buff,
+ const int buff_len)
+{
+ char *bp;
+ int len, b_len, i, key_len;
+ u_char key[HMAC_LEN];
+ HMAC_Key *hkey;
+
+ if (dkey == NULL || dkey->dk_KEY_struct == NULL)
+ return (0);
+ if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+ return (-1); /* no OR not enough space in output area */
+
+ hkey = (HMAC_Key *) dkey->dk_KEY_struct;
+ memset(buff, 0, buff_len); /* just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_HMAC_MD5, "HMAC");
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+
+ memset(key, 0, HMAC_LEN);
+ for (i = 0; i < HMAC_LEN; i++)
+ key[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ for (i = HMAC_LEN - 1; i >= 0; i--)
+ if (key[i] != 0)
+ break;
+ key_len = i + 1;
+
+ strcat(bp, "Key: ");
+ bp += strlen("Key: ");
+ b_len = buff_len - (bp - buff);
+
+ len = b64_ntop(key, key_len, bp, b_len);
+ if (len < 0)
+ return (-1);
+ bp += len;
+ *(bp++) = '\n';
+ *bp = '\0';
+ b_len = buff_len - (bp - buff);
+
+ return (buff_len - b_len);
+}
+
+
+/**************************************************************************
+ * dst_hmac_md5_key_from_file_format
+ * Converts contents of a key file into an HMAC key.
+ * Parameters
+ * hkey structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_hmac_md5_key_from_file_format(DST_KEY *dkey, const char *buff,
+ const int buff_len)
+{
+ const char *p = buff, *eol;
+ u_char key[HMAC_LEN+1]; /* b64_pton needs more than 64 bytes do decode
+ * it should probably be fixed rather than doing
+ * this
+ */
+ u_char *tmp;
+ int key_len, len;
+
+ if (dkey == NULL)
+ return (-2);
+ if (buff == NULL || buff_len < 0)
+ return (-1);
+
+ memset(key, 0, sizeof(key));
+
+ if (!dst_s_verify_str(&p, "Key: "))
+ return (-3);
+
+ eol = strchr(p, '\n');
+ if (eol == NULL)
+ return (-4);
+ len = eol - p;
+ tmp = malloc(len + 2);
+ memcpy(tmp, p, len);
+ *(tmp + len) = 0x0;
+ key_len = b64_pton((char *)tmp, key, HMAC_LEN+1); /* see above */
+ SAFE_FREE2(tmp, len + 2);
+
+ if (dst_buffer_to_hmac_md5(dkey, key, key_len) < 0) {
+ return (-6);
+ }
+ return (0);
+}
+
+/*
+ * dst_hmac_md5_to_dns_key()
+ * function to extract hmac key from DST_KEY structure
+ * intput:
+ * in_key: HMAC-MD5 key
+ * output:
+ * out_str: buffer to write ot
+ * out_len: size of output buffer
+ * returns:
+ * number of bytes written to output buffer
+ */
+static int
+dst_hmac_md5_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+
+ HMAC_Key *hkey;
+ int i;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= in_key->dk_key_size || out_str == NULL)
+ return (-1);
+
+ hkey = (HMAC_Key *) in_key->dk_KEY_struct;
+ for (i = 0; i < in_key->dk_key_size; i++)
+ out_str[i] = hkey->hk_ipad[i] ^ HMAC_IPAD;
+ return (i);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_hmac_md5_compare_keys(const DST_KEY *key1, const DST_KEY *key2)
+{
+ HMAC_Key *hkey1 = (HMAC_Key *) key1->dk_KEY_struct;
+ HMAC_Key *hkey2 = (HMAC_Key *) key2->dk_KEY_struct;
+ return memcmp(hkey1->hk_ipad, hkey2->hk_ipad, HMAC_LEN);
+}
+
+/**************************************************************************
+ * dst_hmac_md5_free_key_structure
+ * Frees all (none) dynamically allocated structures in hkey
+ */
+
+static void *
+dst_hmac_md5_free_key_structure(void *key)
+{
+ HMAC_Key *hkey = key;
+ SAFE_FREE(hkey);
+ return (NULL);
+}
+
+
+/***************************************************************************
+ * dst_hmac_md5_generate_key
+ * Creates a HMAC key of size size with a maximum size of 63 bytes
+ * generating a HMAC key larger than 63 bytes makes no sense as that key
+ * is digested before use.
+ */
+
+static int
+dst_hmac_md5_generate_key(DST_KEY *key, const int nothing)
+{
+ u_char *buff;
+ int i, n, size;
+
+ if (key == NULL || key->dk_alg != KEY_HMAC_MD5)
+ return (0);
+ size = (key->dk_key_size + 7) / 8; /* convert to bytes */
+ if (size <= 0)
+ return(0);
+
+ i = size > 64 ? 64 : size;
+ buff = malloc(i+8);
+
+ n = dst_random(DST_RAND_SEMI, i, buff);
+ n += dst_random(DST_RAND_KEY, i, buff);
+ if (n <= i) { /* failed getting anything */
+ SAFE_FREE2(buff, i);
+ return (-1);
+ }
+ n = dst_buffer_to_hmac_md5(key, buff, i);
+ SAFE_FREE2(buff, i);
+ if (n <= 0)
+ return (n);
+ return (1);
+}
+
+/*
+ * dst_hmac_md5_init() Function to answer set up function pointers for HMAC
+ * related functions
+ */
+int
+dst_hmac_md5_init()
+{
+ if (dst_t_func[KEY_HMAC_MD5] != NULL)
+ return (1);
+ dst_t_func[KEY_HMAC_MD5] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_HMAC_MD5] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_HMAC_MD5], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_HMAC_MD5]->sign = dst_hmac_md5_sign;
+ dst_t_func[KEY_HMAC_MD5]->verify = dst_hmac_md5_verify;
+ dst_t_func[KEY_HMAC_MD5]->compare = dst_hmac_md5_compare_keys;
+ dst_t_func[KEY_HMAC_MD5]->generate = dst_hmac_md5_generate_key;
+ dst_t_func[KEY_HMAC_MD5]->destroy = dst_hmac_md5_free_key_structure;
+ dst_t_func[KEY_HMAC_MD5]->to_dns_key = dst_hmac_md5_to_dns_key;
+ dst_t_func[KEY_HMAC_MD5]->from_dns_key = dst_buffer_to_hmac_md5;
+ dst_t_func[KEY_HMAC_MD5]->to_file_fmt = dst_hmac_md5_key_to_file_format;
+ dst_t_func[KEY_HMAC_MD5]->from_file_fmt = dst_hmac_md5_key_from_file_format;
+ return (1);
+}
+
+#else
+int
+dst_hmac_md5_init(){
+ return (0);
+}
+#endif
+
+
+
+
+
+
+
diff --git a/contrib/bind/lib/dst/md5.h b/contrib/bind/lib/dst/md5.h
new file mode 100644
index 0000000..c8b1580
--- /dev/null
+++ b/contrib/bind/lib/dst/md5.h
@@ -0,0 +1,101 @@
+/* crypto/md/md5.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#ifndef HEADER_MD5_H
+#define HEADER_MD5_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MD5_CBLOCK 64
+#define MD5_LBLOCK 16
+#define MD5_BLOCK 16
+#define MD5_LAST_BLOCK 56
+#define MD5_LENGTH_BLOCK 8
+#define MD5_DIGEST_LENGTH 16
+
+typedef struct MD5state_st
+ {
+ unsigned long A,B,C,D;
+ unsigned long Nl,Nh;
+ unsigned long data[MD5_LBLOCK];
+ int num;
+ } MD5_CTX;
+
+#ifndef NOPROTO
+void MD5_Init(MD5_CTX *c);
+void MD5_Update(MD5_CTX *c, unsigned char *data, unsigned long len);
+void MD5_Final(unsigned char *md, MD5_CTX *c);
+unsigned char *MD5(unsigned char *d, unsigned long n, unsigned char *md);
+#else
+void MD5_Init();
+void MD5_Update();
+void MD5_Final();
+unsigned char *MD5();
+#endif
+
+/* to provide backward compatabilty to RSAREF calls ogud@tis.com 1997/11/14 */
+#define MD5Init(c) MD5_Init(c)
+#define MD5Update(c,data, len) MD5_Update(c,data,len)
+#define MD5Final(md, c) MD5_Final(md, c)
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bind/lib/dst/md5_dgst.c b/contrib/bind/lib/dst/md5_dgst.c
new file mode 100644
index 0000000..82e5a38
--- /dev/null
+++ b/contrib/bind/lib/dst/md5_dgst.c
@@ -0,0 +1,368 @@
+/* crypto/md/md5_dgst.c */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdio.h>
+#ifdef USE_MD5 /* Added by ogud@tis.com 1998/1/26 */
+#include "md5_locl.h"
+
+char *MD5_version="MD5 part of SSLeay 0.8.1 19-Jul-1997";
+
+/* Implemented from RFC1321 The MD5 Message-Digest Algorithm
+ */
+
+#define INIT_DATA_A (unsigned long)0x67452301L
+#define INIT_DATA_B (unsigned long)0xefcdab89L
+#define INIT_DATA_C (unsigned long)0x98badcfeL
+#define INIT_DATA_D (unsigned long)0x10325476L
+
+#ifndef NOPROTO
+static void md5_block(MD5_CTX *c, unsigned long *p);
+#else
+static void md5_block();
+#endif
+
+void MD5_Init(c)
+MD5_CTX *c;
+ {
+ c->A=INIT_DATA_A;
+ c->B=INIT_DATA_B;
+ c->C=INIT_DATA_C;
+ c->D=INIT_DATA_D;
+ c->Nl=0;
+ c->Nh=0;
+ c->num=0;
+ }
+
+void MD5_Update(c, data, len)
+MD5_CTX *c;
+register unsigned char *data;
+unsigned long len;
+ {
+ register ULONG *p;
+ int sw,sc;
+ ULONG l;
+
+ if (len == 0) return;
+
+ l=(c->Nl+(len<<3))&0xffffffffL;
+ /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to
+ * Wei Dai <weidai@eskimo.com> for pointing it out. */
+ if (l < c->Nl) /* overflow */
+ c->Nh++;
+ c->Nh+=(len>>29);
+ c->Nl=l;
+
+ if (c->num != 0)
+ {
+ p=c->data;
+ sw=c->num>>2;
+ sc=c->num&0x03;
+
+ if ((c->num+len) >= MD5_CBLOCK)
+ {
+ l= p[sw];
+ p_c2l(data,l,sc);
+ p[sw++]=l;
+ for (; sw<MD5_LBLOCK; sw++)
+ {
+ c2l(data,l);
+ p[sw]=l;
+ }
+ len-=(MD5_CBLOCK-c->num);
+
+ md5_block(c,p);
+ c->num=0;
+ /* drop through and do the rest */
+ }
+ else
+ {
+ int ew,ec;
+
+ c->num+=(int)len;
+ if ((sc+len) < 4) /* ugly, add char's to a word */
+ {
+ l= p[sw];
+ p_c2l_p(data,l,sc,len);
+ p[sw]=l;
+ }
+ else
+ {
+ ew=(c->num>>2);
+ ec=(c->num&0x03);
+ l= p[sw];
+ p_c2l(data,l,sc);
+ p[sw++]=l;
+ for (; sw < ew; sw++)
+ { c2l(data,l); p[sw]=l; }
+ if (ec)
+ {
+ c2l_p(data,l,ec);
+ p[sw]=l;
+ }
+ }
+ return;
+ }
+ }
+ /* we now can process the input data in blocks of MD5_CBLOCK
+ * chars and save the leftovers to c->data. */
+ p=c->data;
+ while (len >= MD5_CBLOCK)
+ {
+#if defined(L_ENDIAN) || defined(B_ENDIAN)
+ memcpy(p,data,MD5_CBLOCK);
+ data+=MD5_CBLOCK;
+#ifdef B_ENDIAN
+ for (sw=(MD5_LBLOCK/4); sw; sw--)
+ {
+ Endian_Reverse32(p[0]);
+ Endian_Reverse32(p[1]);
+ Endian_Reverse32(p[2]);
+ Endian_Reverse32(p[3]);
+ p+=4;
+ }
+#endif
+#else
+ for (sw=(MD5_LBLOCK/4); sw; sw--)
+ {
+ c2l(data,l); *(p++)=l;
+ c2l(data,l); *(p++)=l;
+ c2l(data,l); *(p++)=l;
+ c2l(data,l); *(p++)=l;
+ }
+#endif
+ p=c->data;
+ md5_block(c,p);
+ len-=MD5_CBLOCK;
+ }
+ sc=(int)len;
+ c->num=sc;
+ if (sc)
+ {
+ sw=sc>>2; /* words to copy */
+#ifdef L_ENDIAN
+ p[sw]=0;
+ memcpy(p,data,sc);
+#else
+ sc&=0x03;
+ for ( ; sw; sw--)
+ { c2l(data,l); *(p++)=l; }
+ c2l_p(data,l,sc);
+ *p=l;
+#endif
+ }
+ }
+
+static void md5_block(c, X)
+MD5_CTX *c;
+register ULONG *X;
+ {
+ register ULONG A,B,C,D;
+
+ A=c->A;
+ B=c->B;
+ C=c->C;
+ D=c->D;
+
+ /* Round 0 */
+ R0(A,B,C,D,X[ 0], 7,0xd76aa478L);
+ R0(D,A,B,C,X[ 1],12,0xe8c7b756L);
+ R0(C,D,A,B,X[ 2],17,0x242070dbL);
+ R0(B,C,D,A,X[ 3],22,0xc1bdceeeL);
+ R0(A,B,C,D,X[ 4], 7,0xf57c0fafL);
+ R0(D,A,B,C,X[ 5],12,0x4787c62aL);
+ R0(C,D,A,B,X[ 6],17,0xa8304613L);
+ R0(B,C,D,A,X[ 7],22,0xfd469501L);
+ R0(A,B,C,D,X[ 8], 7,0x698098d8L);
+ R0(D,A,B,C,X[ 9],12,0x8b44f7afL);
+ R0(C,D,A,B,X[10],17,0xffff5bb1L);
+ R0(B,C,D,A,X[11],22,0x895cd7beL);
+ R0(A,B,C,D,X[12], 7,0x6b901122L);
+ R0(D,A,B,C,X[13],12,0xfd987193L);
+ R0(C,D,A,B,X[14],17,0xa679438eL);
+ R0(B,C,D,A,X[15],22,0x49b40821L);
+ /* Round 1 */
+ R1(A,B,C,D,X[ 1], 5,0xf61e2562L);
+ R1(D,A,B,C,X[ 6], 9,0xc040b340L);
+ R1(C,D,A,B,X[11],14,0x265e5a51L);
+ R1(B,C,D,A,X[ 0],20,0xe9b6c7aaL);
+ R1(A,B,C,D,X[ 5], 5,0xd62f105dL);
+ R1(D,A,B,C,X[10], 9,0x02441453L);
+ R1(C,D,A,B,X[15],14,0xd8a1e681L);
+ R1(B,C,D,A,X[ 4],20,0xe7d3fbc8L);
+ R1(A,B,C,D,X[ 9], 5,0x21e1cde6L);
+ R1(D,A,B,C,X[14], 9,0xc33707d6L);
+ R1(C,D,A,B,X[ 3],14,0xf4d50d87L);
+ R1(B,C,D,A,X[ 8],20,0x455a14edL);
+ R1(A,B,C,D,X[13], 5,0xa9e3e905L);
+ R1(D,A,B,C,X[ 2], 9,0xfcefa3f8L);
+ R1(C,D,A,B,X[ 7],14,0x676f02d9L);
+ R1(B,C,D,A,X[12],20,0x8d2a4c8aL);
+ /* Round 2 */
+ R2(A,B,C,D,X[ 5], 4,0xfffa3942L);
+ R2(D,A,B,C,X[ 8],11,0x8771f681L);
+ R2(C,D,A,B,X[11],16,0x6d9d6122L);
+ R2(B,C,D,A,X[14],23,0xfde5380cL);
+ R2(A,B,C,D,X[ 1], 4,0xa4beea44L);
+ R2(D,A,B,C,X[ 4],11,0x4bdecfa9L);
+ R2(C,D,A,B,X[ 7],16,0xf6bb4b60L);
+ R2(B,C,D,A,X[10],23,0xbebfbc70L);
+ R2(A,B,C,D,X[13], 4,0x289b7ec6L);
+ R2(D,A,B,C,X[ 0],11,0xeaa127faL);
+ R2(C,D,A,B,X[ 3],16,0xd4ef3085L);
+ R2(B,C,D,A,X[ 6],23,0x04881d05L);
+ R2(A,B,C,D,X[ 9], 4,0xd9d4d039L);
+ R2(D,A,B,C,X[12],11,0xe6db99e5L);
+ R2(C,D,A,B,X[15],16,0x1fa27cf8L);
+ R2(B,C,D,A,X[ 2],23,0xc4ac5665L);
+ /* Round 3 */
+ R3(A,B,C,D,X[ 0], 6,0xf4292244L);
+ R3(D,A,B,C,X[ 7],10,0x432aff97L);
+ R3(C,D,A,B,X[14],15,0xab9423a7L);
+ R3(B,C,D,A,X[ 5],21,0xfc93a039L);
+ R3(A,B,C,D,X[12], 6,0x655b59c3L);
+ R3(D,A,B,C,X[ 3],10,0x8f0ccc92L);
+ R3(C,D,A,B,X[10],15,0xffeff47dL);
+ R3(B,C,D,A,X[ 1],21,0x85845dd1L);
+ R3(A,B,C,D,X[ 8], 6,0x6fa87e4fL);
+ R3(D,A,B,C,X[15],10,0xfe2ce6e0L);
+ R3(C,D,A,B,X[ 6],15,0xa3014314L);
+ R3(B,C,D,A,X[13],21,0x4e0811a1L);
+ R3(A,B,C,D,X[ 4], 6,0xf7537e82L);
+ R3(D,A,B,C,X[11],10,0xbd3af235L);
+ R3(C,D,A,B,X[ 2],15,0x2ad7d2bbL);
+ R3(B,C,D,A,X[ 9],21,0xeb86d391L);
+
+ c->A+=A&0xffffffffL;
+ c->B+=B&0xffffffffL;
+ c->C+=C&0xffffffffL;
+ c->D+=D&0xffffffffL;
+ }
+
+void MD5_Final(md, c)
+unsigned char *md;
+MD5_CTX *c;
+ {
+ register int i,j;
+ register ULONG l;
+ register ULONG *p;
+ static unsigned char end[4]={0x80,0x00,0x00,0x00};
+ unsigned char *cp=end;
+
+ /* c->num should definitly have room for at least one more byte. */
+ p=c->data;
+ j=c->num;
+ i=j>>2;
+
+ /* purify often complains about the following line as an
+ * Uninitialized Memory Read. While this can be true, the
+ * following p_c2l macro will reset l when that case is true.
+ * This is because j&0x03 contains the number of 'valid' bytes
+ * already in p[i]. If and only if j&0x03 == 0, the UMR will
+ * occur but this is also the only time p_c2l will do
+ * l= *(cp++) instead of l|= *(cp++)
+ * Many thanks to Alex Tang <altitude@cic.net> for pickup this
+ * 'potential bug' */
+#ifdef PURIFY
+ if ((j&0x03) == 0) p[i]=0;
+#endif
+ l=p[i];
+ p_c2l(cp,l,j&0x03);
+ p[i]=l;
+ i++;
+ /* i is the next 'undefined word' */
+ if (c->num >= MD5_LAST_BLOCK)
+ {
+ for (; i<MD5_LBLOCK; i++)
+ p[i]=0;
+ md5_block(c,p);
+ i=0;
+ }
+ for (; i<(MD5_LBLOCK-2); i++)
+ p[i]=0;
+ p[MD5_LBLOCK-2]=c->Nl;
+ p[MD5_LBLOCK-1]=c->Nh;
+ md5_block(c,p);
+ cp=md;
+ l=c->A; l2c(l,cp);
+ l=c->B; l2c(l,cp);
+ l=c->C; l2c(l,cp);
+ l=c->D; l2c(l,cp);
+
+ /* clear stuff, md5_block may be leaving some stuff on the stack
+ * but I'm not worried :-) */
+ c->num=0;
+/* memset((char *)&c,0,sizeof(c));*/
+ }
+
+#ifdef undef
+int printit(l)
+unsigned long *l;
+ {
+ int i,ii;
+
+ for (i=0; i<2; i++)
+ {
+ for (ii=0; ii<8; ii++)
+ {
+ fprintf(stderr,"%08lx ",l[i*8+ii]);
+ }
+ fprintf(stderr,"\n");
+ }
+ }
+#endif
+#endif /* USE_MD5 */
diff --git a/contrib/bind/lib/dst/md5_locl.h b/contrib/bind/lib/dst/md5_locl.h
new file mode 100644
index 0000000..b2f0028
--- /dev/null
+++ b/contrib/bind/lib/dst/md5_locl.h
@@ -0,0 +1,190 @@
+/* crypto/md/md5_locl.h */
+/* Copyright (C) 1995-1997 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * 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 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 OR CONTRIBUTORS 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.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "md5.h"
+
+#define ULONG unsigned long
+#define UCHAR unsigned char
+#define UINT unsigned int
+
+#if defined(NOCONST)
+#define const
+#endif
+
+#undef c2l
+#define c2l(c,l) (l = ((unsigned long)(*((c)++))) , \
+ l|=(((unsigned long)(*((c)++)))<< 8), \
+ l|=(((unsigned long)(*((c)++)))<<16), \
+ l|=(((unsigned long)(*((c)++)))<<24))
+
+#undef p_c2l
+#define p_c2l(c,l,n) { \
+ switch (n) { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ case 3: l|=((unsigned long)(*((c)++)))<<24; \
+ } \
+ }
+
+/* NOTE the pointer is not incremented at the end of this */
+#undef c2l_p
+#define c2l_p(c,l,n) { \
+ l=0; \
+ (c)+=n; \
+ switch (n) { \
+ case 3: l =((unsigned long)(*(--(c))))<<16; \
+ case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+ case 1: l|=((unsigned long)(*(--(c)))) ; \
+ } \
+ }
+
+#undef p_c2l_p
+#define p_c2l_p(c,l,sc,len) { \
+ switch (sc) \
+ { \
+ case 0: l =((unsigned long)(*((c)++))); \
+ if (--len == 0) break; \
+ case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+ if (--len == 0) break; \
+ case 2: l|=((unsigned long)(*((c)++)))<<16; \
+ } \
+ }
+
+#undef l2c
+#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \
+ *((c)++)=(unsigned char)(((l)>> 8)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>16)&0xff), \
+ *((c)++)=(unsigned char)(((l)>>24)&0xff))
+
+/* NOTE - c is not incremented as per l2c */
+#undef l2cn
+#define l2cn(l1,l2,c,n) { \
+ c+=n; \
+ switch (n) { \
+ case 8: *(--(c))=(unsigned char)(((l2)>>24)&0xff); \
+ case 7: *(--(c))=(unsigned char)(((l2)>>16)&0xff); \
+ case 6: *(--(c))=(unsigned char)(((l2)>> 8)&0xff); \
+ case 5: *(--(c))=(unsigned char)(((l2) )&0xff); \
+ case 4: *(--(c))=(unsigned char)(((l1)>>24)&0xff); \
+ case 3: *(--(c))=(unsigned char)(((l1)>>16)&0xff); \
+ case 2: *(--(c))=(unsigned char)(((l1)>> 8)&0xff); \
+ case 1: *(--(c))=(unsigned char)(((l1) )&0xff); \
+ } \
+ }
+
+/* A nice byte order reversal from Wei Dai <weidai@eskimo.com> */
+#if defined(WIN32)
+/* 5 instructions with rotate instruction, else 9 */
+#define Endian_Reverse32(a) \
+ { \
+ unsigned long l=(a); \
+ (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \
+ }
+#else
+/* 6 instructions with rotate instruction, else 8 */
+#define Endian_Reverse32(a) \
+ { \
+ unsigned long l=(a); \
+ l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \
+ (a)=ROTATE(l,16L); \
+ }
+#endif
+/*
+#define F(x,y,z) (((x) & (y)) | ((~(x)) & (z)))
+#define G(x,y,z) (((x) & (z)) | ((y) & (~(z))))
+*/
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, the above can be
+ * simplified to the code below. Wei attributes these optimisations
+ * to Peter Gutmann's SHS code, and he attributes it to Rich Schroeppel.
+ */
+#define F(x,y,z) ((((y) ^ (z)) & (x)) ^ (z))
+#define G(x,y,z) ((((x) ^ (y)) & (z)) ^ (y))
+#define H(x,y,z) ((x) ^ (y) ^ (z))
+#define I(x,y,z) (((x) | (~(z))) ^ (y))
+
+#undef ROTATE
+#if defined(WIN32)
+#define ROTATE(a,n) _lrotl(a,n)
+#else
+#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n))))
+#endif
+
+
+#define R0(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+F((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };\
+
+#define R1(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+G((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R2(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+H((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
+
+#define R3(a,b,c,d,k,s,t) { \
+ a+=((k)+(t)+I((b),(c),(d))); \
+ a=ROTATE(a,s); \
+ a+=b; };
diff --git a/contrib/bind/lib/dst/prandom.c b/contrib/bind/lib/dst/prandom.c
new file mode 100644
index 0000000..0a66e61
--- /dev/null
+++ b/contrib/bind/lib/dst/prandom.c
@@ -0,0 +1,851 @@
+#ifndef LINT
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/prandom.c,v 1.8 1999/10/13 16:39:24 vixie Exp $";
+#endif
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <dirent.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include "dst_internal.h"
+#include "prand_conf.h"
+
+#include "port_after.h"
+
+#ifndef DST_NUM_HASHES
+#define DST_NUM_HASHES 4
+#endif
+#ifndef DST_NUMBER_OF_COUNTERS
+#define DST_NUMBER_OF_COUNTERS 5 /* 32 * 5 == 160 == SHA(1) > MD5 */
+#endif
+
+/*
+ * the constant below is a prime number to make fixed data structues like
+ * stat and time wrap over blocks. This adds certain uncertanty to what is
+ * in each digested block.
+ * The prime number 2879 has the special property that when
+ * divided by 2,4 and 6 the result is also a prime numbers
+ */
+
+#ifndef DST_RANDOM_BLOCK_SIZE
+#define DST_RANDOM_BLOCK_SIZE 2879
+#endif
+
+/*
+ * This constant dictatates how many bits we shift to the right before using a
+ */
+#ifndef DST_SHIFT
+#define DST_SHIFT 9
+#endif
+
+/*
+ * An initalizer that is as bad as any other with half the bits set
+ */
+#ifndef DST_RANDOM_PATTERN
+#define DST_RANDOM_PATTERN 0x8765CA93
+#endif
+/*
+ * things must have changed in the last 3600 seconds to be used
+ */
+#define MAX_OLD 3600
+
+
+/*
+ * these two data structure are used to process input data into digests,
+ *
+ * The first structure is containts a pointer to a DST HMAC key
+ * the variables accompanying are used for
+ * step : select every step byte from input data for the hash
+ * block: number of data elements going into each hash
+ * digested: number of data elements digested so far
+ * curr: offset into the next input data for the first byte.
+ */
+typedef struct hash {
+ DST_KEY *key;
+ void *ctx;
+ int digested, block, step, curr;
+} prand_hash;
+
+/*
+ * This data structure controlls number of hashes and keeps track of
+ * overall progress in generating correct number of bytes of output.
+ * output : array to store the output data in
+ * needed : how many bytes of output are needed
+ * filled : number of bytes in output so far.
+ * bytes : total number of bytes processed by this structure
+ * file_digest : the HMAC key used to digest files.
+ */
+typedef struct work {
+ int needed, filled, bytes;
+ u_char *output;
+ prand_hash *hash[DST_NUM_HASHES];
+ DST_KEY *file_digest;
+} dst_work;
+
+
+/*
+ * forward function declarations
+ */
+static int get_dev_random(u_char *output, int size);
+static int do_time(dst_work *work);
+static int do_ls(dst_work *work);
+static int unix_cmd(dst_work *work);
+static int digest_file(dst_work *work);
+
+static void force_hash(dst_work *work, prand_hash *hash);
+static int do_hash(dst_work *work, prand_hash *hash, u_char *input,
+ int size);
+static int my_digest(dst_work *tmp, u_char *input, int size);
+static prand_hash *get_hmac_key(int step, int block);
+
+static int own_random(dst_work *work);
+
+
+/*
+ * variables used in the quick random number generator
+ */
+static u_int32_t ran_val = DST_RANDOM_PATTERN;
+static u_int32_t ran_cnt = (DST_RANDOM_PATTERN >> 10);
+
+/*
+ * setting the quick_random generator to particular values or if both
+ * input parameters are 0 then set it to initial vlaues
+ */
+
+void
+dst_s_quick_random_set(u_int32_t val, u_int32_t cnt)
+{
+ ran_val = (val == 0) ? DST_RANDOM_PATTERN : val;
+ ran_cnt = (cnt == 0) ? (DST_RANDOM_PATTERN >> 10) : cnt;
+}
+
+/*
+ * this is a quick and random number generator that seems to generate quite
+ * good distribution of data
+ */
+u_int32_t
+dst_s_quick_random(int inc)
+{
+ ran_val = ((ran_val >> 13) ^ (ran_val << 19)) ^
+ ((ran_val >> 7) ^ (ran_val << 25));
+ if (inc > 0) /* only increasing values accepted */
+ ran_cnt += inc;
+ ran_val += ran_cnt++;
+ return (ran_val);
+}
+
+/*
+ * get_dev_random: Function to read /dev/random reliably
+ * this function returns how many bytes where read from the device.
+ * port_after.h should set the control variable HAVE_DEV_RANDOM
+ */
+static int
+get_dev_random(u_char *output, int size)
+{
+#ifdef HAVE_DEV_RANDOM
+ struct stat st;
+ int n = 0, fd = -1, s;
+
+ s = stat("/dev/random", &st);
+ if (s == 0 && S_ISCHR(st.st_mode)) {
+ if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) != -1) {
+ if ((n = read(fd, output, size)) < 0)
+ n = 0;
+ close(fd);
+ }
+ return (n);
+ }
+#endif
+ return (0);
+}
+
+/*
+ * Portable way of getting the time values if gettimeofday is missing
+ * then compile with -DMISSING_GETTIMEOFDAY time() is POSIX compliant but
+ * gettimeofday() is not.
+ * Time of day is predictable, we are looking for the randomness that comes
+ * the last few bits in the microseconds in the timer are hard to predict when
+ * this is invoked at the end of other operations
+ */
+struct timeval *mtime;
+static int
+do_time(dst_work *work)
+{
+ int cnt = 0;
+ static u_char tmp[sizeof(struct timeval) + sizeof(struct timezone)];
+ struct timezone *zone;
+
+ zone = (struct timezone *) tmp;
+ mtime = (struct timeval *)(tmp + sizeof(struct timezone));
+ gettimeofday(mtime, zone);
+ cnt = sizeof(tmp);
+ my_digest(work, tmp, sizeof(tmp));
+
+ return (cnt);
+}
+
+/*
+ * this function simulates the ls command, but it uses stat which gives more
+ * information and is harder to guess
+ * Each call to this function will visit the next directory on the list of
+ * directories, in a circular manner.
+ * return value is the number of bytes added to the temp buffer
+ *
+ * do_ls() does not visit subdirectories
+ * if attacker has access to machine it can guess most of the values seen
+ * thus it is important to only visit directories that are freqently updated
+ * Attacker that has access to the network can see network traffic
+ * when NFS mounted directories are accessed and know exactly the data used
+ * but may not know exactly in what order data is used.
+ * Returns the number of bytes that where returned in stat structures
+ */
+static int
+do_ls(dst_work *work)
+{
+ struct dir_info {
+ uid_t uid;
+ gid_t gid;
+ off_t size;
+ time_t atime, mtime, ctime;
+ };
+ static struct dir_info dir_info;
+ struct stat buf;
+ struct dirent *entry;
+ static int i = 0;
+ static unsigned long d_round = 0;
+ struct timeval tv;
+ int n = 0, dir_len, tb_i = 0, out = 0;
+
+ char file_name[1024];
+ u_char tmp_buff[1024];
+ DIR *dir = NULL;
+
+ if (dirs[i] == NULL) /* if at the end of the list start over */
+ i = 0;
+ if (stat(dirs[i++], &buf)) /* directory does not exist */
+ return (0);
+
+ gettimeofday(&tv,NULL);
+ if (d_round == 0)
+ d_round = tv.tv_sec - MAX_OLD;
+ else if (i==1) /* if starting a new round cut what we accept */
+ d_round += (tv.tv_sec - d_round)/2;
+
+ if (buf.st_atime < d_round)
+ return (0);
+
+ EREPORT(("do_ls i %d filled %4d in_temp %4d\n",
+ i-1, work->filled, work->in_temp));
+ memcpy(tmp_buff, &buf, sizeof(buf));
+ tb_i += sizeof(buf);
+
+
+ if ((dir = opendir(dirs[i-1])) == NULL)/* open it for read */
+ return (0);
+ strcpy(file_name, dirs[i-1]);
+ dir_len = strlen(file_name);
+ file_name[dir_len++] = '/';
+ while ((entry = readdir(dir))) {
+ int len = strlen(entry->d_name);
+ out += len;
+ if (my_digest(work, (u_char *)entry->d_name, len))
+ break;
+
+ memcpy(&file_name[dir_len], entry->d_name, len);
+ file_name[dir_len + len] = 0x0;
+ /* for all entries in dir get the stats */
+ if (stat(file_name, &buf) == 0) {
+ n++; /* count successfull stat calls */
+ /* copy non static fields */
+ dir_info.uid += buf.st_uid;
+ dir_info.gid += buf.st_gid;
+ dir_info.size += buf.st_size;
+ dir_info.atime += buf.st_atime;
+ dir_info.mtime += buf.st_mtime;
+ dir_info.ctime += buf.st_ctime;
+ out += sizeof(dir_info);
+ if(my_digest(work, (u_char *)&dir_info,
+ sizeof(dir_info)))
+ break;
+ }
+ }
+ closedir(dir); /* done */
+ out += do_time(work); /* add a time stamp */
+ return (out);
+}
+
+
+/*
+ * unix_cmd()
+ * this function executes the a command from the cmds[] list of unix commands
+ * configured in the prand_conf.h file
+ * return value is the number of bytes added to the randomness temp buffer
+ *
+ * it returns the number of bytes that where read in
+ * if more data is needed at the end time is added to the data.
+ * This function maintains a state to selects the next command to run
+ * returns the number of bytes read in from the command
+ */
+static int
+unix_cmd(dst_work *work)
+{
+ static int cmd_index = 0;
+ int cnt = 0, n;
+ FILE *pipe;
+ u_char buffer[4096];
+
+ if (cmds[cmd_index] == NULL)
+ cmd_index = 0;
+ EREPORT(("unix_cmd() i %d filled %4d in_temp %4d\n",
+ cmd_index, work->filled, work->in_temp));
+ pipe = popen(cmds[cmd_index++], "r"); /* execute the command */
+
+ while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0) {
+ cnt += n; /* process the output */
+ if (my_digest(work, buffer, n))
+ break;
+ /* this adds some randomness to the output */
+ cnt += do_time(work);
+ }
+ while ((n = fread(buffer, sizeof(char), sizeof(buffer), pipe)) > 0)
+ NULL; /* drain the pipe */
+ pclose(pipe);
+ return (cnt); /* read how many bytes where read in */
+}
+
+/*
+ * digest_file() This function will read a file and run hash over it
+ * input is a file name
+ */
+static int
+digest_file(dst_work *work)
+{
+ static int f_cnt = 0;
+ static unsigned long f_round = 0;
+ FILE *fp;
+ void *ctx;
+ const char *name;
+ int no, i;
+ struct stat st;
+ struct timeval tv;
+ u_char buf[1024];
+
+ if (f_round == 0 || files[f_cnt] == NULL || work->file_digest == NULL)
+ if (gettimeofday(&tv, NULL)) /* only do this if needed */
+ return (0);
+ if (f_round == 0) /* first time called set to one hour ago */
+ f_round = (tv.tv_sec - MAX_OLD);
+ name = files[f_cnt++];
+ if (files[f_cnt] == NULL) { /* end of list of files */
+ if(f_cnt <= 1) /* list is too short */
+ return (0);
+ f_cnt = 0; /* start again on list */
+ f_round += (tv.tv_sec - f_round)/2; /* set new cutoff */
+ work->file_digest = dst_free_key(work->file_digest);
+ }
+ if (work->file_digest == NULL) {
+ work->file_digest = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0,
+ (u_char *)&tv, sizeof(tv));
+ if (work->file_digest == NULL)
+ return (0);
+ }
+ if (access(name, R_OK) || stat(name, &st))
+ return (0); /* no such file or not allowed to read it */
+ if (strncmp(name, "/proc/", 6) && st.st_mtime < f_round)
+ return(0); /* file has not changed recently enough */
+ if (dst_sign_data(SIG_MODE_INIT, work->file_digest, &ctx,
+ NULL, 0, NULL, 0)) {
+ work->file_digest = dst_free_key(work->file_digest);
+ return (0);
+ }
+ if ((fp = fopen(name, "r")) == NULL)
+ return (0);
+ for (no = 0; (i = fread(buf, sizeof(*buf), sizeof(buf), fp)) > 0;
+ no += i)
+ dst_sign_data(SIG_MODE_UPDATE, work->file_digest, &ctx,
+ buf, i, NULL, 0);
+
+ fclose(fp);
+ if (no >= 64) {
+ i = dst_sign_data(SIG_MODE_FINAL, work->file_digest, &ctx,
+ NULL, 0, &work->output[work->filled],
+ DST_HASH_SIZE);
+ if (i > 0)
+ work->filled += i;
+ }
+ else if (i > 0)
+ my_digest(work, buf, i);
+ my_digest(work, (u_char *)name, strlen(name));
+ return (no + strlen(name));
+}
+
+/*
+ * function to perform the FINAL and INIT operation on a hash if allowed
+ */
+static void
+force_hash(dst_work *work, prand_hash *hash)
+{
+ int i = 0;
+
+ /*
+ * if more than half a block then add data to output
+ * otherwise adde the digest to the next hash
+ */
+ if ((hash->digested * 2) > hash->block) {
+ i = dst_sign_data(SIG_MODE_FINAL, hash->key, &hash->ctx,
+ NULL, 0, &work->output[work->filled],
+ DST_HASH_SIZE);
+
+ hash->digested = 0;
+ dst_sign_data(SIG_MODE_INIT, hash->key, &hash->ctx,
+ NULL, 0, NULL, 0);
+ if (i > 0)
+ work->filled += i;
+ }
+ return;
+}
+
+/*
+ * This function takes the input data does the selection of data specified
+ * by the hash control block.
+ * The step varialbe in the work sturcture determines which 1/step bytes
+ * are used,
+ *
+ */
+static int
+do_hash(dst_work *work, prand_hash *hash, u_char *input, int size)
+{
+ u_char *tmp = input, *tp;
+ int i, cnt = size, n, needed, avail, dig, tmp_size = 0;
+
+ if (cnt <= 0 || input == NULL)
+ return (0);
+
+ if (hash->step > 1) { /* if using subset of input data */
+ tmp_size = size / hash->step + 2;
+ tp = tmp = malloc(tmp_size);
+ for (cnt = 0, i = hash->curr; i < size; i += hash->step, cnt++)
+ *(tp++) = input[i];
+ /* calcutate the starting point in the next input set */
+ hash->curr = (hash->step - (i - size)) % hash->step;
+ }
+ /* digest the data in block sizes */
+ for (n = 0; n < cnt; n += needed) {
+ avail = (cnt - n);
+ needed = hash->block - hash->digested;
+ dig = (avail < needed) ? avail : needed;
+ dst_sign_data(SIG_MODE_UPDATE, hash->key, &hash->ctx,
+ &tmp[n], dig, NULL, 0);
+ hash->digested += dig;
+ if (hash->digested >= hash->block)
+ force_hash(work, hash);
+ if (work->needed < work->filled) {
+ if (tmp != input)
+ SAFE_FREE2(tmp, tmp_size);
+ return (1);
+ }
+ }
+ if (tmp_size > 0)
+ SAFE_FREE2(tmp, tmp_size);
+ return (0);
+}
+
+/*
+ * Copy data from INPUT for length SIZE into the work-block TMP.
+ * If we fill the work-block, digest it; then,
+ * if work-block needs more data, keep filling with the rest of the input.
+ */
+static int
+my_digest(dst_work *work, u_char *input, int size)
+{
+
+ int i, full = 0;
+ static unsigned counter;
+
+ counter += size;
+ /* first do each one of the hashes */
+ for (i = 0; i < DST_NUM_HASHES && full == 0; i++)
+ full = do_hash(work, work->hash[i], input, size) +
+ do_hash(work, work->hash[i], (u_char *) &counter,
+ sizeof(counter));
+/*
+ * if enough data has be generated do final operation on all hashes
+ * that have enough date for that
+ */
+ for (i = 0; full && (i < DST_NUM_HASHES); i++)
+ force_hash(work, work->hash[i]);
+
+ return (full);
+}
+
+/*
+ * this function gets some semi random data and sets that as an HMAC key
+ * If we get a valid key this function returns that key initalized
+ * otherwise it returns NULL;
+ */
+static prand_hash *
+get_hmac_key(int step, int block)
+{
+
+ u_char *buff;
+ int temp = 0, n = 0, size = 70;
+ DST_KEY *new_key = NULL;
+ prand_hash *new = NULL;
+
+ /* use key that is larger than digest algorithms (64) for key size */
+ buff = malloc(size);
+ if (buff == NULL)
+ return (NULL);
+ /* do not memset the allocated memory to get random bytes there */
+ /* time of day is somewhat random expecialy in the last bytes */
+ gettimeofday((struct timeval *) &buff[n], NULL);
+ n += sizeof(struct timeval);
+
+/* get some semi random stuff in here stir it with micro seconds */
+ if (n < size) {
+ temp = dst_s_quick_random((int) buff[n - 1]);
+ memcpy(&buff[n], &temp, sizeof(temp));
+ n += sizeof(temp);
+ }
+/* get the pid of this process and its parent */
+ if (n < size) {
+ temp = (int) getpid();
+ memcpy(&buff[n], &temp, sizeof(temp));
+ n += sizeof(temp);
+ }
+ if (n < size) {
+ temp = (int) getppid();
+ memcpy(&buff[n], &temp, sizeof(temp));
+ n += sizeof(temp);
+ }
+/* get the user ID */
+ if (n < size) {
+ temp = (int) getuid();
+ memcpy(&buff[n], &temp, sizeof(temp));
+ n += sizeof(temp);
+ }
+#ifndef GET_HOST_ID_MISSING
+ if (n < size) {
+ temp = (int) gethostid();
+ memcpy(&buff[n], &temp, sizeof(temp));
+ n += sizeof(temp);
+ }
+#endif
+/* get some more random data */
+ if (n < size) {
+ temp = dst_s_quick_random((int) buff[n - 1]);
+ memcpy(&buff[n], &temp, sizeof(temp));
+ n += sizeof(temp);
+ }
+/* covert this into a HMAC key */
+ new_key = dst_buffer_to_key("", KEY_HMAC_MD5, 0, 0, buff, size);
+ SAFE_FREE(buff);
+
+/* get the control structure */
+ if ((new = malloc(sizeof(prand_hash))) == NULL)
+ return (NULL);
+ new->digested = new->curr = 0;
+ new->step = step;
+ new->block = block;
+ new->key = new_key;
+ if (dst_sign_data(SIG_MODE_INIT, new_key, &new->ctx, NULL, 0, NULL, 0))
+ return (NULL);
+
+ return (new);
+}
+
+/*
+ * own_random()
+ * This function goes out and from various sources tries to generate enough
+ * semi random data that a hash function can generate a random data.
+ * This function will iterate between the two main random source sources,
+ * information from programs and directores in random order.
+ * This function return the number of bytes added to the random output buffer.
+ */
+static int
+own_random(dst_work *work)
+{
+ int dir = 0, b;
+ int bytes, n, cmd = 0, dig = 0;
+ int start =0;
+/*
+ * now get the initial seed to put into the quick random function from
+ * the address of the work structure
+ */
+ bytes = (int) getpid();
+/*
+ * proceed while needed
+ */
+ while (work->filled < work->needed) {
+ EREPORT(("own_random r %08x b %6d t %6d f %6d\n",
+ ran_val, bytes, work->in_temp, work->filled));
+/* pick a random number in the range of 0..7 based on that random number
+ * perform some operations that yield random data
+ */
+ start = work->filled;
+ n = (dst_s_quick_random(bytes) >> DST_SHIFT) & 0x07;
+ switch (n) {
+ case 0:
+ case 3:
+ if (sizeof(cmds) > 2 *sizeof(*cmds)) {
+ b = unix_cmd(work);
+ cmd += b;
+ }
+ break;
+
+ case 1:
+ case 7:
+ if (sizeof(dirs) > 2 *sizeof(*dirs)) {
+ b = do_ls(work);
+ dir += b;
+ }
+ break;
+
+ case 4:
+ case 5:
+ /* retry getting data from /dev/random */
+ b = get_dev_random(&work->output[work->filled],
+ work->needed - work->filled);
+ if (b > 0)
+ work->filled += b;
+ break;
+
+ case 6:
+ if (sizeof(files) > 2 * sizeof(*files)) {
+ b = digest_file(work);
+ dig += b;
+ }
+ break;
+
+ case 2:
+ default: /* to make sure we make some progress */
+ work->output[work->filled++] = 0xff &
+ dst_s_quick_random(bytes);
+ b = 1;
+ break;
+ }
+ if (b > 0)
+ bytes += b;
+ }
+ return (work->filled);
+}
+
+
+/*
+ * dst_s_random() This function will return the requested number of bytes
+ * of randomness to the caller it will use the best available sources of
+ * randomness.
+ * The current order is to use /dev/random, precalculated randomness, and
+ * finaly use some system calls and programs to generate semi random data that
+ * is then digested to generate randomness.
+ * This function is thread safe as each thread uses its own context, but
+ * concurrent treads will affect each other as they update shared state
+ * information.
+ * It is strongly recommended that this function be called requesting a size
+ * that is not a multiple of the output of the hash function used.
+ *
+ * If /dev/random is not available this function is not suitable to generate
+ * large ammounts of data, rather it is suitable to seed a pseudo-random
+ * generator
+ * Returns the number of bytes put in the output buffer
+ */
+int
+dst_s_random(u_char *output, int size)
+{
+ int n = 0, s, i;
+ static u_char old_unused[DST_HASH_SIZE * DST_NUM_HASHES];
+ static int unused = 0;
+
+ if (size <= 0 || output == NULL)
+ return (0);
+
+ if (size >= 2048)
+ return (-1);
+ /*
+ * Read from /dev/random
+ */
+ n = get_dev_random(output, size);
+ /*
+ * If old data is available and needed use it
+ */
+ if (n < size && unused > 0) {
+ int need = size - n;
+ if (unused <= need) {
+ memcpy(output, old_unused, unused);
+ n += unused;
+ unused = 0;
+ } else {
+ memcpy(output, old_unused, need);
+ n += need;
+ unused -= need;
+ memcpy(old_unused, &old_unused[need], unused);
+ }
+ }
+ /*
+ * If we need more use the simulated randomness here.
+ */
+ if (n < size) {
+ dst_work *my_work = (dst_work *) malloc(sizeof(dst_work));
+ if (my_work == NULL)
+ return (n);
+ my_work->needed = size - n;
+ my_work->filled = 0;
+ my_work->output = (u_char *) malloc(my_work->needed +
+ DST_HASH_SIZE *
+ DST_NUM_HASHES);
+ my_work->file_digest = NULL;
+ if (my_work->output == NULL)
+ return (n);
+ memset(my_work->output, 0x0, my_work->needed);
+/* allocate upto 4 different HMAC hash functions out of order */
+#if DST_NUM_HASHES >= 3
+ my_work->hash[2] = get_hmac_key(3, DST_RANDOM_BLOCK_SIZE / 2);
+#endif
+#if DST_NUM_HASHES >= 2
+ my_work->hash[1] = get_hmac_key(7, DST_RANDOM_BLOCK_SIZE / 6);
+#endif
+#if DST_NUM_HASHES >= 4
+ my_work->hash[3] = get_hmac_key(5, DST_RANDOM_BLOCK_SIZE / 4);
+#endif
+ my_work->hash[0] = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE);
+ if (my_work->hash[0] == NULL) /* if failure bail out */
+ return (n);
+ s = own_random(my_work);
+/* if more generated than needed store it for future use */
+ if (s >= my_work->needed) {
+ EREPORT(("dst_s_random(): More than needed %d >= %d\n",
+ s, my_work->needed));
+ memcpy(&output[n], my_work->output, my_work->needed);
+ n += my_work->needed;
+ /* saving unused data for next time */
+ unused = s - my_work->needed;
+ memcpy(old_unused, &my_work->output[my_work->needed],
+ unused);
+ } else {
+ /* XXXX This should not happen */
+ EREPORT(("Not enough %d >= %d\n", s, my_work->needed));
+ memcpy(&output[n], my_work->output, s);
+ n += my_work->needed;
+ }
+
+/* delete the allocated work area */
+ for (i = 0; i < DST_NUM_HASHES; i++) {
+ dst_free_key(my_work->hash[i]->key);
+ SAFE_FREE(my_work->hash[i]);
+ }
+ SAFE_FREE(my_work->output);
+ SAFE_FREE(my_work);
+ }
+ return (n);
+}
+
+/*
+ * A random number generator that is fast and strong
+ * this random number generator is based on HASHing data,
+ * the input to the digest function is a collection of <NUMBER_OF_COUNTERS>
+ * counters that is incremented between digest operations
+ * each increment operation amortizes to 2 bits changed in that value
+ * for 5 counters thus the input will amortize to have 10 bits changed
+ * The counters are initaly set using the strong random function above
+ * the HMAC key is selected by the same methold as the HMAC keys for the
+ * strong random function.
+ * Each set of counters is used for 2^25 operations
+ *
+ * returns the number of bytes written to the output buffer
+ * or negative number in case of error
+ */
+int
+dst_s_semi_random(u_char *output, int size)
+{
+ static u_int32_t counter[DST_NUMBER_OF_COUNTERS];
+ static u_char semi_old[DST_HASH_SIZE];
+ static int semi_loc = 0, cnt = 0, hb_size = 0;
+ static DST_KEY *my_key = NULL;
+ prand_hash *hash;
+ int out = 0, i, n;
+
+ if (output == NULL || size <= 0)
+ return (-2);
+
+/* check if we need a new key */
+ if (my_key == NULL || cnt > (1 << 25)) { /* get HMAC KEY */
+ if (my_key)
+ my_key->dk_func->destroy(my_key);
+ if ((hash = get_hmac_key(1, DST_RANDOM_BLOCK_SIZE)) == NULL)
+ return (0);
+ my_key = hash->key;
+/* check if the key works stir the new key using some old random data */
+ hb_size = dst_sign_data(SIG_MODE_ALL, my_key, NULL,
+ (u_char *) counter, sizeof(counter),
+ semi_old, sizeof(semi_old));
+ if (hb_size <= 0) {
+ EREPORT(("dst_s_semi_random() Sign of alg %d failed %d\n",
+ my_key->dk_alg, hb_size));
+ return (-1);
+ }
+/* new set the counters to random values */
+ dst_s_random((u_char *) counter, sizeof(counter));
+ cnt = 0;
+ }
+/* if old data around use it first */
+ if (semi_loc < hb_size) {
+ if (size <= hb_size - semi_loc) { /* need less */
+ memcpy(output, &semi_old[semi_loc], size);
+ semi_loc += size;
+ return (size); /* DONE */
+ } else {
+ out = hb_size - semi_loc;
+ memcpy(output, &semi_old[semi_loc], out);
+ semi_loc += out;
+ }
+ }
+/* generate more randome stuff */
+ while (out < size) {
+ /*
+ * modify at least one bit by incrementing at least one counter
+ * based on the last bit of the last counter updated update
+ * the next one.
+ * minimaly this operation will modify at least 1 bit,
+ * amortized 2 bits
+ */
+ for (n = 0; n < DST_NUMBER_OF_COUNTERS; n++)
+ i = (int) counter[n]++;
+
+ i = dst_sign_data(SIG_MODE_ALL, my_key, NULL,
+ (u_char *) counter, hb_size,
+ semi_old, sizeof(semi_old));
+ if (i != hb_size)
+ EREPORT(("HMAC SIGNATURE FAILURE %d\n", i));
+ cnt++;
+ if (size - out < i) /* Not all data is needed */
+ semi_loc = i = size - out;
+ memcpy(&output[out], semi_old, i);
+ out += i;
+ }
+ return (out);
+}
diff --git a/contrib/bind/lib/dst/rsaref_link.c b/contrib/bind/lib/dst/rsaref_link.c
new file mode 100644
index 0000000..19c9a67
--- /dev/null
+++ b/contrib/bind/lib/dst/rsaref_link.c
@@ -0,0 +1,754 @@
+#ifdef RSAREF
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/rsaref_link.c,v 1.6 1999/10/13 16:39:24 vixie Exp $";
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+
+/*
+ * This file contains two components
+ * 1. Interface to the rsaref library to allow compilation when RSAREF is
+ * not available all calls to RSAREF are contained inside this file.
+ * 2. The glue to connvert RSA{REF} KEYS to and from external formats
+ */
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "dst_internal.h"
+
+# ifdef __STDC__
+# define PROTOTYPES 1
+# else
+# define PROTOTYPES 0
+# endif
+
+# include <global.h>
+# include <rsaref.h>
+
+#include "port_after.h"
+
+
+typedef struct rsakey {
+ char *rk_signer;
+ R_RSA_PRIVATE_KEY *rk_Private_Key;
+ R_RSA_PUBLIC_KEY *rk_Public_Key;
+} RSA_Key;
+
+
+static int dst_rsaref_sign(const int mode, DST_KEY *key, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len);
+static int dst_rsaref_verify(const int mode, DST_KEY *key, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len);
+
+static int dst_rsaref_to_dns_key(const DST_KEY *public, u_char *out_str,
+ const int out_len);
+static int dst_rsaref_from_dns_key(DST_KEY *s_key, const u_char *key,
+ const int len);
+
+static int dst_rsaref_key_to_file_format(const DST_KEY *dkey,
+ u_char *buff,
+ const int buff_len);
+static int dst_rsaref_key_from_file_format(DST_KEY *dkey,
+ const u_char *buff,
+ const int buff_len);
+
+static int dst_rsaref_compare_keys(const DST_KEY *rkey1,
+ const DST_KEY *rkey2);
+static void *dst_rsaref_free_key_structure(void *d_key);
+
+static int dst_rsaref_generate_keypair(DST_KEY *key, const int exp);
+
+static void dst_rsaref_init_random_struct(R_RANDOM_STRUCT * randomstruct);
+
+/*
+ * dst_rsaref_init() Function to answer set up function pointers for RSAREF
+ * related functions
+ */
+int
+dst_rsaref_init()
+{
+ if (dst_t_func[KEY_RSA] != NULL)
+ return (1);
+ dst_t_func[KEY_RSA] = malloc(sizeof(struct dst_func));
+ if (dst_t_func[KEY_RSA] == NULL)
+ return (0);
+ memset(dst_t_func[KEY_RSA], 0, sizeof(struct dst_func));
+ dst_t_func[KEY_RSA]->sign = dst_rsaref_sign;
+ dst_t_func[KEY_RSA]->verify = dst_rsaref_verify;
+ dst_t_func[KEY_RSA]->compare = dst_rsaref_compare_keys;
+ dst_t_func[KEY_RSA]->generate = dst_rsaref_generate_keypair;
+ dst_t_func[KEY_RSA]->destroy = dst_rsaref_free_key_structure;
+ dst_t_func[KEY_RSA]->to_dns_key = dst_rsaref_to_dns_key;
+ dst_t_func[KEY_RSA]->from_dns_key = dst_rsaref_from_dns_key;
+ dst_t_func[KEY_RSA]->to_file_fmt = dst_rsaref_key_to_file_format;
+ dst_t_func[KEY_RSA]->from_file_fmt = dst_rsaref_key_from_file_format;
+ return (1);
+}
+
+/*
+ * dst_rsa_sign
+ * Call RSAREF signing functions to sign a block of data.
+ * There are three steps to signing, INIT (initialize structures),
+ * UPDATE (hash (more) data), FINAL (generate a signature). This
+ * routine performs one or more of these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * key pointer to a RSA key structure that points to public key
+ * and context to use.
+ * data data to be signed.
+ * len length in bytes of data.
+ * signature location to store signature.
+ * sig_len size of the signature storage area
+ * returns
+ * N Success on SIG_MODE_FINAL = returns signature length in bytes
+ * 0 Success on SIG_MODE_INIT and UPDATE
+ * <0 Failure
+ */
+
+
+static int
+dst_rsaref_sign(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ u_char *signature, const int sig_len)
+{
+ int sign_len = 0;
+ R_SIGNATURE_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (R_SIGNATURE_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if ((mode & SIG_MODE_INIT) && R_SignInit(ctx, DA_MD5))
+ return (SIGN_INIT_FAILURE);
+
+ /* equivalent of SIG_MODE_UPDATE */
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0) &&
+ R_SignUpdate(ctx, (u_char *) data, len))
+ return (SIGN_UPDATE_FAILURE);
+
+ if (mode & SIG_MODE_FINAL) {
+ RSA_Key *key = (RSA_Key *) dkey->dk_KEY_struct;
+ if (signature == NULL ||
+ sig_len < (int)(key->rk_Public_Key->bits + 7) / 8)
+ return (SIGN_FINAL_FAILURE);
+ if(key == NULL || key->rk_Private_Key == NULL)
+ return (-1);
+ if (R_SignFinal(ctx, signature, &sign_len,
+ key->rk_Private_Key))
+ return (SIGN_FINAL_FAILURE);
+ SAFE_FREE(ctx);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+ return (sign_len);
+}
+
+
+/*
+ * dst_rsaref_verify()
+ * Calls RSAREF verification routines. There are three steps to
+ * verification, INIT (initialize structures), UPDATE (hash (more) data),
+ * FINAL (generate a signature). This routine performs one or more of
+ * these steps.
+ * Parameters
+ * mode SIG_MODE_INIT, SIG_MODE_UPDATE and/or SIG_MODE_FINAL.
+ * key pointer to a RSA key structure that points to public key
+ * and context to use.
+ * data data signed.
+ * len length in bytes of data.
+ * signature signature.
+ * sig_len length in bytes of signature.
+ * returns
+ * 0 Success
+ * <0 Failure
+ */
+
+static int
+dst_rsaref_verify(const int mode, DST_KEY *dkey, void **context,
+ const u_char *data, const int len,
+ const u_char *signature, const int sig_len)
+{
+ R_SIGNATURE_CTX *ctx = NULL;
+
+ if (mode & SIG_MODE_INIT)
+ ctx = malloc(sizeof(*ctx));
+ else if (context)
+ ctx = (R_SIGNATURE_CTX *) *context;
+ if (ctx == NULL)
+ return (-1);
+
+ if ((mode & SIG_MODE_INIT) && R_VerifyInit(ctx, DA_MD5))
+ return (VERIFY_INIT_FAILURE);
+
+ if ((mode & SIG_MODE_UPDATE) && (data && len > 0) &&
+ R_VerifyUpdate(ctx, (u_char *) data, len))
+ return (VERIFY_UPDATE_FAILURE);
+
+ if ((mode & SIG_MODE_FINAL)) {
+ RSA_Key *key = (RSA_Key *) dkey->dk_KEY_struct;
+
+ if (key == NULL || key->rk_Public_Key == NULL)
+ return (-1);
+ if (signature == NULL || sig_len <= 0)
+ return (VERIFY_FINAL_FAILURE);
+ if (R_VerifyFinal(ctx, (u_char *) signature, sig_len,
+ key->rk_Public_Key))
+ return (VERIFY_FINAL_FAILURE);
+ }
+ else {
+ if (context == NULL)
+ return (-1);
+ *context = (void *) ctx;
+ }
+
+ return (0);
+}
+
+
+/*
+ * dst_rsaref_to_dns_key
+ * Converts key in RSAREF to DNS distribution format
+ * This function gets in a pointer to the public key and a work area
+ * to write the key into.
+ * Parameters
+ * public KEY structure
+ * out_str buffer to write encoded key into
+ * out_len size of out_str
+ * Return
+ * N >= 0 length of encoded key
+ * n < 0 error
+ */
+
+static int
+dst_rsaref_to_dns_key(const DST_KEY *in_key, u_char *out_str,
+ const int out_len)
+{
+ int n, loc;
+ R_RSA_PUBLIC_KEY *public;
+ u_char *op = (u_char *) out_str;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL ||
+ out_len <= 0 || out_str == NULL)
+ return (-1);
+ public = (R_RSA_PUBLIC_KEY *)
+ ((RSA_Key *) in_key->dk_KEY_struct)->rk_Public_Key;
+ if (public == NULL)
+ return (-1);
+
+ memset(op, 0, out_len);
+
+ /* find first non zero */
+ for (n = 0; public->exponent[n] == 0x0; n++) ;
+
+ n = (MAX_RSA_MODULUS_LEN - n); /* find lenght of exponent */
+ *op++ = (u_int8_t) n;
+
+ if (n > (out_len - (op-out_str)))
+ return (-1);
+ memcpy(op, &public->exponent[MAX_RSA_MODULUS_LEN - n], n);
+ op += n;
+ n++; /* include the lenght field in this count */
+
+ /* find first non zero */
+ for (loc = 0; public->modulus[loc] == 0x0; loc++) ;
+
+ /*copy exponent */
+ if ((MAX_RSA_MODULUS_LEN - loc) > (out_len - (op-out_str)))
+ return (-1);
+ memcpy(op, &public->modulus[loc], MAX_RSA_MODULUS_LEN - loc);
+ n += (MAX_RSA_MODULUS_LEN - loc);
+ return (n);
+}
+
+
+/*
+ * dst_rsaref_from_dns_key
+ * Converts from a DNS KEY RR format to an RSA KEY.
+ * Parameters
+ * len Length in bytes of DNS key
+ * key DNS key
+ * name Key name
+ * s_key DST structure that will point to the RSA key this routine
+ * will build.
+ * Return
+ * -1 The input key has fields that are larger than this package supports
+ * 0 The input key, s_key or name was null.
+ * 1 Success
+ */
+static int
+dst_rsaref_from_dns_key(DST_KEY *s_key, const u_char *key, const int len)
+{
+ int bytes;
+ u_char *key_ptr;
+ RSA_Key *r_key;
+
+ if (key == NULL || s_key == NULL || len < 0)
+ return (0);
+
+ if (s_key->dk_KEY_struct) { /* do not reuse */
+ dst_rsaref_free_key_structure(s_key->dk_KEY_struct);
+ s_key->dk_KEY_struct = NULL;
+ }
+ if (len == 0) /* null key no conversion needed */
+ return (1);
+
+ if ((r_key = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+ EREPORT(("dst_rsaref_from_dns_key(): Memory allocation error 1\n"));
+ return (0);
+ }
+ memset(r_key, 0, sizeof(RSA_Key));
+ s_key->dk_KEY_struct = (void *) r_key;
+ r_key->rk_signer = strdup(s_key->dk_key_name);
+ r_key->rk_Public_Key = (R_RSA_PUBLIC_KEY *)
+ malloc(sizeof(R_RSA_PUBLIC_KEY));
+ if (r_key->rk_Public_Key == NULL) {
+ EREPORT(("dst_rsaref_from_dns_key(): Memory allocation error 3\n"));
+ return (0);
+ }
+ memset(r_key->rk_Public_Key, 0, sizeof(R_RSA_PUBLIC_KEY));
+ key_ptr = (u_char *) key;
+ bytes = (int) *key_ptr++; /* length of exponent in bytes */
+ if (bytes == 0) { /* special case for long exponents */
+ bytes = (int) dst_s_get_int16(key_ptr);
+ key_ptr += sizeof(u_int16_t);
+ }
+ if (bytes > MAX_RSA_MODULUS_LEN) {
+ dst_rsaref_free_key_structure(r_key);
+ return (-1);
+ }
+ memcpy(&r_key->rk_Public_Key->exponent[MAX_RSA_MODULUS_LEN - bytes],
+ key_ptr, bytes);
+
+ key_ptr += bytes; /* beginning of modulus */
+ bytes = len - bytes - 1; /* length of modulus */
+ if (bytes > MAX_RSA_MODULUS_LEN) {
+ dst_rsaref_free_key_structure(r_key);
+ return (-1);
+ }
+ memcpy(&r_key->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - bytes],
+ key_ptr, bytes);
+ r_key->rk_Public_Key->bits = bytes * 8;
+ s_key->dk_id = (u_int16_t) dst_s_get_int16((u_char *)
+ &r_key->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - 3]);
+ s_key->dk_key_size = r_key->rk_Public_Key->bits;
+
+ return (1);
+}
+
+
+/*
+ * dst_rsaref_key_to_file_format
+ * Encodes an RSA Key into the portable file format.
+ * Parameters
+ * rkey RSA KEY structure
+ * buff output buffer
+ * buff_len size of output buffer
+ * Return
+ * 0 Failure - null input rkey
+ * -1 Failure - not enough space in output area
+ * N Success - Length of data returned in buff
+ */
+
+static int
+dst_rsaref_key_to_file_format(const DST_KEY *in_key, u_char *buff,
+ const int buff_len)
+{
+ u_char *bp;
+ int len, b_len;
+ R_RSA_PRIVATE_KEY *rkey;
+
+ if (in_key == NULL || in_key->dk_KEY_struct == NULL)
+ return (-1);
+ rkey = (R_RSA_PRIVATE_KEY *)
+ ((RSA_Key *) in_key->dk_KEY_struct)->rk_Private_Key;
+ if (rkey == NULL) /* no output */
+ return (0);
+ if (buff == NULL || buff_len <= (int) strlen(key_file_fmt_str))
+ return (-1); /* no OR not enough space in output area */
+
+ memset(buff, 0, buff_len); /* just in case */
+ /* write file header */
+ sprintf(buff, key_file_fmt_str, KEY_FILE_FORMAT, KEY_RSA, "RSA");
+
+ bp = (char *) strchr(buff, '\0');
+ b_len = buff_len - (bp - buff);
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Modulus: ",
+ rkey->modulus,
+ MAX_RSA_MODULUS_LEN)) <= 0)
+ return (-1);
+
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PublicExponent: ",
+ rkey->publicExponent,
+ MAX_RSA_MODULUS_LEN)) <= 0)
+ return (-2);
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "PrivateExponent: ",
+ rkey->exponent,
+ MAX_RSA_MODULUS_LEN)) <= 0)
+ return (-3);
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime1: ",
+ rkey->prime[0],
+ MAX_RSA_PRIME_LEN)) < 0)
+ return (-4);
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Prime2: ",
+ rkey->prime[1],
+ MAX_RSA_PRIME_LEN)) < 0)
+ return (-5);
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent1: ",
+ rkey->primeExponent[0],
+ MAX_RSA_PRIME_LEN)) < 0)
+ return (-6);
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Exponent2: ",
+ rkey->primeExponent[1],
+ MAX_RSA_PRIME_LEN)) < 0)
+ return (-7);
+ bp += len;
+ b_len -= len;
+ if ((len = dst_s_conv_bignum_u8_to_b64(bp, b_len, "Coefficient: ",
+ rkey->coefficient,
+ MAX_RSA_PRIME_LEN)) < 0)
+ return (-8);
+ bp += len;
+ b_len -= len;
+ return (buff_len - b_len);
+}
+
+
+/*
+ * dst_rsaref_key_from_file_format
+ * Converts contents of a private key file into a private RSA key.
+ * Parameters
+ * r_key structure to put key into
+ * buff buffer containing the encoded key
+ * buff_len the length of the buffer
+ * Return
+ * n >= 0 Foot print of the key converted
+ * n < 0 Error in conversion
+ */
+
+static int
+dst_rsaref_key_from_file_format(DST_KEY *d_key, const u_char *buff,
+ const int buff_len)
+{
+ const char *p = (char *) buff;
+ R_RSA_PRIVATE_KEY key;
+ int foot = -1;
+ RSA_Key *r_key;
+
+ if (d_key == NULL || buff == NULL || buff_len < 0)
+ return (-1);
+
+ memset(&key, 0, sizeof(key));
+
+ if (!dst_s_verify_str(&p, "Modulus: "))
+ return (-3);
+
+ if (!dst_s_conv_bignum_b64_to_u8(&p, key.modulus, MAX_RSA_MODULUS_LEN))
+ return (-4);
+
+ key.bits = dst_s_calculate_bits(key.modulus, MAX_RSA_MODULUS_BITS);
+
+ while (*++p && p < (char *) &buff[buff_len]) {
+ if (dst_s_verify_str(&p, "PublicExponent: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p,
+ key.publicExponent,
+ MAX_RSA_MODULUS_LEN))
+ return (-5);
+ } else if (dst_s_verify_str(&p, "PrivateExponent: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p, key.exponent,
+ MAX_RSA_MODULUS_LEN))
+ return (-6);
+ } else if (dst_s_verify_str(&p, "Prime1: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p, key.prime[0],
+ MAX_RSA_PRIME_LEN))
+ return (-7);
+ } else if (dst_s_verify_str(&p, "Prime2: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p, key.prime[1],
+ MAX_RSA_PRIME_LEN))
+ return (-8);
+ } else if (dst_s_verify_str(&p, "Exponent1: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p,
+ key.primeExponent[0],
+ MAX_RSA_PRIME_LEN))
+ return (-9);
+ } else if (dst_s_verify_str(&p, "Exponent2: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p,
+ key.primeExponent[1],
+ MAX_RSA_PRIME_LEN))
+ return (-10);
+ } else if (dst_s_verify_str(&p, "Coefficient: ")) {
+ if (!dst_s_conv_bignum_b64_to_u8(&p, key.coefficient,
+ MAX_RSA_PRIME_LEN))
+ return (-11);
+ } else {
+ EREPORT(("dst_rsaref_key_from_file_format: Bad keyword %s\n", p));
+ return (-12);
+ }
+ } /* while p */
+
+ r_key = (RSA_Key *) malloc(sizeof(RSA_Key));
+ if (r_key == NULL) {
+ return (-2);
+ }
+ memset(r_key, 0, sizeof(*r_key));
+
+ r_key->rk_Private_Key =
+ (R_RSA_PRIVATE_KEY *) malloc(sizeof(R_RSA_PRIVATE_KEY));
+ if (r_key->rk_Private_Key == NULL) {
+ EREPORT(("dst_rsaref_key_from_file_format: Memory allocation error\n"));
+ return (-13);
+ }
+ r_key->rk_Public_Key = (R_RSA_PUBLIC_KEY *) r_key->rk_Private_Key;
+ memcpy(r_key->rk_Private_Key, &key, sizeof(R_RSA_PRIVATE_KEY));
+
+ r_key->rk_signer = strdup(d_key->dk_key_name);
+ d_key->dk_KEY_struct = (void *) r_key;
+ d_key->dk_key_size = r_key->rk_Private_Key->bits;
+ d_key->dk_id = (u_int16_t) dst_s_get_int16((u_char *)
+ &r_key->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - 3]);
+ foot = (int) d_key->dk_id;
+ return (foot);
+}
+
+
+
+/*
+ * dst_rsaref_compare_keys
+ * Compare two keys for equality.
+ * Return
+ * 0 The keys are equal
+ * NON-ZERO The keys are not equal
+ */
+
+static int
+dst_rsaref_compare_keys(const DST_KEY *dkey1, const DST_KEY *dkey2)
+{
+ RSA_Key *rkey1 = (RSA_Key *) dkey1->dk_KEY_struct;
+ RSA_Key *rkey2 = (RSA_Key *) dkey2->dk_KEY_struct;
+
+ if (rkey1 == NULL && rkey2 == NULL)
+ return (0); /* same */
+ else if (rkey1 == NULL)
+ return (1);
+ else if (rkey2 == NULL)
+ return (2);
+ return (memcmp(rkey1->rk_Public_Key, rkey2->rk_Public_Key,
+ sizeof(R_RSA_PUBLIC_KEY)));
+}
+
+/*
+ * dst_rsaref_generate_keypair
+ * Generates unique keys that are hard to predict.
+ * Parameters
+ * key generic Key structure
+ * exp the public exponent
+ * Return
+ * 0 Failure
+ * 1 Success
+ */
+
+static int
+dst_rsaref_generate_keypair(DST_KEY *key, const int exp)
+{
+ R_RSA_PUBLIC_KEY *public;
+ R_RSA_PRIVATE_KEY *private;
+ R_RSA_PROTO_KEY proto;
+ R_RANDOM_STRUCT randomStruct;
+ RSA_Key *rsa;
+ int status;
+
+ if (key == NULL || key->dk_alg != KEY_RSA)
+ return (0);
+ if (key->dk_key_size < MIN_RSA_MODULUS_BITS ||
+ key->dk_key_size > MAX_RSA_MODULUS_BITS) {
+ EREPORT(("dst_rsaref_generate_keypair: Invalid key size\n"));
+ return (0); /* these are the limits on key size in RSAREF */
+ }
+ /* allocate space */
+ if ((public = (R_RSA_PUBLIC_KEY *) malloc(sizeof(R_RSA_PUBLIC_KEY)))
+ == NULL) {
+ EREPORT(("dst_rsaref_generate_keypair: Memory allocation error 1\n"));
+ return (0);
+ }
+ if ((private = (R_RSA_PRIVATE_KEY *) malloc(sizeof(R_RSA_PRIVATE_KEY)))
+ == NULL) {
+ EREPORT(("dst_rsaref_generate_keypair: Memory allocation error 2\n"));
+ return (0);
+ }
+ if ((rsa = (RSA_Key *) malloc(sizeof(RSA_Key))) == NULL) {
+ EREPORT(("dst_rsaref_generate_keypair: Memory allocation error 3\n"));
+ return (0);
+ }
+ memset(public, 0, sizeof(*public));
+ memset(private, 0, sizeof(*private));
+
+ proto.bits = key->dk_key_size;
+ proto.useFermat4 = exp ? 0x1 : 0x0; /* 1 for f4=65537, 0 for f0=3 */
+ EREPORT(("\ndst_rsaref_generate_keypair: Generating KEY for %s Please wait\n",
+ key->dk_key_name));
+
+ /* set up random seed */
+ dst_rsaref_init_random_struct(&randomStruct);
+
+ /* generate keys */
+ status = R_GeneratePEMKeys(public, private, &proto, &randomStruct);
+ if (status) {
+ EREPORT(("dst_rsaref_generate_keypair: No Key Pair generated %d\n",
+ status));
+ SAFE_FREE(public);
+ SAFE_FREE(private);
+ SAFE_FREE(rsa);
+ return (0);
+ }
+ memset(rsa, 0, sizeof(*rsa));
+ rsa->rk_signer = key->dk_key_name;
+ rsa->rk_Private_Key = private;
+ rsa->rk_Public_Key = public;
+ key->dk_KEY_struct = (void *) rsa;
+
+ key->dk_id = (u_int16_t) dst_s_get_int16((u_char *)
+ &rsa->rk_Public_Key->modulus[MAX_RSA_MODULUS_LEN - 3]);
+ return (1);
+}
+
+
+/*
+ * dst_rsaref_free_key_structure
+ * Frees all dynamicly allocated structures in r_key
+ */
+
+static void *
+dst_rsaref_free_key_structure(void *v_key)
+{
+ RSA_Key *r_key = (RSA_Key *) v_key;
+
+ if (r_key != NULL) {
+ if ((void *) r_key->rk_Private_Key == (void *) r_key->rk_Public_Key)
+ r_key->rk_Public_Key = NULL;
+ SAFE_FREE(r_key->rk_Private_Key);
+ SAFE_FREE(r_key->rk_Public_Key);
+ SAFE_FREE(r_key->rk_signer);
+ SAFE_FREE(r_key);
+ }
+ return (NULL);
+}
+
+
+/*
+ * dst_rsaref_init_random_struct
+ * A random seed value is used in key generation.
+ * This routine gets a bunch of system values to randomize the
+ * randomstruct. A number of system calls are used to get somewhat
+ * unpredicable values, then a special function dst_s_prandom() is called
+ * that will do some magic depending on the system used.
+ * If this function is executed on reasonably busy machine then the values
+ * that prandom uses are hard to
+ * 1. Predict
+ * 2. Regenerate
+ * 3. Hard to spy on as nothing is stored to disk and data is consumed
+ * as fast as it is generated.
+ */
+
+static void
+dst_rsaref_init_random_struct(R_RANDOM_STRUCT * randomstruct)
+{
+ unsigned bytesNeeded;
+ struct timeval tv;
+ u_char *array;
+ int n;
+
+ R_RandomInit(randomstruct);
+
+ /* The runtime of the script is unpredictable within some range
+ * thus I'm getting the time of day again as this is an hard to guess
+ * value and the number of characters of the output from the script is
+ * hard to guess.
+ * This must be the FIRST CALL
+ */
+ gettimeofday(&tv, 0);
+ R_RandomUpdate(randomstruct, (u_char *) &tv,
+ sizeof(struct timeval));
+
+ /*
+ * first find out how many bytes I need
+ */
+ R_GetRandomBytesNeeded(&bytesNeeded, randomstruct);
+
+ /*
+ * get a storage area for it addjust the area for the possible
+ * side effects of digest functions writing out in blocks
+ */
+ array = (u_char *) malloc(bytesNeeded);
+
+ /* extract the random data from /dev/random if present, generate
+ * it if not present
+ * first fill the buffer with semi random data
+ * then fill as much as possible with good random data
+ */
+ n = dst_random(DST_RAND_SEMI, bytesNeeded, array);
+ n += dst_random(DST_RAND_KEY, bytesNeeded, array);
+ if (n <= bytesNeeded) {
+ SAFE_FREE(array);
+ return(0);
+ }
+
+ /* supply the random data (even if it is larger than requested) */
+ R_RandomUpdate(randomstruct, array, bytesNeeded);
+
+ SAFE_FREE(array);
+
+ R_GetRandomBytesNeeded(&bytesNeeded, randomstruct);
+ if (bytesNeeded) {
+ EREPORT(("InitRandomStruct() didn't initialize enough randomness\n"));
+ exit(33);
+ }
+}
+
+
+#else
+int /* rsaref is not available */
+dst_rsaref_init()
+{
+ return (0);
+}
+#endif /* RSAREF */
diff --git a/contrib/bind/lib/dst/support.c b/contrib/bind/lib/dst/support.c
new file mode 100644
index 0000000..d50aa07
--- /dev/null
+++ b/contrib/bind/lib/dst/support.c
@@ -0,0 +1,461 @@
+static const char rcsid[] = "$Header: /proj/cvs/isc/bind/src/lib/dst/support.c,v 1.8 1999/10/13 16:39:24 vixie Exp $";
+
+
+/*
+ * Portions Copyright (c) 1995-1998 by Trusted Information Systems, Inc.
+ *
+ * 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 TRUSTED INFORMATION SYSTEMS
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * TRUSTED INFORMATION SYSTEMS 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 THE SOFTWARE.
+ */
+
+#include "port_before.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+
+#include "dst_internal.h"
+
+#include "port_after.h"
+/*
+ * dst_s_conv_bignum_u8_to_b64
+ * This function converts binary data stored as a u_char[] to a
+ * base-64 string. Leading zeroes are discarded. If a header is
+ * supplied, it is prefixed to the input prior to encoding. The
+ * output is \n\0 terminated (the \0 is not included in output length).
+ * Parameters
+ * out_buf binary data to convert
+ * header character string to prefix to the output (label)
+ * bin_data binary data
+ * bin_len size of binary data
+ * Return
+ * -1 not enough space in output work area
+ * 0 no output
+ * >0 number of bytes written to output work area
+ */
+
+int
+dst_s_conv_bignum_u8_to_b64(char *out_buf, const int out_len,
+ const char *header, const u_char *bin_data,
+ const int bin_len)
+{
+ const u_char *bp = bin_data;
+ char *op = out_buf;
+ int lenh = 0, len64 = 0;
+ int local_in_len = bin_len;
+ int local_out_len = out_len;
+
+ if (bin_data == NULL || bin_len <= 0) /* no data no */
+ return (0);
+
+ if (out_buf == NULL || out_len <= 0) /* no output_work area */
+ return (-1);
+
+ /* suppress leading \0 */
+ for (; (*bp == 0x0) && (local_in_len > 0); local_in_len--)
+ bp++;
+
+ if (header) { /* add header to output string */
+ lenh = strlen(header);
+ if (lenh < out_len)
+ memcpy(op, header, lenh);
+ else
+ return (-1);
+ local_out_len -= lenh;
+ op += lenh;
+ }
+ len64 = b64_ntop(bp, local_in_len, op, local_out_len - 2);
+ if (len64 < 0)
+ return (-1);
+ op += len64++;
+ *(op++) = '\n'; /* put CR in the output */
+ *op = '\0'; /* make sure output is 0 terminated */
+ return (lenh + len64);
+}
+
+
+/*
+ * dst_s_verify_str()
+ * Validate that the input string(*str) is at the head of the input
+ * buffer(**buf). If so, move the buffer head pointer (*buf) to
+ * the first byte of data following the string(*str).
+ * Parameters
+ * buf Input buffer.
+ * str Input string.
+ * Return
+ * 0 *str is not the head of **buff
+ * 1 *str is the head of **buff, *buf is is advanced to
+ * the tail of **buf.
+ */
+
+int
+dst_s_verify_str(const char **buf, const char *str)
+{
+ int b, s;
+ if (*buf == NULL) /* error checks */
+ return (0);
+ if (str == NULL || *str == '\0')
+ return (1);
+
+ b = strlen(*buf); /* get length of strings */
+ s = strlen(str);
+ if (s > b || strncmp(*buf, str, s)) /* check if same */
+ return (0); /* not a match */
+ (*buf) += s; /* advance pointer */
+ return (1);
+}
+
+
+/*
+ * dst_s_conv_bignum_b64_to_u8
+ * Read a line of base-64 encoded string from the input buffer,
+ * convert it to binary, and store it in an output area. The
+ * input buffer is read until reaching a newline marker or the
+ * end of the buffer. The binary data is stored in the last X
+ * number of bytes of the output area where X is the size of the
+ * binary output. If the operation is successful, the input buffer
+ * pointer is advanced. This procedure does not do network to host
+ * byte order conversion.
+ * Parameters
+ * buf Pointer to encoded input string. Pointer is updated if
+ * function is successfull.
+ * loc Output area.
+ * loclen Size in bytes of output area.
+ * Return
+ * >0 Return = number of bytes of binary data stored in loc.
+ * 0 Failure.
+ */
+
+int
+dst_s_conv_bignum_b64_to_u8(const char **buf, u_char *loc, const int loclen)
+{
+ int blen;
+ char *bp;
+ u_char bstr[RAW_KEY_SIZE];
+
+ if (buf == NULL || *buf == NULL) { /* error checks */
+ EREPORT(("dst_s_conv_bignum_b64_to_u8: null input buffer.\n"));
+ return (0);
+ }
+ bp = strchr(*buf, '\n'); /* find length of input line */
+ if (bp != NULL)
+ *bp = (u_char) NULL;
+
+ blen = b64_pton(*buf, bstr, sizeof(bstr));
+ if (blen <= 0) {
+ EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is null.\n"));
+ return (0);
+ }
+ else if (loclen < blen) {
+ EREPORT(("dst_s_conv_bignum_b64_to_u8: decoded value is longer than output buffer.\n"));
+ return (0);
+ }
+ if (bp)
+ *buf = bp; /* advancing buffer past \n */
+ memset(loc, 0, loclen - blen); /* clearing unused output area */
+ memcpy(loc + loclen - blen, bstr, blen); /* write last blen bytes */
+ return (blen);
+}
+
+
+/*
+ * dst_s_calculate_bits
+ * Given a binary number represented in a u_char[], determine
+ * the number of significant bits used.
+ * Parameters
+ * str An input character string containing a binary number.
+ * max_bits The maximum possible significant bits.
+ * Return
+ * N The number of significant bits in str.
+ */
+
+int
+dst_s_calculate_bits(const u_char *str, const int max_bits)
+{
+ const u_char *p = str;
+ u_char i, j = 0x80;
+ int bits;
+ for (bits = max_bits; *p == 0x00 && bits > 0; p++)
+ bits -= 8;
+ for (i = *p; (i & j) != j; j >>= 1)
+ bits--;
+ return (bits);
+}
+
+
+/*
+ * calculates a checksum used in kmt for a id.
+ * takes an array of bytes and a length.
+ * returns a 16 bit checksum.
+ */
+u_int16_t
+dst_s_id_calc(const u_char *key, const int keysize)
+{
+ u_int32_t ac;
+ const u_char *kp = key;
+ int size = keysize;
+
+ if (!key || (keysize <= 0))
+ return (-1);
+
+ for (ac = 0; size > 1; size -= 2, kp += 2)
+ ac += ((*kp) << 8) + *(kp + 1);
+
+ if (size > 0)
+ ac += ((*kp) << 8);
+ ac += (ac >> 16) & 0xffff;
+
+ return (ac & 0xffff);
+}
+
+/*
+ * dst_s_dns_key_id() Function to calculated DNSSEC footprint from KEY reocrd
+ * rdata (all of record)
+ * Input:
+ * dns_key_rdata: the raw data in wire format
+ * rdata_len: the size of the input data
+ * Output:
+ * the key footprint/id calcuated from the key data
+ */
+u_int16_t
+dst_s_dns_key_id(const u_char *dns_key_rdata, const int rdata_len)
+{
+ int key_data = 4;
+
+ if (!dns_key_rdata || (rdata_len < key_data))
+ return 0;
+
+ /* check the extended parameters bit in the DNS Key RR flags */
+ if (dst_s_get_int16(dns_key_rdata) & DST_EXTEND_FLAG)
+ key_data += 2;
+
+ /* compute id */
+ if (dns_key_rdata[3] == KEY_RSA) /* Algorithm RSA */
+ return dst_s_get_int16((u_char *)
+ &dns_key_rdata[rdata_len - 3]);
+ else
+ /* compute a checksum on the key part of the key rr */
+ return dst_s_id_calc(&dns_key_rdata[key_data],
+ (rdata_len - key_data));
+}
+
+/*
+ * dst_s_get_int16
+ * This routine extracts a 16 bit integer from a two byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A two byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int16_t
+dst_s_get_int16(const u_char *buf)
+{
+ register u_int16_t a = 0;
+ a = ((u_int16_t)(buf[0] << 8)) | ((u_int16_t)(buf[1]));
+ return (a);
+}
+
+
+/*
+ * dst_s_get_int32
+ * This routine extracts a 32 bit integer from a four byte character
+ * string. The character string is assumed to be in network byte
+ * order and may be unaligned. The number returned is in host order.
+ * Parameter
+ * buf A four byte character string.
+ * Return
+ * The converted integer value.
+ */
+
+u_int32_t
+dst_s_get_int32(const u_char *buf)
+{
+ register u_int32_t a = 0;
+ a = ((u_int32_t)(buf[0] << 24)) | ((u_int32_t)(buf[1] << 16)) |
+ ((u_int32_t)(buf[2] << 8)) | ((u_int32_t)(buf[3]));
+ return (a);
+}
+
+
+/*
+ * dst_s_put_int16
+ * Take a 16 bit integer and store the value in a two byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a two byte character string.
+ * val 16 bit integer.
+ */
+
+void
+dst_s_put_int16(u_int8_t *buf, const u_int16_t val)
+{
+ buf[0] = (u_int8_t)(val >> 8);
+ buf[1] = (u_int8_t)(val);
+}
+
+
+/*
+ * dst_s_put_int32
+ * Take a 32 bit integer and store the value in a four byte
+ * character string. The integer is assumed to be in network
+ * order and the string is returned in host order.
+ *
+ * Parameters
+ * buf Storage for a four byte character string.
+ * val 32 bit integer.
+ */
+
+void
+dst_s_put_int32(u_int8_t *buf, const u_int32_t val)
+{
+ buf[0] = (u_int8_t)(val >> 24);
+ buf[1] = (u_int8_t)(val >> 16);
+ buf[2] = (u_int8_t)(val >> 8);
+ buf[3] = (u_int8_t)(val);
+}
+
+
+/*
+ * dst_s_filename_length
+ *
+ * This function returns the number of bytes needed to hold the
+ * filename for a key file. '/', '\' and ':' are not allowed.
+ * form: K<keyname>+<alg>+<id>.<suffix>
+ *
+ * Returns 0 if the filename would contain either '\', '/' or ':'
+ */
+size_t
+dst_s_filename_length(const char *name, const char *suffix)
+{
+ if (name == NULL)
+ return (0);
+ if (strrchr(name, '\\'))
+ return (0);
+ if (strrchr(name, '/'))
+ return (0);
+ if (strrchr(name, ':'))
+ return (0);
+ if (suffix == NULL)
+ return (0);
+ if (strrchr(suffix, '\\'))
+ return (0);
+ if (strrchr(suffix, '/'))
+ return (0);
+ if (strrchr(suffix, ':'))
+ return (0);
+ return (1 + strlen(name) + 6 + strlen(suffix));
+}
+
+
+/*
+ * dst_s_build_filename ()
+ * Builds a key filename from the key name, it's id, and a
+ * suffix. '\', '/' and ':' are not allowed. fA filename is of the
+ * form: K<keyname><id>.<suffix>
+ * form: K<keyname>+<alg>+<id>.<suffix>
+ *
+ * Returns -1 if the conversion fails:
+ * if the filename would be too long for space allotted
+ * if the filename would contain a '\', '/' or ':'
+ * Returns 0 on success
+ */
+
+int
+dst_s_build_filename(char *filename, const char *name, u_int16_t id,
+ int alg, const char *suffix, size_t filename_length)
+{
+ u_int32_t my_id;
+ if (filename == NULL)
+ return (-1);
+ memset(filename, 0, filename_length);
+ if (name == NULL)
+ return (-1);
+ if (suffix == NULL)
+ return (-1);
+ if (filename_length < 1 + strlen(name) + 4 + 6 + 1 + strlen(suffix))
+ return (-1);
+ my_id = id;
+ sprintf(filename, "K%s+%03d+%05d.%s", name, alg, my_id,
+ (char *) suffix);
+ if (strrchr(filename, '/'))
+ return (-1);
+ if (strrchr(filename, '\\'))
+ return (-1);
+ if (strrchr(filename, ':'))
+ return (-1);
+ return (0);
+}
+
+/*
+ * dst_s_fopen ()
+ * Open a file in the dst_path directory. If perm is specified, the
+ * file is checked for existence first, and not opened if it exists.
+ * Parameters
+ * filename File to open
+ * mode Mode to open the file (passed directly to fopen)
+ * perm File permission, if creating a new file.
+ * Returns
+ * NULL Failure
+ * NON-NULL (FILE *) of opened file.
+ */
+FILE *
+dst_s_fopen(const char *filename, const char *mode, int perm)
+{
+ FILE *fp;
+ char pathname[PATH_MAX];
+ int plen = sizeof(pathname);
+
+ if (*dst_path != '\0') {
+ strcpy(pathname, dst_path);
+ plen -= strlen(pathname);
+ }
+ else
+ pathname[0] = '\0';
+
+ if (plen > strlen(filename))
+ strncpy(&pathname[PATH_MAX - plen], filename, plen-1);
+ else
+ return (NULL);
+
+ fp = fopen(pathname, mode);
+ if (perm)
+ chmod(pathname, perm);
+ return (fp);
+}
+
+void
+dst_s_dump(const int mode, const u_char *data, const int size,
+ const char *msg)
+{
+ if (size > 0) {
+#ifdef LONG_TEST
+ static u_char scratch[1000];
+ int n ;
+ n = b64_ntop(data, scratch, size, sizeof(scratch));
+ printf("%s: %x %d %s\n", msg, mode, n, scratch);
+#else
+ printf("%s,%x %d\n", msg, mode, size);
+#endif
+ }
+}
OpenPOWER on IntegriCloud