1 /* $NetBSD: isakmp_frag.c,v 1.12 2025/03/08 16:39:08 christos Exp $ */ 2 3 /* Id: isakmp_frag.c,v 1.4 2004/11/13 17:31:36 manubsd Exp */ 4 5 /* 6 * Copyright (C) 2004 Emmanuel Dreyfus 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the project nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "config.h" 35 36 #include <sys/types.h> 37 #include <sys/param.h> 38 #include <sys/socket.h> 39 #include <sys/queue.h> 40 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 44 #include <openssl/md5.h> 45 46 #include <stdlib.h> 47 #include <stdio.h> 48 #include <fcntl.h> 49 #include <string.h> 50 #include <errno.h> 51 #if TIME_WITH_SYS_TIME 52 # include <sys/time.h> 53 # include <time.h> 54 #else 55 # if HAVE_SYS_TIME_H 56 # include <sys/time.h> 57 # else 58 # include <time.h> 59 # endif 60 #endif 61 #include <netdb.h> 62 #ifdef HAVE_UNISTD_H 63 #include <unistd.h> 64 #endif 65 #include <ctype.h> 66 67 #include "var.h" 68 #include "misc.h" 69 #include "vmbuf.h" 70 #include "plog.h" 71 #include "sockmisc.h" 72 #include "schedule.h" 73 #include "debug.h" 74 75 #include "isakmp_var.h" 76 #include "isakmp.h" 77 #include "handler.h" 78 #include "isakmp_frag.h" 79 #include "strnames.h" 80 81 int 82 isakmp_sendfrags(struct ph1handle *iph1, vchar_t *buf) 83 { 84 struct isakmp *hdr; 85 struct isakmp_frag *fraghdr; 86 caddr_t data; 87 caddr_t sdata; 88 size_t datalen; 89 size_t max_datalen; 90 size_t fraglen; 91 vchar_t *frag; 92 unsigned int fragnum = 0; 93 size_t len; 94 int etype; 95 96 /* 97 * Catch the exchange type for later: the fragments and the 98 * fragmented packet must have the same exchange type. 99 */ 100 hdr = (struct isakmp *)buf->v; 101 etype = hdr->etype; 102 103 /* 104 * We want to send a a packet smaller than ISAKMP_FRAG_MAXLEN 105 * First compute the maximum data length that will fit in it 106 */ 107 max_datalen = ISAKMP_FRAG_MAXLEN - 108 (sizeof(*hdr) + sizeof(*fraghdr) + sizeof(unsigned int)); 109 110 sdata = buf->v; 111 len = buf->l; 112 113 while (len > 0) { 114 fragnum++; 115 116 if (len > max_datalen) 117 datalen = max_datalen; 118 else 119 datalen = len; 120 121 fraglen = sizeof(*hdr) 122 + sizeof(*fraghdr) 123 + datalen; 124 125 if ((frag = vmalloc(fraglen)) == NULL) { 126 plog(LLV_ERROR, LOCATION, NULL, 127 "Cannot allocate memory\n"); 128 return -1; 129 } 130 131 set_isakmp_header1(frag, iph1, ISAKMP_NPTYPE_FRAG); 132 hdr = (struct isakmp *)frag->v; 133 hdr->etype = etype; 134 135 fraghdr = (struct isakmp_frag *)(hdr + 1); 136 fraghdr->unknown0 = htons(0); 137 fraghdr->len = htons(fraglen - sizeof(*hdr)); 138 fraghdr->unknown1 = htons(1); 139 fraghdr->index = fragnum; 140 if (len == datalen) 141 fraghdr->flags = ISAKMP_FRAG_LAST; 142 else 143 fraghdr->flags = 0; 144 145 data = (caddr_t)(fraghdr + 1); 146 memcpy(data, sdata, datalen); 147 148 if (isakmp_send(iph1, frag) < 0) { 149 plog(LLV_ERROR, LOCATION, NULL, "isakmp_send failed\n"); 150 return -1; 151 } 152 153 vfree(frag); 154 155 len -= datalen; 156 sdata += datalen; 157 } 158 159 return fragnum; 160 } 161 162 unsigned int 163 vendorid_frag_cap(struct isakmp_gen *gen) 164 { 165 int *hp; 166 167 hp = (int *)(gen + 1); 168 169 return ntohl(hp[MD5_DIGEST_LENGTH / sizeof(*hp)]); 170 } 171 172 static int 173 isakmp_frag_insert(struct ph1handle *iph1, struct isakmp_frag_item *item) 174 { 175 struct isakmp_frag_item *pitem = NULL; 176 struct isakmp_frag_item *citem = iph1->frag_chain; 177 178 /* no frag yet, just insert at beginning of list */ 179 if (iph1->frag_chain == NULL) { 180 iph1->frag_chain = item; 181 return 0; 182 } 183 184 do { 185 /* duplicate fragment number, abort (CVE-2016-10396) */ 186 if (citem->frag_num == item->frag_num) 187 return -1; 188 189 /* need to insert before current item */ 190 if (citem->frag_num > item->frag_num) { 191 if (pitem != NULL) 192 pitem->frag_next = item; 193 else 194 /* insert at the beginning of the list */ 195 iph1->frag_chain = item; 196 item->frag_next = citem; 197 return 0; 198 } 199 200 pitem = citem; 201 citem = citem->frag_next; 202 } while (citem != NULL); 203 204 /* we reached the end of the list, insert */ 205 pitem->frag_next = item; 206 return 0; 207 } 208 209 int 210 isakmp_frag_extract(struct ph1handle *iph1, vchar_t *msg) 211 { 212 struct isakmp *isakmp; 213 struct isakmp_frag *frag; 214 struct isakmp_frag_item *item; 215 vchar_t *buf; 216 const char *m; 217 char *data; 218 int i; 219 220 if (iph1->frag_chain == NULL) { 221 plog(LLV_DEBUG, LOCATION, NULL, 222 "fragmented IKE phase 1 message payload detected\n"); 223 } 224 225 if (msg->l < sizeof(*isakmp) + sizeof(*frag)) { 226 plog(LLV_ERROR, LOCATION, NULL, "Message too short\n"); 227 return -1; 228 } 229 230 isakmp = (struct isakmp *)msg->v; 231 frag = (struct isakmp_frag *)(isakmp + 1); 232 233 /* 234 * frag->len is the frag payload data plus the frag payload header, 235 * whose size is sizeof(*frag) 236 */ 237 if (msg->l < sizeof(*isakmp) + ntohs(frag->len) || 238 ntohs(frag->len) < sizeof(*frag) + 1) { 239 plog(LLV_ERROR, LOCATION, NULL, "Fragment too short\n"); 240 return -1; 241 } 242 243 if ((buf = vmalloc(ntohs(frag->len) - sizeof(*frag))) == NULL) { 244 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 245 return -1; 246 } 247 248 if ((item = racoon_malloc(sizeof(*item))) == NULL) { 249 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 250 vfree(buf); 251 return -1; 252 } 253 254 data = (char *)(frag + 1); 255 memcpy(buf->v, data, buf->l); 256 257 item->frag_num = frag->index; 258 item->frag_last = (frag->flags & ISAKMP_FRAG_LAST); 259 item->frag_next = NULL; 260 item->frag_packet = buf; 261 262 263 /* Perform required last frag checks before inserting the new item in 264 the chain */ 265 if (iph1->frag_last_index != 0) { 266 /* Only one fragment payload allowed with last frag flag set */ 267 if (item->frag_last) { 268 m = "Message has multiple tail fragments\n"; 269 goto out; 270 } 271 272 /* Fragment payload with fragment number greater than the 273 fragment number of the last fragment is not allowed*/ 274 if (item->frag_num > iph1->frag_last_index) { 275 m = "Fragment number greater than tail fragment number\n"; 276 goto out; 277 } 278 } 279 280 /* insert fragment into chain */ 281 if (isakmp_frag_insert(iph1, item) == -1) { 282 m = "Duplicate fragment number\n"; 283 goto out; 284 } 285 286 plog(LLV_DEBUG, LOCATION, NULL, 287 "fragment payload #%d queued\n", item->frag_num); 288 289 /* remember last frag after insertion into fragment chain */ 290 if (item->frag_last) 291 iph1->frag_last_index = item->frag_num; 292 293 /* If we saw the last frag, check if the chain is complete 294 * we have a sorted list now, so just walk through */ 295 if (iph1->frag_last_index != 0) { 296 item = iph1->frag_chain; 297 for (i = 1; i <= iph1->frag_last_index; i++) { 298 if (item == NULL || 299 item->frag_num != i) { 300 plog(LLV_DEBUG, LOCATION, NULL, 301 "fragment payload #%d still missing\n", 302 i); 303 break; 304 } 305 item = item->frag_next; 306 } 307 308 if (i > iph1->frag_last_index) {/* It is complete */ 309 plog(LLV_DEBUG, LOCATION, NULL, 310 "fragment #%d completed IKE phase 1 message payload.\n", 311 frag->index); 312 return 1; 313 } 314 } 315 316 return 0; 317 out: 318 plog(LLV_ERROR, LOCATION, NULL, "%s", m); 319 racoon_free(item); 320 vfree(buf); 321 return -1; 322 } 323 324 vchar_t * 325 isakmp_frag_reassembly(struct ph1handle *iph1) 326 { 327 struct isakmp_frag_item *item; 328 size_t len = 0; 329 vchar_t *buf = NULL; 330 int frag_count = 0; 331 int i; 332 char *data; 333 334 if ((item = iph1->frag_chain) == NULL) { 335 plog(LLV_ERROR, LOCATION, NULL, "No fragment to reassemble\n"); 336 goto out; 337 } 338 339 do { 340 frag_count++; 341 len += item->frag_packet->l; 342 item = item->frag_next; 343 } while (item != NULL); 344 345 if ((buf = vmalloc(len)) == NULL) { 346 plog(LLV_ERROR, LOCATION, NULL, "Cannot allocate memory\n"); 347 goto out; 348 } 349 data = buf->v; 350 351 item = iph1->frag_chain; 352 for (i = 1; i <= frag_count; i++) { 353 if (item->frag_num != i) { 354 plog(LLV_ERROR, LOCATION, NULL, 355 "Missing fragment #%d\n", i); 356 vfree(buf); 357 buf = NULL; 358 goto out; 359 } 360 memcpy(data, item->frag_packet->v, item->frag_packet->l); 361 data += item->frag_packet->l; 362 item = item->frag_next; 363 } 364 365 out: 366 item = iph1->frag_chain; 367 do { 368 struct isakmp_frag_item *next_item; 369 370 next_item = item->frag_next; 371 372 vfree(item->frag_packet); 373 racoon_free(item); 374 375 item = next_item; 376 } while (item != NULL); 377 378 iph1->frag_chain = NULL; 379 iph1->frag_last_index = 0; 380 381 return buf; 382 } 383 384 vchar_t * 385 isakmp_frag_addcap(vchar_t *buf, int cap) 386 { 387 int *capp; 388 size_t len; 389 390 /* If the capability has not been added, add room now */ 391 len = buf->l; 392 if (len == MD5_DIGEST_LENGTH) { 393 if ((buf = vrealloc(buf, len + sizeof(cap))) == NULL) { 394 plog(LLV_ERROR, LOCATION, NULL, 395 "Cannot allocate memory\n"); 396 return NULL; 397 } 398 capp = (int *)(buf->v + len); 399 *capp = htonl(0); 400 } 401 402 capp = (int *)(buf->v + MD5_DIGEST_LENGTH); 403 *capp |= htonl(cap); 404 405 return buf; 406 } 407 408