| File: | programs/pluto/ikev2.c |
| Warning: | line 2905, column 8 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* demultiplex incoming IKE messages | |||
| 2 | * | |||
| 3 | * Copyright (C) 1997 Angelos D. Keromytis. | |||
| 4 | * Copyright (C) 1998-2010,2013-2017 D. Hugh Redelmeier <hugh@mimosa.com> | |||
| 5 | * Copyright (C) 2007-2008 Michael Richardson <mcr@xelerance.com> | |||
| 6 | * Copyright (C) 2009 David McCullough <david_mccullough@securecomputing.com> | |||
| 7 | * Copyright (C) 2008-2011 Paul Wouters <paul@xelerance.com> | |||
| 8 | * Copyright (C) 2010 Simon Deziel <simon@xelerance.com> | |||
| 9 | * Copyright (C) 2010 Tuomo Soini <tis@foobar.fi> | |||
| 10 | * Copyright (C) 2011-2012 Avesh Agarwal <avagarwa@redhat.com> | |||
| 11 | * Copyright (C) 2012 Paul Wouters <paul@libreswan.org> | |||
| 12 | * Copyright (C) 2012-2019 Paul Wouters <pwouters@redhat.com> | |||
| 13 | * Copyright (C) 2013 Matt Rogers <mrogers@redhat.com> | |||
| 14 | * Copyright (C) 2015-2019 Andrew Cagney | |||
| 15 | * Copyright (C) 2016-2018 Antony Antony <appu@phenome.org> | |||
| 16 | * Copyright (C) 2017 Sahana Prasad <sahana.prasad07@gmail.com> | |||
| 17 | * Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com> | |||
| 18 | * Copyright (C) 2021 Paul Wouters <paul.wouters@aiven.io> | |||
| 19 | * | |||
| 20 | * This program is free software; you can redistribute it and/or modify it | |||
| 21 | * under the terms of the GNU General Public License as published by the | |||
| 22 | * Free Software Foundation; either version 2 of the License, or (at your | |||
| 23 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. | |||
| 24 | * | |||
| 25 | * This program is distributed in the hope that it will be useful, but | |||
| 26 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
| 27 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
| 28 | * for more details. | |||
| 29 | * | |||
| 30 | */ | |||
| 31 | ||||
| 32 | #include <unistd.h> | |||
| 33 | #include <sys/types.h> | |||
| 34 | #include <sys/socket.h> | |||
| 35 | #include <netinet/in.h> | |||
| 36 | #include <arpa/inet.h> | |||
| 37 | ||||
| 38 | ||||
| 39 | #include "sysdep.h" | |||
| 40 | #include "constants.h" | |||
| 41 | ||||
| 42 | #include "defs.h" | |||
| 43 | #include "id.h" | |||
| 44 | #include "x509.h" | |||
| 45 | #include "pluto_x509.h" | |||
| 46 | #include "certs.h" | |||
| 47 | #include "connections.h" /* needs id.h */ | |||
| 48 | #include "state.h" | |||
| 49 | #include "packet.h" | |||
| 50 | #include "crypto.h" | |||
| 51 | #include "crypt_symkey.h" | |||
| 52 | #include "ike_alg.h" | |||
| 53 | #include "log.h" | |||
| 54 | #include "demux.h" /* needs packet.h */ | |||
| 55 | #include "ikev2.h" | |||
| 56 | #include "ipsec_doi.h" /* needs demux.h and state.h */ | |||
| 57 | #include "timer.h" | |||
| 58 | #include "whack.h" /* requires connections.h */ | |||
| 59 | #include "server.h" | |||
| 60 | #include "nat_traversal.h" | |||
| 61 | #include "vendor.h" | |||
| 62 | #include "ip_address.h" | |||
| 63 | #include "ikev2_send.h" | |||
| 64 | #include "state_db.h" | |||
| 65 | #include "ietf_constants.h" | |||
| 66 | #include "ikev2_cookie.h" | |||
| 67 | #include "plutoalg.h" /* for default_ike_groups */ | |||
| 68 | #include "ikev2_message.h" /* for ikev2_decrypt_msg() */ | |||
| 69 | #include "pluto_stats.h" | |||
| 70 | #include "keywords.h" | |||
| 71 | #include "ikev2_msgid.h" | |||
| 72 | #include "ikev2_redirect.h" | |||
| 73 | #include "ikev2_states.h" | |||
| 74 | #include "ip_endpoint.h" | |||
| 75 | #include "host_pair.h" /* for find_v2_host_connection() */ | |||
| 76 | #include "kernel.h" | |||
| 77 | #include "iface.h" | |||
| 78 | #include "ikev2_notify.h" | |||
| 79 | #include "unpack.h" | |||
| 80 | #include "pending.h" /* for release_pending_whacks() */ | |||
| 81 | #include "ikev2_host_pair.h" | |||
| 82 | #include "ikev2_ike_sa_init.h" | |||
| 83 | #include "ikev2_informational.h" | |||
| 84 | #include "ikev2_create_child_sa.h" | |||
| 85 | #include "ikev2_ike_intermediate.h" | |||
| 86 | #include "ikev2_ike_auth.h" | |||
| 87 | #include "ikev2_delete.h" /* for record_v2_delete() */ | |||
| 88 | #include "ikev2_child.h" /* for jam_v2_child_sa_details() */ | |||
| 89 | ||||
| 90 | /* | |||
| 91 | * IKEv2 has slightly different states than IKEv1. | |||
| 92 | * | |||
| 93 | * IKEv2 puts all the responsibility for retransmission on the end that | |||
| 94 | * wants to do something, usually, that the initiator. (But, not always | |||
| 95 | * the original initiator, of the responder decides it needs to rekey first) | |||
| 96 | * | |||
| 97 | * Each exchange has a bit that indicates if it is an Initiator message, | |||
| 98 | * or if it is a response. The Responder never retransmits its messages | |||
| 99 | * except in response to an Initiator retransmission. | |||
| 100 | * | |||
| 101 | * The message ID is *NOT* used in the cryptographic state at all, but instead | |||
| 102 | * serves the role of a sequence number. This makes the state machine far | |||
| 103 | * simpler, and there really are no exceptions. | |||
| 104 | * | |||
| 105 | * The upper level state machine is therefore much simpler. | |||
| 106 | * The lower level takes care of retransmissions, and the upper layer state | |||
| 107 | * machine just has to worry about whether it needs to go into cookie mode, | |||
| 108 | * etc. | |||
| 109 | * | |||
| 110 | * Like IKEv1, IKEv2 can have multiple child SAs. Like IKEv1, each one of | |||
| 111 | * the child SAs ("Phase 2") will get their own state. Unlike IKEv1, | |||
| 112 | * an implementation may negotiate multiple CHILD_SAs at the same time | |||
| 113 | * using different MessageIDs. This is enabled by an option (a notify) | |||
| 114 | * that the responder sends to the initiator. The initiator may only | |||
| 115 | * do concurrent negotiations if it sees the notify. | |||
| 116 | * | |||
| 117 | * XXX This implementation does not support concurrency, but it shouldn't be | |||
| 118 | * that hard to do. The most difficult part will be to map the message IDs | |||
| 119 | * to the right state. Some CHILD_SAs may take multiple round trips, | |||
| 120 | * and each one will have to be mapped to the same state. | |||
| 121 | * | |||
| 122 | * The IKEv2 state values are chosen from the same state space as IKEv1. | |||
| 123 | * | |||
| 124 | */ | |||
| 125 | ||||
| 126 | /* | |||
| 127 | * From RFC 5996 syntax: [optional] and {encrypted} | |||
| 128 | * | |||
| 129 | * Initiator Responder | |||
| 130 | * ------------------------------------------------------------------- | |||
| 131 | * | |||
| 132 | * IKE_SA_INIT exchange (initial exchange): | |||
| 133 | * | |||
| 134 | * HDR, SAi1, KEi, Ni --> | |||
| 135 | * <-- HDR, SAr1, KEr, Nr, [CERTREQ] | |||
| 136 | * | |||
| 137 | * IKE_AUTH exchange (after IKE_SA_INIT exchange): | |||
| 138 | * | |||
| 139 | * HDR, SK {IDi, [CERT,] [CERTREQ,] | |||
| 140 | * [IDr,] AUTH, SAi2, | |||
| 141 | * TSi, TSr} --> | |||
| 142 | * <-- HDR, SK {IDr, [CERT,] AUTH, | |||
| 143 | * SAr2, TSi, TSr} | |||
| 144 | * [Parent SA (SAx1) established. Child SA (SAx2) may have been established] | |||
| 145 | * | |||
| 146 | * | |||
| 147 | * Extended IKE_AUTH (see RFC 5996bis 2.6): | |||
| 148 | * | |||
| 149 | * HDR(A,0), SAi1, KEi, Ni --> | |||
| 150 | * <-- HDR(A,0), N(COOKIE) | |||
| 151 | * HDR(A,0), N(COOKIE), SAi1, | |||
| 152 | * KEi, Ni --> | |||
| 153 | * <-- HDR(A,B), SAr1, KEr, | |||
| 154 | * Nr, [CERTREQ] | |||
| 155 | * HDR(A,B), SK {IDi, [CERT,] | |||
| 156 | * [CERTREQ,] [IDr,] AUTH, | |||
| 157 | * SAi2, TSi, TSr} --> | |||
| 158 | * <-- HDR(A,B), SK {IDr, [CERT,] | |||
| 159 | * AUTH, SAr2, TSi, TSr} | |||
| 160 | * [Parent SA (SAx1) established. Child SA (SAx2) may have been established] | |||
| 161 | * | |||
| 162 | * | |||
| 163 | * CREATE_CHILD_SA Exchange (new child variant RFC 5996 1.3.1): | |||
| 164 | * | |||
| 165 | * HDR, SK {SA, Ni, [KEi], | |||
| 166 | * TSi, TSr} --> | |||
| 167 | * <-- HDR, SK {SA, Nr, [KEr], | |||
| 168 | * TSi, TSr} | |||
| 169 | * | |||
| 170 | * | |||
| 171 | * CREATE_CHILD_SA Exchange (rekey child variant RFC 5996 1.3.3): | |||
| 172 | * | |||
| 173 | * HDR, SK {N(REKEY_SA), SA, Ni, [KEi], | |||
| 174 | * TSi, TSr} --> | |||
| 175 | * <-- HDR, SK {SA, Nr, [KEr], | |||
| 176 | * TSi, TSr} | |||
| 177 | * | |||
| 178 | * | |||
| 179 | * CREATE_CHILD_SA Exchange (rekey parent SA variant RFC 5996 1.3.2): | |||
| 180 | * | |||
| 181 | * HDR, SK {SA, Ni, KEi} --> | |||
| 182 | * <-- HDR, SK {SA, Nr, KEr} | |||
| 183 | */ | |||
| 184 | ||||
| 185 | /* Short forms for building payload type sets */ | |||
| 186 | ||||
| 187 | #define P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) LELEM(ISAKMP_NEXT_v2##N)((lset_t)1 << (ISAKMP_NEXT_v2##N)) | |||
| 188 | ||||
| 189 | /* | |||
| 190 | * IKEv2 State transitions (aka microcodes). | |||
| 191 | * | |||
| 192 | * This table contains all possible state transitions, some of which | |||
| 193 | * involve a message. | |||
| 194 | * | |||
| 195 | * During initialization this table parsed populating the | |||
| 196 | * corresponding IKEv2 finite states. While not the most efficient, | |||
| 197 | * it seems to work. | |||
| 198 | */ | |||
| 199 | ||||
| 200 | static /*const*/ struct v2_state_transition v2_state_transition_table[] = { | |||
| 201 | ||||
| 202 | #define req_clear_payloads message_payloads.required /* required unencrypted payloads (allows just one) for received packet */ | |||
| 203 | #define opt_clear_payloads message_payloads.optional /* optional unencrypted payloads (none or one) for received packet */ | |||
| 204 | #define req_enc_payloads encrypted_payloads.required /* required encrypted payloads (allows just one) for received packet */ | |||
| 205 | #define opt_enc_payloads encrypted_payloads.optional /* optional encrypted payloads (none or one) for received packet */ | |||
| 206 | ||||
| 207 | /* no state: --> I1 | |||
| 208 | * HDR, SAi1, KEi, Ni --> | |||
| 209 | */ | |||
| 210 | { .story = "initiate IKE_SA_INIT", | |||
| 211 | .state = STATE_V2_PARENT_I0, | |||
| 212 | .next_state = STATE_V2_PARENT_I1, | |||
| 213 | .send = MESSAGE_REQUEST, | |||
| 214 | .processor = NULL((void*)0), | |||
| 215 | .timeout_event = EVENT_RETRANSMIT, }, | |||
| 216 | ||||
| 217 | /* STATE_V2_PARENT_I1: R1B --> I1B | |||
| 218 | * <-- HDR, N | |||
| 219 | * HDR, N, SAi1, KEi, Ni --> | |||
| 220 | */ | |||
| 221 | ||||
| 222 | { .story = "received anti-DDOS COOKIE notify response; resending IKE_SA_INIT request with cookie payload added", | |||
| 223 | .state = STATE_V2_PARENT_I1, | |||
| 224 | .next_state = STATE_V2_PARENT_I0, | |||
| 225 | .flags = SMF2_SUPPRESS_SUCCESS_LOG, | |||
| 226 | .send = NO_MESSAGE, | |||
| 227 | .message_payloads = { .required = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)), .notification = v2N_COOKIE, }, | |||
| 228 | .processor = ikev2_in_IKE_SA_INIT_R_v2N_COOKIE, | |||
| 229 | .recv_role = MESSAGE_RESPONSE, | |||
| 230 | .recv_type = ISAKMP_v2_IKE_SA_INIT, | |||
| 231 | .timeout_event = EVENT_SA_DISCARD, }, | |||
| 232 | ||||
| 233 | { .story = "received IKE_SA_INIT INVALID_KE_PAYLOAD notify response; resending IKE_SA_INIT with new KE payload", | |||
| 234 | .state = STATE_V2_PARENT_I1, | |||
| 235 | .next_state = STATE_V2_PARENT_I0, | |||
| 236 | .flags = SMF2_SUPPRESS_SUCCESS_LOG, | |||
| 237 | .send = NO_MESSAGE, | |||
| 238 | .message_payloads = { .required = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)), .notification = v2N_INVALID_KE_PAYLOAD, }, | |||
| 239 | .processor = process_v2_IKE_SA_INIT_response_v2N_INVALID_KE_PAYLOAD, | |||
| 240 | .recv_role = MESSAGE_RESPONSE, | |||
| 241 | .recv_type = ISAKMP_v2_IKE_SA_INIT, | |||
| 242 | .timeout_event = EVENT_SA_DISCARD, }, | |||
| 243 | ||||
| 244 | { .story = "received REDIRECT notify response; resending IKE_SA_INIT request to new destination", | |||
| 245 | .state = STATE_V2_PARENT_I1, | |||
| 246 | .next_state = STATE_V2_IKE_SA_DELETE, | |||
| 247 | .flags = SMF2_SUPPRESS_SUCCESS_LOG, | |||
| 248 | .send = NO_MESSAGE, | |||
| 249 | .message_payloads = { .required = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)), .notification = v2N_REDIRECT, }, | |||
| 250 | .processor = ikev2_in_IKE_SA_INIT_R_v2N_REDIRECT, | |||
| 251 | .recv_role = MESSAGE_RESPONSE, | |||
| 252 | .recv_type = ISAKMP_v2_IKE_SA_INIT, | |||
| 253 | /* XXX: this is an instant timeout */ | |||
| 254 | .timeout_event = EVENT_v2_REDIRECT, | |||
| 255 | }, | |||
| 256 | ||||
| 257 | /* STATE_V2_PARENT_I1: R1 --> I2 | |||
| 258 | * <-- HDR, SAr1, KEr, Nr, [CERTREQ] | |||
| 259 | * HDR, SK {IDi, [CERT,] [CERTREQ,] | |||
| 260 | * [IDr,] AUTH, SAi2, | |||
| 261 | * TSi, TSr} --> | |||
| 262 | */ | |||
| 263 | { .story = "Initiator: process IKE_SA_INIT reply, initiate IKE_AUTH or IKE_INTERMEDIATE", | |||
| 264 | .state = STATE_V2_PARENT_I1, | |||
| 265 | .next_state = STATE_V2_PARENT_I2, | |||
| 266 | .send = MESSAGE_REQUEST, | |||
| 267 | .req_clear_payloads = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)) | P(Nr)((lset_t)1 << (ISAKMP_NEXT_v2Nr)), | |||
| 268 | .opt_clear_payloads = P(CERTREQ)((lset_t)1 << (ISAKMP_NEXT_v2CERTREQ)), | |||
| 269 | .processor = process_v2_IKE_SA_INIT_response, | |||
| 270 | .recv_role = MESSAGE_RESPONSE, | |||
| 271 | .recv_type = ISAKMP_v2_IKE_SA_INIT, | |||
| 272 | .timeout_event = EVENT_RETRANSMIT, }, | |||
| 273 | ||||
| 274 | { .story = "Initiator: process IKE_INTERMEDIATE reply, initiate IKE_AUTH or IKE_INTERMEDIATE", | |||
| 275 | .state = STATE_V2_PARENT_I2, | |||
| 276 | .next_state = STATE_V2_PARENT_I2, | |||
| 277 | .flags = MESSAGE_RESPONSE, | |||
| 278 | .send = MESSAGE_REQUEST, | |||
| 279 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 280 | .opt_clear_payloads = LEMPTY((lset_t)0), | |||
| 281 | .processor = process_v2_IKE_INTERMEDIATE_response, | |||
| 282 | .recv_role = MESSAGE_RESPONSE, | |||
| 283 | .recv_type = ISAKMP_v2_IKE_INTERMEDIATE, | |||
| 284 | .timeout_event = EVENT_RETRANSMIT, }, | |||
| 285 | ||||
| 286 | /* STATE_V2_PARENT_I2: R2 --> | |||
| 287 | * <-- HDR, SK {IDr, [CERT,] AUTH, | |||
| 288 | * SAr2, TSi, TSr} | |||
| 289 | * [Parent SA established] | |||
| 290 | */ | |||
| 291 | ||||
| 292 | /* | |||
| 293 | * This pair of state transitions should be merged? | |||
| 294 | */ | |||
| 295 | { .story = "Initiator: process IKE_AUTH response", | |||
| 296 | .state = STATE_V2_PARENT_I2, | |||
| 297 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 298 | /* logged mid transition */ | |||
| 299 | .flags = SMF2_SUPPRESS_SUCCESS_LOG|SMF2_RELEASE_WHACK, | |||
| 300 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 301 | .req_enc_payloads = P(IDr)((lset_t)1 << (ISAKMP_NEXT_v2IDr)) | P(AUTH)((lset_t)1 << (ISAKMP_NEXT_v2AUTH)), | |||
| 302 | .opt_enc_payloads = P(CERT)((lset_t)1 << (ISAKMP_NEXT_v2CERT)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)) | P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(TSi)((lset_t)1 << (ISAKMP_NEXT_v2TSi)) | P(TSr)((lset_t)1 << (ISAKMP_NEXT_v2TSr)), | |||
| 303 | .processor = process_v2_IKE_AUTH_response, | |||
| 304 | .recv_role = MESSAGE_RESPONSE, | |||
| 305 | .recv_type = ISAKMP_v2_IKE_AUTH, | |||
| 306 | .timeout_event = EVENT_SA_REPLACE, | |||
| 307 | }, | |||
| 308 | ||||
| 309 | { .story = "Initiator: processing IKE_AUTH failure response", | |||
| 310 | .state = STATE_V2_PARENT_I2, | |||
| 311 | .next_state = STATE_V2_PARENT_I2, | |||
| 312 | .message_payloads = { .required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), }, | |||
| 313 | /* .encrypted_payloads = { .required = P(N), }, */ | |||
| 314 | .processor = process_v2_IKE_AUTH_failure_response, | |||
| 315 | .recv_role = MESSAGE_RESPONSE, | |||
| 316 | .recv_type = ISAKMP_v2_IKE_AUTH, | |||
| 317 | }, | |||
| 318 | ||||
| 319 | /* no state: none I1 --> R1 | |||
| 320 | * <-- HDR, SAi1, KEi, Ni | |||
| 321 | * HDR, SAr1, KEr, Nr, [CERTREQ] --> | |||
| 322 | */ | |||
| 323 | { .story = "Respond to IKE_SA_INIT", | |||
| 324 | .state = STATE_V2_PARENT_R0, | |||
| 325 | .next_state = STATE_V2_PARENT_R1, | |||
| 326 | .send = MESSAGE_RESPONSE, | |||
| 327 | .req_clear_payloads = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)), | |||
| 328 | .processor = process_v2_IKE_SA_INIT_request, | |||
| 329 | .recv_role = MESSAGE_REQUEST, | |||
| 330 | .recv_type = ISAKMP_v2_IKE_SA_INIT, | |||
| 331 | .timeout_event = EVENT_SA_DISCARD, }, | |||
| 332 | ||||
| 333 | /* STATE_V2_PARENT_R1: I2 --> R2 | |||
| 334 | * <-- HDR, SK {IDi, [CERT,] [CERTREQ,] | |||
| 335 | * [IDr,] AUTH, SAi2, | |||
| 336 | * TSi, TSr} | |||
| 337 | * HDR, SK {IDr, [CERT,] AUTH, | |||
| 338 | * SAr2, TSi, TSr} --> | |||
| 339 | * | |||
| 340 | * [Parent SA established] | |||
| 341 | */ | |||
| 342 | { .story = "Responder: process IKE_AUTH request (no SKEYSEED)", | |||
| 343 | .state = STATE_V2_PARENT_R1, | |||
| 344 | .next_state = STATE_V2_PARENT_R1, | |||
| 345 | .flags = SMF2_NO_SKEYSEED, | |||
| 346 | .send = MESSAGE_RESPONSE, | |||
| 347 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 348 | .req_enc_payloads = LEMPTY((lset_t)0), | |||
| 349 | .opt_enc_payloads = LEMPTY((lset_t)0), | |||
| 350 | .processor = process_v2_IKE_AUTH_request_no_skeyseed, | |||
| 351 | .recv_role = MESSAGE_REQUEST, | |||
| 352 | .recv_type = ISAKMP_v2_IKE_AUTH, | |||
| 353 | .timeout_event = EVENT_SA_DISCARD, }, | |||
| 354 | ||||
| 355 | { .story = "Responder: process IKE_INTERMEDIATE request (no SKEYSEED)", | |||
| 356 | .state = STATE_V2_PARENT_R1, | |||
| 357 | .next_state = STATE_V2_PARENT_R1, | |||
| 358 | .flags = MESSAGE_REQUEST | SMF2_NO_SKEYSEED, | |||
| 359 | .send = MESSAGE_RESPONSE, | |||
| 360 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 361 | .req_enc_payloads = LEMPTY((lset_t)0), | |||
| 362 | .opt_enc_payloads = LEMPTY((lset_t)0), | |||
| 363 | .processor = process_v2_IKE_INTERMEDIATE_request_no_skeyseed, | |||
| 364 | .recv_role = MESSAGE_REQUEST, | |||
| 365 | .recv_type = ISAKMP_v2_IKE_INTERMEDIATE, | |||
| 366 | .timeout_event = EVENT_SA_DISCARD, }, | |||
| 367 | ||||
| 368 | { .story = "Responder: process IKE_INTERMEDIATE request (with SKEYSEED)", | |||
| 369 | .state = STATE_V2_PARENT_R1, | |||
| 370 | .next_state = STATE_V2_PARENT_R1, | |||
| 371 | .flags = MESSAGE_REQUEST, | |||
| 372 | .send = MESSAGE_RESPONSE, | |||
| 373 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 374 | .req_enc_payloads = LEMPTY((lset_t)0), | |||
| 375 | .opt_enc_payloads = LEMPTY((lset_t)0), | |||
| 376 | .processor = process_v2_IKE_INTERMEDIATE_request, | |||
| 377 | .recv_role = MESSAGE_REQUEST, | |||
| 378 | .recv_type = ISAKMP_v2_IKE_INTERMEDIATE, | |||
| 379 | .timeout_event = EVENT_SA_DISCARD, }, | |||
| 380 | ||||
| 381 | /* | |||
| 382 | * These two transitions should be merged; the no-child | |||
| 383 | * variant is just so that the code can be hobbled. | |||
| 384 | */ | |||
| 385 | ||||
| 386 | { .story = "Responder: process IKE_AUTH request", | |||
| 387 | .state = STATE_V2_PARENT_R1, | |||
| 388 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 389 | .flags = SMF2_SUPPRESS_SUCCESS_LOG|SMF2_RELEASE_WHACK, | |||
| 390 | .send = MESSAGE_RESPONSE, | |||
| 391 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 392 | .req_enc_payloads = P(IDi)((lset_t)1 << (ISAKMP_NEXT_v2IDi)) | P(AUTH)((lset_t)1 << (ISAKMP_NEXT_v2AUTH)), | |||
| 393 | .opt_enc_payloads = P(CERT)((lset_t)1 << (ISAKMP_NEXT_v2CERT)) | P(CERTREQ)((lset_t)1 << (ISAKMP_NEXT_v2CERTREQ)) | P(IDr)((lset_t)1 << (ISAKMP_NEXT_v2IDr)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)) | P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(TSi)((lset_t)1 << (ISAKMP_NEXT_v2TSi)) | P(TSr)((lset_t)1 << (ISAKMP_NEXT_v2TSr)), | |||
| 394 | .processor = process_v2_IKE_AUTH_request, | |||
| 395 | .recv_role = MESSAGE_REQUEST, | |||
| 396 | .recv_type = ISAKMP_v2_IKE_AUTH, | |||
| 397 | .timeout_event = EVENT_SA_REPLACE, }, | |||
| 398 | ||||
| 399 | /* | |||
| 400 | * There are three different CREATE_CHILD_SA's invocations, | |||
| 401 | * this is the combined write up (not in RFC). See above for | |||
| 402 | * individual cases from RFC. | |||
| 403 | * | |||
| 404 | * The order that they rekey here matters. | |||
| 405 | * | |||
| 406 | * HDR, SK {SA, Ni, [KEi], [N(REKEY_SA)], [TSi, TSr]} --> | |||
| 407 | * <-- HDR, SK {N} | |||
| 408 | * <-- HDR, SK {SA, Nr, [KEr], [TSi, TSr]} | |||
| 409 | */ | |||
| 410 | ||||
| 411 | /* | |||
| 412 | * CREATE_CHILD_SA exchange to rekey IKE SA. | |||
| 413 | * | |||
| 414 | * In the responder, note the lack of TS (traffic selectors) | |||
| 415 | * payload. Since rekey and create child exchanges contain TS | |||
| 416 | * they won't match. | |||
| 417 | */ | |||
| 418 | ||||
| 419 | /* no state: --> CREATE_CHILD IKE Rekey Request | |||
| 420 | * HDR, SAi, KEi, Ni --> | |||
| 421 | */ | |||
| 422 | ||||
| 423 | { .story = "initiate rekey IKE_SA (CREATE_CHILD_SA)", | |||
| 424 | .state = STATE_V2_REKEY_IKE_I0, | |||
| 425 | .next_state = STATE_V2_REKEY_IKE_I1, | |||
| 426 | .send = MESSAGE_REQUEST, | |||
| 427 | .processor = initiate_v2_CREATE_CHILD_SA_rekey_ike_request, | |||
| 428 | .timeout_event = EVENT_RETRANSMIT, }, | |||
| 429 | ||||
| 430 | { .story = "process rekey IKE SA request (CREATE_CHILD_SA)", | |||
| 431 | .state = STATE_V2_REKEY_IKE_R0, | |||
| 432 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 433 | .send = MESSAGE_RESPONSE, | |||
| 434 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 435 | .req_enc_payloads = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)) | P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)), | |||
| 436 | .opt_enc_payloads = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)), | |||
| 437 | .processor = process_v2_CREATE_CHILD_SA_rekey_ike_request, | |||
| 438 | .recv_role = MESSAGE_REQUEST, | |||
| 439 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 440 | .timeout_event = EVENT_SA_REPLACE }, | |||
| 441 | ||||
| 442 | { .story = "process rekey IKE SA response (CREATE_CHILD_SA)", | |||
| 443 | .state = STATE_V2_REKEY_IKE_I1, | |||
| 444 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 445 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 446 | .req_enc_payloads = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)) | P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)), | |||
| 447 | .opt_enc_payloads = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)), | |||
| 448 | .processor = process_v2_CREATE_CHILD_SA_rekey_ike_response, | |||
| 449 | .recv_role = MESSAGE_RESPONSE, | |||
| 450 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 451 | .timeout_event = EVENT_SA_REPLACE, }, | |||
| 452 | ||||
| 453 | { .story = "process rekey IKE SA failure response (CREATE_CHILD_SA)", | |||
| 454 | .state = STATE_V2_REKEY_IKE_I1, | |||
| 455 | .next_state = STATE_V2_CHILD_SA_DELETE, /* never reached */ | |||
| 456 | .flags = SMF2_RELEASE_WHACK, | |||
| 457 | .message_payloads = { .required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), }, | |||
| 458 | .processor = process_v2_CREATE_CHILD_SA_failure_response, | |||
| 459 | .recv_role = MESSAGE_RESPONSE, | |||
| 460 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 461 | .timeout_event = EVENT_RETAIN, /* no timeout really */ | |||
| 462 | }, | |||
| 463 | ||||
| 464 | /* | |||
| 465 | * CREATE_CHILD_SA exchange to rekey existing child. | |||
| 466 | * | |||
| 467 | * In the responder, note the presence of both TS (traffic | |||
| 468 | * selectors) payload and REKEY_SA notification. Since a | |||
| 469 | * create child does not include the REKEY_SA notify it won't | |||
| 470 | * match. | |||
| 471 | */ | |||
| 472 | ||||
| 473 | { .story = "initiate rekey Child SA (CREATE_CHILD_SA)", | |||
| 474 | .state = STATE_V2_REKEY_CHILD_I0, | |||
| 475 | .next_state = STATE_V2_REKEY_CHILD_I1, | |||
| 476 | .send = MESSAGE_REQUEST, | |||
| 477 | .processor = initiate_v2_CREATE_CHILD_SA_rekey_child_request, | |||
| 478 | .timeout_event = EVENT_RETRANSMIT, }, | |||
| 479 | ||||
| 480 | { .story = "process rekey Child SA request (CREATE_CHILD_SA)", | |||
| 481 | .state = STATE_V2_REKEY_CHILD_R0, | |||
| 482 | .next_state = STATE_V2_ESTABLISHED_CHILD_SA, | |||
| 483 | .flags = SMF2_RELEASE_WHACK, | |||
| 484 | .send = MESSAGE_RESPONSE, | |||
| 485 | .message_payloads.required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 486 | .encrypted_payloads.required = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)) | P(TSi)((lset_t)1 << (ISAKMP_NEXT_v2TSi)) | P(TSr)((lset_t)1 << (ISAKMP_NEXT_v2TSr)), | |||
| 487 | .encrypted_payloads.optional = P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)) | P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 488 | .encrypted_payloads.notification = v2N_REKEY_SA, | |||
| 489 | .processor = process_v2_CREATE_CHILD_SA_rekey_child_request, | |||
| 490 | .recv_role = MESSAGE_REQUEST, | |||
| 491 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 492 | .timeout_event = EVENT_SA_REPLACE, }, | |||
| 493 | ||||
| 494 | { .story = "process rekey Child SA response (CREATE_CHILD_SA)", | |||
| 495 | .state = STATE_V2_REKEY_CHILD_I1, | |||
| 496 | .next_state = STATE_V2_ESTABLISHED_CHILD_SA, | |||
| 497 | .flags = SMF2_RELEASE_WHACK, | |||
| 498 | .message_payloads.required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 499 | .encrypted_payloads.required = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)) | P(TSi)((lset_t)1 << (ISAKMP_NEXT_v2TSi)) | P(TSr)((lset_t)1 << (ISAKMP_NEXT_v2TSr)), | |||
| 500 | .encrypted_payloads.optional = P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)) | P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 501 | .processor = process_v2_CREATE_CHILD_SA_rekey_child_response, | |||
| 502 | .recv_role = MESSAGE_RESPONSE, | |||
| 503 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 504 | .timeout_event = EVENT_SA_REPLACE, }, | |||
| 505 | ||||
| 506 | { .story = "process rekey Child SA failure response (CREATE_CHILD_SA)", | |||
| 507 | .state = STATE_V2_REKEY_CHILD_I1, | |||
| 508 | .next_state = STATE_V2_CHILD_SA_DELETE, /* never reached */ | |||
| 509 | .flags = SMF2_RELEASE_WHACK, | |||
| 510 | .message_payloads = { .required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), }, | |||
| 511 | .processor = process_v2_CREATE_CHILD_SA_failure_response, | |||
| 512 | .recv_role = MESSAGE_RESPONSE, | |||
| 513 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 514 | .timeout_event = EVENT_RETAIN, /* no timeout really */ | |||
| 515 | }, | |||
| 516 | ||||
| 517 | /* | |||
| 518 | * CREATE_CHILD_SA exchange to create a new child. | |||
| 519 | * | |||
| 520 | * In the responder note the presence of just TS (traffic | |||
| 521 | * selectors) payloads. Earlier rules will have weeded out | |||
| 522 | * both rekey IKE (no TS payload) and rekey Child (has | |||
| 523 | * REKEY_SA notify) leaving just create new child. | |||
| 524 | */ | |||
| 525 | ||||
| 526 | { .story = "initiate create Child SA (CREATE_CHILD_SA)", | |||
| 527 | .state = STATE_V2_NEW_CHILD_I0, | |||
| 528 | .next_state = STATE_V2_NEW_CHILD_I1, | |||
| 529 | .send = MESSAGE_REQUEST, | |||
| 530 | .processor = initiate_v2_CREATE_CHILD_SA_new_child_request, | |||
| 531 | .timeout_event = EVENT_RETRANSMIT, }, | |||
| 532 | ||||
| 533 | { .story = "process create Child SA request (CREATE_CHILD_SA)", | |||
| 534 | .state = STATE_V2_NEW_CHILD_R0, | |||
| 535 | .next_state = STATE_V2_ESTABLISHED_CHILD_SA, | |||
| 536 | .flags = SMF2_RELEASE_WHACK, | |||
| 537 | .send = MESSAGE_RESPONSE, | |||
| 538 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 539 | .req_enc_payloads = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)) | P(TSi)((lset_t)1 << (ISAKMP_NEXT_v2TSi)) | P(TSr)((lset_t)1 << (ISAKMP_NEXT_v2TSr)), | |||
| 540 | .opt_enc_payloads = P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)) | P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 541 | .processor = process_v2_CREATE_CHILD_SA_new_child_request, | |||
| 542 | .recv_role = MESSAGE_REQUEST, | |||
| 543 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 544 | .timeout_event = EVENT_SA_REPLACE, }, | |||
| 545 | ||||
| 546 | { .story = "process create Child SA response (CREATE_CHILD_SA)", | |||
| 547 | .state = STATE_V2_NEW_CHILD_I1, | |||
| 548 | .next_state = STATE_V2_ESTABLISHED_CHILD_SA, | |||
| 549 | .flags = SMF2_RELEASE_WHACK, | |||
| 550 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 551 | .req_enc_payloads = P(SA)((lset_t)1 << (ISAKMP_NEXT_v2SA)) | P(Ni)((lset_t)1 << (ISAKMP_NEXT_v2Ni)) | P(TSi)((lset_t)1 << (ISAKMP_NEXT_v2TSi)) | P(TSr)((lset_t)1 << (ISAKMP_NEXT_v2TSr)), | |||
| 552 | .opt_enc_payloads = P(KE)((lset_t)1 << (ISAKMP_NEXT_v2KE)) | P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 553 | .processor = process_v2_CREATE_CHILD_SA_new_child_response, | |||
| 554 | .recv_role = MESSAGE_RESPONSE, | |||
| 555 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 556 | .timeout_event = EVENT_SA_REPLACE, }, | |||
| 557 | ||||
| 558 | { .story = "process create Child SA failure response (CREATE_CHILD_SA)", | |||
| 559 | .state = STATE_V2_NEW_CHILD_I1, | |||
| 560 | .next_state = STATE_V2_CHILD_SA_DELETE, /* never reached */ | |||
| 561 | .flags = SMF2_RELEASE_WHACK, | |||
| 562 | .message_payloads = { .required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), }, | |||
| 563 | .processor = process_v2_CREATE_CHILD_SA_failure_response, | |||
| 564 | .recv_role = MESSAGE_RESPONSE, | |||
| 565 | .recv_type = ISAKMP_v2_CREATE_CHILD_SA, | |||
| 566 | .timeout_event = EVENT_RETAIN, /* no timeout really */ | |||
| 567 | }, | |||
| 568 | ||||
| 569 | /* Informational Exchange */ | |||
| 570 | ||||
| 571 | /* RFC 5996 1.4 "The INFORMATIONAL Exchange" | |||
| 572 | * | |||
| 573 | * HDR, SK {[N,] [D,] [CP,] ...} --> | |||
| 574 | * <-- HDR, SK {[N,] [D,] [CP], ...} | |||
| 575 | * | |||
| 576 | * A liveness exchange is a special empty message. | |||
| 577 | * | |||
| 578 | * XXX: since these just generate an empty response, they | |||
| 579 | * might as well have a dedicated liveness function. | |||
| 580 | * | |||
| 581 | * XXX: rather than all this transition duplication, the | |||
| 582 | * established states should share common transition stored | |||
| 583 | * outside of this table. | |||
| 584 | */ | |||
| 585 | ||||
| 586 | { .story = "Informational Request (liveness probe)", | |||
| 587 | .state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 588 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 589 | .flags = SMF2_SUPPRESS_SUCCESS_LOG, | |||
| 590 | .send = MESSAGE_RESPONSE, | |||
| 591 | .message_payloads.required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 592 | .processor = process_v2_INFORMATIONAL_request, | |||
| 593 | .recv_role = MESSAGE_REQUEST, | |||
| 594 | .recv_type = ISAKMP_v2_INFORMATIONAL, | |||
| 595 | .timeout_event = EVENT_RETAIN, }, | |||
| 596 | ||||
| 597 | { .story = "Informational Response (liveness probe)", | |||
| 598 | .state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 599 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 600 | .flags = SMF2_SUPPRESS_SUCCESS_LOG|SMF2_RELEASE_WHACK, | |||
| 601 | .message_payloads.required = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 602 | .processor = process_v2_INFORMATIONAL_response, | |||
| 603 | .recv_role = MESSAGE_RESPONSE, | |||
| 604 | .recv_type = ISAKMP_v2_INFORMATIONAL, | |||
| 605 | .timeout_event = EVENT_RETAIN, }, | |||
| 606 | ||||
| 607 | { .story = "Informational Request", | |||
| 608 | .state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 609 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 610 | .send = MESSAGE_RESPONSE, | |||
| 611 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 612 | .opt_enc_payloads = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(D)((lset_t)1 << (ISAKMP_NEXT_v2D)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 613 | .processor = process_v2_INFORMATIONAL_request, | |||
| 614 | .recv_role = MESSAGE_REQUEST, | |||
| 615 | .recv_type = ISAKMP_v2_INFORMATIONAL, | |||
| 616 | .timeout_event = EVENT_RETAIN, }, | |||
| 617 | ||||
| 618 | { .story = "Informational Response", | |||
| 619 | .state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 620 | .recv_type = ISAKMP_v2_INFORMATIONAL, | |||
| 621 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 622 | .opt_enc_payloads = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(D)((lset_t)1 << (ISAKMP_NEXT_v2D)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 623 | .processor = process_v2_INFORMATIONAL_response, | |||
| 624 | .next_state = STATE_V2_ESTABLISHED_IKE_SA, | |||
| 625 | .recv_role = MESSAGE_RESPONSE, | |||
| 626 | .timeout_event = EVENT_RETAIN, }, | |||
| 627 | ||||
| 628 | { .story = "IKE_SA_DEL: process INFORMATIONAL response", | |||
| 629 | .state = STATE_V2_IKE_SA_DELETE, | |||
| 630 | .next_state = STATE_V2_IKE_SA_DELETE, | |||
| 631 | .flags = 0, | |||
| 632 | .req_clear_payloads = P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)), | |||
| 633 | .opt_enc_payloads = P(N)((lset_t)1 << (ISAKMP_NEXT_v2N)) | P(D)((lset_t)1 << (ISAKMP_NEXT_v2D)) | P(CP)((lset_t)1 << (ISAKMP_NEXT_v2CP)), | |||
| 634 | .processor = IKE_SA_DEL_process_v2_INFORMATIONAL_response, | |||
| 635 | .recv_role = MESSAGE_RESPONSE, | |||
| 636 | .recv_type = ISAKMP_v2_INFORMATIONAL, | |||
| 637 | .timeout_event = EVENT_RETAIN, }, | |||
| 638 | ||||
| 639 | /* last entry */ | |||
| 640 | { .story = "roof", | |||
| 641 | .state = STATE_IKEv2_ROOF } | |||
| 642 | ||||
| 643 | #undef req_clear_payloads | |||
| 644 | #undef opt_clear_payloads | |||
| 645 | #undef req_enc_payloads | |||
| 646 | #undef opt_enc_payloads | |||
| 647 | ||||
| 648 | }; | |||
| 649 | ||||
| 650 | void init_ikev2(void) | |||
| 651 | { | |||
| 652 | dbg("checking IKEv2 state table"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("checking IKEv2 state table"); } }; | |||
| 653 | ||||
| 654 | /* | |||
| 655 | * Fill in FINITE_STATES[]. | |||
| 656 | * | |||
| 657 | * This is a hack until each finite-state is a separate object | |||
| 658 | * with corresponding edges (aka microcodes). | |||
| 659 | * | |||
| 660 | * XXX: Long term goal is to have a constant FINITE_STATES[] | |||
| 661 | * contain constant pointers and this static writeable array | |||
| 662 | * to just go away. | |||
| 663 | */ | |||
| 664 | for (enum state_kind kind = STATE_IKEv2_FLOOR; kind < STATE_IKEv2_ROOF; kind++) { | |||
| 665 | /* fill in using static struct */ | |||
| 666 | const struct finite_state *fs = &v2_states[kind - STATE_IKEv2_FLOOR]; | |||
| 667 | passert(fs->kind == kind)({ _Bool assertion__ = fs->kind == kind; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 667, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "fs->kind == kind"); } (void) 1; }); | |||
| 668 | passert(finite_states[kind] == NULL)({ _Bool assertion__ = finite_states[kind] == ((void*)0); if ( !assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 668, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_passert(logger_, here, "%s", "finite_states[kind] == ((void*)0)" ); } (void) 1; }); | |||
| 669 | finite_states[kind] = fs; | |||
| 670 | } | |||
| 671 | ||||
| 672 | /* | |||
| 673 | * Iterate over the state transitions filling in missing bits | |||
| 674 | * and checking for consistency. | |||
| 675 | */ | |||
| 676 | for (struct v2_state_transition *t = v2_state_transition_table; | |||
| 677 | t->state < STATE_IKEv2_ROOF; t++) { | |||
| 678 | ||||
| 679 | passert(t->state >= STATE_IKEv2_FLOOR)({ _Bool assertion__ = t->state >= STATE_IKEv2_FLOOR; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 679, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "t->state >= STATE_IKEv2_FLOOR" ); } (void) 1; }); | |||
| 680 | passert(t->state < STATE_IKEv2_ROOF)({ _Bool assertion__ = t->state < STATE_IKEv2_ROOF; if ( !assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 680, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_passert(logger_, here, "%s", "t->state < STATE_IKEv2_ROOF" ); } (void) 1; }); | |||
| 681 | struct finite_state *from = &v2_states[t->state - STATE_IKEv2_FLOOR]; | |||
| 682 | ||||
| 683 | passert(t->next_state >= STATE_IKEv2_FLOOR)({ _Bool assertion__ = t->next_state >= STATE_IKEv2_FLOOR ; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 683, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "t->next_state >= STATE_IKEv2_FLOOR" ); } (void) 1; }); | |||
| 684 | passert(t->next_state < STATE_IKEv2_ROOF)({ _Bool assertion__ = t->next_state < STATE_IKEv2_ROOF ; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 684, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "t->next_state < STATE_IKEv2_ROOF" ); } (void) 1; }); | |||
| 685 | const struct finite_state *to = finite_states[t->next_state]; | |||
| 686 | passert(to != NULL)({ _Bool assertion__ = to != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 686, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_passert (logger_, here, "%s", "to != ((void*)0)"); } (void) 1; }); | |||
| 687 | ||||
| 688 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
| 689 | if (from->nr_transitions == 0) { | |||
| 690 | LSWLOG_DEBUG(buf)for (char lswbuf[((size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf), sizeof(lswbuf)), *buf = &jambuf ; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*) 0); jambuf_to_logger(buf, &failsafe_logger, DEBUG_STREAM) , buf = ((void*)0)) { | |||
| 691 | jam(buf, " "); | |||
| 692 | lswlog_finite_state(buf, from); | |||
| 693 | jam(buf, ":"); | |||
| 694 | } | |||
| 695 | } | |||
| 696 | const char *send; | |||
| 697 | switch (t->send) { | |||
| 698 | case NO_MESSAGE: send = ""; break; | |||
| 699 | case MESSAGE_REQUEST: send = " send-request"; break; | |||
| 700 | case MESSAGE_RESPONSE: send = " send-response"; break; | |||
| 701 | default: bad_case(t->send)libreswan_bad_case("t->send", (t->send), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 701, }; &here; })); | |||
| 702 | } | |||
| 703 | DBG_log(" -> %s %s%s (%s)", to->short_name, | |||
| 704 | enum_name_short(&event_type_names, | |||
| 705 | t->timeout_event), | |||
| 706 | send, t->story); | |||
| 707 | } | |||
| 708 | ||||
| 709 | /* | |||
| 710 | * Check that the NOTIFY -> PBS -> MD.pbs[]!=NULL will work. | |||
| 711 | */ | |||
| 712 | if (t->message_payloads.notification != v2N_NOTHING_WRONG) { | |||
| 713 | pexpect(v2_pd_from_notification(t->message_payloads.notification) != PD_v2_INVALID)({ _Bool assertion__ = v2_pd_from_notification(t->message_payloads .notification) != PD_v2_INVALID; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 713, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect( logger_, here_, "%s", "v2_pd_from_notification(t->message_payloads.notification) != PD_v2_INVALID" ); } assertion__; }); | |||
| 714 | } | |||
| 715 | if (t->encrypted_payloads.notification != v2N_NOTHING_WRONG) { | |||
| 716 | pexpect(v2_pd_from_notification(t->encrypted_payloads.notification) != PD_v2_INVALID)({ _Bool assertion__ = v2_pd_from_notification(t->encrypted_payloads .notification) != PD_v2_INVALID; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 716, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect( logger_, here_, "%s", "v2_pd_from_notification(t->encrypted_payloads.notification) != PD_v2_INVALID" ); } assertion__; }); | |||
| 717 | } | |||
| 718 | ||||
| 719 | /* | |||
| 720 | * Check recv:MESSAGE_REQUEST->send:MESSAGE_RESPONSE. | |||
| 721 | */ | |||
| 722 | pexpect(t->recv_role == MESSAGE_REQUEST ? t->send = MESSAGE_RESPONSE : true)({ _Bool assertion__ = t->recv_role == MESSAGE_REQUEST ? t ->send = MESSAGE_RESPONSE : 1; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 722, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "t->recv_role == MESSAGE_REQUEST ? t->send = MESSAGE_RESPONSE : 1" ); } assertion__; }); | |||
| 723 | ||||
| 724 | /* | |||
| 725 | * Check recv_type && recv_role | |||
| 726 | */ | |||
| 727 | pexpect(t->recv_role == NO_MESSAGE ? t->recv_type == 0 : t->recv_type != 0)({ _Bool assertion__ = t->recv_role == NO_MESSAGE ? t-> recv_type == 0 : t->recv_type != 0; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 727, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "t->recv_role == NO_MESSAGE ? t->recv_type == 0 : t->recv_type != 0" ); } assertion__; }); | |||
| 728 | ||||
| 729 | /* | |||
| 730 | * Point .fs_v2_microcode at the first transition for | |||
| 731 | * the from state. All other transitions for the from | |||
| 732 | * state should follow immediately after (or to put it | |||
| 733 | * another way, previous should match). | |||
| 734 | */ | |||
| 735 | if (from->v2_transitions == NULL((void*)0)) { | |||
| 736 | /* start of the next state */ | |||
| 737 | passert(from->nr_transitions == 0)({ _Bool assertion__ = from->nr_transitions == 0; if (!assertion__ ) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 737, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "from->nr_transitions == 0" ); } (void) 1; }); | |||
| 738 | from->v2_transitions = t; | |||
| 739 | } else { | |||
| 740 | passert(t[-1].state == t->state)({ _Bool assertion__ = t[-1].state == t->state; if (!assertion__ ) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 740, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "t[-1].state == t->state" ); } (void) 1; }); | |||
| 741 | } | |||
| 742 | from->nr_transitions++; | |||
| 743 | } | |||
| 744 | } | |||
| 745 | ||||
| 746 | /* | |||
| 747 | * split an incoming message into payloads | |||
| 748 | */ | |||
| 749 | struct payload_summary ikev2_decode_payloads(struct logger *log, | |||
| 750 | struct msg_digest *md, | |||
| 751 | pb_stream *in_pbs, | |||
| 752 | enum next_payload_types_ikev2 np) | |||
| 753 | { | |||
| 754 | struct payload_summary summary = { | |||
| 755 | .parsed = true1, | |||
| 756 | .n = v2N_NOTHING_WRONG, | |||
| 757 | }; | |||
| 758 | ||||
| 759 | /* | |||
| 760 | * ??? zero out the digest descriptors -- might nuke | |||
| 761 | * ISAKMP_NEXT_v2SK digest! | |||
| 762 | * | |||
| 763 | * XXX: and v2SKF? Safer to leave them as is and just use new | |||
| 764 | * ones - always add to MD, never take away. | |||
| 765 | */ | |||
| 766 | ||||
| 767 | /* | |||
| 768 | * XXX: Currently, when a message containing an SK payload is | |||
| 769 | * decoded, the encrypted payloads get appended to the | |||
| 770 | * previously decoded non-encrypted payloads. For instance, | |||
| 771 | * given a message containing two notifications: | |||
| 772 | * | |||
| 773 | * N(1), SK{ N(2) } | |||
| 774 | * | |||
| 775 | * The notification digest would contain both the unencrypted | |||
| 776 | * N(1) and encrypted N(2). Since the unencrypted value is | |||
| 777 | * protected, while not very good, isn't really dangerous. | |||
| 778 | */ | |||
| 779 | ||||
| 780 | while (np != ISAKMP_NEXT_v2NONE) { | |||
| 781 | esb_buf b; | |||
| 782 | dbg("Now let's proceed with payload (%s)",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Now let's proceed with payload (%s)", enum_show (&ikev2_payload_names, np, &b)); } } | |||
| 783 | enum_show(&ikev2_payload_names, np, &b)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Now let's proceed with payload (%s)", enum_show (&ikev2_payload_names, np, &b)); } }; | |||
| 784 | ||||
| 785 | if (md->digest_roof >= elemsof(md->digest)(sizeof(md->digest) / sizeof(*(md->digest)))) { | |||
| 786 | llog(RC_LOG_SERIOUS, log, | |||
| 787 | "more than %zu payloads in message; ignored", | |||
| 788 | elemsof(md->digest)(sizeof(md->digest) / sizeof(*(md->digest)))); | |||
| 789 | summary.n = v2N_INVALID_SYNTAX; | |||
| 790 | break; | |||
| 791 | } | |||
| 792 | ||||
| 793 | /* | |||
| 794 | * *pd is the payload digest for this payload. | |||
| 795 | * It has three fields: | |||
| 796 | * pbs is filled in by in_struct | |||
| 797 | * payload is filled in by in_struct | |||
| 798 | * next is filled in by list linking logic | |||
| 799 | */ | |||
| 800 | struct payload_digest *const pd = md->digest + md->digest_roof; | |||
| 801 | ||||
| 802 | /* | |||
| 803 | * map the payload onto its payload descriptor which | |||
| 804 | * describes how to decode it | |||
| 805 | */ | |||
| 806 | const struct_desc *sd = v2_payload_desc(np); | |||
| 807 | ||||
| 808 | if (sd == NULL((void*)0)) { | |||
| 809 | /* | |||
| 810 | * This payload is unknown to us. RFCs 4306 | |||
| 811 | * and 5996 2.5 say that if the payload has | |||
| 812 | * the Critical Bit, we should be upset but if | |||
| 813 | * it does not, we should just ignore it. | |||
| 814 | */ | |||
| 815 | diag_t d = pbs_in_struct(in_pbs, &ikev2_generic_desc, | |||
| 816 | &pd->payload, sizeof(pd->payload), &pd->pbs); | |||
| 817 | if (d != NULL((void*)0)) { | |||
| 818 | llog_diag(RC_LOG_SERIOUS, log, &d, | |||
| 819 | "malformed payload in packet"); | |||
| 820 | summary.n = v2N_INVALID_SYNTAX; | |||
| 821 | break; | |||
| 822 | } | |||
| 823 | if (pd->payload.v2gen.isag_critical & ISAKMP_PAYLOAD_CRITICAL(1<<ISAKMP_PAYLOAD_FLAG_CRITICAL_IX)) { | |||
| 824 | /* | |||
| 825 | * It was critical. See RFC 5996 1.5 | |||
| 826 | * "Version Numbers and Forward | |||
| 827 | * Compatibility" | |||
| 828 | */ | |||
| 829 | const char *role; | |||
| 830 | switch (v2_msg_role(md)) { | |||
| 831 | case MESSAGE_REQUEST: | |||
| 832 | role = "request"; | |||
| 833 | break; | |||
| 834 | case MESSAGE_RESPONSE: | |||
| 835 | role = "response"; | |||
| 836 | break; | |||
| 837 | default: | |||
| 838 | bad_case(v2_msg_role(md))libreswan_bad_case("v2_msg_role(md)", (v2_msg_role(md)), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 838, }; &here; })); | |||
| 839 | } | |||
| 840 | esb_buf b; | |||
| 841 | llog(RC_LOG_SERIOUS, log, | |||
| 842 | "message %s contained an unknown critical payload type (%s)", | |||
| 843 | role, enum_show(&ikev2_payload_names, np, &b)); | |||
| 844 | summary.n = v2N_UNSUPPORTED_CRITICAL_PAYLOAD; | |||
| 845 | summary.data[0] = np; | |||
| 846 | summary.data_size = 1; | |||
| 847 | break; | |||
| 848 | } | |||
| 849 | esb_buf eb; | |||
| 850 | llog(RC_COMMENT, log, | |||
| 851 | "non-critical payload ignored because it contains an unknown or unexpected payload type (%s) at the outermost level", | |||
| 852 | enum_show(&ikev2_payload_names, np, &eb)); | |||
| 853 | np = pd->payload.generic.isag_np; | |||
| 854 | continue; | |||
| 855 | } | |||
| 856 | ||||
| 857 | if (np >= LELEM_ROOF64) { | |||
| 858 | dbg("huge next-payload %u", np){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("huge next-payload %u", np); } }; | |||
| 859 | summary.n = v2N_INVALID_SYNTAX; | |||
| 860 | break; | |||
| 861 | } | |||
| 862 | summary.repeated |= (summary.present & LELEM(np)((lset_t)1 << (np))); | |||
| 863 | summary.present |= LELEM(np)((lset_t)1 << (np)); | |||
| 864 | ||||
| 865 | /* | |||
| 866 | * Read in the payload recording what type it should | |||
| 867 | * be. | |||
| 868 | */ | |||
| 869 | pd->payload_type = np; | |||
| 870 | diag_t d = pbs_in_struct(in_pbs, sd, | |||
| 871 | &pd->payload, sizeof(pd->payload), | |||
| 872 | &pd->pbs); | |||
| 873 | if (d != NULL((void*)0)) { | |||
| 874 | llog_diag(RC_LOG_SERIOUS, log, &d, | |||
| 875 | "malformed payload in packet"); | |||
| 876 | summary.n = v2N_INVALID_SYNTAX; | |||
| 877 | break; | |||
| 878 | } | |||
| 879 | ||||
| 880 | dbg("processing payload: %s (len=%zu)",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("processing payload: %s (len=%zu)", enum_show( &ikev2_payload_names, np, &b), ((size_t)((&pd-> pbs)->roof - (&pd->pbs)->cur))); } } | |||
| 881 | enum_show(&ikev2_payload_names, np, &b),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("processing payload: %s (len=%zu)", enum_show( &ikev2_payload_names, np, &b), ((size_t)((&pd-> pbs)->roof - (&pd->pbs)->cur))); } } | |||
| 882 | pbs_left(&pd->pbs)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("processing payload: %s (len=%zu)", enum_show( &ikev2_payload_names, np, &b), ((size_t)((&pd-> pbs)->roof - (&pd->pbs)->cur))); } }; | |||
| 883 | ||||
| 884 | /* | |||
| 885 | * Place payload at the end of the chain for this | |||
| 886 | * type. | |||
| 887 | */ | |||
| 888 | if (md->last[np] == NULL((void*)0)) { | |||
| 889 | /* first */ | |||
| 890 | md->chain[np] = md->last[np] = pd; | |||
| 891 | pd->next = NULL((void*)0); | |||
| 892 | } else { | |||
| 893 | /* append */ | |||
| 894 | md->last[np]->next = pd; | |||
| 895 | md->last[np] = pd; | |||
| 896 | pd->next = NULL((void*)0); | |||
| 897 | } | |||
| 898 | ||||
| 899 | /* | |||
| 900 | * Go deeper: | |||
| 901 | * | |||
| 902 | * XXX: should this do 'deeper' analysis of packets. | |||
| 903 | * For instance checking the SPI of a notification | |||
| 904 | * payload? Probably not as the value may be ignored. | |||
| 905 | * | |||
| 906 | * The exception is seems to be v2N - both cookie and | |||
| 907 | * redirect code happen early and use the values. | |||
| 908 | */ | |||
| 909 | ||||
| 910 | switch (np) { | |||
| 911 | case ISAKMP_NEXT_v2N: | |||
| 912 | decode_v2N_payload(log, md, pd); | |||
| 913 | break; | |||
| 914 | default: | |||
| 915 | break; | |||
| 916 | } | |||
| 917 | ||||
| 918 | /* | |||
| 919 | * Determine the next payload. | |||
| 920 | * | |||
| 921 | * SK and SKF are special - their next-payload field | |||
| 922 | * is for the first embedded payload - so force it to | |||
| 923 | * NONE: | |||
| 924 | * | |||
| 925 | * RFC 5996 2.14 "Encrypted Payload": | |||
| 926 | * | |||
| 927 | * Next Payload - The payload type of the first | |||
| 928 | * embedded payload. Note that this is an exception | |||
| 929 | * in the standard header format, since the Encrypted | |||
| 930 | * payload is the last payload in the message and | |||
| 931 | * therefore the Next Payload field would normally be | |||
| 932 | * zero. But because the content of this payload is | |||
| 933 | * embedded payloads and there was no natural place to | |||
| 934 | * put the type of the first one, that type is placed | |||
| 935 | * here. | |||
| 936 | */ | |||
| 937 | switch (np) { | |||
| 938 | case ISAKMP_NEXT_v2SK: | |||
| 939 | case ISAKMP_NEXT_v2SKF: | |||
| 940 | /* special */ | |||
| 941 | np = ISAKMP_NEXT_v2NONE; | |||
| 942 | break; | |||
| 943 | default: | |||
| 944 | np = pd->payload.generic.isag_np; | |||
| 945 | break; | |||
| 946 | } | |||
| 947 | ||||
| 948 | md->digest_roof++; | |||
| 949 | } | |||
| 950 | ||||
| 951 | return summary; | |||
| 952 | } | |||
| 953 | ||||
| 954 | static struct child_sa *process_v2_child_ix(struct ike_sa *ike, | |||
| 955 | const struct v2_state_transition *svm) | |||
| 956 | { | |||
| 957 | /* | |||
| 958 | * XXX: Still a mess. Should call processor with the IKE SA. | |||
| 959 | * The processor can then create a nested state. | |||
| 960 | */ | |||
| 961 | enum sa_type sa_type; | |||
| 962 | switch (svm->state) { | |||
| 963 | case STATE_V2_NEW_CHILD_R0: | |||
| 964 | case STATE_V2_REKEY_CHILD_R0: | |||
| 965 | sa_type = IPSEC_SA; | |||
| 966 | break; | |||
| 967 | default: | |||
| 968 | pexpect(svm->state == STATE_V2_REKEY_IKE_R0)({ _Bool assertion__ = svm->state == STATE_V2_REKEY_IKE_R0 ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 968, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "svm->state == STATE_V2_REKEY_IKE_R0" ); } assertion__; }); | |||
| 969 | sa_type = IKE_SA; | |||
| 970 | } | |||
| 971 | ||||
| 972 | struct child_sa *child = new_v2_child_state(ike->sa.st_connection, | |||
| 973 | ike, sa_type, | |||
| 974 | SA_RESPONDER, | |||
| 975 | svm->state, | |||
| 976 | null_fd((struct fd *) ((void*)0))); | |||
| 977 | ||||
| 978 | connection_buf ibuf; | |||
| 979 | connection_buf cbuf; | |||
| 980 | dbg(PRI_CONNECTION" #%lu received %s CREATE_CHILD_SA Child "PRI_CONNECTION" #%lu in %s will process it further",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("\"%s\"%s"" #%lu received %s CREATE_CHILD_SA Child " "\"%s\"%s"" #%lu in %s will process it further", (ike->sa. st_connection)->name, str_connection_instance(ike->sa.st_connection , &ibuf), ike->sa.st_serialno, svm->story, (child-> sa.st_connection)->name, str_connection_instance(child-> sa.st_connection, &cbuf), child->sa.st_serialno, child ->sa.st_state->name); } } | |||
| 981 | pri_connection(ike->sa.st_connection, &ibuf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("\"%s\"%s"" #%lu received %s CREATE_CHILD_SA Child " "\"%s\"%s"" #%lu in %s will process it further", (ike->sa. st_connection)->name, str_connection_instance(ike->sa.st_connection , &ibuf), ike->sa.st_serialno, svm->story, (child-> sa.st_connection)->name, str_connection_instance(child-> sa.st_connection, &cbuf), child->sa.st_serialno, child ->sa.st_state->name); } } | |||
| 982 | ike->sa.st_serialno, svm->story,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("\"%s\"%s"" #%lu received %s CREATE_CHILD_SA Child " "\"%s\"%s"" #%lu in %s will process it further", (ike->sa. st_connection)->name, str_connection_instance(ike->sa.st_connection , &ibuf), ike->sa.st_serialno, svm->story, (child-> sa.st_connection)->name, str_connection_instance(child-> sa.st_connection, &cbuf), child->sa.st_serialno, child ->sa.st_state->name); } } | |||
| 983 | pri_connection(child->sa.st_connection, &cbuf),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("\"%s\"%s"" #%lu received %s CREATE_CHILD_SA Child " "\"%s\"%s"" #%lu in %s will process it further", (ike->sa. st_connection)->name, str_connection_instance(ike->sa.st_connection , &ibuf), ike->sa.st_serialno, svm->story, (child-> sa.st_connection)->name, str_connection_instance(child-> sa.st_connection, &cbuf), child->sa.st_serialno, child ->sa.st_state->name); } } | |||
| 984 | child->sa.st_serialno, child->sa.st_state->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("\"%s\"%s"" #%lu received %s CREATE_CHILD_SA Child " "\"%s\"%s"" #%lu in %s will process it further", (ike->sa. st_connection)->name, str_connection_instance(ike->sa.st_connection , &ibuf), ike->sa.st_serialno, svm->story, (child-> sa.st_connection)->name, str_connection_instance(child-> sa.st_connection, &cbuf), child->sa.st_serialno, child ->sa.st_state->name); } }; | |||
| 985 | ||||
| 986 | return child; | |||
| 987 | } | |||
| 988 | ||||
| 989 | /* | |||
| 990 | * Find the SA (IKE or CHILD), within IKE's family, that is initiated | |||
| 991 | * or is responding to Message ID. | |||
| 992 | * | |||
| 993 | * XXX: There's overlap between this and the is_duplicate_*() code. | |||
| 994 | * For instance, there's little point in looking for a state when the | |||
| 995 | * IKE SA's window shows it too old (at least if we ignore | |||
| 996 | * record'n'send bugs). | |||
| 997 | */ | |||
| 998 | ||||
| 999 | static struct state *find_v2_sa_by_initiator_wip(struct ike_sa *ike, const msgid_t msgid) | |||
| 1000 | { | |||
| 1001 | /* | |||
| 1002 | * XXX: Would a linked list of CHILD SAs work better, would | |||
| 1003 | * mean reference counting? Should this also check that MSGID | |||
| 1004 | * is within the IKE SA's window? | |||
| 1005 | */ | |||
| 1006 | struct state *st; | |||
| 1007 | if (ike->sa.st_v2_msgid_wip.initiator == msgid) { | |||
| 1008 | /* short-cut */ | |||
| 1009 | st = &ike->sa; | |||
| 1010 | } else { | |||
| 1011 | struct state_query stq = { | |||
| 1012 | .where = HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1012, }; &here; }), | |||
| 1013 | .ike_version = IKEv2, | |||
| 1014 | .ike_spis = &ike->sa.st_ike_spis, | |||
| 1015 | }; | |||
| 1016 | st = NULL((void*)0); | |||
| 1017 | while (old2new_state(&stq)) { | |||
| 1018 | if (stq.st->st_v2_msgid_wip.initiator == msgid) { | |||
| 1019 | st = stq.st; | |||
| 1020 | break; | |||
| 1021 | } | |||
| 1022 | } | |||
| 1023 | } | |||
| 1024 | pexpect(st == NULL ||({ _Bool assertion__ = st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno; if ( !assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1026, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno" ); } assertion__; }) | |||
| 1025 | st->st_clonedfrom == SOS_NOBODY ||({ _Bool assertion__ = st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno; if ( !assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1026, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno" ); } assertion__; }) | |||
| 1026 | st->st_clonedfrom == ike->sa.st_serialno)({ _Bool assertion__ = st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno; if ( !assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1026, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno" ); } assertion__; }); | |||
| 1027 | return st; | |||
| 1028 | } | |||
| 1029 | ||||
| 1030 | static struct state *find_v2_sa_by_responder_wip(struct ike_sa *ike, const msgid_t msgid) | |||
| 1031 | { | |||
| 1032 | /* | |||
| 1033 | * XXX: Would a linked list of CHILD SAs work better, would | |||
| 1034 | * mean reference counting? Should this also check that MSGID | |||
| 1035 | * is within the IKE SA's window? | |||
| 1036 | */ | |||
| 1037 | struct state *st; | |||
| 1038 | if (ike->sa.st_v2_msgid_wip.responder == msgid) { | |||
| 1039 | /* short-cut */ | |||
| 1040 | st = &ike->sa; | |||
| 1041 | } else { | |||
| 1042 | struct state_query stq = { | |||
| 1043 | .where = HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1043, }; &here; }), | |||
| 1044 | .ike_version = IKEv2, | |||
| 1045 | .ike_spis = &ike->sa.st_ike_spis, | |||
| 1046 | }; | |||
| 1047 | st = NULL((void*)0); | |||
| 1048 | while (old2new_state(&stq)) { | |||
| 1049 | if (stq.st->st_v2_msgid_wip.responder == msgid) { | |||
| 1050 | st = stq.st; | |||
| 1051 | break; | |||
| 1052 | } | |||
| 1053 | } | |||
| 1054 | } | |||
| 1055 | pexpect(st == NULL ||({ _Bool assertion__ = st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno; if ( !assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1057, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno" ); } assertion__; }) | |||
| 1056 | st->st_clonedfrom == SOS_NOBODY ||({ _Bool assertion__ = st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno; if ( !assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1057, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno" ); } assertion__; }) | |||
| 1057 | st->st_clonedfrom == ike->sa.st_serialno)({ _Bool assertion__ = st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno; if ( !assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1057, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "st == ((void*)0) || st->st_clonedfrom == 0 || st->st_clonedfrom == ike->sa.st_serialno" ); } assertion__; }); | |||
| 1058 | return st; | |||
| 1059 | } | |||
| 1060 | ||||
| 1061 | /* | |||
| 1062 | * Is this a duplicate message? | |||
| 1063 | * | |||
| 1064 | * XXX: | |||
| 1065 | * | |||
| 1066 | * record'n'send bypassing the send queue can result in pluto having | |||
| 1067 | * more outstanding messages then the negotiated window size. | |||
| 1068 | * | |||
| 1069 | * This and the find_v2_sa_by_*_wip() have some overlap. For | |||
| 1070 | * instance, little point in searching for a state when the IKE SA's | |||
| 1071 | * window shows the Message ID is too old (only record'n'send breakage | |||
| 1072 | * means it might still have a message, argh!). | |||
| 1073 | */ | |||
| 1074 | ||||
| 1075 | /* | |||
| 1076 | * A duplicate request could be: | |||
| 1077 | * | |||
| 1078 | * - the request still being processed (for instance waiting on | |||
| 1079 | * crypto), which can be tossed | |||
| 1080 | * | |||
| 1081 | * - the request last processed, which should trigger a retransmit of | |||
| 1082 | * the response | |||
| 1083 | * | |||
| 1084 | * - an older request which can be tossed | |||
| 1085 | * | |||
| 1086 | * But if it is a fragment, much of this is skipped. | |||
| 1087 | */ | |||
| 1088 | static bool_Bool is_duplicate_request(struct ike_sa *ike, | |||
| 1089 | struct msg_digest *md) | |||
| 1090 | { | |||
| 1091 | passert(v2_msg_role(md) == MESSAGE_REQUEST)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_REQUEST; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1091, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "v2_msg_role(md) == MESSAGE_REQUEST" ); } (void) 1; }); | |||
| 1092 | intmax_t msgid = md->hdr.isa_msgid; | |||
| 1093 | ||||
| 1094 | /* lie to keep test results happy */ | |||
| 1095 | dbg("#%lu st.st_msgid_lastrecv %jd md.hdr.isa_msgid %08jx",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu st.st_msgid_lastrecv %jd md.hdr.isa_msgid %08jx" , ike->sa.st_serialno, ike->sa.st_v2_msgid_windows.responder .recv, msgid); } } | |||
| 1096 | ike->sa.st_serialno, ike->sa.st_v2_msgid_windows.responder.recv, msgid){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu st.st_msgid_lastrecv %jd md.hdr.isa_msgid %08jx" , ike->sa.st_serialno, ike->sa.st_v2_msgid_windows.responder .recv, msgid); } }; | |||
| 1097 | ||||
| 1098 | /* the sliding window is really small?!? */ | |||
| 1099 | pexpect(ike->sa.st_v2_msgid_windows.responder.recv ==({ _Bool assertion__ = ike->sa.st_v2_msgid_windows.responder .recv == ike->sa.st_v2_msgid_windows.responder.sent; if (! assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1100, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.st_v2_msgid_windows.responder.recv == ike->sa.st_v2_msgid_windows.responder.sent" ); } assertion__; }) | |||
| 1100 | ike->sa.st_v2_msgid_windows.responder.sent)({ _Bool assertion__ = ike->sa.st_v2_msgid_windows.responder .recv == ike->sa.st_v2_msgid_windows.responder.sent; if (! assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1100, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.st_v2_msgid_windows.responder.recv == ike->sa.st_v2_msgid_windows.responder.sent" ); } assertion__; }); | |||
| 1101 | ||||
| 1102 | if (msgid < ike->sa.st_v2_msgid_windows.responder.sent) { | |||
| 1103 | /* | |||
| 1104 | * this is an OLD retransmit and out sliding window | |||
| 1105 | * holds only the most recent response. we can't do | |||
| 1106 | * anything | |||
| 1107 | */ | |||
| 1108 | log_state(RC_LOG, &ike->sa, | |||
| 1109 | "received too old retransmit: %jd < %jd", | |||
| 1110 | msgid, ike->sa.st_v2_msgid_windows.responder.sent); | |||
| 1111 | return true1; | |||
| 1112 | } else if (msgid == ike->sa.st_v2_msgid_windows.responder.sent) { | |||
| 1113 | /* | |||
| 1114 | * This was the last request processed and, | |||
| 1115 | * presumably, a response was sent. Retransmit the | |||
| 1116 | * saved response (the response was saved right?). | |||
| 1117 | */ | |||
| 1118 | if (ike->sa.st_v2_outgoing[MESSAGE_RESPONSE] == NULL((void*)0)) { | |||
| 1119 | FAIL_V2_MSGID(ike, &ike->sa,fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1122, }; &here ; }), ike, &ike->sa, "retransmission for message %jd exchange %s failed responder.sent %jd - there is no stored message or fragments to retransmit" , msgid, enum_name(&ikev2_exchange_names, md->hdr.isa_xchg ), ike->sa.st_v2_msgid_windows.responder.sent) | |||
| 1120 | "retransmission for message %jd exchange %s failed responder.sent %jd - there is no stored message or fragments to retransmit",fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1122, }; &here ; }), ike, &ike->sa, "retransmission for message %jd exchange %s failed responder.sent %jd - there is no stored message or fragments to retransmit" , msgid, enum_name(&ikev2_exchange_names, md->hdr.isa_xchg ), ike->sa.st_v2_msgid_windows.responder.sent) | |||
| 1121 | msgid, enum_name(&ikev2_exchange_names, md->hdr.isa_xchg),fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1122, }; &here ; }), ike, &ike->sa, "retransmission for message %jd exchange %s failed responder.sent %jd - there is no stored message or fragments to retransmit" , msgid, enum_name(&ikev2_exchange_names, md->hdr.isa_xchg ), ike->sa.st_v2_msgid_windows.responder.sent) | |||
| 1122 | ike->sa.st_v2_msgid_windows.responder.sent)fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1122, }; &here ; }), ike, &ike->sa, "retransmission for message %jd exchange %s failed responder.sent %jd - there is no stored message or fragments to retransmit" , msgid, enum_name(&ikev2_exchange_names, md->hdr.isa_xchg ), ike->sa.st_v2_msgid_windows.responder.sent); | |||
| 1123 | return true1; | |||
| 1124 | } | |||
| 1125 | /* | |||
| 1126 | * If things are fragmented, only respond to the first | |||
| 1127 | * fragment. | |||
| 1128 | */ | |||
| 1129 | unsigned fragment = 0; | |||
| 1130 | if (md->hdr.isa_np == ISAKMP_NEXT_v2SKF) { | |||
| 1131 | struct ikev2_skf skf; | |||
| 1132 | pb_stream in_pbs = md->message_pbs; /* copy */ | |||
| 1133 | pb_stream ignored; | |||
| 1134 | diag_t d = pbs_in_struct(&in_pbs, &ikev2_skf_desc, | |||
| 1135 | &skf, sizeof(skf), &ignored); | |||
| 1136 | if (d != NULL((void*)0)) { | |||
| 1137 | llog_diag(RC_LOG, ike->sa.st_logger, &d, "%s", ""); | |||
| 1138 | return true1; | |||
| 1139 | } | |||
| 1140 | fragment = skf.isaskf_number; | |||
| 1141 | } | |||
| 1142 | if (fragment == 0) { | |||
| 1143 | log_state(RC_LOG, &ike->sa, | |||
| 1144 | "received duplicate %s message request (Message ID %jd); retransmitting response", | |||
| 1145 | enum_name_short(&ikev2_exchange_names, md->hdr.isa_xchg), | |||
| 1146 | msgid); | |||
| 1147 | send_recorded_v2_message(ike, "ikev2-responder-retransmit", | |||
| 1148 | MESSAGE_RESPONSE); | |||
| 1149 | } else if (fragment == 1) { | |||
| 1150 | log_state(RC_LOG, &ike->sa, | |||
| 1151 | "received duplicate %s message request (Message ID %jd, fragment %u); retransmitting response", | |||
| 1152 | enum_name_short(&ikev2_exchange_names, md->hdr.isa_xchg), | |||
| 1153 | msgid, fragment); | |||
| 1154 | send_recorded_v2_message(ike, "ikev2-responder-retransmt (fragment 1)", | |||
| 1155 | MESSAGE_RESPONSE); | |||
| 1156 | } else { | |||
| 1157 | dbg_v2_msgid(ike, &ike->sa, | |||
| 1158 | "received duplicate %s message request (Message ID %jd, fragment %u); discarded as not fragment 1", | |||
| 1159 | enum_name_short(&ikev2_exchange_names, md->hdr.isa_xchg), | |||
| 1160 | msgid, fragment); | |||
| 1161 | } | |||
| 1162 | return true1; | |||
| 1163 | } else { | |||
| 1164 | /* all that is left */ | |||
| 1165 | pexpect(msgid > ike->sa.st_v2_msgid_windows.responder.sent)({ _Bool assertion__ = msgid > ike->sa.st_v2_msgid_windows .responder.sent; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 1165, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "msgid > ike->sa.st_v2_msgid_windows.responder.sent" ); } assertion__; }); | |||
| 1166 | } | |||
| 1167 | ||||
| 1168 | /* | |||
| 1169 | * Is something already processing this request? | |||
| 1170 | * | |||
| 1171 | * Processing only starts for real once a responder has | |||
| 1172 | * accumulated all fragments and obtained KEYMAT. | |||
| 1173 | */ | |||
| 1174 | { | |||
| 1175 | struct state *responder = find_v2_sa_by_responder_wip(ike, md->hdr.isa_msgid); | |||
| 1176 | /* only a true responder */ | |||
| 1177 | pexpect(responder == NULL ||({ _Bool assertion__ = responder == ((void*)0) || responder-> st_v2_msgid_wip.responder == msgid; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1178, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "responder == ((void*)0) || responder->st_v2_msgid_wip.responder == msgid" ); } assertion__; }) | |||
| 1178 | responder->st_v2_msgid_wip.responder == msgid)({ _Bool assertion__ = responder == ((void*)0) || responder-> st_v2_msgid_wip.responder == msgid; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1178, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "responder == ((void*)0) || responder->st_v2_msgid_wip.responder == msgid" ); } assertion__; }); | |||
| 1179 | if (responder != NULL((void*)0)) { | |||
| 1180 | /* this generates the log message */ | |||
| 1181 | pexpect(verbose_state_busy(responder))({ _Bool assertion__ = verbose_state_busy(responder); if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1181, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "verbose_state_busy(responder)" ); } assertion__; }); | |||
| 1182 | return true1; | |||
| 1183 | } | |||
| 1184 | } | |||
| 1185 | ||||
| 1186 | /* | |||
| 1187 | * The IKE SA responder, having accumulated all the fragments | |||
| 1188 | * for the IKE_AUTH request, is computing the SKEYSEED. When | |||
| 1189 | * SKEYSEED finishes .st_v2_rfrags is wiped and the Message | |||
| 1190 | * IDs updated to flag that the message as work-in-progress | |||
| 1191 | * (so above check will have succeeded). | |||
| 1192 | */ | |||
| 1193 | if (state_is_busy(&ike->sa)) { | |||
| 1194 | /* | |||
| 1195 | * To keep tests happy, try to output text matching | |||
| 1196 | * verbose_state_busy(); but with some extra detail. | |||
| 1197 | */ | |||
| 1198 | #if 0 | |||
| 1199 | /* | |||
| 1200 | * XXX: hang onto this code for now - it shows how to | |||
| 1201 | * lightly unpack fragments. Will be useful when | |||
| 1202 | * fragmentation code is moved out of the state lookup | |||
| 1203 | * code. | |||
| 1204 | */ | |||
| 1205 | unsigned fragment = 0; | |||
| 1206 | if (md->hdr.isa_np == ISAKMP_NEXT_v2SKF) { | |||
| 1207 | struct ikev2_skf skf; | |||
| 1208 | pb_stream in_pbs = md->message_pbs; /* copy */ | |||
| 1209 | pb_stream ignored; | |||
| 1210 | diag_t d = pbs_in_struct(&skf, &ikev2_skf_desc, &in_pbs, &ignored); | |||
| 1211 | if (d != NULL((void*)0)) { | |||
| 1212 | llog_diag(RC_LOG, st->st_logger, &d, "%s", ""); | |||
| 1213 | return true1; | |||
| 1214 | } | |||
| 1215 | fragment = skf.isaskf_number; | |||
| 1216 | } | |||
| 1217 | if (fragment == 0) { | |||
| 1218 | log_state(RC_LOG, &ike->sa, | |||
| 1219 | "discarding packet received during asynchronous work (DNS or crypto) in %s", | |||
| 1220 | ike->sa.st_state->name); | |||
| 1221 | } else if (fragment == 1) { | |||
| 1222 | log_state(RC_LOG, &ike->sa, | |||
| 1223 | "discarding fragments received during asynchronous work (DNS or crypto) in %s", | |||
| 1224 | ike->sa.st_state->name); | |||
| 1225 | } else { | |||
| 1226 | dbg_v2_msgid(ike, &ike->sa, | |||
| 1227 | "discarding fragment %u received during asynchronous work (DNS or crypto) in %s", | |||
| 1228 | fragment, ike->sa.st_state->name); | |||
| 1229 | } | |||
| 1230 | #else | |||
| 1231 | log_state(RC_LOG, &ike->sa, | |||
| 1232 | "discarding packet received during asynchronous work (DNS or crypto) in %s", | |||
| 1233 | ike->sa.st_state->name); | |||
| 1234 | #endif | |||
| 1235 | return true1; | |||
| 1236 | } | |||
| 1237 | ||||
| 1238 | struct v2_incoming_fragments *frags = ike->sa.st_v2_incoming[MESSAGE_REQUEST]; | |||
| 1239 | if (frags != NULL((void*)0)) { | |||
| 1240 | pexpect(frags->count < frags->total)({ _Bool assertion__ = frags->count < frags->total; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1240, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "frags->count < frags->total" ); } assertion__; }); | |||
| 1241 | dbg_v2_msgid(ike, &ike->sa, | |||
| 1242 | "not a duplicate - responder is accumulating fragments for message request %jd", | |||
| 1243 | msgid); | |||
| 1244 | } else { | |||
| 1245 | dbg_v2_msgid(ike, &ike->sa, | |||
| 1246 | "not a duplicate - message request %jd is new", | |||
| 1247 | msgid); | |||
| 1248 | } | |||
| 1249 | ||||
| 1250 | return false0; | |||
| 1251 | } | |||
| 1252 | ||||
| 1253 | /* | |||
| 1254 | * A duplicate response could be: | |||
| 1255 | * | |||
| 1256 | * - for an old request where there's no longer an initiator waiting, | |||
| 1257 | * and can be dropped | |||
| 1258 | * | |||
| 1259 | * - the initiator is busy, presumably because this response is a | |||
| 1260 | * duplicate and the initiator is waiting on crypto to complete so | |||
| 1261 | * it can decrypt the response | |||
| 1262 | */ | |||
| 1263 | static bool_Bool is_duplicate_response(struct ike_sa *ike, | |||
| 1264 | struct state *initiator, | |||
| 1265 | struct msg_digest *md) | |||
| 1266 | { | |||
| 1267 | passert(v2_msg_role(md) == MESSAGE_RESPONSE)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_RESPONSE; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1267, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "v2_msg_role(md) == MESSAGE_RESPONSE" ); } (void) 1; }); | |||
| 1268 | intmax_t msgid = md->hdr.isa_msgid; | |||
| 1269 | ||||
| 1270 | /* only a true initiator */ | |||
| 1271 | pexpect(initiator == NULL ||({ _Bool assertion__ = initiator == ((void*)0) || initiator-> st_v2_msgid_wip.initiator == msgid; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1272, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "initiator == ((void*)0) || initiator->st_v2_msgid_wip.initiator == msgid" ); } assertion__; }) | |||
| 1272 | initiator->st_v2_msgid_wip.initiator == msgid)({ _Bool assertion__ = initiator == ((void*)0) || initiator-> st_v2_msgid_wip.initiator == msgid; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1272, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "initiator == ((void*)0) || initiator->st_v2_msgid_wip.initiator == msgid" ); } assertion__; }); | |||
| 1273 | ||||
| 1274 | /* the sliding window is really small?!? */ | |||
| 1275 | pexpect(ike->sa.st_v2_msgid_windows.responder.recv ==({ _Bool assertion__ = ike->sa.st_v2_msgid_windows.responder .recv == ike->sa.st_v2_msgid_windows.responder.sent; if (! assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1276, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.st_v2_msgid_windows.responder.recv == ike->sa.st_v2_msgid_windows.responder.sent" ); } assertion__; }) | |||
| 1276 | ike->sa.st_v2_msgid_windows.responder.sent)({ _Bool assertion__ = ike->sa.st_v2_msgid_windows.responder .recv == ike->sa.st_v2_msgid_windows.responder.sent; if (! assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1276, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.st_v2_msgid_windows.responder.recv == ike->sa.st_v2_msgid_windows.responder.sent" ); } assertion__; }); | |||
| 1277 | ||||
| 1278 | if (msgid <= ike->sa.st_v2_msgid_windows.initiator.recv) { | |||
| 1279 | /* | |||
| 1280 | * Processing of the response was completed so drop as | |||
| 1281 | * too old. | |||
| 1282 | * | |||
| 1283 | * XXX: Should be rate_log() but that shows up in the | |||
| 1284 | * whack output. While "correct" it messes with test | |||
| 1285 | * output. The old log line didn't show up because | |||
| 1286 | * current-state wasn't set. | |||
| 1287 | * | |||
| 1288 | * Here's roughly why INITIATOR can be non-NULL: | |||
| 1289 | * | |||
| 1290 | * - west.#8 needs a rekey, so west.#11 is created and | |||
| 1291 | * it sends a CREATE_CHILD_SA with Message ID 3. | |||
| 1292 | * | |||
| 1293 | * - west.#8 gives up on the re-key so it forces a | |||
| 1294 | * delete request (aka record'n'send), sending a | |||
| 1295 | * second message with ID 4 | |||
| 1296 | * | |||
| 1297 | * West has two outstanding messages yet its window | |||
| 1298 | * size of 1! | |||
| 1299 | * | |||
| 1300 | * - east receives the rekey with ID 3, creates | |||
| 1301 | * east.#11 and and sends it off for further | |||
| 1302 | * processing | |||
| 1303 | * | |||
| 1304 | * - east receives the delete with ID 4, forces a | |||
| 1305 | * message ID update and sends an ID 4 response | |||
| 1306 | * confirming the delete | |||
| 1307 | * | |||
| 1308 | * - east.#11 finishes its crypto so east sends back | |||
| 1309 | * its response with Message ID 3 for a re-keyed SA it | |||
| 1310 | * just deleted?!?! | |||
| 1311 | * | |||
| 1312 | * East has responded with two out-of-order messages | |||
| 1313 | * (if the window size was 2 this would be ok but it | |||
| 1314 | * isn't). | |||
| 1315 | * | |||
| 1316 | * - west receives the ID 4 response, tries to delete | |||
| 1317 | * the IKE SA but can't because west.#11 is lurking; | |||
| 1318 | * but regardless the ID window is forced 2->4 | |||
| 1319 | * | |||
| 1320 | * - west receives the ID 3 response, which is clearly | |||
| 1321 | * to-old so doesn't expect there to be a matching | |||
| 1322 | * initiator, arrg | |||
| 1323 | */ | |||
| 1324 | if (initiator != NULL((void*)0)) { | |||
| 1325 | dbg_v2_msgid(ike, initiator, "XXX: expecting initiator==NULL - suspect record'n'send with an out-of-order wrong packet response; discarding packet"); | |||
| 1326 | } else { | |||
| 1327 | dbg_v2_msgid(ike, initiator, "already processed response %jd (%s); discarding packet", | |||
| 1328 | msgid, enum_name_short(&ikev2_exchange_names, md->hdr.isa_xchg)); | |||
| 1329 | } | |||
| 1330 | return true1; | |||
| 1331 | } | |||
| 1332 | ||||
| 1333 | if (initiator == NULL((void*)0)) { | |||
| 1334 | /* | |||
| 1335 | * While there's an IKE SA matching the IKE SPIs, | |||
| 1336 | * there's no corresponding initiator for the message. | |||
| 1337 | * | |||
| 1338 | * XXX: rate_log() sends to whack which, while making | |||
| 1339 | * sense, but churns the test output. | |||
| 1340 | */ | |||
| 1341 | log_state(RC_LOG, &ike->sa, | |||
| 1342 | "%s message response with Message ID %jd has no matching SA", | |||
| 1343 | enum_name(&ikev2_exchange_names, md->hdr.isa_xchg), msgid); | |||
| 1344 | return true1; | |||
| 1345 | } | |||
| 1346 | ||||
| 1347 | /* | |||
| 1348 | * Sanity check the MSGID and initiator against the IKE SA | |||
| 1349 | * Message ID window. | |||
| 1350 | */ | |||
| 1351 | ||||
| 1352 | if (msgid > ike->sa.st_v2_msgid_windows.initiator.sent) { | |||
| 1353 | /* | |||
| 1354 | * There was an initiator waiting for a message that, | |||
| 1355 | * according to the IKE SA, has yet to be sent?!? | |||
| 1356 | */ | |||
| 1357 | FAIL_V2_MSGID(ike, initiator,fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1359, }; &here ; }), ike, initiator, "dropping response with Message ID %jd which is from the future - last request sent was %jd" , msgid, ike->sa.st_v2_msgid_windows.initiator.sent) | |||
| 1358 | "dropping response with Message ID %jd which is from the future - last request sent was %jd",fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1359, }; &here ; }), ike, initiator, "dropping response with Message ID %jd which is from the future - last request sent was %jd" , msgid, ike->sa.st_v2_msgid_windows.initiator.sent) | |||
| 1359 | msgid, ike->sa.st_v2_msgid_windows.initiator.sent)fail_v2_msgid(({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1359, }; &here ; }), ike, initiator, "dropping response with Message ID %jd which is from the future - last request sent was %jd" , msgid, ike->sa.st_v2_msgid_windows.initiator.sent); | |||
| 1360 | return true1; | |||
| 1361 | } | |||
| 1362 | ||||
| 1363 | /* | |||
| 1364 | * If the state is busy, presumably doing something like | |||
| 1365 | * crypto, skip further processing. | |||
| 1366 | * | |||
| 1367 | * For fragments, things only go busy once all fragments have | |||
| 1368 | * been received (and re-transmitted fragments are ignored). | |||
| 1369 | * If this changes then a lot more than this code will need to | |||
| 1370 | * be moved. | |||
| 1371 | * | |||
| 1372 | * XXX: Is there a better way to handle this? | |||
| 1373 | */ | |||
| 1374 | if (verbose_state_busy(initiator)) { | |||
| 1375 | return true1; | |||
| 1376 | } | |||
| 1377 | ||||
| 1378 | return false0; | |||
| 1379 | } | |||
| 1380 | ||||
| 1381 | /* | |||
| 1382 | * process an input packet, possibly generating a reply. | |||
| 1383 | * | |||
| 1384 | * If all goes well, this routine eventually calls a state-specific | |||
| 1385 | * transition function. | |||
| 1386 | * | |||
| 1387 | * This routine will not release_any_md(mdp). It is expected that its | |||
| 1388 | * caller will do this. In fact, it will zap *mdp to NULL if it thinks | |||
| 1389 | * **mdp should not be freed. So the caller should be prepared for | |||
| 1390 | * *mdp being set to NULL. | |||
| 1391 | * | |||
| 1392 | * Start by looking for (or creating) the IKE SA responsible for the | |||
| 1393 | * IKE SPIs group ..... | |||
| 1394 | */ | |||
| 1395 | ||||
| 1396 | static void ike_process_packet(struct msg_digest *mdp, struct ike_sa *ike); | |||
| 1397 | ||||
| 1398 | void ikev2_process_packet(struct msg_digest *md) | |||
| 1399 | { | |||
| 1400 | /* Look for an state that matches the various things we know: | |||
| 1401 | * | |||
| 1402 | * 1) exchange type received? | |||
| 1403 | * 2) is it initiator or not? | |||
| 1404 | */ | |||
| 1405 | const enum isakmp_xchg_type ix = md->hdr.isa_xchg; | |||
| 1406 | ||||
| 1407 | /* | |||
| 1408 | * If the IKE SA initiator sent the message then this end is | |||
| 1409 | * looking for the IKE SA responder (and vice versa). | |||
| 1410 | */ | |||
| 1411 | enum sa_role expected_local_ike_role = (md->hdr.isa_flags & ISAKMP_FLAGS_v2_IKE_I(1<<ISAKMP_FLAGS_v2_IKE_I_IX)) ? SA_RESPONDER : SA_INITIATOR; | |||
| 1412 | ||||
| 1413 | /* | |||
| 1414 | * Dump what the message says, once a state has been found | |||
| 1415 | * this can be checked against what is. | |||
| 1416 | */ | |||
| 1417 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_logger(buf , &failsafe_logger, DEBUG_STREAM), buf = ((void*)0)) { | |||
| 1418 | switch (expected_local_ike_role) { | |||
| 1419 | case SA_RESPONDER: | |||
| 1420 | jam(buf, "I am the IKE SA Original Responder"); | |||
| 1421 | break; | |||
| 1422 | case SA_INITIATOR: | |||
| 1423 | jam(buf, "I am the IKE SA Original Initiator"); | |||
| 1424 | break; | |||
| 1425 | default: | |||
| 1426 | bad_case(expected_local_ike_role)libreswan_bad_case("expected_local_ike_role", (expected_local_ike_role ), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1426, }; &here; })); | |||
| 1427 | } | |||
| 1428 | jam(buf, " receiving an IKEv2 "); | |||
| 1429 | jam_enum_short(buf, &ikev2_exchange_names, ix); | |||
| 1430 | switch (v2_msg_role(md)) { | |||
| 1431 | case MESSAGE_RESPONSE: | |||
| 1432 | jam(buf, " response "); | |||
| 1433 | break; | |||
| 1434 | case MESSAGE_REQUEST: | |||
| 1435 | jam(buf, " request "); | |||
| 1436 | break; | |||
| 1437 | default: | |||
| 1438 | bad_case(v2_msg_role(md))libreswan_bad_case("v2_msg_role(md)", (v2_msg_role(md)), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 1438, }; &here; })); | |||
| 1439 | } | |||
| 1440 | } | |||
| 1441 | ||||
| 1442 | /* | |||
| 1443 | * If the message is a new IKE_SA_INIT request (or previously | |||
| 1444 | * discarded request due to cookies) then there is no IKE SA, | |||
| 1445 | * and no point trying to use the state machinery. | |||
| 1446 | * | |||
| 1447 | * If the message is an IKE_SA_INIT response, then there might | |||
| 1448 | * be an IKE SA; but the number of checks required means that | |||
| 1449 | * it is also a good idea to just avoid the state machinery. | |||
| 1450 | */ | |||
| 1451 | ||||
| 1452 | if (ix == ISAKMP_v2_IKE_SA_INIT) { | |||
| 1453 | process_v2_IKE_SA_INIT(md); | |||
| 1454 | return; | |||
| 1455 | } | |||
| 1456 | ||||
| 1457 | passert(v2_msg_role(md) == MESSAGE_REQUEST ||({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_REQUEST || v2_msg_role (md) == MESSAGE_RESPONSE; if (!assertion__) { where_t here = ( { static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1458, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert( logger_, here, "%s", "v2_msg_role(md) == MESSAGE_REQUEST || v2_msg_role(md) == MESSAGE_RESPONSE" ); } (void) 1; }) | |||
| 1458 | v2_msg_role(md) == MESSAGE_RESPONSE)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_REQUEST || v2_msg_role (md) == MESSAGE_RESPONSE; if (!assertion__) { where_t here = ( { static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1458, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert( logger_, here, "%s", "v2_msg_role(md) == MESSAGE_REQUEST || v2_msg_role(md) == MESSAGE_RESPONSE" ); } (void) 1; }); | |||
| 1459 | ||||
| 1460 | /* | |||
| 1461 | * Find the IKE SA with matching SPIs. | |||
| 1462 | * | |||
| 1463 | * The IKE SA's Message IDs can then be used to determine if | |||
| 1464 | * the message fits in the message window (new request, | |||
| 1465 | * expected response, or old message). | |||
| 1466 | */ | |||
| 1467 | struct ike_sa *ike = find_v2_ike_sa(&md->hdr.isa_ike_spis, | |||
| 1468 | expected_local_ike_role); | |||
| 1469 | if (ike == NULL((void*)0)) { | |||
| 1470 | esb_buf ixb; | |||
| 1471 | rate_log(md, "%s message %s has no corresponding IKE SA", | |||
| 1472 | enum_show_short(&ikev2_exchange_names, ix, &ixb), | |||
| 1473 | v2_msg_role(md) == MESSAGE_REQUEST ? "request" : "response"); | |||
| 1474 | return; | |||
| 1475 | } | |||
| 1476 | ||||
| 1477 | /* | |||
| 1478 | * There's at least an IKE SA, and possibly ST willing to | |||
| 1479 | * process the message. | |||
| 1480 | */ | |||
| 1481 | passert(ike != NULL)({ _Bool assertion__ = ike != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1481, }; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "ike != ((void*)0)"); } ( void) 1; }); | |||
| 1482 | ||||
| 1483 | /* | |||
| 1484 | * Re-check ST's IKE SA's role against the I(Initiator) flag | |||
| 1485 | * in the headers. Since above searches will only find an IKE | |||
| 1486 | * SA when the IKE SA's role is correct, this should always | |||
| 1487 | * work. | |||
| 1488 | */ | |||
| 1489 | if (!pexpect(ike->sa.st_sa_role == expected_local_ike_role)({ _Bool assertion__ = ike->sa.st_sa_role == expected_local_ike_role ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1489, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.st_sa_role == expected_local_ike_role" ); } assertion__; })) { | |||
| 1490 | return; | |||
| 1491 | } | |||
| 1492 | ||||
| 1493 | /* | |||
| 1494 | * Since there's an IKE SA start billing and logging against | |||
| 1495 | * it. | |||
| 1496 | */ | |||
| 1497 | statetime_t start = statetime_backdate(&ike->sa, &md->md_inception); | |||
| 1498 | ike_process_packet(md, ike); | |||
| 1499 | statetime_stop(&start, "%s()", __func__); | |||
| 1500 | } | |||
| 1501 | ||||
| 1502 | /* | |||
| 1503 | * The IKE SA for the message has been found (or created). Continue | |||
| 1504 | * verification, and identify the state (ST) that the message should | |||
| 1505 | * be sent to. | |||
| 1506 | */ | |||
| 1507 | ||||
| 1508 | static void ike_process_packet(struct msg_digest *md, struct ike_sa *ike) | |||
| 1509 | { | |||
| 1510 | /* | |||
| 1511 | * Deal with duplicate messages and busy states. | |||
| 1512 | */ | |||
| 1513 | struct state *st; | |||
| 1514 | switch (v2_msg_role(md)) { | |||
| 1515 | case MESSAGE_REQUEST: | |||
| 1516 | /* | |||
| 1517 | * The IKE SA always processes requests. | |||
| 1518 | * | |||
| 1519 | * XXX: except further down where the code creates a | |||
| 1520 | * new state when CREATE_CHILD_SA and switches to | |||
| 1521 | * that. | |||
| 1522 | * | |||
| 1523 | * The other quirk is with fragments; but the only | |||
| 1524 | * case that matters it when the IKE SA accumulating | |||
| 1525 | * them. | |||
| 1526 | */ | |||
| 1527 | if (md->fake_clone) { | |||
| 1528 | log_state(RC_LOG, &ike->sa, "IMPAIR: processing a fake (cloned) message"); | |||
| 1529 | } | |||
| 1530 | /* | |||
| 1531 | * Is this duplicate? | |||
| 1532 | * | |||
| 1533 | * If MD is a fragment then it isn't considered a | |||
| 1534 | * duplicate. | |||
| 1535 | */ | |||
| 1536 | if (is_duplicate_request(ike, md)) { | |||
| 1537 | return; | |||
| 1538 | } | |||
| 1539 | st = &ike->sa; | |||
| 1540 | break; | |||
| 1541 | case MESSAGE_RESPONSE: | |||
| 1542 | /* | |||
| 1543 | * This is the response to an earlier request; use the | |||
| 1544 | * IKE SA to find the state that initiated the | |||
| 1545 | * exchange (sent that request). | |||
| 1546 | * | |||
| 1547 | * If the response is a fragment then ST will be | |||
| 1548 | * non-NULL; is_duplicate_state() gets to figure out | |||
| 1549 | * if the fragments are complete or need to wait | |||
| 1550 | * longer. | |||
| 1551 | */ | |||
| 1552 | st = find_v2_sa_by_initiator_wip(ike, md->hdr.isa_msgid); | |||
| 1553 | if (md->fake_clone) { | |||
| 1554 | log_state(RC_LOG, &ike->sa, "IMPAIR: processing a fake (cloned) message"); | |||
| 1555 | } | |||
| 1556 | if (is_duplicate_response(ike, st, md)) { | |||
| 1557 | return; | |||
| 1558 | } | |||
| 1559 | pexpect(st != NULL)({ _Bool assertion__ = st != ((void*)0); if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1559, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect (logger_, here_, "%s", "st != ((void*)0)"); } assertion__; }); | |||
| 1560 | break; | |||
| 1561 | default: | |||
| 1562 | bad_case(v2_msg_role(md))libreswan_bad_case("v2_msg_role(md)", (v2_msg_role(md)), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 1562, }; &here; })); | |||
| 1563 | } | |||
| 1564 | ||||
| 1565 | /* | |||
| 1566 | * Now that the state that is to process the message has been | |||
| 1567 | * selected, switch logging to it. | |||
| 1568 | * | |||
| 1569 | * XXX: why the need to constantly pick a single winner and | |||
| 1570 | * switch to it? Because tests expect messages to be logged | |||
| 1571 | * against a specific state. It would be better of that code | |||
| 1572 | * specified that state as a parameter. | |||
| 1573 | */ | |||
| 1574 | passert(st != NULL)({ _Bool assertion__ = st != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1574, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_passert (logger_, here, "%s", "st != ((void*)0)"); } (void) 1; }); | |||
| 1575 | /* XXX: debug-logging this is redundant */ | |||
| 1576 | ||||
| 1577 | /* | |||
| 1578 | * Have a state an and IKE SA, time to decode the payloads. | |||
| 1579 | */ | |||
| 1580 | dbg("unpacking clear payload"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unpacking clear payload"); } }; | |||
| 1581 | passert(!md->message_payloads.parsed)({ _Bool assertion__ = !md->message_payloads.parsed; if (! assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1581, }; &here; }); const struct logger *logger_ = & failsafe_logger; llog_passert(logger_, here, "%s", "!md->message_payloads.parsed" ); } (void) 1; }); | |||
| 1582 | pexpect(v2_msg_role(md) == MESSAGE_RESPONSE ||({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_RESPONSE || md->hdr.isa_xchg != ISAKMP_v2_IKE_SA_INIT; if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1583, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "v2_msg_role(md) == MESSAGE_RESPONSE || md->hdr.isa_xchg != ISAKMP_v2_IKE_SA_INIT" ); } assertion__; }) | |||
| 1583 | md->hdr.isa_xchg != ISAKMP_v2_IKE_SA_INIT)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_RESPONSE || md->hdr.isa_xchg != ISAKMP_v2_IKE_SA_INIT; if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1583, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "v2_msg_role(md) == MESSAGE_RESPONSE || md->hdr.isa_xchg != ISAKMP_v2_IKE_SA_INIT" ); } assertion__; }); | |||
| 1584 | md->message_payloads = | |||
| 1585 | ikev2_decode_payloads(ike->sa.st_logger, md, | |||
| 1586 | &md->message_pbs, | |||
| 1587 | md->hdr.isa_np); | |||
| 1588 | if (md->message_payloads.n != v2N_NOTHING_WRONG) { | |||
| 1589 | /* | |||
| 1590 | * Should only respond when the message is an | |||
| 1591 | * IKE_SA_INIT request. But that was handled above | |||
| 1592 | * when dealing with cookies so here, there's zero | |||
| 1593 | * reason to respond. | |||
| 1594 | * | |||
| 1595 | * decode calls packet code and that logs errors on | |||
| 1596 | * the spot | |||
| 1597 | */ | |||
| 1598 | /* already logged */ | |||
| 1599 | return; | |||
| 1600 | } | |||
| 1601 | ||||
| 1602 | ikev2_process_state_packet(ike, st, md); | |||
| 1603 | } | |||
| 1604 | ||||
| 1605 | /* | |||
| 1606 | * XXX: Hack to find the transition that would have been run if the | |||
| 1607 | * packet was ok, so it can be 'failed'. | |||
| 1608 | * | |||
| 1609 | * This is largely astetic. It could use the first transition but | |||
| 1610 | * often a later transition reads better. Perhaps the last transition | |||
| 1611 | * since, presumably, that is the most generic? | |||
| 1612 | */ | |||
| 1613 | ||||
| 1614 | static void hack_error_transition(struct state *st, struct msg_digest *md) | |||
| 1615 | { | |||
| 1616 | passert(md != NULL)({ _Bool assertion__ = md != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1616, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_passert (logger_, here, "%s", "md != ((void*)0)"); } (void) 1; }); | |||
| 1617 | const struct v2_state_transition *transition; | |||
| 1618 | const struct finite_state *state = st->st_state; | |||
| 1619 | switch (state->kind) { | |||
| 1620 | case STATE_V2_PARENT_R1: | |||
| 1621 | /* | |||
| 1622 | * Responding to either an IKE_INTERMEDIATE or | |||
| 1623 | * IKE_AUTH request: look for the NOSKEYSEED | |||
| 1624 | * transitions (and prefer IKE_AUTH). | |||
| 1625 | * | |||
| 1626 | * Once SKEYSEED is off-loaded and STATE_V2_PARENT_I1 has | |||
| 1627 | * only one (ok, two) transition, this is no longer a | |||
| 1628 | * hack. | |||
| 1629 | */ | |||
| 1630 | pexpect(state->nr_transitions == 4)({ _Bool assertion__ = state->nr_transitions == 4; if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1630, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "state->nr_transitions == 4" ); } assertion__; }); | |||
| 1631 | if (md->hdr.isa_xchg == ISAKMP_v2_IKE_INTERMEDIATE) { | |||
| 1632 | transition = &state->v2_transitions[2]; | |||
| 1633 | pexpect(transition->recv_type == ISAKMP_v2_IKE_INTERMEDIATE)({ _Bool assertion__ = transition->recv_type == ISAKMP_v2_IKE_INTERMEDIATE ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1633, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->recv_type == ISAKMP_v2_IKE_INTERMEDIATE" ); } assertion__; }); | |||
| 1634 | pexpect(transition->next_state == STATE_V2_PARENT_R1)({ _Bool assertion__ = transition->next_state == STATE_V2_PARENT_R1 ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1634, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->next_state == STATE_V2_PARENT_R1" ); } assertion__; }); | |||
| 1635 | } else { | |||
| 1636 | transition = &state->v2_transitions[3]; | |||
| 1637 | pexpect(transition->recv_type == ISAKMP_v2_IKE_AUTH)({ _Bool assertion__ = transition->recv_type == ISAKMP_v2_IKE_AUTH ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1637, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->recv_type == ISAKMP_v2_IKE_AUTH" ); } assertion__; }); | |||
| 1638 | pexpect(transition->next_state == STATE_V2_ESTABLISHED_IKE_SA)({ _Bool assertion__ = transition->next_state == STATE_V2_ESTABLISHED_IKE_SA ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1638, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->next_state == STATE_V2_ESTABLISHED_IKE_SA" ); } assertion__; }); | |||
| 1639 | } | |||
| 1640 | pexpect((transition->flags & SMF2_NO_SKEYSEED) == 0)({ _Bool assertion__ = (transition->flags & SMF2_NO_SKEYSEED ) == 0; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 1640, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "(transition->flags & SMF2_NO_SKEYSEED) == 0" ); } assertion__; }); | |||
| 1641 | pexpect(transition->state == STATE_V2_PARENT_R1)({ _Bool assertion__ = transition->state == STATE_V2_PARENT_R1 ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1641, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->state == STATE_V2_PARENT_R1" ); } assertion__; }); | |||
| 1642 | break; | |||
| 1643 | case STATE_V2_PARENT_I2: | |||
| 1644 | { | |||
| 1645 | /* | |||
| 1646 | * Receiving IKE_AUTH response: it is buried deep | |||
| 1647 | * down; would adding an extra transition that always | |||
| 1648 | * matches be better? | |||
| 1649 | */ | |||
| 1650 | unsigned transition_nr = 1; | |||
| 1651 | pexpect(state->nr_transitions > transition_nr)({ _Bool assertion__ = state->nr_transitions > transition_nr ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1651, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "state->nr_transitions > transition_nr" ); } assertion__; }); | |||
| 1652 | transition = &state->v2_transitions[transition_nr]; | |||
| 1653 | pexpect(transition->state == STATE_V2_PARENT_I2)({ _Bool assertion__ = transition->state == STATE_V2_PARENT_I2 ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1653, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->state == STATE_V2_PARENT_I2" ); } assertion__; }); | |||
| 1654 | pexpect(transition->next_state == STATE_V2_ESTABLISHED_IKE_SA)({ _Bool assertion__ = transition->next_state == STATE_V2_ESTABLISHED_IKE_SA ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1654, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->next_state == STATE_V2_ESTABLISHED_IKE_SA" ); } assertion__; }); | |||
| 1655 | break; | |||
| 1656 | } | |||
| 1657 | default: | |||
| 1658 | if (/*pexpect*/(state->nr_transitions > 0)) { | |||
| 1659 | transition = &state->v2_transitions[state->nr_transitions - 1]; | |||
| 1660 | } else { | |||
| 1661 | static const struct v2_state_transition undefined_transition = { | |||
| 1662 | .story = "suspect message", | |||
| 1663 | .state = STATE_UNDEFINED, | |||
| 1664 | .next_state = STATE_UNDEFINED, | |||
| 1665 | }; | |||
| 1666 | transition = &undefined_transition; | |||
| 1667 | } | |||
| 1668 | break; | |||
| 1669 | } | |||
| 1670 | /*pexpect(st->st_v2_transition == NULL);*/ | |||
| 1671 | st->st_v2_transition = transition; | |||
| 1672 | } | |||
| 1673 | ||||
| 1674 | /* | |||
| 1675 | * The SA the message is intended for has also been identified. | |||
| 1676 | * Continue ... | |||
| 1677 | * | |||
| 1678 | * XXX: Well except for a CREATE_CHILD_SA request where, after further | |||
| 1679 | * processing the SA may get created. Should this message instead be | |||
| 1680 | * sent to the IKE SA, which can then create a WIP child? | |||
| 1681 | */ | |||
| 1682 | ||||
| 1683 | void ikev2_process_state_packet(struct ike_sa *ike, struct state *st, | |||
| 1684 | struct msg_digest *md) | |||
| 1685 | { | |||
| 1686 | passert(ike != NULL)({ _Bool assertion__ = ike != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1686, }; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "ike != ((void*)0)"); } ( void) 1; }); | |||
| 1687 | passert(st != NULL)({ _Bool assertion__ = st != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 1687, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_passert (logger_, here, "%s", "st != ((void*)0)"); } (void) 1; }); | |||
| 1688 | ||||
| 1689 | /* | |||
| 1690 | * There is no "struct state" object if-and-only-if we're | |||
| 1691 | * responding to a shiny new SA_INIT message. The start-state | |||
| 1692 | * transition will (probably) create the object. | |||
| 1693 | * | |||
| 1694 | * But what about when pluto, as the initial responder, is | |||
| 1695 | * fending of an attack attack by sending back and requiring | |||
| 1696 | * cookies - won't the cookie need a "struct state"? | |||
| 1697 | * According to the RFC: no. Instead a small table of | |||
| 1698 | * constants can be used to generate cookies on the fly. | |||
| 1699 | */ | |||
| 1700 | const struct finite_state *from_state = st->st_state; | |||
| 1701 | dbg("#%lu in state %s: %s", st->st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu in state %s: %s", st->st_serialno, from_state ->short_name, from_state->story); } } | |||
| 1702 | from_state->short_name, from_state->story){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu in state %s: %s", st->st_serialno, from_state ->short_name, from_state->story); } }; | |||
| 1703 | ||||
| 1704 | struct ikev2_payload_errors message_payload_status = { .bad = false0 }; | |||
| 1705 | struct ikev2_payload_errors encrypted_payload_status = { .bad = false0 }; | |||
| 1706 | ||||
| 1707 | const enum isakmp_xchg_type ix = md->hdr.isa_xchg; | |||
| 1708 | ||||
| 1709 | /* | |||
| 1710 | * XXX: Unlike find_v2_state_transition(), the below scans | |||
| 1711 | * every single state transition and then, in the case of a | |||
| 1712 | * CREATE_CHILD_SA, ignores the "from" state. | |||
| 1713 | * | |||
| 1714 | * XXX: Unlike find_v2_state_transition(), this code detects | |||
| 1715 | * and decrypts packets and fragments in the middle of the | |||
| 1716 | * lookup. Being more aggressive with decrypting fragments | |||
| 1717 | * will likely force that logic to be moved to before this | |||
| 1718 | * lookup. | |||
| 1719 | */ | |||
| 1720 | ||||
| 1721 | const struct v2_state_transition *svm; | |||
| 1722 | for (svm = v2_state_transition_table; svm->state != STATE_IKEv2_ROOF; | |||
| 1723 | svm++) { | |||
| 1724 | ||||
| 1725 | /* | |||
| 1726 | * Does the message match the state transition? | |||
| 1727 | */ | |||
| 1728 | if (svm->recv_type != ix) { | |||
| 1729 | continue; | |||
| 1730 | } | |||
| 1731 | if (svm->recv_role != v2_msg_role(md)) { | |||
| 1732 | continue; | |||
| 1733 | } | |||
| 1734 | ||||
| 1735 | /* | |||
| 1736 | * Does the from state match the SA's current state? | |||
| 1737 | * | |||
| 1738 | * XXX: Eventually this part won't be needed as each | |||
| 1739 | * state will have its own list of transitions. See | |||
| 1740 | * find_v2_state_transition() which is currently only | |||
| 1741 | * used by IKES_SA_INIT. | |||
| 1742 | * | |||
| 1743 | * Unfortunately ... | |||
| 1744 | * | |||
| 1745 | * For CREATE_CHILD_SA, the responder ignores the | |||
| 1746 | * .from_state and instead applies some other magic | |||
| 1747 | * (the .from_state ends up being used when creating | |||
| 1748 | * the Child SA). | |||
| 1749 | */ | |||
| 1750 | if (ix == ISAKMP_v2_CREATE_CHILD_SA && | |||
| 1751 | /* matched above */ svm->recv_role == MESSAGE_REQUEST) { | |||
| 1752 | dbg("potential CREATE_CHILD_SA responder stumbling through to process_v2_child_ix()"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("potential CREATE_CHILD_SA responder stumbling through to process_v2_child_ix()" ); } }; | |||
| 1753 | } else if (svm->state != from_state->kind) { | |||
| 1754 | continue; | |||
| 1755 | } | |||
| 1756 | ||||
| 1757 | /* | |||
| 1758 | * Check the message payloads are as expected. | |||
| 1759 | */ | |||
| 1760 | pexpect(md->message_payloads.parsed)({ _Bool assertion__ = md->message_payloads.parsed; if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1760, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "md->message_payloads.parsed" ); } assertion__; }); | |||
| 1761 | struct ikev2_payload_errors message_payload_errors | |||
| 1762 | = ikev2_verify_payloads(md, &md->message_payloads, | |||
| 1763 | &svm->message_payloads); | |||
| 1764 | if (message_payload_errors.bad) { | |||
| 1765 | /* Save this failure for later logging. */ | |||
| 1766 | message_payload_status = message_payload_errors; | |||
| 1767 | continue; | |||
| 1768 | } | |||
| 1769 | ||||
| 1770 | /* | |||
| 1771 | * If there is no SK (or SKF) payload then checking is | |||
| 1772 | * complete and things have matched. | |||
| 1773 | * | |||
| 1774 | * (.seen&(P(SK)|P(SKF))!=0 is equivalent. | |||
| 1775 | */ | |||
| 1776 | if (!(svm->message_payloads.required & P(SK)((lset_t)1 << (ISAKMP_NEXT_v2SK)))) { | |||
| 1777 | break; | |||
| 1778 | } | |||
| 1779 | ||||
| 1780 | /* | |||
| 1781 | * Since the encrypted payload appears plausible, deal | |||
| 1782 | * with fragmentation. | |||
| 1783 | */ | |||
| 1784 | if (!md->encrypted_payloads.parsed) { | |||
| 1785 | /* | |||
| 1786 | * Deal with fragmentation. The function | |||
| 1787 | * returns FALSE either when there are more | |||
| 1788 | * fragments, the fragment is corrupt, the | |||
| 1789 | * fragment is a duplicate, or the fragment | |||
| 1790 | * count changed (it also drops all | |||
| 1791 | * fragments). Either way stop processing. | |||
| 1792 | * | |||
| 1793 | * Only upon _first_ arrival of the last | |||
| 1794 | * fragment, does the function return TRUE. | |||
| 1795 | * The the processing flow below can then | |||
| 1796 | * continue to the SKEYSEED check. | |||
| 1797 | * | |||
| 1798 | * However, if SKEYSEED (g^{xy}) needed to be | |||
| 1799 | * computed then this code will be re-entered | |||
| 1800 | * with all fragments present (so "the" | |||
| 1801 | * function should not be called). | |||
| 1802 | */ | |||
| 1803 | struct v2_incoming_fragments *frags = | |||
| 1804 | ike->sa.st_v2_incoming[v2_msg_role(md)]; | |||
| 1805 | bool_Bool have_all_fragments = | |||
| 1806 | (frags != NULL((void*)0) && frags->count == frags->total); | |||
| 1807 | /* | |||
| 1808 | * XXX: Because fragments are only checked | |||
| 1809 | * all-at-once after they have all arrived, a | |||
| 1810 | * single corrupt fragment will cause all | |||
| 1811 | * fragments being thrown away, and the entire | |||
| 1812 | * process re-start (Is this tested?) | |||
| 1813 | * | |||
| 1814 | * XXX: This code should instead check | |||
| 1815 | * fragments as they arrive. That means | |||
| 1816 | * kicking off the g^{xy} calculation in the | |||
| 1817 | * background (if it were in the foreground, | |||
| 1818 | * the fragments would be dropped). Later. | |||
| 1819 | */ | |||
| 1820 | if (md->message_payloads.present & P(SKF)((lset_t)1 << (ISAKMP_NEXT_v2SKF))) { | |||
| 1821 | if (have_all_fragments) { | |||
| 1822 | dbg("already have all fragments, skipping fragment collection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("already have all fragments, skipping fragment collection" ); } }; | |||
| 1823 | } else if (!ikev2_collect_fragment(md, ike)) { | |||
| 1824 | return; | |||
| 1825 | } | |||
| 1826 | } | |||
| 1827 | /* | |||
| 1828 | * For this state transition, does it only | |||
| 1829 | * apply when there's no SKEYSEED? If so, and | |||
| 1830 | * SKEYSEED is missing, then things match; else | |||
| 1831 | * things can't match. | |||
| 1832 | */ | |||
| 1833 | if (svm->flags & SMF2_NO_SKEYSEED) { | |||
| 1834 | if (ike->sa.hidden_variables.st_skeyid_calculated) { | |||
| 1835 | continue; | |||
| 1836 | } else { | |||
| 1837 | break; | |||
| 1838 | } | |||
| 1839 | } | |||
| 1840 | /* | |||
| 1841 | * XXX: Shouldn't reach this point without | |||
| 1842 | * SKEYSEED so bail if somehow that hasn't | |||
| 1843 | * happened. No point in even calling | |||
| 1844 | * ikev2_decrypt_msg() (it will also fail). | |||
| 1845 | * | |||
| 1846 | * Suspect it would be cleaner if the state | |||
| 1847 | * machine included an explicit SMF2_SKEYSEED | |||
| 1848 | * flag and all states requiring integrity | |||
| 1849 | * were marked with that. Currently P(SK) and | |||
| 1850 | * P(SKF) imply this. | |||
| 1851 | */ | |||
| 1852 | if (!pexpect(ike->sa.hidden_variables.st_skeyid_calculated)({ _Bool assertion__ = ike->sa.hidden_variables.st_skeyid_calculated ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 1852, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.hidden_variables.st_skeyid_calculated" ); } assertion__; })) { | |||
| 1853 | return; | |||
| 1854 | } | |||
| 1855 | /* | |||
| 1856 | * Decrypt the packet, checking it for | |||
| 1857 | * integrity. Anything lacking integrity is | |||
| 1858 | * dropped. | |||
| 1859 | */ | |||
| 1860 | if (!ikev2_decrypt_msg(ike, md)) { | |||
| 1861 | log_state(RC_LOG, &ike->sa, | |||
| 1862 | "encrypted payload seems to be corrupt; dropping packet"); | |||
| 1863 | return; | |||
| 1864 | } | |||
| 1865 | /* | |||
| 1866 | * The message is protected - the integrity | |||
| 1867 | * check passed - so it was definitely sent by | |||
| 1868 | * the other end of the secured IKE SA. | |||
| 1869 | * | |||
| 1870 | * However, for an AUTH packet, the other end | |||
| 1871 | * hasn't yet been authenticated (and an | |||
| 1872 | * INFORMATIONAL exchange immediately | |||
| 1873 | * following AUTH be due to failed | |||
| 1874 | * authentication). | |||
| 1875 | * | |||
| 1876 | * If there's something wrong with the message | |||
| 1877 | * contents, then the IKE SA gets abandoned, | |||
| 1878 | * but a new new one may be initiated. | |||
| 1879 | * | |||
| 1880 | * See "2.21.2. Error Handling in IKE_AUTH" | |||
| 1881 | * and "2.21.3. Error Handling after IKE SA | |||
| 1882 | * is Authenticated". | |||
| 1883 | * | |||
| 1884 | * For UNSUPPORTED_CRITICAL_PAYLOAD, while the | |||
| 1885 | * RFC clearly states that for the initial | |||
| 1886 | * exchanges and an INFORMATIONAL exchange | |||
| 1887 | * immediately following, the notification | |||
| 1888 | * causes a delete, it says nothing for | |||
| 1889 | * exchanges that follow. | |||
| 1890 | * | |||
| 1891 | * For moment treat it the same. Given the | |||
| 1892 | * PAYLOAD ID that should identify the problem | |||
| 1893 | * isn't being returned this is the least of | |||
| 1894 | * our problems. | |||
| 1895 | */ | |||
| 1896 | struct payload_digest *sk = md->chain[ISAKMP_NEXT_v2SK]; | |||
| 1897 | md->encrypted_payloads = ikev2_decode_payloads(ike->sa.st_logger, md, &sk->pbs, | |||
| 1898 | sk->payload.generic.isag_np); | |||
| 1899 | if (md->encrypted_payloads.n != v2N_NOTHING_WRONG) { | |||
| 1900 | /* | |||
| 1901 | * XXX: Hack to get the | |||
| 1902 | * transition that would have | |||
| 1903 | * been run so it can be | |||
| 1904 | * 'failed'. | |||
| 1905 | */ | |||
| 1906 | hack_error_transition(st, md); | |||
| 1907 | switch (v2_msg_role(md)) { | |||
| 1908 | case MESSAGE_REQUEST: | |||
| 1909 | /* | |||
| 1910 | * Send back a protected error | |||
| 1911 | * response. Need to first | |||
| 1912 | * put the IKE SA into | |||
| 1913 | * responder mode. | |||
| 1914 | */ | |||
| 1915 | v2_msgid_start_responder(ike, st, md); | |||
| 1916 | chunk_t data = chunk2(md->encrypted_payloads.data, | |||
| 1917 | md->encrypted_payloads.data_size); | |||
| 1918 | record_v2N_response(st->st_logger, ike, md, | |||
| 1919 | md->encrypted_payloads.n, &data, | |||
| 1920 | ENCRYPTED_PAYLOAD); | |||
| 1921 | break; | |||
| 1922 | case MESSAGE_RESPONSE: | |||
| 1923 | /* | |||
| 1924 | * Can't respond so kill the | |||
| 1925 | * IKE SA. The secured | |||
| 1926 | * message contained crap so | |||
| 1927 | * there's little that can be | |||
| 1928 | * done. | |||
| 1929 | */ | |||
| 1930 | break; | |||
| 1931 | default: | |||
| 1932 | bad_case(v2_msg_role(md))libreswan_bad_case("v2_msg_role(md)", (v2_msg_role(md)), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 1932, }; &here; })); | |||
| 1933 | } | |||
| 1934 | complete_v2_state_transition(st, md, STF_FATAL); | |||
| 1935 | return; | |||
| 1936 | } | |||
| 1937 | } /* else { go ahead } */ | |||
| 1938 | struct ikev2_payload_errors encrypted_payload_errors | |||
| 1939 | = ikev2_verify_payloads(md, &md->encrypted_payloads, | |||
| 1940 | &svm->encrypted_payloads); | |||
| 1941 | if (encrypted_payload_errors.bad) { | |||
| 1942 | /* Save this failure for later logging. */ | |||
| 1943 | encrypted_payload_status = encrypted_payload_errors; | |||
| 1944 | continue; | |||
| 1945 | } | |||
| 1946 | ||||
| 1947 | if (svm->state != from_state->kind && ix == ISAKMP_v2_CREATE_CHILD_SA) { | |||
| 1948 | /* | |||
| 1949 | * The IKE SA is receiving a CREATE_CHILD_SA | |||
| 1950 | * request. Unlike STATE_V2_PARENT_R0 (and the | |||
| 1951 | * initial responder) the R0 state isn't | |||
| 1952 | * obvious - rekey IKE SA, rekey CHILD SA, and | |||
| 1953 | * create CHILD SA are all slightly different. | |||
| 1954 | * | |||
| 1955 | * The code deals with this by ignoring the | |||
| 1956 | * from_state, and then later, forcing MD's | |||
| 1957 | * from state to values in the table. | |||
| 1958 | */ | |||
| 1959 | dbg("state #%lu forced to match CREATE_CHILD_SA from %s->%s by ignoring from state",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("state #%lu forced to match CREATE_CHILD_SA from %s->%s by ignoring from state" , st->st_serialno, finite_states[svm->state]->name, finite_states [svm->next_state]->name); } } | |||
| 1960 | st->st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("state #%lu forced to match CREATE_CHILD_SA from %s->%s by ignoring from state" , st->st_serialno, finite_states[svm->state]->name, finite_states [svm->next_state]->name); } } | |||
| 1961 | finite_states[svm->state]->name,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("state #%lu forced to match CREATE_CHILD_SA from %s->%s by ignoring from state" , st->st_serialno, finite_states[svm->state]->name, finite_states [svm->next_state]->name); } } | |||
| 1962 | finite_states[svm->next_state]->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("state #%lu forced to match CREATE_CHILD_SA from %s->%s by ignoring from state" , st->st_serialno, finite_states[svm->state]->name, finite_states [svm->next_state]->name); } }; | |||
| 1963 | } | |||
| 1964 | ||||
| 1965 | /* must be the right state machine entry */ | |||
| 1966 | break; | |||
| 1967 | } | |||
| 1968 | ||||
| 1969 | dbg("selected state microcode %s", svm->story){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("selected state microcode %s", svm->story); } }; | |||
| 1970 | ||||
| 1971 | /* no useful state microcode entry? */ | |||
| 1972 | if (svm->state == STATE_IKEv2_ROOF) { | |||
| 1973 | /* count all the error notifications */ | |||
| 1974 | for (struct payload_digest *ntfy = md->chain[ISAKMP_NEXT_v2N]; | |||
| 1975 | ntfy != NULL((void*)0); ntfy = ntfy->next) { | |||
| 1976 | pstat(ikev2_recv_notifies_e, ntfy->payload.v2n.isan_type){ const unsigned pstat_ = (ntfy->payload.v2n.isan_type); const struct pluto_stat *ps_ = &pstats_ikev2_recv_notifies_e; if (pstat_ < ps_->floor || pstat_ >= ps_->roof) { ps_ ->count[ps_->roof - ps_->floor]++; } else { ps_-> count[pstat_-ps_->floor]++; } }; | |||
| 1977 | } | |||
| 1978 | /* | |||
| 1979 | * All branches: log error, [complete transition] | |||
| 1980 | * (why), return so first error wins. | |||
| 1981 | */ | |||
| 1982 | if (message_payload_status.bad) { | |||
| 1983 | /* | |||
| 1984 | * A very messed up message - none of the | |||
| 1985 | * state transitions recognized it!. | |||
| 1986 | */ | |||
| 1987 | log_v2_payload_errors(st->st_logger, md, | |||
| 1988 | &message_payload_status); | |||
| 1989 | return; | |||
| 1990 | } | |||
| 1991 | if (encrypted_payload_status.bad) { | |||
| 1992 | /* | |||
| 1993 | * Payload decrypted and integrity was ok but | |||
| 1994 | * contents weren't valid. | |||
| 1995 | * | |||
| 1996 | * XXX: According to "2.21.2. Error Handling | |||
| 1997 | * in IKE_AUTH" and "2.21.3. Error Handling | |||
| 1998 | * after IKE SA is Authenticated" this should | |||
| 1999 | * be fatal, killing the IKE SA. Oops. | |||
| 2000 | * | |||
| 2001 | * XXX: how can one complete a state | |||
| 2002 | * transition on something that was never | |||
| 2003 | * started? Since this is fatal, the state | |||
| 2004 | * needs to be deleted. | |||
| 2005 | * | |||
| 2006 | * XXX: an alternative would be to treat this | |||
| 2007 | * like some new but as-of-yet not supported | |||
| 2008 | * message combination so just ignore it (but | |||
| 2009 | * update Message IDs). | |||
| 2010 | */ | |||
| 2011 | log_v2_payload_errors(st->st_logger, md, | |||
| 2012 | &encrypted_payload_status); | |||
| 2013 | /* | |||
| 2014 | * XXX: Hack to get the transition | |||
| 2015 | * that would have been run so it can | |||
| 2016 | * be 'failed'. | |||
| 2017 | */ | |||
| 2018 | hack_error_transition(st, md); | |||
| 2019 | switch (v2_msg_role(md)) { | |||
| 2020 | case MESSAGE_REQUEST: | |||
| 2021 | /* | |||
| 2022 | * Send back a protected error | |||
| 2023 | * response. Need to first put the | |||
| 2024 | * IKE SA into responder mode. | |||
| 2025 | */ | |||
| 2026 | v2_msgid_start_responder(ike, st, md); | |||
| 2027 | record_v2N_response(st->st_logger, ike, md, | |||
| 2028 | v2N_INVALID_SYNTAX, NULL((void*)0), | |||
| 2029 | ENCRYPTED_PAYLOAD); | |||
| 2030 | break; | |||
| 2031 | case MESSAGE_RESPONSE: | |||
| 2032 | /* | |||
| 2033 | * Can't respond so kill the IKE SA - | |||
| 2034 | * the secured message contained crap | |||
| 2035 | * so there's little that can be done. | |||
| 2036 | */ | |||
| 2037 | break; | |||
| 2038 | default: | |||
| 2039 | bad_case(v2_msg_role(md))libreswan_bad_case("v2_msg_role(md)", (v2_msg_role(md)), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 2039, }; &here; })); | |||
| 2040 | } | |||
| 2041 | /* XXX: calls delete_state() */ | |||
| 2042 | complete_v2_state_transition(st, md, STF_FATAL); | |||
| 2043 | return; | |||
| 2044 | } | |||
| 2045 | /* | |||
| 2046 | * Presumably things are pretty messed up. While | |||
| 2047 | * there might be a state there probably isn't an | |||
| 2048 | * established IKE SA (so don't even consider trying | |||
| 2049 | * to send an encrypted response), for instance: | |||
| 2050 | * | |||
| 2051 | * - instead of an IKE_AUTH request, the initiator | |||
| 2052 | * sends something totally unexpected (such as an | |||
| 2053 | * informational) and things end up here | |||
| 2054 | * | |||
| 2055 | * - when an IKE_AUTH request's IKE SA succeeeds but | |||
| 2056 | * CHILD SA fails (and pluto screws up the IKE SA by | |||
| 2057 | * updating its state but not its Message ID and not | |||
| 2058 | * responding), the re-transmitted IKE_AUTH ends up | |||
| 2059 | * here | |||
| 2060 | * | |||
| 2061 | * If a request, should it send an un-encrypted | |||
| 2062 | * v2N_INVALID_SYNTAX? | |||
| 2063 | */ | |||
| 2064 | log_state(RC_LOG, &ike->sa, "no useful state microcode entry found for incoming packet"); | |||
| 2065 | /* "dropping message with no matching microcode" */ | |||
| 2066 | return; | |||
| 2067 | } | |||
| 2068 | ||||
| 2069 | if (ix == ISAKMP_v2_CREATE_CHILD_SA) { | |||
| 2070 | /* | |||
| 2071 | * XXX: This code was embedded in the end of the FSM | |||
| 2072 | * search loop. Since it was always executed when the | |||
| 2073 | * state matches, move it out of the loop. Suspect | |||
| 2074 | * this, and the code below, really belong in the | |||
| 2075 | * state transition function proper. | |||
| 2076 | */ | |||
| 2077 | /* going to switch to child st. before that update parent */ | |||
| 2078 | if (!LHAS(ike->sa.hidden_variables.st_nat_traversal, NATED_HOST)(((ike->sa.hidden_variables.st_nat_traversal) & ((lset_t )1 << (NATED_HOST))) != ((lset_t)0))) | |||
| 2079 | update_ike_endpoints(ike, md); | |||
| 2080 | ||||
| 2081 | /* bit further processing of create CREATE_CHILD_SA exchange */ | |||
| 2082 | ||||
| 2083 | /* | |||
| 2084 | * let's get a child state either new or existing to | |||
| 2085 | * proceed | |||
| 2086 | */ | |||
| 2087 | struct child_sa *child; | |||
| 2088 | if (v2_msg_role(md) == MESSAGE_RESPONSE) { | |||
| 2089 | child = pexpect_child_sa(st); | |||
| 2090 | } else { | |||
| 2091 | pexpect(IS_IKE_SA(st))({ _Bool assertion__ = ((st)->st_clonedfrom == 0); if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2091, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "((st)->st_clonedfrom == 0)" ); } assertion__; }); | |||
| 2092 | child = process_v2_child_ix(ike, svm); | |||
| 2093 | } | |||
| 2094 | ||||
| 2095 | /* | |||
| 2096 | * Switch to child state (possibly from the same child | |||
| 2097 | * state, see above) | |||
| 2098 | */ | |||
| 2099 | dbg("forcing ST #%lu to CHILD #%lu.#%lu in FSM processor",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("forcing ST #%lu to CHILD #%lu.#%lu in FSM processor" , st->st_serialno, ike->sa.st_serialno, child->sa.st_serialno ); } } | |||
| 2100 | st->st_serialno, ike->sa.st_serialno, child->sa.st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("forcing ST #%lu to CHILD #%lu.#%lu in FSM processor" , st->st_serialno, ike->sa.st_serialno, child->sa.st_serialno ); } }; | |||
| 2101 | st = &child->sa; | |||
| 2102 | } | |||
| 2103 | ||||
| 2104 | v2_dispatch(ike, st, md, svm); | |||
| 2105 | } | |||
| 2106 | ||||
| 2107 | void v2_dispatch(struct ike_sa *ike, struct state *st, | |||
| 2108 | struct msg_digest *md, | |||
| 2109 | const struct v2_state_transition *svm) | |||
| 2110 | { | |||
| 2111 | md->svm = svm; | |||
| 2112 | ||||
| 2113 | /* | |||
| 2114 | * For the responder, update the work-in-progress Message ID | |||
| 2115 | * window (since work has commenced). | |||
| 2116 | * | |||
| 2117 | * Exclude the SKEYSEED calculation - the message has yet to | |||
| 2118 | * be decrypted so true work on the message is yet to comence. | |||
| 2119 | */ | |||
| 2120 | if (v2_msg_role(md) == MESSAGE_REQUEST && | |||
| 2121 | !(svm->flags & SMF2_NO_SKEYSEED)) { | |||
| 2122 | v2_msgid_start_responder(ike, st, md); | |||
| 2123 | } | |||
| 2124 | ||||
| 2125 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
| 2126 | if (pbs_left(&md->message_pbs)((size_t)((&md->message_pbs)->roof - (&md->message_pbs )->cur)) != 0) | |||
| 2127 | DBG_log("removing %d bytes of padding", | |||
| 2128 | (int) pbs_left(&md->message_pbs)((size_t)((&md->message_pbs)->roof - (&md->message_pbs )->cur))); | |||
| 2129 | } | |||
| 2130 | ||||
| 2131 | md->message_pbs.roof = md->message_pbs.cur; /* trim padding (not actually legit) */ | |||
| 2132 | ||||
| 2133 | dbg("calling processor %s", svm->story){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("calling processor %s", svm->story); } }; | |||
| 2134 | ||||
| 2135 | /* | |||
| 2136 | * XXX: for now pass in the possibly NULL child; suspect a | |||
| 2137 | * better model is to drop the child and instead have the IKE | |||
| 2138 | * SA run a nested state machine for the child. | |||
| 2139 | * | |||
| 2140 | * For instance, when a CREATE_CHILD_SA request arrives, pass | |||
| 2141 | * that to the IKE SA and then let it do all the create child | |||
| 2142 | * magic. | |||
| 2143 | */ | |||
| 2144 | so_serial_t old_st = st->st_serialno; | |||
| 2145 | ||||
| 2146 | statetime_t start = statetime_start(st); | |||
| 2147 | struct child_sa *child = IS_CHILD_SA(st)((st)->st_clonedfrom != 0) ? pexpect_child_sa(st) : NULL((void*)0); | |||
| 2148 | /* danger: st may not be valid */ | |||
| 2149 | stf_status e = svm->processor(ike, child, md); | |||
| 2150 | ||||
| 2151 | if (e == STF_SKIP_COMPLETE_STATE_TRANSITION) { | |||
| 2152 | /* | |||
| 2153 | * Danger! Processor did something dodgy like free ST! | |||
| 2154 | */ | |||
| 2155 | dbg("processor '%s' for #%lu suppresed complete st_v2_transition",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("processor '%s' for #%lu suppresed complete st_v2_transition" , svm->story, old_st); } } | |||
| 2156 | svm->story, old_st){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("processor '%s' for #%lu suppresed complete st_v2_transition" , svm->story, old_st); } }; | |||
| 2157 | } else { | |||
| 2158 | complete_v2_state_transition(st, md, e); | |||
| 2159 | } | |||
| 2160 | ||||
| 2161 | statetime_stop(&start, "processing: %s in %s()", svm->story, __func__); | |||
| 2162 | /* our caller with release_any_md(mdp) */ | |||
| 2163 | } | |||
| 2164 | ||||
| 2165 | /* | |||
| 2166 | * This logs to the main log the authentication and encryption keys | |||
| 2167 | * for an IKEv2 SA. This is done in a format that is compatible with | |||
| 2168 | * tcpdump 4.0's -E option. | |||
| 2169 | * | |||
| 2170 | * The log message will require that a cut command is used to remove | |||
| 2171 | * the initial text. | |||
| 2172 | * | |||
| 2173 | * DANGER: this intentionally leaks cryptographic secrets. | |||
| 2174 | */ | |||
| 2175 | void ikev2_log_parentSA(const struct state *st) | |||
| 2176 | { | |||
| 2177 | if (DBGP(DBG_PRIVATE)(cur_debugging & (((lset_t)1 << (DBG_PRIVATE_IX))))) { | |||
| 2178 | if (st->st_oakley.ta_integ == NULL((void*)0) || | |||
| 2179 | st->st_oakley.ta_encrypt == NULL((void*)0)) | |||
| 2180 | return; | |||
| 2181 | ||||
| 2182 | /* format initiator SPI */ | |||
| 2183 | char tispi[3 + 2*IKE_SA_SPI_SIZE8]; | |||
| 2184 | (void)datatot(st->st_ike_spis.initiator.bytes, sizeof(st->st_ike_spis.initiator.bytes), | |||
| 2185 | 'x', | |||
| 2186 | tispi, sizeof(tispi)); | |||
| 2187 | ||||
| 2188 | /* format responder SPI */ | |||
| 2189 | char trspi[3 + 2*IKE_SA_SPI_SIZE8]; | |||
| 2190 | (void)datatot(st->st_ike_spis.responder.bytes, sizeof(st->st_ike_spis.responder.bytes), | |||
| 2191 | 'x', | |||
| 2192 | trspi, sizeof(trspi)); | |||
| 2193 | ||||
| 2194 | const char *authalgo = st->st_oakley.ta_integ->integ_tcpdump_name; | |||
| 2195 | const char *encalgo = st->st_oakley.ta_encrypt->encrypt_tcpdump_name; | |||
| 2196 | ||||
| 2197 | /* | |||
| 2198 | * Text of encryption key length (suffix for encalgo). | |||
| 2199 | * No more than 3 digits, but compiler fears it might be 5. | |||
| 2200 | */ | |||
| 2201 | char tekl[6] = ""; | |||
| 2202 | if (st->st_oakley.enckeylen != 0) | |||
| 2203 | snprintf(tekl, sizeof(tekl), "%u", | |||
| 2204 | st->st_oakley.enckeylen); | |||
| 2205 | ||||
| 2206 | /* v2 IKE authentication key for initiator (256 bit bound) */ | |||
| 2207 | chunk_t ai = chunk_from_symkey("ai", st->st_skey_ai_nss, | |||
| 2208 | st->st_logger); | |||
| 2209 | char tai[3 + 2 * BYTES_FOR_BITS(256)(((256) + 8 - 1) / 8)] = ""; | |||
| 2210 | (void)datatot(ai.ptr, ai.len, 'x', tai, sizeof(tai)); | |||
| 2211 | free_chunk_content(&ai); | |||
| 2212 | ||||
| 2213 | /* v2 IKE encryption key for initiator (256 bit bound) */ | |||
| 2214 | chunk_t ei = chunk_from_symkey("ei", st->st_skey_ei_nss, | |||
| 2215 | st->st_logger); | |||
| 2216 | char tei[3 + 2 * BYTES_FOR_BITS(256)(((256) + 8 - 1) / 8)] = ""; | |||
| 2217 | (void)datatot(ei.ptr, ei.len, 'x', tei, sizeof(tei)); | |||
| 2218 | free_chunk_content(&ei); | |||
| 2219 | ||||
| 2220 | DBG_log("ikev2 I %s %s %s:%s %s%s:%s", | |||
| 2221 | tispi, trspi, | |||
| 2222 | authalgo, tai, | |||
| 2223 | encalgo, tekl, tei); | |||
| 2224 | ||||
| 2225 | /* v2 IKE authentication key for responder (256 bit bound) */ | |||
| 2226 | chunk_t ar = chunk_from_symkey("ar", st->st_skey_ar_nss, | |||
| 2227 | st->st_logger); | |||
| 2228 | char tar[3 + 2 * BYTES_FOR_BITS(256)(((256) + 8 - 1) / 8)] = ""; | |||
| 2229 | (void)datatot(ar.ptr, ar.len, 'x', tar, sizeof(tar)); | |||
| 2230 | free_chunk_content(&ar); | |||
| 2231 | ||||
| 2232 | /* v2 IKE encryption key for responder (256 bit bound) */ | |||
| 2233 | chunk_t er = chunk_from_symkey("er", st->st_skey_er_nss, | |||
| 2234 | st->st_logger); | |||
| 2235 | char ter[3 + 2 * BYTES_FOR_BITS(256)(((256) + 8 - 1) / 8)] = ""; | |||
| 2236 | (void)datatot(er.ptr, er.len, 'x', ter, sizeof(ter)); | |||
| 2237 | free_chunk_content(&er); | |||
| 2238 | ||||
| 2239 | DBG_log("ikev2 R %s %s %s:%s %s%s:%s", | |||
| 2240 | tispi, trspi, | |||
| 2241 | authalgo, tar, | |||
| 2242 | encalgo, tekl, ter); | |||
| 2243 | } | |||
| 2244 | } | |||
| 2245 | ||||
| 2246 | static void ikev2_child_emancipate(struct ike_sa *from, struct child_sa *to, | |||
| 2247 | const struct v2_state_transition *transition) | |||
| 2248 | { | |||
| 2249 | /* initialize the the new IKE SA. reset and message ID */ | |||
| 2250 | to->sa.st_clonedfrom = SOS_NOBODY0; | |||
| 2251 | v2_msgid_init_ike(pexpect_ike_sa(&to->sa)); | |||
| 2252 | ||||
| 2253 | /* Switch to the new IKE SPIs */ | |||
| 2254 | to->sa.st_ike_spis = to->sa.st_ike_rekey_spis; | |||
| 2255 | rehash_state_cookies_in_db(&to->sa); | |||
| 2256 | ||||
| 2257 | /* TO has correct IKE_SPI so can migrate */ | |||
| 2258 | v2_migrate_children(from, to); | |||
| 2259 | ||||
| 2260 | dbg("moving over any pending requests"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("moving over any pending requests"); } }; | |||
| 2261 | v2_msgid_migrate_queue(from, to); | |||
| 2262 | ||||
| 2263 | /* child is now a parent */ | |||
| 2264 | ikev2_ike_sa_established(pexpect_ike_sa(&to->sa), | |||
| 2265 | transition, transition->next_state); | |||
| 2266 | } | |||
| 2267 | ||||
| 2268 | static void jam_v2_ike_details(struct jambuf *buf, struct state *st) | |||
| 2269 | { | |||
| 2270 | jam_parent_sa_details(buf, st); | |||
| 2271 | } | |||
| 2272 | ||||
| 2273 | static void success_v2_state_transition(struct state *st, struct msg_digest *md, | |||
| 2274 | const struct v2_state_transition *transition) | |||
| 2275 | { | |||
| 2276 | /* | |||
| 2277 | * XXX: the transition's from state can lie - it may be | |||
| 2278 | * different to the ST's state! | |||
| 2279 | */ | |||
| 2280 | enum state_kind from_state = transition->state; | |||
| 2281 | struct connection *c = st->st_connection; | |||
| 2282 | struct ike_sa *ike = ike_sa(st, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2282, }; &here; })); | |||
| 2283 | ||||
| 2284 | if (from_state != transition->next_state) { | |||
| 2285 | dbg("transitioning from state %s to state %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("transitioning from state %s to state %s", finite_states [from_state]->name, finite_states[transition->next_state ]->name); } } | |||
| 2286 | finite_states[from_state]->name,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("transitioning from state %s to state %s", finite_states [from_state]->name, finite_states[transition->next_state ]->name); } } | |||
| 2287 | finite_states[transition->next_state]->name){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("transitioning from state %s to state %s", finite_states [from_state]->name, finite_states[transition->next_state ]->name); } }; | |||
| 2288 | } | |||
| 2289 | ||||
| 2290 | /* | |||
| 2291 | * Update counters, and if part of the transition, send the | |||
| 2292 | * new message. | |||
| 2293 | */ | |||
| 2294 | ||||
| 2295 | dbg("Message ID: updating counters for #%lu", st->st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Message ID: updating counters for #%lu", st-> st_serialno); } }; | |||
| 2296 | v2_msgid_update_recv(ike, st, md); | |||
| 2297 | v2_msgid_update_sent(ike, st, md, transition->send); | |||
| 2298 | ||||
| 2299 | bool_Bool established_before = (IS_IKE_SA_ESTABLISHED(st)((st)->st_state->kind == STATE_V2_ESTABLISHED_IKE_SA) || | |||
| 2300 | IS_CHILD_SA_ESTABLISHED(st)((st)->st_state->kind == STATE_V2_ESTABLISHED_CHILD_SA)); | |||
| 2301 | ||||
| 2302 | if (from_state == STATE_V2_REKEY_IKE_R0 || | |||
| 2303 | from_state == STATE_V2_REKEY_IKE_I1) { | |||
| 2304 | ikev2_child_emancipate(ike, pexpect_child_sa(st), | |||
| 2305 | transition); | |||
| 2306 | /* Emancipated ST answers to no one - it's an IKE SA */ | |||
| 2307 | v2_msgid_schedule_next_initiator(pexpect_ike_sa(st)); | |||
| 2308 | } else { | |||
| 2309 | change_state(st, transition->next_state); | |||
| 2310 | v2_msgid_schedule_next_initiator(ike); | |||
| 2311 | } | |||
| 2312 | passert(st->st_state->kind >= STATE_IKEv2_FLOOR)({ _Bool assertion__ = st->st_state->kind >= STATE_IKEv2_FLOOR ; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2312, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "st->st_state->kind >= STATE_IKEv2_FLOOR" ); } (void) 1; }); | |||
| 2313 | passert(st->st_state->kind < STATE_IKEv2_ROOF)({ _Bool assertion__ = st->st_state->kind < STATE_IKEv2_ROOF ; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2313, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "st->st_state->kind < STATE_IKEv2_ROOF" ); } (void) 1; }); | |||
| 2314 | ||||
| 2315 | bool_Bool established_after = (IS_IKE_SA_ESTABLISHED(st)((st)->st_state->kind == STATE_V2_ESTABLISHED_IKE_SA) || | |||
| 2316 | IS_CHILD_SA_ESTABLISHED(st)((st)->st_state->kind == STATE_V2_ESTABLISHED_CHILD_SA)); | |||
| 2317 | ||||
| 2318 | bool_Bool just_established = (!established_before && established_after); | |||
| 2319 | if (just_established) { | |||
| 2320 | /* | |||
| 2321 | * Count successful transition into an established | |||
| 2322 | * state. | |||
| 2323 | */ | |||
| 2324 | pstat_sa_established(st); | |||
| 2325 | } | |||
| 2326 | ||||
| 2327 | /* | |||
| 2328 | * Tell whack and logs our progress. | |||
| 2329 | * | |||
| 2330 | * If it's OE or a state transition we're not telling anyone | |||
| 2331 | * about, then be quiet. | |||
| 2332 | */ | |||
| 2333 | ||||
| 2334 | dbg("announcing the state transition"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("announcing the state transition"); } }; | |||
| 2335 | enum rc_type w; | |||
| 2336 | void (*jam_details)(struct jambuf *buf, struct state *st); | |||
| 2337 | bool_Bool suppress_log = ((transition->flags & SMF2_SUPPRESS_SUCCESS_LOG) || | |||
| 2338 | (c != NULL((void*)0) && (c->policy & POLICY_OPPORTUNISTIC((lset_t)1 << (POLICY_OPPORTUNISTIC_IX))))); | |||
| 2339 | const char *sep = " "; | |||
| 2340 | if (transition->state == transition->next_state) { | |||
| 2341 | /* | |||
| 2342 | * HACK for seemingly going around in circles | |||
| 2343 | */ | |||
| 2344 | jam_details = NULL((void*)0); | |||
| 2345 | w = RC_NEW_V2_STATE + st->st_state->kind; | |||
| 2346 | } else if (IS_CHILD_SA(st)((st)->st_clonedfrom != 0) && just_established) { | |||
| 2347 | jam_details = jam_v2_child_details; | |||
| 2348 | suppress_log = false0; | |||
| 2349 | sep = "; "; | |||
| 2350 | w = RC_SUCCESS; /* also triggers detach */ | |||
| 2351 | } else if (IS_IKE_SA(st)((st)->st_clonedfrom == 0) && just_established) { | |||
| 2352 | /* ike_sa_established() called elsewhere */ | |||
| 2353 | jam_details = jam_v2_ike_details; | |||
| 2354 | w = RC_SUCCESS; /* also triggers detach */ | |||
| 2355 | } else if (transition->state == STATE_V2_PARENT_I1 && | |||
| 2356 | transition->next_state == STATE_V2_PARENT_I2) { | |||
| 2357 | jam_details = jam_v2_ike_details; | |||
| 2358 | w = RC_NEW_V2_STATE + st->st_state->kind; | |||
| 2359 | } else if (st->st_state->kind == STATE_V2_PARENT_R1) { | |||
| 2360 | jam_details = jam_v2_ike_details; | |||
| 2361 | w = RC_NEW_V2_STATE + st->st_state->kind; | |||
| 2362 | } else { | |||
| 2363 | jam_details = NULL((void*)0); | |||
| 2364 | w = RC_NEW_V2_STATE + st->st_state->kind; | |||
| 2365 | } | |||
| 2366 | ||||
| 2367 | if (suppress_log) { | |||
| 2368 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_logger(buf , &failsafe_logger, DEBUG_STREAM), buf = ((void*)0)) { | |||
| 2369 | jam(buf, "%s", st->st_state->story); | |||
| 2370 | /* document SA details for admin's pleasure */ | |||
| 2371 | if (jam_details != NULL((void*)0)) { | |||
| 2372 | jam_string(buf, sep); | |||
| 2373 | jam_details(buf, st); | |||
| 2374 | } | |||
| 2375 | } | |||
| 2376 | } else { | |||
| 2377 | LLOG_JAMBUF(w, st->st_logger, buf)for (char lswbuf[((size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf), sizeof(lswbuf)), *buf = &jambuf ; buf != ((void*)0); buf = ((void*)0)) for (({ if (((w) & NO_PREFIX) == ((lset_t)0) && (((w) & STREAM_MASK ) != DEBUG_STREAM || (cur_debugging & (((lset_t)1 << (DBG_ADD_PREFIX_IX)))))) { (st->st_logger)->object_vec ->jam_object_prefix(buf, (st->st_logger)->object); } }); buf != ((void*)0); jambuf_to_logger(buf, (st->st_logger ), w), buf = ((void*)0)) { | |||
| 2378 | jam(buf, "%s", st->st_state->story); | |||
| 2379 | /* document SA details for admin's pleasure */ | |||
| 2380 | if (jam_details != NULL((void*)0)) { | |||
| 2381 | jam_string(buf, sep); | |||
| 2382 | jam_details(buf, st); | |||
| 2383 | } | |||
| 2384 | } | |||
| 2385 | } | |||
| 2386 | ||||
| 2387 | /* | |||
| 2388 | * 2.23. NAT Traversal | |||
| 2389 | * | |||
| 2390 | * There are cases where a NAT box decides to remove mappings | |||
| 2391 | * that are still alive (for example, the keepalive interval | |||
| 2392 | * is too long, or the NAT box is rebooted). This will be | |||
| 2393 | * apparent to a host if it receives a packet whose integrity | |||
| 2394 | * protection validates, but has a different port, address, or | |||
| 2395 | * both from the one that was associated with the SA in the | |||
| 2396 | * validated packet. When such a validated packet is found, a | |||
| 2397 | * host that does not support other methods of recovery such | |||
| 2398 | * as IKEv2 Mobility and Multihoming (MOBIKE) [MOBIKE], and | |||
| 2399 | * that is not behind a NAT, SHOULD send all packets | |||
| 2400 | * (including retransmission packets) to the IP address and | |||
| 2401 | * port in the validated packet, and SHOULD store this as the | |||
| 2402 | * new address and port combination for the SA (that is, they | |||
| 2403 | * SHOULD dynamically update the address). A host behind a | |||
| 2404 | * NAT SHOULD NOT do this type of dynamic address update if a | |||
| 2405 | * validated packet has different port and/or address values | |||
| 2406 | * because it opens a possible DoS attack (such as allowing an | |||
| 2407 | * attacker to break the connection with a single packet). | |||
| 2408 | * Also, dynamic address update should only be done in | |||
| 2409 | * response to a new packet; otherwise, an attacker can revert | |||
| 2410 | * the addresses with old replayed packets. Because of this, | |||
| 2411 | * dynamic updates can only be done safely if replay | |||
| 2412 | * protection is enabled. When IKEv2 is used with MOBIKE, | |||
| 2413 | * dynamically updating the addresses described above | |||
| 2414 | * interferes with MOBIKE's way of recovering from the same | |||
| 2415 | * situation. See Section 3.8 of [MOBIKE] for more | |||
| 2416 | * information. | |||
| 2417 | * | |||
| 2418 | * XXX: so .... | |||
| 2419 | * | |||
| 2420 | * - replay protection? | |||
| 2421 | * | |||
| 2422 | * - IKE_AUTH exchange? Already handled? Exclude? | |||
| 2423 | */ | |||
| 2424 | if (nat_traversal_enabled && | |||
| 2425 | /* | |||
| 2426 | * Only when responding ... | |||
| 2427 | */ | |||
| 2428 | transition->send == MESSAGE_RESPONSE && | |||
| 2429 | pexpect(v2_msg_role(md) == MESSAGE_REQUEST)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_REQUEST; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2429, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "v2_msg_role(md) == MESSAGE_REQUEST" ); } assertion__; }) && | |||
| 2430 | /* | |||
| 2431 | * Only when the request changes the remote's endpoint ... | |||
| 2432 | */ | |||
| 2433 | !endpoint_eq_endpoint(ike->sa.st_remote_endpoint, md->sender) && | |||
| 2434 | /* | |||
| 2435 | * Only when the request was protected and passes | |||
| 2436 | * integrity ... | |||
| 2437 | * | |||
| 2438 | * Once keymat is present, only encrypted messessages with | |||
| 2439 | * valid integrity can successfully complete a transaction | |||
| 2440 | * with STF_OK. True? True. | |||
| 2441 | * | |||
| 2442 | * IS_IKE_SA_ESTABLISHED() better? False. IKE_AUTH | |||
| 2443 | * messages meet the above requirements. | |||
| 2444 | */ | |||
| 2445 | ike->sa.hidden_variables.st_skeyid_calculated && | |||
| 2446 | md->encrypted_payloads.parsed && | |||
| 2447 | md->encrypted_payloads.n == v2N_NOTHING_WRONG && | |||
| 2448 | /* | |||
| 2449 | * Only when the local IKE SA isn't behind NAT but the | |||
| 2450 | * remote IKE SA is ... | |||
| 2451 | */ | |||
| 2452 | !LHAS(ike->sa.hidden_variables.st_nat_traversal, NATED_HOST)(((ike->sa.hidden_variables.st_nat_traversal) & ((lset_t )1 << (NATED_HOST))) != ((lset_t)0)) && | |||
| 2453 | LHAS(ike->sa.hidden_variables.st_nat_traversal, NATED_PEER)(((ike->sa.hidden_variables.st_nat_traversal) & ((lset_t )1 << (NATED_PEER))) != ((lset_t)0))) { | |||
| 2454 | /* | |||
| 2455 | * Things are looking plausible. | |||
| 2456 | */ | |||
| 2457 | if (ike->sa.st_ike_sent_v2n_mobike_supported && | |||
| 2458 | ike->sa.st_ike_seen_v2n_mobike_supported && | |||
| 2459 | md->hdr.isa_xchg == ISAKMP_v2_INFORMATIONAL) { | |||
| 2460 | /* | |||
| 2461 | * Only when MOBIKE has not been negotiated ... | |||
| 2462 | */ | |||
| 2463 | endpoint_buf sb, mb; | |||
| 2464 | dbg("NAT: MOBIKE: skipping remote sender from %s -> %s as MOBIKE delt with it in informational code(?)",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT: MOBIKE: skipping remote sender from %s -> %s as MOBIKE delt with it in informational code(?)" , str_endpoint(&ike->sa.st_remote_endpoint, &sb), str_endpoint (&md->sender, &mb)); } } | |||
| 2465 | str_endpoint(&ike->sa.st_remote_endpoint, &sb),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT: MOBIKE: skipping remote sender from %s -> %s as MOBIKE delt with it in informational code(?)" , str_endpoint(&ike->sa.st_remote_endpoint, &sb), str_endpoint (&md->sender, &mb)); } } | |||
| 2466 | str_endpoint(&md->sender, &mb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT: MOBIKE: skipping remote sender from %s -> %s as MOBIKE delt with it in informational code(?)" , str_endpoint(&ike->sa.st_remote_endpoint, &sb), str_endpoint (&md->sender, &mb)); } }; | |||
| 2467 | } else { | |||
| 2468 | endpoint_buf sb, mb; | |||
| 2469 | dbg("NAT: MOBKIE: updating remote sender from %s -> %s as non-MOBIKE or non-INFORMATIONAL",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT: MOBKIE: updating remote sender from %s -> %s as non-MOBIKE or non-INFORMATIONAL" , str_endpoint(&ike->sa.st_remote_endpoint, &sb), str_endpoint (&md->sender, &mb)); } } | |||
| 2470 | str_endpoint(&ike->sa.st_remote_endpoint, &sb),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT: MOBKIE: updating remote sender from %s -> %s as non-MOBIKE or non-INFORMATIONAL" , str_endpoint(&ike->sa.st_remote_endpoint, &sb), str_endpoint (&md->sender, &mb)); } } | |||
| 2471 | str_endpoint(&md->sender, &mb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("NAT: MOBKIE: updating remote sender from %s -> %s as non-MOBIKE or non-INFORMATIONAL" , str_endpoint(&ike->sa.st_remote_endpoint, &sb), str_endpoint (&md->sender, &mb)); } }; | |||
| 2472 | ike->sa.st_remote_endpoint = md->sender; | |||
| 2473 | } | |||
| 2474 | } | |||
| 2475 | ||||
| 2476 | /* if requested, send the new reply packet */ | |||
| 2477 | switch (transition->send) { | |||
| 2478 | case MESSAGE_REQUEST: | |||
| 2479 | case MESSAGE_RESPONSE: | |||
| 2480 | send_recorded_v2_message(ike, finite_states[from_state]->name, | |||
| 2481 | transition->send); | |||
| 2482 | break; | |||
| 2483 | case NO_MESSAGE: | |||
| 2484 | break; | |||
| 2485 | default: | |||
| 2486 | bad_case(transition->send)libreswan_bad_case("transition->send", (transition->send ), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2486, }; &here; }));; | |||
| 2487 | } | |||
| 2488 | ||||
| 2489 | if (just_established) { | |||
| 2490 | release_any_whack(st, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2490, }; &here; }), "IKEv2 transitions finished"); | |||
| 2491 | ||||
| 2492 | /* XXX should call unpend again on parent SA */ | |||
| 2493 | if (IS_CHILD_SA(st)((st)->st_clonedfrom != 0)) { | |||
| 2494 | /* with failed child sa, we end up here with an orphan?? */ | |||
| 2495 | dbg("unpending #%lu's IKE SA #%lu", st->st_serialno,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unpending #%lu's IKE SA #%lu", st->st_serialno , ike->sa.st_serialno); } } | |||
| 2496 | ike->sa.st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("unpending #%lu's IKE SA #%lu", st->st_serialno , ike->sa.st_serialno); } }; | |||
| 2497 | /* a better call unpend in ikev2_ike_sa_established? */ | |||
| 2498 | unpend(ike, c); | |||
| 2499 | ||||
| 2500 | /* | |||
| 2501 | * If this was an OE connection, check for removing a potential | |||
| 2502 | * matching bare shunt entry - bare shunts are always a %pass or | |||
| 2503 | * %hold SPI but are found regardless of whether we passed in | |||
| 2504 | * SPI_PASS or SPI_HOLD ? | |||
| 2505 | */ | |||
| 2506 | if (LIN(POLICY_OPPORTUNISTIC, c->policy)(((((lset_t)1 << (POLICY_OPPORTUNISTIC_IX))) & (c-> policy)) == (((lset_t)1 << (POLICY_OPPORTUNISTIC_IX))))) { | |||
| 2507 | struct spd_route *sr = &c->spd; | |||
| 2508 | struct bare_shunt **bs = bare_shunt_ptr(&sr->this.client, | |||
| 2509 | &sr->that.client, | |||
| 2510 | sr->this.protocol, | |||
| 2511 | "old bare shunt to delete"); | |||
| 2512 | ||||
| 2513 | if (bs != NULL((void*)0)) { | |||
| 2514 | dbg("deleting old bare shunt"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("deleting old bare shunt"); } }; | |||
| 2515 | if (!delete_bare_shunt(&c->spd.this.host_addr, | |||
| 2516 | &c->spd.that.host_addr, | |||
| 2517 | c->spd.this.protocol, | |||
| 2518 | SPI_PASS /* else its not bare */, | |||
| 2519 | /*skip_xfrm_policy_delete?*/true1, | |||
| 2520 | "installed IPsec SA replaced old bare shunt", | |||
| 2521 | st->st_logger)) { | |||
| 2522 | log_state(RC_LOG_SERIOUS, &ike->sa, | |||
| 2523 | "Failed to delete old bare shunt"); | |||
| 2524 | } | |||
| 2525 | } | |||
| 2526 | } | |||
| 2527 | release_any_whack(&ike->sa, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2527, }; &here; }), "IKEv2 transitions finished so releaseing IKE SA"); | |||
| 2528 | } | |||
| 2529 | } else if (transition->flags & SMF2_RELEASE_WHACK) { | |||
| 2530 | dbg("releasing whack"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("releasing whack"); } }; | |||
| 2531 | release_any_whack(st, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2531, }; &here; }), "ST per transition"); | |||
| 2532 | if (st != &ike->sa) { | |||
| 2533 | release_any_whack(&ike->sa, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2533, }; &here; }), "IKE per transition"); | |||
| 2534 | } | |||
| 2535 | } | |||
| 2536 | ||||
| 2537 | /* Schedule for whatever timeout is specified */ | |||
| 2538 | { | |||
| 2539 | enum event_type kind = transition->timeout_event; | |||
| 2540 | struct connection *c = st->st_connection; | |||
| 2541 | ||||
| 2542 | switch (kind) { | |||
| 2543 | ||||
| 2544 | case EVENT_RETRANSMIT: | |||
| 2545 | /* | |||
| 2546 | * Event retransmit is really a secret code to | |||
| 2547 | * indicate that a request is being sent and a | |||
| 2548 | * retransmit should already be scheduled. | |||
| 2549 | */ | |||
| 2550 | dbg("checking that a retransmit timeout_event was already"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("checking that a retransmit timeout_event was already" ); } }; | |||
| 2551 | delete_event(st); /* relying on retransmit */ | |||
| 2552 | pexpect(ike->sa.st_retransmit_event != NULL)({ _Bool assertion__ = ike->sa.st_retransmit_event != ((void *)0); if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c" , .line = 2552, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "ike->sa.st_retransmit_event != ((void*)0)" ); } assertion__; }); | |||
| 2553 | pexpect(transition->send == MESSAGE_REQUEST)({ _Bool assertion__ = transition->send == MESSAGE_REQUEST ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2553, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->send == MESSAGE_REQUEST" ); } assertion__; }); | |||
| 2554 | break; | |||
| 2555 | ||||
| 2556 | case EVENT_SA_REPLACE: /* IKE or Child SA replacement event */ | |||
| 2557 | schedule_v2_replace_event(st); | |||
| 2558 | break; | |||
| 2559 | ||||
| 2560 | case EVENT_SA_DISCARD: | |||
| 2561 | delete_event(st); | |||
| 2562 | event_schedule(kind, MAXIMUM_RESPONDER_WAIT_DELAYdeltatime(200), st); | |||
| 2563 | break; | |||
| 2564 | ||||
| 2565 | case EVENT_NULL: | |||
| 2566 | /* | |||
| 2567 | * Is there really no case where we want to | |||
| 2568 | * set no timer? more likely an accident? | |||
| 2569 | */ | |||
| 2570 | pexpect_failllog_pexpect(st->st_logger, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2570, }; &here; }), | |||
| 2571 | "V2 microcode entry (%s) has unspecified timeout_event", | |||
| 2572 | transition->story); | |||
| 2573 | break; | |||
| 2574 | ||||
| 2575 | case EVENT_v2_REDIRECT: | |||
| 2576 | event_delete(EVENT_v2_REDIRECT, st); | |||
| 2577 | event_schedule(EVENT_v2_REDIRECT, deltatime(0), st); | |||
| 2578 | break; | |||
| 2579 | ||||
| 2580 | case EVENT_RETAIN: | |||
| 2581 | /* the previous event is retained */ | |||
| 2582 | dbg("#%lu is retaining %s with is previously set timeout",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu is retaining %s with is previously set timeout" , st->st_serialno, (st->st_event == ((void*)0) ? "<no-event>" : enum_name(&event_type_names, st->st_event->ev_type ))); } } | |||
| 2583 | st->st_serialno, (st->st_event == NULL ? "<no-event>" :{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu is retaining %s with is previously set timeout" , st->st_serialno, (st->st_event == ((void*)0) ? "<no-event>" : enum_name(&event_type_names, st->st_event->ev_type ))); } } | |||
| 2584 | enum_name(&event_type_names, st->st_event->ev_type))){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("#%lu is retaining %s with is previously set timeout" , st->st_serialno, (st->st_event == ((void*)0) ? "<no-event>" : enum_name(&event_type_names, st->st_event->ev_type ))); } }; | |||
| 2585 | break; | |||
| 2586 | ||||
| 2587 | default: | |||
| 2588 | bad_case(kind)libreswan_bad_case("kind", (kind), ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2588, }; &here; })); | |||
| 2589 | break; | |||
| 2590 | } | |||
| 2591 | /* | |||
| 2592 | * start liveness checks if set, making sure we only | |||
| 2593 | * schedule once when moving from I2->I3 or R1->R2 | |||
| 2594 | */ | |||
| 2595 | if (st->st_state->kind != from_state && | |||
| 2596 | st->st_state->kind != STATE_UNDEFINED && | |||
| 2597 | IS_CHILD_SA_ESTABLISHED(st)((st)->st_state->kind == STATE_V2_ESTABLISHED_CHILD_SA) && | |||
| 2598 | dpd_active_locally(st)) { | |||
| 2599 | dbg("dpd enabled, scheduling ikev2 liveness checks"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("dpd enabled, scheduling ikev2 liveness checks" ); } }; | |||
| 2600 | deltatime_t delay = deltatime_max(c->dpd_delay, deltatime(MIN_LIVENESS1)); | |||
| 2601 | event_schedule(EVENT_v2_LIVENESS, delay, st); | |||
| 2602 | } | |||
| 2603 | } | |||
| 2604 | } | |||
| 2605 | ||||
| 2606 | /* | |||
| 2607 | * Dependent on RESULT, either complete, suspend, abandon, or abort | |||
| 2608 | * (delete state) the state transition started by the state-specific | |||
| 2609 | * state transition function. | |||
| 2610 | * | |||
| 2611 | * Since this is function is meaningless without a state, ST really | |||
| 2612 | * should be non-NULL. | |||
| 2613 | * | |||
| 2614 | * XXX: A broken exception is when responding to an IKE_SA_INIT | |||
| 2615 | * request - the state machine calls the state transition function | |||
| 2616 | * with no state (trusting that the transition function will do the | |||
| 2617 | * job, but that isn't always true). The fix is to create the state | |||
| 2618 | * before calling the state transition function (like is done for the | |||
| 2619 | * CHILD_SA code). | |||
| 2620 | * | |||
| 2621 | * Since, when initiating an exchange there is no message, code can't | |||
| 2622 | * assume that (*MDP) is non-NULL. | |||
| 2623 | * | |||
| 2624 | * XXX: Some state transition functions switch state part way (see | |||
| 2625 | * AUTH child code) and then tunnel the new state to this code via | |||
| 2626 | * (*MDP)->st and some callers passing in (*MDP)->st). The fix is for | |||
| 2627 | * the AUTH code to handle the CHILD SA as a nested or separate | |||
| 2628 | * transition. | |||
| 2629 | * | |||
| 2630 | * XXX: The state transition structure (microcode) is stored in (*MDP) | |||
| 2631 | * forcing that structure to be created. The fix is to store the | |||
| 2632 | * state's transition in the state. As a bonus this makes determining | |||
| 2633 | * if a state is busy really really easy - if there's a | |||
| 2634 | * state-transition then it must be. | |||
| 2635 | * | |||
| 2636 | * This routine does not free (*MDP) (using release_any_md(mdp)). | |||
| 2637 | * However, when suspending a state transition, it will save it in ST | |||
| 2638 | * and zap (*MDP) so that the caller can't free it. Hence, the caller | |||
| 2639 | * must be prepared for (*MDP) being set to NULL. | |||
| 2640 | * | |||
| 2641 | * XXX: At some point (*MDP) was being used for: | |||
| 2642 | * | |||
| 2643 | * - find st | |||
| 2644 | * - success_v2_state_transition(st, md); | |||
| 2645 | * - for svm: | |||
| 2646 | * - svm->next_state, | |||
| 2647 | * - svm->flags & SMF2_SEND, | |||
| 2648 | * - svm->timeout_event, | |||
| 2649 | * -svm->flags, story | |||
| 2650 | * - find from_state (st might be gone) | |||
| 2651 | * - ikev2_update_msgid_counters(md); | |||
| 2652 | * - nat_traversal_change_port_lookup(md, st) | |||
| 2653 | * - !(md->hdr.isa_flags & ISAKMP_FLAGS_v2_MSG_R) to gate Notify payloads/exchanges [WRONG] | |||
| 2654 | * - find note for STF_INTERNAL_ERROR | |||
| 2655 | * - find note for STF_FAIL (might not be part of result (STF_FAIL+note)) | |||
| 2656 | * | |||
| 2657 | * We don't use these but complete_v1_state_transition does: | |||
| 2658 | * - record md->event_already_set | |||
| 2659 | * - remember_received_packet(st, md); | |||
| 2660 | * - fragvid, dpd, nortel | |||
| 2661 | */ | |||
| 2662 | void complete_v2_state_transition(struct state *st, | |||
| 2663 | struct msg_digest *md, | |||
| 2664 | stf_status result) | |||
| 2665 | { | |||
| 2666 | passert(st != NULL)({ _Bool assertion__ = st != ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 2666, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_passert (logger_, here, "%s", "st != ((void*)0)"); } (void) 1; }); | |||
| ||||
| 2667 | struct ike_sa *ike = ike_sa(st, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2667, }; &here; })); | |||
| 2668 | /* struct child_sa *child = IS_CHILD_SA(st) ? pexpect_child_sa(st) : NULL; */ | |||
| 2669 | ||||
| 2670 | /* statistics */ | |||
| 2671 | /* this really depends on the type of error whether it is an IKE or IPsec fail */ | |||
| 2672 | if (result > STF_FAIL) { | |||
| 2673 | pstats(ike_stf, STF_FAIL){ const unsigned __pstat = (STF_FAIL); if (__pstat < (sizeof (pstats_ike_stf) / sizeof(*(pstats_ike_stf)))) { pstats_ike_stf [__pstat]++; } else if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { DBG_log("pstats %s %d", "ike_stf", __pstat ); } }; | |||
| 2674 | } else { | |||
| 2675 | pstats(ike_stf, result){ const unsigned __pstat = (result); if (__pstat < (sizeof (pstats_ike_stf) / sizeof(*(pstats_ike_stf)))) { pstats_ike_stf [__pstat]++; } else if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { DBG_log("pstats %s %d", "ike_stf", __pstat ); } }; | |||
| 2676 | } | |||
| 2677 | ||||
| 2678 | /* | |||
| 2679 | * Try to get the transition that is being completed ... | |||
| 2680 | * | |||
| 2681 | * For the moment this comes from the (presumably non-NULL) | |||
| 2682 | * MD.SVM. | |||
| 2683 | * | |||
| 2684 | * XXX: However, when a packet is bad and no transition is | |||
| 2685 | * selected, this code is still called: | |||
| 2686 | * | |||
| 2687 | * STF_IGNORE: to undo the v2_msgid_start_responder() call; | |||
| 2688 | * better would probably be to move that call to after a | |||
| 2689 | * transition has been found (but fragmentation makes this | |||
| 2690 | * messy). | |||
| 2691 | * | |||
| 2692 | * STF_FATAL: to discard a state in response to a bad exchange | |||
| 2693 | * (for instance a protected packet's contents are bogus). | |||
| 2694 | * | |||
| 2695 | * Long term, this value should be extracted from the state | |||
| 2696 | * and .st_v2_state_transition - it just isn't possible to | |||
| 2697 | * squeeze both the IKE and CHILD transitions into MD.ST. | |||
| 2698 | */ | |||
| 2699 | #if 0 | |||
| 2700 | const struct v2_state_transition *transition = st->st_v2_transition; | |||
| 2701 | if (!pexpect(transition != NULL)({ _Bool assertion__ = transition != ((void*)0); if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2701, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "transition != ((void*)0)" ); } assertion__; }) && md != NULL((void*)0)) { | |||
| 2702 | transition = md->svm; | |||
| 2703 | } | |||
| 2704 | #else | |||
| 2705 | const struct v2_state_transition *transition = (md != NULL((void*)0) && md->svm != NULL((void*)0) ? md->svm : | |||
| 2706 | st->st_v2_transition); | |||
| 2707 | #endif | |||
| 2708 | static const struct v2_state_transition undefined_transition = { | |||
| 2709 | .story = "suspect message", | |||
| 2710 | .state = STATE_UNDEFINED, | |||
| 2711 | .next_state = STATE_UNDEFINED, | |||
| 2712 | }; | |||
| 2713 | /* double negative */ | |||
| 2714 | if (!pexpect(transition != NULL)({ _Bool assertion__ = transition != ((void*)0); if (!assertion__ ) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2714, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_pexpect(logger_, here_, "%s", "transition != ((void*)0)" ); } assertion__; })) { | |||
| 2715 | transition = &undefined_transition; | |||
| 2716 | } | |||
| 2717 | ||||
| 2718 | LSWDBGP(DBG_BASE, buf)for (_Bool lswlog_p = (cur_debugging & (((lset_t)1 << (DBG_BASE_IX)))); lswlog_p; lswlog_p = 0) for (char lswbuf[( (size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ != ((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf = array_as_jambuf((lswbuf ), sizeof(lswbuf)), *buf = &jambuf; buf != ((void*)0); buf = ((void*)0)) for (; buf != ((void*)0); jambuf_to_logger(buf , &failsafe_logger, DEBUG_STREAM), buf = ((void*)0)) { | |||
| 2719 | const struct finite_state *transition_from = finite_states[transition->state]; | |||
| 2720 | ||||
| 2721 | jam(buf, "#%lu complete_v2_state_transition()", st->st_serialno); | |||
| 2722 | if (st->st_state != transition_from) { | |||
| 2723 | jam(buf, " in state %s", st->st_state->short_name); | |||
| 2724 | } | |||
| 2725 | jam(buf, " "); | |||
| 2726 | jam_v2_transition(buf, transition); | |||
| 2727 | jam(buf, " with status "); | |||
| 2728 | jam_v2_stf_status(buf, result); | |||
| 2729 | /* does MD.SVM diverge? */ | |||
| 2730 | if (md != NULL((void*)0) && transition != md->svm) { | |||
| 2731 | jam(buf, "; md.svm="); | |||
| 2732 | jam_v2_transition(buf, md->svm); | |||
| 2733 | } | |||
| 2734 | /* does ST.ST_V2_TRANSITION diverge? */ | |||
| 2735 | if (transition != st->st_v2_transition) { | |||
| 2736 | jam(buf, "; .st_v2_transition="); | |||
| 2737 | jam_v2_transition(buf, st->st_v2_transition); | |||
| 2738 | } | |||
| 2739 | } | |||
| 2740 | ||||
| 2741 | switch (result) { | |||
| 2742 | ||||
| 2743 | case STF_SUSPEND: | |||
| 2744 | /* | |||
| 2745 | * If this transition was triggered by an | |||
| 2746 | * incoming packet, save it. | |||
| 2747 | * | |||
| 2748 | * XXX: some initiator code creates a fake MD | |||
| 2749 | * (there isn't a real one); save that as | |||
| 2750 | * well. | |||
| 2751 | * | |||
| 2752 | * XXX: should the helper code be responsible for | |||
| 2753 | * saving an MD reference? | |||
| 2754 | */ | |||
| 2755 | suspend_any_md(st, md){ if (md != ((void*)0)) { { if ((cur_debugging & (((lset_t )1 << (DBG_BASE_IX))))) { DBG_log("suspending state #%lu and saving MD %p" , (st)->st_serialno, md); } }; ({ _Bool assertion__ = (st) ->st_suspended_md == ((void*)0); if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__ , .file = "programs/pluto/ikev2.c", .line = 2755, }; &here ; }); const struct logger *logger_ = &failsafe_logger; llog_passert (logger_, here, "%s", "(st)->st_suspended_md == ((void*)0)" ); } (void) 1; }); (st)->st_suspended_md = md_addref(md, ( { static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2755, }; &here; })); ( st)->st_suspended_md_func = __func__; (st)->st_suspended_md_line = 2755; ({ _Bool assertion__ = state_is_busy(st); if (!assertion__ ) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2755, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "state_is_busy(st)"); } ( void) 1; }); } else { { if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { DBG_log("no MD to suspend"); } }; } }; | |||
| 2756 | return; | |||
| 2757 | ||||
| 2758 | case STF_IGNORE: | |||
| 2759 | /* | |||
| 2760 | * logged above | |||
| 2761 | * | |||
| 2762 | * XXX: really? Suspect this means to say logged | |||
| 2763 | * where STF_IGNORE is returned. | |||
| 2764 | * | |||
| 2765 | * XXX: even when a packet is invalid and no | |||
| 2766 | * transition is selected (TRANSITION==NULL) this code | |||
| 2767 | * is executed - caller needs to cancel the responder | |||
| 2768 | * processing the message. | |||
| 2769 | */ | |||
| 2770 | if (v2_msg_role(md) == MESSAGE_REQUEST) { | |||
| 2771 | v2_msgid_cancel_responder(ike, st, md); | |||
| 2772 | } | |||
| 2773 | return; | |||
| 2774 | ||||
| 2775 | case STF_OK: | |||
| 2776 | /* advance the state */ | |||
| 2777 | success_v2_state_transition(st, md, transition); | |||
| 2778 | break; | |||
| 2779 | ||||
| 2780 | case STF_INTERNAL_ERROR: | |||
| 2781 | log_state(RC_INTERNALERR, st, "state transition function for %s had internal error", | |||
| 2782 | st->st_state->name); | |||
| 2783 | release_pending_whacks(st, "internal error"); | |||
| 2784 | break; | |||
| 2785 | ||||
| 2786 | case STF_V2_DELETE_IKE_AUTH_INITIATOR: | |||
| 2787 | /* | |||
| 2788 | * XXX: this is a hack so that IKE_AUTH initiator can | |||
| 2789 | * both delete the IKE SA and send an IKE SA delete | |||
| 2790 | * notification because the IKE_AUTH response was | |||
| 2791 | * rejected. | |||
| 2792 | */ | |||
| 2793 | /* | |||
| 2794 | * Initiator processing response, finish current | |||
| 2795 | * exchange ready for delete request. | |||
| 2796 | */ | |||
| 2797 | dbg("Message ID: forcing a response received update (deleting IKE_AUTH initiator)"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Message ID: forcing a response received update (deleting IKE_AUTH initiator)" ); } }; | |||
| 2798 | pexpect(st->st_state->kind == STATE_V2_PARENT_I2)({ _Bool assertion__ = st->st_state->kind == STATE_V2_PARENT_I2 ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2798, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "st->st_state->kind == STATE_V2_PARENT_I2" ); } assertion__; }); | |||
| 2799 | pexpect(v2_msg_role(md) == MESSAGE_RESPONSE)({ _Bool assertion__ = v2_msg_role(md) == MESSAGE_RESPONSE; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2799, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "v2_msg_role(md) == MESSAGE_RESPONSE" ); } assertion__; }); | |||
| 2800 | v2_msgid_update_recv(ike, &ike->sa, md); | |||
| 2801 | /* | |||
| 2802 | * All done, now delete the IKE family sending out a | |||
| 2803 | * last gasp delete. | |||
| 2804 | * | |||
| 2805 | * XXX: this call will fire and forget. It should | |||
| 2806 | * call v2_msgid_queue_initiator() with high priority | |||
| 2807 | * so this is performed as a separate transition? | |||
| 2808 | */ | |||
| 2809 | delete_ike_family(ike, DO_SEND_DELETE); | |||
| 2810 | /* get out of here -- everything is invalid */ | |||
| 2811 | ike = NULL((void*)0); | |||
| 2812 | st = NULL((void*)0); | |||
| 2813 | return; | |||
| 2814 | ||||
| 2815 | case STF_FATAL: | |||
| 2816 | /* | |||
| 2817 | * XXX: even when a packet is invalid and no | |||
| 2818 | * transition is selected (TRANSITION==NULL) this code | |||
| 2819 | * is executed - caller needs to kill the state. | |||
| 2820 | */ | |||
| 2821 | log_state(RC_FATAL, st, "encountered fatal error in state %s", | |||
| 2822 | st->st_state->name); | |||
| 2823 | switch (v2_msg_role(md)) { | |||
| 2824 | case MESSAGE_RESPONSE: | |||
| 2825 | dbg("Message ID: forcing a response received update"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Message ID: forcing a response received update" ); } }; | |||
| 2826 | v2_msgid_update_recv(ike, NULL((void*)0), md); | |||
| 2827 | break; | |||
| 2828 | case MESSAGE_REQUEST: | |||
| 2829 | dbg("Message ID: responding with recorded fatal error"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Message ID: responding with recorded fatal error" ); } }; | |||
| 2830 | pexpect(transition->send == MESSAGE_RESPONSE)({ _Bool assertion__ = transition->send == MESSAGE_RESPONSE ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2830, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->send == MESSAGE_RESPONSE" ); } assertion__; }); | |||
| 2831 | if (ike->sa.st_v2_outgoing[MESSAGE_RESPONSE] != NULL((void*)0)) { | |||
| 2832 | v2_msgid_update_recv(ike, st, md); | |||
| 2833 | v2_msgid_update_sent(ike, st, md, transition->send); | |||
| 2834 | send_recorded_v2_message(ike, "STF_FATAL", | |||
| 2835 | MESSAGE_RESPONSE); | |||
| 2836 | } else { | |||
| 2837 | dbg("Message ID: exchange zombie as no response?"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Message ID: exchange zombie as no response?") ; } }; | |||
| 2838 | } | |||
| 2839 | break; | |||
| 2840 | case NO_MESSAGE: | |||
| 2841 | break; | |||
| 2842 | } | |||
| 2843 | ||||
| 2844 | /* if this was a child fail, don't destroy the IKE SA */ | |||
| 2845 | if (IS_IKE_SA(st)((st)->st_clonedfrom == 0)) { | |||
| 2846 | delete_ike_family(ike, DONT_SEND_DELETE); | |||
| 2847 | ike = NULL((void*)0); | |||
| 2848 | } | |||
| 2849 | ||||
| 2850 | /* kill all st pointers */ | |||
| 2851 | st = NULL((void*)0); | |||
| 2852 | break; | |||
| 2853 | ||||
| 2854 | case STF_FAIL: | |||
| 2855 | log_state(RC_NOTIFICATION, st, "state transition '%s' failed", | |||
| 2856 | transition->story); | |||
| 2857 | switch (v2_msg_role(md)) { | |||
| 2858 | case MESSAGE_RESPONSE: | |||
| 2859 | v2_msgid_update_recv(ike, st, md); | |||
| 2860 | v2_msgid_schedule_next_initiator(ike); | |||
| 2861 | break; | |||
| 2862 | case MESSAGE_REQUEST: | |||
| 2863 | dbg("Message ID: responding with recorded error"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("Message ID: responding with recorded error"); } }; | |||
| 2864 | pexpect(transition->send == MESSAGE_RESPONSE)({ _Bool assertion__ = transition->send == MESSAGE_RESPONSE ; if (!assertion__) { where_t here_ = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2864, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_pexpect(logger_, here_, "%s", "transition->send == MESSAGE_RESPONSE" ); } assertion__; }); | |||
| 2865 | v2_msgid_update_recv(ike, st, md); | |||
| 2866 | v2_msgid_update_sent(ike, st, md, transition->send); | |||
| 2867 | send_recorded_v2_message(ike, "STF_FAIL", MESSAGE_RESPONSE); | |||
| 2868 | break; | |||
| 2869 | case NO_MESSAGE: | |||
| 2870 | break; | |||
| 2871 | } | |||
| 2872 | release_pending_whacks(st, "fatal error"); /* fatal != STF_FATAL :) */ | |||
| 2873 | delete_state(st); | |||
| 2874 | ||||
| 2875 | /* kill all st pointers */ | |||
| 2876 | st = NULL((void*)0); | |||
| 2877 | ike = NULL((void*)0); | |||
| 2878 | break; | |||
| 2879 | ||||
| 2880 | default: /* STF_FAIL+notification */ | |||
| 2881 | passert(result > STF_FAIL)({ _Bool assertion__ = result > STF_FAIL; if (!assertion__ ) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2881, } ; &here; }); const struct logger *logger_ = &failsafe_logger ; llog_passert(logger_, here, "%s", "result > STF_FAIL"); } (void) 1; }); | |||
| 2882 | /* | |||
| 2883 | * XXX: For IKEv2, this code path isn't sufficient - a | |||
| 2884 | * message request can result in a response that | |||
| 2885 | * contains both a success and a fail. Better to | |||
| 2886 | * record the responses and and then return | |||
| 2887 | * STF_ZOMBIFY signaling both that the message should | |||
| 2888 | * be sent and the state deleted. | |||
| 2889 | */ | |||
| 2890 | v2_notification_t notification = result - STF_FAIL; | |||
| 2891 | /* Only the responder sends a notification */ | |||
| 2892 | if (v2_msg_role(md) == MESSAGE_REQUEST) { | |||
| 2893 | dbg("sending a notification reply"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("sending a notification reply"); } }; | |||
| 2894 | v2_msgid_update_recv(ike, st, md); | |||
| 2895 | record_v2N_response(st->st_logger, ike, md, | |||
| 2896 | notification, NULL((void*)0)/*no data*/, | |||
| 2897 | ENCRYPTED_PAYLOAD); | |||
| 2898 | v2_msgid_update_sent(ike, st, md, transition->send); | |||
| 2899 | send_recorded_v2_message(ike, "STF_FAIL", | |||
| 2900 | MESSAGE_RESPONSE); | |||
| 2901 | /* | |||
| 2902 | * XXX: is this always false; if true above | |||
| 2903 | * record would pexpect()? | |||
| 2904 | */ | |||
| 2905 | if (md->hdr.isa_xchg == ISAKMP_v2_IKE_SA_INIT) { | |||
| ||||
| 2906 | delete_state(st); | |||
| 2907 | /* kill all st pointers */ | |||
| 2908 | st = NULL((void*)0); ike = NULL((void*)0); | |||
| 2909 | } else { | |||
| 2910 | dbg("forcing #%lu to a discard event",{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("forcing #%lu to a discard event", st->st_serialno ); } } | |||
| 2911 | st->st_serialno){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("forcing #%lu to a discard event", st->st_serialno ); } }; | |||
| 2912 | delete_event(st); | |||
| 2913 | event_schedule(EVENT_SA_DISCARD, | |||
| 2914 | MAXIMUM_RESPONDER_WAIT_DELAYdeltatime(200), | |||
| 2915 | st); | |||
| 2916 | } | |||
| 2917 | } else { | |||
| 2918 | log_state(RC_NOTIFICATION+notification, st, | |||
| 2919 | "state transition '%s' failed with %s", | |||
| 2920 | transition->story, enum_name(&ikev2_notify_names, notification)); | |||
| 2921 | } | |||
| 2922 | break; | |||
| 2923 | } | |||
| 2924 | } | |||
| 2925 | ||||
| 2926 | void jam_v2_stf_status(struct jambuf *buf, unsigned status) | |||
| 2927 | { | |||
| 2928 | if (status <= STF_FAIL) { | |||
| 2929 | jam_enum(buf, &stf_status_names, status); | |||
| 2930 | } else { | |||
| 2931 | jam(buf, "STF_FAIL+"); | |||
| 2932 | jam_enum(buf, &ikev2_notify_names, status - STF_FAIL); | |||
| 2933 | } | |||
| 2934 | } | |||
| 2935 | ||||
| 2936 | static void reinitiate_ike_sa_init(struct state *st, void *arg) | |||
| 2937 | { | |||
| 2938 | if (st == NULL((void*)0)) { | |||
| 2939 | dbg("re-initiate lost state"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("re-initiate lost state"); } }; | |||
| 2940 | return; | |||
| 2941 | } | |||
| 2942 | struct ike_sa *ike = ike_sa(st, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2942, }; &here; })); | |||
| 2943 | if (ike == NULL((void*)0)) { | |||
| 2944 | /* already logged */ | |||
| 2945 | return; | |||
| 2946 | } | |||
| 2947 | stf_status (*resume)(struct ike_sa *ike) = arg; | |||
| 2948 | ||||
| 2949 | /* | |||
| 2950 | * Need to wind back the Message ID counters so that the send | |||
| 2951 | * code things it is creating Message 0. | |||
| 2952 | */ | |||
| 2953 | v2_msgid_init_ike(ike); | |||
| 2954 | ||||
| 2955 | /* | |||
| 2956 | * Pretend to be running the initiate state. | |||
| 2957 | */ | |||
| 2958 | set_v2_transition(&ike->sa, finite_states[STATE_V2_PARENT_I0]->v2_transitions, HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2958, }; &here; })); /* first */ | |||
| 2959 | complete_v2_state_transition(&ike->sa, NULL((void*)0)/*no-MD*/, resume(ike)); | |||
| 2960 | } | |||
| 2961 | ||||
| 2962 | void schedule_reinitiate_v2_ike_sa_init(struct ike_sa *ike, | |||
| 2963 | stf_status (*resume)(struct ike_sa *ike)) | |||
| 2964 | { | |||
| 2965 | schedule_callback("reinitiating IKE_SA_INIT", ike->sa.st_serialno, | |||
| 2966 | reinitiate_ike_sa_init, resume); | |||
| 2967 | } | |||
| 2968 | ||||
| 2969 | bool_Bool v2_notification_fatal(v2_notification_t n) | |||
| 2970 | { | |||
| 2971 | return (n == v2N_INVALID_SYNTAX || | |||
| 2972 | n == v2N_AUTHENTICATION_FAILED || | |||
| 2973 | n == v2N_UNSUPPORTED_CRITICAL_PAYLOAD); | |||
| 2974 | } | |||
| 2975 | ||||
| 2976 | stf_status stf_status_from_v2_notification(v2_notification_t n) | |||
| 2977 | { | |||
| 2978 | return (n == v2N_NOTHING_WRONG ? STF_OK : | |||
| 2979 | v2_notification_fatal(n) ? STF_FATAL : | |||
| 2980 | STF_FAIL); | |||
| 2981 | } | |||
| 2982 | ||||
| 2983 | bool_Bool already_has_larval_v2_child(struct ike_sa *ike, const struct connection *c) | |||
| 2984 | { | |||
| 2985 | const lset_t pending_states = (LELEM(STATE_V2_NEW_CHILD_I1)((lset_t)1 << (STATE_V2_NEW_CHILD_I1)) | | |||
| 2986 | LELEM(STATE_V2_NEW_CHILD_I0)((lset_t)1 << (STATE_V2_NEW_CHILD_I0)) | | |||
| 2987 | LELEM(STATE_V2_NEW_CHILD_R0)((lset_t)1 << (STATE_V2_NEW_CHILD_R0))); | |||
| 2988 | ||||
| 2989 | struct state_query query = { | |||
| 2990 | .where = HERE({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2.c", .line = 2990, }; &here; }), | |||
| 2991 | .ike_version = IKEv2, | |||
| 2992 | .ike_spis = &ike->sa.st_ike_spis, | |||
| 2993 | /* only children */ | |||
| 2994 | .ike = ike, | |||
| 2995 | }; | |||
| 2996 | ||||
| 2997 | while (old2new_state(&query)) { | |||
| 2998 | struct state *st = query.st; | |||
| 2999 | ||||
| 3000 | /* larval child state? */ | |||
| 3001 | if (!LHAS(pending_states, st->st_state->kind)(((pending_states) & ((lset_t)1 << (st->st_state ->kind))) != ((lset_t)0))) { | |||
| 3002 | continue; | |||
| 3003 | } | |||
| 3004 | /* not an instance, but a connection? */ | |||
| 3005 | if (!streq(st->st_connection->name, c->name)(strcmp((st->st_connection->name), (c->name)) == 0)) { | |||
| 3006 | continue; | |||
| 3007 | } | |||
| 3008 | llog(RC_LOG, c->logger, "connection already has the pending Child SA negotiation #%lu using IKE SA #%lu", | |||
| 3009 | st->st_serialno, ike->sa.st_serialno); | |||
| 3010 | return true1; | |||
| 3011 | } | |||
| 3012 | ||||
| 3013 | return false0; | |||
| 3014 | } |