1 /* $KAME: gssapi.c,v 1.18 2001/03/05 23:36:31 thorpej Exp $ */
4 * Copyright 2000 Wasabi Systems, Inc.
7 * This software was written by Frank van der Linden of Wasabi Systems
8 * for Zembu Labs, Inc. http://www.zembu.com/
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Wasabi Systems for
21 * Zembu Labs, Inc. http://www.zembu.com/
22 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23 * or promote products derived from this software without specific prior
26 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/types.h>
41 #include <sys/queue.h>
42 #include <sys/socket.h>
57 #include "localconf.h"
58 #include "remoteconf.h"
59 #include "isakmp_var.h"
63 #include "ipsec_doi.h"
64 #include "crypto_openssl.h"
66 #include "isakmp_ident.h"
67 #include "isakmp_inf.h"
74 gssapi_error(OM_uint32 status_code
, const char *where
,
77 OM_uint32 message_context
, maj_stat
, min_stat
;
78 gss_buffer_desc status_string
;
82 plogv(LLV_ERROR
, where
, NULL
, fmt
, ap
);
88 maj_stat
= gss_display_status(&min_stat
, status_code
,
89 GSS_C_MECH_CODE
, GSS_C_NO_OID
, &message_context
,
91 if (GSS_ERROR(maj_stat
))
92 plog(LLV_ERROR
, LOCATION
, NULL
,
93 "UNABLE TO GET GSSAPI ERROR CODE\n");
95 plog(LLV_ERROR
, where
, NULL
,
96 "%s\n", status_string
.value
);
97 gss_release_buffer(&min_stat
, &status_string
);
99 } while (message_context
!= 0);
103 * vmbufs and gss_buffer_descs are really just the same on NetBSD, but
104 * this is to be portable.
107 gssapi_vm2gssbuf(vchar_t
*vmbuf
, gss_buffer_t gsstoken
)
110 gsstoken
->value
= racoon_malloc(vmbuf
->l
);
111 if (gsstoken
->value
== NULL
)
113 memcpy(gsstoken
->value
, vmbuf
->v
, vmbuf
->l
);
114 gsstoken
->length
= vmbuf
->l
;
120 gssapi_gss2vmbuf(gss_buffer_t gsstoken
, vchar_t
**vmbuf
)
123 *vmbuf
= vmalloc(gsstoken
->length
);
126 memcpy((*vmbuf
)->v
, gsstoken
->value
, gsstoken
->length
);
127 (*vmbuf
)->l
= gsstoken
->length
;
133 gssapi_get_default_name(struct ph1handle
*iph1
, int remote
, gss_name_t
*service
)
135 char name
[NI_MAXHOST
];
137 gss_buffer_desc name_token
;
138 OM_uint32 min_stat
, maj_stat
;
140 sa
= remote
? iph1
->remote
: iph1
->local
;
142 if (getnameinfo(sa
, sa
->sa_len
, name
, NI_MAXHOST
, NULL
, 0, 0) != 0)
145 name_token
.length
= asprintf((char **)&name_token
.value
,
146 "%s@%s", GSSAPI_DEF_NAME
, name
);
147 maj_stat
= gss_import_name(&min_stat
, &name_token
,
148 GSS_C_NT_HOSTBASED_SERVICE
, service
);
149 if (GSS_ERROR(maj_stat
)) {
150 gssapi_error(min_stat
, LOCATION
, "import name\n");
151 maj_stat
= gss_release_buffer(&min_stat
, &name_token
);
152 if (GSS_ERROR(maj_stat
))
153 gssapi_error(min_stat
, LOCATION
, "release name_token");
156 maj_stat
= gss_release_buffer(&min_stat
, &name_token
);
157 if (GSS_ERROR(maj_stat
))
158 gssapi_error(min_stat
, LOCATION
, "release name_token");
164 gssapi_init(struct ph1handle
*iph1
)
166 struct gssapi_ph1_state
*gps
;
167 gss_buffer_desc id_token
, cred_token
;
168 gss_buffer_t cred
= &cred_token
;
169 gss_name_t princ
, canon_princ
;
170 OM_uint32 maj_stat
, min_stat
;
172 gps
= racoon_calloc(1, sizeof (struct gssapi_ph1_state
));
174 plog(LLV_ERROR
, LOCATION
, NULL
, "racoon_calloc failed\n");
177 gps
->gss_context
= GSS_C_NO_CONTEXT
;
178 gps
->gss_cred
= GSS_C_NO_CREDENTIAL
;
180 gssapi_set_state(iph1
, gps
);
182 if (iph1
->rmconf
->proposal
->gssid
!= NULL
) {
183 id_token
.length
= iph1
->rmconf
->proposal
->gssid
->l
;
184 id_token
.value
= iph1
->rmconf
->proposal
->gssid
->v
;
185 maj_stat
= gss_import_name(&min_stat
, &id_token
, GSS_C_NO_OID
,
187 if (GSS_ERROR(maj_stat
)) {
188 gssapi_error(min_stat
, LOCATION
, "import name\n");
189 gssapi_free_state(iph1
);
193 gssapi_get_default_name(iph1
, 0, &princ
);
195 maj_stat
= gss_canonicalize_name(&min_stat
, princ
, GSS_C_NO_OID
,
197 if (GSS_ERROR(maj_stat
)) {
198 gssapi_error(min_stat
, LOCATION
, "canonicalize name\n");
199 maj_stat
= gss_release_name(&min_stat
, &princ
);
200 if (GSS_ERROR(maj_stat
))
201 gssapi_error(min_stat
, LOCATION
, "release princ\n");
202 gssapi_free_state(iph1
);
205 maj_stat
= gss_release_name(&min_stat
, &princ
);
206 if (GSS_ERROR(maj_stat
))
207 gssapi_error(min_stat
, LOCATION
, "release princ\n");
209 maj_stat
= gss_export_name(&min_stat
, canon_princ
, cred
);
210 if (GSS_ERROR(maj_stat
)) {
211 gssapi_error(min_stat
, LOCATION
, "export name\n");
212 maj_stat
= gss_release_name(&min_stat
, &canon_princ
);
213 if (GSS_ERROR(maj_stat
))
214 gssapi_error(min_stat
, LOCATION
,
215 "release canon_princ\n");
216 gssapi_free_state(iph1
);
220 plog(LLV_DEBUG
, LOCATION
, NULL
, "will try to acquire '%*s' creds\n",
221 cred
->length
, cred
->value
);
222 maj_stat
= gss_release_buffer(&min_stat
, cred
);
223 if (GSS_ERROR(maj_stat
))
224 gssapi_error(min_stat
, LOCATION
, "release cred buffer\n");
226 maj_stat
= gss_acquire_cred(&min_stat
, canon_princ
, GSS_C_INDEFINITE
,
227 GSS_C_NO_OID_SET
, GSS_C_BOTH
, &gps
->gss_cred
, NULL
, NULL
);
228 if (GSS_ERROR(maj_stat
)) {
229 gssapi_error(min_stat
, LOCATION
, "acquire cred\n");
230 maj_stat
= gss_release_name(&min_stat
, &canon_princ
);
231 if (GSS_ERROR(maj_stat
))
232 gssapi_error(min_stat
, LOCATION
,
233 "release canon_princ\n");
234 gssapi_free_state(iph1
);
237 maj_stat
= gss_release_name(&min_stat
, &canon_princ
);
238 if (GSS_ERROR(maj_stat
))
239 gssapi_error(min_stat
, LOCATION
, "release canon_princ\n");
245 gssapi_get_itoken(struct ph1handle
*iph1
, int *lenp
)
247 struct gssapi_ph1_state
*gps
;
248 gss_buffer_desc empty
, name_token
;
249 gss_buffer_t itoken
, rtoken
, dummy
;
250 OM_uint32 maj_stat
, min_stat
;
253 if (gssapi_get_state(iph1
) == NULL
&& gssapi_init(iph1
) < 0)
256 gps
= gssapi_get_state(iph1
);
262 if (iph1
->approval
!= NULL
&& iph1
->approval
->gssid
!= NULL
) {
263 plog(LLV_DEBUG
, LOCATION
, NULL
, "using provided service '%s'\n",
264 iph1
->approval
->gssid
->v
);
265 name_token
.length
= iph1
->approval
->gssid
->l
;
266 name_token
.value
= iph1
->approval
->gssid
->v
;
267 maj_stat
= gss_import_name(&min_stat
, &name_token
,
268 GSS_C_NO_OID
, &partner
);
269 if (GSS_ERROR(maj_stat
)) {
270 gssapi_error(min_stat
, LOCATION
, "import of %s\n",
275 if (gssapi_get_default_name(iph1
, 1, &partner
) < 0)
278 rtoken
= gps
->gsscnt_p
== 0 ? dummy
: &gps
->gss_p
[gps
->gsscnt_p
- 1];
279 itoken
= &gps
->gss
[gps
->gsscnt
];
281 gps
->gss_status
= gss_init_sec_context(&min_stat
, gps
->gss_cred
,
282 &gps
->gss_context
, partner
, GSS_C_NO_OID
,
283 GSS_C_MUTUAL_FLAG
| GSS_C_SEQUENCE_FLAG
|
284 GSS_C_CONF_FLAG
| GSS_C_INTEG_FLAG
,
285 0, GSS_C_NO_CHANNEL_BINDINGS
, rtoken
, NULL
,
288 if (GSS_ERROR(gps
->gss_status
)) {
289 gssapi_error(min_stat
, LOCATION
, "init_sec_context\n");
290 maj_stat
= gss_release_name(&min_stat
, &partner
);
291 if (GSS_ERROR(maj_stat
))
292 gssapi_error(min_stat
, LOCATION
, "release name\n");
295 maj_stat
= gss_release_name(&min_stat
, &partner
);
296 if (GSS_ERROR(maj_stat
))
297 gssapi_error(min_stat
, LOCATION
, "release name\n");
299 plog(LLV_DEBUG
, LOCATION
, NULL
, "gss_init_sec_context status %x\n",
303 *lenp
= itoken
->length
;
305 if (itoken
->length
!= 0)
312 * Call gss_accept_context, with token just read from the wire.
315 gssapi_get_rtoken(struct ph1handle
*iph1
, int *lenp
)
317 struct gssapi_ph1_state
*gps
;
318 gss_buffer_desc name_token
;
319 gss_buffer_t itoken
, rtoken
;
320 OM_uint32 min_stat
, maj_stat
;
321 gss_name_t client_name
;
323 if (gssapi_get_state(iph1
) == NULL
&& gssapi_init(iph1
) < 0)
326 gps
= gssapi_get_state(iph1
);
328 rtoken
= &gps
->gss_p
[gps
->gsscnt_p
- 1];
329 itoken
= &gps
->gss
[gps
->gsscnt
];
331 gps
->gss_status
= gss_accept_sec_context(&min_stat
, &gps
->gss_context
,
332 gps
->gss_cred
, rtoken
, GSS_C_NO_CHANNEL_BINDINGS
, &client_name
,
333 NULL
, itoken
, NULL
, NULL
, NULL
);
335 if (GSS_ERROR(gps
->gss_status
)) {
336 gssapi_error(min_stat
, LOCATION
, "accept_sec_context\n");
340 maj_stat
= gss_display_name(&min_stat
, client_name
, &name_token
, NULL
);
341 if (GSS_ERROR(maj_stat
)) {
342 gssapi_error(min_stat
, LOCATION
, "gss_display_name\n");
343 maj_stat
= gss_release_name(&min_stat
, &client_name
);
344 if (GSS_ERROR(maj_stat
))
345 gssapi_error(min_stat
, LOCATION
,
346 "release client_name\n");
349 maj_stat
= gss_release_name(&min_stat
, &client_name
);
350 if (GSS_ERROR(maj_stat
))
351 gssapi_error(min_stat
, LOCATION
, "release client_name\n");
353 plog(LLV_DEBUG
, LOCATION
, NULL
,
354 "gss_accept_sec_context: other side is %s\n",
356 maj_stat
= gss_release_buffer(&min_stat
, &name_token
);
357 if (GSS_ERROR(maj_stat
))
358 gssapi_error(min_stat
, LOCATION
, "release name buffer\n");
360 if (itoken
->length
!= 0)
364 *lenp
= itoken
->length
;
370 gssapi_save_received_token(struct ph1handle
*iph1
, vchar_t
*token
)
372 struct gssapi_ph1_state
*gps
;
373 gss_buffer_t gsstoken
;
376 if (gssapi_get_state(iph1
) == NULL
&& gssapi_init(iph1
) < 0)
379 gps
= gssapi_get_state(iph1
);
381 gsstoken
= &gps
->gss_p
[gps
->gsscnt_p
];
383 ret
= gssapi_vm2gssbuf(token
, gsstoken
);
392 gssapi_get_token_to_send(struct ph1handle
*iph1
, vchar_t
**token
)
394 struct gssapi_ph1_state
*gps
;
395 gss_buffer_t gsstoken
;
398 gps
= gssapi_get_state(iph1
);
400 plog(LLV_ERROR
, LOCATION
, NULL
,
401 "gssapi not yet initialized?\n");
404 gsstoken
= &gps
->gss
[gps
->gsscnt
- 1];
405 ret
= gssapi_gss2vmbuf(gsstoken
, token
);
413 gssapi_get_itokens(struct ph1handle
*iph1
, vchar_t
**tokens
)
415 struct gssapi_ph1_state
*gps
;
420 gps
= gssapi_get_state(iph1
);
422 plog(LLV_ERROR
, LOCATION
, NULL
,
423 "gssapi not yet initialized?\n");
427 for (i
= len
= 0; i
< gps
->gsscnt
; i
++)
428 len
+= gps
->gss
[i
].length
;
434 for (i
= 0; i
< gps
->gsscnt
; i
++) {
435 memcpy(p
, gps
->gss
[i
].value
, gps
->gss
[i
].length
);
436 p
+= gps
->gss
[i
].length
;
441 plog(LLV_DEBUG
, LOCATION
, NULL
,
442 "%d itokens of length %d\n", gps
->gsscnt
, (*tokens
)->l
);
448 gssapi_get_rtokens(struct ph1handle
*iph1
, vchar_t
**tokens
)
450 struct gssapi_ph1_state
*gps
;
455 gps
= gssapi_get_state(iph1
);
457 plog(LLV_ERROR
, LOCATION
, NULL
,
458 "gssapi not yet initialized?\n");
462 if (gssapi_more_tokens(iph1
)) {
463 plog(LLV_ERROR
, LOCATION
, NULL
,
464 "gssapi roundtrips not complete\n");
468 for (i
= len
= 0; i
< gps
->gsscnt_p
; i
++)
469 len
+= gps
->gss_p
[i
].length
;
475 for (i
= 0; i
< gps
->gsscnt_p
; i
++) {
476 memcpy(p
, gps
->gss_p
[i
].value
, gps
->gss_p
[i
].length
);
477 p
+= gps
->gss_p
[i
].length
;
486 gssapi_wraphash(struct ph1handle
*iph1
)
488 struct gssapi_ph1_state
*gps
;
489 OM_uint32 maj_stat
, min_stat
;
490 gss_buffer_desc hash_in_buf
, hash_out_buf
;
491 gss_buffer_t hash_in
= &hash_in_buf
, hash_out
= &hash_out_buf
;
494 gps
= gssapi_get_state(iph1
);
496 plog(LLV_ERROR
, LOCATION
, NULL
,
497 "gssapi not yet initialized?\n");
501 if (gssapi_more_tokens(iph1
)) {
502 plog(LLV_ERROR
, LOCATION
, NULL
,
503 "gssapi roundtrips not complete\n");
507 if (gssapi_vm2gssbuf(iph1
->hash
, hash_in
) < 0) {
508 plog(LLV_ERROR
, LOCATION
, NULL
, "vm2gssbuf failed\n");
512 maj_stat
= gss_wrap(&min_stat
, gps
->gss_context
, 1, GSS_C_QOP_DEFAULT
,
513 hash_in
, NULL
, hash_out
);
514 if (GSS_ERROR(maj_stat
)) {
515 gssapi_error(min_stat
, LOCATION
, "wrapping hash value\n");
516 maj_stat
= gss_release_buffer(&min_stat
, hash_in
);
517 if (GSS_ERROR(maj_stat
))
518 gssapi_error(min_stat
, LOCATION
,
519 "release hash_in buffer\n");
523 plog(LLV_DEBUG
, LOCATION
, NULL
, "wrapped HASH, ilen %d olen %d\n",
524 hash_in
->length
, hash_out
->length
);
526 maj_stat
= gss_release_buffer(&min_stat
, hash_in
);
527 if (GSS_ERROR(maj_stat
))
528 gssapi_error(min_stat
, LOCATION
, "release hash_in buffer\n");
530 if (gssapi_gss2vmbuf(hash_out
, &outbuf
) < 0) {
531 plog(LLV_ERROR
, LOCATION
, NULL
, "gss2vmbuf failed\n");
532 maj_stat
= gss_release_buffer(&min_stat
, hash_out
);
533 if (GSS_ERROR(maj_stat
))
534 gssapi_error(min_stat
, LOCATION
,
535 "release hash_out buffer\n");
538 maj_stat
= gss_release_buffer(&min_stat
, hash_out
);
539 if (GSS_ERROR(maj_stat
))
540 gssapi_error(min_stat
, LOCATION
, "release hash_out buffer\n");
546 gssapi_unwraphash(struct ph1handle
*iph1
)
548 struct gssapi_ph1_state
*gps
;
549 OM_uint32 maj_stat
, min_stat
;
550 gss_buffer_desc hashbuf
, hash_outbuf
;
551 gss_buffer_t hash_in
= &hashbuf
, hash_out
= &hash_outbuf
;
554 gps
= gssapi_get_state(iph1
);
556 plog(LLV_ERROR
, LOCATION
, NULL
,
557 "gssapi not yet initialized?\n");
562 hashbuf
.length
= ntohs(iph1
->pl_hash
->h
.len
) - sizeof(*iph1
->pl_hash
);
563 hashbuf
.value
= (char *)(iph1
->pl_hash
+ 1);
565 plog(LLV_DEBUG
, LOCATION
, NULL
, "unwrapping HASH of len %d\n",
568 maj_stat
= gss_unwrap(&min_stat
, gps
->gss_context
, hash_in
, hash_out
,
570 if (GSS_ERROR(maj_stat
)) {
571 gssapi_error(min_stat
, LOCATION
, "unwrapping hash value\n");
575 if (gssapi_gss2vmbuf(hash_out
, &outbuf
) < 0) {
576 plog(LLV_ERROR
, LOCATION
, NULL
, "gss2vmbuf failed\n");
577 maj_stat
= gss_release_buffer(&min_stat
, hash_out
);
578 if (GSS_ERROR(maj_stat
))
579 gssapi_error(min_stat
, LOCATION
,
580 "release hash_out buffer\n");
583 maj_stat
= gss_release_buffer(&min_stat
, hash_out
);
584 if (GSS_ERROR(maj_stat
))
585 gssapi_error(min_stat
, LOCATION
, "release hash_out buffer\n");
591 gssapi_set_id_sent(struct ph1handle
*iph1
)
593 struct gssapi_ph1_state
*gps
;
595 gps
= gssapi_get_state(iph1
);
597 gps
->gss_flags
|= GSSFLAG_ID_SENT
;
601 gssapi_id_sent(struct ph1handle
*iph1
)
603 struct gssapi_ph1_state
*gps
;
605 gps
= gssapi_get_state(iph1
);
607 return (gps
->gss_flags
& GSSFLAG_ID_SENT
) != 0;
611 gssapi_set_id_rcvd(struct ph1handle
*iph1
)
613 struct gssapi_ph1_state
*gps
;
615 gps
= gssapi_get_state(iph1
);
617 gps
->gss_flags
|= GSSFLAG_ID_RCVD
;
621 gssapi_id_rcvd(struct ph1handle
*iph1
)
623 struct gssapi_ph1_state
*gps
;
625 gps
= gssapi_get_state(iph1
);
627 return (gps
->gss_flags
& GSSFLAG_ID_RCVD
) != 0;
631 gssapi_free_state(struct ph1handle
*iph1
)
633 struct gssapi_ph1_state
*gps
;
634 OM_uint32 maj_stat
, min_stat
;
636 gps
= gssapi_get_state(iph1
);
641 gssapi_set_state(iph1
, NULL
);
643 if (gps
->gss_cred
!= GSS_C_NO_CREDENTIAL
) {
644 maj_stat
= gss_release_cred(&min_stat
, &gps
->gss_cred
);
645 if (GSS_ERROR(maj_stat
))
646 gssapi_error(min_stat
, LOCATION
,
647 "releasing credentials\n");
653 gssapi_get_default_id(struct ph1handle
*iph1
)
655 gss_buffer_desc id_buffer
;
656 gss_buffer_t id
= &id_buffer
;
657 gss_name_t defname
, canon_name
;
658 OM_uint32 min_stat
, maj_stat
;
661 if (gssapi_get_default_name(iph1
, 0, &defname
) < 0)
664 maj_stat
= gss_canonicalize_name(&min_stat
, defname
, GSS_C_NO_OID
,
666 if (GSS_ERROR(maj_stat
)) {
667 gssapi_error(min_stat
, LOCATION
, "canonicalize name\n");
668 maj_stat
= gss_release_name(&min_stat
, &defname
);
669 if (GSS_ERROR(maj_stat
))
670 gssapi_error(min_stat
, LOCATION
,
671 "release default name\n");
674 maj_stat
= gss_release_name(&min_stat
, &defname
);
675 if (GSS_ERROR(maj_stat
))
676 gssapi_error(min_stat
, LOCATION
, "release default name\n");
678 maj_stat
= gss_export_name(&min_stat
, canon_name
, id
);
679 if (GSS_ERROR(maj_stat
)) {
680 gssapi_error(min_stat
, LOCATION
, "export name\n");
681 maj_stat
= gss_release_name(&min_stat
, &canon_name
);
682 if (GSS_ERROR(maj_stat
))
683 gssapi_error(min_stat
, LOCATION
,
684 "release canonical name\n");
687 maj_stat
= gss_release_name(&min_stat
, &canon_name
);
688 if (GSS_ERROR(maj_stat
))
689 gssapi_error(min_stat
, LOCATION
, "release canonical name\n");
691 plog(LLV_DEBUG
, LOCATION
, NULL
, "will try to acquire '%*s' creds\n",
692 id
->length
, id
->value
);
694 if (gssapi_gss2vmbuf(id
, &vmbuf
) < 0) {
695 plog(LLV_ERROR
, LOCATION
, NULL
, "gss2vmbuf failed\n");
696 maj_stat
= gss_release_buffer(&min_stat
, id
);
697 if (GSS_ERROR(maj_stat
))
698 gssapi_error(min_stat
, LOCATION
, "release id buffer\n");
701 maj_stat
= gss_release_buffer(&min_stat
, id
);
702 if (GSS_ERROR(maj_stat
))
703 gssapi_error(min_stat
, LOCATION
, "release id buffer\n");