]>
Commit | Line | Data |
---|---|---|
ac2f15b3 | 1 | /* $KAME: isakmp_base.c,v 1.48 2001/12/12 15:29:13 sakane Exp $ */ |
7ba0088d A |
2 | |
3 | /* | |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
5 | * All rights reserved. | |
6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the project nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | |
18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | |
30 | */ | |
31 | ||
32 | /* Base Exchange (Base Mode) */ | |
33 | ||
34 | #include <sys/types.h> | |
35 | #include <sys/param.h> | |
36 | ||
37 | #include <stdlib.h> | |
38 | #include <stdio.h> | |
39 | #include <string.h> | |
40 | #include <errno.h> | |
41 | #if TIME_WITH_SYS_TIME | |
42 | # include <sys/time.h> | |
43 | # include <time.h> | |
44 | #else | |
45 | # if HAVE_SYS_TIME_H | |
46 | # include <sys/time.h> | |
47 | # else | |
48 | # include <time.h> | |
49 | # endif | |
50 | #endif | |
51 | ||
52 | #include "var.h" | |
53 | #include "misc.h" | |
54 | #include "vmbuf.h" | |
55 | #include "plog.h" | |
56 | #include "sockmisc.h" | |
57 | #include "schedule.h" | |
58 | #include "debug.h" | |
59 | ||
60 | #include "localconf.h" | |
61 | #include "remoteconf.h" | |
62 | #include "isakmp_var.h" | |
63 | #include "isakmp.h" | |
64 | #include "oakley.h" | |
65 | #include "handler.h" | |
66 | #include "ipsec_doi.h" | |
67 | #include "crypto_openssl.h" | |
68 | #include "pfkey.h" | |
69 | #include "isakmp_base.h" | |
70 | #include "isakmp_inf.h" | |
71 | #include "vendorid.h" | |
72 | ||
73 | /* %%% | |
74 | * begin Identity Protection Mode as initiator. | |
75 | */ | |
76 | /* | |
77 | * send to responder | |
78 | * psk: HDR, SA, Idii, Ni_b | |
79 | * sig: HDR, SA, Idii, Ni_b | |
80 | * rsa: HDR, SA, [HASH(1),] <IDii_b>Pubkey_r, <Ni_b>Pubkey_r | |
81 | * rev: HDR, SA, [HASH(1),] <Ni_b>Pubkey_r, <IDii_b>Ke_i | |
82 | */ | |
83 | int | |
84 | base_i1send(iph1, msg) | |
85 | struct ph1handle *iph1; | |
86 | vchar_t *msg; /* must be null */ | |
87 | { | |
88 | struct isakmp_gen *gen; | |
89 | caddr_t p; | |
90 | int tlen; | |
91 | int error = -1; | |
92 | ||
93 | /* validity check */ | |
94 | if (msg != NULL) { | |
95 | plog(LLV_ERROR, LOCATION, NULL, | |
96 | "msg has to be NULL in this function.\n"); | |
97 | goto end; | |
98 | } | |
99 | if (iph1->status != PHASE1ST_START) { | |
100 | plog(LLV_ERROR, LOCATION, NULL, | |
101 | "status mismatched %d.\n", iph1->status); | |
102 | goto end; | |
103 | } | |
104 | ||
105 | /* create isakmp index */ | |
106 | memset(&iph1->index, 0, sizeof(iph1->index)); | |
107 | isakmp_newcookie((caddr_t)&iph1->index, iph1->remote, iph1->local); | |
108 | ||
109 | /* make ID payload into isakmp status */ | |
110 | if (ipsecdoi_setid1(iph1) < 0) | |
111 | goto end; | |
112 | ||
113 | /* create SA payload for my proposal */ | |
114 | iph1->sa = ipsecdoi_setph1proposal(iph1->rmconf->proposal); | |
115 | if (iph1->sa == NULL) | |
116 | goto end; | |
117 | ||
118 | /* generate NONCE value */ | |
119 | iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); | |
120 | if (iph1->nonce == NULL) | |
121 | goto end; | |
122 | ||
123 | /* create buffer to send isakmp payload */ | |
124 | tlen = sizeof(struct isakmp) | |
125 | + sizeof(*gen) + iph1->sa->l | |
126 | + sizeof(*gen) + iph1->id->l | |
127 | + sizeof(*gen) + iph1->nonce->l; | |
128 | ||
129 | iph1->sendbuf = vmalloc(tlen); | |
130 | if (iph1->sendbuf == NULL) { | |
131 | plog(LLV_ERROR, LOCATION, NULL, | |
132 | "failed to get buffer to send.\n"); | |
133 | goto end; | |
134 | } | |
135 | ||
136 | /* set isakmp header */ | |
137 | p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); | |
138 | if (p == NULL) | |
139 | goto end; | |
140 | ||
141 | /* set SA payload to propose */ | |
142 | p = set_isakmp_payload(p, iph1->sa, ISAKMP_NPTYPE_ID); | |
143 | ||
144 | /* create isakmp ID payload */ | |
145 | p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_NONCE); | |
146 | ||
147 | /* create isakmp NONCE payload */ | |
148 | p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_NONE); | |
149 | ||
150 | #ifdef HAVE_PRINT_ISAKMP_C | |
151 | isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); | |
152 | #endif | |
153 | ||
154 | /* send the packet, add to the schedule to resend */ | |
155 | iph1->retry_counter = iph1->rmconf->retry_counter; | |
156 | if (isakmp_ph1resend(iph1) == -1) | |
157 | goto end; | |
158 | ||
159 | iph1->status = PHASE1ST_MSG1SENT; | |
160 | ||
161 | error = 0; | |
162 | ||
163 | end: | |
164 | ||
165 | return error; | |
166 | } | |
167 | ||
168 | /* | |
169 | * receive from responder | |
170 | * psk: HDR, SA, Idir, Nr_b | |
171 | * sig: HDR, SA, Idir, Nr_b, [ CR ] | |
172 | * rsa: HDR, SA, <IDir_b>PubKey_i, <Nr_b>PubKey_i | |
173 | * rev: HDR, SA, <Nr_b>PubKey_i, <IDir_b>Ke_r | |
174 | */ | |
175 | int | |
176 | base_i2recv(iph1, msg) | |
177 | struct ph1handle *iph1; | |
178 | vchar_t *msg; | |
179 | { | |
180 | vchar_t *pbuf = NULL; | |
181 | struct isakmp_parse_t *pa; | |
182 | vchar_t *satmp = NULL; | |
183 | int error = -1; | |
184 | ||
185 | /* validity check */ | |
186 | if (iph1->status != PHASE1ST_MSG1SENT) { | |
187 | plog(LLV_ERROR, LOCATION, NULL, | |
188 | "status mismatched %d.\n", iph1->status); | |
189 | goto end; | |
190 | } | |
191 | ||
192 | /* validate the type of next payload */ | |
193 | pbuf = isakmp_parse(msg); | |
194 | if (pbuf == NULL) | |
195 | goto end; | |
196 | pa = (struct isakmp_parse_t *)pbuf->v; | |
197 | ||
198 | /* SA payload is fixed postion */ | |
199 | if (pa->type != ISAKMP_NPTYPE_SA) { | |
200 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
201 | "received invalid next payload type %d, " | |
202 | "expecting %d.\n", | |
203 | pa->type, ISAKMP_NPTYPE_SA); | |
204 | goto end; | |
205 | } | |
206 | if (isakmp_p2ph(&satmp, pa->ptr) < 0) | |
207 | goto end; | |
208 | pa++; | |
209 | ||
210 | for (/*nothing*/; | |
211 | pa->type != ISAKMP_NPTYPE_NONE; | |
212 | pa++) { | |
213 | ||
214 | switch (pa->type) { | |
215 | case ISAKMP_NPTYPE_NONCE: | |
216 | if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) | |
217 | goto end; | |
218 | break; | |
219 | case ISAKMP_NPTYPE_ID: | |
220 | if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) | |
221 | goto end; | |
222 | break; | |
223 | case ISAKMP_NPTYPE_VID: | |
224 | (void)check_vendorid(pa->ptr); | |
225 | break; | |
226 | default: | |
227 | /* don't send information, see ident_r1recv() */ | |
228 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
229 | "ignore the packet, " | |
230 | "received unexpecting payload type %d.\n", | |
231 | pa->type); | |
232 | goto end; | |
233 | } | |
234 | } | |
235 | ||
236 | if (iph1->nonce_p == NULL || iph1->id_p == NULL) { | |
237 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
238 | "few isakmp message received.\n"); | |
239 | goto end; | |
240 | } | |
241 | ||
242 | /* verify identifier */ | |
243 | if (ipsecdoi_checkid1(iph1) != 0) { | |
244 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
245 | "invalid ID payload.\n"); | |
246 | goto end; | |
247 | } | |
248 | ||
249 | /* check SA payload and set approval SA for use */ | |
250 | if (ipsecdoi_checkph1proposal(satmp, iph1) < 0) { | |
251 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
252 | "failed to get valid proposal.\n"); | |
253 | /* XXX send information */ | |
254 | goto end; | |
255 | } | |
256 | if (iph1->sa_ret) { | |
257 | vfree(iph1->sa_ret); | |
258 | iph1->sa_ret = NULL; | |
259 | } | |
260 | ||
261 | iph1->status = PHASE1ST_MSG2RECEIVED; | |
262 | ||
263 | error = 0; | |
264 | ||
265 | end: | |
266 | if (pbuf) | |
267 | vfree(pbuf); | |
268 | if (satmp) | |
269 | vfree(satmp); | |
270 | ||
271 | if (error) { | |
272 | VPTRINIT(iph1->nonce_p); | |
273 | VPTRINIT(iph1->id_p); | |
274 | } | |
275 | ||
276 | return error; | |
277 | } | |
278 | ||
279 | /* | |
280 | * send to responder | |
281 | * psk: HDR, KE, HASH_I | |
282 | * sig: HDR, KE, [ CR, ] [CERT,] SIG_I | |
283 | * rsa: HDR, KE, HASH_I | |
284 | * rev: HDR, <KE>Ke_i, HASH_I | |
285 | */ | |
286 | int | |
287 | base_i2send(iph1, msg) | |
288 | struct ph1handle *iph1; | |
289 | vchar_t *msg; | |
290 | { | |
291 | struct isakmp_gen *gen; | |
292 | caddr_t p; | |
293 | vchar_t *vid = NULL; | |
294 | int tlen; | |
295 | int need_cert = 0; | |
296 | int error = -1; | |
297 | ||
298 | /* validity check */ | |
299 | if (iph1->status != PHASE1ST_MSG2RECEIVED) { | |
300 | plog(LLV_ERROR, LOCATION, NULL, | |
301 | "status mismatched %d.\n", iph1->status); | |
302 | goto end; | |
303 | } | |
304 | ||
305 | /* fix isakmp index */ | |
306 | memcpy(&iph1->index.r_ck, &((struct isakmp *)msg->v)->r_ck, | |
307 | sizeof(cookie_t)); | |
308 | ||
309 | /* generate DH public value */ | |
310 | if (oakley_dh_generate(iph1->approval->dhgrp, | |
311 | &iph1->dhpub, &iph1->dhpriv) < 0) | |
312 | goto end; | |
313 | ||
314 | /* generate SKEYID to compute hash if not signature mode */ | |
315 | if (iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_RSASIG | |
316 | && iph1->approval->authmethod != OAKLEY_ATTR_AUTH_METHOD_DSSSIG) { | |
317 | if (oakley_skeyid(iph1) < 0) | |
318 | goto end; | |
319 | } | |
320 | ||
321 | /* generate HASH to send */ | |
322 | plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); | |
323 | iph1->hash = oakley_ph1hash_base_i(iph1, GENERATE); | |
324 | if (iph1->hash == NULL) | |
325 | goto end; | |
326 | ||
327 | /* create buffer to send isakmp payload */ | |
328 | tlen = sizeof(struct isakmp); | |
329 | ||
330 | switch (iph1->approval->authmethod) { | |
331 | case OAKLEY_ATTR_AUTH_METHOD_PSKEY: | |
332 | tlen += sizeof(*gen) + iph1->dhpub->l | |
333 | + sizeof(*gen) + iph1->hash->l; | |
334 | if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) | |
335 | tlen += sizeof(*gen) + vid->l; | |
336 | ||
337 | iph1->sendbuf = vmalloc(tlen); | |
338 | if (iph1->sendbuf == NULL) { | |
339 | plog(LLV_ERROR, LOCATION, NULL, | |
340 | "failed to get buffer to send.\n"); | |
341 | goto end; | |
342 | } | |
343 | ||
344 | /* set isakmp header */ | |
345 | p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); | |
346 | if (p == NULL) | |
347 | goto end; | |
348 | ||
349 | /* create isakmp KE payload */ | |
350 | p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_HASH); | |
351 | ||
352 | /* create isakmp HASH payload */ | |
353 | p = set_isakmp_payload(p, iph1->hash, | |
354 | vid ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE); | |
355 | ||
356 | /* append vendor id, if needed */ | |
357 | if (vid) | |
358 | p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE); | |
359 | break; | |
360 | #ifdef HAVE_SIGNING_C | |
361 | case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: | |
362 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: | |
363 | /* XXX if there is CR or not ? */ | |
364 | ||
365 | if (oakley_getmycert(iph1) < 0) | |
366 | goto end; | |
367 | ||
368 | if (oakley_getsign(iph1) < 0) | |
369 | goto end; | |
370 | ||
371 | if (iph1->cert && iph1->rmconf->send_cert) | |
372 | need_cert = 1; | |
373 | ||
374 | tlen += sizeof(*gen) + iph1->dhpub->l | |
375 | + sizeof(*gen) + iph1->sig->l; | |
376 | if (need_cert) | |
377 | tlen += sizeof(*gen) + iph1->cert->pl->l; | |
378 | ||
379 | iph1->sendbuf = vmalloc(tlen); | |
380 | if (iph1->sendbuf == NULL) { | |
381 | plog(LLV_ERROR, LOCATION, NULL, | |
382 | "failed to get buffer to send.\n"); | |
383 | goto end; | |
384 | } | |
385 | ||
386 | /* set isakmp header */ | |
387 | p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); | |
388 | if (p == NULL) | |
389 | goto end; | |
390 | ||
391 | /* create isakmp KE payload */ | |
392 | p = set_isakmp_payload(p, iph1->dhpub, need_cert | |
393 | ? ISAKMP_NPTYPE_CERT | |
394 | : ISAKMP_NPTYPE_SIG); | |
395 | ||
396 | /* add CERT payload if there */ | |
397 | if (need_cert) | |
398 | p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); | |
399 | /* add SIG payload */ | |
400 | p = set_isakmp_payload(p, iph1->sig, ISAKMP_NPTYPE_NONE); | |
401 | break; | |
402 | #endif | |
403 | case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: | |
404 | /* ... */ | |
405 | break; | |
406 | case OAKLEY_ATTR_AUTH_METHOD_RSAENC: | |
407 | case OAKLEY_ATTR_AUTH_METHOD_RSAREV: | |
408 | tlen += sizeof(*gen) + iph1->hash->l; | |
409 | break; | |
410 | } | |
411 | ||
412 | #ifdef HAVE_PRINT_ISAKMP_C | |
413 | isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); | |
414 | #endif | |
415 | ||
416 | /* send the packet, add to the schedule to resend */ | |
417 | iph1->retry_counter = iph1->rmconf->retry_counter; | |
418 | if (isakmp_ph1resend(iph1) == -1) | |
419 | goto end; | |
420 | ||
421 | /* the sending message is added to the received-list. */ | |
422 | if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { | |
423 | plog(LLV_ERROR , LOCATION, NULL, | |
424 | "failed to add a response packet to the tree.\n"); | |
425 | goto end; | |
426 | } | |
427 | ||
428 | iph1->status = PHASE1ST_MSG2SENT; | |
429 | ||
430 | error = 0; | |
431 | ||
432 | end: | |
433 | if (vid) | |
434 | vfree(vid); | |
435 | return error; | |
436 | } | |
437 | ||
438 | /* | |
439 | * receive from responder | |
440 | * psk: HDR, KE, HASH_R | |
441 | * sig: HDR, KE, [CERT,] SIG_R | |
442 | * rsa: HDR, KE, HASH_R | |
443 | * rev: HDR, <KE>_Ke_r, HASH_R | |
444 | */ | |
445 | int | |
446 | base_i3recv(iph1, msg) | |
447 | struct ph1handle *iph1; | |
448 | vchar_t *msg; | |
449 | { | |
450 | vchar_t *pbuf = NULL; | |
451 | struct isakmp_parse_t *pa; | |
452 | int error = -1; | |
453 | ||
454 | /* validity check */ | |
455 | if (iph1->status != PHASE1ST_MSG2SENT) { | |
456 | plog(LLV_ERROR, LOCATION, NULL, | |
457 | "status mismatched %d.\n", iph1->status); | |
458 | goto end; | |
459 | } | |
460 | ||
461 | /* validate the type of next payload */ | |
462 | pbuf = isakmp_parse(msg); | |
463 | if (pbuf == NULL) | |
464 | goto end; | |
465 | ||
466 | for (pa = (struct isakmp_parse_t *)pbuf->v; | |
467 | pa->type != ISAKMP_NPTYPE_NONE; | |
468 | pa++) { | |
469 | ||
470 | switch (pa->type) { | |
471 | case ISAKMP_NPTYPE_KE: | |
472 | if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) | |
473 | goto end; | |
474 | break; | |
475 | case ISAKMP_NPTYPE_HASH: | |
476 | iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; | |
477 | break; | |
478 | #ifdef HAVE_SIGNING_C | |
479 | case ISAKMP_NPTYPE_CERT: | |
480 | if (oakley_savecert(iph1, pa->ptr) < 0) | |
481 | goto end; | |
482 | break; | |
483 | case ISAKMP_NPTYPE_SIG: | |
484 | if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) | |
485 | goto end; | |
486 | break; | |
487 | #endif | |
488 | case ISAKMP_NPTYPE_VID: | |
489 | (void)check_vendorid(pa->ptr); | |
490 | break; | |
491 | default: | |
492 | /* don't send information, see ident_r1recv() */ | |
493 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
494 | "ignore the packet, " | |
495 | "received unexpecting payload type %d.\n", | |
496 | pa->type); | |
497 | goto end; | |
498 | } | |
499 | } | |
500 | ||
501 | /* payload existency check */ | |
502 | /* validate authentication value */ | |
503 | { | |
504 | int type; | |
505 | type = oakley_validate_auth(iph1); | |
506 | if (type != 0) { | |
507 | if (type == -1) { | |
508 | /* message printed inner oakley_validate_auth() */ | |
509 | goto end; | |
510 | } | |
511 | isakmp_info_send_n1(iph1, type, NULL); | |
512 | goto end; | |
513 | } | |
514 | } | |
515 | ||
516 | /* compute sharing secret of DH */ | |
517 | if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, | |
518 | iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) | |
519 | goto end; | |
520 | ||
521 | /* generate SKEYID to compute hash if signature mode */ | |
522 | if (iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_RSASIG | |
523 | || iph1->approval->authmethod == OAKLEY_ATTR_AUTH_METHOD_DSSSIG) { | |
524 | if (oakley_skeyid(iph1) < 0) | |
525 | goto end; | |
526 | } | |
527 | ||
528 | /* generate SKEYIDs & IV & final cipher key */ | |
529 | if (oakley_skeyid_dae(iph1) < 0) | |
530 | goto end; | |
531 | if (oakley_compute_enckey(iph1) < 0) | |
532 | goto end; | |
533 | if (oakley_newiv(iph1) < 0) | |
534 | goto end; | |
535 | ||
536 | /* see handler.h about IV synchronization. */ | |
537 | memcpy(iph1->ivm->iv->v, iph1->ivm->ive->v, iph1->ivm->iv->l); | |
538 | ||
539 | /* set encryption flag */ | |
540 | iph1->flags |= ISAKMP_FLAG_E; | |
541 | ||
542 | iph1->status = PHASE1ST_MSG3RECEIVED; | |
543 | ||
544 | error = 0; | |
545 | ||
546 | end: | |
547 | if (pbuf) | |
548 | vfree(pbuf); | |
549 | ||
550 | if (error) { | |
551 | VPTRINIT(iph1->dhpub_p); | |
552 | oakley_delcert(iph1->cert_p); | |
553 | iph1->cert_p = NULL; | |
554 | oakley_delcert(iph1->crl_p); | |
555 | iph1->crl_p = NULL; | |
556 | VPTRINIT(iph1->sig_p); | |
557 | } | |
558 | ||
559 | return error; | |
560 | } | |
561 | ||
562 | /* | |
563 | * status update and establish isakmp sa. | |
564 | */ | |
565 | int | |
566 | base_i3send(iph1, msg) | |
567 | struct ph1handle *iph1; | |
568 | vchar_t *msg; | |
569 | { | |
570 | int error = -1; | |
571 | ||
572 | /* validity check */ | |
573 | if (iph1->status != PHASE1ST_MSG3RECEIVED) { | |
574 | plog(LLV_ERROR, LOCATION, NULL, | |
575 | "status mismatched %d.\n", iph1->status); | |
576 | goto end; | |
577 | } | |
578 | ||
579 | iph1->status = PHASE1ST_ESTABLISHED; | |
580 | ||
581 | error = 0; | |
582 | ||
583 | end: | |
584 | return error; | |
585 | } | |
586 | ||
587 | /* | |
588 | * receive from initiator | |
589 | * psk: HDR, SA, Idii, Ni_b | |
590 | * sig: HDR, SA, Idii, Ni_b | |
591 | * rsa: HDR, SA, [HASH(1),] <IDii_b>Pubkey_r, <Ni_b>Pubkey_r | |
592 | * rev: HDR, SA, [HASH(1),] <Ni_b>Pubkey_r, <IDii_b>Ke_i | |
593 | */ | |
594 | int | |
595 | base_r1recv(iph1, msg) | |
596 | struct ph1handle *iph1; | |
597 | vchar_t *msg; | |
598 | { | |
599 | vchar_t *pbuf = NULL; | |
600 | struct isakmp_parse_t *pa; | |
601 | int error = -1; | |
602 | ||
603 | /* validity check */ | |
604 | if (iph1->status != PHASE1ST_START) { | |
605 | plog(LLV_ERROR, LOCATION, NULL, | |
606 | "status mismatched %d.\n", iph1->status); | |
607 | goto end; | |
608 | } | |
609 | ||
610 | /* validate the type of next payload */ | |
611 | /* | |
612 | * NOTE: XXX even if multiple VID, we'll silently ignore those. | |
613 | */ | |
614 | pbuf = isakmp_parse(msg); | |
615 | if (pbuf == NULL) | |
616 | goto end; | |
617 | pa = (struct isakmp_parse_t *)pbuf->v; | |
618 | ||
619 | /* check the position of SA payload */ | |
620 | if (pa->type != ISAKMP_NPTYPE_SA) { | |
621 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
622 | "received invalid next payload type %d, " | |
623 | "expecting %d.\n", | |
624 | pa->type, ISAKMP_NPTYPE_SA); | |
625 | goto end; | |
626 | } | |
627 | if (isakmp_p2ph(&iph1->sa, pa->ptr) < 0) | |
628 | goto end; | |
629 | pa++; | |
630 | ||
631 | for (/*nothing*/; | |
632 | pa->type != ISAKMP_NPTYPE_NONE; | |
633 | pa++) { | |
634 | ||
635 | switch (pa->type) { | |
636 | case ISAKMP_NPTYPE_NONCE: | |
637 | if (isakmp_p2ph(&iph1->nonce_p, pa->ptr) < 0) | |
638 | goto end; | |
639 | break; | |
640 | case ISAKMP_NPTYPE_ID: | |
641 | if (isakmp_p2ph(&iph1->id_p, pa->ptr) < 0) | |
642 | goto end; | |
643 | break; | |
644 | case ISAKMP_NPTYPE_VID: | |
645 | (void)check_vendorid(pa->ptr); | |
646 | break; | |
647 | default: | |
648 | /* don't send information, see ident_r1recv() */ | |
649 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
650 | "ignore the packet, " | |
651 | "received unexpecting payload type %d.\n", | |
652 | pa->type); | |
653 | goto end; | |
654 | } | |
655 | } | |
656 | ||
657 | if (iph1->nonce_p == NULL || iph1->id_p == NULL) { | |
658 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
659 | "few isakmp message received.\n"); | |
660 | goto end; | |
661 | } | |
662 | ||
663 | /* verify identifier */ | |
664 | if (ipsecdoi_checkid1(iph1) != 0) { | |
665 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
666 | "invalid ID payload.\n"); | |
667 | goto end; | |
668 | } | |
669 | ||
670 | /* check SA payload and set approval SA for use */ | |
671 | if (ipsecdoi_checkph1proposal(iph1->sa, iph1) < 0) { | |
672 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
673 | "failed to get valid proposal.\n"); | |
674 | /* XXX send information */ | |
675 | goto end; | |
676 | } | |
677 | ||
678 | iph1->status = PHASE1ST_MSG1RECEIVED; | |
679 | ||
680 | error = 0; | |
681 | ||
682 | end: | |
683 | if (pbuf) | |
684 | vfree(pbuf); | |
685 | ||
686 | if (error) { | |
687 | VPTRINIT(iph1->sa); | |
688 | VPTRINIT(iph1->nonce_p); | |
689 | VPTRINIT(iph1->id_p); | |
690 | } | |
691 | ||
692 | return error; | |
693 | } | |
694 | ||
695 | /* | |
696 | * send to initiator | |
697 | * psk: HDR, SA, Idir, Nr_b | |
698 | * sig: HDR, SA, Idir, Nr_b, [ CR ] | |
699 | * rsa: HDR, SA, <IDir_b>PubKey_i, <Nr_b>PubKey_i | |
700 | * rev: HDR, SA, <Nr_b>PubKey_i, <IDir_b>Ke_r | |
701 | */ | |
702 | int | |
703 | base_r1send(iph1, msg) | |
704 | struct ph1handle *iph1; | |
705 | vchar_t *msg; | |
706 | { | |
707 | struct isakmp_gen *gen; | |
708 | caddr_t p; | |
709 | int tlen; | |
710 | int error = -1; | |
711 | ||
712 | /* validity check */ | |
713 | if (iph1->status != PHASE1ST_MSG1RECEIVED) { | |
714 | plog(LLV_ERROR, LOCATION, NULL, | |
715 | "status mismatched %d.\n", iph1->status); | |
716 | goto end; | |
717 | } | |
718 | ||
719 | /* set responder's cookie */ | |
720 | isakmp_newcookie((caddr_t)&iph1->index.r_ck, iph1->remote, iph1->local); | |
721 | ||
722 | /* make ID payload into isakmp status */ | |
723 | if (ipsecdoi_setid1(iph1) < 0) | |
724 | goto end; | |
725 | ||
726 | /* generate NONCE value */ | |
727 | iph1->nonce = eay_set_random(iph1->rmconf->nonce_size); | |
728 | if (iph1->nonce == NULL) | |
729 | goto end; | |
730 | ||
731 | /* create buffer to send isakmp payload */ | |
732 | tlen = sizeof(struct isakmp) | |
733 | + sizeof(*gen) + iph1->sa_ret->l | |
734 | + sizeof(*gen) + iph1->id->l | |
735 | + sizeof(*gen) + iph1->nonce->l; | |
736 | ||
737 | iph1->sendbuf = vmalloc(tlen); | |
738 | if (iph1->sendbuf == NULL) { | |
739 | plog(LLV_ERROR, LOCATION, NULL, | |
740 | "failed to get buffer to send.\n"); | |
741 | goto end; | |
742 | } | |
743 | ||
744 | /* set isakmp header */ | |
745 | p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_SA); | |
746 | if (p == NULL) | |
747 | goto end; | |
748 | ||
749 | /* set SA payload to reply */ | |
750 | p = set_isakmp_payload(p, iph1->sa_ret, ISAKMP_NPTYPE_ID); | |
751 | ||
752 | /* create isakmp ID payload */ | |
753 | p = set_isakmp_payload(p, iph1->id, ISAKMP_NPTYPE_NONCE); | |
754 | ||
755 | /* create isakmp NONCE payload */ | |
756 | p = set_isakmp_payload(p, iph1->nonce, ISAKMP_NPTYPE_NONE); | |
757 | ||
758 | #ifdef HAVE_PRINT_ISAKMP_C | |
759 | isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); | |
760 | #endif | |
761 | ||
762 | /* send the packet, add to the schedule to resend */ | |
763 | iph1->retry_counter = iph1->rmconf->retry_counter; | |
764 | if (isakmp_ph1resend(iph1) == -1) | |
765 | goto end; | |
766 | ||
767 | /* the sending message is added to the received-list. */ | |
768 | if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { | |
769 | plog(LLV_ERROR , LOCATION, NULL, | |
770 | "failed to add a response packet to the tree.\n"); | |
771 | goto end; | |
772 | } | |
773 | ||
774 | iph1->status = PHASE1ST_MSG1SENT; | |
775 | ||
776 | error = 0; | |
777 | ||
778 | end: | |
779 | if (iph1->sa_ret) { | |
780 | vfree(iph1->sa_ret); | |
781 | iph1->sa_ret = NULL; | |
782 | } | |
783 | ||
784 | return error; | |
785 | } | |
786 | ||
787 | /* | |
788 | * receive from initiator | |
789 | * psk: HDR, KE, HASH_I | |
790 | * sig: HDR, KE, [ CR, ] [CERT,] SIG_I | |
791 | * rsa: HDR, KE, HASH_I | |
792 | * rev: HDR, <KE>Ke_i, HASH_I | |
793 | */ | |
794 | int | |
795 | base_r2recv(iph1, msg) | |
796 | struct ph1handle *iph1; | |
797 | vchar_t *msg; | |
798 | { | |
799 | vchar_t *pbuf = NULL; | |
800 | struct isakmp_parse_t *pa; | |
801 | int error = -1; | |
802 | ||
803 | /* validity check */ | |
804 | if (iph1->status != PHASE1ST_MSG1SENT) { | |
805 | plog(LLV_ERROR, LOCATION, NULL, | |
806 | "status mismatched %d.\n", iph1->status); | |
807 | goto end; | |
808 | } | |
809 | ||
810 | /* validate the type of next payload */ | |
811 | pbuf = isakmp_parse(msg); | |
812 | if (pbuf == NULL) | |
813 | goto end; | |
814 | ||
815 | iph1->pl_hash = NULL; | |
816 | ||
817 | for (pa = (struct isakmp_parse_t *)pbuf->v; | |
818 | pa->type != ISAKMP_NPTYPE_NONE; | |
819 | pa++) { | |
820 | ||
821 | switch (pa->type) { | |
822 | case ISAKMP_NPTYPE_KE: | |
823 | if (isakmp_p2ph(&iph1->dhpub_p, pa->ptr) < 0) | |
824 | goto end; | |
825 | break; | |
826 | case ISAKMP_NPTYPE_HASH: | |
827 | iph1->pl_hash = (struct isakmp_pl_hash *)pa->ptr; | |
828 | break; | |
829 | #ifdef HAVE_SIGNING_C | |
830 | case ISAKMP_NPTYPE_CERT: | |
831 | if (oakley_savecert(iph1, pa->ptr) < 0) | |
832 | goto end; | |
833 | break; | |
834 | case ISAKMP_NPTYPE_SIG: | |
835 | if (isakmp_p2ph(&iph1->sig_p, pa->ptr) < 0) | |
836 | goto end; | |
837 | break; | |
838 | #endif | |
839 | case ISAKMP_NPTYPE_VID: | |
840 | (void)check_vendorid(pa->ptr); | |
841 | break; | |
842 | default: | |
843 | /* don't send information, see ident_r1recv() */ | |
844 | plog(LLV_ERROR, LOCATION, iph1->remote, | |
845 | "ignore the packet, " | |
846 | "received unexpecting payload type %d.\n", | |
847 | pa->type); | |
848 | goto end; | |
849 | } | |
850 | } | |
851 | ||
852 | /* generate DH public value */ | |
853 | if (oakley_dh_generate(iph1->approval->dhgrp, | |
854 | &iph1->dhpub, &iph1->dhpriv) < 0) | |
855 | goto end; | |
856 | ||
857 | /* compute sharing secret of DH */ | |
858 | if (oakley_dh_compute(iph1->approval->dhgrp, iph1->dhpub, | |
859 | iph1->dhpriv, iph1->dhpub_p, &iph1->dhgxy) < 0) | |
860 | goto end; | |
861 | ||
862 | /* generate SKEYID */ | |
863 | if (oakley_skeyid(iph1) < 0) | |
864 | goto end; | |
865 | ||
866 | /* payload existency check */ | |
867 | /* validate authentication value */ | |
868 | { | |
869 | int type; | |
870 | type = oakley_validate_auth(iph1); | |
871 | if (type != 0) { | |
872 | if (type == -1) { | |
873 | /* message printed inner oakley_validate_auth() */ | |
874 | goto end; | |
875 | } | |
876 | isakmp_info_send_n1(iph1, type, NULL); | |
877 | goto end; | |
878 | } | |
879 | } | |
880 | ||
881 | iph1->status = PHASE1ST_MSG2RECEIVED; | |
882 | ||
883 | error = 0; | |
884 | ||
885 | end: | |
886 | if (pbuf) | |
887 | vfree(pbuf); | |
888 | ||
889 | if (error) { | |
890 | VPTRINIT(iph1->dhpub_p); | |
891 | oakley_delcert(iph1->cert_p); | |
892 | iph1->cert_p = NULL; | |
893 | oakley_delcert(iph1->crl_p); | |
894 | iph1->crl_p = NULL; | |
895 | VPTRINIT(iph1->sig_p); | |
896 | } | |
897 | ||
898 | return error; | |
899 | } | |
900 | ||
901 | /* | |
902 | * send to initiator | |
903 | * psk: HDR, KE, HASH_R | |
904 | * sig: HDR, KE, [CERT,] SIG_R | |
905 | * rsa: HDR, KE, HASH_R | |
906 | * rev: HDR, <KE>_Ke_r, HASH_R | |
907 | */ | |
908 | int | |
909 | base_r2send(iph1, msg) | |
910 | struct ph1handle *iph1; | |
911 | vchar_t *msg; | |
912 | { | |
913 | struct isakmp_gen *gen; | |
914 | char *p; | |
915 | vchar_t *vid = NULL; | |
916 | int tlen; | |
917 | int need_cert = 0; | |
918 | int error = -1; | |
919 | ||
920 | /* validity check */ | |
921 | if (iph1->status != PHASE1ST_MSG2RECEIVED) { | |
922 | plog(LLV_ERROR, LOCATION, NULL, | |
923 | "status mismatched %d.\n", iph1->status); | |
924 | goto end; | |
925 | } | |
926 | ||
927 | /* generate HASH to send */ | |
928 | plog(LLV_DEBUG, LOCATION, NULL, "generate HASH_I\n"); | |
929 | switch (iph1->approval->authmethod) { | |
930 | case OAKLEY_ATTR_AUTH_METHOD_PSKEY: | |
931 | case OAKLEY_ATTR_AUTH_METHOD_RSAENC: | |
932 | case OAKLEY_ATTR_AUTH_METHOD_RSAREV: | |
933 | iph1->hash = oakley_ph1hash_common(iph1, GENERATE); | |
934 | break; | |
935 | case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: | |
936 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: | |
937 | case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: | |
938 | iph1->hash = oakley_ph1hash_base_r(iph1, GENERATE); | |
939 | break; | |
940 | default: | |
941 | plog(LLV_ERROR, LOCATION, NULL, | |
942 | "invalid authentication method %d\n", | |
943 | iph1->approval->authmethod); | |
944 | goto end; | |
945 | } | |
946 | if (iph1->hash == NULL) | |
947 | goto end; | |
948 | ||
949 | /* create HDR;KE;NONCE payload */ | |
950 | tlen = sizeof(struct isakmp); | |
951 | ||
952 | switch (iph1->approval->authmethod) { | |
953 | case OAKLEY_ATTR_AUTH_METHOD_PSKEY: | |
954 | tlen += sizeof(*gen) + iph1->dhpub->l | |
955 | + sizeof(*gen) + iph1->hash->l; | |
956 | if ((vid = set_vendorid(iph1->approval->vendorid)) != NULL) | |
957 | tlen += sizeof(*gen) + vid->l; | |
958 | ||
959 | iph1->sendbuf = vmalloc(tlen); | |
960 | if (iph1->sendbuf == NULL) { | |
961 | plog(LLV_ERROR, LOCATION, NULL, | |
962 | "failed to get iph1->sendbuf to send.\n"); | |
963 | goto end; | |
964 | } | |
965 | ||
966 | /* set isakmp header */ | |
967 | p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); | |
968 | if (p == NULL) | |
969 | goto end; | |
970 | ||
971 | /* create isakmp KE payload */ | |
972 | p = set_isakmp_payload(p, iph1->dhpub, ISAKMP_NPTYPE_HASH); | |
973 | ||
974 | /* create isakmp HASH payload */ | |
975 | p = set_isakmp_payload(p, iph1->hash, | |
976 | vid ? ISAKMP_NPTYPE_VID : ISAKMP_NPTYPE_NONE); | |
977 | ||
978 | /* append vendor id, if needed */ | |
979 | if (vid) | |
980 | p = set_isakmp_payload(p, vid, ISAKMP_NPTYPE_NONE); | |
981 | break; | |
982 | #ifdef HAVE_SIGNING_C | |
983 | case OAKLEY_ATTR_AUTH_METHOD_DSSSIG: | |
984 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: | |
985 | /* XXX if there is CR or not ? */ | |
986 | ||
987 | if (oakley_getmycert(iph1) < 0) | |
988 | goto end; | |
989 | ||
990 | if (oakley_getsign(iph1) < 0) | |
991 | goto end; | |
992 | ||
993 | if (iph1->cert && iph1->rmconf->send_cert) | |
994 | need_cert = 1; | |
995 | ||
996 | tlen += sizeof(*gen) + iph1->dhpub->l | |
997 | + sizeof(*gen) + iph1->sig->l; | |
998 | if (need_cert) | |
999 | tlen += sizeof(*gen) + iph1->cert->pl->l; | |
1000 | ||
1001 | iph1->sendbuf = vmalloc(tlen); | |
1002 | if (iph1->sendbuf == NULL) { | |
1003 | plog(LLV_ERROR, LOCATION, NULL, | |
1004 | "failed to get buffer to send.\n"); | |
1005 | goto end; | |
1006 | } | |
1007 | ||
1008 | /* set isakmp header */ | |
1009 | p = set_isakmp_header(iph1->sendbuf, iph1, ISAKMP_NPTYPE_KE); | |
1010 | if (p == NULL) | |
1011 | goto end; | |
1012 | ||
1013 | /* create isakmp KE payload */ | |
1014 | p = set_isakmp_payload(p, iph1->dhpub, need_cert | |
1015 | ? ISAKMP_NPTYPE_CERT | |
1016 | : ISAKMP_NPTYPE_SIG); | |
1017 | ||
1018 | /* add CERT payload if there */ | |
1019 | if (need_cert) | |
1020 | p = set_isakmp_payload(p, iph1->cert->pl, ISAKMP_NPTYPE_SIG); | |
1021 | /* add SIG payload */ | |
1022 | p = set_isakmp_payload(p, iph1->sig, ISAKMP_NPTYPE_NONE); | |
1023 | break; | |
1024 | #endif | |
1025 | case OAKLEY_ATTR_AUTH_METHOD_GSSAPI_KRB: | |
1026 | /* ... */ | |
1027 | break; | |
1028 | case OAKLEY_ATTR_AUTH_METHOD_RSAENC: | |
1029 | case OAKLEY_ATTR_AUTH_METHOD_RSAREV: | |
1030 | tlen += sizeof(*gen) + iph1->hash->l; | |
1031 | break; | |
1032 | } | |
1033 | ||
1034 | #ifdef HAVE_PRINT_ISAKMP_C | |
1035 | isakmp_printpacket(iph1->sendbuf, iph1->local, iph1->remote, 0); | |
1036 | #endif | |
1037 | ||
1038 | /* send HDR;KE;NONCE to responder */ | |
1039 | if (isakmp_send(iph1, iph1->sendbuf) < 0) | |
1040 | goto end; | |
1041 | ||
1042 | /* the sending message is added to the received-list. */ | |
1043 | if (add_recvdpkt(iph1->remote, iph1->local, iph1->sendbuf, msg) == -1) { | |
1044 | plog(LLV_ERROR , LOCATION, NULL, | |
1045 | "failed to add a response packet to the tree.\n"); | |
1046 | goto end; | |
1047 | } | |
1048 | ||
1049 | /* generate SKEYIDs & IV & final cipher key */ | |
1050 | if (oakley_skeyid_dae(iph1) < 0) | |
1051 | goto end; | |
1052 | if (oakley_compute_enckey(iph1) < 0) | |
1053 | goto end; | |
1054 | if (oakley_newiv(iph1) < 0) | |
1055 | goto end; | |
1056 | ||
1057 | /* set encryption flag */ | |
1058 | iph1->flags |= ISAKMP_FLAG_E; | |
1059 | ||
1060 | iph1->status = PHASE1ST_ESTABLISHED; | |
1061 | ||
1062 | error = 0; | |
1063 | ||
1064 | end: | |
1065 | if (vid) | |
1066 | vfree(vid); | |
1067 | return error; | |
1068 | } |