diff options
Diffstat (limited to 'sbin/ipsec/photurisd/handle_identity_request.c')
-rw-r--r-- | sbin/ipsec/photurisd/handle_identity_request.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/sbin/ipsec/photurisd/handle_identity_request.c b/sbin/ipsec/photurisd/handle_identity_request.c new file mode 100644 index 00000000000..145594eaf5f --- /dev/null +++ b/sbin/ipsec/photurisd/handle_identity_request.c @@ -0,0 +1,323 @@ +/* + * 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. + */ +/* + * handle_identity_request: + * receive a IDENTITY_REQUEST packet; return -1 on failure, 0 on success + * + */ + +#ifndef lint +static char rcsid[] = "$Id: handle_identity_request.c,v 1.1 1997/07/18 22:48:50 provos Exp $"; +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "config.h" +#include "photuris.h" +#include "packets.h" +#include "state.h" +#include "cookie.h" +#include "buffer.h" +#include "packet.h" +#include "encrypt.h" +#include "identity.h" +#include "spi.h" +#include "secrets.h" +#include "scheme.h" +#include "errlog.h" +#include "schedule.h" +#ifdef IPSEC +#include "kernel.h" +#endif + +int +handle_identity_request(u_char *packet, int size, char *address, + char *local_address) +{ + struct identity_message *header; + struct stateob *st; + struct spiob *spi; + u_int8_t *p, *attributes; + u_int16_t i, asize, attribsize, tmp; + u_int8_t signature[22]; /* XXX - constant */ + + if (size < IDENTITY_MESSAGE_MIN) + return -1; /* packet too small */ + + header = (struct identity_message *) packet; + + st = state_find_cookies(address, header->icookie, header->rcookie); + if (st == NULL) { + packet_size = PACKET_BUFFER_SIZE; + photuris_error_message(st, packet_buffer, &packet_size, + header->icookie, header->rcookie, + 0, BAD_COOKIE); + send_packet(); + return 0; + } + + if (st->phase != VALUE_RESPONSE && st->phase != SPI_UPDATE) + return -1; /* We don't want this packet */ + + /* Decrypt message */ + tmp = size - IDENTITY_MESSAGE_MIN; + if (packet_decrypt(st, IDENTITY_MESSAGE_CHOICE(header), &tmp) == -1) { + log_error(0, "packet_decrypt() in handle_identity_request()"); + packet_size = PACKET_BUFFER_SIZE; + photuris_error_message(st, packet_buffer, &packet_size, + header->icookie, header->rcookie, + 0, VERIFICATION_FAILURE); + send_packet(); + return -1; + } + + /* Verify message */ + if (!(i = get_identity_verification_size(st, IDENTITY_MESSAGE_CHOICE(header)))) { + packet_size = PACKET_BUFFER_SIZE; + photuris_error_message(st, packet_buffer, &packet_size, + header->icookie, header->rcookie, + 0, VERIFICATION_FAILURE); + send_packet(); + return -1; + } + + asize = IDENTITY_MESSAGE_MIN; + + p = IDENTITY_MESSAGE_CHOICE(header); + asize += p[1] + 2; + p += p[1] + 2; + asize += varpre2octets(p); + p += varpre2octets(p); + + attributes = p + i; + asize += i; /* Verification size */ + asize += packet[size-1]; /* Padding size */ + attribsize = 0; + while(asize + attribsize < size) + attribsize += attributes[attribsize+1] + 2; + + asize += attribsize; + + if (asize != size) { + log_error(0, "wrong packet size in handle_identity_request()"); + return -1; + } + + if (i > sizeof(signature)) { + log_error(0, "verification too long in handle_identity_request()"); + packet_size = PACKET_BUFFER_SIZE; + photuris_error_message(st, packet_buffer, &packet_size, + header->icookie, header->rcookie, + 0, VERIFICATION_FAILURE); + send_packet(); + return -1; + } + + bcopy(p, signature, i); + bzero(p, i); + + if (st->phase == VALUE_RESPONSE) { + /* Fill the state object, but only if we have not dont so before */ + if (st->uSPIidentver == NULL) { + if((st->uSPIidentver = calloc(i, sizeof(u_int8_t))) == NULL) { + log_error(1, "calloc() in handle_identity_request()"); + return -1; + } + bcopy(signature, st->uSPIidentver, i); + st->uSPIidentversize = i; + } + + p = IDENTITY_MESSAGE_CHOICE(header); + if (st->uSPIidentchoice == NULL) { + if((st->uSPIidentchoice = calloc(p[1]+2, sizeof(u_int8_t))) == NULL) { + log_error(1, "calloc() in handle_identity_request()"); + return -1; + } + bcopy(p, st->uSPIidentchoice, p[1]+2); + st->uSPIidentchoicesize = p[1]+2; + } + + p += p[1] + 2; + if (st->uSPIident == NULL) { + if((st->uSPIident = calloc(varpre2octets(p), sizeof(u_int8_t))) == NULL) { + log_error(1,"calloc() in handle_identity_request()"); + return -1; + } + bcopy(p, st->uSPIident, varpre2octets(p)); + } + + if (st->uSPIattrib == NULL) { + if((st->uSPIattrib = calloc(attribsize, sizeof(u_int8_t))) == NULL) { + log_error(1, "calloc() in handle_identity_request()"); + return -1; + } + bcopy(attributes, st->uSPIattrib, attribsize); + st->uSPIattribsize = attribsize; + } + + if (st->oSPIident == NULL && + get_secrets(st, (ID_REMOTE|ID_LOCAL)) == -1) { + log_error(0, "get_secrets() in in handle_identity_request()"); + return -1; + } + + } + + if (!verify_identity_verification(st, signature, packet, size)) { + if (st->phase != SPI_UPDATE) { + /* + * Clean up everything used from this packet + * but only if we did not get a valid packet before. + * Otherwise this could be used as Denial of Service. + */ + free(st->uSPIidentchoice); + st->uSPIidentchoice = NULL; st->uSPIidentchoicesize = 0; + free(st->uSPIidentver); + st->uSPIidentver = NULL; st->uSPIidentversize = 0; + free(st->uSPIattrib); + st->uSPIattrib = NULL; st->uSPIattribsize = 0; + free(st->uSPIident); + st->uSPIident = NULL; + free(st->oSPIident); + st->oSPIident = NULL; + + /* Clean up secrets */ + free(st->oSPIsecret); + st->oSPIsecret = NULL; st->oSPIsecretsize = 0; + free(st->uSPIsecret); + st->uSPIsecret = NULL; st->uSPIsecretsize = 0; + } + + log_error(0, "verification failed in handle_identity_request()"); + packet_size = PACKET_BUFFER_SIZE; + photuris_error_message(st, packet_buffer, &packet_size, + header->icookie, header->rcookie, + 0, VERIFICATION_FAILURE); + send_packet(); + return 0; + } + + if (st->phase != VALUE_RESPONSE) { + /* We got send the old packet again */ + bcopy(st->packet, packet_buffer, st->packetlen); + packet_size = st->packetlen; + + send_packet(); + return 0; + } + + /* Create SPI + choice of attributes */ + if(make_spi(st, local_address, st->oSPI, &(st->olifetime), + &(st->oSPIattrib), &(st->oSPIattribsize)) == -1) { + log_error(0, "make_spi() in handle_identity_request()"); + return -1; + } + + packet_size = PACKET_BUFFER_SIZE; + if (photuris_identity_response(st, packet_buffer, &packet_size) == -1) + return -1; + + send_packet(); + + packet_save(st, packet_buffer, packet_size); + + bcopy(header->SPI, st->uSPI, SPI_SIZE); + st->ulifetime = (header->lifetime[0] << 16) + + (header->lifetime[1] << 8) + header->lifetime[2]; + + if (st->oSPI[0] || st->oSPI[1] || st->oSPI[2] || st->oSPI[3]) { + /* Insert Owner SPI */ + if ((spi = spi_new(st->address, st->oSPI)) == NULL) { + log_error(0, "spi_new() in handle_identity_request()"); + return -1; + } + if ((spi->local_address = strdup(local_address)) == NULL) { + log_error(0, "strdup() in handle_identity_request()"); + return -1; + } + bcopy(st->icookie, spi->icookie, COOKIE_SIZE); + spi->owner = 1; + spi->attribsize = st->oSPIattribsize; + spi->attributes = calloc(spi->attribsize, sizeof(u_int8_t)); + if (spi->attributes == NULL) { + log_error(1, "calloc() in handle_identity_request()"); + spi_value_reset(spi); + return -1; + } + bcopy(st->oSPIattrib, spi->attributes, spi->attribsize); + spi->lifetime = time(NULL) + st->olifetime; + + /* Make session keys for Owner */ + make_session_keys(st, spi); + + spi_insert(spi); +#ifdef IPSEC + kernel_insert_spi(spi); +#endif + schedule_insert(UPDATE, st->olifetime/2, spi->SPI, SPI_SIZE); + } + + if (st->uSPI[0] || st->uSPI[1] || st->uSPI[2] || st->uSPI[3]) { + /* Insert User SPI */ + if ((spi = spi_new(st->address, st->uSPI)) == NULL) { + log_error(0, "spi_new() in handle_identity_request()"); + return -1; + } + if ((spi->local_address = strdup(local_address)) == NULL) { + log_error(1, "strdup() in handle_identity_request()"); + return -1; + } + bcopy(st->icookie, spi->icookie, COOKIE_SIZE); + spi->attribsize = st->uSPIattribsize; + spi->attributes = calloc(spi->attribsize, sizeof(u_int8_t)); + if (spi->attributes == NULL) { + log_error(1, "calloc() in handle_identity_request()"); + spi_value_reset(spi); + return -1; + } + bcopy(st->uSPIattrib, spi->attributes, spi->attribsize); + spi->lifetime = time(NULL) + st->ulifetime; + + /* Make session keys for User */ + make_session_keys(st, spi); + + spi_insert(spi); +#ifdef IPSEC + kernel_insert_spi(spi); +#endif + } + + st->lifetime = exchange_lifetime + time(NULL) + random() % 20; + + st->retries = 0; + st->phase = SPI_UPDATE; + return 0; +} |