]>
Commit | Line | Data |
---|---|---|
d1e348cf A |
1 | /* $NetBSD: oakley.c,v 1.9.6.2 2007/04/04 13:08:28 vanhu Exp $ */ |
2 | ||
3 | /* Id: oakley.c,v 1.32 2006/05/26 12:19:46 manubsd Exp */ | |
52b7d2ce A |
4 | |
5 | /* | |
6 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
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> /* XXX for subjectaltname */ | |
39 | #include <netinet/in.h> /* XXX for subjectaltname */ | |
40 | ||
e8d9021d | 41 | #ifdef HAVE_OPENSSL |
52b7d2ce | 42 | #include <openssl/pkcs7.h> |
d1e348cf | 43 | #include <openssl/x509.h> |
e8d9021d | 44 | #endif |
52b7d2ce A |
45 | |
46 | #include <stdlib.h> | |
47 | #include <stdio.h> | |
48 | #include <string.h> | |
49 | #include <errno.h> | |
d1e348cf A |
50 | #include <arpa/inet.h> |
51 | #include <TargetConditionals.h> | |
52b7d2ce A |
52 | |
53 | #if TIME_WITH_SYS_TIME | |
54 | # include <sys/time.h> | |
55 | # include <time.h> | |
56 | #else | |
57 | # if HAVE_SYS_TIME_H | |
58 | # include <sys/time.h> | |
59 | # else | |
60 | # include <time.h> | |
61 | # endif | |
62 | #endif | |
d1e348cf A |
63 | #ifdef ENABLE_HYBRID |
64 | #include <resolv.h> | |
65 | #endif | |
52b7d2ce A |
66 | |
67 | #include "var.h" | |
68 | #include "misc.h" | |
69 | #include "vmbuf.h" | |
70 | #include "str2val.h" | |
71 | #include "plog.h" | |
72 | #include "debug.h" | |
73 | ||
74 | #include "isakmp_var.h" | |
75 | #include "isakmp.h" | |
76 | #ifdef ENABLE_HYBRID | |
77 | #include "isakmp_xauth.h" | |
78 | #include "isakmp_cfg.h" | |
79 | #endif | |
80 | #include "oakley.h" | |
52b7d2ce | 81 | #include "localconf.h" |
52b7d2ce A |
82 | #include "policy.h" |
83 | #include "handler.h" | |
84 | #include "ipsec_doi.h" | |
85 | #include "algorithm.h" | |
86 | #include "dhgroup.h" | |
87 | #include "sainfo.h" | |
88 | #include "proposal.h" | |
89 | #include "crypto_openssl.h" | |
52b7d2ce | 90 | #include "crypto_cssm.h" |
d1e348cf | 91 | #if HAVE_OPENDIR |
52b7d2ce A |
92 | #include "open_dir.h" |
93 | #endif | |
94 | #include "dnssec.h" | |
95 | #include "sockmisc.h" | |
96 | #include "strnames.h" | |
97 | #include "gcmalloc.h" | |
e8d9021d | 98 | #include <CoreFoundation/CoreFoundation.h> |
d1e348cf | 99 | #include "remoteconf.h" |
fce29cd9 | 100 | #include "vpn_control.h" |
e8d9021d A |
101 | #if TARGET_OS_EMBEDDED |
102 | #include <Security/SecCertificate.h> | |
103 | #include <Security/SecCertificatePriv.h> | |
104 | #endif | |
e8d9021d | 105 | #include "vpn_control_var.h" |
65c25746 A |
106 | #include "ikev2_rfc.h" |
107 | #include "extern.h" | |
52b7d2ce A |
108 | |
109 | #define OUTBOUND_SA 0 | |
110 | #define INBOUND_SA 1 | |
111 | ||
52b7d2ce A |
112 | #define CERT_CHECKID_FROM_PEER 0 |
113 | #define CERT_CHECKID_FROM_RMCONFIG 1 | |
52b7d2ce | 114 | |
e8d9021d | 115 | #ifdef HAVE_OPENSSL |
52b7d2ce A |
116 | #define INITDHVAL(a, s, d, t) \ |
117 | do { \ | |
e8d9021d A |
118 | vchar_t buf; \ |
119 | buf.v = str2val((s), 16, &buf.l); \ | |
120 | memset(&a, 0, sizeof(struct dhgroup)); \ | |
121 | a.type = (t); \ | |
122 | a.prime = vdup(&buf); \ | |
123 | a.gen1 = 2; \ | |
124 | a.gen2 = 0; \ | |
125 | racoon_free(buf.v); \ | |
52b7d2ce | 126 | } while(0); |
e8d9021d A |
127 | #else /* HAVE_OPENSSL */ |
128 | #define INITDHVAL(a, s, d, t) \ | |
129 | do { \ | |
130 | vchar_t buf; \ | |
131 | buf.v = str2val((s), 16, &buf.l); \ | |
132 | memset(&a, 0, sizeof(struct dhgroup)); \ | |
133 | a.desc = (d); \ | |
134 | a.type = (t); \ | |
135 | a.prime = vdup(&buf); \ | |
136 | a.gen1 = 2; \ | |
137 | a.gen2 = 0; \ | |
138 | racoon_free(buf.v); \ | |
139 | } while(0); | |
140 | #endif /* HAVE_OPENSSL */ | |
52b7d2ce A |
141 | |
142 | struct dhgroup dh_modp768; | |
143 | struct dhgroup dh_modp1024; | |
144 | struct dhgroup dh_modp1536; | |
145 | struct dhgroup dh_modp2048; | |
146 | struct dhgroup dh_modp3072; | |
147 | struct dhgroup dh_modp4096; | |
148 | struct dhgroup dh_modp6144; | |
149 | struct dhgroup dh_modp8192; | |
150 | ||
151 | ||
65c25746 A |
152 | static int oakley_check_dh_pub (vchar_t *, vchar_t **); |
153 | static int oakley_compute_keymat_x (phase2_handle_t *, int, int); | |
154 | static int oakley_compute_ikev2_keymat_x (phase2_handle_t *); | |
155 | static int get_cert_fromlocal (phase1_handle_t *, int); | |
156 | static int oakley_check_certid (phase1_handle_t *iph1); | |
157 | static int oakley_check_certid_1 (vchar_t *, int, int, void*, cert_status_t *certStatus); | |
158 | static vchar_t * oakley_prf_plus (vchar_t *, vchar_t *, int, phase1_handle_t *iph1); | |
e8d9021d | 159 | #ifdef HAVE_OPENSSL |
65c25746 | 160 | static int check_typeofcertname (int, int); |
e8d9021d | 161 | #endif |
65c25746 A |
162 | static cert_t *save_certbuf (struct isakmp_gen *); |
163 | static int oakley_padlen (int, int); | |
e8d9021d | 164 | |
65c25746 A |
165 | static int base64toCFData (vchar_t *, CFDataRef*); |
166 | static cert_t *oakley_appendcert_to_certchain (cert_t *, cert_t *); | |
52b7d2ce A |
167 | |
168 | int | |
169 | oakley_get_defaultlifetime() | |
170 | { | |
171 | return OAKLEY_ATTR_SA_LD_SEC_DEFAULT; | |
172 | } | |
173 | ||
174 | int | |
175 | oakley_dhinit() | |
176 | { | |
177 | /* set DH MODP */ | |
178 | INITDHVAL(dh_modp768, OAKLEY_PRIME_MODP768, | |
179 | OAKLEY_ATTR_GRP_DESC_MODP768, OAKLEY_ATTR_GRP_TYPE_MODP); | |
180 | INITDHVAL(dh_modp1024, OAKLEY_PRIME_MODP1024, | |
181 | OAKLEY_ATTR_GRP_DESC_MODP1024, OAKLEY_ATTR_GRP_TYPE_MODP); | |
182 | INITDHVAL(dh_modp1536, OAKLEY_PRIME_MODP1536, | |
183 | OAKLEY_ATTR_GRP_DESC_MODP1536, OAKLEY_ATTR_GRP_TYPE_MODP); | |
184 | INITDHVAL(dh_modp2048, OAKLEY_PRIME_MODP2048, | |
185 | OAKLEY_ATTR_GRP_DESC_MODP2048, OAKLEY_ATTR_GRP_TYPE_MODP); | |
186 | INITDHVAL(dh_modp3072, OAKLEY_PRIME_MODP3072, | |
187 | OAKLEY_ATTR_GRP_DESC_MODP3072, OAKLEY_ATTR_GRP_TYPE_MODP); | |
188 | INITDHVAL(dh_modp4096, OAKLEY_PRIME_MODP4096, | |
189 | OAKLEY_ATTR_GRP_DESC_MODP4096, OAKLEY_ATTR_GRP_TYPE_MODP); | |
190 | INITDHVAL(dh_modp6144, OAKLEY_PRIME_MODP6144, | |
191 | OAKLEY_ATTR_GRP_DESC_MODP6144, OAKLEY_ATTR_GRP_TYPE_MODP); | |
192 | INITDHVAL(dh_modp8192, OAKLEY_PRIME_MODP8192, | |
193 | OAKLEY_ATTR_GRP_DESC_MODP8192, OAKLEY_ATTR_GRP_TYPE_MODP); | |
194 | ||
195 | return 0; | |
196 | } | |
197 | ||
198 | void | |
65c25746 | 199 | oakley_dhgrp_free(struct dhgroup *dhgrp) |
52b7d2ce | 200 | { |
65c25746 A |
201 | VPTRINIT(dhgrp->prime); |
202 | VPTRINIT(dhgrp->curve_a); | |
203 | VPTRINIT(dhgrp->curve_b); | |
204 | VPTRINIT(dhgrp->order); | |
52b7d2ce A |
205 | racoon_free(dhgrp); |
206 | } | |
207 | ||
208 | /* | |
209 | * RFC2409 5 | |
210 | * The length of the Diffie-Hellman public value MUST be equal to the | |
211 | * length of the prime modulus over which the exponentiation was | |
212 | * performed, prepending zero bits to the value if necessary. | |
213 | */ | |
214 | static int | |
65c25746 | 215 | oakley_check_dh_pub(vchar_t *prime, vchar_t **pub0) |
52b7d2ce A |
216 | { |
217 | vchar_t *tmp; | |
218 | vchar_t *pub = *pub0; | |
219 | ||
220 | if (prime->l == pub->l) | |
221 | return 0; | |
222 | ||
223 | if (prime->l < pub->l) { | |
224 | /* what should i do ? */ | |
65c25746 | 225 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
226 | "invalid public information was generated.\n"); |
227 | return -1; | |
228 | } | |
229 | ||
230 | /* prime->l > pub->l */ | |
231 | tmp = vmalloc(prime->l); | |
232 | if (tmp == NULL) { | |
65c25746 | 233 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
234 | "failed to get DH buffer.\n"); |
235 | return -1; | |
236 | } | |
237 | memcpy(tmp->v + prime->l - pub->l, pub->v, pub->l); | |
238 | ||
239 | vfree(*pub0); | |
240 | *pub0 = tmp; | |
241 | ||
242 | return 0; | |
243 | } | |
244 | ||
245 | /* | |
246 | * compute sharing secret of DH | |
247 | * IN: *dh, *pub, *priv, *pub_p | |
248 | * OUT: **gxy | |
249 | */ | |
e8d9021d | 250 | #ifdef HAVE_OPENSSL |
52b7d2ce | 251 | int |
e8d9021d | 252 | oakley_dh_compute(const struct dhgroup *dh, vchar_t *pub, vchar_t *priv, vchar_t *pub_p, vchar_t **gxy) |
52b7d2ce A |
253 | { |
254 | #ifdef ENABLE_STATS | |
255 | struct timeval start, end; | |
256 | #endif | |
257 | if ((*gxy = vmalloc(dh->prime->l)) == NULL) { | |
65c25746 | 258 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
259 | "failed to get DH buffer.\n"); |
260 | return -1; | |
261 | } | |
262 | ||
263 | #ifdef ENABLE_STATS | |
264 | gettimeofday(&start, NULL); | |
265 | #endif | |
266 | switch (dh->type) { | |
267 | case OAKLEY_ATTR_GRP_TYPE_MODP: | |
268 | if (eay_dh_compute(dh->prime, dh->gen1, pub, priv, pub_p, gxy) < 0) { | |
65c25746 | 269 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
270 | "failed to compute dh value.\n"); |
271 | return -1; | |
272 | } | |
273 | break; | |
274 | case OAKLEY_ATTR_GRP_TYPE_ECP: | |
275 | case OAKLEY_ATTR_GRP_TYPE_EC2N: | |
65c25746 | 276 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
277 | "dh type %d isn't supported.\n", dh->type); |
278 | return -1; | |
279 | default: | |
65c25746 | 280 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
281 | "invalid dh type %d.\n", dh->type); |
282 | return -1; | |
283 | } | |
284 | ||
285 | #ifdef ENABLE_STATS | |
286 | gettimeofday(&end, NULL); | |
65c25746 | 287 | plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, |
52b7d2ce A |
288 | s_attr_isakmp_group(dh->type), dh->prime->l << 3, |
289 | timedelta(&start, &end)); | |
290 | #endif | |
291 | ||
65c25746 | 292 | plog(ASL_LEVEL_DEBUG, "compute DH's shared.\n"); |
52b7d2ce A |
293 | |
294 | return 0; | |
295 | } | |
e8d9021d A |
296 | #else |
297 | int | |
65c25746 | 298 | oakley_dh_compute(const struct dhgroup *dh, vchar_t *pub_p, size_t publicKeySize, vchar_t **gxy, SecDHContext *dhC) |
e8d9021d A |
299 | { |
300 | ||
301 | vchar_t *computed_key = NULL; | |
302 | size_t computed_keylen; | |
303 | size_t maxKeyLen; | |
304 | ||
305 | #ifdef ENABLE_STATS | |
306 | struct timeval start, end; | |
307 | gettimeofday(&start, NULL); | |
308 | #endif | |
309 | ||
65c25746 | 310 | plog(ASL_LEVEL_DEBUG, "compute DH result.\n"); |
e8d9021d | 311 | |
65c25746 | 312 | maxKeyLen = SecDHGetMaxKeyLength(*dhC); |
e8d9021d A |
313 | computed_key = vmalloc(maxKeyLen); |
314 | if (computed_key == NULL) { | |
65c25746 | 315 | plog(ASL_LEVEL_ERR, "memory error.\n"); |
e8d9021d A |
316 | goto fail; |
317 | } | |
318 | computed_keylen = computed_key->l; | |
65c25746 A |
319 | if (SecDHComputeKey(*dhC, (uint8_t*)pub_p->v + (maxKeyLen - publicKeySize), publicKeySize, |
320 | (uint8_t*)computed_key->v, &computed_keylen)) { | |
321 | plog(ASL_LEVEL_ERR, "failed to compute dh value.\n"); | |
e8d9021d A |
322 | goto fail; |
323 | } | |
324 | ||
325 | #ifdef ENABLE_STATS | |
326 | gettimeofday(&end, NULL); | |
65c25746 | 327 | plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, |
e8d9021d A |
328 | s_attr_isakmp_group(dh->type), dh->prime->l << 3, |
329 | timedelta(&start, &end)); | |
330 | #endif | |
331 | ||
332 | *gxy = vmalloc(maxKeyLen); | |
333 | if (*gxy == NULL) { | |
65c25746 | 334 | plog(ASL_LEVEL_ERR, "memory error.\n"); |
e8d9021d A |
335 | goto fail; |
336 | } | |
337 | memcpy((*gxy)->v + (maxKeyLen - computed_keylen), computed_key->v, computed_keylen); | |
65c25746 A |
338 | plog(ASL_LEVEL_DEBUG, "compute DH's shared.\n"); |
339 | if (*dhC) { | |
340 | SecDHDestroy(*dhC); | |
341 | *dhC = NULL; | |
342 | } | |
e8d9021d A |
343 | vfree(computed_key); |
344 | return 0; | |
345 | ||
346 | fail: | |
65c25746 A |
347 | if (*dhC) { |
348 | SecDHDestroy(*dhC); | |
349 | *dhC = NULL; | |
350 | } | |
e8d9021d A |
351 | vfree(*gxy); |
352 | vfree(computed_key); | |
353 | return -1; | |
354 | } | |
355 | ||
356 | #endif | |
52b7d2ce A |
357 | |
358 | /* | |
359 | * generate values of DH | |
360 | * IN: *dh | |
361 | * OUT: **pub, **priv | |
362 | */ | |
e8d9021d | 363 | #ifdef HAVE_OPENSSL |
52b7d2ce | 364 | int |
65c25746 | 365 | oakley_dh_generate(const struct dhgroup *dh, vchar_t **pub, vchar_t **priv) |
52b7d2ce A |
366 | { |
367 | #ifdef ENABLE_STATS | |
368 | struct timeval start, end; | |
369 | gettimeofday(&start, NULL); | |
370 | #endif | |
371 | switch (dh->type) { | |
372 | case OAKLEY_ATTR_GRP_TYPE_MODP: | |
373 | if (eay_dh_generate(dh->prime, dh->gen1, dh->gen2, pub, priv) < 0) { | |
65c25746 | 374 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
375 | "failed to compute dh value.\n"); |
376 | return -1; | |
377 | } | |
378 | break; | |
379 | ||
380 | case OAKLEY_ATTR_GRP_TYPE_ECP: | |
381 | case OAKLEY_ATTR_GRP_TYPE_EC2N: | |
65c25746 | 382 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
383 | "dh type %d isn't supported.\n", dh->type); |
384 | return -1; | |
385 | default: | |
65c25746 | 386 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
387 | "invalid dh type %d.\n", dh->type); |
388 | return -1; | |
389 | } | |
390 | ||
391 | #ifdef ENABLE_STATS | |
392 | gettimeofday(&end, NULL); | |
65c25746 | 393 | plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, |
52b7d2ce A |
394 | s_attr_isakmp_group(dh->type), dh->prime->l << 3, |
395 | timedelta(&start, &end)); | |
396 | #endif | |
397 | ||
398 | if (oakley_check_dh_pub(dh->prime, pub) != 0) | |
399 | return -1; | |
400 | ||
65c25746 A |
401 | plog(ASL_LEVEL_DEBUG, "compute DH's private.\n"); |
402 | plog(ASL_LEVEL_DEBUG, "compute DH's public.\n"); | |
52b7d2ce A |
403 | |
404 | return 0; | |
405 | } | |
e8d9021d A |
406 | #else |
407 | int | |
408 | oakley_dh_generate(const struct dhgroup *dh, vchar_t **pub, size_t *publicKeySize, SecDHContext *dhC) | |
409 | { | |
410 | vchar_t *public = NULL; | |
411 | size_t maxKeyLen; | |
412 | ||
413 | #ifdef ENABLE_STATS | |
414 | struct timeval start, end; | |
415 | gettimeofday(&start, NULL); | |
416 | #endif | |
417 | ||
65c25746 | 418 | plog(ASL_LEVEL_DEBUG, "generate DH key pair.\n"); |
e8d9021d A |
419 | *pub = NULL; |
420 | switch (dh->type) { | |
421 | case OAKLEY_ATTR_GRP_TYPE_MODP: | |
65c25746 A |
422 | #define SECDH_MODP_GENERATOR 2 |
423 | if (SecDHCreate(SECDH_MODP_GENERATOR, (uint8_t*)dh->prime->v, dh->prime->l, 0, NULL, 0, dhC)) { | |
424 | plog(ASL_LEVEL_ERR, "failed to create dh context.\n"); | |
e8d9021d A |
425 | goto fail; |
426 | } | |
427 | maxKeyLen = SecDHGetMaxKeyLength(*dhC); | |
428 | public = vmalloc(maxKeyLen); | |
429 | *publicKeySize = public->l; | |
430 | if (public == NULL) { | |
65c25746 | 431 | plog(ASL_LEVEL_ERR, "memory error.\n"); |
e8d9021d A |
432 | goto fail; |
433 | } | |
65c25746 A |
434 | if (SecDHGenerateKeypair(*dhC, (uint8_t*)public->v, publicKeySize)) { |
435 | plog(ASL_LEVEL_ERR, "failed to generate dh key pair.\n"); | |
e8d9021d A |
436 | goto fail; |
437 | } | |
65c25746 | 438 | plog(ASL_LEVEL_DEBUG, "got DH key pair.\n"); |
e8d9021d A |
439 | |
440 | *pub = vmalloc(maxKeyLen); | |
441 | if (*pub == NULL) { | |
65c25746 | 442 | plog(ASL_LEVEL_ERR, "memory error.\n"); |
e8d9021d A |
443 | goto fail; |
444 | } | |
445 | /* copy and fill with leading zeros */ | |
446 | memcpy((*pub)->v + (maxKeyLen - *publicKeySize), public->v, *publicKeySize); | |
447 | break; | |
448 | ||
449 | case OAKLEY_ATTR_GRP_TYPE_ECP: | |
450 | case OAKLEY_ATTR_GRP_TYPE_EC2N: | |
65c25746 | 451 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
452 | "dh type %d isn't supported.\n", dh->type); |
453 | goto fail; | |
454 | default: | |
65c25746 | 455 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
456 | "invalid dh type %d.\n", dh->type); |
457 | goto fail; | |
458 | } | |
459 | ||
460 | #ifdef ENABLE_STATS | |
461 | gettimeofday(&end, NULL); | |
65c25746 | 462 | plog(ASL_LEVEL_NOTICE, "%s(%s%d): %8.6f", __func__, |
e8d9021d A |
463 | s_attr_isakmp_group(dh->type), dh->prime->l << 3, |
464 | timedelta(&start, &end)); | |
465 | #endif | |
466 | ||
467 | if (oakley_check_dh_pub(dh->prime, pub) != 0) { | |
65c25746 | 468 | plog(ASL_LEVEL_DEBUG, "failed DH public key size check.\n"); |
e8d9021d A |
469 | goto fail; |
470 | } | |
471 | ||
65c25746 | 472 | //plogdump(ASL_LEVEL_DEBUG, (*pub)->v, (*pub)->l, "compute DH's public.\n"); |
e8d9021d A |
473 | |
474 | vfree(public); | |
475 | return 0; | |
476 | ||
477 | fail: | |
65c25746 A |
478 | if (*dhC) { |
479 | SecDHDestroy(*dhC); | |
480 | *dhC = NULL; | |
481 | } | |
e8d9021d A |
482 | vfree(*pub); |
483 | vfree(public); | |
484 | return -1; | |
485 | ||
486 | } | |
487 | #endif | |
52b7d2ce A |
488 | |
489 | /* | |
490 | * copy pre-defined dhgroup values. | |
491 | */ | |
492 | int | |
65c25746 | 493 | oakley_setdhgroup(int group, struct dhgroup **dhgrp) |
52b7d2ce A |
494 | { |
495 | struct dhgroup *g; | |
496 | ||
497 | *dhgrp = NULL; /* just make sure, initialize */ | |
498 | ||
499 | g = alg_oakley_dhdef_group(group); | |
500 | if (g == NULL) { | |
65c25746 | 501 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
502 | "invalid DH parameter grp=%d.\n", group); |
503 | return -1; | |
504 | } | |
505 | ||
506 | if (!g->type || !g->prime || !g->gen1) { | |
507 | /* unsuported */ | |
65c25746 | 508 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
509 | "unsupported DH parameters grp=%d.\n", group); |
510 | return -1; | |
511 | } | |
512 | ||
513 | *dhgrp = racoon_calloc(1, sizeof(struct dhgroup)); | |
514 | if (*dhgrp == NULL) { | |
65c25746 | 515 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
516 | "failed to get DH buffer.\n"); |
517 | return 0; | |
518 | } | |
519 | ||
520 | /* set defined dh vlaues */ | |
521 | memcpy(*dhgrp, g, sizeof(*g)); | |
522 | (*dhgrp)->prime = vdup(g->prime); | |
523 | ||
524 | return 0; | |
525 | } | |
526 | ||
527 | /* | |
528 | * PRF | |
529 | * | |
530 | * NOTE: we do not support prf with different input/output bitwidth, | |
531 | * so we do not implement RFC2409 Appendix B (DOORAK-MAC example) in | |
532 | * oakley_compute_keymat(). If you add support for such prf function, | |
533 | * modify oakley_compute_keymat() accordingly. | |
534 | */ | |
535 | vchar_t * | |
65c25746 | 536 | oakley_prf(vchar_t *key, vchar_t *buf, phase1_handle_t *iph1) |
52b7d2ce A |
537 | { |
538 | vchar_t *res = NULL; | |
539 | int type; | |
540 | ||
541 | if (iph1->approval == NULL) { | |
65c25746 A |
542 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { |
543 | /* | |
544 | * it's before negotiating hash algorithm. | |
545 | * We use md5 as default. | |
546 | */ | |
547 | type = OAKLEY_ATTR_HASH_ALG_MD5; | |
548 | } else { | |
549 | type = OAKLEY_ATTR_HASH_ALG_SHA; | |
550 | } | |
52b7d2ce | 551 | } else |
65c25746 A |
552 | { |
553 | type = iph1->approval->hashtype; | |
554 | } | |
555 | res = alg_oakley_hmacdef_one(type, key, buf); | |
52b7d2ce | 556 | if (res == NULL) { |
65c25746 | 557 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
558 | "invalid hmac algorithm %d.\n", type); |
559 | return NULL; | |
560 | } | |
561 | ||
562 | return res; | |
563 | } | |
564 | ||
565 | /* | |
566 | * hash | |
567 | */ | |
568 | vchar_t * | |
65c25746 | 569 | oakley_hash(vchar_t *buf, phase1_handle_t *iph1) |
52b7d2ce A |
570 | { |
571 | vchar_t *res = NULL; | |
572 | int type; | |
573 | ||
574 | if (iph1->approval == NULL) { | |
65c25746 A |
575 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { |
576 | /* | |
577 | * it's before negotiating hash algorithm. | |
578 | * We use md5 as default. | |
579 | */ | |
580 | type = OAKLEY_ATTR_HASH_ALG_MD5; | |
581 | } else { | |
582 | type = OAKLEY_ATTR_HASH_ALG_SHA; | |
583 | } | |
584 | } else { | |
585 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { | |
586 | type = iph1->approval->hashtype; | |
587 | } else { | |
588 | type = OAKLEY_ATTR_HASH_ALG_SHA; | |
589 | } | |
590 | } | |
52b7d2ce A |
591 | |
592 | res = alg_oakley_hashdef_one(type, buf); | |
593 | if (res == NULL) { | |
65c25746 | 594 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
595 | "invalid hash algorithm %d.\n", type); |
596 | return NULL; | |
597 | } | |
598 | ||
599 | return res; | |
600 | } | |
601 | ||
602 | /* | |
603 | * compute KEYMAT | |
604 | * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. | |
605 | */ | |
606 | int | |
65c25746 | 607 | oakley_compute_keymat(phase2_handle_t *iph2, int side) |
52b7d2ce A |
608 | { |
609 | int error = -1; | |
610 | ||
611 | /* compute sharing secret of DH when PFS */ | |
612 | if (iph2->approval->pfs_group && iph2->dhpub_p) { | |
e8d9021d | 613 | #ifdef HAVE_OPENSSL |
52b7d2ce | 614 | if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub, |
e8d9021d A |
615 | iph2->dhpriv, iph2->dhpub_p, &iph2->dhgxy) < 0) |
616 | #else | |
65c25746 | 617 | if (oakley_dh_compute(iph2->pfsgrp, iph2->dhpub_p, iph2->publicKeySize, &iph2->dhgxy, &iph2->dhC) < 0) |
e8d9021d | 618 | #endif |
52b7d2ce A |
619 | goto end; |
620 | } | |
621 | ||
622 | /* compute keymat */ | |
623 | if (oakley_compute_keymat_x(iph2, side, INBOUND_SA) < 0 | |
624 | || oakley_compute_keymat_x(iph2, side, OUTBOUND_SA) < 0) | |
625 | goto end; | |
626 | ||
65c25746 | 627 | plog(ASL_LEVEL_DEBUG, "KEYMAT computed.\n"); |
52b7d2ce A |
628 | |
629 | error = 0; | |
630 | ||
631 | end: | |
632 | return error; | |
633 | } | |
634 | ||
65c25746 | 635 | |
52b7d2ce A |
636 | /* |
637 | * compute KEYMAT. | |
638 | * KEYMAT = prf(SKEYID_d, protocol | SPI | Ni_b | Nr_b). | |
639 | * If PFS is desired and KE payloads were exchanged, | |
640 | * KEYMAT = prf(SKEYID_d, g(qm)^xy | protocol | SPI | Ni_b | Nr_b) | |
641 | * | |
642 | * NOTE: we do not support prf with different input/output bitwidth, | |
643 | * so we do not implement RFC2409 Appendix B (DOORAK-MAC example). | |
644 | */ | |
645 | static int | |
65c25746 | 646 | oakley_compute_keymat_x(phase2_handle_t *iph2, int side, int sa_dir) |
52b7d2ce A |
647 | { |
648 | vchar_t *buf = NULL, *res = NULL, *bp; | |
649 | char *p; | |
650 | int len; | |
651 | int error = -1; | |
652 | int pfs = 0; | |
653 | int dupkeymat; /* generate K[1-dupkeymat] */ | |
654 | struct saproto *pr; | |
655 | struct satrns *tr; | |
656 | int encklen, authklen, l; | |
657 | ||
658 | pfs = ((iph2->approval->pfs_group && iph2->dhgxy) ? 1 : 0); | |
659 | ||
660 | len = pfs ? iph2->dhgxy->l : 0; | |
661 | len += (1 | |
662 | + sizeof(u_int32_t) /* XXX SPI size */ | |
663 | + iph2->nonce->l | |
664 | + iph2->nonce_p->l); | |
665 | buf = vmalloc(len); | |
666 | if (buf == NULL) { | |
65c25746 | 667 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
668 | "failed to get keymat buffer.\n"); |
669 | goto end; | |
670 | } | |
671 | ||
672 | for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { | |
673 | p = buf->v; | |
674 | ||
675 | /* if PFS */ | |
676 | if (pfs) { | |
677 | memcpy(p, iph2->dhgxy->v, iph2->dhgxy->l); | |
678 | p += iph2->dhgxy->l; | |
679 | } | |
680 | ||
681 | p[0] = pr->proto_id; | |
682 | p += 1; | |
683 | ||
684 | memcpy(p, (sa_dir == INBOUND_SA ? &pr->spi : &pr->spi_p), | |
685 | sizeof(pr->spi)); | |
686 | p += sizeof(pr->spi); | |
687 | ||
688 | bp = (side == INITIATOR ? iph2->nonce : iph2->nonce_p); | |
689 | memcpy(p, bp->v, bp->l); | |
690 | p += bp->l; | |
691 | ||
692 | bp = (side == INITIATOR ? iph2->nonce_p : iph2->nonce); | |
693 | memcpy(p, bp->v, bp->l); | |
694 | p += bp->l; | |
695 | ||
696 | /* compute IV */ | |
65c25746 | 697 | //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "KEYMAT compute with\n"); |
52b7d2ce A |
698 | |
699 | /* res = K1 */ | |
700 | res = oakley_prf(iph2->ph1->skeyid_d, buf, iph2->ph1); | |
701 | if (res == NULL) | |
702 | goto end; | |
703 | ||
704 | /* compute key length needed */ | |
705 | encklen = authklen = 0; | |
706 | switch (pr->proto_id) { | |
707 | case IPSECDOI_PROTO_IPSEC_ESP: | |
708 | for (tr = pr->head; tr; tr = tr->next) { | |
709 | l = alg_ipsec_encdef_keylen(tr->trns_id, | |
710 | tr->encklen); | |
711 | if (l > encklen) | |
712 | encklen = l; | |
713 | ||
714 | l = alg_ipsec_hmacdef_hashlen(tr->authtype); | |
715 | if (l > authklen) | |
716 | authklen = l; | |
717 | } | |
718 | break; | |
719 | case IPSECDOI_PROTO_IPSEC_AH: | |
720 | for (tr = pr->head; tr; tr = tr->next) { | |
721 | l = alg_ipsec_hmacdef_hashlen(tr->trns_id); | |
722 | if (l > authklen) | |
723 | authklen = l; | |
724 | } | |
725 | break; | |
726 | default: | |
727 | break; | |
728 | } | |
65c25746 | 729 | plog(ASL_LEVEL_DEBUG, "encklen=%d authklen=%d\n", |
52b7d2ce A |
730 | encklen, authklen); |
731 | ||
732 | dupkeymat = (encklen + authklen) / 8 / res->l; | |
733 | dupkeymat += 2; /* safety mergin */ | |
734 | if (dupkeymat < 3) | |
735 | dupkeymat = 3; | |
65c25746 A |
736 | //plog(ASL_LEVEL_DEBUG, |
737 | // "generating %zu bits of key (dupkeymat=%d)\n", | |
738 | // dupkeymat * 8 * res->l, dupkeymat); | |
52b7d2ce A |
739 | if (0 < --dupkeymat) { |
740 | vchar_t *prev = res; /* K(n-1) */ | |
741 | vchar_t *seed = NULL; /* seed for Kn */ | |
742 | size_t l; | |
743 | ||
744 | /* | |
745 | * generating long key (isakmp-oakley-08 5.5) | |
746 | * KEYMAT = K1 | K2 | K3 | ... | |
747 | * where | |
748 | * src = [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b | |
749 | * K1 = prf(SKEYID_d, src) | |
750 | * K2 = prf(SKEYID_d, K1 | src) | |
751 | * K3 = prf(SKEYID_d, K2 | src) | |
752 | * Kn = prf(SKEYID_d, K(n-1) | src) | |
753 | */ | |
65c25746 A |
754 | //plog(ASL_LEVEL_DEBUG, |
755 | // "generating K1...K%d for KEYMAT.\n", | |
756 | // dupkeymat + 1); | |
52b7d2ce A |
757 | |
758 | seed = vmalloc(prev->l + buf->l); | |
759 | if (seed == NULL) { | |
65c25746 | 760 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
761 | "failed to get keymat buffer.\n"); |
762 | if (prev && prev != res) | |
763 | vfree(prev); | |
764 | goto end; | |
765 | } | |
766 | ||
767 | while (dupkeymat--) { | |
768 | vchar_t *this = NULL; /* Kn */ | |
d1e348cf | 769 | int update_prev; |
52b7d2ce A |
770 | |
771 | memcpy(seed->v, prev->v, prev->l); | |
772 | memcpy(seed->v + prev->l, buf->v, buf->l); | |
773 | this = oakley_prf(iph2->ph1->skeyid_d, seed, | |
774 | iph2->ph1); | |
775 | if (!this) { | |
65c25746 | 776 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
777 | "oakley_prf memory overflow\n"); |
778 | if (prev && prev != res) | |
779 | vfree(prev); | |
780 | vfree(this); | |
781 | vfree(seed); | |
782 | goto end; | |
783 | } | |
784 | ||
d1e348cf A |
785 | update_prev = (prev && prev == res) ? 1 : 0; |
786 | ||
52b7d2ce A |
787 | l = res->l; |
788 | res = vrealloc(res, l + this->l); | |
d1e348cf A |
789 | |
790 | if (update_prev) | |
791 | prev = res; | |
792 | ||
52b7d2ce | 793 | if (res == NULL) { |
65c25746 | 794 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
795 | "failed to get keymat buffer.\n"); |
796 | if (prev && prev != res) | |
797 | vfree(prev); | |
798 | vfree(this); | |
799 | vfree(seed); | |
800 | goto end; | |
801 | } | |
802 | memcpy(res->v + l, this->v, this->l); | |
803 | ||
804 | if (prev && prev != res) | |
805 | vfree(prev); | |
806 | prev = this; | |
807 | this = NULL; | |
808 | } | |
809 | ||
810 | if (prev && prev != res) | |
811 | vfree(prev); | |
812 | vfree(seed); | |
813 | } | |
814 | ||
65c25746 | 815 | //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, ""); |
52b7d2ce A |
816 | |
817 | if (sa_dir == INBOUND_SA) | |
818 | pr->keymat = res; | |
819 | else | |
820 | pr->keymat_p = res; | |
821 | res = NULL; | |
822 | } | |
823 | ||
824 | error = 0; | |
825 | ||
826 | end: | |
827 | if (error) { | |
828 | for (pr = iph2->approval->head; pr != NULL; pr = pr->next) { | |
829 | if (pr->keymat) { | |
830 | vfree(pr->keymat); | |
831 | pr->keymat = NULL; | |
832 | } | |
833 | if (pr->keymat_p) { | |
834 | vfree(pr->keymat_p); | |
835 | pr->keymat_p = NULL; | |
836 | } | |
837 | } | |
838 | } | |
839 | ||
840 | if (buf != NULL) | |
841 | vfree(buf); | |
842 | if (res) | |
843 | vfree(res); | |
844 | ||
845 | return error; | |
846 | } | |
847 | ||
52b7d2ce A |
848 | |
849 | /* | |
850 | * compute HASH(3) prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) | |
851 | * see seciton 5.5 Phase 2 - Quick Mode in isakmp-oakley-05. | |
852 | */ | |
853 | vchar_t * | |
65c25746 | 854 | oakley_compute_hash3(phase1_handle_t *iph1, u_int32_t msgid, vchar_t *body) |
52b7d2ce A |
855 | { |
856 | vchar_t *buf = 0, *res = 0; | |
857 | int len; | |
858 | int error = -1; | |
859 | ||
860 | /* create buffer */ | |
861 | len = 1 + sizeof(u_int32_t) + body->l; | |
862 | buf = vmalloc(len); | |
863 | if (buf == NULL) { | |
65c25746 | 864 | plog(ASL_LEVEL_DEBUG, |
52b7d2ce A |
865 | "failed to get hash buffer\n"); |
866 | goto end; | |
867 | } | |
868 | ||
869 | buf->v[0] = 0; | |
870 | ||
871 | memcpy(buf->v + 1, (char *)&msgid, sizeof(msgid)); | |
872 | ||
873 | memcpy(buf->v + 1 + sizeof(u_int32_t), body->v, body->l); | |
874 | ||
52b7d2ce A |
875 | /* compute HASH */ |
876 | res = oakley_prf(iph1->skeyid_a, buf, iph1); | |
877 | if (res == NULL) | |
878 | goto end; | |
879 | ||
880 | error = 0; | |
881 | ||
65c25746 | 882 | //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH computed:\n"); |
52b7d2ce A |
883 | |
884 | end: | |
885 | if (buf != NULL) | |
886 | vfree(buf); | |
887 | return res; | |
888 | } | |
889 | ||
890 | /* | |
891 | * compute HASH type of prf(SKEYID_a, M-ID | buffer) | |
892 | * e.g. | |
893 | * for quick mode HASH(1): | |
894 | * prf(SKEYID_a, M-ID | SA | Ni [ | KE ] [ | IDci | IDcr ]) | |
895 | * for quick mode HASH(2): | |
896 | * prf(SKEYID_a, M-ID | Ni_b | SA | Nr [ | KE ] [ | IDci | IDcr ]) | |
897 | * for Informational exchange: | |
898 | * prf(SKEYID_a, M-ID | N/D) | |
899 | */ | |
900 | vchar_t * | |
65c25746 | 901 | oakley_compute_hash1(phase1_handle_t *iph1, u_int32_t msgid, vchar_t *body) |
52b7d2ce A |
902 | { |
903 | vchar_t *buf = NULL, *res = NULL; | |
904 | char *p; | |
905 | int len; | |
906 | int error = -1; | |
907 | ||
908 | /* create buffer */ | |
909 | len = sizeof(u_int32_t) + body->l; | |
910 | buf = vmalloc(len); | |
911 | if (buf == NULL) { | |
65c25746 | 912 | plog(ASL_LEVEL_DEBUG, |
52b7d2ce A |
913 | "failed to get hash buffer\n"); |
914 | goto end; | |
915 | } | |
916 | ||
917 | p = buf->v; | |
918 | ||
919 | memcpy(buf->v, (char *)&msgid, sizeof(msgid)); | |
920 | p += sizeof(u_int32_t); | |
921 | ||
922 | memcpy(p, body->v, body->l); | |
923 | ||
52b7d2ce A |
924 | /* compute HASH */ |
925 | res = oakley_prf(iph1->skeyid_a, buf, iph1); | |
926 | if (res == NULL) | |
927 | goto end; | |
928 | ||
929 | error = 0; | |
930 | ||
65c25746 | 931 | //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH computed:\n"); |
52b7d2ce A |
932 | |
933 | end: | |
934 | if (buf != NULL) | |
935 | vfree(buf); | |
936 | return res; | |
937 | } | |
938 | ||
939 | /* | |
940 | * compute phase1 HASH | |
941 | * main/aggressive | |
942 | * I-digest = prf(SKEYID, g^i | g^r | CKY-I | CKY-R | SAi_b | ID_i1_b) | |
943 | * R-digest = prf(SKEYID, g^r | g^i | CKY-R | CKY-I | SAi_b | ID_r1_b) | |
944 | * for gssapi, also include all GSS tokens, and call gss_wrap on the result | |
945 | */ | |
946 | vchar_t * | |
65c25746 | 947 | oakley_ph1hash_common(phase1_handle_t *iph1, int sw) |
52b7d2ce A |
948 | { |
949 | vchar_t *buf = NULL, *res = NULL, *bp; | |
950 | char *p, *bp2; | |
951 | int len, bl; | |
952 | int error = -1; | |
52b7d2ce A |
953 | |
954 | /* create buffer */ | |
955 | len = iph1->dhpub->l | |
956 | + iph1->dhpub_p->l | |
957 | + sizeof(cookie_t) * 2 | |
958 | + iph1->sa->l | |
959 | + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); | |
960 | ||
52b7d2ce A |
961 | buf = vmalloc(len); |
962 | if (buf == NULL) { | |
65c25746 | 963 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
964 | "failed to get hash buffer\n"); |
965 | goto end; | |
966 | } | |
967 | ||
968 | p = buf->v; | |
969 | ||
970 | bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); | |
971 | memcpy(p, bp->v, bp->l); | |
972 | p += bp->l; | |
973 | ||
974 | bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub); | |
975 | memcpy(p, bp->v, bp->l); | |
976 | p += bp->l; | |
977 | ||
978 | if (iph1->side == INITIATOR) | |
979 | bp2 = (sw == GENERATE ? | |
980 | (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck); | |
981 | else | |
982 | bp2 = (sw == GENERATE ? | |
983 | (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck); | |
984 | bl = sizeof(cookie_t); | |
985 | memcpy(p, bp2, bl); | |
986 | p += bl; | |
987 | ||
988 | if (iph1->side == INITIATOR) | |
989 | bp2 = (sw == GENERATE ? | |
990 | (char *)&iph1->index.r_ck : (char *)&iph1->index.i_ck); | |
991 | else | |
992 | bp2 = (sw == GENERATE ? | |
993 | (char *)&iph1->index.i_ck : (char *)&iph1->index.r_ck); | |
994 | bl = sizeof(cookie_t); | |
995 | memcpy(p, bp2, bl); | |
996 | p += bl; | |
997 | ||
998 | bp = iph1->sa; | |
999 | memcpy(p, bp->v, bp->l); | |
1000 | p += bp->l; | |
1001 | ||
1002 | bp = (sw == GENERATE ? iph1->id : iph1->id_p); | |
1003 | memcpy(p, bp->v, bp->l); | |
1004 | p += bp->l; | |
1005 | ||
52b7d2ce A |
1006 | /* compute HASH */ |
1007 | res = oakley_prf(iph1->skeyid, buf, iph1); | |
1008 | if (res == NULL) | |
1009 | goto end; | |
1010 | ||
1011 | error = 0; | |
1012 | ||
52b7d2ce A |
1013 | end: |
1014 | if (buf != NULL) | |
1015 | vfree(buf); | |
52b7d2ce A |
1016 | return res; |
1017 | } | |
1018 | ||
1019 | /* | |
1020 | * compute HASH_I on base mode. | |
1021 | * base:psk,rsa | |
1022 | * HASH_I = prf(SKEYID, g^xi | CKY-I | CKY-R | SAi_b | IDii_b) | |
1023 | * base:sig | |
1024 | * HASH_I = prf(hash(Ni_b | Nr_b), g^xi | CKY-I | CKY-R | SAi_b | IDii_b) | |
1025 | */ | |
1026 | vchar_t * | |
65c25746 | 1027 | oakley_ph1hash_base_i(phase1_handle_t *iph1, int sw) |
52b7d2ce A |
1028 | { |
1029 | vchar_t *buf = NULL, *res = NULL, *bp; | |
1030 | vchar_t *hashkey = NULL; | |
1031 | vchar_t *hash = NULL; /* for signature mode */ | |
1032 | char *p; | |
1033 | int len; | |
1034 | int error = -1; | |
1035 | ||
1036 | /* sanity check */ | |
1037 | if (iph1->etype != ISAKMP_ETYPE_BASE) { | |
65c25746 | 1038 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1039 | "invalid etype for this hash function\n"); |
1040 | return NULL; | |
1041 | } | |
1042 | ||
d1e348cf | 1043 | switch (AUTHMETHOD(iph1)) { |
52b7d2ce A |
1044 | case OAKLEY_ATTR_AUTH_METHOD_PSKEY: |
1045 | case OAKLEY_ATTR_AUTH_METHOD_RSAENC: | |
1046 | case OAKLEY_ATTR_AUTH_METHOD_RSAREV: | |
d1e348cf A |
1047 | #ifdef ENABLE_HYBRID |
1048 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: | |
1049 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: | |
1050 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: | |
1051 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: | |
1052 | case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: | |
1053 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: | |
1054 | #endif | |
52b7d2ce | 1055 | if (iph1->skeyid == NULL) { |
65c25746 | 1056 | plog(ASL_LEVEL_ERR, "no SKEYID found.\n"); |
52b7d2ce A |
1057 | return NULL; |
1058 | } | |
1059 | hashkey = iph1->skeyid; | |
1060 | break; | |
1061 | ||
52b7d2ce | 1062 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: |
52b7d2ce | 1063 | #ifdef ENABLE_HYBRID |
52b7d2ce | 1064 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: |
d1e348cf | 1065 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: |
d1e348cf A |
1066 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: |
1067 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: | |
52b7d2ce A |
1068 | #endif |
1069 | /* make hash for seed */ | |
1070 | len = iph1->nonce->l + iph1->nonce_p->l; | |
1071 | buf = vmalloc(len); | |
1072 | if (buf == NULL) { | |
65c25746 | 1073 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1074 | "failed to get hash buffer\n"); |
1075 | goto end; | |
1076 | } | |
1077 | p = buf->v; | |
1078 | ||
1079 | bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce); | |
1080 | memcpy(p, bp->v, bp->l); | |
1081 | p += bp->l; | |
1082 | ||
1083 | bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p); | |
1084 | memcpy(p, bp->v, bp->l); | |
1085 | p += bp->l; | |
1086 | ||
1087 | hash = oakley_hash(buf, iph1); | |
1088 | if (hash == NULL) | |
1089 | goto end; | |
1090 | vfree(buf); | |
1091 | buf = NULL; | |
1092 | ||
1093 | hashkey = hash; | |
1094 | break; | |
1095 | ||
1096 | default: | |
65c25746 | 1097 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1098 | "not supported authentication method %d\n", |
1099 | iph1->approval->authmethod); | |
1100 | return NULL; | |
1101 | ||
1102 | } | |
1103 | ||
1104 | len = (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l) | |
1105 | + sizeof(cookie_t) * 2 | |
1106 | + iph1->sa->l | |
1107 | + (sw == GENERATE ? iph1->id->l : iph1->id_p->l); | |
1108 | buf = vmalloc(len); | |
1109 | if (buf == NULL) { | |
65c25746 | 1110 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1111 | "failed to get hash buffer\n"); |
1112 | goto end; | |
1113 | } | |
1114 | p = buf->v; | |
1115 | ||
1116 | bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); | |
1117 | memcpy(p, bp->v, bp->l); | |
1118 | p += bp->l; | |
1119 | ||
1120 | memcpy(p, &iph1->index.i_ck, sizeof(cookie_t)); | |
1121 | p += sizeof(cookie_t); | |
1122 | memcpy(p, &iph1->index.r_ck, sizeof(cookie_t)); | |
1123 | p += sizeof(cookie_t); | |
1124 | ||
1125 | memcpy(p, iph1->sa->v, iph1->sa->l); | |
1126 | p += iph1->sa->l; | |
1127 | ||
1128 | bp = (sw == GENERATE ? iph1->id : iph1->id_p); | |
1129 | memcpy(p, bp->v, bp->l); | |
1130 | p += bp->l; | |
1131 | ||
65c25746 | 1132 | //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "HASH_I with:\n"); |
52b7d2ce A |
1133 | |
1134 | /* compute HASH */ | |
1135 | res = oakley_prf(hashkey, buf, iph1); | |
1136 | if (res == NULL) | |
1137 | goto end; | |
1138 | ||
1139 | error = 0; | |
1140 | ||
65c25746 | 1141 | //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH_I computed:\n"); |
52b7d2ce A |
1142 | |
1143 | end: | |
1144 | if (hash != NULL) | |
1145 | vfree(hash); | |
1146 | if (buf != NULL) | |
1147 | vfree(buf); | |
1148 | return res; | |
1149 | } | |
1150 | ||
1151 | /* | |
1152 | * compute HASH_R on base mode for signature method. | |
1153 | * base: | |
1154 | * HASH_R = prf(hash(Ni_b | Nr_b), g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b) | |
1155 | */ | |
1156 | vchar_t * | |
65c25746 | 1157 | oakley_ph1hash_base_r(phase1_handle_t *iph1, int sw) |
52b7d2ce A |
1158 | { |
1159 | vchar_t *buf = NULL, *res = NULL, *bp; | |
1160 | vchar_t *hash = NULL; | |
1161 | char *p; | |
1162 | int len; | |
1163 | int error = -1; | |
1164 | ||
1165 | /* sanity check */ | |
1166 | if (iph1->etype != ISAKMP_ETYPE_BASE) { | |
65c25746 | 1167 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1168 | "invalid etype for this hash function\n"); |
1169 | return NULL; | |
1170 | } | |
d1e348cf A |
1171 | |
1172 | switch(AUTHMETHOD(iph1)) { | |
d1e348cf | 1173 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: |
52b7d2ce | 1174 | #ifdef ENABLE_HYBRID |
d1e348cf A |
1175 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: |
1176 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: | |
d1e348cf A |
1177 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: |
1178 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: | |
d1e348cf | 1179 | case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: |
52b7d2ce | 1180 | #endif |
d1e348cf A |
1181 | break; |
1182 | default: | |
65c25746 | 1183 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1184 | "not supported authentication method %d\n", |
1185 | iph1->approval->authmethod); | |
1186 | return NULL; | |
d1e348cf | 1187 | break; |
52b7d2ce A |
1188 | } |
1189 | ||
1190 | /* make hash for seed */ | |
1191 | len = iph1->nonce->l + iph1->nonce_p->l; | |
1192 | buf = vmalloc(len); | |
1193 | if (buf == NULL) { | |
65c25746 | 1194 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1195 | "failed to get hash buffer\n"); |
1196 | goto end; | |
1197 | } | |
1198 | p = buf->v; | |
1199 | ||
1200 | bp = (sw == GENERATE ? iph1->nonce_p : iph1->nonce); | |
1201 | memcpy(p, bp->v, bp->l); | |
1202 | p += bp->l; | |
1203 | ||
1204 | bp = (sw == GENERATE ? iph1->nonce : iph1->nonce_p); | |
1205 | memcpy(p, bp->v, bp->l); | |
1206 | p += bp->l; | |
1207 | ||
1208 | hash = oakley_hash(buf, iph1); | |
1209 | if (hash == NULL) | |
1210 | goto end; | |
1211 | vfree(buf); | |
1212 | buf = NULL; | |
1213 | ||
1214 | /* make really hash */ | |
1215 | len = (sw == GENERATE ? iph1->dhpub_p->l : iph1->dhpub->l) | |
1216 | + (sw == GENERATE ? iph1->dhpub->l : iph1->dhpub_p->l) | |
1217 | + sizeof(cookie_t) * 2 | |
1218 | + iph1->sa->l | |
1219 | + (sw == GENERATE ? iph1->id_p->l : iph1->id->l); | |
1220 | buf = vmalloc(len); | |
1221 | if (buf == NULL) { | |
65c25746 | 1222 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1223 | "failed to get hash buffer\n"); |
1224 | goto end; | |
1225 | } | |
1226 | p = buf->v; | |
1227 | ||
1228 | ||
1229 | bp = (sw == GENERATE ? iph1->dhpub_p : iph1->dhpub); | |
1230 | memcpy(p, bp->v, bp->l); | |
1231 | p += bp->l; | |
1232 | ||
1233 | bp = (sw == GENERATE ? iph1->dhpub : iph1->dhpub_p); | |
1234 | memcpy(p, bp->v, bp->l); | |
1235 | p += bp->l; | |
1236 | ||
1237 | memcpy(p, &iph1->index.i_ck, sizeof(cookie_t)); | |
1238 | p += sizeof(cookie_t); | |
1239 | memcpy(p, &iph1->index.r_ck, sizeof(cookie_t)); | |
1240 | p += sizeof(cookie_t); | |
1241 | ||
1242 | memcpy(p, iph1->sa->v, iph1->sa->l); | |
1243 | p += iph1->sa->l; | |
1244 | ||
1245 | bp = (sw == GENERATE ? iph1->id_p : iph1->id); | |
1246 | memcpy(p, bp->v, bp->l); | |
1247 | p += bp->l; | |
1248 | ||
65c25746 | 1249 | //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "HASH_R with:\n"); |
52b7d2ce A |
1250 | |
1251 | /* compute HASH */ | |
1252 | res = oakley_prf(hash, buf, iph1); | |
1253 | if (res == NULL) | |
1254 | goto end; | |
1255 | ||
1256 | error = 0; | |
1257 | ||
65c25746 | 1258 | //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, "HASH_R computed:\n"); |
52b7d2ce A |
1259 | |
1260 | end: | |
1261 | if (buf != NULL) | |
1262 | vfree(buf); | |
1263 | if (hash) | |
1264 | vfree(hash); | |
1265 | return res; | |
1266 | } | |
1267 | ||
e8d9021d A |
1268 | #if HAVE_OPENDIR |
1269 | static int | |
65c25746 | 1270 | oakley_verify_userid(phase1_handle_t *iph1) |
e8d9021d A |
1271 | { |
1272 | cert_t *p; | |
1273 | vchar_t *user_id; | |
1274 | int user_id_found = 0; | |
1275 | ||
1276 | for (p = iph1->cert_p; p; p = p->chain) { | |
65c25746 | 1277 | user_id = eay_get_x509_common_name(&p->cert); //%%%%%%%% fix this |
e8d9021d A |
1278 | if (user_id) { |
1279 | user_id_found = 1; | |
1280 | // the following functions will check if user_id == 0 | |
1281 | if (open_dir_authorize_id(user_id, iph1->rmconf->open_dir_auth_group)) { | |
1282 | vfree(user_id); | |
1283 | return 0; | |
1284 | } | |
1285 | vfree(user_id); | |
1286 | } | |
1287 | } | |
1288 | if (user_id_found) { | |
65c25746 | 1289 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
1290 | "the peer is not authorized for access.\n"); |
1291 | } else { | |
65c25746 | 1292 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
1293 | "the peer is not authorized for access - user ID not found.\n"); |
1294 | } | |
1295 | return ISAKMP_NTYPE_AUTHENTICATION_FAILED; | |
1296 | } | |
1297 | #endif /* HAVE_OPENDIR */ | |
1298 | ||
52b7d2ce A |
1299 | /* |
1300 | * compute each authentication method in phase 1. | |
1301 | * OUT: | |
1302 | * 0: OK | |
1303 | * -1: error | |
1304 | * other: error to be reply with notification. | |
1305 | * the value is notification type. | |
1306 | */ | |
1307 | int | |
65c25746 | 1308 | oakley_validate_auth(phase1_handle_t *iph1) |
52b7d2ce A |
1309 | { |
1310 | vchar_t *my_hash = NULL; | |
1311 | int result; | |
52b7d2ce A |
1312 | #ifdef ENABLE_STATS |
1313 | struct timeval start, end; | |
1314 | #endif | |
65c25746 | 1315 | SecKeyRef publicKeyRef = NULL; |
52b7d2ce A |
1316 | |
1317 | #ifdef ENABLE_STATS | |
1318 | gettimeofday(&start, NULL); | |
1319 | #endif | |
d1e348cf A |
1320 | |
1321 | switch (AUTHMETHOD(iph1)) { | |
52b7d2ce | 1322 | case OAKLEY_ATTR_AUTH_METHOD_PSKEY: |
d1e348cf A |
1323 | #ifdef ENABLE_HYBRID |
1324 | case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: | |
1325 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: | |
1326 | #endif | |
52b7d2ce A |
1327 | /* validate HASH */ |
1328 | { | |
1329 | char *r_hash; | |
1330 | ||
1331 | if (iph1->id_p == NULL || iph1->pl_hash == NULL) { | |
65c25746 | 1332 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1333 | "few isakmp message received.\n"); |
1334 | return ISAKMP_NTYPE_PAYLOAD_MALFORMED; | |
1335 | } | |
d1e348cf A |
1336 | #ifdef ENABLE_HYBRID |
1337 | if (AUTHMETHOD(iph1) == FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I && | |
1338 | ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0)) | |
1339 | { | |
65c25746 | 1340 | plog(ASL_LEVEL_ERR, "No SIG was passed, " |
d1e348cf A |
1341 | "hybrid auth is enabled, " |
1342 | "but peer is no Xauth compliant\n"); | |
1343 | return ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED; | |
1344 | break; | |
1345 | } | |
1346 | #endif | |
52b7d2ce A |
1347 | r_hash = (caddr_t)(iph1->pl_hash + 1); |
1348 | ||
65c25746 A |
1349 | //plogdump(ASL_LEVEL_DEBUG, r_hash, |
1350 | // ntohs(iph1->pl_hash->h.len) - sizeof(*iph1->pl_hash), "HASH received:\n"); | |
52b7d2ce | 1351 | |
65c25746 A |
1352 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { |
1353 | switch (iph1->etype) { | |
1354 | case ISAKMP_ETYPE_IDENT: | |
1355 | case ISAKMP_ETYPE_AGG: | |
52b7d2ce | 1356 | my_hash = oakley_ph1hash_common(iph1, VALIDATE); |
65c25746 A |
1357 | break; |
1358 | case ISAKMP_ETYPE_BASE: | |
1359 | if (iph1->side == INITIATOR) | |
1360 | my_hash = oakley_ph1hash_common(iph1, VALIDATE); | |
1361 | else | |
1362 | my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); | |
1363 | break; | |
1364 | default: | |
1365 | plog(ASL_LEVEL_ERR, | |
1366 | "invalid etype %d\n", iph1->etype); | |
1367 | return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; | |
1368 | } | |
1369 | } else { | |
1370 | my_hash = oakley_ph1hash_common(iph1, VALIDATE); | |
52b7d2ce A |
1371 | } |
1372 | if (my_hash == NULL) | |
1373 | return ISAKMP_INTERNAL_ERROR; | |
1374 | ||
1375 | result = memcmp(my_hash->v, r_hash, my_hash->l); | |
1376 | vfree(my_hash); | |
1377 | ||
1378 | if (result) { | |
65c25746 | 1379 | plog(ASL_LEVEL_ERR, "HASH mismatched\n"); |
52b7d2ce A |
1380 | return ISAKMP_NTYPE_INVALID_HASH_INFORMATION; |
1381 | } | |
1382 | ||
65c25746 | 1383 | plog(ASL_LEVEL_DEBUG, "HASH for PSK validated.\n"); |
52b7d2ce A |
1384 | } |
1385 | break; | |
52b7d2ce A |
1386 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: |
1387 | #ifdef ENABLE_HYBRID | |
d1e348cf | 1388 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: |
d1e348cf A |
1389 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: |
1390 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: | |
52b7d2ce A |
1391 | #endif |
1392 | { | |
1393 | int error = 0; | |
1394 | int certtype = 0; | |
1395 | ||
1396 | /* validation */ | |
1397 | if (iph1->id_p == NULL) { | |
65c25746 | 1398 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1399 | "no ID payload was passed.\n"); |
1400 | return ISAKMP_NTYPE_PAYLOAD_MALFORMED; | |
1401 | } | |
1402 | if (iph1->sig_p == NULL) { | |
65c25746 | 1403 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1404 | "no SIG payload was passed.\n"); |
1405 | return ISAKMP_NTYPE_PAYLOAD_MALFORMED; | |
1406 | } | |
1407 | ||
65c25746 | 1408 | plog(ASL_LEVEL_DEBUG, "*** SIGN passed\n"); |
52b7d2ce A |
1409 | |
1410 | /* get peer's cert */ | |
1411 | switch (iph1->rmconf->getcert_method) { | |
1412 | case ISAKMP_GETCERT_PAYLOAD: | |
1413 | if (iph1->cert_p == NULL) { | |
65c25746 | 1414 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1415 | "no peer's CERT payload found.\n"); |
1416 | return ISAKMP_INTERNAL_ERROR; | |
1417 | } | |
1418 | break; | |
52b7d2ce | 1419 | default: |
65c25746 | 1420 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1421 | "invalid getcert_mothod: %d\n", |
1422 | iph1->rmconf->getcert_method); | |
1423 | return ISAKMP_INTERNAL_ERROR; | |
1424 | } | |
1425 | ||
1426 | /* compare ID payload and certificate name */ | |
1427 | if (iph1->rmconf->verify_cert && | |
65c25746 | 1428 | (error = oakley_check_certid(iph1)) != 0) |
52b7d2ce A |
1429 | return error; |
1430 | ||
d1e348cf | 1431 | #if HAVE_OPENDIR |
52b7d2ce A |
1432 | /* check cert common name against Open Directory authentication group */ |
1433 | if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_OPEN_DIR) { | |
e8d9021d A |
1434 | if (oakley_verify_userid(iph1)) { |
1435 | return ISAKMP_NTYPE_AUTHENTICATION_FAILED; | |
52b7d2ce A |
1436 | } |
1437 | } | |
d1e348cf | 1438 | #endif /* HAVE_OPENDIR */ |
52b7d2ce A |
1439 | |
1440 | /* verify certificate */ | |
1441 | if (iph1->rmconf->verify_cert | |
1442 | && iph1->rmconf->getcert_method == ISAKMP_GETCERT_PAYLOAD) { | |
1443 | certtype = iph1->rmconf->certtype; | |
1444 | #ifdef ENABLE_HYBRID | |
d1e348cf A |
1445 | switch (AUTHMETHOD(iph1)) { |
1446 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: | |
52b7d2ce A |
1447 | certtype = iph1->cert_p->type; |
1448 | break; | |
1449 | default: | |
1450 | break; | |
1451 | } | |
1452 | #endif | |
1453 | switch (certtype) { | |
1454 | case ISAKMP_CERT_X509SIGN: | |
d1e348cf A |
1455 | { |
1456 | /* use ID from remote configuration */ | |
1457 | /* check each ID in list */ | |
1458 | struct idspec *id_spec; | |
1459 | CFStringRef hostname = NULL; | |
1460 | char *peers_id; | |
1461 | struct genlist_entry *gpb = NULL; | |
1462 | ||
1463 | if (iph1->rmconf->cert_verification_option == VERIFICATION_OPTION_PEERS_IDENTIFIER) { | |
1464 | id_spec = genlist_next(iph1->rmconf->idvl_p, &gpb); /* expect only one id */ | |
1465 | if (id_spec->idtype == IDTYPE_ADDRESS) { | |
85f41bec | 1466 | switch ((ALIGNED_CAST(struct sockaddr_storage *)(id_spec->id->v))->ss_family) { |
d1e348cf | 1467 | case AF_INET: |
85f41bec | 1468 | peers_id = inet_ntoa((ALIGNED_CAST(struct sockaddr_in *)(id_spec->id->v))->sin_addr); |
d1e348cf A |
1469 | hostname = CFStringCreateWithCString(NULL, peers_id, kCFStringEncodingUTF8); |
1470 | break; | |
1471 | #ifdef INET6 | |
1472 | case AF_INET6: | |
1473 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; /* not currently supported for embedded */ | |
1474 | break; | |
1475 | #endif | |
1476 | default: | |
65c25746 | 1477 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
1478 | "unknown address type for peers identifier.\n"); |
1479 | return ISAKMP_NTYPE_AUTHENTICATION_FAILED; | |
1480 | break; | |
1481 | } | |
1482 | } else | |
1483 | hostname = CFStringCreateWithBytes(NULL, (u_int8_t *)id_spec->id->v, id_spec->id->l, kCFStringEncodingUTF8, FALSE); | |
1484 | } | |
e8d9021d | 1485 | error = crypto_cssm_check_x509cert(oakley_get_peer_cert_from_certchain(iph1), iph1->cert_p, hostname, &publicKeyRef); |
d1e348cf A |
1486 | if (hostname) |
1487 | CFRelease(hostname); | |
1488 | } | |
85f41bec | 1489 | break; |
52b7d2ce A |
1490 | |
1491 | default: | |
65c25746 | 1492 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1493 | "no supported certtype %d\n", certtype); |
1494 | return ISAKMP_INTERNAL_ERROR; | |
1495 | } | |
1496 | if (error != 0) { | |
65c25746 | 1497 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1498 | "the peer's certificate is not verified.\n"); |
1499 | return ISAKMP_NTYPE_INVALID_CERT_AUTHORITY; | |
1500 | } | |
1501 | } | |
1502 | ||
65c25746 | 1503 | plog(ASL_LEVEL_DEBUG, "CERT validated\n"); |
52b7d2ce | 1504 | |
65c25746 A |
1505 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { |
1506 | /* compute hash */ | |
1507 | switch (iph1->etype) { | |
1508 | case ISAKMP_ETYPE_IDENT: | |
1509 | case ISAKMP_ETYPE_AGG: | |
1510 | my_hash = oakley_ph1hash_common(iph1, VALIDATE); | |
1511 | break; | |
1512 | case ISAKMP_ETYPE_BASE: | |
1513 | if (iph1->side == INITIATOR) | |
1514 | my_hash = oakley_ph1hash_base_r(iph1, VALIDATE); | |
1515 | else | |
1516 | my_hash = oakley_ph1hash_base_i(iph1, VALIDATE); | |
1517 | break; | |
1518 | default: | |
1519 | plog(ASL_LEVEL_ERR, | |
1520 | "invalid etype %d\n", iph1->etype); | |
1521 | return ISAKMP_NTYPE_INVALID_EXCHANGE_TYPE; | |
1522 | } | |
1523 | } else { | |
1524 | vchar_t *octets = NULL; | |
1525 | octets = ikev2_ike_sa_auth_get_octets(iph1, (iph1->side == INITIATOR)? FALSE : TRUE); | |
1526 | my_hash = alg_oakley_hashdef_one(OAKLEY_ATTR_HASH_ALG_SHA, octets); | |
52b7d2ce A |
1527 | } |
1528 | if (my_hash == NULL) | |
1529 | return ISAKMP_INTERNAL_ERROR; | |
1530 | ||
1531 | ||
1532 | certtype = iph1->rmconf->certtype; | |
1533 | #ifdef ENABLE_HYBRID | |
d1e348cf A |
1534 | switch (AUTHMETHOD(iph1)) { |
1535 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: | |
52b7d2ce A |
1536 | certtype = iph1->cert_p->type; |
1537 | break; | |
1538 | default: | |
1539 | break; | |
1540 | } | |
1541 | #endif | |
1542 | /* check signature */ | |
1543 | switch (certtype) { | |
65c25746 A |
1544 | case ISAKMP_CERT_X509SIGN: |
1545 | if (publicKeyRef == NULL) { | |
1546 | plog(ASL_LEVEL_ERR, "@@@@@@ publicKeyRef is NULL\n"); | |
1547 | } | |
1548 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { | |
1549 | error = crypto_cssm_verify_x509sign(publicKeyRef, my_hash, iph1->sig_p, FALSE); | |
1550 | } else { | |
1551 | error = crypto_cssm_verify_x509sign(publicKeyRef, my_hash, iph1->sig_p, TRUE); | |
1552 | } | |
1553 | if (error) { | |
1554 | plog(ASL_LEVEL_ERR, "error verifying signature %s\n", GetSecurityErrorString(error)); | |
1555 | } | |
1556 | ||
1557 | CFRelease(publicKeyRef); | |
1558 | break; | |
1559 | default: | |
1560 | plog(ASL_LEVEL_ERR, | |
1561 | "no supported certtype %d\n", | |
1562 | certtype); | |
1563 | vfree(my_hash); | |
1564 | return ISAKMP_INTERNAL_ERROR; | |
52b7d2ce A |
1565 | } |
1566 | ||
1567 | vfree(my_hash); | |
1568 | if (error != 0) { | |
65c25746 | 1569 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1570 | "Invalid SIG.\n"); |
1571 | return ISAKMP_NTYPE_INVALID_SIGNATURE; | |
1572 | } | |
65c25746 | 1573 | plog(ASL_LEVEL_DEBUG, "SIG authenticated\n"); |
52b7d2ce A |
1574 | } |
1575 | break; | |
1576 | #ifdef ENABLE_HYBRID | |
d1e348cf | 1577 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: |
52b7d2ce A |
1578 | { |
1579 | if ((iph1->mode_cfg->flags & ISAKMP_CFG_VENDORID_XAUTH) == 0) { | |
65c25746 | 1580 | plog(ASL_LEVEL_ERR, "No SIG was passed, " |
52b7d2ce A |
1581 | "hybrid auth is enabled, " |
1582 | "but peer is no Xauth compliant\n"); | |
1583 | return ISAKMP_NTYPE_SITUATION_NOT_SUPPORTED; | |
1584 | break; | |
1585 | } | |
65c25746 | 1586 | plog(ASL_LEVEL_INFO, "No SIG was passed, " |
52b7d2ce A |
1587 | "but hybrid auth is enabled\n"); |
1588 | ||
1589 | return 0; | |
1590 | break; | |
1591 | } | |
52b7d2ce A |
1592 | #endif |
1593 | case OAKLEY_ATTR_AUTH_METHOD_RSAENC: | |
1594 | case OAKLEY_ATTR_AUTH_METHOD_RSAREV: | |
d1e348cf A |
1595 | #ifdef ENABLE_HYBRID |
1596 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: | |
1597 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: | |
1598 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: | |
1599 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: | |
1600 | #endif | |
52b7d2ce | 1601 | if (iph1->id_p == NULL || iph1->pl_hash == NULL) { |
65c25746 | 1602 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1603 | "few isakmp message received.\n"); |
1604 | return ISAKMP_NTYPE_PAYLOAD_MALFORMED; | |
1605 | } | |
65c25746 | 1606 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1607 | "not supported authmethod type %s\n", |
1608 | s_oakley_attr_method(iph1->approval->authmethod)); | |
1609 | return ISAKMP_INTERNAL_ERROR; | |
1610 | default: | |
65c25746 | 1611 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1612 | "invalid authmethod %d why ?\n", |
1613 | iph1->approval->authmethod); | |
1614 | return ISAKMP_INTERNAL_ERROR; | |
1615 | } | |
1616 | #ifdef ENABLE_STATS | |
1617 | gettimeofday(&end, NULL); | |
65c25746 | 1618 | plog(ASL_LEVEL_NOTICE, "%s(%s): %8.6f", __func__, |
52b7d2ce A |
1619 | s_oakley_attr_method(iph1->approval->authmethod), |
1620 | timedelta(&start, &end)); | |
1621 | #endif | |
1622 | ||
1623 | return 0; | |
1624 | } | |
1625 | ||
e8d9021d A |
1626 | int |
1627 | oakley_find_status_in_certchain (cert_t *certchain, cert_status_t certStatus) | |
1628 | { | |
1629 | cert_t *p; | |
1630 | ||
1631 | for (p = certchain; p; p = p->chain) { | |
1632 | if (p->status == certStatus) { | |
1633 | return 1; | |
1634 | } | |
1635 | } | |
1636 | return 0; | |
1637 | } | |
1638 | ||
1639 | static | |
1640 | int | |
65c25746 | 1641 | oakley_vpncontrol_notify_ike_failed_if_mycert_invalid (phase1_handle_t *iph1, int notify_initiator) |
e8d9021d A |
1642 | { |
1643 | #if TARGET_OS_EMBEDDED | |
1644 | int premature = oakley_find_status_in_certchain(iph1->cert, CERT_STATUS_PREMATURE); | |
1645 | int expired = oakley_find_status_in_certchain(iph1->cert, CERT_STATUS_EXPIRED); | |
1646 | if (premature || expired) { | |
1647 | u_int32_t address; | |
1648 | u_int32_t fail_reason; | |
1649 | ||
85f41bec | 1650 | if (iph1->remote->ss_family == AF_INET) |
e8d9021d A |
1651 | address = ((struct sockaddr_in *)(iph1->remote))->sin_addr.s_addr; |
1652 | else | |
1653 | address = 0; | |
1654 | if (premature) { | |
1655 | fail_reason = VPNCTL_NTYPE_LOCAL_CERT_PREMATURE; | |
1656 | } else { | |
1657 | fail_reason = VPNCTL_NTYPE_LOCAL_CERT_EXPIRED; | |
1658 | } | |
1659 | vpncontrol_notify_ike_failed(fail_reason, notify_initiator, address, 0, NULL); | |
1660 | return -1; | |
1661 | } | |
1662 | #endif /* TARGET_OS_EMBEDDED */ | |
1663 | return 0; | |
1664 | } | |
1665 | ||
52b7d2ce A |
1666 | /* get my certificate |
1667 | * NOTE: include certificate type. | |
1668 | */ | |
1669 | int | |
65c25746 | 1670 | oakley_getmycert(phase1_handle_t *iph1) |
52b7d2ce | 1671 | { |
fce29cd9 | 1672 | int err; |
fce29cd9 | 1673 | |
52b7d2ce A |
1674 | switch (iph1->rmconf->certtype) { |
1675 | case ISAKMP_CERT_X509SIGN: | |
1676 | if (iph1->cert) | |
1677 | return 0; | |
fce29cd9 | 1678 | if ( !(err = get_cert_fromlocal(iph1, 1))){ |
e8d9021d | 1679 | if (oakley_vpncontrol_notify_ike_failed_if_mycert_invalid(iph1, FROM_LOCAL)) { |
fce29cd9 A |
1680 | return -1; |
1681 | } | |
1682 | } | |
fce29cd9 | 1683 | return err; |
52b7d2ce | 1684 | default: |
65c25746 | 1685 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1686 | "Unknown certtype #%d\n", |
1687 | iph1->rmconf->certtype); | |
1688 | return -1; | |
1689 | } | |
1690 | ||
1691 | } | |
1692 | ||
1693 | /* | |
1694 | * get a CERT from local file. | |
1695 | * IN: | |
1696 | * my != 0 my cert. | |
1697 | * my == 0 peer's cert. | |
1698 | */ | |
1699 | static int | |
65c25746 | 1700 | get_cert_fromlocal(phase1_handle_t *iph1, int my) |
52b7d2ce | 1701 | { |
52b7d2ce A |
1702 | vchar_t *cert = NULL; |
1703 | cert_t **certpl; | |
52b7d2ce | 1704 | int error = -1; |
fce29cd9 | 1705 | cert_status_t status = CERT_STATUS_OK; |
52b7d2ce | 1706 | |
65c25746 | 1707 | if (my) |
52b7d2ce | 1708 | certpl = &iph1->cert; |
65c25746 | 1709 | else |
52b7d2ce | 1710 | certpl = &iph1->cert_p; |
65c25746 A |
1711 | if (iph1->rmconf->identity_in_keychain == 0) { |
1712 | plog(ASL_LEVEL_ERR, "no CERT defined.\n"); | |
52b7d2ce A |
1713 | return 0; |
1714 | } | |
1715 | ||
1716 | switch (iph1->rmconf->certtype) { | |
1717 | case ISAKMP_CERT_X509SIGN: | |
52b7d2ce A |
1718 | if (iph1->rmconf->identity_in_keychain) { |
1719 | CFDataRef dataRef; | |
1720 | ||
d1e348cf | 1721 | if (iph1->rmconf->keychainCertRef == NULL || base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) |
52b7d2ce | 1722 | goto end; |
fce29cd9 | 1723 | cert = crypto_cssm_get_x509cert(dataRef, &status); |
65c25746 | 1724 | plog(ASL_LEVEL_DEBUG, "done with chking cert status %d\n",status); |
52b7d2ce A |
1725 | CFRelease(dataRef); |
1726 | break; | |
1727 | } // else fall thru | |
52b7d2ce | 1728 | default: |
65c25746 | 1729 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1730 | "not supported certtype %d\n", |
1731 | iph1->rmconf->certtype); | |
1732 | goto end; | |
1733 | } | |
1734 | ||
1735 | if (!cert) { | |
65c25746 | 1736 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1737 | "failed to get %s CERT.\n", |
1738 | my ? "my" : "peers"); | |
1739 | goto end; | |
1740 | } | |
1741 | ||
1742 | *certpl = oakley_newcert(); | |
1743 | if (!*certpl) { | |
65c25746 | 1744 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1745 | "failed to get cert buffer.\n"); |
1746 | goto end; | |
1747 | } | |
1748 | (*certpl)->pl = vmalloc(cert->l + 1); | |
1749 | if ((*certpl)->pl == NULL) { | |
65c25746 | 1750 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1751 | "failed to get cert buffer\n"); |
1752 | oakley_delcert(*certpl); | |
1753 | *certpl = NULL; | |
1754 | goto end; | |
1755 | } | |
1756 | memcpy((*certpl)->pl->v + 1, cert->v, cert->l); | |
1757 | (*certpl)->pl->v[0] = iph1->rmconf->certtype; | |
1758 | (*certpl)->type = iph1->rmconf->certtype; | |
fce29cd9 | 1759 | (*certpl)->status = status; |
52b7d2ce A |
1760 | (*certpl)->cert.v = (*certpl)->pl->v + 1; |
1761 | (*certpl)->cert.l = (*certpl)->pl->l - 1; | |
1762 | ||
65c25746 | 1763 | plog(ASL_LEVEL_DEBUG, "created CERT payload\n"); |
e8d9021d | 1764 | |
52b7d2ce A |
1765 | error = 0; |
1766 | ||
1767 | end: | |
1768 | if (cert != NULL) | |
1769 | vfree(cert); | |
1770 | ||
1771 | return error; | |
1772 | } | |
1773 | ||
52b7d2ce A |
1774 | |
1775 | /* get signature */ | |
1776 | int | |
65c25746 | 1777 | oakley_getsign(phase1_handle_t *iph1) |
52b7d2ce | 1778 | { |
52b7d2ce A |
1779 | vchar_t *privkey = NULL; |
1780 | int error = -1; | |
1781 | ||
1782 | switch (iph1->rmconf->certtype) { | |
1783 | case ISAKMP_CERT_X509SIGN: | |
52b7d2ce A |
1784 | // cert in keychain - use cssm to sign |
1785 | if (iph1->rmconf->identity_in_keychain) { | |
1786 | CFDataRef dataRef; | |
1787 | ||
d1e348cf | 1788 | if (iph1->rmconf->keychainCertRef == NULL || base64toCFData(iph1->rmconf->keychainCertRef, &dataRef)) |
52b7d2ce A |
1789 | goto end; |
1790 | iph1->sig = crypto_cssm_getsign(dataRef, iph1->hash); | |
1791 | CFRelease(dataRef); | |
1792 | break; | |
1793 | } // else fall thru | |
52b7d2ce | 1794 | default: |
65c25746 | 1795 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
1796 | "Unknown certtype #%d\n", |
1797 | iph1->rmconf->certtype); | |
1798 | goto end; | |
1799 | } | |
1800 | ||
1801 | if (iph1->sig == NULL) { | |
65c25746 | 1802 | plog(ASL_LEVEL_ERR, "failed to sign.\n"); |
52b7d2ce A |
1803 | goto end; |
1804 | } | |
1805 | ||
65c25746 | 1806 | //plogdump(ASL_LEVEL_DEBUG, iph1->sig->v, iph1->sig->l, "SIGN computed:\n"); |
52b7d2ce A |
1807 | |
1808 | error = 0; | |
1809 | ||
1810 | end: | |
1811 | if (privkey != NULL) | |
1812 | vfree(privkey); | |
1813 | ||
1814 | return error; | |
1815 | } | |
1816 | ||
e8d9021d | 1817 | void |
65c25746 | 1818 | oakley_verify_certid(phase1_handle_t *iph1) |
e8d9021d A |
1819 | { |
1820 | if (iph1->rmconf->verify_cert && | |
65c25746 A |
1821 | oakley_check_certid(iph1)){ |
1822 | plog(ASL_LEVEL_DEBUG, | |
e8d9021d A |
1823 | "Discarding CERT: does not match ID:\n"); |
1824 | oakley_delcert(iph1->cert_p); | |
1825 | iph1->cert_p = NULL; | |
1826 | } | |
1827 | } | |
1828 | ||
1829 | static int | |
65c25746 | 1830 | oakley_check_certid_in_certchain(cert_t *certchain, int idtype, int idlen, void *id) |
e8d9021d A |
1831 | { |
1832 | cert_t *p; | |
1833 | ||
1834 | for (p = certchain; p; p = p->chain) { | |
1835 | if (oakley_check_certid_1(&p->cert, idtype, idlen, id, &p->status) == 0) { | |
1836 | return 0; | |
1837 | } | |
1838 | } | |
1839 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
1840 | } | |
1841 | ||
1842 | cert_t * | |
65c25746 | 1843 | oakley_get_peer_cert_from_certchain(phase1_handle_t * iph1) |
e8d9021d A |
1844 | { |
1845 | cert_t *p; | |
1846 | struct ipsecdoi_id_b *id_b; | |
1847 | int idlen; | |
1848 | void *peers_id; | |
1849 | ||
1850 | if (!iph1->id_p || !iph1->cert_p) { | |
65c25746 | 1851 | plog(ASL_LEVEL_ERR, "no ID nor CERT found.\n"); |
e8d9021d A |
1852 | return NULL; |
1853 | } | |
1854 | if (!iph1->cert_p->chain) { | |
1855 | // no chain: simply return the only cert | |
1856 | return iph1->cert_p; | |
1857 | } | |
1858 | ||
85f41bec | 1859 | id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)iph1->id_p->v; |
e8d9021d A |
1860 | peers_id = id_b + 1; |
1861 | idlen = iph1->id_p->l - sizeof(*id_b); | |
1862 | for (p = iph1->cert_p; p; p = p->chain) { | |
1863 | if (oakley_check_certid_1(&p->cert, id_b->type, idlen, peers_id, &p->status) == 0) { | |
1864 | return p; | |
1865 | } | |
1866 | } | |
1867 | return NULL; | |
1868 | } | |
52b7d2ce A |
1869 | |
1870 | /* | |
1871 | * compare certificate name and ID value. | |
1872 | */ | |
1873 | static int | |
65c25746 | 1874 | oakley_check_certid(phase1_handle_t *iph1) |
52b7d2ce A |
1875 | { |
1876 | struct ipsecdoi_id_b *id_b; | |
1877 | int idlen; | |
1878 | u_int8_t doi_type = 255; | |
1879 | void *peers_id = NULL; | |
52b7d2ce | 1880 | |
65c25746 A |
1881 | /* use ID from peer */ |
1882 | if (iph1->id_p == NULL || iph1->cert_p == NULL) { | |
1883 | plog(ASL_LEVEL_ERR, "no ID nor CERT found.\n"); | |
1884 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
1885 | } | |
1886 | id_b = ALIGNED_CAST(struct ipsecdoi_id_b *)iph1->id_p->v; | |
1887 | doi_type = id_b->type; | |
1888 | peers_id = id_b + 1; | |
1889 | idlen = iph1->id_p->l - sizeof(*id_b); | |
1890 | ||
1891 | return oakley_check_certid_in_certchain(iph1->cert_p, doi_type, idlen, peers_id); | |
52b7d2ce | 1892 | |
52b7d2ce | 1893 | } |
65c25746 | 1894 | |
52b7d2ce | 1895 | static int |
65c25746 | 1896 | oakley_check_certid_1(vchar_t *cert, int idtype, int idlen, void *id, cert_status_t *certStatus) |
52b7d2ce A |
1897 | { |
1898 | ||
85f41bec | 1899 | int len; |
65c25746 | 1900 | int error = 0; |
52b7d2ce | 1901 | |
85f41bec A |
1902 | #if !TARGET_OS_EMBEDDED |
1903 | int type; | |
85f41bec A |
1904 | char *altname = NULL; |
1905 | #endif | |
1906 | ||
52b7d2ce A |
1907 | switch (idtype) { |
1908 | case IPSECDOI_ID_DER_ASN1_DN: | |
e8d9021d | 1909 | { |
65c25746 A |
1910 | CFDataRef subject; |
1911 | SecCertificateRef certificate; | |
1912 | UInt8* namePtr; | |
1913 | ||
1914 | certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); | |
e8d9021d | 1915 | if (certificate == NULL) { |
65c25746 A |
1916 | plog(ASL_LEVEL_ERR, |
1917 | "failed to get SecCertificateRef\n"); | |
e8d9021d A |
1918 | if (certStatus && !*certStatus) { |
1919 | *certStatus = CERT_STATUS_INVALID; | |
1920 | } | |
e8d9021d | 1921 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
65c25746 A |
1922 | } |
1923 | subject = crypto_cssm_CopySubjectSequence(certificate); | |
1924 | if (subject == NULL) { | |
1925 | plog(ASL_LEVEL_ERR, "failed to get certificate subjectName\n"); | |
1926 | if (certStatus && !*certStatus) { | |
1927 | *certStatus = CERT_STATUS_INVALID_SUBJNAME; | |
1928 | } | |
1929 | error = ISAKMP_NTYPE_INVALID_CERTIFICATE; | |
1930 | } else { | |
1931 | len = CFDataGetLength(subject); | |
1932 | namePtr = (UInt8*)CFDataGetBytePtr(subject); | |
1933 | if (namePtr) { | |
1934 | if (idlen != len || memcmp(id, namePtr, idlen)) { | |
1935 | plog(ASL_LEVEL_ERR, "ID mismatched with certificate subjectName\n"); | |
1936 | error =ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
1937 | } | |
1938 | } else { | |
1939 | plog(ASL_LEVEL_ERR, "no certificate subjectName found\n"); | |
1940 | error = ISAKMP_NTYPE_INVALID_CERTIFICATE; | |
1941 | } | |
1942 | } | |
1943 | if (error) { | |
1944 | plog(ASL_LEVEL_ERR, | |
1945 | "ID mismatched with certificate subjectName\n"); | |
1946 | plogdump(ASL_LEVEL_ERR, namePtr, len, "subjectName (type %s):\n", | |
1947 | s_ipsecdoi_ident(idtype)); | |
1948 | plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); | |
1949 | if (certStatus && !*certStatus) { | |
1950 | *certStatus = CERT_STATUS_INVALID_SUBJNAME; | |
1951 | } | |
1952 | } | |
85f41bec A |
1953 | CFRelease(certificate); |
1954 | CFRelease(subject); | |
65c25746 A |
1955 | return 0; |
1956 | } | |
1957 | break; | |
e8d9021d | 1958 | |
52b7d2ce A |
1959 | case IPSECDOI_ID_IPV4_ADDR: |
1960 | case IPSECDOI_ID_IPV6_ADDR: | |
1961 | { | |
e8d9021d A |
1962 | #if TARGET_OS_EMBEDDED |
1963 | CFIndex pos, count; | |
1964 | SecCertificateRef certificate; | |
1965 | CFArrayRef addresses; | |
85f41bec | 1966 | #define ADDRESS_BUF_SIZE 64 |
65c25746 A |
1967 | |
1968 | certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); | |
e8d9021d | 1969 | if (certificate == NULL) { |
65c25746 | 1970 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
1971 | "failed to get SecCertificateRef\n"); |
1972 | if (certStatus && !*certStatus) { | |
1973 | *certStatus = CERT_STATUS_INVALID; | |
1974 | } | |
1975 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; | |
1976 | } | |
1977 | addresses = SecCertificateCopyIPAddresses(certificate); | |
1978 | if (addresses == NULL) { | |
65c25746 | 1979 | plog(ASL_LEVEL_ERR, "failed to get subjectName\n"); |
e8d9021d A |
1980 | if (certStatus && !*certStatus) { |
1981 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
1982 | } | |
1983 | CFRelease(certificate); | |
1984 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; | |
1985 | } | |
1986 | count = CFArrayGetCount(addresses); | |
1987 | for (pos = 0; pos < count; pos++) { | |
1988 | ||
1989 | CFStringRef address; | |
1990 | CFIndex addressLen; | |
1991 | char *addressBuf, numAddress[128]; | |
1992 | int result; | |
1993 | ||
1994 | address = CFArrayGetValueAtIndex(addresses, pos); | |
1995 | addressLen = CFStringGetLength(address); | |
1996 | if (addressLen == 0) | |
1997 | continue; | |
85f41bec | 1998 | addressBuf = racoon_malloc(ADDRESS_BUF_SIZE); |
e8d9021d | 1999 | if (addressBuf == NULL) { |
65c25746 | 2000 | plog(ASL_LEVEL_ERR, "out of memory\n"); |
85f41bec A |
2001 | CFRelease(addresses); |
2002 | CFRelease(certificate); | |
e8d9021d A |
2003 | return -1; |
2004 | } | |
85f41bec | 2005 | if (CFStringGetCString(address, addressBuf, ADDRESS_BUF_SIZE, kCFStringEncodingUTF8) == TRUE) { |
e8d9021d A |
2006 | result = inet_pton(idtype == IPSECDOI_ID_IPV4_ADDR ? AF_INET : AF_INET6, addressBuf, numAddress); |
2007 | racoon_free(addressBuf); | |
2008 | if (result == 0) | |
2009 | continue; // wrong type or invalid address | |
85f41bec | 2010 | if (!memcmp(id, numAddress, idtype == IPSECDOI_ID_IPV4_ADDR ? 32 : 128) == 0) { // found a match ? |
e8d9021d A |
2011 | CFRelease(addresses); |
2012 | CFRelease(certificate); | |
2013 | return 0; | |
2014 | } | |
2015 | } else | |
2016 | racoon_free(addressBuf); | |
2017 | } | |
65c25746 A |
2018 | plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); |
2019 | plog(ASL_LEVEL_ERR, | |
e8d9021d | 2020 | "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); |
65c25746 | 2021 | plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); |
e8d9021d A |
2022 | CFRelease(addresses); |
2023 | CFRelease(certificate); | |
2024 | if (certStatus && !*certStatus) { | |
2025 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2026 | } | |
2027 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
2028 | #else | |
52b7d2ce A |
2029 | /* |
2030 | * Openssl returns the IPAddress as an ASN1 octet string (binary format) | |
2031 | * followed by a trailing NULL. 5 bytes for IPv4 and 17 bytes for IPv6 | |
2032 | */ | |
2033 | #define SUBJ_ALT_NAME_IPV4_ADDRESS_LEN 5 | |
2034 | #define SUBJ_ALT_NAME_IPV6_ADDRESS_LEN 17 | |
2035 | ||
2036 | int pos; | |
2037 | ||
65c25746 A |
2038 | if ((idtype == IPSECDOI_ID_IPV4_ADDR && idlen != sizeof(struct in_addr)) |
2039 | || (idtype == IPSECDOI_ID_IPV6_ADDR && idlen != sizeof(struct in6_addr))) { | |
2040 | plog(ASL_LEVEL_ERR, | |
52b7d2ce A |
2041 | "invalid address length passed.\n"); |
2042 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
2043 | } | |
2044 | ||
2045 | for (pos = 1; ; pos++) { | |
e8d9021d | 2046 | if (eay_get_x509subjectaltname(cert, &altname, &type, pos, &len) !=0) { |
65c25746 | 2047 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 2048 | "failed to get subjectAltName\n"); |
e8d9021d A |
2049 | if (certStatus && !*certStatus) { |
2050 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2051 | } | |
52b7d2ce A |
2052 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
2053 | } | |
2054 | ||
2055 | /* it's the end condition of the loop. */ | |
2056 | if (!altname) { | |
65c25746 | 2057 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2058 | "invalid subjectAltName\n"); |
2059 | if (certStatus && !*certStatus) { | |
2060 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2061 | } | |
52b7d2ce A |
2062 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; |
2063 | } | |
2064 | ||
2065 | if (check_typeofcertname(idtype, type) != 0) { | |
2066 | /* wrong type - skip this one */ | |
2067 | racoon_free(altname); | |
2068 | altname = NULL; | |
2069 | continue; | |
2070 | } | |
2071 | ||
2072 | if (len == SUBJ_ALT_NAME_IPV4_ADDRESS_LEN) { /* IPv4 */ | |
2073 | if (idtype != IPSECDOI_ID_IPV4_ADDR) { | |
2074 | /* wrong IP address type - skip this one */ | |
2075 | racoon_free(altname); | |
2076 | altname = NULL; | |
2077 | continue; | |
2078 | } | |
2079 | } | |
2080 | #ifdef INET6 | |
2081 | else if (len == SUBJ_ALT_NAME_IPV6_ADDRESS_LEN) { /* IPv6 */ | |
2082 | if (idtype != IPSECDOI_ID_IPV6_ADDR) { | |
2083 | /* wrong IP address type - skip this one */ | |
2084 | racoon_free(altname); | |
2085 | altname = NULL; | |
2086 | continue; | |
2087 | } | |
2088 | } | |
2089 | #endif | |
2090 | else { | |
2091 | /* invalid IP address length in certificate - bad or bogus certificate */ | |
65c25746 | 2092 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 2093 | "invalid IP address in certificate.\n"); |
65c25746 A |
2094 | plogdump(ASL_LEVEL_ERR, altname, len, "subjectAltName (expected type %s, got type %s):\n", |
2095 | s_ipsecdoi_ident(idtype), | |
2096 | s_ipsecdoi_ident(type)); | |
52b7d2ce A |
2097 | racoon_free(altname); |
2098 | altname = NULL; | |
e8d9021d A |
2099 | if (certStatus && !*certStatus) { |
2100 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2101 | } | |
52b7d2ce A |
2102 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
2103 | } | |
2104 | ||
2105 | /* compare the addresses */ | |
2106 | error = memcmp(id, altname, idlen); | |
e8d9021d | 2107 | if (error) |
52b7d2ce | 2108 | continue; |
52b7d2ce | 2109 | racoon_free(altname); |
52b7d2ce | 2110 | return 0; |
e8d9021d A |
2111 | } |
2112 | /* failed to find a match */ | |
65c25746 | 2113 | plog(ASL_LEVEL_ERR, |
e8d9021d | 2114 | "ID mismatched with subjectAltName.\n"); |
65c25746 A |
2115 | plogdump(ASL_LEVEL_ERR, altname, len, "subjectAltName (expected type %s, got type %s):\n", |
2116 | s_ipsecdoi_ident(idtype), | |
2117 | s_ipsecdoi_ident(type)); | |
2118 | plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); | |
e8d9021d A |
2119 | racoon_free(altname); |
2120 | if (certStatus && !*certStatus) | |
2121 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
52b7d2ce | 2122 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; |
e8d9021d A |
2123 | |
2124 | #endif /* TARGET_OS_EMBEDDED */ | |
52b7d2ce A |
2125 | } |
2126 | ||
e8d9021d A |
2127 | #if TARGET_OS_EMBEDDED |
2128 | case IPSECDOI_ID_FQDN: | |
2129 | { | |
2130 | CFIndex pos, count; | |
2131 | SecCertificateRef certificate; | |
2132 | CFArrayRef names; | |
2133 | CFStringRef name, ID; | |
2134 | ||
65c25746 | 2135 | certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); |
e8d9021d | 2136 | if (certificate == NULL) { |
65c25746 | 2137 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2138 | "failed to get SecCertificateRef\n"); |
2139 | if (certStatus && !*certStatus) { | |
2140 | *certStatus = CERT_STATUS_INVALID; | |
2141 | } | |
52b7d2ce A |
2142 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
2143 | } | |
e8d9021d A |
2144 | names = SecCertificateCopyDNSNames(certificate); |
2145 | if (names == NULL) { | |
65c25746 | 2146 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2147 | "failed to get subjectName\n"); |
2148 | if (certStatus && !*certStatus) { | |
2149 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2150 | } | |
2151 | CFRelease(certificate); | |
2152 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; | |
52b7d2ce | 2153 | } |
e8d9021d | 2154 | count = CFArrayGetCount(names); |
65c25746 | 2155 | ID = CFStringCreateWithBytes(kCFAllocatorDefault, id, idlen, kCFStringEncodingUTF8, FALSE); |
e8d9021d | 2156 | if (ID== NULL) { |
65c25746 | 2157 | plog(ASL_LEVEL_ERR, "memory error\n"); |
e8d9021d A |
2158 | CFRelease(names); |
2159 | CFRelease(certificate); | |
65c25746 | 2160 | return 0; |
52b7d2ce | 2161 | } |
e8d9021d A |
2162 | for (pos = 0; pos < count; pos++) { |
2163 | name = CFArrayGetValueAtIndex(names, pos); | |
2164 | if (CFStringCompare(name, ID, 0) == kCFCompareEqualTo) { | |
2165 | CFRelease(ID); | |
2166 | CFRelease(names); | |
2167 | CFRelease(certificate); | |
2168 | return 0; | |
52b7d2ce | 2169 | } |
52b7d2ce | 2170 | } |
65c25746 A |
2171 | plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); |
2172 | plog(ASL_LEVEL_ERR, | |
e8d9021d | 2173 | "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); |
65c25746 | 2174 | plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); |
e8d9021d A |
2175 | CFRelease(ID); |
2176 | CFRelease(names); | |
2177 | CFRelease(certificate); | |
2178 | if (certStatus && !*certStatus) { | |
2179 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2180 | } | |
2181 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
2182 | } | |
2183 | ||
2184 | case IPSECDOI_ID_USER_FQDN: | |
2185 | { | |
2186 | CFIndex pos, count; | |
2187 | ||
2188 | SecCertificateRef certificate; | |
2189 | CFArrayRef names; | |
2190 | CFStringRef name, ID; | |
2191 | ||
65c25746 | 2192 | certificate = crypto_cssm_x509cert_CreateSecCertificateRef(cert); |
e8d9021d | 2193 | if (certificate == NULL) { |
65c25746 | 2194 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2195 | "failed to get SecCertificateRef\n"); |
2196 | if (certStatus && !*certStatus) { | |
2197 | *certStatus = CERT_STATUS_INVALID; | |
2198 | } | |
52b7d2ce A |
2199 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
2200 | } | |
e8d9021d A |
2201 | names = SecCertificateCopyRFC822Names(certificate); |
2202 | if (names == NULL) { | |
65c25746 | 2203 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2204 | "failed to get subjectName\n"); |
2205 | if (certStatus && !*certStatus) { | |
2206 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2207 | } | |
2208 | CFRelease(certificate); | |
52b7d2ce A |
2209 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
2210 | } | |
e8d9021d | 2211 | count = CFArrayGetCount(names); |
65c25746 | 2212 | ID = CFStringCreateWithBytes(kCFAllocatorDefault, id, idlen, kCFStringEncodingUTF8, FALSE); |
e8d9021d | 2213 | if (ID == NULL) { |
65c25746 | 2214 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2215 | "memory error\n"); |
2216 | if (certStatus && !*certStatus) { | |
2217 | *certStatus = CERT_STATUS_INVALID; | |
2218 | } | |
2219 | CFRelease(names); | |
2220 | CFRelease(certificate); | |
2221 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; | |
2222 | } | |
2223 | for (pos = 0; pos < count; pos++) { | |
2224 | name = CFArrayGetValueAtIndex(names, pos); | |
2225 | if (CFStringCompare(name, ID, 0) == kCFCompareEqualTo) { | |
2226 | CFRelease(ID); | |
2227 | CFRelease(names); | |
2228 | CFRelease(certificate); | |
2229 | return 0; | |
2230 | } | |
52b7d2ce | 2231 | } |
65c25746 A |
2232 | plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); |
2233 | plog(ASL_LEVEL_ERR, | |
e8d9021d | 2234 | "subjectAltName (expected type %s):\n", s_ipsecdoi_ident(idtype)); |
65c25746 | 2235 | plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); |
e8d9021d A |
2236 | CFRelease(ID); |
2237 | CFRelease(names); | |
2238 | CFRelease(certificate); | |
2239 | if (certStatus && !*certStatus) { | |
2240 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2241 | } | |
2242 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
52b7d2ce | 2243 | } |
e8d9021d | 2244 | #else |
52b7d2ce A |
2245 | case IPSECDOI_ID_FQDN: |
2246 | case IPSECDOI_ID_USER_FQDN: | |
2247 | { | |
2248 | int pos; | |
2249 | ||
2250 | for (pos = 1; ; pos++) { | |
e8d9021d | 2251 | if (eay_get_x509subjectaltname(cert, &altname, &type, pos, &len) != 0) { |
65c25746 | 2252 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 2253 | "failed to get subjectAltName\n"); |
e8d9021d A |
2254 | if (certStatus && !*certStatus) { |
2255 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2256 | } | |
52b7d2ce A |
2257 | return ISAKMP_NTYPE_INVALID_CERTIFICATE; |
2258 | } | |
2259 | ||
2260 | /* it's the end condition of the loop. */ | |
2261 | if (!altname) { | |
65c25746 | 2262 | plog(ASL_LEVEL_ERR, |
e8d9021d A |
2263 | "invalid subjectAltName\n"); |
2264 | if (certStatus && !*certStatus) { | |
2265 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2266 | } | |
2267 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
52b7d2ce A |
2268 | } |
2269 | ||
e8d9021d A |
2270 | if (check_typeofcertname(idtype, type) != 0) { |
2271 | /* wrong general type - skip this one */ | |
2272 | racoon_free(altname); | |
2273 | altname = NULL; | |
2274 | continue; | |
2275 | } | |
52b7d2ce | 2276 | |
e8d9021d A |
2277 | if (idlen != strlen(altname)) { |
2278 | /* wrong length - skip this one */ | |
2279 | racoon_free(altname); | |
2280 | altname = NULL; | |
2281 | continue; | |
2282 | } | |
2283 | error = memcmp(id, altname, idlen); | |
2284 | if (error) | |
2285 | continue; | |
52b7d2ce | 2286 | racoon_free(altname); |
e8d9021d | 2287 | return 0; |
52b7d2ce | 2288 | } |
65c25746 A |
2289 | plog(ASL_LEVEL_ERR, "ID mismatched with subjectAltName.\n"); |
2290 | plog(ASL_LEVEL_ERR, | |
e8d9021d A |
2291 | "subjectAltName (expected type %s, got type %s):\n", |
2292 | s_ipsecdoi_ident(idtype), | |
2293 | s_ipsecdoi_ident(type)); | |
65c25746 A |
2294 | plogdump(ASL_LEVEL_ERR, altname, len, "subjectAltName (expected type %s, got type %s):\n", |
2295 | s_ipsecdoi_ident(idtype), | |
2296 | s_ipsecdoi_ident(type)); | |
2297 | plogdump(ASL_LEVEL_ERR, id, idlen, "ID:\n"); | |
52b7d2ce | 2298 | racoon_free(altname); |
e8d9021d A |
2299 | if (certStatus && !*certStatus) |
2300 | *certStatus = CERT_STATUS_INVALID_SUBJALTNAME; | |
2301 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; | |
52b7d2ce | 2302 | } |
e8d9021d | 2303 | #endif |
52b7d2ce | 2304 | default: |
65c25746 | 2305 | plog(ASL_LEVEL_ERR, |
52b7d2ce | 2306 | "Impropper ID type passed: %s.\n", |
e8d9021d | 2307 | s_ipsecdoi_ident(idtype)); |
52b7d2ce | 2308 | return ISAKMP_NTYPE_INVALID_ID_INFORMATION; |
e8d9021d | 2309 | } |
52b7d2ce A |
2310 | /*NOTREACHED*/ |
2311 | } | |
e8d9021d | 2312 | #ifdef HAVE_OPENSSL |
52b7d2ce | 2313 | static int |
65c25746 | 2314 | check_typeofcertname(int doi, int genid) |
52b7d2ce A |
2315 | { |
2316 | switch (doi) { | |
2317 | case IPSECDOI_ID_IPV4_ADDR: | |
2318 | case IPSECDOI_ID_IPV4_ADDR_SUBNET: | |
2319 | case IPSECDOI_ID_IPV6_ADDR: | |
2320 | case IPSECDOI_ID_IPV6_ADDR_SUBNET: | |
2321 | case IPSECDOI_ID_IPV4_ADDR_RANGE: | |
2322 | case IPSECDOI_ID_IPV6_ADDR_RANGE: | |
2323 | if (genid != GENT_IPADD) | |
2324 | return -1; | |
2325 | return 0; | |
2326 | case IPSECDOI_ID_FQDN: | |
2327 | if (genid != GENT_DNS) | |
2328 | return -1; | |
2329 | return 0; | |
2330 | case IPSECDOI_ID_USER_FQDN: | |
2331 | if (genid != GENT_EMAIL) | |
2332 | return -1; | |
2333 | return 0; | |
2334 | case IPSECDOI_ID_DER_ASN1_DN: /* should not be passed to this function*/ | |
2335 | case IPSECDOI_ID_DER_ASN1_GN: | |
2336 | case IPSECDOI_ID_KEY_ID: | |
2337 | default: | |
2338 | return -1; | |
2339 | } | |
2340 | /*NOTREACHED*/ | |
2341 | } | |
e8d9021d | 2342 | #endif |
52b7d2ce A |
2343 | |
2344 | /* | |
2345 | * save certificate including certificate type. | |
2346 | */ | |
2347 | int | |
65c25746 | 2348 | oakley_savecert(phase1_handle_t *iph1, struct isakmp_gen *gen) |
52b7d2ce A |
2349 | { |
2350 | cert_t **c; | |
2351 | u_int8_t type; | |
52b7d2ce A |
2352 | type = *(u_int8_t *)(gen + 1) & 0xff; |
2353 | ||
2354 | switch (type) { | |
52b7d2ce | 2355 | case ISAKMP_CERT_X509SIGN: |
52b7d2ce A |
2356 | c = &iph1->cert_p; |
2357 | break; | |
52b7d2ce | 2358 | default: |
65c25746 | 2359 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2360 | "Invalid CERT type %d\n", type); |
2361 | return -1; | |
2362 | } | |
2363 | ||
52b7d2ce | 2364 | if (*c) { |
65c25746 | 2365 | plog(ASL_LEVEL_WARNING, |
e8d9021d | 2366 | "preexisting CERT payload... chaining.\n"); |
52b7d2ce | 2367 | } |
52b7d2ce | 2368 | |
65c25746 A |
2369 | cert_t *new; |
2370 | new = save_certbuf(gen); | |
2371 | if (!new) { | |
2372 | plog(ASL_LEVEL_ERR, | |
2373 | "Failed to get CERT buffer.\n"); | |
2374 | return -1; | |
2375 | } | |
52b7d2ce | 2376 | |
65c25746 A |
2377 | switch (new->type) { |
2378 | case ISAKMP_CERT_X509SIGN: | |
2379 | /* Ignore cert if it doesn't match identity | |
2380 | * XXX If verify cert is disabled, we still just take | |
2381 | * the first certificate.... | |
2382 | */ | |
2383 | *c = oakley_appendcert_to_certchain(*c, new); | |
2384 | plog(ASL_LEVEL_DEBUG, "CERT saved:\n"); | |
2385 | break; | |
2386 | default: | |
2387 | /* XXX */ | |
2388 | oakley_delcert(new); | |
2389 | return 0; | |
2390 | } | |
52b7d2ce A |
2391 | |
2392 | return 0; | |
2393 | } | |
2394 | ||
2395 | /* | |
2396 | * save certificate including certificate type. | |
2397 | */ | |
2398 | int | |
65c25746 | 2399 | oakley_savecr(phase1_handle_t *iph1, struct isakmp_gen *gen) |
52b7d2ce A |
2400 | { |
2401 | cert_t **c; | |
2402 | u_int8_t type; | |
e8d9021d | 2403 | cert_t *new; |
52b7d2ce A |
2404 | |
2405 | type = *(u_int8_t *)(gen + 1) & 0xff; | |
2406 | ||
2407 | switch (type) { | |
52b7d2ce | 2408 | case ISAKMP_CERT_X509SIGN: |
e97d2cf9 A |
2409 | if (iph1->cr_p) { |
2410 | oakley_delcert(iph1->cr_p); | |
2411 | iph1->cr_p = NULL; | |
2412 | } | |
52b7d2ce A |
2413 | c = &iph1->cr_p; |
2414 | break; | |
52b7d2ce | 2415 | default: |
65c25746 | 2416 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2417 | "Invalid CR type %d\n", type); |
2418 | return -1; | |
2419 | } | |
2420 | ||
e8d9021d A |
2421 | new = save_certbuf(gen); |
2422 | if (!new) { | |
65c25746 | 2423 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2424 | "Failed to get CR buffer.\n"); |
2425 | return -1; | |
2426 | } | |
e8d9021d | 2427 | *c = oakley_appendcert_to_certchain(*c, new); |
65c25746 | 2428 | plog(ASL_LEVEL_DEBUG, "CR saved\n"); |
52b7d2ce A |
2429 | |
2430 | return 0; | |
2431 | } | |
2432 | ||
2433 | static cert_t * | |
65c25746 | 2434 | save_certbuf(struct isakmp_gen *gen) |
52b7d2ce A |
2435 | { |
2436 | cert_t *new; | |
2437 | ||
d1e348cf | 2438 | if(ntohs(gen->len) <= sizeof(*gen)){ |
65c25746 | 2439 | plog(ASL_LEVEL_ERR, |
d1e348cf A |
2440 | "Len is too small !!.\n"); |
2441 | return NULL; | |
2442 | } | |
2443 | ||
52b7d2ce A |
2444 | new = oakley_newcert(); |
2445 | if (!new) { | |
65c25746 | 2446 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2447 | "Failed to get CERT buffer.\n"); |
2448 | return NULL; | |
2449 | } | |
2450 | ||
2451 | new->pl = vmalloc(ntohs(gen->len) - sizeof(*gen)); | |
2452 | if (new->pl == NULL) { | |
65c25746 | 2453 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2454 | "Failed to copy CERT from packet.\n"); |
2455 | oakley_delcert(new); | |
2456 | new = NULL; | |
2457 | return NULL; | |
2458 | } | |
2459 | memcpy(new->pl->v, gen + 1, new->pl->l); | |
2460 | new->type = new->pl->v[0] & 0xff; | |
2461 | new->cert.v = new->pl->v + 1; | |
2462 | new->cert.l = new->pl->l - 1; | |
2463 | ||
2464 | return new; | |
2465 | } | |
2466 | ||
52b7d2ce A |
2467 | /* |
2468 | * get my CR. | |
2469 | * NOTE: No Certificate Authority field is included to CR payload at the | |
2470 | * moment. Becuase any certificate authority are accepted without any check. | |
2471 | * The section 3.10 in RFC2408 says that this field SHOULD not be included, | |
2472 | * if there is no specific certificate authority requested. | |
2473 | */ | |
2474 | vchar_t * | |
65c25746 | 2475 | oakley_getcr(phase1_handle_t *iph1) |
52b7d2ce A |
2476 | { |
2477 | vchar_t *buf; | |
2478 | ||
2479 | buf = vmalloc(1); | |
2480 | if (buf == NULL) { | |
65c25746 | 2481 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2482 | "failed to get cr buffer\n"); |
2483 | return NULL; | |
2484 | } | |
d1e348cf A |
2485 | if(iph1->rmconf->certtype == ISAKMP_CERT_NONE) { |
2486 | buf->v[0] = iph1->rmconf->cacerttype; | |
65c25746 | 2487 | plog(ASL_LEVEL_DEBUG, "create my CR: NONE, using %s instead\n", |
d1e348cf A |
2488 | s_isakmp_certtype(iph1->rmconf->cacerttype)); |
2489 | } else { | |
2490 | buf->v[0] = iph1->rmconf->certtype; | |
65c25746 | 2491 | plog(ASL_LEVEL_DEBUG, "create my CR: %s\n", |
52b7d2ce | 2492 | s_isakmp_certtype(iph1->rmconf->certtype)); |
d1e348cf | 2493 | } |
65c25746 A |
2494 | //if (buf->l > 1) |
2495 | // plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, ""); | |
52b7d2ce A |
2496 | |
2497 | return buf; | |
2498 | } | |
2499 | ||
2500 | /* | |
2501 | * check peer's CR. | |
2502 | */ | |
2503 | int | |
65c25746 | 2504 | oakley_checkcr(phase1_handle_t *iph1) |
52b7d2ce A |
2505 | { |
2506 | if (iph1->cr_p == NULL) | |
2507 | return 0; | |
2508 | ||
65c25746 | 2509 | plog(ASL_LEVEL_DEBUG, |
52b7d2ce A |
2510 | "peer transmitted CR: %s\n", |
2511 | s_isakmp_certtype(iph1->cr_p->type)); | |
2512 | ||
2513 | if (iph1->cr_p->type != iph1->rmconf->certtype) { | |
65c25746 | 2514 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2515 | "such a cert type isn't supported: %d\n", |
2516 | (char)iph1->cr_p->type); | |
2517 | return -1; | |
2518 | } | |
2519 | ||
2520 | return 0; | |
2521 | } | |
2522 | ||
2523 | /* | |
2524 | * check to need CR payload. | |
2525 | */ | |
2526 | int | |
65c25746 | 2527 | oakley_needcr(int type) |
52b7d2ce A |
2528 | { |
2529 | switch (type) { | |
52b7d2ce A |
2530 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: |
2531 | #ifdef ENABLE_HYBRID | |
2532 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: | |
d1e348cf A |
2533 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: |
2534 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: | |
52b7d2ce A |
2535 | #endif |
2536 | return 1; | |
2537 | default: | |
2538 | return 0; | |
2539 | } | |
2540 | /*NOTREACHED*/ | |
2541 | } | |
2542 | ||
85f41bec | 2543 | vchar_t * |
65c25746 | 2544 | oakley_getpskall(phase1_handle_t *iph1) |
85f41bec A |
2545 | { |
2546 | vchar_t *secret = NULL; | |
2547 | ||
2548 | if (iph1->rmconf->shared_secret) { | |
2549 | ||
2550 | switch (iph1->rmconf->secrettype) { | |
2551 | case SECRETTYPE_KEY: | |
2552 | /* in psk file - use KEY from remote configuration to locate it */ | |
2553 | secret = getpsk(iph1->rmconf->shared_secret->v, iph1->rmconf->shared_secret->l-1); | |
2554 | break; | |
2555 | #if HAVE_KEYCHAIN | |
2556 | case SECRETTYPE_KEYCHAIN: | |
2557 | /* in the system keychain */ | |
2558 | secret = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, NULL); | |
2559 | break; | |
2560 | case SECRETTYPE_KEYCHAIN_BY_ID: | |
2561 | /* in the system keychain - use peer id */ | |
2562 | secret = getpskfromkeychain(iph1->rmconf->shared_secret->v, iph1->etype, iph1->rmconf->secrettype, iph1->id_p); | |
2563 | break; | |
2564 | #endif // HAVE_KEYCHAIN | |
2565 | case SECRETTYPE_USE: | |
2566 | /* in the remote configuration */ | |
2567 | default: | |
2568 | /* rmconf->shared_secret is a string and contains a NULL character that must be removed */ | |
2569 | secret = vmalloc(iph1->rmconf->shared_secret->l - 1); | |
2570 | if (secret == NULL) { | |
65c25746 | 2571 | plog(ASL_LEVEL_ERR, "memory error.\n"); |
85f41bec A |
2572 | goto end; |
2573 | } | |
2574 | memcpy(secret->v, iph1->rmconf->shared_secret->v, secret->l); | |
2575 | } | |
65c25746 A |
2576 | } else if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV2 || |
2577 | iph1->etype != ISAKMP_ETYPE_IDENT) { | |
85f41bec A |
2578 | secret = getpskbyname(iph1->id_p); |
2579 | if (!secret) { | |
2580 | if (iph1->rmconf->verify_identifier) { | |
65c25746 | 2581 | plog(ASL_LEVEL_ERR, "couldn't find pskey by peer's ID.\n"); |
85f41bec A |
2582 | goto end; |
2583 | } | |
2584 | } | |
2585 | } | |
2586 | if (!secret) { | |
65c25746 | 2587 | plog(ASL_LEVEL_NOTICE, "try to get pskey by the peer's address.\n"); |
85f41bec | 2588 | secret = getpskbyaddr(iph1->remote); |
65c25746 A |
2589 | if (!secret) { |
2590 | plog(ASL_LEVEL_ERR, | |
2591 | "couldn't find the pskey by address %s.\n", | |
2592 | saddrwop2str((struct sockaddr *)iph1->remote)); | |
2593 | } | |
85f41bec A |
2594 | } |
2595 | ||
2596 | end: | |
2597 | return secret; | |
2598 | } | |
2599 | ||
52b7d2ce A |
2600 | /* |
2601 | * compute SKEYID | |
2602 | * see seciton 5. Exchanges in RFC 2409 | |
2603 | * psk: SKEYID = prf(pre-shared-key, Ni_b | Nr_b) | |
2604 | * sig: SKEYID = prf(Ni_b | Nr_b, g^ir) | |
2605 | * enc: SKEYID = prf(H(Ni_b | Nr_b), CKY-I | CKY-R) | |
2606 | */ | |
2607 | int | |
65c25746 | 2608 | oakley_skeyid(phase1_handle_t *iph1) |
52b7d2ce | 2609 | { |
65c25746 A |
2610 | vchar_t *key = NULL; |
2611 | vchar_t *buf = NULL; | |
2612 | vchar_t *bp; | |
52b7d2ce A |
2613 | char *p; |
2614 | int len; | |
2615 | int error = -1; | |
65c25746 A |
2616 | |
2617 | ||
52b7d2ce | 2618 | /* SKEYID */ |
d1e348cf | 2619 | switch (AUTHMETHOD(iph1)) { |
65c25746 | 2620 | case OAKLEY_ATTR_AUTH_METHOD_PSKEY: |
d1e348cf | 2621 | #ifdef ENABLE_HYBRID |
65c25746 A |
2622 | case FICTIVE_AUTH_METHOD_XAUTH_PSKEY_I: |
2623 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_PSKEY_R: | |
d1e348cf | 2624 | #endif |
65c25746 A |
2625 | key = oakley_getpskall(iph1); |
2626 | if (key == NULL) { | |
2627 | plog(ASL_LEVEL_ERR, | |
2628 | "couldn't find the pskey for %s.\n", | |
2629 | saddrwop2str((struct sockaddr *)iph1->remote)); | |
2630 | goto end; | |
2631 | } | |
2632 | plog(ASL_LEVEL_DEBUG, "the psk found.\n"); | |
2633 | /* should be secret PSK */ | |
2634 | plogdump(ASL_LEVEL_DEBUG, key->v, key->l, "psk: "); | |
2635 | ||
2636 | len = iph1->nonce->l + iph1->nonce_p->l; | |
2637 | buf = vmalloc(len); | |
2638 | if (buf == NULL) { | |
2639 | plog(ASL_LEVEL_ERR, | |
2640 | "failed to get skeyid buffer\n"); | |
2641 | goto end; | |
2642 | } | |
2643 | p = buf->v; | |
2644 | ||
2645 | bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); | |
2646 | //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce 1: "); | |
2647 | memcpy(p, bp->v, bp->l); | |
2648 | p += bp->l; | |
2649 | ||
2650 | bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); | |
2651 | //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce 2: "); | |
2652 | memcpy(p, bp->v, bp->l); | |
2653 | p += bp->l; | |
2654 | ||
2655 | iph1->skeyid = oakley_prf(key, buf, iph1); | |
2656 | ||
2657 | if (iph1->skeyid == NULL) | |
2658 | goto end; | |
2659 | break; | |
2660 | ||
2661 | case OAKLEY_ATTR_AUTH_METHOD_RSASIG: | |
52b7d2ce | 2662 | #ifdef ENABLE_HYBRID |
65c25746 A |
2663 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_I: |
2664 | case OAKLEY_ATTR_AUTH_METHOD_HYBRID_RSA_R: | |
2665 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_I: | |
2666 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSASIG_R: | |
52b7d2ce | 2667 | #endif |
65c25746 A |
2668 | len = iph1->nonce->l + iph1->nonce_p->l; |
2669 | buf = vmalloc(len); | |
2670 | if (buf == NULL) { | |
2671 | plog(ASL_LEVEL_ERR, | |
2672 | "failed to get nonce buffer\n"); | |
2673 | goto end; | |
2674 | } | |
2675 | p = buf->v; | |
2676 | ||
2677 | bp = (iph1->side == INITIATOR ? iph1->nonce : iph1->nonce_p); | |
2678 | //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce1: "); | |
2679 | memcpy(p, bp->v, bp->l); | |
2680 | p += bp->l; | |
2681 | ||
2682 | bp = (iph1->side == INITIATOR ? iph1->nonce_p : iph1->nonce); | |
2683 | //plogdump(ASL_LEVEL_DEBUG, bp->v, bp->l, "nonce2: "); | |
2684 | memcpy(p, bp->v, bp->l); | |
2685 | p += bp->l; | |
2686 | ||
2687 | iph1->skeyid = oakley_prf(buf, iph1->dhgxy, iph1); | |
2688 | if (iph1->skeyid == NULL) | |
2689 | goto end; | |
2690 | break; | |
2691 | case OAKLEY_ATTR_AUTH_METHOD_RSAENC: | |
2692 | case OAKLEY_ATTR_AUTH_METHOD_RSAREV: | |
d1e348cf | 2693 | #ifdef ENABLE_HYBRID |
65c25746 A |
2694 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_I: |
2695 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAENC_R: | |
2696 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_I: | |
2697 | case OAKLEY_ATTR_AUTH_METHOD_XAUTH_RSAREV_R: | |
d1e348cf | 2698 | #endif |
65c25746 A |
2699 | plog(ASL_LEVEL_WARNING, |
2700 | "not supported authentication method %s\n", | |
2701 | s_oakley_attr_method(iph1->approval->authmethod)); | |
2702 | goto end; | |
2703 | default: | |
2704 | plog(ASL_LEVEL_ERR, | |
2705 | "invalid authentication method %d\n", | |
2706 | iph1->approval->authmethod); | |
2707 | goto end; | |
52b7d2ce | 2708 | } |
65c25746 A |
2709 | |
2710 | //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid->v, iph1->skeyid->l, "IKEv1 SKEYID computed:\n"); | |
2711 | ||
52b7d2ce | 2712 | error = 0; |
65c25746 | 2713 | |
52b7d2ce | 2714 | end: |
65c25746 A |
2715 | if (key != NULL) |
2716 | vfree(key); | |
52b7d2ce A |
2717 | if (buf != NULL) |
2718 | vfree(buf); | |
2719 | return error; | |
2720 | } | |
2721 | ||
65c25746 A |
2722 | static vchar_t * |
2723 | oakley_prf_plus (vchar_t *key, vchar_t *buf, int result_len, phase1_handle_t *iph1) | |
2724 | { | |
2725 | vchar_t *t = 0; | |
2726 | uint8_t byte_value; | |
2727 | vchar_t *result = 0; | |
2728 | uint8_t *p; | |
2729 | vchar_t *bp; | |
2730 | int bp_len; | |
2731 | uint8_t *tmp; | |
2732 | vchar_t *prf; | |
2733 | ||
2734 | /* | |
2735 | * (draft-17) | |
2736 | prf+ (K,S) = T1 | T2 | T3 | T4 | ... | |
2737 | ||
2738 | where: | |
2739 | T1 = prf (K, S | 0x01) | |
2740 | T2 = prf (K, T1 | S | 0x02) | |
2741 | T3 = prf (K, T2 | S | 0x03) | |
2742 | T4 = prf (K, T3 | S | 0x04) | |
2743 | */ | |
2744 | ||
2745 | if (!(result = vmalloc(result_len))) { | |
2746 | return NULL; | |
2747 | } | |
2748 | ||
2749 | /* | |
2750 | * initial T0 = empty | |
2751 | */ | |
2752 | t = 0; | |
2753 | p = (uint8_t *)result->v; | |
2754 | for (byte_value = 1; result_len > 0; ++byte_value) { | |
2755 | /* | |
2756 | * prf_output = prf(K, Ti-1 | S | byte) | |
2757 | */ | |
2758 | bp_len = buf->l + sizeof(byte_value); | |
2759 | if (t) { | |
2760 | bp_len += t->l; | |
2761 | } | |
2762 | bp = vmalloc(bp_len); | |
2763 | if (!bp) { | |
2764 | return NULL; | |
2765 | } | |
2766 | tmp = (__typeof__(tmp))bp->v; | |
2767 | ||
2768 | if (t) { | |
2769 | memcpy(tmp, t->v, t->l); | |
2770 | tmp += t->l; | |
2771 | } | |
2772 | memcpy(tmp, buf->v, buf->l); | |
2773 | tmp += buf->l; | |
2774 | memcpy(tmp, &byte_value, sizeof(byte_value)); | |
2775 | tmp += sizeof(byte_value); | |
2776 | ||
2777 | if (!(prf = oakley_prf(key, bp, iph1))) { | |
2778 | VPTRINIT(bp); | |
2779 | return (vchar_t *)-1; | |
2780 | } | |
2781 | VPTRINIT(bp); | |
2782 | ||
2783 | /* | |
2784 | * concat prf_output | |
2785 | */ | |
2786 | memcpy(p, prf->v, prf->l > (size_t)result_len ? (size_t)result_len : prf->l); | |
2787 | p += prf->l; | |
2788 | result_len -= prf->l; | |
2789 | ||
2790 | /* | |
2791 | * Ti = prf_output | |
2792 | */ | |
2793 | if (t) { | |
2794 | bzero(t->v, t->l); | |
2795 | vfree(t); | |
2796 | } | |
2797 | t = prf; | |
2798 | } | |
2799 | if (t) { | |
2800 | bzero(t->v, t->l); | |
2801 | vfree(t); | |
2802 | } | |
2803 | return result; | |
2804 | } | |
2805 | ||
52b7d2ce A |
2806 | /* |
2807 | * compute SKEYID_[dae] | |
52b7d2ce A |
2808 | */ |
2809 | int | |
65c25746 | 2810 | oakley_skeyid_dae(phase1_handle_t *iph1) |
52b7d2ce | 2811 | { |
65c25746 | 2812 | vchar_t *buf = NULL, *bp = NULL; |
52b7d2ce A |
2813 | char *p; |
2814 | int len; | |
2815 | int error = -1; | |
2816 | ||
2817 | if (iph1->skeyid == NULL) { | |
65c25746 | 2818 | plog(ASL_LEVEL_ERR, "no SKEYID found.\n"); |
52b7d2ce A |
2819 | goto end; |
2820 | } | |
65c25746 A |
2821 | /* |
2822 | * see seciton 5. Exchanges in RFC 2409 | |
2823 | * SKEYID_d = prf(SKEYID, g^ir | CKY-I | CKY-R | 0) | |
2824 | * SKEYID_a = prf(SKEYID, SKEYID_d | g^ir | CKY-I | CKY-R | 1) | |
2825 | * SKEYID_e = prf(SKEYID, SKEYID_a | g^ir | CKY-I | CKY-R | 2) | |
2826 | */ | |
52b7d2ce A |
2827 | /* SKEYID D */ |
2828 | /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ | |
2829 | len = iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; | |
2830 | buf = vmalloc(len); | |
2831 | if (buf == NULL) { | |
65c25746 | 2832 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2833 | "failed to get skeyid buffer\n"); |
2834 | goto end; | |
2835 | } | |
2836 | p = buf->v; | |
2837 | ||
2838 | memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); | |
2839 | p += iph1->dhgxy->l; | |
2840 | memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); | |
2841 | p += sizeof(cookie_t); | |
2842 | memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); | |
2843 | p += sizeof(cookie_t); | |
2844 | *p = 0; | |
2845 | iph1->skeyid_d = oakley_prf(iph1->skeyid, buf, iph1); | |
2846 | if (iph1->skeyid_d == NULL) | |
2847 | goto end; | |
2848 | ||
2849 | vfree(buf); | |
2850 | buf = NULL; | |
2851 | ||
65c25746 | 2852 | //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid_d->v, iph1->skeyid_d->l, "SKEYID_d computed:\n"); |
52b7d2ce A |
2853 | |
2854 | /* SKEYID A */ | |
2855 | /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ | |
2856 | len = iph1->skeyid_d->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; | |
2857 | buf = vmalloc(len); | |
2858 | if (buf == NULL) { | |
65c25746 | 2859 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2860 | "failed to get skeyid buffer\n"); |
2861 | goto end; | |
2862 | } | |
2863 | p = buf->v; | |
2864 | memcpy(p, iph1->skeyid_d->v, iph1->skeyid_d->l); | |
2865 | p += iph1->skeyid_d->l; | |
2866 | memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); | |
2867 | p += iph1->dhgxy->l; | |
2868 | memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); | |
2869 | p += sizeof(cookie_t); | |
2870 | memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); | |
2871 | p += sizeof(cookie_t); | |
2872 | *p = 1; | |
2873 | iph1->skeyid_a = oakley_prf(iph1->skeyid, buf, iph1); | |
2874 | if (iph1->skeyid_a == NULL) | |
2875 | goto end; | |
2876 | ||
2877 | vfree(buf); | |
2878 | buf = NULL; | |
2879 | ||
65c25746 | 2880 | //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid_a->v, iph1->skeyid_a->l, "SKEYID_a computed:\n"); |
52b7d2ce A |
2881 | |
2882 | /* SKEYID E */ | |
2883 | /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ | |
2884 | len = iph1->skeyid_a->l + iph1->dhgxy->l + sizeof(cookie_t) * 2 + 1; | |
2885 | buf = vmalloc(len); | |
2886 | if (buf == NULL) { | |
65c25746 | 2887 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2888 | "failed to get skeyid buffer\n"); |
2889 | goto end; | |
2890 | } | |
2891 | p = buf->v; | |
2892 | memcpy(p, iph1->skeyid_a->v, iph1->skeyid_a->l); | |
2893 | p += iph1->skeyid_a->l; | |
2894 | memcpy(p, iph1->dhgxy->v, iph1->dhgxy->l); | |
2895 | p += iph1->dhgxy->l; | |
2896 | memcpy(p, (caddr_t)&iph1->index.i_ck, sizeof(cookie_t)); | |
2897 | p += sizeof(cookie_t); | |
2898 | memcpy(p, (caddr_t)&iph1->index.r_ck, sizeof(cookie_t)); | |
2899 | p += sizeof(cookie_t); | |
2900 | *p = 2; | |
2901 | iph1->skeyid_e = oakley_prf(iph1->skeyid, buf, iph1); | |
2902 | if (iph1->skeyid_e == NULL) | |
2903 | goto end; | |
2904 | ||
2905 | vfree(buf); | |
2906 | buf = NULL; | |
2907 | ||
65c25746 | 2908 | //plogdump(ASL_LEVEL_DEBUG, iph1->skeyid_e->v, iph1->skeyid_e->l, "SKEYID_e computed:\n"); |
52b7d2ce A |
2909 | |
2910 | error = 0; | |
2911 | ||
2912 | end: | |
2913 | if (buf != NULL) | |
2914 | vfree(buf); | |
2915 | return error; | |
2916 | } | |
2917 | ||
2918 | /* | |
2919 | * compute final encryption key. | |
2920 | * see Appendix B. | |
2921 | */ | |
2922 | int | |
65c25746 | 2923 | oakley_compute_enckey(phase1_handle_t *iph1) |
52b7d2ce A |
2924 | { |
2925 | u_int keylen, prflen; | |
2926 | int error = -1; | |
2927 | ||
2928 | /* RFC2409 p39 */ | |
2929 | keylen = alg_oakley_encdef_keylen(iph1->approval->enctype, | |
2930 | iph1->approval->encklen); | |
2931 | if (keylen == -1) { | |
65c25746 | 2932 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2933 | "invalid encryption algoritym %d, " |
2934 | "or invalid key length %d.\n", | |
2935 | iph1->approval->enctype, | |
2936 | iph1->approval->encklen); | |
2937 | goto end; | |
2938 | } | |
2939 | iph1->key = vmalloc(keylen >> 3); | |
2940 | if (iph1->key == NULL) { | |
65c25746 | 2941 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2942 | "failed to get key buffer\n"); |
2943 | goto end; | |
2944 | } | |
65c25746 A |
2945 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV2) { |
2946 | iph1->key_p = vmalloc(keylen >> 3); | |
2947 | if (iph1->key_p == NULL) { | |
2948 | plog(ASL_LEVEL_ERR, | |
2949 | "failed to get key buffer\n"); | |
2950 | goto end; | |
2951 | } | |
2952 | ||
2953 | if (iph1->key->l <= iph1->skeyid_e->l) { | |
2954 | plog(ASL_LEVEL_DEBUG, | |
2955 | "%s setting key len %zd, val %d (len %zd)", __FUNCTION__, iph1->key->l, (int)iph1->skeyid_e->v[0], iph1->skeyid_e->l); | |
2956 | /* | |
2957 | * if length(Ka) <= length(SKEYID_e) | |
2958 | * Ka = first length(K) bit of SKEYID_e | |
2959 | */ | |
2960 | memcpy(iph1->key->v, iph1->skeyid_e->v, iph1->key->l); | |
2961 | } else { | |
2962 | plog(ASL_LEVEL_ERR, | |
2963 | "unexpected key length error (exp %zd, got %zd)", | |
2964 | iph1->key->l, iph1->skeyid_e->l); | |
2965 | goto end; | |
2966 | } | |
2967 | if (iph1->key_p->l <= iph1->skeyid_e_p->l) { | |
2968 | plog(ASL_LEVEL_DEBUG, | |
2969 | "%s setting peer key len %zd, val %d (len %zd)", __FUNCTION__, iph1->key_p->l, (int)iph1->skeyid_e_p->v[0], iph1->skeyid_e_p->l); | |
2970 | /* | |
2971 | * if length(Ka) <= length(SKEYID_e) | |
2972 | * Ka = first length(K) bit of SKEYID_e | |
2973 | */ | |
2974 | memcpy(iph1->key_p->v, iph1->skeyid_e_p->v, iph1->key_p->l); | |
2975 | } else { | |
2976 | plog(ASL_LEVEL_ERR, | |
2977 | "unexpected peer key length error (exp %zd, got %zd)", | |
2978 | iph1->key_p->l, iph1->skeyid_e_p->l); | |
2979 | goto end; | |
2980 | } | |
2981 | } | |
52b7d2ce A |
2982 | |
2983 | /* set prf length */ | |
2984 | prflen = alg_oakley_hashdef_hashlen(iph1->approval->hashtype); | |
2985 | if (prflen == -1) { | |
65c25746 | 2986 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
2987 | "invalid hash type %d.\n", iph1->approval->hashtype); |
2988 | goto end; | |
2989 | } | |
2990 | ||
2991 | /* see isakmp-oakley-08 5.3. */ | |
2992 | if (iph1->key->l <= iph1->skeyid_e->l) { | |
2993 | /* | |
2994 | * if length(Ka) <= length(SKEYID_e) | |
2995 | * Ka = first length(K) bit of SKEYID_e | |
2996 | */ | |
2997 | memcpy(iph1->key->v, iph1->skeyid_e->v, iph1->key->l); | |
2998 | } else { | |
2999 | vchar_t *buf = NULL, *res = NULL; | |
3000 | u_char *p, *ep; | |
3001 | int cplen; | |
3002 | int subkey; | |
3003 | ||
65c25746 A |
3004 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV2) { |
3005 | plog(ASL_LEVEL_ERR, | |
3006 | "invalid key len (got %zu, expected %zu.\n", iph1->key->l, iph1->skeyid_e->l); | |
3007 | goto end; | |
3008 | } | |
3009 | ||
52b7d2ce A |
3010 | /* |
3011 | * otherwise, | |
3012 | * Ka = K1 | K2 | K3 | |
3013 | * where | |
3014 | * K1 = prf(SKEYID_e, 0) | |
3015 | * K2 = prf(SKEYID_e, K1) | |
3016 | * K3 = prf(SKEYID_e, K2) | |
3017 | */ | |
65c25746 | 3018 | plog(ASL_LEVEL_DEBUG, |
52b7d2ce A |
3019 | "len(SKEYID_e) < len(Ka) (%zu < %zu), " |
3020 | "generating long key (Ka = K1 | K2 | ...)\n", | |
3021 | iph1->skeyid_e->l, iph1->key->l); | |
3022 | ||
3023 | if ((buf = vmalloc(prflen >> 3)) == 0) { | |
65c25746 | 3024 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
3025 | "failed to get key buffer\n"); |
3026 | goto end; | |
3027 | } | |
3028 | p = (u_char *)iph1->key->v; | |
3029 | ep = p + iph1->key->l; | |
3030 | ||
3031 | subkey = 1; | |
3032 | while (p < ep) { | |
3033 | if (p == (u_char *)iph1->key->v) { | |
3034 | /* just for computing K1 */ | |
3035 | buf->v[0] = 0; | |
3036 | buf->l = 1; | |
3037 | } | |
3038 | res = oakley_prf(iph1->skeyid_e, buf, iph1); | |
3039 | if (res == NULL) { | |
3040 | vfree(buf); | |
3041 | goto end; | |
3042 | } | |
65c25746 | 3043 | plog(ASL_LEVEL_DEBUG, |
52b7d2ce A |
3044 | "compute intermediate encryption key K%d\n", |
3045 | subkey); | |
65c25746 A |
3046 | //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, ""); |
3047 | //plogdump(ASL_LEVEL_DEBUG, res->v, res->l, ""); | |
52b7d2ce A |
3048 | |
3049 | cplen = (res->l < ep - p) ? res->l : ep - p; | |
3050 | memcpy(p, res->v, cplen); | |
3051 | p += cplen; | |
3052 | ||
3053 | buf->l = prflen >> 3; /* to cancel K1 speciality */ | |
3054 | if (res->l != buf->l) { | |
65c25746 | 3055 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
3056 | "internal error: res->l=%zu buf->l=%zu\n", |
3057 | res->l, buf->l); | |
3058 | vfree(res); | |
3059 | vfree(buf); | |
3060 | goto end; | |
3061 | } | |
3062 | memcpy(buf->v, res->v, res->l); | |
3063 | vfree(res); | |
3064 | subkey++; | |
3065 | } | |
3066 | ||
3067 | vfree(buf); | |
3068 | } | |
3069 | ||
3070 | /* | |
3071 | * don't check any weak key or not. | |
3072 | * draft-ietf-ipsec-ike-01.txt Appendix B. | |
3073 | * draft-ietf-ipsec-ciph-aes-cbc-00.txt Section 2.3. | |
3074 | */ | |
52b7d2ce | 3075 | |
65c25746 | 3076 | //plogdump(ASL_LEVEL_DEBUG, iph1->key->v, iph1->key->l, "final encryption key computed:\n"); |
52b7d2ce A |
3077 | |
3078 | error = 0; | |
3079 | ||
3080 | end: | |
3081 | return error; | |
3082 | } | |
3083 | ||
3084 | /* allocated new buffer for CERT */ | |
3085 | cert_t * | |
65c25746 | 3086 | oakley_newcert(void) |
52b7d2ce A |
3087 | { |
3088 | cert_t *new; | |
3089 | ||
3090 | new = racoon_calloc(1, sizeof(*new)); | |
3091 | if (new == NULL) { | |
65c25746 | 3092 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
3093 | "failed to get cert's buffer\n"); |
3094 | return NULL; | |
3095 | } | |
3096 | ||
3097 | new->pl = NULL; | |
e8d9021d | 3098 | new->chain = NULL; |
52b7d2ce A |
3099 | |
3100 | return new; | |
3101 | } | |
3102 | ||
3103 | /* delete buffer for CERT */ | |
3104 | void | |
65c25746 | 3105 | oakley_delcert_1(cert_t *cert) |
52b7d2ce A |
3106 | { |
3107 | if (!cert) | |
3108 | return; | |
3109 | if (cert->pl) | |
3110 | VPTRINIT(cert->pl); | |
3111 | racoon_free(cert); | |
3112 | } | |
e8d9021d A |
3113 | |
3114 | /* delete buffer for CERT */ | |
3115 | void | |
65c25746 | 3116 | oakley_delcert(cert_t *cert) |
e8d9021d A |
3117 | { |
3118 | cert_t *p, *to_delete; | |
3119 | ||
3120 | if (!cert) | |
3121 | return; | |
3122 | ||
3123 | for (p = cert; p;) { | |
3124 | to_delete = p; | |
3125 | p = p->chain; | |
3126 | oakley_delcert_1(to_delete); | |
3127 | } | |
3128 | } | |
3129 | ||
3130 | /* delete buffer for CERT */ | |
3131 | static cert_t * | |
65c25746 | 3132 | oakley_appendcert_to_certchain(cert_t *certchain, cert_t *new) |
e8d9021d A |
3133 | { |
3134 | cert_t *p; | |
3135 | ||
3136 | if (!certchain) | |
3137 | return new; | |
3138 | ||
3139 | for (p = certchain; p; p = p->chain) { | |
3140 | if (!p->chain) { | |
3141 | p->chain = new; | |
3142 | return certchain; | |
3143 | } | |
3144 | } | |
3145 | return NULL; | |
3146 | } | |
3147 | ||
52b7d2ce A |
3148 | /* |
3149 | * compute IV and set to ph1handle | |
3150 | * IV = hash(g^xi | g^xr) | |
3151 | * see 4.1 Phase 1 state in draft-ietf-ipsec-ike. | |
3152 | */ | |
3153 | int | |
65c25746 | 3154 | oakley_newiv(phase1_handle_t *iph1) |
52b7d2ce A |
3155 | { |
3156 | struct isakmp_ivm *newivm = NULL; | |
3157 | vchar_t *buf = NULL, *bp; | |
3158 | char *p; | |
3159 | int len; | |
3160 | ||
3161 | /* create buffer */ | |
3162 | len = iph1->dhpub->l + iph1->dhpub_p->l; | |
3163 | buf = vmalloc(len); | |
3164 | if (buf == NULL) { | |
65c25746 A |
3165 | plog(ASL_LEVEL_ERR, |
3166 | "Failed to get IV buffer\n"); | |
52b7d2ce A |
3167 | return -1; |
3168 | } | |
3169 | ||
3170 | p = buf->v; | |
3171 | ||
3172 | bp = (iph1->side == INITIATOR ? iph1->dhpub : iph1->dhpub_p); | |
3173 | memcpy(p, bp->v, bp->l); | |
3174 | p += bp->l; | |
3175 | ||
3176 | bp = (iph1->side == INITIATOR ? iph1->dhpub_p : iph1->dhpub); | |
3177 | memcpy(p, bp->v, bp->l); | |
3178 | p += bp->l; | |
3179 | ||
3180 | /* allocate IVm */ | |
3181 | newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); | |
3182 | if (newivm == NULL) { | |
65c25746 A |
3183 | plog(ASL_LEVEL_ERR, |
3184 | "Failed to get IV buffer\n"); | |
52b7d2ce A |
3185 | vfree(buf); |
3186 | return -1; | |
3187 | } | |
3188 | ||
3189 | /* compute IV */ | |
3190 | newivm->iv = oakley_hash(buf, iph1); | |
3191 | if (newivm->iv == NULL) { | |
3192 | vfree(buf); | |
3193 | oakley_delivm(newivm); | |
3194 | return -1; | |
3195 | } | |
3196 | ||
3197 | /* adjust length of iv */ | |
3198 | newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); | |
3199 | if (newivm->iv->l == -1) { | |
65c25746 A |
3200 | plog(ASL_LEVEL_ERR, |
3201 | "Invalid encryption algorithm %d.\n", | |
52b7d2ce A |
3202 | iph1->approval->enctype); |
3203 | vfree(buf); | |
3204 | oakley_delivm(newivm); | |
3205 | return -1; | |
3206 | } | |
3207 | ||
3208 | /* create buffer to save iv */ | |
3209 | if ((newivm->ive = vdup(newivm->iv)) == NULL) { | |
65c25746 | 3210 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
3211 | "vdup (%s)\n", strerror(errno)); |
3212 | vfree(buf); | |
3213 | oakley_delivm(newivm); | |
3214 | return -1; | |
3215 | } | |
3216 | ||
3217 | vfree(buf); | |
3218 | ||
65c25746 | 3219 | //plogdump(ASL_LEVEL_DEBUG, newivm->iv->v, newivm->iv->l, "IV computed:\n"); |
52b7d2ce | 3220 | |
d1e348cf A |
3221 | if (iph1->ivm != NULL) |
3222 | oakley_delivm(iph1->ivm); | |
3223 | ||
52b7d2ce A |
3224 | iph1->ivm = newivm; |
3225 | ||
3226 | return 0; | |
3227 | } | |
3228 | ||
3229 | /* | |
3230 | * compute IV for the payload after phase 1. | |
3231 | * It's not limited for phase 2. | |
3232 | * if pahse 1 was encrypted. | |
3233 | * IV = hash(last CBC block of Phase 1 | M-ID) | |
3234 | * if phase 1 was not encrypted. | |
3235 | * IV = hash(phase 1 IV | M-ID) | |
3236 | * see 4.2 Phase 2 state in draft-ietf-ipsec-ike. | |
3237 | */ | |
3238 | struct isakmp_ivm * | |
65c25746 | 3239 | oakley_newiv2(phase1_handle_t *iph1, u_int32_t msgid) |
52b7d2ce A |
3240 | { |
3241 | struct isakmp_ivm *newivm = NULL; | |
3242 | vchar_t *buf = NULL; | |
3243 | char *p; | |
3244 | int len; | |
3245 | int error = -1; | |
3246 | ||
3247 | /* create buffer */ | |
3248 | len = iph1->ivm->iv->l + sizeof(msgid_t); | |
3249 | buf = vmalloc(len); | |
3250 | if (buf == NULL) { | |
65c25746 A |
3251 | plog(ASL_LEVEL_ERR, |
3252 | "Failed to get IV buffer\n"); | |
52b7d2ce A |
3253 | goto end; |
3254 | } | |
3255 | ||
3256 | p = buf->v; | |
3257 | ||
3258 | memcpy(p, iph1->ivm->iv->v, iph1->ivm->iv->l); | |
3259 | p += iph1->ivm->iv->l; | |
3260 | ||
3261 | memcpy(p, &msgid, sizeof(msgid)); | |
3262 | ||
65c25746 A |
3263 | plog(ASL_LEVEL_DEBUG, "Compute IV for Phase 2\n"); |
3264 | //plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "Phase 1 last IV:\n"); | |
52b7d2ce A |
3265 | |
3266 | /* allocate IVm */ | |
3267 | newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); | |
3268 | if (newivm == NULL) { | |
65c25746 A |
3269 | plog(ASL_LEVEL_ERR, |
3270 | "Failed to get IV buffer\n"); | |
52b7d2ce A |
3271 | goto end; |
3272 | } | |
3273 | ||
3274 | /* compute IV */ | |
3275 | if ((newivm->iv = oakley_hash(buf, iph1)) == NULL) | |
3276 | goto end; | |
3277 | ||
3278 | /* adjust length of iv */ | |
3279 | newivm->iv->l = alg_oakley_encdef_blocklen(iph1->approval->enctype); | |
3280 | if (newivm->iv->l == -1) { | |
65c25746 A |
3281 | plog(ASL_LEVEL_ERR, |
3282 | "Invalid encryption algorithm %d.\n", | |
52b7d2ce A |
3283 | iph1->approval->enctype); |
3284 | goto end; | |
3285 | } | |
3286 | ||
3287 | /* create buffer to save new iv */ | |
3288 | if ((newivm->ive = vdup(newivm->iv)) == NULL) { | |
65c25746 | 3289 | plog(ASL_LEVEL_ERR, "vdup (%s)\n", strerror(errno)); |
52b7d2ce A |
3290 | goto end; |
3291 | } | |
3292 | ||
3293 | error = 0; | |
3294 | ||
65c25746 | 3295 | //plogdump(ASL_LEVEL_DEBUG, newivm->iv->v, newivm->iv->l, "Phase 2 IV computed:\n"); |
52b7d2ce A |
3296 | |
3297 | end: | |
3298 | if (error && newivm != NULL){ | |
3299 | oakley_delivm(newivm); | |
3300 | newivm=NULL; | |
3301 | } | |
3302 | if (buf != NULL) | |
3303 | vfree(buf); | |
3304 | return newivm; | |
3305 | } | |
3306 | ||
65c25746 A |
3307 | /* |
3308 | * Compute unpredictable IV for IKEv2. | |
3309 | */ | |
3310 | int | |
3311 | oakley_newiv_ikev2(phase1_handle_t * iph1) | |
3312 | { | |
3313 | struct isakmp_ivm *newivm = NULL; | |
3314 | int iv_length; | |
3315 | ||
3316 | /* Get IV length */ | |
3317 | iv_length = alg_oakley_encdef_blocklen(iph1->approval->enctype); | |
3318 | if (iv_length == -1) { | |
3319 | plog(ASL_LEVEL_ERR, "Invalid encryption algorithm %d.\n", iph1->approval->enctype); | |
3320 | } | |
3321 | ||
3322 | /* Allocate IV Manager */ | |
3323 | newivm = racoon_calloc(1, sizeof(struct isakmp_ivm)); | |
3324 | if (newivm == NULL) { | |
3325 | plog(ASL_LEVEL_ERR, "Failed to allocate IV buffer.\n"); | |
3326 | return -1; | |
3327 | } | |
3328 | ||
3329 | /* Compute IV */ | |
3330 | /* There are two recommended methods for generating unpredictable IVs. The first method is to apply the forward cipher function, under the same key that is used for the encryption of the plaintext, to a nonce. The nonce must be a data block that is unique to each execution of the encryption operation. For example, the nonce may be a counter, as described in Appendix B, or a message number. The second method is to generate a random data block using a FIPS- approved random number generator. | |
3331 | [National Institute of Standards and Technology, U.S. | |
3332 | Department of Commerce, "Recommendation for Block Cipher | |
3333 | Modes of Operation", SP 800-38A, 2001.] | |
3334 | */ | |
3335 | /* Currently, we implement the second scheme, which uses a random block */ | |
3336 | newivm->iv = eay_set_random(iv_length); | |
3337 | if (newivm->iv == NULL) { | |
3338 | oakley_delivm(newivm); | |
3339 | return -1; | |
3340 | } | |
3341 | ||
3342 | /* Adjust length of IV */ | |
3343 | if (newivm->iv->l != iv_length) { | |
3344 | plog(ASL_LEVEL_WARNING, "IV length was adjusted.\n"); | |
3345 | newivm->iv->l = iv_length; | |
3346 | } | |
3347 | ||
3348 | /* Make copy of IV in IVe */ | |
3349 | if ((newivm->ive = vdup(newivm->iv)) == NULL) { | |
3350 | plog(ASL_LEVEL_ERR, "vdup (%s)\n", strerror(errno)); | |
3351 | oakley_delivm(newivm); | |
3352 | return -1; | |
3353 | } | |
3354 | ||
3355 | /* Delete old IV if there is one */ | |
3356 | if (iph1->ivm != NULL) | |
3357 | oakley_delivm(iph1->ivm); | |
3358 | ||
3359 | iph1->ivm = newivm; | |
3360 | ||
3361 | return 0; | |
3362 | } | |
3363 | ||
3364 | ||
52b7d2ce | 3365 | void |
65c25746 | 3366 | oakley_delivm(struct isakmp_ivm *ivm) |
52b7d2ce A |
3367 | { |
3368 | if (ivm == NULL) | |
3369 | return; | |
3370 | ||
3371 | if (ivm->iv != NULL) | |
3372 | vfree(ivm->iv); | |
3373 | if (ivm->ive != NULL) | |
3374 | vfree(ivm->ive); | |
3375 | racoon_free(ivm); | |
65c25746 | 3376 | plog(ASL_LEVEL_DEBUG, "IV freed\n"); |
52b7d2ce A |
3377 | |
3378 | return; | |
3379 | } | |
3380 | ||
3381 | /* | |
3382 | * decrypt packet. | |
3383 | * save new iv and old iv. | |
3384 | */ | |
3385 | vchar_t * | |
65c25746 | 3386 | oakley_do_ikev1_decrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivdp, vchar_t *ivep) |
52b7d2ce A |
3387 | { |
3388 | vchar_t *buf = NULL, *new = NULL; | |
3389 | char *pl; | |
3390 | int len; | |
3391 | u_int8_t padlen; | |
3392 | int blen; | |
3393 | int error = -1; | |
3394 | ||
65c25746 | 3395 | plog(ASL_LEVEL_DEBUG, "Begin decryption.\n"); |
52b7d2ce A |
3396 | |
3397 | blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); | |
3398 | if (blen == -1) { | |
65c25746 A |
3399 | plog(ASL_LEVEL_ERR, |
3400 | "Invalid encryption algorithm %d.\n", | |
52b7d2ce A |
3401 | iph1->approval->enctype); |
3402 | goto end; | |
3403 | } | |
3404 | ||
3405 | /* save IV for next, but not sync. */ | |
3406 | memset(ivep->v, 0, ivep->l); | |
3407 | memcpy(ivep->v, (caddr_t)&msg->v[msg->l - blen], blen); | |
3408 | ||
65c25746 | 3409 | plogdump(ASL_LEVEL_DEBUG, ivep->v, ivep->l, "IV was saved for next processing:\n"); |
52b7d2ce A |
3410 | |
3411 | pl = msg->v + sizeof(struct isakmp); | |
3412 | ||
3413 | len = msg->l - sizeof(struct isakmp); | |
3414 | ||
3415 | /* create buffer */ | |
3416 | buf = vmalloc(len); | |
3417 | if (buf == NULL) { | |
65c25746 A |
3418 | plog(ASL_LEVEL_ERR, |
3419 | "Failed to get buffer to decrypt.\n"); | |
52b7d2ce A |
3420 | goto end; |
3421 | } | |
3422 | memcpy(buf->v, pl, len); | |
3423 | ||
3424 | /* do decrypt */ | |
3425 | new = alg_oakley_encdef_decrypt(iph1->approval->enctype, | |
3426 | buf, iph1->key, ivdp); | |
47612122 | 3427 | if (new == NULL || new->v == NULL || new->l == 0) { |
65c25746 A |
3428 | plog(ASL_LEVEL_ERR, |
3429 | "Decryption %d failed.\n", iph1->approval->enctype); | |
52b7d2ce A |
3430 | goto end; |
3431 | } | |
65c25746 | 3432 | //plogdump(ASL_LEVEL_DEBUG, iph1->key->v, iph1->key->l, "with key:\n"); |
52b7d2ce A |
3433 | |
3434 | vfree(buf); | |
3435 | buf = NULL; | |
3436 | if (new == NULL) | |
3437 | goto end; | |
3438 | ||
65c25746 | 3439 | plog(ASL_LEVEL_DEBUG, "decrypted payload by IV:\n"); |
52b7d2ce A |
3440 | |
3441 | /* get padding length */ | |
3442 | if (lcconf->pad_excltail) | |
3443 | padlen = new->v[new->l - 1] + 1; | |
3444 | else | |
3445 | padlen = new->v[new->l - 1]; | |
65c25746 | 3446 | plog(ASL_LEVEL_DEBUG, "padding len=%u\n", padlen); |
52b7d2ce A |
3447 | |
3448 | /* trim padding */ | |
3449 | if (lcconf->pad_strict) { | |
3450 | if (padlen > new->l) { | |
65c25746 A |
3451 | plog(ASL_LEVEL_ERR, "invalid padding len=%u, buflen=%zu.\n", |
3452 | padlen, new->l); | |
52b7d2ce A |
3453 | goto end; |
3454 | } | |
3455 | new->l -= padlen; | |
65c25746 | 3456 | plog(ASL_LEVEL_DEBUG, "trimmed padding\n"); |
52b7d2ce | 3457 | } else { |
65c25746 | 3458 | plog(ASL_LEVEL_DEBUG, "skip to trim padding.\n"); |
52b7d2ce A |
3459 | } |
3460 | ||
3461 | /* create new buffer */ | |
3462 | len = sizeof(struct isakmp) + new->l; | |
3463 | buf = vmalloc(len); | |
3464 | if (buf == NULL) { | |
65c25746 | 3465 | plog(ASL_LEVEL_ERR, |
52b7d2ce A |
3466 | "failed to get buffer to decrypt.\n"); |
3467 | goto end; | |
3468 | } | |
3469 | memcpy(buf->v, msg->v, sizeof(struct isakmp)); | |
3470 | memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); | |
3471 | ((struct isakmp *)buf->v)->len = htonl(buf->l); | |
3472 | ||
65c25746 | 3473 | plog(ASL_LEVEL_DEBUG, "decrypted.\n"); |
52b7d2ce A |
3474 | |
3475 | #ifdef HAVE_PRINT_ISAKMP_C | |
3476 | isakmp_printpacket(buf, iph1->remote, iph1->local, 1); | |
3477 | #endif | |
3478 | ||
3479 | error = 0; | |
3480 | ||
3481 | end: | |
3482 | if (error && buf != NULL) { | |
3483 | vfree(buf); | |
3484 | buf = NULL; | |
3485 | } | |
3486 | if (new != NULL) | |
3487 | vfree(new); | |
3488 | ||
3489 | return buf; | |
3490 | } | |
3491 | ||
65c25746 A |
3492 | /* |
3493 | * decrypt packet. | |
3494 | */ | |
3495 | vchar_t * | |
3496 | oakley_do_decrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivdp, vchar_t *ivep) | |
3497 | { | |
3498 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { | |
3499 | return(oakley_do_ikev1_decrypt(iph1, msg, ivdp, ivep)); | |
3500 | } | |
3501 | plog(ASL_LEVEL_ERR, "Failed to decrypt invalid IKE version"); | |
3502 | return NULL; | |
3503 | } | |
3504 | ||
52b7d2ce A |
3505 | /* |
3506 | * encrypt packet. | |
3507 | */ | |
3508 | vchar_t * | |
65c25746 | 3509 | oakley_do_ikev1_encrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivep, vchar_t *ivp) |
52b7d2ce A |
3510 | { |
3511 | vchar_t *buf = 0, *new = 0; | |
3512 | char *pl; | |
3513 | int len; | |
3514 | u_int padlen; | |
3515 | int blen; | |
3516 | int error = -1; | |
3517 | ||
65c25746 | 3518 | plog(ASL_LEVEL_DEBUG, "Begin encryption.\n"); |
52b7d2ce A |
3519 | |
3520 | /* set cbc block length */ | |
3521 | blen = alg_oakley_encdef_blocklen(iph1->approval->enctype); | |
3522 | if (blen == -1) { | |
65c25746 A |
3523 | plog(ASL_LEVEL_ERR, |
3524 | "Invalid encryption algorithm %d.\n", | |
52b7d2ce A |
3525 | iph1->approval->enctype); |
3526 | goto end; | |
3527 | } | |
3528 | ||
3529 | pl = msg->v + sizeof(struct isakmp); | |
3530 | len = msg->l - sizeof(struct isakmp); | |
3531 | ||
3532 | /* add padding */ | |
3533 | padlen = oakley_padlen(len, blen); | |
65c25746 | 3534 | plog(ASL_LEVEL_DEBUG, "pad length = %u\n", padlen); |
52b7d2ce A |
3535 | |
3536 | /* create buffer */ | |
3537 | buf = vmalloc(len + padlen); | |
3538 | if (buf == NULL) { | |
65c25746 A |
3539 | plog(ASL_LEVEL_ERR, |
3540 | "Failed to get buffer to encrypt.\n"); | |
52b7d2ce A |
3541 | goto end; |
3542 | } | |
3543 | if (padlen) { | |
3544 | int i; | |
3545 | char *p = &buf->v[len]; | |
3546 | if (lcconf->pad_random) { | |
3547 | for (i = 0; i < padlen; i++) | |
3548 | *p++ = eay_random() & 0xff; | |
3549 | } | |
3550 | } | |
3551 | memcpy(buf->v, pl, len); | |
3552 | ||
3553 | /* make pad into tail */ | |
3554 | if (lcconf->pad_excltail) | |
3555 | buf->v[len + padlen - 1] = padlen - 1; | |
3556 | else | |
3557 | buf->v[len + padlen - 1] = padlen; | |
3558 | ||
65c25746 | 3559 | plogdump(ASL_LEVEL_DEBUG, buf->v, buf->l, "About to encrypt %d bytes", buf->l); |
52b7d2ce A |
3560 | |
3561 | /* do encrypt */ | |
3562 | new = alg_oakley_encdef_encrypt(iph1->approval->enctype, | |
3563 | buf, iph1->key, ivep); | |
3564 | if (new == NULL) { | |
65c25746 A |
3565 | plog(ASL_LEVEL_ERR, |
3566 | "Encryption %d failed.\n", iph1->approval->enctype); | |
52b7d2ce A |
3567 | goto end; |
3568 | } | |
65c25746 | 3569 | //plogdump(ASL_LEVEL_DEBUG, iph1->key->v, iph1->key->l, "with key:\n"); |
52b7d2ce A |
3570 | |
3571 | vfree(buf); | |
3572 | buf = NULL; | |
3573 | if (new == NULL) | |
3574 | goto end; | |
3575 | ||
65c25746 | 3576 | //plogdump(ASL_LEVEL_DEBUG, ivep->v, ivep->l, "encrypted payload by IV:\n"); |
52b7d2ce A |
3577 | |
3578 | /* save IV for next */ | |
3579 | memset(ivp->v, 0, ivp->l); | |
3580 | memcpy(ivp->v, (caddr_t)&new->v[new->l - blen], blen); | |
3581 | ||
65c25746 | 3582 | //plogdump(ASL_LEVEL_DEBUG, ivp->v, ivp->l, "save IV for next:\n"); |
52b7d2ce A |
3583 | |
3584 | /* create new buffer */ | |
3585 | len = sizeof(struct isakmp) + new->l; | |
3586 | buf = vmalloc(len); | |
3587 | if (buf == NULL) { | |
65c25746 A |
3588 | plog(ASL_LEVEL_ERR, |
3589 | "Failed to get buffer to encrypt.\n"); | |
52b7d2ce A |
3590 | goto end; |
3591 | } | |
3592 | memcpy(buf->v, msg->v, sizeof(struct isakmp)); | |
3593 | memcpy(buf->v + sizeof(struct isakmp), new->v, new->l); | |
3594 | ((struct isakmp *)buf->v)->len = htonl(buf->l); | |
3595 | ||
3596 | error = 0; | |
3597 | ||
65c25746 | 3598 | plog(ASL_LEVEL_DEBUG, "Encrypted.\n"); |
52b7d2ce A |
3599 | |
3600 | end: | |
3601 | if (error && buf != NULL) { | |
3602 | vfree(buf); | |
3603 | buf = NULL; | |
3604 | } | |
3605 | if (new != NULL) | |
3606 | vfree(new); | |
3607 | ||
3608 | return buf; | |
3609 | } | |
3610 | ||
65c25746 A |
3611 | |
3612 | /* | |
3613 | * encrypt packet. | |
3614 | */ | |
3615 | vchar_t * | |
3616 | oakley_do_encrypt(phase1_handle_t *iph1, vchar_t *msg, vchar_t *ivep, vchar_t *ivp) | |
3617 | { | |
3618 | if (iph1->version == ISAKMP_VERSION_NUMBER_IKEV1) { | |
3619 | return(oakley_do_ikev1_encrypt(iph1, msg, ivep, ivp)); | |
3620 | } | |
3621 | plog(ASL_LEVEL_ERR, "Failed to encrypt invalid IKE version"); | |
3622 | return NULL; | |
3623 | } | |
3624 | ||
52b7d2ce A |
3625 | /* culculate padding length */ |
3626 | static int | |
65c25746 | 3627 | oakley_padlen(int len, int base) |
52b7d2ce A |
3628 | { |
3629 | int padlen; | |
3630 | ||
65c25746 | 3631 | padlen = base - (len % base); |
52b7d2ce A |
3632 | |
3633 | if (lcconf->pad_randomlen) | |
3634 | padlen += ((eay_random() % (lcconf->pad_maxsize + 1) + 1) * | |
3635 | base); | |
3636 | ||
3637 | return padlen; | |
3638 | } | |
3639 | ||
52b7d2ce A |
3640 | /* ----------------------------------------------------------------------------- |
3641 | The base-64 encoding packs three 8-bit bytes into four 7-bit ASCII | |
3642 | characters. If the number of bytes in the original data isn't divisable | |
3643 | by three, "=" characters are used to pad the encoded data. The complete | |
3644 | set of characters used in base-64 are: | |
3645 | 'A'..'Z' => 00..25 | |
3646 | 'a'..'z' => 26..51 | |
3647 | '0'..'9' => 52..61 | |
3648 | '+' => 62 | |
3649 | '/' => 63 | |
3650 | '=' => pad | |
3651 | ||
3652 | ----------------------------------------------------------------------------- */ | |
3653 | static const signed char base64_DecodeTable[128] = { | |
3654 | /* 000 */ -1, -1, -1, -1, -1, -1, -1, -1, | |
3655 | /* 010 */ -1, -1, -1, -1, -1, -1, -1, -1, | |
3656 | /* 020 */ -1, -1, -1, -1, -1, -1, -1, -1, | |
3657 | /* 030 */ -1, -1, -1, -1, -1, -1, -1, -1, | |
3658 | /* ' ' */ -1, -1, -1, -1, -1, -1, -1, -1, | |
3659 | /* '(' */ -1, -1, -1, 62, -1, -1, -1, 63, | |
3660 | /* '0' */ 52, 53, 54, 55, 56, 57, 58, 59, | |
3661 | /* '8' */ 60, 61, -1, -1, -1, 0, -1, -1, | |
3662 | /* '@' */ -1, 0, 1, 2, 3, 4, 5, 6, | |
3663 | /* 'H' */ 7, 8, 9, 10, 11, 12, 13, 14, | |
3664 | /* 'P' */ 15, 16, 17, 18, 19, 20, 21, 22, | |
3665 | /* 'X' */ 23, 24, 25, -1, -1, -1, -1, -1, | |
3666 | /* '`' */ -1, 26, 27, 28, 29, 30, 31, 32, | |
3667 | /* 'h' */ 33, 34, 35, 36, 37, 38, 39, 40, | |
3668 | /* 'p' */ 41, 42, 43, 44, 45, 46, 47, 48, | |
3669 | /* 'x' */ 49, 50, 51, -1, -1, -1, -1, -1 | |
3670 | }; | |
3671 | ||
3672 | static int base64toCFData(vchar_t *textin, CFDataRef *dataRef) | |
3673 | { | |
3674 | uint8_t *tmpbuf; | |
3675 | uint8_t c; | |
3676 | int tmpbufpos = 0; | |
3677 | int numeq = 0; | |
3678 | int acc = 0; | |
3679 | int cntr = 0; | |
65c25746 | 3680 | uint8_t *textcur = (__typeof__(textcur))textin->v; |
52b7d2ce A |
3681 | int len = textin->l; |
3682 | int i; | |
3683 | ||
3684 | tmpbuf = malloc(len); // len of result will be less than encoded len | |
3685 | if (tmpbuf == NULL) { | |
3686 | yyerror("memory error - could not allocate buffer for certificate reference conversion from base-64."); | |
3687 | return -1; | |
3688 | } | |
3689 | ||
3690 | for (i = 0; i < len; i++) { | |
3691 | c = *(textcur++); | |
3692 | if (c == '=') | |
3693 | numeq++; | |
3694 | else if (!isspace(c)) | |
3695 | numeq = 0; | |
3696 | if (base64_DecodeTable[c] < 0) | |
3697 | continue; | |
3698 | cntr++; | |
3699 | acc <<= 6; | |
3700 | acc += base64_DecodeTable[c]; | |
3701 | if (0 == (cntr & 0x3)) { | |
3702 | tmpbuf[tmpbufpos++] = (acc >> 16) & 0xff; | |
3703 | if (numeq < 2) | |
3704 | tmpbuf[tmpbufpos++] = (acc >> 8) & 0xff; | |
3705 | if (numeq < 1) | |
3706 | tmpbuf[tmpbufpos++] = acc & 0xff; | |
3707 | } | |
3708 | } | |
3709 | *dataRef = CFDataCreate(NULL, tmpbuf, tmpbufpos); | |
3710 | free(tmpbuf); | |
3711 | if (*dataRef) | |
3712 | return 0; | |
3713 | else | |
3714 | return -1; | |
3715 | ||
3716 | } | |
e8d9021d | 3717 |