summaryrefslogtreecommitdiff
path: root/sbin/ipsec/photurisd/exchange.c
diff options
context:
space:
mode:
authorNiels Provos <provos@cvs.openbsd.org>1997-07-18 22:48:52 +0000
committerNiels Provos <provos@cvs.openbsd.org>1997-07-18 22:48:52 +0000
commita182901164f2df77714485fcf4f81b0cdcb0e0b5 (patch)
tree080dc3e1b75e07f244a3f6c7a710c0e9e2782602 /sbin/ipsec/photurisd/exchange.c
parentabe3a6221fda054003729a6f7d6d61dbb31e77b0 (diff)
initial import of the photuris keymanagement daemon
Diffstat (limited to 'sbin/ipsec/photurisd/exchange.c')
-rw-r--r--sbin/ipsec/photurisd/exchange.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/sbin/ipsec/photurisd/exchange.c b/sbin/ipsec/photurisd/exchange.c
new file mode 100644
index 00000000000..0198bda91e1
--- /dev/null
+++ b/sbin/ipsec/photurisd/exchange.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Niels Provos.
+ * 4. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * exchange.c:
+ *
+ */
+
+#ifndef lint
+static char rcsid[] = "$Id: exchange.c,v 1.1 1997/07/18 22:48:48 provos Exp $";
+#endif
+
+#define _EXCHANGE_C_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "config.h"
+#include "state.h"
+#include "gmp.h"
+#include "exchange.h"
+#include "modulus.h"
+#include "attributes.h"
+#include "buffer.h"
+#include "cookie.h"
+#include "schedule.h"
+#include "scheme.h"
+#include "errlog.h"
+
+void
+make_random_mpz(mpz_t a, mpz_t bits)
+{
+ mpz_t d;
+
+ mpz_init_set_str(d, "0x100000000", 0);
+
+ /* XXX - we generate too many bits */
+
+ mpz_set_ui(a, 0);
+ mpz_cdiv_q_ui(bits,bits,32); /* We work in 2^32 chucks */
+
+ while(mpz_cmp_ui(bits,0)>0) {
+ mpz_mul(a, a, d); /* c = a * 0x100000000 */
+ mpz_add_ui(a, a, arc4random()); /* d = random */
+ mpz_sub_ui(bits, bits, 1);
+ }
+ mpz_clear(d);
+}
+
+/*
+ * Get the number of bits from a variable precision number
+ * according to draft-simpson-photuris-11
+ */
+
+u_int8_t *
+varpre_get_number_bits(mpz_t bits, u_int8_t *varpre)
+{
+ u_int8_t blocks;
+ mpz_t a;
+
+ mpz_init_set_ui(a,0);
+
+ mpz_set_ui(bits, 0);
+ if (varpre == NULL)
+ return NULL;
+
+ if(*varpre == 255 && *(varpre+1) == 255) {
+ blocks = 6;
+ varpre += 2;
+ mpz_set_ui(bits, 16776960);
+ } else if(*varpre == 255) {
+ blocks = 3;
+ mpz_set_ui(bits, 65280);
+ varpre++;
+ } else
+ blocks = 2;
+
+ while(blocks-->0) {
+ mpz_mul_ui(a,a,256);
+ mpz_add_ui(a,a,*varpre);
+ varpre++;
+ }
+ mpz_add(bits,a,bits); /* Add the above bits */
+ mpz_clear(a);
+ return varpre;
+}
+
+/*
+ * Convert a variable precision number to a mpz number
+ */
+
+u_int8_t *
+mpz_set_varpre(mpz_t a, u_int8_t *varpre)
+{
+ u_int8_t *p;
+ mpz_t bytes;
+
+ mpz_init(bytes);
+ mpz_set_ui(a, 0);
+ p = varpre_get_number_bits(bytes, varpre);
+ mpz_cdiv_q_ui(bytes,bytes,8); /* Number of bytes */
+ while(mpz_cmp_ui(bytes,0)) {
+ mpz_mul_ui(a, a, 256);
+ mpz_sub_ui(bytes, bytes, 1);
+ mpz_add_ui(a, a, *p);
+ p++;
+ }
+ mpz_clear(bytes);
+
+ return p;
+}
+
+u_int8_t *
+mpz_init_set_varpre(mpz_t a, u_int8_t *varpre)
+{
+ mpz_init(a);
+ return mpz_set_varpre(a,varpre);
+}
+
+void
+mpz_get_number_bits(mpz_t rop, mpz_t p)
+{
+ size_t bits;
+
+ bits = mpz_sizeinbase(p, 2);
+ mpz_set_ui(rop, bits);
+}
+
+int
+mpz_to_varpre(u_int8_t *value, u_int16_t *size, mpz_t p, mpz_t gbits)
+{
+ u_int16_t header;
+ mpz_t a, tmp, bits, bytes;
+ u_int32_t count;
+
+ mpz_init(bytes);
+ mpz_init(tmp);
+ mpz_init_set(bits, gbits);
+
+ mpz_cdiv_q_ui(bytes, bits, 8);
+
+ count = mpz_get_ui(bytes);
+
+ /* XXX - only support 4 octets at the moment */
+ if(mpz_cmp_ui(bits, 65279) > 0) {
+ mpz_sub_ui(bits,bits,65280);
+ value[0] = 255;
+ value[3] = mpz_fdiv_qr_ui(bits,tmp,bits,256) & 0xFF;
+ value[2] = mpz_fdiv_qr_ui(bits,tmp,bits,256) & 0xFF;
+ value[1] = mpz_fdiv_qr_ui(bits,tmp,bits,256) & 0xFF;
+ header = 4;
+ } else {
+ value[1] = mpz_fdiv_qr_ui(bits,tmp,bits,256) & 0xFF;
+ value[0] = mpz_fdiv_qr_ui(bits,tmp,bits,256) & 0xFF;
+ header = 2;
+ }
+
+ if(mpz_cmp_ui(bytes, *size-header)>0)
+ return -1; /* Not enough buffer */
+
+ mpz_init_set(a, p);
+
+ /* XXX - int16 vs. int32 */
+ *size = count+header;
+
+ while(count>0) {
+ count--;
+ value[count+header]=mpz_fdiv_qr_ui(a, tmp, a, 256);
+ }
+ mpz_clear(a);
+ mpz_clear(tmp);
+ mpz_clear(bits);
+ mpz_clear(bytes);
+
+ return 0;
+}
+
+/*
+ * Finds to a given modulus and generator cached information
+ * which is used to create the private value and exchange value
+ */
+
+int
+exchange_make_values(struct stateob *st, mpz_t modulus, mpz_t generator)
+{
+ struct moduli_cache *p, *tmp;
+ u_int8_t *mod;
+ time_t tm;
+
+ tm = time(NULL);
+
+ /* See if we have this cached already */
+ if((p = mod_find_modgen(modulus,generator)) == NULL) {
+ /* Create a new modulus, generator pair */
+ if((p = mod_new_modgen(modulus,generator)) == NULL) {
+ mpz_clear(generator);
+ mpz_clear(modulus);
+ log_error(1, "Not enough memory in exchange_make_values()");
+ return -1;
+ }
+ mod_insert(p);
+ }
+ /* If we don't have a private value calculate a new one */
+ if(p->lifetime < tm || !mpz_cmp_ui(p->private_value,0)) {
+ if (p->exchangevalue != NULL)
+ free(p->exchangevalue);
+
+ /* See if we can find a cached private value */
+ if((tmp = mod_find_modulus(modulus)) != NULL &&
+ tmp->lifetime > tm && mpz_cmp_ui(tmp->private_value,0)) {
+ mpz_set(p->private_value, tmp->private_value);
+
+
+ /* Keep exchange value on same (gen,mod) pair */
+ if (!mpz_cmp(p->generator, tmp->generator)) {
+ p->exchangevalue = calloc(tmp->exchangesize,sizeof(u_int8_t));
+ if (p->exchangevalue == NULL) {
+ log_error(1, "calloc() in exchange_make_values()");
+ return -1;
+ }
+ bcopy(tmp->exchangevalue, p->exchangevalue,
+ tmp->exchangesize);
+ p->exchangesize = tmp->exchangesize;
+ } else
+ p->exchangevalue = NULL;
+
+ p->iterations = tmp->iterations;
+ p->status = tmp->status;
+ p->lifetime = tmp->lifetime;
+ } else {
+ mpz_t bits;
+
+ /*
+ * Make a new private value and change responder secrets
+ * as required by draft.
+ */
+
+ schedule_remove(REKEY, NULL);
+ schedule_insert(REKEY, REKEY_TIMEOUT, NULL, 0);
+ reset_secret();
+
+ mpz_init(bits);
+
+ p->lifetime = tm + MOD_TIMEOUT;
+ p->exchangevalue = NULL;
+
+ /* Find pointer to the VPN containing the modulus */
+ mod = scheme_get_mod(st->scheme);
+ varpre_get_number_bits(bits, mod);
+ make_random_mpz(p->private_value, bits);
+ mpz_clear(bits);
+ }
+ /* Do we need to generate a new exchange value */
+ if (p->exchangevalue == NULL) {
+ mpz_t tmp, bits;
+
+ mpz_init(tmp);
+ mpz_powm(tmp, p->generator, p->private_value, p->modulus);
+
+ mpz_init(bits);
+ mod = scheme_get_mod(st->scheme);
+ varpre_get_number_bits(bits, mod);
+
+ p->exchangesize = BUFFER_SIZE;
+ mpz_to_varpre(buffer, &(p->exchangesize), tmp, bits);
+
+ p->exchangevalue = calloc(p->exchangesize, sizeof(u_int8_t));
+ if (p->exchangevalue == NULL) {
+ log_error(1, "calloc() in exchange_make_value()");
+ mpz_clear(bits); mpz_clear(tmp);
+ return -1;
+ }
+ bcopy(buffer, p->exchangevalue, p->exchangesize);
+
+ mpz_clear(bits);
+ mpz_clear(tmp);
+ }
+ }
+ mpz_set(st->modulus, p->modulus);
+ mpz_set(st->generator, p->generator);
+ return 0;
+}
+
+/*
+ * Generates the exchange values needed for the value_request
+ * and value_response packets.
+ */
+
+int
+exchange_value_generate(struct stateob *st, u_int8_t *value, u_int16_t *size)
+{
+ mpz_t modulus,generator;
+ struct moduli_cache *p;
+ u_int8_t *varpre;
+
+ switch (ntohs(*((u_int16_t *) st->scheme))) {
+ case DH_G_2_MD5: /* DH: Generator of 2 */
+ case DH_G_2_DES_MD5: /* DH: Generator of 2 + privacy */
+ case DH_G_2_3DES_SHA1:
+ mpz_init_set_ui(generator,2);
+ break;
+ case DH_G_3_MD5:
+ case DH_G_3_DES_MD5:
+ case DH_G_3_3DES_SHA1:
+ mpz_init_set_ui(generator,3);
+ break;
+ case DH_G_5_MD5:
+ case DH_G_5_DES_MD5:
+ case DH_G_5_3DES_SHA1:
+ mpz_init_set_ui(generator,5);
+ break;
+ default:
+ log_error(0, "Unsupported exchange scheme: %d\n",
+ *((u_int16_t *)st->scheme));
+ return -1;
+ }
+
+ if ((varpre = scheme_get_mod(st->scheme)) == NULL)
+ return -1;
+
+ mpz_init_set_varpre(modulus, varpre);
+
+ if(exchange_make_values(st, modulus, generator) == -1) {
+ mpz_clear(modulus);
+ mpz_clear(generator);
+ return -1;
+ }
+
+ p = mod_find_modgen(modulus,generator);
+ if (*size < p->exchangesize)
+ return -1;
+
+ bcopy(p->exchangevalue, value, p->exchangesize);
+ mpz_clear(modulus);
+ mpz_clear(generator);
+
+ *size = p->exchangesize;
+ return 1;
+}