diff options
author | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1999-11-30 02:43:11 +0000 |
commit | 4ef23ce6957fc75fc005885496d605fed48213e1 (patch) | |
tree | 7828b08c74ef918938b1b853c98f0cb41edac52c /contrib/bind/lib/dst | |
parent | 67e0f3ce71726dc4058c2f80a813341a59244dbd (diff) | |
download | FreeBSD-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/Makefile | 96 | ||||
-rw-r--r-- | contrib/bind/lib/dst/README | 27 | ||||
-rw-r--r-- | contrib/bind/lib/dst/bsafe_link.c | 1125 | ||||
-rw-r--r-- | contrib/bind/lib/dst/cylink_link.c | 676 | ||||
-rw-r--r-- | contrib/bind/lib/dst/dst_api.c | 1068 | ||||
-rw-r--r-- | contrib/bind/lib/dst/dst_internal.h | 163 | ||||
-rw-r--r-- | contrib/bind/lib/dst/eay_dss_link.c | 624 | ||||
-rw-r--r-- | contrib/bind/lib/dst/hmac_link.c | 493 | ||||
-rw-r--r-- | contrib/bind/lib/dst/md5.h | 101 | ||||
-rw-r--r-- | contrib/bind/lib/dst/md5_dgst.c | 368 | ||||
-rw-r--r-- | contrib/bind/lib/dst/md5_locl.h | 190 | ||||
-rw-r--r-- | contrib/bind/lib/dst/prandom.c | 851 | ||||
-rw-r--r-- | contrib/bind/lib/dst/rsaref_link.c | 754 | ||||
-rw-r--r-- | contrib/bind/lib/dst/support.c | 461 |
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 + } +} |