Beispiel #1
0
/* Add a NAT-D payload to our message.  */
static int
nat_t_add_nat_d(struct message *msg, struct sockaddr *sa)
{
	int	  ret;
	u_int8_t *hbuf, *buf;
	size_t	  hbuflen, buflen;

	hbuf = nat_t_generate_nat_d_hash(msg, sa, &hbuflen);
	if (!hbuf) {
		log_print("nat_t_add_nat_d: NAT-D hash gen failed");
		return -1;
	}

	buflen = ISAKMP_NAT_D_DATA_OFF + hbuflen;
	buf = malloc(buflen);
	if (!buf) {
		log_error("nat_t_add_nat_d: malloc (%lu) failed",
		    (unsigned long)buflen);
		free(hbuf);
		return -1;
	}

	SET_ISAKMP_GEN_LENGTH(buf, buflen);
	memcpy(buf + ISAKMP_NAT_D_DATA_OFF, hbuf, hbuflen);
	free(hbuf);

	if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_RFC)
		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D, buf,
		    buflen, 1);
	else if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_DRAFT)
		ret = message_add_payload(msg, ISAKMP_PAYLOAD_NAT_D_DRAFT,
		    buf, buflen, 1);
	else
		ret = -1;
		
	if (ret) {
		free(buf);
		return -1;
	}
	return 0;
}
/*
 * As "the server", this ends REQ/REPLY mode.
 * As "the client", this ends SET/ACK mode.
 */
static int
cfg_responder_send_ATTR(struct message *msg)
{
	struct ipsec_exch *ie = msg->exchange->data;
	struct sa      *isakmp_sa = msg->isakmp_sa;
	u_int8_t       *hashp = 0, *attrp;
	u_int16_t       attrlen;
	char           *id_string;

	if (msg->exchange->phase == 2) {
		hashp = cfg_add_hash(msg);
		if (!hashp)
			return -1;
	}
	/* We are responder, check isakmp_sa for other side.  */
	if (isakmp_sa->initiator ^ (ie->cfg_type == ISAKMP_CFG_REQUEST))
		id_string = ipsec_id_string(isakmp_sa->id_i,
		    isakmp_sa->id_i_len);
	else
		id_string = ipsec_id_string(isakmp_sa->id_r,
		    isakmp_sa->id_r_len);
	if (!id_string) {
		log_print("cfg_responder_send_ATTR: cannot parse client's ID");
		return -1;
	}
	if (cfg_encode_attributes(&ie->attrs, (ie->cfg_type == ISAKMP_CFG_SET ?
	    ISAKMP_CFG_ACK : ISAKMP_CFG_REPLY), ie->cfg_id, id_string, &attrp,
	    &attrlen)) {
		free(id_string);
		return -1;
	}
	free(id_string);

	if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen,
	    1)) {
		free(attrp);
		return -1;
	}
	if (msg->exchange->phase == 2)
		if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
			return -1;

	return 0;
}
u_int8_t *
cfg_add_hash(struct message *msg)
{
	struct ipsec_sa *isa = msg->isakmp_sa->data;
	struct hash    *hash = hash_get(isa->hash);
	u_int8_t       *hashp;

	hashp = malloc(ISAKMP_HASH_SZ + hash->hashsize);
	if (!hashp) {
		log_error("cfg_add_hash: malloc (%lu) failed",
		    ISAKMP_HASH_SZ + (unsigned long)hash->hashsize);
		return 0;
	}
	if (message_add_payload(msg, ISAKMP_PAYLOAD_HASH, hashp,
	    ISAKMP_HASH_SZ + hash->hashsize, 1)) {
		free(hashp);
		return 0;
	}
	return hashp;
}
Beispiel #4
0
/* Add one NAT-T VENDOR payload.  */
static int
nat_t_add_vendor_payload(struct message *msg, struct nat_t_cap *cap)
{
	size_t	  buflen = cap->hashsize + ISAKMP_GEN_SZ;
	u_int8_t *buf;

	if (disable_nat_t)
		return 0;

	buf = malloc(buflen);
	if (!buf) {
		log_error("nat_t_add_vendor_payload: malloc (%lu) failed",
		    (unsigned long)buflen);
		return -1;
	}

	SET_ISAKMP_GEN_LENGTH(buf, buflen);
	memcpy(buf + ISAKMP_VENDOR_ID_OFF, cap->hash, cap->hashsize);
	if (message_add_payload(msg, ISAKMP_PAYLOAD_VENDOR, buf, buflen, 1)) {
		free(buf);
		return -1;
	}
	return 0;
}
/*
 * When we are "the server", this starts SET/ACK mode
 * When we are "the client", this starts REQ/REPLY mode
 */
static int
cfg_initiator_send_ATTR(struct message *msg)
{
	struct sa      *isakmp_sa = msg->isakmp_sa;
	struct ipsec_exch *ie = msg->exchange->data;
	u_int8_t       *hashp = 0, *attrp, *attr;
	size_t          attrlen, off;
	char           *id_string, *cfg_mode, *field;
	struct sockaddr *sa;
#define CFG_ATTR_BIT_MAX ISAKMP_CFG_ATTR_FUTURE_MIN	/* XXX */
	bitstr_t        bit_decl(attrbits, CFG_ATTR_BIT_MAX);
	u_int16_t       bit, length;
	u_int32_t       life;

	if (msg->exchange->phase == 2) {
		hashp = cfg_add_hash(msg);
		if (!hashp)
			return -1;
	}
	/* We initiated this exchange, check isakmp_sa for other side.  */
	if (isakmp_sa->initiator)
		id_string = ipsec_id_string(isakmp_sa->id_r,
		    isakmp_sa->id_r_len);
	else
		id_string = ipsec_id_string(isakmp_sa->id_i,
		    isakmp_sa->id_i_len);
	if (!id_string) {
		log_print("cfg_initiator_send_ATTR: cannot parse ID");
		goto fail;
	}
	/* Check for attribute list to send to the other side */
	attrlen = 0;
	bit_nclear(attrbits, 0, CFG_ATTR_BIT_MAX - 1);

	cfg_mode = conf_get_str(id_string, "Mode");
	if (!cfg_mode || strcmp(cfg_mode, "SET") == 0) {
		/* SET/ACK mode */
		ie->cfg_type = ISAKMP_CFG_SET;

		LOG_DBG((LOG_NEGOTIATION, 10,
		    "cfg_initiator_send_ATTR: SET/ACK mode"));

#define ATTRFIND(STR,ATTR4,LEN4,ATTR6,LEN6) do				\
	{								\
		if ((sa = conf_get_address (id_string, STR)) != NULL)	\
			switch (sa->sa_family) {			\
			case AF_INET:					\
				bit_set (attrbits, ATTR4);		\
				attrlen += ISAKMP_ATTR_SZ + LEN4;	\
				break;					\
			case AF_INET6:					\
				bit_set (attrbits, ATTR6);		\
				attrlen += ISAKMP_ATTR_SZ + LEN6;	\
				break;					\
			default:					\
				break;					\
			}						\
		free (sa);						\
	} while (0)

		/*
		 * XXX We don't simultaneously support IPv4 and IPv6
		 * addresses.
		 */
		ATTRFIND("Address", ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS, 16);
		ATTRFIND("Netmask", ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK, 16);
		ATTRFIND("Nameserver", ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS, 16);
		ATTRFIND("WINS-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS, 16);
		ATTRFIND("DHCP-server", ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP, 4,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP, 16);
#ifdef notyet
		ATTRFIND("Network", ISAKMP_CFG_ATTR_INTERNAL_IP4_SUBNET, 8,
		    ISAKMP_CFG_ATTR_INTERNAL_IP6_SUBNET, 17);
#endif
#undef ATTRFIND

		if (conf_get_str(id_string, "Lifetime")) {
			bit_set(attrbits,
			    ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
			attrlen += ISAKMP_ATTR_SZ + 4;
		}
	} else {
		struct conf_list *alist;
		struct conf_list_node *anode;

		ie->cfg_type = ISAKMP_CFG_REQUEST;

		LOG_DBG((LOG_NEGOTIATION, 10,
		    "cfg_initiator_send_ATTR: REQ/REPLY mode"));

		alist = conf_get_list(id_string, "Attributes");
		if (alist) {
			for (anode = TAILQ_FIRST(&alist->fields); anode;
			    anode = TAILQ_NEXT(anode, link)) {
				if (strcasecmp(anode->field, "Address") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field, "Netmask")
				    == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "Nameserver") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "WINS-server") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "DHCP-server") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP);
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP);
					attrlen += ISAKMP_ATTR_SZ * 2;
				} else if (strcasecmp(anode->field,
				    "Lifetime") == 0) {
					bit_set(attrbits, ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY);
					attrlen += ISAKMP_ATTR_SZ;
				} else {
					log_print("cfg_initiator_send_ATTR: "
					    "unknown attribute %.20s in "
					    "section [%s]", anode->field,
					    id_string);
				}
			}

			conf_free_list(alist);
		}
	}

	if (attrlen == 0) {
		/* No data found.  */
		log_print("cfg_initiator_send_ATTR: no IKECFG attributes "
		    "found for [%s]", id_string);

		/*
		 * We can continue, but this indicates a configuration error
		 * that the user probably will want to correct.
		 */
		free(id_string);
		return 0;
	}
	attrlen += ISAKMP_ATTRIBUTE_SZ;
	attrp = calloc(1, attrlen);
	if (!attrp) {
		log_error("cfg_initiator_send_ATTR: calloc (1, %lu) failed",
		    (unsigned long)attrlen);
		goto fail;
	}
	if (message_add_payload(msg, ISAKMP_PAYLOAD_ATTRIBUTE, attrp, attrlen,
	    1)) {
		free(attrp);
		goto fail;
	}
	SET_ISAKMP_ATTRIBUTE_TYPE(attrp, ie->cfg_type);
	getrandom((u_int8_t *) & ie->cfg_id, sizeof ie->cfg_id);
	SET_ISAKMP_ATTRIBUTE_ID(attrp, ie->cfg_id);

	off = ISAKMP_ATTRIBUTE_SZ;

	/*
	 * Use the bitstring built previously to collect the right
	 * parameters for attrp.
         */
	for (bit = 0; bit < CFG_ATTR_BIT_MAX; bit++)
		if (bit_test(attrbits, bit)) {
			attr = attrp + off;
			SET_ISAKMP_ATTR_TYPE(attr, bit);

			if (ie->cfg_type == ISAKMP_CFG_REQUEST) {
				off += ISAKMP_ATTR_SZ;
				continue;
			}
			/* All the other are similar, this is the odd one.  */
			if (bit == ISAKMP_CFG_ATTR_INTERNAL_ADDRESS_EXPIRY) {
				life = conf_get_num(id_string, "Lifetime",
				    1200);
				SET_ISAKMP_ATTR_LENGTH_VALUE(attr, 4);
				encode_32(attr + ISAKMP_ATTR_VALUE_OFF, life);
				off += ISAKMP_ATTR_SZ + 4;
				continue;
			}
			switch (bit) {
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
				length = 4;
				break;

			case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
				length = 16;
				break;

			default:
				length = 0;	/* Silence gcc.  */
			}

			switch (bit) {
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_ADDRESS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_ADDRESS:
				field = "Address";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NETMASK:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NETMASK:
				field = "Netmask";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DNS:
				field = "Nameserver";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_DHCP:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_DHCP:
				field = "DHCP-server";
				break;
			case ISAKMP_CFG_ATTR_INTERNAL_IP4_NBNS:
			case ISAKMP_CFG_ATTR_INTERNAL_IP6_NBNS:
				field = "WINS-server";
				break;
			default:
				field = 0;	/* Silence gcc.  */
			}

			sa = conf_get_address(id_string, field);

			SET_ISAKMP_ATTR_LENGTH_VALUE(attr, length);
			memcpy(attr + ISAKMP_ATTR_VALUE_OFF,
			    sockaddr_addrdata(sa), length);

			free(sa);

			off += ISAKMP_ATTR_SZ + length;
		}
	if (msg->exchange->phase == 2)
		if (cfg_finalize_hash(msg, hashp, attrp, attrlen))
			goto fail;

	return 0;

fail:
	free(id_string);
	return -1;
}
Beispiel #6
0
int
ike_phase_1_send_ID (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    u_int8_t *buf;
    char header[80];
    ssize_t sz;
    struct sockaddr *src;
    int initiator = exchange->initiator;
    u_int8_t **id;
    size_t *id_len;
    char *my_id = 0;
    u_int8_t id_type;

    /* Choose the right fields to fill-in.  */
    id = initiator ? &exchange->id_i : &exchange->id_r;
    id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len;

    if (exchange->name)
        my_id = conf_get_str (exchange->name, "ID");

    if (!my_id)
        my_id = conf_get_str ("General", "Default-phase-1-ID");

    msg->transport->vtbl->get_src (msg->transport, &src);
    sz = my_id ? ipsec_id_size (my_id, &id_type) : sockaddr_addrlen (src);
    if (sz == -1)
        return -1;

    sz += ISAKMP_ID_DATA_OFF;
    buf = malloc (sz);
    if (!buf)
    {
        log_error ("ike_phase_1_send_ID: malloc (%lu) failed",
                   (unsigned long)sz);
        return -1;
    }

    SET_IPSEC_ID_PROTO (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
    SET_IPSEC_ID_PORT (buf + ISAKMP_ID_DOI_DATA_OFF, 0);
    if (my_id)
    {
        SET_ISAKMP_ID_TYPE (buf, id_type);
        switch (id_type)
        {
        case IPSEC_ID_IPV4_ADDR:
        case IPSEC_ID_IPV6_ADDR:
            /* Already in network byteorder.  */
            memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),
                    sockaddr_addrlen (src));
            break;

        case IPSEC_ID_FQDN:
        case IPSEC_ID_USER_FQDN:
        case IPSEC_ID_KEY_ID:
            memcpy (buf + ISAKMP_ID_DATA_OFF, conf_get_str (my_id, "Name"),
                    sz - ISAKMP_ID_DATA_OFF);
            break;

        default:
            log_print ("ike_phase_1_send_ID: unsupported ID type %d", id_type);
            free (buf);
            return -1;
        }
    }
    else
    {
        switch (src->sa_family)
        {
        case AF_INET:
            SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV4_ADDR);
            break;
        case AF_INET6:
            SET_ISAKMP_ID_TYPE (buf, IPSEC_ID_IPV6_ADDR);
            break;
        }
        /* Already in network byteorder.  */
        memcpy (buf + ISAKMP_ID_DATA_OFF, sockaddr_addrdata (src),
                sockaddr_addrlen (src));
    }

    if (message_add_payload (msg, ISAKMP_PAYLOAD_ID, buf, sz, 1))
    {
        free (buf);
        return -1;
    }
    *id_len = sz - ISAKMP_GEN_SZ;
    *id = malloc (*id_len);
    if (!*id)
    {
        log_error ("ike_phase_1_send_ID: malloc (%lu) failed",
                   (unsigned long)*id_len);
        return -1;
    }
    memcpy (*id, buf + ISAKMP_GEN_SZ, *id_len);
    snprintf (header, sizeof header, "ike_phase_1_send_ID: %s",
              constant_name (ipsec_id_cst, GET_ISAKMP_ID_TYPE (buf)));
    LOG_DBG_BUF ((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,
                  sz - ISAKMP_ID_DATA_OFF));

    return 0;
}
Beispiel #7
0
/* Offer a set of transforms to the responder in the MSG message.  */
int
ike_phase_1_initiator_send_SA (struct message *msg)
{
    struct exchange *exchange = msg->exchange;
    struct ipsec_exch *ie = exchange->data;
    u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr;
    u_int8_t **transform = 0;
    size_t transforms_len = 0, proposal_len, sa_len;
    size_t *transform_len = 0;
    struct conf_list *conf, *life_conf;
    struct conf_list_node *xf, *life;
    int i, value, update_nextp;
    struct payload *p;
    struct proto *proto;
    int group_desc = -1, new_group_desc;

    /* Get the list of transforms.  */
    conf = conf_get_list (exchange->policy, "Transforms");
    if (!conf)
        return -1;

    transform = calloc (conf->cnt, sizeof *transform);
    if (!transform)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (%d, %lu) failed",
                   conf->cnt, (unsigned long)sizeof *transform);
        goto bail_out;
    }

    transform_len = calloc (conf->cnt, sizeof *transform_len);
    if (!transform_len)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (%d, %lu) failed",
                   conf->cnt, (unsigned long)sizeof *transform_len);
        goto bail_out;
    }

    for (xf = TAILQ_FIRST (&conf->fields), i = 0; i < conf->cnt;
            i++, xf = TAILQ_NEXT (xf, link))
    {
        /* XXX The sizing needs to be dynamic.  */
        transform[i]
            = malloc (ISAKMP_TRANSFORM_SA_ATTRS_OFF + 16 * ISAKMP_ATTR_VALUE_OFF);
        if (!transform[i])
        {
            log_error ("ike_phase_1_initiator_send_SA: malloc (%d) failed",
                       ISAKMP_TRANSFORM_SA_ATTRS_OFF
                       + 16 * ISAKMP_ATTR_VALUE_OFF);
            goto bail_out;
        }

        SET_ISAKMP_TRANSFORM_NO (transform[i], i);
        SET_ISAKMP_TRANSFORM_ID (transform[i], IPSEC_TRANSFORM_KEY_IKE);
        SET_ISAKMP_TRANSFORM_RESERVED (transform[i], 0);

        attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF;

        if (attribute_set_constant (xf->field, "ENCRYPTION_ALGORITHM",
                                    ike_encrypt_cst,
                                    IKE_ATTR_ENCRYPTION_ALGORITHM, &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "HASH_ALGORITHM", ike_hash_cst,
                                    IKE_ATTR_HASH_ALGORITHM, &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "AUTHENTICATION_METHOD",
                                    ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD,
                                    &attr))
            goto bail_out;

        if (attribute_set_constant (xf->field, "GROUP_DESCRIPTION",
                                    ike_group_desc_cst,
                                    IKE_ATTR_GROUP_DESCRIPTION, &attr))
        {
            /*
             * If no group description exists, try looking for a user-defined
             * one.
             */
            if (attribute_set_constant (xf->field, "GROUP_TYPE", ike_group_cst,
                                        IKE_ATTR_GROUP_TYPE, &attr))
                goto bail_out;

#if 0
            if (attribute_set_bignum (xf->field, "GROUP_PRIME",
                                      IKE_ATTR_GROUP_PRIME, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
                                      IKE_ATTR_GROUP_GENERATOR_2, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_GENERATOR_2",
                                      IKE_ATTR_GROUP_GENERATOR_2, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_CURVE_A",
                                      IKE_ATTR_GROUP_CURVE_A, &attr))
                goto bail_out;

            if (attribute_set_bignum (xf->field, "GROUP_CURVE_B",
                                      IKE_ATTR_GROUP_CURVE_B, &attr))
                goto bail_out;
#endif
        }

        /*
         * Life durations are special, we should be able to specify
         * several, one per type.
         */
        life_conf = conf_get_list (xf->field, "Life");
        if (life_conf)
        {
            for (life = TAILQ_FIRST (&life_conf->fields); life;
                    life = TAILQ_NEXT (life, link))
            {
                attribute_set_constant (life->field, "LIFE_TYPE",
                                        ike_duration_cst, IKE_ATTR_LIFE_TYPE,
                                        &attr);

                /* XXX Deals with 16 and 32 bit lifetimes only */
                value = conf_get_num (life->field, "LIFE_DURATION", 0);
                if (value)
                {
                    if (value <= 0xffff)
                        attr = attribute_set_basic (attr, IKE_ATTR_LIFE_DURATION,
                                                    value);
                    else
                    {
                        value = htonl (value);
                        attr = attribute_set_var (attr, IKE_ATTR_LIFE_DURATION,
                                                  (u_int8_t *)&value,
                                                  sizeof value);
                    }
                }
            }
            conf_free_list (life_conf);
        }

        attribute_set_constant (xf->field, "PRF", ike_prf_cst, IKE_ATTR_PRF,
                                &attr);

        value = conf_get_num (xf->field, "KEY_LENGTH", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_KEY_LENGTH, value);

        value = conf_get_num (xf->field, "FIELD_SIZE", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_FIELD_SIZE, value);

        value = conf_get_num (xf->field, "GROUP_ORDER", 0);
        if (value)
            attr = attribute_set_basic (attr, IKE_ATTR_GROUP_ORDER, value);

        /* Record the real transform size.  */
        transforms_len += transform_len[i] = attr - transform[i];

        /* XXX I don't like exchange-specific stuff in here.  */
        if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
        {
            /*
             * Make sure that if a group description is specified, it is
             * specified for all transforms equally.
             */
            attr = (u_int8_t *)conf_get_str (xf->field, "GROUP_DESCRIPTION");
            new_group_desc
                = attr ? constant_value (ike_group_desc_cst, (char *)attr) : 0;
            if (group_desc == -1)
                group_desc = new_group_desc;
            else if (group_desc != new_group_desc)
            {
                log_print ("ike_phase_1_initiator_send_SA: "
                           "differing group descriptions in a proposal");
                goto bail_out;
            }
        }

        /* We need to check that we actually support our configuration.  */
        if (attribute_map (transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                           transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF,
                           exchange->doi->is_attribute_incompatible, msg))
        {
            log_print ("ike_phase_1_initiator_send_SA: "
                       "section [%s] has unsupported attribute(s)",
                       xf->field);
            goto bail_out;
        }
    }

    /* XXX I don't like exchange-specific stuff in here.  */
    if (exchange->type == ISAKMP_EXCH_AGGRESSIVE)
        ie->group = group_get (group_desc);

    proposal_len = ISAKMP_PROP_SPI_OFF;
    proposal = malloc (proposal_len);
    if (!proposal)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)proposal_len);
        goto bail_out;
    }

    SET_ISAKMP_PROP_NO (proposal, 1);
    SET_ISAKMP_PROP_PROTO (proposal, ISAKMP_PROTO_ISAKMP);
    SET_ISAKMP_PROP_SPI_SZ (proposal, 0);
    SET_ISAKMP_PROP_NTRANSFORMS (proposal, conf->cnt);

    /* XXX I would like to see this factored out.  */
    proto = calloc (1, sizeof *proto);
    if (!proto)
    {
        log_error ("ike_phase_1_initiator_send_SA: calloc (1, %lu) failed",
                   (unsigned long)sizeof *proto);
        goto bail_out;
    }

    proto->no = 1;
    proto->proto = ISAKMP_PROTO_ISAKMP;
    proto->sa = TAILQ_FIRST (&exchange->sa_list);
    TAILQ_INSERT_TAIL (&TAILQ_FIRST (&exchange->sa_list)->protos, proto,
                       link);

    sa_len = ISAKMP_SA_SIT_OFF + IPSEC_SIT_SIT_LEN;
    sa_buf = malloc (sa_len);
    if (!sa_buf)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)sa_len);
        goto bail_out;
    }

    SET_ISAKMP_SA_DOI (sa_buf, IPSEC_DOI_IPSEC);
    SET_IPSEC_SIT_SIT (sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY);

    /*
     * Add the payloads.  As this is a SA, we need to recompute the
     * lengths of the payloads containing others.
     */
    if (message_add_payload (msg, ISAKMP_PAYLOAD_SA, sa_buf, sa_len, 1))
        goto bail_out;
    SET_ISAKMP_GEN_LENGTH (sa_buf,
                           sa_len + proposal_len + transforms_len);
    sa_buf = 0;

    saved_nextp = msg->nextp;
    if (message_add_payload (msg, ISAKMP_PAYLOAD_PROPOSAL, proposal,
                             proposal_len, 0))
        goto bail_out;
    SET_ISAKMP_GEN_LENGTH (proposal, proposal_len + transforms_len);
    proposal = 0;

    update_nextp = 0;
    for (i = 0; i < conf->cnt; i++)
    {
        if (message_add_payload (msg, ISAKMP_PAYLOAD_TRANSFORM, transform[i],
                                 transform_len[i], update_nextp))
            goto bail_out;
        update_nextp = 1;
        transform[i] = 0;
    }
    msg->nextp = saved_nextp;

    /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len.  */
    ie->sa_i_b_len = sa_len + proposal_len + transforms_len - ISAKMP_GEN_SZ;
    ie->sa_i_b = malloc (ie->sa_i_b_len);
    if (!ie->sa_i_b)
    {
        log_error ("ike_phase_1_initiator_send_SA: malloc (%lu) failed",
                   (unsigned long)ie->sa_i_b_len);
        goto bail_out;
    }
    memcpy (ie->sa_i_b,
            TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_SA])->p + ISAKMP_GEN_SZ,
            sa_len - ISAKMP_GEN_SZ);
    memcpy (ie->sa_i_b + sa_len - ISAKMP_GEN_SZ,
            TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_PROPOSAL])->p,
            proposal_len);
    transforms_len = 0;
    for (i = 0, p = TAILQ_FIRST (&msg->payload[ISAKMP_PAYLOAD_TRANSFORM]);
            i < conf->cnt; i++, p = TAILQ_NEXT (p, link))
    {
        memcpy (ie->sa_i_b + sa_len + proposal_len + transforms_len
                - ISAKMP_GEN_SZ,
                p->p, transform_len[i]);
        transforms_len += transform_len[i];
    }

    conf_free_list (conf);
    free (transform);
    free (transform_len);
    return 0;

bail_out:
    if (sa_buf)
        free (sa_buf);
    if (proposal)
        free (proposal);
    if (transform)
    {
        for (i = 0; i < conf->cnt; i++)
            if (transform[i])
                free (transform[i]);
        free (transform);
    }
    if (transform_len)
        free (transform_len);
    conf_free_list (conf);
    return -1;
}
Beispiel #8
0
/* Encrypt the HASH into a SIG type.  */
static int
rsa_sig_encode_hash (struct message *msg)
{
  struct exchange *exchange = msg->exchange;
  struct ipsec_exch *ie = exchange->data;
  size_t hashsize = ie->hash->hashsize;
  struct cert_handler *handler;
  char header[80];
  int initiator = exchange->initiator;
  u_int8_t *buf, *data, *buf2;
  u_int32_t datalen;
  u_int8_t *id;
  size_t id_len;
  int idtype;
  void *sent_key;

  id = initiator ? exchange->id_i : exchange->id_r;
  id_len = initiator ? exchange->id_i_len : exchange->id_r_len;

  /* We may have been provided these by the kernel */
  buf = (u_int8_t *)conf_get_str (exchange->name, "Credentials");
  if (buf
      && (idtype = conf_get_num (exchange->name, "Credential_Type", -1) != -1))
    {
      exchange->sent_certtype = idtype;
      handler = cert_get (idtype);
      if (!handler)
	{
	  log_print ("rsa_sig_encode_hash: cert_get (%d) failed", idtype);
	  return -1;
	}

      exchange->sent_cert = handler->cert_from_printable ((char *)buf);
      if (!exchange->sent_cert)
	{
	  log_print ("rsa_sig_encode_hash: failed to retrieve certificate");
	  return -1;
	}

      handler->cert_serialize (exchange->sent_cert, &data, &datalen);
      if (!data)
	{
	  log_print ("rsa_sig_encode_hash: cert serialization failed");
	  return -1;
	}

      goto aftercert; /* Skip all the certificate discovery */
    }

  /* XXX This needs to be configurable.  */
  idtype = ISAKMP_CERTENC_KEYNOTE;

  /* Find a certificate with subjectAltName = id.  */
  handler = cert_get (idtype);
  if (!handler)
    {
      idtype = ISAKMP_CERTENC_X509_SIG;
      handler = cert_get (idtype);
      if (!handler)
	{
	  log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype);
	  return -1;
	}
    }

  if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0)
    {
      if (idtype == ISAKMP_CERTENC_KEYNOTE)
	{
	  idtype = ISAKMP_CERTENC_X509_SIG;
	  handler = cert_get (idtype);
	  if (!handler)
	    {
	      log_print ("rsa_sig_encode_hash: cert_get(%d) failed", idtype);
	      return -1;
	    }

	  if (handler->cert_obtain (id, id_len, 0, &data, &datalen) == 0)
	    {
	      LOG_DBG ((LOG_MISC, 10,
			"rsa_sig_encode_hash: no certificate to send"));
	      goto skipcert;
	    }
	}
      else
	{
	  LOG_DBG ((LOG_MISC, 10,
		    "rsa_sig_encode_hash: no certificate to send"));
	  goto skipcert;
	}
    }

  /* Let's store the certificate we are going to use */
  exchange->sent_certtype = idtype;
  exchange->sent_cert = handler->cert_get (data, datalen);
  if (!exchange->sent_cert)
    {
      free (data);
      log_print ("rsa_sig_encode_hash: failed to get certificate from wire "
		 "encoding");
      return -1;
    }

 aftercert:

  buf = realloc (data, ISAKMP_CERT_SZ + datalen);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
		 ISAKMP_CERT_SZ + datalen);
      free (data);
      return -1;
    }
  memmove (buf + ISAKMP_CERT_SZ, buf, datalen);
  SET_ISAKMP_CERT_ENCODING (buf, idtype);
  if (message_add_payload (msg, ISAKMP_PAYLOAD_CERT, buf,
			   ISAKMP_CERT_SZ + datalen, 1))
    {
      free (buf);
      return -1;
    }

 skipcert:

  /* Again, we may have these from the kernel */
  buf = (u_int8_t *)conf_get_str (exchange->name, "PKAuthentication");
  if (buf)
    {
      key_from_printable (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, (char *)buf,
			  &data, &datalen);
      if (!data || datalen == -1)
	{
	  log_print ("rsa_sig_encode_hash: badly formatted RSA private key");
	  return 0;
	}

      sent_key = key_internalize (ISAKMP_KEY_RSA, ISAKMP_KEYTYPE_PRIVATE, data,
				  datalen);
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: bad RSA private key from dynamic "
		     "SA acquisition subsystem");
	  return 0;
	}
#if defined (USE_PRIVSEP)
      {
	/* With USE_PRIVSEP, the sent_key should be a key number. */
	void *key = sent_key;
	sent_key = monitor_RSA_upload_key (key);
      }
#endif
    }
  else /* Try through the regular means.  */
    {
      switch (id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ])
	{
	case IPSEC_ID_IPV4_ADDR:
	case IPSEC_ID_IPV6_ADDR:
	  util_ntoa ((char **)&buf2,
		     id[ISAKMP_ID_TYPE_OFF - ISAKMP_GEN_SZ] == IPSEC_ID_IPV4_ADDR
		     ? AF_INET : AF_INET6,
		     id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ);
	  if (!buf2)
	    return 0;
	  break;

	case IPSEC_ID_FQDN:
	case IPSEC_ID_USER_FQDN:
	  buf2 = calloc (id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1,
			 sizeof (char));
	  if (!buf2)
	    {
	      log_print ("rsa_sig_encode_hash: malloc (%lu) failed",
			 (unsigned long)id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ + 1);
	      return 0;
	    }
	  memcpy (buf2, id + ISAKMP_ID_DATA_OFF - ISAKMP_GEN_SZ,
		  id_len - ISAKMP_ID_DATA_OFF + ISAKMP_GEN_SZ);
	  break;

	  /* XXX Support more ID types?  */
	default:
	  buf2 = 0;
	  return 0;
	}

#if defined (USE_PRIVSEP)
      sent_key = monitor_RSA_get_private_key (exchange->name, (char *)buf2);
#else
      sent_key = ike_auth_get_key (IKE_AUTH_RSA_SIG, exchange->name,
				   (char *)buf2, 0);
#endif
      free (buf2);

      /* Did we find a key?  */
      if (!sent_key)
	{
	  log_print ("rsa_sig_encode_hash: could not get private key");
	  return -1;
	}
    }

#if !defined (USE_PRIVSEP)
  /* Enable RSA blinding.  */
  if (RSA_blinding_on (sent_key, NULL) != 1)
    {
      log_error ("rsa_sig_encode_hash: RSA_blinding_on () failed.");
      return -1;
    }
#endif

  /* XXX hashsize is not necessarily prf->blocksize.  */
  buf = malloc (hashsize);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: malloc (%lu) failed",
	(unsigned long)hashsize);
      return -1;
    }

  if (ike_auth_hash (exchange, buf) == -1)
    {
      free (buf);
      return -1;
    }

  snprintf (header, sizeof header, "rsa_sig_encode_hash: HASH_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf, hashsize));

#if !defined (USE_PRIVSEP)
  data = malloc (RSA_size (sent_key));
  if (!data)
    {
      log_error ("rsa_sig_encode_hash: malloc (%d) failed",
		 RSA_size (sent_key));
      return -1;
    }

  datalen = RSA_private_encrypt (hashsize, buf, data, sent_key,
				 RSA_PKCS1_PADDING);
#else
  datalen = monitor_RSA_private_encrypt (hashsize, buf, &data, sent_key,
					 RSA_PKCS1_PADDING);
#endif /* USE_PRIVSEP */
  if (datalen == -1)
    {
      log_print ("rsa_sig_encode_hash: RSA_private_encrypt () failed");
      if (data)
	free (data);
      free (buf);
      monitor_RSA_free (sent_key);
      return -1;
    }

  free (buf);

  buf = realloc (data, ISAKMP_SIG_SZ + datalen);
  if (!buf)
    {
      log_error ("rsa_sig_encode_hash: realloc (%p, %d) failed", data,
		 ISAKMP_SIG_SZ + datalen);
      free (data);
      return -1;
    }
  memmove (buf + ISAKMP_SIG_SZ, buf, datalen);

  snprintf (header, sizeof header, "rsa_sig_encode_hash: SIG_%c",
	    initiator ? 'I' : 'R');
  LOG_DBG_BUF ((LOG_MISC, 80, header, buf + ISAKMP_SIG_DATA_OFF, datalen));
  if (message_add_payload (msg, ISAKMP_PAYLOAD_SIG, buf,
			   ISAKMP_SIG_SZ + datalen, 1))
    {
      free (buf);
      return -1;
    }
  return 0;
}