| File: | src/sbin/isakmpd/ike_phase_1.c |
| Warning: | line 1235, column 3 1st function call argument is an uninitialized value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ike_phase_1.c,v 1.78 2018/09/20 11:49:55 jsg Exp $ */ | |||
| 2 | /* $EOM: ike_phase_1.c,v 1.31 2000/12/11 23:47:56 niklas Exp $ */ | |||
| 3 | ||||
| 4 | /* | |||
| 5 | * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved. | |||
| 6 | * Copyright (c) 1999, 2000 Angelos D. Keromytis. All rights reserved. | |||
| 7 | * Copyright (c) 2001, 2004 Håkan Olsson. All rights reserved. | |||
| 8 | * | |||
| 9 | * Redistribution and use in source and binary forms, with or without | |||
| 10 | * modification, are permitted provided that the following conditions | |||
| 11 | * are met: | |||
| 12 | * 1. Redistributions of source code must retain the above copyright | |||
| 13 | * notice, this list of conditions and the following disclaimer. | |||
| 14 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 15 | * notice, this list of conditions and the following disclaimer in the | |||
| 16 | * documentation and/or other materials provided with the distribution. | |||
| 17 | * | |||
| 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |||
| 19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |||
| 20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |||
| 21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |||
| 22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |||
| 23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| 24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| 25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| 26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |||
| 27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| 28 | */ | |||
| 29 | ||||
| 30 | /* | |||
| 31 | * This code was written under funding by Ericsson Radio Systems. | |||
| 32 | */ | |||
| 33 | ||||
| 34 | #include <sys/types.h> | |||
| 35 | #include <netinet/in.h> | |||
| 36 | #include <arpa/inet.h> | |||
| 37 | #include <stdlib.h> | |||
| 38 | #include <string.h> | |||
| 39 | ||||
| 40 | #include "attribute.h" | |||
| 41 | #include "conf.h" | |||
| 42 | #include "constants.h" | |||
| 43 | #include "crypto.h" | |||
| 44 | #include "dh.h" | |||
| 45 | #include "doi.h" | |||
| 46 | #include "dpd.h" | |||
| 47 | #include "exchange.h" | |||
| 48 | #include "hash.h" | |||
| 49 | #include "ike_auth.h" | |||
| 50 | #include "ike_phase_1.h" | |||
| 51 | #include "ipsec.h" | |||
| 52 | #include "ipsec_doi.h" | |||
| 53 | #include "isakmp.h" | |||
| 54 | #include "log.h" | |||
| 55 | #include "message.h" | |||
| 56 | #include "nat_traversal.h" | |||
| 57 | #include "prf.h" | |||
| 58 | #include "sa.h" | |||
| 59 | #include "transport.h" | |||
| 60 | #include "util.h" | |||
| 61 | #include "vendor.h" | |||
| 62 | ||||
| 63 | static int attribute_unacceptable(u_int16_t, u_int8_t *, u_int16_t, | |||
| 64 | void *); | |||
| 65 | static int ike_phase_1_validate_prop(struct exchange *, struct sa *, | |||
| 66 | struct sa *); | |||
| 67 | ||||
| 68 | /* Offer a set of transforms to the responder in the MSG message. */ | |||
| 69 | int | |||
| 70 | ike_phase_1_initiator_send_SA(struct message *msg) | |||
| 71 | { | |||
| 72 | struct exchange *exchange = msg->exchange; | |||
| 73 | struct ipsec_exch *ie = exchange->data; | |||
| 74 | u_int8_t *proposal = 0, *sa_buf = 0, *saved_nextp, *attr; | |||
| 75 | u_int8_t **transform = 0; | |||
| 76 | size_t transforms_len = 0, proposal_len, sa_len; | |||
| 77 | size_t *transform_len = 0; | |||
| 78 | struct conf_list *conf, *life_conf; | |||
| 79 | struct conf_list_node *xf, *life; | |||
| 80 | int value, update_nextp; | |||
| 81 | size_t i; | |||
| 82 | struct payload *p; | |||
| 83 | struct proto *proto; | |||
| 84 | struct proto_attr *pa; | |||
| 85 | int group_desc = -1, new_group_desc; | |||
| 86 | ||||
| 87 | /* Get the list of transforms. */ | |||
| 88 | conf = conf_get_list(exchange->policy, "Transforms"); | |||
| 89 | if (!conf) | |||
| 90 | return -1; | |||
| 91 | ||||
| 92 | transform = calloc(conf->cnt, sizeof *transform); | |||
| 93 | if (!transform) { | |||
| 94 | log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " | |||
| 95 | "failed", (u_long)conf->cnt, (u_long)sizeof *transform); | |||
| 96 | goto bail_out; | |||
| 97 | } | |||
| 98 | transform_len = calloc(conf->cnt, sizeof *transform_len); | |||
| 99 | if (!transform_len) { | |||
| 100 | log_error("ike_phase_1_initiator_send_SA: calloc (%lu, %lu) " | |||
| 101 | "failed", (u_long)conf->cnt, | |||
| 102 | (u_long)sizeof *transform_len); | |||
| 103 | goto bail_out; | |||
| 104 | } | |||
| 105 | for (xf = TAILQ_FIRST(&conf->fields)((&conf->fields)->tqh_first), i = 0; i < conf->cnt; | |||
| 106 | i++, xf = TAILQ_NEXT(xf, link)((xf)->link.tqe_next)) { | |||
| 107 | /* XXX The sizing needs to be dynamic. */ | |||
| 108 | transform[i] = malloc(ISAKMP_TRANSFORM_SA_ATTRS_OFF8 + | |||
| 109 | 16 * ISAKMP_ATTR_VALUE_OFF4); | |||
| 110 | if (!transform[i]) { | |||
| 111 | log_error("ike_phase_1_initiator_send_SA: malloc (%d) " | |||
| 112 | "failed", ISAKMP_TRANSFORM_SA_ATTRS_OFF8 + | |||
| 113 | 16 * ISAKMP_ATTR_VALUE_OFF4); | |||
| 114 | goto bail_out; | |||
| 115 | } | |||
| 116 | SET_ISAKMP_TRANSFORM_NO(transform[i], i)field_set_num (isakmp_transform_fld + 0, transform[i], i); | |||
| 117 | SET_ISAKMP_TRANSFORM_ID(transform[i], IPSEC_TRANSFORM_KEY_IKE)field_set_num (isakmp_transform_fld + 1, transform[i], 1); | |||
| 118 | SET_ISAKMP_TRANSFORM_RESERVED(transform[i], 0)field_set_num (isakmp_transform_fld + 2, transform[i], 0); | |||
| 119 | ||||
| 120 | attr = transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF8; | |||
| 121 | ||||
| 122 | if (attribute_set_constant(xf->field, "ENCRYPTION_ALGORITHM", | |||
| 123 | ike_encrypt_cst, IKE_ATTR_ENCRYPTION_ALGORITHM1, &attr)) | |||
| 124 | goto bail_out; | |||
| 125 | ||||
| 126 | if (attribute_set_constant(xf->field, "HASH_ALGORITHM", | |||
| 127 | ike_hash_cst, IKE_ATTR_HASH_ALGORITHM2, &attr)) | |||
| 128 | goto bail_out; | |||
| 129 | ||||
| 130 | if (attribute_set_constant(xf->field, "AUTHENTICATION_METHOD", | |||
| 131 | ike_auth_cst, IKE_ATTR_AUTHENTICATION_METHOD3, &attr)) | |||
| 132 | goto bail_out; | |||
| 133 | ||||
| 134 | if (attribute_set_constant(xf->field, "GROUP_DESCRIPTION", | |||
| 135 | ike_group_desc_cst, IKE_ATTR_GROUP_DESCRIPTION4, &attr)) { | |||
| 136 | /* | |||
| 137 | * If no group description exists, try looking for | |||
| 138 | * a user-defined one. | |||
| 139 | */ | |||
| 140 | if (attribute_set_constant(xf->field, "GROUP_TYPE", | |||
| 141 | ike_group_cst, IKE_ATTR_GROUP_TYPE5, &attr)) | |||
| 142 | goto bail_out; | |||
| 143 | ||||
| 144 | #if 0 | |||
| 145 | if (attribute_set_bignum(xf->field, "GROUP_PRIME", | |||
| 146 | IKE_ATTR_GROUP_PRIME6, &attr)) | |||
| 147 | goto bail_out; | |||
| 148 | ||||
| 149 | if (attribute_set_bignum(xf->field, | |||
| 150 | "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_28, | |||
| 151 | &attr)) | |||
| 152 | goto bail_out; | |||
| 153 | ||||
| 154 | if (attribute_set_bignum(xf->field, | |||
| 155 | "GROUP_GENERATOR_2", IKE_ATTR_GROUP_GENERATOR_28, | |||
| 156 | &attr)) | |||
| 157 | goto bail_out; | |||
| 158 | ||||
| 159 | if (attribute_set_bignum(xf->field, "GROUP_CURVE_A", | |||
| 160 | IKE_ATTR_GROUP_CURVE_A9, &attr)) | |||
| 161 | goto bail_out; | |||
| 162 | ||||
| 163 | if (attribute_set_bignum(xf->field, "GROUP_CURVE_B", | |||
| 164 | IKE_ATTR_GROUP_CURVE_B10, &attr)) | |||
| 165 | goto bail_out; | |||
| 166 | #endif | |||
| 167 | } | |||
| 168 | /* | |||
| 169 | * Life durations are special, we should be able to specify | |||
| 170 | * several, one per type. | |||
| 171 | */ | |||
| 172 | life_conf = conf_get_list(xf->field, "Life"); | |||
| 173 | if (life_conf) { | |||
| 174 | for (life = TAILQ_FIRST(&life_conf->fields)((&life_conf->fields)->tqh_first); life; | |||
| 175 | life = TAILQ_NEXT(life, link)((life)->link.tqe_next)) { | |||
| 176 | attribute_set_constant(life->field, | |||
| 177 | "LIFE_TYPE", ike_duration_cst, | |||
| 178 | IKE_ATTR_LIFE_TYPE11, &attr); | |||
| 179 | ||||
| 180 | /* | |||
| 181 | * XXX Deals with 16 and 32 bit lifetimes | |||
| 182 | * only | |||
| 183 | */ | |||
| 184 | value = conf_get_num(life->field, | |||
| 185 | "LIFE_DURATION", 0); | |||
| 186 | if (value) { | |||
| 187 | if (value <= 0xffff) | |||
| 188 | attr = attribute_set_basic( | |||
| 189 | attr, | |||
| 190 | IKE_ATTR_LIFE_DURATION12, | |||
| 191 | value); | |||
| 192 | else { | |||
| 193 | value = htonl(value)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t )(value) & 0xff) << 24 | ((__uint32_t)(value) & 0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >> 8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md (value)); | |||
| 194 | attr = attribute_set_var(attr, | |||
| 195 | IKE_ATTR_LIFE_DURATION12, | |||
| 196 | (u_int8_t *)&value, | |||
| 197 | sizeof value); | |||
| 198 | } | |||
| 199 | } | |||
| 200 | } | |||
| 201 | conf_free_list(life_conf); | |||
| 202 | } | |||
| 203 | attribute_set_constant(xf->field, "PRF", ike_prf_cst, | |||
| 204 | IKE_ATTR_PRF13, &attr); | |||
| 205 | ||||
| 206 | value = conf_get_num(xf->field, "KEY_LENGTH", 0); | |||
| 207 | if (value) | |||
| 208 | attr = attribute_set_basic(attr, IKE_ATTR_KEY_LENGTH14, | |||
| 209 | value); | |||
| 210 | ||||
| 211 | value = conf_get_num(xf->field, "FIELD_SIZE", 0); | |||
| 212 | if (value) | |||
| 213 | attr = attribute_set_basic(attr, IKE_ATTR_FIELD_SIZE15, | |||
| 214 | value); | |||
| 215 | ||||
| 216 | value = conf_get_num(xf->field, "GROUP_ORDER", 0); | |||
| 217 | if (value) | |||
| 218 | attr = attribute_set_basic(attr, IKE_ATTR_GROUP_ORDER16, | |||
| 219 | value); | |||
| 220 | ||||
| 221 | /* Record the real transform size. */ | |||
| 222 | transforms_len += transform_len[i] = attr - transform[i]; | |||
| 223 | ||||
| 224 | /* XXX I don't like exchange-specific stuff in here. */ | |||
| 225 | if (exchange->type == ISAKMP_EXCH_AGGRESSIVE4) { | |||
| 226 | /* | |||
| 227 | * Make sure that if a group description is specified, | |||
| 228 | * it is specified for all transforms equally. | |||
| 229 | */ | |||
| 230 | attr = (u_int8_t *)conf_get_str(xf->field, | |||
| 231 | "GROUP_DESCRIPTION"); | |||
| 232 | new_group_desc = | |||
| 233 | attr ? constant_value(ike_group_desc_cst, | |||
| 234 | (char *)attr) : 0; | |||
| 235 | if (group_desc == -1) | |||
| 236 | group_desc = new_group_desc; | |||
| 237 | else if (group_desc != new_group_desc) { | |||
| 238 | log_print("ike_phase_1_initiator_send_SA: " | |||
| 239 | "differing group descriptions in a " | |||
| 240 | "proposal"); | |||
| 241 | goto bail_out; | |||
| 242 | } | |||
| 243 | } | |||
| 244 | /* | |||
| 245 | * We need to check that we actually support our | |||
| 246 | * configuration. | |||
| 247 | */ | |||
| 248 | if (attribute_map(transform[i] + ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
| 249 | transform_len[i] - ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
| 250 | exchange->doi->is_attribute_incompatible, msg)) { | |||
| 251 | log_print("ike_phase_1_initiator_send_SA: " | |||
| 252 | "section [%s] has unsupported attribute(s)", | |||
| 253 | xf->field); | |||
| 254 | goto bail_out; | |||
| 255 | } | |||
| 256 | } | |||
| 257 | ||||
| 258 | /* XXX I don't like exchange-specific stuff in here. */ | |||
| 259 | if (exchange->type == ISAKMP_EXCH_AGGRESSIVE4) | |||
| 260 | ie->group = group_get(group_desc); | |||
| 261 | ||||
| 262 | proposal_len = ISAKMP_PROP_SPI_OFF8; | |||
| 263 | proposal = malloc(proposal_len); | |||
| 264 | if (!proposal) { | |||
| 265 | log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", | |||
| 266 | (unsigned long)proposal_len); | |||
| 267 | goto bail_out; | |||
| 268 | } | |||
| 269 | SET_ISAKMP_PROP_NO(proposal, 1)field_set_num (isakmp_prop_fld + 0, proposal, 1); | |||
| 270 | SET_ISAKMP_PROP_PROTO(proposal, ISAKMP_PROTO_ISAKMP)field_set_num (isakmp_prop_fld + 1, proposal, 1); | |||
| 271 | SET_ISAKMP_PROP_SPI_SZ(proposal, 0)field_set_num (isakmp_prop_fld + 2, proposal, 0); | |||
| 272 | SET_ISAKMP_PROP_NTRANSFORMS(proposal, conf->cnt)field_set_num (isakmp_prop_fld + 3, proposal, conf->cnt); | |||
| 273 | ||||
| 274 | /* XXX I would like to see this factored out. */ | |||
| 275 | proto = calloc(1, sizeof *proto); | |||
| 276 | if (!proto) { | |||
| 277 | log_error("ike_phase_1_initiator_send_SA: " | |||
| 278 | "calloc (1, %lu) failed", (unsigned long)sizeof *proto); | |||
| 279 | goto bail_out; | |||
| 280 | } | |||
| 281 | proto->no = 1; | |||
| 282 | proto->proto = ISAKMP_PROTO_ISAKMP1; | |||
| 283 | proto->sa = TAILQ_FIRST(&exchange->sa_list)((&exchange->sa_list)->tqh_first); | |||
| 284 | proto->xf_cnt = conf->cnt; | |||
| 285 | TAILQ_INIT(&proto->xfs)do { (&proto->xfs)->tqh_first = ((void*)0); (&proto ->xfs)->tqh_last = &(&proto->xfs)->tqh_first ; } while (0); | |||
| 286 | for (i = 0; i < proto->xf_cnt; i++) { | |||
| 287 | pa = calloc(1, sizeof *pa); | |||
| 288 | if (!pa) | |||
| 289 | goto bail_out; | |||
| 290 | pa->len = transform_len[i]; | |||
| 291 | pa->attrs = malloc(pa->len); | |||
| 292 | if (!pa->attrs) { | |||
| 293 | free(pa); | |||
| 294 | goto bail_out; | |||
| 295 | } | |||
| 296 | memcpy(pa->attrs, transform[i], pa->len); | |||
| 297 | TAILQ_INSERT_TAIL(&proto->xfs, pa, next)do { (pa)->next.tqe_next = ((void*)0); (pa)->next.tqe_prev = (&proto->xfs)->tqh_last; *(&proto->xfs)-> tqh_last = (pa); (&proto->xfs)->tqh_last = &(pa )->next.tqe_next; } while (0); | |||
| 298 | } | |||
| 299 | TAILQ_INSERT_TAIL(&TAILQ_FIRST(&exchange->sa_list)->protos, proto,do { (proto)->link.tqe_next = ((void*)0); (proto)->link .tqe_prev = (&((&exchange->sa_list)->tqh_first) ->protos)->tqh_last; *(&((&exchange->sa_list )->tqh_first)->protos)->tqh_last = (proto); (&(( &exchange->sa_list)->tqh_first)->protos)->tqh_last = &(proto)->link.tqe_next; } while (0) | |||
| 300 | link)do { (proto)->link.tqe_next = ((void*)0); (proto)->link .tqe_prev = (&((&exchange->sa_list)->tqh_first) ->protos)->tqh_last; *(&((&exchange->sa_list )->tqh_first)->protos)->tqh_last = (proto); (&(( &exchange->sa_list)->tqh_first)->protos)->tqh_last = &(proto)->link.tqe_next; } while (0); | |||
| 301 | ||||
| 302 | sa_len = ISAKMP_SA_SIT_OFF8 + IPSEC_SIT_SIT_LEN4; | |||
| 303 | sa_buf = malloc(sa_len); | |||
| 304 | if (!sa_buf) { | |||
| 305 | log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", | |||
| 306 | (unsigned long)sa_len); | |||
| 307 | goto bail_out; | |||
| 308 | } | |||
| 309 | SET_ISAKMP_SA_DOI(sa_buf, IPSEC_DOI_IPSEC)field_set_num (isakmp_sa_fld + 0, sa_buf, 1); | |||
| 310 | SET_IPSEC_SIT_SIT(sa_buf + ISAKMP_SA_SIT_OFF, IPSEC_SIT_IDENTITY_ONLY)field_set_num (ipsec_sit_fld + 0, sa_buf + 8, 1); | |||
| 311 | ||||
| 312 | /* | |||
| 313 | * Add the payloads. As this is a SA, we need to recompute the | |||
| 314 | * lengths of the payloads containing others. | |||
| 315 | */ | |||
| 316 | if (message_add_payload(msg, ISAKMP_PAYLOAD_SA1, sa_buf, sa_len, 1)) | |||
| 317 | goto bail_out; | |||
| 318 | SET_ISAKMP_GEN_LENGTH(sa_buf,field_set_num (isakmp_gen_fld + 2, sa_buf, sa_len + proposal_len + transforms_len) | |||
| 319 | sa_len + proposal_len + transforms_len)field_set_num (isakmp_gen_fld + 2, sa_buf, sa_len + proposal_len + transforms_len); | |||
| 320 | sa_buf = 0; | |||
| 321 | ||||
| 322 | saved_nextp = msg->nextp; | |||
| 323 | if (message_add_payload(msg, ISAKMP_PAYLOAD_PROPOSAL2, proposal, | |||
| 324 | proposal_len, 0)) | |||
| 325 | goto bail_out; | |||
| 326 | SET_ISAKMP_GEN_LENGTH(proposal, proposal_len + transforms_len)field_set_num (isakmp_gen_fld + 2, proposal, proposal_len + transforms_len ); | |||
| 327 | proposal = 0; | |||
| 328 | ||||
| 329 | update_nextp = 0; | |||
| 330 | for (i = 0; i < conf->cnt; i++) { | |||
| 331 | if (message_add_payload(msg, ISAKMP_PAYLOAD_TRANSFORM3, | |||
| 332 | transform[i], transform_len[i], update_nextp)) | |||
| 333 | goto bail_out; | |||
| 334 | update_nextp = 1; | |||
| 335 | transform[i] = 0; | |||
| 336 | } | |||
| 337 | msg->nextp = saved_nextp; | |||
| 338 | ||||
| 339 | /* Save SA payload body in ie->sa_i_b, length ie->sa_i_b_len. */ | |||
| 340 | ie->sa_i_b_len = sa_len + proposal_len + transforms_len - | |||
| 341 | ISAKMP_GEN_SZ4; | |||
| 342 | ie->sa_i_b = malloc(ie->sa_i_b_len); | |||
| 343 | if (!ie->sa_i_b) { | |||
| 344 | log_error("ike_phase_1_initiator_send_SA: malloc (%lu) failed", | |||
| 345 | (unsigned long)ie->sa_i_b_len); | |||
| 346 | goto bail_out; | |||
| 347 | } | |||
| 348 | memcpy(ie->sa_i_b, | |||
| 349 | payload_first(msg, ISAKMP_PAYLOAD_SA1)->p + ISAKMP_GEN_SZ4, | |||
| 350 | sa_len - ISAKMP_GEN_SZ4); | |||
| 351 | memcpy(ie->sa_i_b + sa_len - ISAKMP_GEN_SZ4, | |||
| 352 | payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL2)->p, proposal_len); | |||
| 353 | transforms_len = 0; | |||
| 354 | for (i = 0, p = TAILQ_FIRST(&msg->payload[ISAKMP_PAYLOAD_TRANSFORM])((&msg->payload[3])->tqh_first); | |||
| 355 | i < conf->cnt; i++, p = TAILQ_NEXT(p, link)((p)->link.tqe_next)) { | |||
| 356 | memcpy(ie->sa_i_b + sa_len + proposal_len + transforms_len - | |||
| 357 | ISAKMP_GEN_SZ4, p->p, transform_len[i]); | |||
| 358 | transforms_len += transform_len[i]; | |||
| 359 | } | |||
| 360 | ||||
| 361 | /* Advertise OpenBSD isakmpd. */ | |||
| 362 | if (add_vendor_openbsd(msg)) | |||
| 363 | goto bail_out; | |||
| 364 | ||||
| 365 | /* Advertise NAT-T capability. */ | |||
| 366 | if (nat_t_add_vendor_payloads(msg)) | |||
| 367 | goto bail_out; | |||
| 368 | ||||
| 369 | /* Advertise DPD capability. */ | |||
| 370 | if (dpd_add_vendor_payload(msg)) | |||
| 371 | goto bail_out; | |||
| 372 | ||||
| 373 | conf_free_list(conf); | |||
| 374 | free(transform); | |||
| 375 | free(transform_len); | |||
| 376 | return 0; | |||
| 377 | ||||
| 378 | bail_out: | |||
| 379 | free(sa_buf); | |||
| 380 | free(proposal); | |||
| 381 | if (transform) { | |||
| 382 | for (i = 0; i < conf->cnt; i++) | |||
| 383 | free(transform[i]); | |||
| 384 | free(transform); | |||
| 385 | } | |||
| 386 | free(transform_len); | |||
| 387 | conf_free_list(conf); | |||
| 388 | return -1; | |||
| 389 | } | |||
| 390 | ||||
| 391 | /* Figure out what transform the responder chose. */ | |||
| 392 | int | |||
| 393 | ike_phase_1_initiator_recv_SA(struct message *msg) | |||
| 394 | { | |||
| 395 | struct exchange *exchange = msg->exchange; | |||
| 396 | struct sa *sa = TAILQ_FIRST(&exchange->sa_list)((&exchange->sa_list)->tqh_first); | |||
| 397 | struct ipsec_exch *ie = exchange->data; | |||
| 398 | struct ipsec_sa *isa = sa->data; | |||
| 399 | struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA1); | |||
| 400 | struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL2); | |||
| 401 | struct payload *xf = payload_first(msg, ISAKMP_PAYLOAD_TRANSFORM3); | |||
| 402 | ||||
| 403 | /* | |||
| 404 | * IKE requires that only one SA with only one proposal exists and | |||
| 405 | * since we are getting an answer on our transform offer, only one | |||
| 406 | * transform. | |||
| 407 | */ | |||
| 408 | if (TAILQ_NEXT(sa_p, link)((sa_p)->link.tqe_next) || TAILQ_NEXT(prop, link)((prop)->link.tqe_next) || | |||
| 409 | TAILQ_NEXT(xf, link)((xf)->link.tqe_next)) { | |||
| 410 | log_print("ike_phase_1_initiator_recv_SA: " | |||
| 411 | "multiple SA, proposal or transform payloads in phase 1"); | |||
| 412 | /* XXX Is there a better notification type? */ | |||
| 413 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
| 414 | return -1; | |||
| 415 | } | |||
| 416 | /* Check that the chosen transform matches an offer. */ | |||
| 417 | if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || | |||
| 418 | !TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)) | |||
| 419 | return -1; | |||
| 420 | ||||
| 421 | ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first), xf->p); | |||
| 422 | ||||
| 423 | /* XXX I don't like exchange-specific stuff in here. */ | |||
| 424 | if (exchange->type != ISAKMP_EXCH_AGGRESSIVE4) | |||
| 425 | ie->group = group_get(isa->group_desc); | |||
| 426 | ||||
| 427 | /* Mark the SA as handled. */ | |||
| 428 | sa_p->flags |= PL_MARK1; | |||
| 429 | ||||
| 430 | return 0; | |||
| 431 | } | |||
| 432 | ||||
| 433 | /* Send our public DH value and a nonce to the responder. */ | |||
| 434 | int | |||
| 435 | ike_phase_1_initiator_send_KE_NONCE(struct message *msg) | |||
| 436 | { | |||
| 437 | struct ipsec_exch *ie = msg->exchange->data; | |||
| 438 | ||||
| 439 | ie->g_x_len = dh_getlen(ie->group); | |||
| 440 | ||||
| 441 | /* XXX I want a better way to specify the nonce's size. */ | |||
| 442 | return ike_phase_1_send_KE_NONCE(msg, 16); | |||
| 443 | } | |||
| 444 | ||||
| 445 | /* Accept responder's public DH value and nonce. */ | |||
| 446 | int | |||
| 447 | ike_phase_1_initiator_recv_KE_NONCE(struct message *msg) | |||
| 448 | { | |||
| 449 | if (ike_phase_1_recv_KE_NONCE(msg)) | |||
| 450 | return -1; | |||
| 451 | ||||
| 452 | return ike_phase_1_post_exchange_KE_NONCE(msg); | |||
| 453 | } | |||
| 454 | ||||
| 455 | /* | |||
| 456 | * Accept a set of transforms offered by the initiator and chose one we can | |||
| 457 | * handle. | |||
| 458 | */ | |||
| 459 | int | |||
| 460 | ike_phase_1_responder_recv_SA(struct message *msg) | |||
| 461 | { | |||
| 462 | struct exchange *exchange = msg->exchange; | |||
| 463 | struct sa *sa = TAILQ_FIRST(&exchange->sa_list)((&exchange->sa_list)->tqh_first); | |||
| 464 | struct ipsec_sa *isa = sa->data; | |||
| 465 | struct payload *sa_p = payload_first(msg, ISAKMP_PAYLOAD_SA1); | |||
| 466 | struct payload *prop = payload_first(msg, ISAKMP_PAYLOAD_PROPOSAL2); | |||
| 467 | struct ipsec_exch *ie = exchange->data; | |||
| 468 | ||||
| 469 | /* Mark the SA as handled. */ | |||
| 470 | sa_p->flags |= PL_MARK1; | |||
| 471 | ||||
| 472 | /* IKE requires that only one SA with only one proposal exists. */ | |||
| 473 | if (TAILQ_NEXT(sa_p, link)((sa_p)->link.tqe_next) || TAILQ_NEXT(prop, link)((prop)->link.tqe_next)) { | |||
| 474 | log_print("ike_phase_1_responder_recv_SA: " | |||
| 475 | "multiple SA or proposal payloads in phase 1"); | |||
| 476 | /* XXX Is there a better notification type? */ | |||
| 477 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
| 478 | return -1; | |||
| 479 | } | |||
| 480 | /* Chose a transform from the SA. */ | |||
| 481 | if (message_negotiate_sa(msg, ike_phase_1_validate_prop) || | |||
| 482 | !TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)) | |||
| 483 | return -1; | |||
| 484 | ||||
| 485 | /* XXX Move into message_negotiate_sa? */ | |||
| 486 | ipsec_decode_transform(msg, sa, TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first), | |||
| 487 | TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first)->chosen->p); | |||
| 488 | ||||
| 489 | ie->group = group_get(isa->group_desc); | |||
| 490 | ||||
| 491 | /* | |||
| 492 | * Check that the mandatory attributes: encryption, hash, | |||
| 493 | * authentication method and Diffie-Hellman group description, has | |||
| 494 | * been supplied. | |||
| 495 | */ | |||
| 496 | if (!exchange->crypto || !ie->hash || !ie->ike_auth || !ie->group) { | |||
| 497 | message_drop(msg, ISAKMP_NOTIFY_PAYLOAD_MALFORMED16, 0, 1, 0); | |||
| 498 | return -1; | |||
| 499 | } | |||
| 500 | /* Save the body for later hash computation. */ | |||
| 501 | ie->sa_i_b_len = GET_ISAKMP_GEN_LENGTH(sa_p->p)field_get_num (isakmp_gen_fld + 2, sa_p->p) - ISAKMP_GEN_SZ4; | |||
| 502 | ie->sa_i_b = malloc(ie->sa_i_b_len); | |||
| 503 | if (!ie->sa_i_b) { | |||
| 504 | /* XXX How to notify peer? */ | |||
| 505 | log_error("ike_phase_1_responder_recv_SA: malloc (%lu) failed", | |||
| 506 | (unsigned long)ie->sa_i_b_len); | |||
| 507 | return -1; | |||
| 508 | } | |||
| 509 | memcpy(ie->sa_i_b, sa_p->p + ISAKMP_GEN_SZ4, ie->sa_i_b_len); | |||
| 510 | return 0; | |||
| 511 | } | |||
| 512 | ||||
| 513 | /* Reply with the transform we chose. */ | |||
| 514 | int | |||
| 515 | ike_phase_1_responder_send_SA(struct message *msg) | |||
| 516 | { | |||
| 517 | /* Add the SA payload with the transform that was chosen. */ | |||
| 518 | if (message_add_sa_payload(msg)) | |||
| 519 | return -1; | |||
| 520 | ||||
| 521 | /* Advertise OpenBSD isakmpd. */ | |||
| 522 | if (add_vendor_openbsd(msg)) | |||
| 523 | return -1; | |||
| 524 | ||||
| 525 | /* Advertise NAT-T capability. */ | |||
| 526 | if (nat_t_add_vendor_payloads(msg)) | |||
| 527 | return -1; | |||
| 528 | ||||
| 529 | /* Advertise DPD capability. */ | |||
| 530 | if (dpd_add_vendor_payload(msg)) | |||
| 531 | return -1; | |||
| 532 | return 0; | |||
| 533 | } | |||
| 534 | ||||
| 535 | /* Send our public DH value and a nonce to the peer. */ | |||
| 536 | int | |||
| 537 | ike_phase_1_send_KE_NONCE(struct message *msg, size_t nonce_sz) | |||
| 538 | { | |||
| 539 | /* Public DH key. */ | |||
| 540 | if (ipsec_gen_g_x(msg)) { | |||
| 541 | /* XXX How to log and notify peer? */ | |||
| 542 | return -1; | |||
| 543 | } | |||
| 544 | /* Generate a nonce, and add it to the message. */ | |||
| 545 | if (exchange_gen_nonce(msg, nonce_sz)) { | |||
| 546 | /* XXX Log? */ | |||
| 547 | return -1; | |||
| 548 | } | |||
| 549 | /* Are there any CERTREQs to send? */ | |||
| 550 | if (exchange_add_certreqs(msg)) { | |||
| 551 | /* XXX Log? */ | |||
| 552 | return -1; | |||
| 553 | } | |||
| 554 | /* Try to add certificates which are acceptable for the CERTREQs */ | |||
| 555 | if (exchange_add_certs(msg)) { | |||
| 556 | /* XXX Log? */ | |||
| 557 | return -1; | |||
| 558 | } | |||
| 559 | /* If this exchange uses NAT-Traversal, add NAT-D payloads now. */ | |||
| 560 | if (msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER0x0008) | |||
| 561 | if (nat_t_exchange_add_nat_d(msg)) { | |||
| 562 | /* XXX Log? */ | |||
| 563 | return -1; | |||
| 564 | } | |||
| 565 | return 0; | |||
| 566 | } | |||
| 567 | ||||
| 568 | /* Receive our peer's public DH value and nonce. */ | |||
| 569 | int | |||
| 570 | ike_phase_1_recv_KE_NONCE(struct message *msg) | |||
| 571 | { | |||
| 572 | /* Copy out the initiator's DH public value. */ | |||
| 573 | if (ipsec_save_g_x(msg)) { | |||
| 574 | /* XXX How to log and notify peer? */ | |||
| 575 | return -1; | |||
| 576 | } | |||
| 577 | /* Copy out the initiator's nonce. */ | |||
| 578 | if (exchange_save_nonce(msg)) { | |||
| 579 | /* XXX How to log and notify peer? */ | |||
| 580 | return -1; | |||
| 581 | } | |||
| 582 | /* Copy out the initiator's cert requests. */ | |||
| 583 | if (exchange_save_certreq(msg)) { | |||
| 584 | /* XXX How to log and notify peer? */ | |||
| 585 | return -1; | |||
| 586 | } | |||
| 587 | /* MainMode: Check for NAT-D payloads and contents. */ | |||
| 588 | if (msg->exchange->type == ISAKMP_EXCH_ID_PROT2 && | |||
| 589 | msg->exchange->flags & EXCHANGE_FLAG_NAT_T_CAP_PEER0x0008) | |||
| 590 | (void)nat_t_exchange_check_nat_d(msg); | |||
| 591 | return 0; | |||
| 592 | } | |||
| 593 | ||||
| 594 | /* | |||
| 595 | * Compute DH values and key material. This is done in a post-send function | |||
| 596 | * as that means we can do parallel work in both the initiator and responder | |||
| 597 | * thus speeding up exchanges. | |||
| 598 | */ | |||
| 599 | int | |||
| 600 | ike_phase_1_post_exchange_KE_NONCE(struct message *msg) | |||
| 601 | { | |||
| 602 | struct exchange *exchange = msg->exchange; | |||
| 603 | struct ipsec_exch *ie = exchange->data; | |||
| 604 | struct prf *prf; | |||
| 605 | struct hash *hash = ie->hash; | |||
| 606 | enum cryptoerr err; | |||
| 607 | ||||
| 608 | /* Compute Diffie-Hellman shared value. */ | |||
| 609 | ie->g_xy_len = dh_secretlen(ie->group); | |||
| 610 | ie->g_xy = malloc(ie->g_xy_len); | |||
| 611 | if (!ie->g_xy) { | |||
| 612 | /* XXX How to notify peer? */ | |||
| 613 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 614 | "malloc (%lu) failed", (unsigned long)ie->g_xy_len); | |||
| 615 | return -1; | |||
| 616 | } | |||
| 617 | if (dh_create_shared(ie->group, ie->g_xy, | |||
| 618 | exchange->initiator ? ie->g_xr : ie->g_xi)) { | |||
| 619 | log_print("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 620 | "dh_create_shared failed"); | |||
| 621 | return -1; | |||
| 622 | } | |||
| 623 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy" , ie->g_xy, ie->g_xy_len) | |||
| 624 | "ike_phase_1_post_exchange_KE_NONCE: g^xy", ie->g_xy,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy" , ie->g_xy, ie->g_xy_len) | |||
| 625 | ie->g_xy_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: g^xy" , ie->g_xy, ie->g_xy_len); | |||
| 626 | ||||
| 627 | /* Compute the SKEYID depending on the authentication method. */ | |||
| 628 | ie->skeyid = ie->ike_auth->gen_skeyid(exchange, &ie->skeyid_len); | |||
| 629 | if (!ie->skeyid) { | |||
| 630 | /* XXX Log and teardown? */ | |||
| 631 | return -1; | |||
| 632 | } | |||
| 633 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID" , ie->skeyid, ie->skeyid_len) | |||
| 634 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID", ie->skeyid,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID" , ie->skeyid, ie->skeyid_len) | |||
| 635 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID" , ie->skeyid, ie->skeyid_len); | |||
| 636 | ||||
| 637 | /* SKEYID_d. */ | |||
| 638 | ie->skeyid_d = malloc(ie->skeyid_len); | |||
| 639 | if (!ie->skeyid_d) { | |||
| 640 | /* XXX How to notify peer? */ | |||
| 641 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 642 | "malloc (%lu) failed", (unsigned long)ie->skeyid_len); | |||
| 643 | return -1; | |||
| 644 | } | |||
| 645 | prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); | |||
| 646 | if (!prf) { | |||
| 647 | /* XXX Log and teardown? */ | |||
| 648 | return -1; | |||
| 649 | } | |||
| 650 | prf->Init(prf->prfctx); | |||
| 651 | prf->Update(prf->prfctx, ie->g_xy, ie->g_xy_len); | |||
| 652 | prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
| 653 | prf->Update(prf->prfctx, (unsigned char *)"\0", 1); | |||
| 654 | prf->Final(ie->skeyid_d, prf->prfctx); | |||
| 655 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d" , ie->skeyid_d, ie->skeyid_len) | |||
| 656 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d", ie->skeyid_d,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d" , ie->skeyid_d, ie->skeyid_len) | |||
| 657 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_d" , ie->skeyid_d, ie->skeyid_len); | |||
| 658 | ||||
| 659 | /* SKEYID_a. */ | |||
| 660 | ie->skeyid_a = malloc(ie->skeyid_len); | |||
| 661 | if (!ie->skeyid_a) { | |||
| 662 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 663 | "malloc (%lu) failed", (unsigned long)ie->skeyid_len); | |||
| 664 | prf_free(prf); | |||
| 665 | return -1; | |||
| 666 | } | |||
| 667 | prf->Init(prf->prfctx); | |||
| 668 | prf->Update(prf->prfctx, ie->skeyid_d, ie->skeyid_len); | |||
| 669 | prf->Update(prf->prfctx, ie->g_xy, ie->g_xy_len); | |||
| 670 | prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
| 671 | prf->Update(prf->prfctx, (unsigned char *)"\1", 1); | |||
| 672 | prf->Final(ie->skeyid_a, prf->prfctx); | |||
| 673 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a" , ie->skeyid_a, ie->skeyid_len) | |||
| 674 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a", ie->skeyid_a,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a" , ie->skeyid_a, ie->skeyid_len) | |||
| 675 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_a" , ie->skeyid_a, ie->skeyid_len); | |||
| 676 | ||||
| 677 | /* SKEYID_e. */ | |||
| 678 | ie->skeyid_e = malloc(ie->skeyid_len); | |||
| 679 | if (!ie->skeyid_e) { | |||
| 680 | /* XXX How to notify peer? */ | |||
| 681 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 682 | "malloc (%lu) failed", (unsigned long)ie->skeyid_len); | |||
| 683 | prf_free(prf); | |||
| 684 | return -1; | |||
| 685 | } | |||
| 686 | prf->Init(prf->prfctx); | |||
| 687 | prf->Update(prf->prfctx, ie->skeyid_a, ie->skeyid_len); | |||
| 688 | prf->Update(prf->prfctx, ie->g_xy, ie->g_xy_len); | |||
| 689 | prf->Update(prf->prfctx, exchange->cookies, ISAKMP_HDR_COOKIES_LEN(8 + 8)); | |||
| 690 | prf->Update(prf->prfctx, (unsigned char *)"\2", 1); | |||
| 691 | prf->Final(ie->skeyid_e, prf->prfctx); | |||
| 692 | prf_free(prf); | |||
| 693 | LOG_DBG_BUF((LOG_NEGOTIATION, 80,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e" , ie->skeyid_e, ie->skeyid_len) | |||
| 694 | "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e", ie->skeyid_e,log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e" , ie->skeyid_e, ie->skeyid_len) | |||
| 695 | ie->skeyid_len))log_debug_buf (LOG_NEGOTIATION, 80, "ike_phase_1_post_exchange_KE_NONCE: SKEYID_e" , ie->skeyid_e, ie->skeyid_len); | |||
| 696 | ||||
| 697 | /* Key length determination. */ | |||
| 698 | if (!exchange->key_length) | |||
| 699 | exchange->key_length = exchange->crypto->keymax; | |||
| 700 | ||||
| 701 | /* Derive a longer key from skeyid_e */ | |||
| 702 | if (ie->skeyid_len < exchange->key_length) { | |||
| 703 | u_int16_t len, keylen; | |||
| 704 | u_int8_t *key, *p; | |||
| 705 | ||||
| 706 | prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid_e, | |||
| 707 | ie->skeyid_len); | |||
| 708 | if (!prf) { | |||
| 709 | /* XXX - notify peer */ | |||
| 710 | return -1; | |||
| 711 | } | |||
| 712 | /* Make keylen a multiple of prf->blocksize */ | |||
| 713 | keylen = exchange->key_length; | |||
| 714 | if (keylen % prf->blocksize) | |||
| 715 | keylen += prf->blocksize - (keylen % prf->blocksize); | |||
| 716 | ||||
| 717 | key = malloc(keylen); | |||
| 718 | if (!key) { | |||
| 719 | /* XXX - Notify peer. */ | |||
| 720 | prf_free(prf); | |||
| 721 | log_error("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 722 | "malloc (%d) failed", keylen); | |||
| 723 | return -1; | |||
| 724 | } | |||
| 725 | prf->Init(prf->prfctx); | |||
| 726 | prf->Update(prf->prfctx, (unsigned char *)"\0", 1); | |||
| 727 | prf->Final(key, prf->prfctx); | |||
| 728 | ||||
| 729 | for (len = prf->blocksize, p = key; len < exchange->key_length; | |||
| 730 | len += prf->blocksize, p += prf->blocksize) { | |||
| 731 | prf->Init(prf->prfctx); | |||
| 732 | prf->Update(prf->prfctx, p, prf->blocksize); | |||
| 733 | prf->Final(p + prf->blocksize, prf->prfctx); | |||
| 734 | } | |||
| 735 | prf_free(prf); | |||
| 736 | ||||
| 737 | /* Setup our keystate using the derived encryption key. */ | |||
| 738 | exchange->keystate = crypto_init(exchange->crypto, key, | |||
| 739 | exchange->key_length, &err); | |||
| 740 | ||||
| 741 | free(key); | |||
| 742 | } else | |||
| 743 | /* Setup our keystate using the raw skeyid_e. */ | |||
| 744 | exchange->keystate = crypto_init(exchange->crypto, | |||
| 745 | ie->skeyid_e, exchange->key_length, &err); | |||
| 746 | ||||
| 747 | /* Special handling for DES weak keys. */ | |||
| 748 | if (!exchange->keystate && err == EWEAKKEY && | |||
| 749 | (exchange->key_length << 1) <= ie->skeyid_len) { | |||
| 750 | log_print("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 751 | "weak key, trying subseq. skeyid_e"); | |||
| 752 | exchange->keystate = crypto_init(exchange->crypto, | |||
| 753 | ie->skeyid_e + exchange->key_length, | |||
| 754 | exchange->key_length, &err); | |||
| 755 | } | |||
| 756 | if (!exchange->keystate) { | |||
| 757 | log_print("ike_phase_1_post_exchange_KE_NONCE: " | |||
| 758 | "exchange->crypto->init () failed: %d", err); | |||
| 759 | ||||
| 760 | /* | |||
| 761 | * XXX We really need to know if problems are of transient | |||
| 762 | * nature or fatal (like failed assertions etc.) | |||
| 763 | */ | |||
| 764 | return -1; | |||
| 765 | } | |||
| 766 | /* Setup IV. XXX Only for CBC transforms, no? */ | |||
| 767 | hash->Init(hash->ctx); | |||
| 768 | hash->Update(hash->ctx, ie->g_xi, ie->g_x_len); | |||
| 769 | hash->Update(hash->ctx, ie->g_xr, ie->g_x_len); | |||
| 770 | hash->Final(hash->digest, hash->ctx); | |||
| 771 | crypto_init_iv(exchange->keystate, hash->digest, | |||
| 772 | exchange->crypto->blocksize); | |||
| 773 | return 0; | |||
| 774 | } | |||
| 775 | ||||
| 776 | int | |||
| 777 | ike_phase_1_responder_send_ID_AUTH(struct message *msg) | |||
| 778 | { | |||
| 779 | if (ike_phase_1_send_ID(msg)) | |||
| 780 | return -1; | |||
| 781 | ||||
| 782 | return ike_phase_1_send_AUTH(msg); | |||
| 783 | } | |||
| 784 | ||||
| 785 | int | |||
| 786 | ike_phase_1_send_ID(struct message *msg) | |||
| 787 | { | |||
| 788 | struct exchange *exchange = msg->exchange; | |||
| 789 | u_int8_t *buf; | |||
| 790 | char header[80]; | |||
| 791 | ssize_t sz; | |||
| 792 | struct sockaddr *src; | |||
| 793 | int initiator = exchange->initiator; | |||
| 794 | u_int8_t **id; | |||
| 795 | size_t *id_len; | |||
| 796 | char *my_id = 0, *data; | |||
| 797 | u_int8_t id_type; | |||
| 798 | sa_family_t af = 0; | |||
| 799 | ||||
| 800 | /* Choose the right fields to fill-in. */ | |||
| 801 | id = initiator ? &exchange->id_i : &exchange->id_r; | |||
| 802 | id_len = initiator ? &exchange->id_i_len : &exchange->id_r_len; | |||
| 803 | ||||
| 804 | if (exchange->name) | |||
| 805 | my_id = conf_get_str(exchange->name, "ID"); | |||
| 806 | ||||
| 807 | if (!my_id) | |||
| 808 | my_id = conf_get_str("General", "Default-phase-1-ID"); | |||
| 809 | ||||
| 810 | msg->transport->vtbl->get_src(msg->transport, &src); | |||
| 811 | sz = my_id ? ipsec_id_size(my_id, &id_type) : sockaddr_addrlen(src); | |||
| 812 | if (sz == -1) | |||
| 813 | return -1; | |||
| 814 | ||||
| 815 | sz += ISAKMP_ID_DATA_OFF8; | |||
| 816 | buf = malloc(sz); | |||
| 817 | if (!buf) { | |||
| 818 | log_error("ike_phase_1_send_ID: malloc (%lu) failed", | |||
| 819 | (unsigned long)sz); | |||
| 820 | return -1; | |||
| 821 | } | |||
| 822 | SET_IPSEC_ID_PROTO(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 0, buf + 5, 0); | |||
| 823 | SET_IPSEC_ID_PORT(buf + ISAKMP_ID_DOI_DATA_OFF, 0)field_set_num (ipsec_id_fld + 1, buf + 5, 0); | |||
| 824 | if (my_id) { | |||
| 825 | SET_ISAKMP_ID_TYPE(buf, id_type)field_set_num (isakmp_id_fld + 0, buf, id_type); | |||
| 826 | switch (id_type) { | |||
| 827 | case IPSEC_ID_IPV4_ADDR1: | |||
| 828 | case IPSEC_ID_IPV4_ADDR_SUBNET4: | |||
| 829 | af = AF_INET2; | |||
| 830 | break; | |||
| 831 | case IPSEC_ID_IPV6_ADDR5: | |||
| 832 | case IPSEC_ID_IPV6_ADDR_SUBNET6: | |||
| 833 | af = AF_INET624; | |||
| 834 | break; | |||
| 835 | } | |||
| 836 | switch (id_type) { | |||
| 837 | case IPSEC_ID_IPV4_ADDR1: | |||
| 838 | case IPSEC_ID_IPV6_ADDR5: | |||
| 839 | data = conf_get_str(my_id, "Address"); | |||
| 840 | if (!data) { | |||
| 841 | log_print("ike_phase_1_send_ID: section %s " | |||
| 842 | "has no \"Address\" tag", my_id); | |||
| 843 | free(buf); | |||
| 844 | return -1; | |||
| 845 | } | |||
| 846 | if (text2sockaddr(data, NULL((void*)0), &src, af, 0)) { | |||
| 847 | log_error("ike_phase_1_send_ID: " | |||
| 848 | "text2sockaddr() failed"); | |||
| 849 | free(buf); | |||
| 850 | return -1; | |||
| 851 | } | |||
| 852 | memcpy(buf + ISAKMP_ID_DATA_OFF8, | |||
| 853 | sockaddr_addrdata(src), sockaddr_addrlen(src)); | |||
| 854 | free(src); | |||
| 855 | break; | |||
| 856 | ||||
| 857 | case IPSEC_ID_IPV4_ADDR_SUBNET4: | |||
| 858 | case IPSEC_ID_IPV6_ADDR_SUBNET6: | |||
| 859 | /* Network */ | |||
| 860 | data = conf_get_str(my_id, "Network"); | |||
| 861 | if (!data) { | |||
| 862 | log_print("ike_phase_1_send_ID: section %s " | |||
| 863 | "has no \"Network\" tag", my_id); | |||
| 864 | free(buf); | |||
| 865 | return -1; | |||
| 866 | } | |||
| 867 | if (text2sockaddr(data, NULL((void*)0), &src, af, 0)) { | |||
| 868 | log_error("ike_phase_1_send_ID: " | |||
| 869 | "text2sockaddr() failed"); | |||
| 870 | free(buf); | |||
| 871 | return -1; | |||
| 872 | } | |||
| 873 | memcpy(buf + ISAKMP_ID_DATA_OFF8, | |||
| 874 | sockaddr_addrdata(src), sockaddr_addrlen(src)); | |||
| 875 | free(src); | |||
| 876 | /* Netmask */ | |||
| 877 | data = conf_get_str(my_id, "Netmask"); | |||
| 878 | if (!data) { | |||
| 879 | log_print("ike_phase_1_send_ID: section %s " | |||
| 880 | "has no \"Netmask\" tag", my_id); | |||
| 881 | free(buf); | |||
| 882 | return -1; | |||
| 883 | } | |||
| 884 | if (text2sockaddr(data, NULL((void*)0), &src, af, 1)) { | |||
| 885 | log_error("ike_phase_1_send_ID: " | |||
| 886 | "text2sockaddr() failed"); | |||
| 887 | free(buf); | |||
| 888 | return -1; | |||
| 889 | } | |||
| 890 | memcpy(buf + ISAKMP_ID_DATA_OFF8 + | |||
| 891 | sockaddr_addrlen(src), sockaddr_addrdata(src), | |||
| 892 | sockaddr_addrlen(src)); | |||
| 893 | free(src); | |||
| 894 | break; | |||
| 895 | ||||
| 896 | case IPSEC_ID_FQDN2: | |||
| 897 | case IPSEC_ID_USER_FQDN3: | |||
| 898 | case IPSEC_ID_KEY_ID11: | |||
| 899 | data = conf_get_str(my_id, "Name"); | |||
| 900 | if (!data) { | |||
| 901 | log_print("ike_phase_1_send_ID: section %s " | |||
| 902 | "has no \"Name\" tag", my_id); | |||
| 903 | free(buf); | |||
| 904 | return -1; | |||
| 905 | } | |||
| 906 | memcpy(buf + ISAKMP_ID_DATA_OFF8, data, | |||
| 907 | sz - ISAKMP_ID_DATA_OFF8); | |||
| 908 | break; | |||
| 909 | ||||
| 910 | default: | |||
| 911 | log_print("ike_phase_1_send_ID: " | |||
| 912 | "unsupported ID type %d", id_type); | |||
| 913 | free(buf); | |||
| 914 | return -1; | |||
| 915 | } | |||
| 916 | } else { | |||
| 917 | switch (src->sa_family) { | |||
| 918 | case AF_INET2: | |||
| 919 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV4_ADDR)field_set_num (isakmp_id_fld + 0, buf, 1); | |||
| 920 | break; | |||
| 921 | case AF_INET624: | |||
| 922 | SET_ISAKMP_ID_TYPE(buf, IPSEC_ID_IPV6_ADDR)field_set_num (isakmp_id_fld + 0, buf, 5); | |||
| 923 | break; | |||
| 924 | } | |||
| 925 | /* Already in network byteorder. */ | |||
| 926 | memcpy(buf + ISAKMP_ID_DATA_OFF8, sockaddr_addrdata(src), | |||
| 927 | sockaddr_addrlen(src)); | |||
| 928 | } | |||
| 929 | ||||
| 930 | if (message_add_payload(msg, ISAKMP_PAYLOAD_ID5, buf, sz, 1)) { | |||
| 931 | free(buf); | |||
| 932 | return -1; | |||
| 933 | } | |||
| 934 | *id_len = sz - ISAKMP_GEN_SZ4; | |||
| 935 | *id = malloc(*id_len); | |||
| 936 | if (!*id) { | |||
| 937 | log_error("ike_phase_1_send_ID: malloc (%lu) failed", | |||
| 938 | (unsigned long)*id_len); | |||
| 939 | return -1; | |||
| 940 | } | |||
| 941 | memcpy(*id, buf + ISAKMP_GEN_SZ4, *id_len); | |||
| 942 | snprintf(header, sizeof header, "ike_phase_1_send_ID: %s", | |||
| 943 | constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(buf)field_get_num (isakmp_id_fld + 0, buf))); | |||
| 944 | LOG_DBG_BUF((LOG_NEGOTIATION, 40, header, buf + ISAKMP_ID_DATA_OFF,log_debug_buf (LOG_NEGOTIATION, 40, header, buf + 8, sz - 8) | |||
| 945 | sz - ISAKMP_ID_DATA_OFF))log_debug_buf (LOG_NEGOTIATION, 40, header, buf + 8, sz - 8); | |||
| 946 | return 0; | |||
| 947 | } | |||
| 948 | ||||
| 949 | int | |||
| 950 | ike_phase_1_send_AUTH(struct message *msg) | |||
| 951 | { | |||
| 952 | struct exchange *exchange = msg->exchange; | |||
| 953 | struct ipsec_exch *ie = exchange->data; | |||
| 954 | ||||
| 955 | if (ie->ike_auth->encode_hash(msg)) { | |||
| 956 | /* XXX Log? */ | |||
| 957 | return -1; | |||
| 958 | } | |||
| 959 | /* | |||
| 960 | * XXX Many people say the COMMIT flag is just junk, especially in | |||
| 961 | * Phase 1. | |||
| 962 | */ | |||
| 963 | #ifdef notyet | |||
| 964 | if ((exchange->flags & EXCHANGE_FLAG_COMMITTED(0x0001 | 0x0002)) == 0) | |||
| 965 | exchange->flags |= EXCHANGE_FLAG_I_COMMITTED0x0001; | |||
| 966 | #endif | |||
| 967 | ||||
| 968 | return 0; | |||
| 969 | } | |||
| 970 | ||||
| 971 | /* Receive ID and HASH and check that the exchange has been consistent. */ | |||
| 972 | int | |||
| 973 | ike_phase_1_recv_ID_AUTH(struct message *msg) | |||
| 974 | { | |||
| 975 | if (ike_phase_1_recv_ID(msg)) | |||
| 976 | return -1; | |||
| 977 | ||||
| 978 | return ike_phase_1_recv_AUTH(msg); | |||
| 979 | } | |||
| 980 | ||||
| 981 | /* Receive ID. */ | |||
| 982 | int | |||
| 983 | ike_phase_1_recv_ID(struct message *msg) | |||
| 984 | { | |||
| 985 | struct exchange *exchange = msg->exchange; | |||
| 986 | struct payload *payload; | |||
| 987 | char header[80], *rs = 0, *rid = 0, *p; | |||
| 988 | int initiator = exchange->initiator; | |||
| 989 | u_int8_t **id, id_type; | |||
| 990 | size_t *id_len; | |||
| 991 | ssize_t sz; | |||
| 992 | struct sockaddr *sa; | |||
| 993 | sa_family_t af = 0; | |||
| 994 | ||||
| 995 | payload = payload_first(msg, ISAKMP_PAYLOAD_ID5); | |||
| 996 | ||||
| 997 | if (exchange->name) | |||
| 998 | rs = conf_get_str(exchange->name, "Remote-ID"); | |||
| 999 | ||||
| 1000 | if (rs) { | |||
| 1001 | sz = ipsec_id_size(rs, &id_type); | |||
| 1002 | if (sz == -1) { | |||
| 1003 | log_print("ike_phase_1_recv_ID: could not handle " | |||
| 1004 | "specified Remote-ID [%s]", rs); | |||
| 1005 | return -1; | |||
| 1006 | } | |||
| 1007 | rid = malloc(sz); | |||
| 1008 | if (!rid) { | |||
| 1009 | log_error("ike_phase_1_recv_ID: malloc (%lu) failed", | |||
| 1010 | (unsigned long)sz); | |||
| 1011 | return -1; | |||
| 1012 | } | |||
| 1013 | switch (id_type) { | |||
| 1014 | case IPSEC_ID_IPV4_ADDR1: | |||
| 1015 | af = AF_INET2; | |||
| 1016 | break; | |||
| 1017 | case IPSEC_ID_IPV6_ADDR5: | |||
| 1018 | af = AF_INET624; | |||
| 1019 | break; | |||
| 1020 | } | |||
| 1021 | switch (id_type) { | |||
| 1022 | case IPSEC_ID_IPV4_ADDR1: | |||
| 1023 | case IPSEC_ID_IPV6_ADDR5: | |||
| 1024 | p = conf_get_str(rs, "Address"); | |||
| 1025 | if (!p) { | |||
| 1026 | log_print("ike_phase_1_recv_ID: failed to get " | |||
| 1027 | "Address in Remote-ID section [%s]", rs); | |||
| 1028 | free(rid); | |||
| 1029 | return -1; | |||
| 1030 | } | |||
| 1031 | if (text2sockaddr(p, 0, &sa, af, 0) == -1) { | |||
| 1032 | log_print("ike_phase_1_recv_ID: " | |||
| 1033 | "failed to parse address %s", p); | |||
| 1034 | free(rid); | |||
| 1035 | return -1; | |||
| 1036 | } | |||
| 1037 | if ((id_type == IPSEC_ID_IPV4_ADDR1 && | |||
| 1038 | sa->sa_family != AF_INET2) || | |||
| 1039 | (id_type == IPSEC_ID_IPV6_ADDR5 && | |||
| 1040 | sa->sa_family != AF_INET624)) { | |||
| 1041 | log_print("ike_phase_1_recv_ID: " | |||
| 1042 | "address %s not of expected family", p); | |||
| 1043 | free(rid); | |||
| 1044 | free(sa); | |||
| 1045 | return -1; | |||
| 1046 | } | |||
| 1047 | memcpy(rid, sockaddr_addrdata(sa), | |||
| 1048 | sockaddr_addrlen(sa)); | |||
| 1049 | free(sa); | |||
| 1050 | break; | |||
| 1051 | ||||
| 1052 | case IPSEC_ID_FQDN2: | |||
| 1053 | case IPSEC_ID_USER_FQDN3: | |||
| 1054 | case IPSEC_ID_KEY_ID11: | |||
| 1055 | p = conf_get_str(rs, "Name"); | |||
| 1056 | if (!p) { | |||
| 1057 | log_print("ike_phase_1_recv_ID: failed to " | |||
| 1058 | "get Name in Remote-ID section [%s]", rs); | |||
| 1059 | free(rid); | |||
| 1060 | return -1; | |||
| 1061 | } | |||
| 1062 | memcpy(rid, p, sz); | |||
| 1063 | break; | |||
| 1064 | ||||
| 1065 | default: | |||
| 1066 | log_print("ike_phase_1_recv_ID: " | |||
| 1067 | "unsupported ID type %d", id_type); | |||
| 1068 | free(rid); | |||
| 1069 | return -1; | |||
| 1070 | } | |||
| 1071 | ||||
| 1072 | /* Compare expected/desired and received remote ID */ | |||
| 1073 | if (memcmp(rid, payload->p + ISAKMP_ID_DATA_OFF8, sz) != 0) { | |||
| 1074 | free(rid); | |||
| 1075 | log_print("ike_phase_1_recv_ID: " | |||
| 1076 | "received remote ID other than expected %s", p); | |||
| 1077 | return -1; | |||
| 1078 | } | |||
| 1079 | free(rid); | |||
| 1080 | } | |||
| 1081 | /* Choose the right fields to fill in */ | |||
| 1082 | id = initiator ? &exchange->id_r : &exchange->id_i; | |||
| 1083 | id_len = initiator ? &exchange->id_r_len : &exchange->id_i_len; | |||
| 1084 | ||||
| 1085 | *id_len = GET_ISAKMP_GEN_LENGTH(payload->p)field_get_num (isakmp_gen_fld + 2, payload->p) - ISAKMP_GEN_SZ4; | |||
| 1086 | *id = malloc(*id_len); | |||
| 1087 | if (!*id) { | |||
| 1088 | log_error("ike_phase_1_recv_ID: malloc (%lu) failed", | |||
| 1089 | (unsigned long)*id_len); | |||
| 1090 | return -1; | |||
| 1091 | } | |||
| 1092 | memcpy(*id, payload->p + ISAKMP_GEN_SZ4, *id_len); | |||
| 1093 | snprintf(header, sizeof header, "ike_phase_1_recv_ID: %s", | |||
| 1094 | constant_name(ipsec_id_cst, GET_ISAKMP_ID_TYPE(payload->p)field_get_num (isakmp_id_fld + 0, payload->p))); | |||
| 1095 | LOG_DBG_BUF((LOG_NEGOTIATION, 40, header,log_debug_buf (LOG_NEGOTIATION, 40, header, payload->p + 8 , *id_len + 4 - 8) | |||
| 1096 | payload->p + ISAKMP_ID_DATA_OFF,log_debug_buf (LOG_NEGOTIATION, 40, header, payload->p + 8 , *id_len + 4 - 8) | |||
| 1097 | *id_len + ISAKMP_GEN_SZ - ISAKMP_ID_DATA_OFF))log_debug_buf (LOG_NEGOTIATION, 40, header, payload->p + 8 , *id_len + 4 - 8); | |||
| 1098 | payload->flags |= PL_MARK1; | |||
| 1099 | return 0; | |||
| 1100 | } | |||
| 1101 | ||||
| 1102 | /* Receive HASH and check that the exchange has been consistent. */ | |||
| 1103 | int | |||
| 1104 | ike_phase_1_recv_AUTH(struct message *msg) | |||
| 1105 | { | |||
| 1106 | struct exchange *exchange = msg->exchange; | |||
| 1107 | struct ipsec_exch *ie = exchange->data; | |||
| 1108 | struct prf *prf; | |||
| 1109 | struct hash *hash = ie->hash; | |||
| 1110 | char header[80]; | |||
| 1111 | size_t hashsize = hash->hashsize; | |||
| 1112 | int initiator = exchange->initiator; | |||
| 1113 | u_int8_t **hash_p, *id; | |||
| 1114 | size_t id_len; | |||
| 1115 | ||||
| 1116 | /* Choose the right fields to fill in */ | |||
| 1117 | hash_p = initiator ? &ie->hash_r : &ie->hash_i; | |||
| 1118 | id = initiator ? exchange->id_r : exchange->id_i; | |||
| 1119 | id_len = initiator ? exchange->id_r_len : exchange->id_i_len; | |||
| 1120 | ||||
| 1121 | /* The decoded hash will be in ie->hash_r or ie->hash_i */ | |||
| 1122 | if (ie->ike_auth->decode_hash(msg)) { | |||
| 1123 | message_drop(msg, ISAKMP_NOTIFY_INVALID_ID_INFORMATION18, 0, 1, | |||
| 1124 | 0); | |||
| 1125 | return -1; | |||
| 1126 | } | |||
| 1127 | /* Allocate the prf and start calculating his HASH. */ | |||
| 1128 | prf = prf_alloc(ie->prf_type, hash->type, ie->skeyid, ie->skeyid_len); | |||
| 1129 | if (!prf) { | |||
| 1130 | /* XXX Log? */ | |||
| 1131 | return -1; | |||
| 1132 | } | |||
| 1133 | prf->Init(prf->prfctx); | |||
| 1134 | prf->Update(prf->prfctx, initiator ? ie->g_xr : ie->g_xi, ie->g_x_len); | |||
| 1135 | prf->Update(prf->prfctx, initiator ? ie->g_xi : ie->g_xr, ie->g_x_len); | |||
| 1136 | prf->Update(prf->prfctx, exchange->cookies + | |||
| 1137 | (initiator ? ISAKMP_HDR_RCOOKIE_OFF8 : ISAKMP_HDR_ICOOKIE_OFF0), | |||
| 1138 | ISAKMP_HDR_ICOOKIE_LEN8); | |||
| 1139 | prf->Update(prf->prfctx, exchange->cookies + | |||
| 1140 | (initiator ? ISAKMP_HDR_ICOOKIE_OFF0 : ISAKMP_HDR_RCOOKIE_OFF8), | |||
| 1141 | ISAKMP_HDR_ICOOKIE_LEN8); | |||
| 1142 | prf->Update(prf->prfctx, ie->sa_i_b, ie->sa_i_b_len); | |||
| 1143 | prf->Update(prf->prfctx, id, id_len); | |||
| 1144 | prf->Final(hash->digest, prf->prfctx); | |||
| 1145 | prf_free(prf); | |||
| 1146 | snprintf(header, sizeof header, "ike_phase_1_recv_AUTH: " | |||
| 1147 | "computed HASH_%c", initiator ? 'R' : 'I'); | |||
| 1148 | LOG_DBG_BUF((LOG_NEGOTIATION, 80, header, hash->digest, hashsize))log_debug_buf (LOG_NEGOTIATION, 80, header, hash->digest, hashsize ); | |||
| 1149 | ||||
| 1150 | /* Check that the hash we got matches the one we computed. */ | |||
| 1151 | if (memcmp(*hash_p, hash->digest, hashsize) != 0) { | |||
| 1152 | /* XXX Log? */ | |||
| 1153 | return -1; | |||
| 1154 | } | |||
| 1155 | ||||
| 1156 | /* Mark message as authenticated. */ | |||
| 1157 | msg->flags |= MSG_AUTHENTICATED0x10; | |||
| 1158 | ||||
| 1159 | return 0; | |||
| 1160 | } | |||
| 1161 | ||||
| 1162 | struct attr_node { | |||
| 1163 | LIST_ENTRY(attr_node)struct { struct attr_node *le_next; struct attr_node **le_prev ; } link; | |||
| 1164 | u_int16_t type; | |||
| 1165 | }; | |||
| 1166 | ||||
| 1167 | struct validation_state { | |||
| 1168 | struct conf_list_node *xf; | |||
| 1169 | LIST_HEAD(attr_head, attr_node)struct attr_head { struct attr_node *lh_first; } attrs; | |||
| 1170 | char *life; | |||
| 1171 | }; | |||
| 1172 | ||||
| 1173 | /* Validate a proposal inside SA according to EXCHANGE's policy. */ | |||
| 1174 | static int | |||
| 1175 | ike_phase_1_validate_prop(struct exchange *exchange, struct sa *sa, | |||
| 1176 | struct sa *isakmp_sa) | |||
| 1177 | { | |||
| 1178 | struct conf_list *conf, *tags; | |||
| 1179 | struct conf_list_node *xf, *tag; | |||
| 1180 | struct proto *proto; | |||
| 1181 | struct validation_state vs; | |||
| 1182 | struct attr_node *node, *next_node; | |||
| 1183 | ||||
| 1184 | /* Get the list of transforms. */ | |||
| 1185 | conf = conf_get_list(exchange->policy, "Transforms"); | |||
| 1186 | if (!conf) | |||
| ||||
| 1187 | return 0; | |||
| 1188 | ||||
| 1189 | for (xf = TAILQ_FIRST(&conf->fields)((&conf->fields)->tqh_first); xf; xf = TAILQ_NEXT(xf, link)((xf)->link.tqe_next)) { | |||
| 1190 | for (proto = TAILQ_FIRST(&sa->protos)((&sa->protos)->tqh_first); proto; | |||
| 1191 | proto = TAILQ_NEXT(proto, link)((proto)->link.tqe_next)) { | |||
| 1192 | /* Mark all attributes in our policy as unseen. */ | |||
| 1193 | LIST_INIT(&vs.attrs)do { ((&vs.attrs)->lh_first) = ((void*)0); } while (0); | |||
| 1194 | vs.xf = xf; | |||
| 1195 | vs.life = 0; | |||
| 1196 | if (attribute_map(proto->chosen->p + | |||
| 1197 | ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
| 1198 | GET_ISAKMP_GEN_LENGTH(proto->chosen->p)field_get_num (isakmp_gen_fld + 2, proto->chosen->p) - | |||
| 1199 | ISAKMP_TRANSFORM_SA_ATTRS_OFF8, | |||
| 1200 | attribute_unacceptable, &vs)) | |||
| 1201 | goto try_next; | |||
| 1202 | ||||
| 1203 | /* Sweep over unseen tags in this section. */ | |||
| 1204 | tags = conf_get_tag_list(xf->field); | |||
| 1205 | if (tags) { | |||
| 1206 | for (tag = TAILQ_FIRST(&tags->fields)((&tags->fields)->tqh_first); tag; | |||
| 1207 | tag = TAILQ_NEXT(tag, link)((tag)->link.tqe_next)) | |||
| 1208 | /* | |||
| 1209 | * XXX Should we care about attributes | |||
| 1210 | * we have, they do not provide? | |||
| 1211 | */ | |||
| 1212 | for (node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
| 1213 | node; node = next_node) { | |||
| 1214 | next_node = | |||
| 1215 | LIST_NEXT(node, link)((node)->link.le_next); | |||
| 1216 | if (node->type == | |||
| 1217 | constant_value(ike_attr_cst, | |||
| 1218 | tag->field)) { | |||
| 1219 | LIST_REMOVE(node, link)do { if ((node)->link.le_next != ((void*)0)) (node)->link .le_next->link.le_prev = (node)->link.le_prev; *(node)-> link.le_prev = (node)->link.le_next; ; ; } while (0); | |||
| 1220 | free(node); | |||
| 1221 | } | |||
| 1222 | } | |||
| 1223 | conf_free_list(tags); | |||
| 1224 | } | |||
| 1225 | /* Are there leftover tags in this section? */ | |||
| 1226 | node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
| 1227 | if (node) | |||
| 1228 | goto try_next; | |||
| 1229 | } | |||
| 1230 | ||||
| 1231 | /* All protocols were OK, we succeeded. */ | |||
| 1232 | LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: "log_debug (LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: " "success") | |||
| 1233 | "success"))log_debug (LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: " "success"); | |||
| 1234 | conf_free_list(conf); | |||
| 1235 | free(vs.life); | |||
| ||||
| 1236 | return 1; | |||
| 1237 | ||||
| 1238 | try_next: | |||
| 1239 | /* Are there leftover tags in this section? */ | |||
| 1240 | node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
| 1241 | while (node) { | |||
| 1242 | LIST_REMOVE(node, link)do { if ((node)->link.le_next != ((void*)0)) (node)->link .le_next->link.le_prev = (node)->link.le_prev; *(node)-> link.le_prev = (node)->link.le_next; ; ; } while (0); | |||
| 1243 | free(node); | |||
| 1244 | node = LIST_FIRST(&vs.attrs)((&vs.attrs)->lh_first); | |||
| 1245 | } | |||
| 1246 | free(vs.life); | |||
| 1247 | } | |||
| 1248 | ||||
| 1249 | LOG_DBG((LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure"))log_debug (LOG_NEGOTIATION, 20, "ike_phase_1_validate_prop: failure" ); | |||
| 1250 | conf_free_list(conf); | |||
| 1251 | return 0; | |||
| 1252 | } | |||
| 1253 | ||||
| 1254 | /* | |||
| 1255 | * Look at the attribute of type TYPE, located at VALUE for LEN bytes forward. | |||
| 1256 | * The VVS argument holds a validation state kept across invocations. | |||
| 1257 | * If the attribute is unacceptable to use, return non-zero, otherwise zero. | |||
| 1258 | */ | |||
| 1259 | static int | |||
| 1260 | attribute_unacceptable(u_int16_t type, u_int8_t *value, u_int16_t len, | |||
| 1261 | void *vvs) | |||
| 1262 | { | |||
| 1263 | struct validation_state *vs = vvs; | |||
| 1264 | struct conf_list *life_conf; | |||
| 1265 | struct conf_list_node *xf = vs->xf, *life; | |||
| 1266 | char *tag = constant_lookup(ike_attr_cst, type); | |||
| 1267 | char *str; | |||
| 1268 | struct constant_map *map; | |||
| 1269 | struct attr_node *node; | |||
| 1270 | int rv, dur = 0; | |||
| 1271 | ||||
| 1272 | if (!tag) { | |||
| 1273 | log_print("attribute_unacceptable: " | |||
| 1274 | "attribute type %d not known", type); | |||
| 1275 | return 1; | |||
| 1276 | } | |||
| 1277 | switch (type) { | |||
| 1278 | case IKE_ATTR_ENCRYPTION_ALGORITHM1: | |||
| 1279 | case IKE_ATTR_HASH_ALGORITHM2: | |||
| 1280 | case IKE_ATTR_AUTHENTICATION_METHOD3: | |||
| 1281 | case IKE_ATTR_GROUP_DESCRIPTION4: | |||
| 1282 | case IKE_ATTR_GROUP_TYPE5: | |||
| 1283 | case IKE_ATTR_PRF13: | |||
| 1284 | str = conf_get_str(xf->field, tag); | |||
| 1285 | if (!str) { | |||
| 1286 | /* This attribute does not exist in this policy. */ | |||
| 1287 | log_print("attribute_unacceptable: " | |||
| 1288 | "attr %s does not exist in %s", tag, xf->field); | |||
| 1289 | return 1; | |||
| 1290 | } | |||
| 1291 | map = constant_link_lookup(ike_attr_cst, type); | |||
| 1292 | if (!map) | |||
| 1293 | return 1; | |||
| 1294 | ||||
| 1295 | if ((constant_value(map, str) == decode_16(value)) || | |||
| 1296 | (!strcmp(str, "ANY"))) { | |||
| 1297 | /* Mark this attribute as seen. */ | |||
| 1298 | node = malloc(sizeof *node); | |||
| 1299 | if (!node) { | |||
| 1300 | log_error("attribute_unacceptable: " | |||
| 1301 | "malloc (%lu) failed", | |||
| 1302 | (unsigned long)sizeof *node); | |||
| 1303 | return 1; | |||
| 1304 | } | |||
| 1305 | node->type = type; | |||
| 1306 | LIST_INSERT_HEAD(&vs->attrs, node, link)do { if (((node)->link.le_next = (&vs->attrs)->lh_first ) != ((void*)0)) (&vs->attrs)->lh_first->link.le_prev = &(node)->link.le_next; (&vs->attrs)->lh_first = (node); (node)->link.le_prev = &(&vs->attrs) ->lh_first; } while (0); | |||
| 1307 | return 0; | |||
| 1308 | } | |||
| 1309 | log_print("attribute_unacceptable: %s: got %s, expected %s", | |||
| 1310 | tag, constant_name(map, decode_16(value)), str); | |||
| 1311 | return 1; | |||
| 1312 | ||||
| 1313 | case IKE_ATTR_GROUP_PRIME6: | |||
| 1314 | case IKE_ATTR_GROUP_GENERATOR_17: | |||
| 1315 | case IKE_ATTR_GROUP_GENERATOR_28: | |||
| 1316 | case IKE_ATTR_GROUP_CURVE_A9: | |||
| 1317 | case IKE_ATTR_GROUP_CURVE_B10: | |||
| 1318 | /* XXX Bignums not handled yet. */ | |||
| 1319 | log_print("attribute_unacceptable: " | |||
| 1320 | "bignum type %d not supported", type); | |||
| 1321 | return 1; | |||
| 1322 | ||||
| 1323 | case IKE_ATTR_LIFE_TYPE11: | |||
| 1324 | case IKE_ATTR_LIFE_DURATION12: | |||
| 1325 | life_conf = conf_get_list(xf->field, "Life"); | |||
| 1326 | if (life_conf && | |||
| 1327 | !strcmp(conf_get_str(xf->field, "Life"), "ANY")) { | |||
| 1328 | conf_free_list(life_conf); | |||
| 1329 | return 0; | |||
| 1330 | } | |||
| 1331 | ||||
| 1332 | rv = 1; | |||
| 1333 | if (!life_conf) { | |||
| 1334 | /* Life attributes given, but not in our policy. */ | |||
| 1335 | log_print("attribute_unacceptable: " | |||
| 1336 | "life attribute received, none in policy"); | |||
| 1337 | return 1; | |||
| 1338 | } | |||
| 1339 | /* | |||
| 1340 | * Each lifetime type must match, otherwise we turn the | |||
| 1341 | * proposal down. In order to do this we need to find the | |||
| 1342 | * specific section of our policy's "Life" list and match | |||
| 1343 | * its duration. | |||
| 1344 | */ | |||
| 1345 | switch (type) { | |||
| 1346 | case IKE_ATTR_LIFE_TYPE11: | |||
| 1347 | for (life = TAILQ_FIRST(&life_conf->fields)((&life_conf->fields)->tqh_first); life; | |||
| 1348 | life = TAILQ_NEXT(life, link)((life)->link.tqe_next)) { | |||
| 1349 | str = conf_get_str(life->field, "LIFE_TYPE"); | |||
| 1350 | if (!str) { | |||
| 1351 | log_print("attribute_unacceptable: " | |||
| 1352 | "section [%s] has no LIFE_TYPE", | |||
| 1353 | life->field); | |||
| 1354 | continue; | |||
| 1355 | } | |||
| 1356 | ||||
| 1357 | /* | |||
| 1358 | * If this is the type we are looking at, | |||
| 1359 | * save a pointer to this section in vs->life. | |||
| 1360 | */ | |||
| 1361 | if (constant_value(ike_duration_cst, str) == | |||
| 1362 | decode_16(value)) { | |||
| 1363 | vs->life = strdup(life->field); | |||
| 1364 | rv = 0; | |||
| 1365 | goto bail_out; | |||
| 1366 | } | |||
| 1367 | } | |||
| 1368 | log_print("attribute_unacceptable: " | |||
| 1369 | "unrecognized LIFE_TYPE %d", decode_16(value)); | |||
| 1370 | vs->life = 0; | |||
| 1371 | break; | |||
| 1372 | ||||
| 1373 | case IKE_ATTR_LIFE_DURATION12: | |||
| 1374 | if (!vs->life) { | |||
| 1375 | log_print("attribute_unacceptable: " | |||
| 1376 | "LIFE_DURATION without LIFE_TYPE"); | |||
| 1377 | rv = 1; | |||
| 1378 | goto bail_out; | |||
| 1379 | } | |||
| 1380 | str = conf_get_str(vs->life, "LIFE_DURATION"); | |||
| 1381 | if (str) { | |||
| 1382 | if (!strcmp(str, "ANY")) | |||
| 1383 | rv = 0; | |||
| 1384 | else { | |||
| 1385 | dur = (len == 4) ? decode_32(value) : | |||
| 1386 | decode_16(value); | |||
| 1387 | if ((rv = !conf_match_num(vs->life, | |||
| 1388 | "LIFE_DURATION", dur))) { | |||
| 1389 | log_print( | |||
| 1390 | "attribute_unacceptable: " | |||
| 1391 | "LIFE_DURATION: got %d, " | |||
| 1392 | " expected %s", dur, str); | |||
| 1393 | } | |||
| 1394 | } | |||
| 1395 | } else { | |||
| 1396 | log_print("attribute_unacceptable: " | |||
| 1397 | "section [%s] has no LIFE_DURATION", | |||
| 1398 | vs->life); | |||
| 1399 | rv = 1; | |||
| 1400 | } | |||
| 1401 | ||||
| 1402 | free(vs->life); | |||
| 1403 | vs->life = 0; | |||
| 1404 | break; | |||
| 1405 | } | |||
| 1406 | ||||
| 1407 | bail_out: | |||
| 1408 | conf_free_list(life_conf); | |||
| 1409 | return rv; | |||
| 1410 | ||||
| 1411 | case IKE_ATTR_KEY_LENGTH14: | |||
| 1412 | case IKE_ATTR_FIELD_SIZE15: | |||
| 1413 | case IKE_ATTR_GROUP_ORDER16: | |||
| 1414 | if (conf_match_num(xf->field, tag, decode_16(value))) { | |||
| 1415 | /* Mark this attribute as seen. */ | |||
| 1416 | node = malloc(sizeof *node); | |||
| 1417 | if (!node) { | |||
| 1418 | log_error("attribute_unacceptable: " | |||
| 1419 | "malloc (%lu) failed", | |||
| 1420 | (unsigned long)sizeof *node); | |||
| 1421 | return 1; | |||
| 1422 | } | |||
| 1423 | node->type = type; | |||
| 1424 | LIST_INSERT_HEAD(&vs->attrs, node, link)do { if (((node)->link.le_next = (&vs->attrs)->lh_first ) != ((void*)0)) (&vs->attrs)->lh_first->link.le_prev = &(node)->link.le_next; (&vs->attrs)->lh_first = (node); (node)->link.le_prev = &(&vs->attrs) ->lh_first; } while (0); | |||
| 1425 | return 0; | |||
| 1426 | } | |||
| 1427 | return 1; | |||
| 1428 | default: | |||
| 1429 | log_print("attribute_unacceptable: unexpected type %d", | |||
| 1430 | type); | |||
| 1431 | } | |||
| 1432 | return 1; | |||
| 1433 | } |