Esempio n. 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;
}
Esempio n. 2
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;
}
Esempio n. 3
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;
}