1 /* kerberos_v5.c --- Implementation of experimental SASL mechanism KERBEROS_V5.
2 * Copyright (C) 2003, 2004 Simon Josefsson
4 * This file is part of GNU SASL Library.
6 * GNU SASL Library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
11 * GNU SASL Library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GNU SASL Library; if not, write to the Free
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
21 * NB! Shishi is licensed under GPL, so linking GSASL with it require
22 * that you follow the GPL for GSASL as well.
26 #include "kerberos_v5.h"
31 #ifdef HAVE_NETINET_IN_H
32 #include <netinet/in.h> /* ntohl */
40 #define MUTUAL (1 << 3)
42 #define SERVER_HELLO_LEN BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN
43 #define CLIENT_HELLO_LEN BITMAP_LEN + MAXBUF_LEN
45 #define MAXBUF_DEFAULT 65536
51 struct _Gsasl_kerberos_v5_client_state
54 char serverhello
[BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
];
58 uint32_t servermaxbuf
;
59 uint32_t clientmaxbuf
;
64 Shishi_key
*sessionkey
;
69 _gsasl_kerberos_v5_client_init (Gsasl_ctx
* ctx
)
71 if (!shishi_check_version (SHISHI_VERSION
))
72 return GSASL_UNKNOWN_MECHANISM
;
78 _gsasl_kerberos_v5_client_start (Gsasl_session
* sctx
, void **mech_data
)
80 struct _Gsasl_kerberos_v5_client_state
*state
;
84 state
= malloc (sizeof (*state
));
86 return GSASL_MALLOC_ERROR
;
88 memset (state
, 0, sizeof (*state
));
90 err
= shishi_init (&state
->sh
);
92 return GSASL_KERBEROS_V5_INIT_ERROR
;
95 state
->clientqop
= GSASL_QOP_AUTH_INT
;
103 #define STEP_NONINFRA_SEND_ASREQ 1
104 #define STEP_NONINFRA_WAIT_ASREP 2
105 #define STEP_NONINFRA_SEND_APREQ 3
106 #define STEP_NONINFRA_WAIT_APREP 4
107 #define STEP_SUCCESS 5
110 _gsasl_kerberos_v5_client_step (Gsasl_session
* sctx
,
114 char *output
, size_t * output_len
)
116 struct _Gsasl_kerberos_v5_client_state
*state
= mech_data
;
117 Gsasl_client_callback_authentication_id cb_authentication_id
;
118 Gsasl_client_callback_authorization_id cb_authorization_id
;
119 Gsasl_client_callback_qop cb_qop
;
120 Gsasl_client_callback_realm cb_realm
;
121 Gsasl_client_callback_password cb_password
;
122 Gsasl_client_callback_service cb_service
;
123 Gsasl_client_callback_maxbuf cb_maxbuf
;
128 ctx
= gsasl_client_ctx_get (sctx
);
130 return GSASL_CANNOT_GET_CTX
;
132 /* These are optional */
133 cb_realm
= gsasl_client_callback_realm_get (ctx
);
134 cb_service
= gsasl_client_callback_service_get (ctx
);
135 cb_authentication_id
= gsasl_client_callback_authentication_id_get (ctx
);
136 cb_authorization_id
= gsasl_client_callback_authorization_id_get (ctx
);
137 cb_qop
= gsasl_client_callback_qop_get (ctx
);
138 cb_maxbuf
= gsasl_client_callback_maxbuf_get (ctx
);
140 /* Only optionally needed in infrastructure mode */
141 cb_password
= gsasl_client_callback_password_get (ctx
);
142 if (cb_password
== NULL
)
143 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK
;
145 /* I think we really need this one */
146 cb_service
= gsasl_client_callback_service_get (ctx
);
147 if (cb_service
== NULL
)
148 return GSASL_NEED_CLIENT_SERVICE_CALLBACK
;
156 return GSASL_NEEDS_MORE
;
159 if (input_len
!= SERVER_HELLO_LEN
)
160 return GSASL_MECHANISM_PARSE_ERROR
;
162 memcpy (state
->serverhello
, input
, input_len
);
165 unsigned char serverbitmap
;
167 memcpy (&serverbitmap
, input
, BITMAP_LEN
);
168 state
->serverqops
= 0;
169 if (serverbitmap
& GSASL_QOP_AUTH
)
170 state
->serverqops
|= GSASL_QOP_AUTH
;
171 if (serverbitmap
& GSASL_QOP_AUTH_INT
)
172 state
->serverqops
|= GSASL_QOP_AUTH_INT
;
173 if (serverbitmap
& GSASL_QOP_AUTH_CONF
)
174 state
->serverqops
|= GSASL_QOP_AUTH_CONF
;
175 if (serverbitmap
& MUTUAL
)
176 state
->servermutual
= 1;
178 memcpy (&state
->servermaxbuf
, &input
[BITMAP_LEN
], MAXBUF_LEN
);
179 state
->servermaxbuf
= ntohl (state
->servermaxbuf
);
182 state
->clientqop
= cb_qop (sctx
, state
->serverqops
);
184 if (!(state
->serverqops
& state
->clientqop
&
185 (GSASL_QOP_AUTH
| GSASL_QOP_AUTH_INT
| GSASL_QOP_AUTH_CONF
)))
186 return GSASL_AUTHENTICATION_ERROR
;
188 /* XXX for now we require server authentication */
189 if (!state
->servermutual
)
190 return GSASL_AUTHENTICATION_ERROR
;
192 /* Decide policy here: non-infrastructure, infrastructure or proxy.
194 * A callback to decide should be added, but without the default
197 * IF shishi_tktset_get_for_server() THEN
198 * INFRASTRUCTURE MODE
199 * ELSE IF shishi_realm_for_server(server) THEN
200 * PROXY INFRASTRUCTURE (then fallback to NIM?)
202 * NON-INFRASTRUCTURE MODE
204 state
->step
= STEP_NONINFRA_SEND_APREQ
; /* only NIM for now.. */
207 case STEP_NONINFRA_SEND_ASREQ
:
208 res
= shishi_as (state
->sh
, &state
->as
);
210 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
212 if (cb_authentication_id
) /* Shishi defaults to one otherwise */
214 len
= *output_len
- 1;
215 res
= cb_authentication_id (sctx
, output
, &len
);
220 res
= shishi_kdcreq_set_cname (state
->sh
, shishi_as_req (state
->as
),
221 SHISHI_NT_UNKNOWN
, output
);
228 len
= *output_len
- 1;
229 res
= cb_realm (sctx
, output
, &len
);
237 res
= shishi_kdcreq_set_realm (state
->sh
, shishi_as_req (state
->as
),
245 size_t servicelen
= 0;
246 size_t hostnamelen
= 0;
248 res
= cb_service (sctx
, NULL
, &servicelen
, NULL
, &hostnamelen
,
249 /* XXX support servicename a'la DIGEST-MD5 too? */
254 if (*output_len
< servicelen
+ 1 + hostnamelen
+ 1)
255 return GSASL_TOO_SMALL_BUFFER
;
257 sname
[0] = &output
[0];
258 sname
[1] = &output
[servicelen
+ 2];
261 res
= cb_service (sctx
, sname
[0], &servicelen
,
262 sname
[1], &hostnamelen
, NULL
, NULL
);
266 sname
[0][servicelen
] = '\0';
267 sname
[1][hostnamelen
] = '\0';
269 res
= shishi_kdcreq_set_sname (state
->sh
, shishi_as_req (state
->as
),
270 SHISHI_NT_UNKNOWN
, sname
);
275 /* XXX query application for encryption types and set the etype
276 field? Already configured by shishi though... */
278 res
= shishi_a2d (state
->sh
, shishi_as_req (state
->as
),
280 if (res
!= SHISHI_OK
)
281 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
283 state
->step
= STEP_NONINFRA_WAIT_ASREP
;
285 res
= GSASL_NEEDS_MORE
;
288 case STEP_NONINFRA_WAIT_ASREP
:
289 if (shishi_as_rep_der_set (state
->as
, input
, input_len
) != SHISHI_OK
)
290 return GSASL_MECHANISM_PARSE_ERROR
;
292 /* XXX? password stored in callee's output buffer */
293 len
= *output_len
- 1;
294 res
= cb_password (sctx
, output
, &len
);
295 if (res
!= GSASL_OK
&& res
!= GSASL_NEEDS_MORE
)
299 res
= shishi_as_rep_process (state
->as
, NULL
, output
);
300 if (res
!= SHISHI_OK
)
301 return GSASL_AUTHENTICATION_ERROR
;
303 state
->step
= STEP_NONINFRA_SEND_APREQ
;
306 case STEP_NONINFRA_SEND_APREQ
:
307 if (*output_len
<= CLIENT_HELLO_LEN
+ SERVER_HELLO_LEN
)
308 return GSASL_TOO_SMALL_BUFFER
;
310 if (!(state
->clientqop
& ~GSASL_QOP_AUTH
))
311 state
->clientmaxbuf
= 0;
313 state
->clientmaxbuf
= cb_maxbuf (sctx
, state
->servermaxbuf
);
315 state
->clientmaxbuf
= MAXBUF_DEFAULT
;
317 /* XXX for now we require server authentication */
318 output
[0] = state
->clientqop
| MUTUAL
;
322 tmp
= ntohl (state
->clientmaxbuf
);
323 memcpy (&output
[BITMAP_LEN
], &tmp
, MAXBUF_LEN
);
325 memcpy (&output
[CLIENT_HELLO_LEN
], state
->serverhello
,
328 if (cb_authorization_id
)
330 len
= *output_len
- CLIENT_HELLO_LEN
+ SERVER_HELLO_LEN
;
331 res
= cb_authorization_id (sctx
, &output
[CLIENT_HELLO_LEN
+
332 SERVER_HELLO_LEN
], &len
);
337 len
+= CLIENT_HELLO_LEN
+ SERVER_HELLO_LEN
;
338 res
= shishi_ap_tktoptionsdata (state
->sh
,
340 shishi_as_tkt (state
->as
),
341 SHISHI_APOPTIONS_MUTUAL_REQUIRED
,
343 if (res
!= SHISHI_OK
)
344 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
346 res
= shishi_authenticator_add_authorizationdata
347 (state
->sh
, shishi_ap_authenticator (state
->ap
), -1, output
, len
);
348 if (res
!= SHISHI_OK
)
349 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
351 /* XXX set realm in AP-REQ and Authenticator */
353 res
= shishi_ap_req_der (state
->ap
, output
, output_len
);
354 if (res
!= SHISHI_OK
)
355 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
357 state
->step
= STEP_NONINFRA_WAIT_APREP
;
359 res
= GSASL_NEEDS_MORE
;
362 case STEP_NONINFRA_WAIT_APREP
:
363 if (shishi_ap_rep_der_set (state
->ap
, input
, input_len
) != SHISHI_OK
)
364 return GSASL_MECHANISM_PARSE_ERROR
;
366 res
= shishi_ap_rep_verify (state
->ap
);
367 if (res
!= SHISHI_OK
)
368 return GSASL_AUTHENTICATION_ERROR
;
370 state
->step
= STEP_SUCCESS
;
372 /* XXX support AP session keys */
373 state
->sessionkey
= shishi_tkt_key (shishi_as_tkt (state
->as
));
380 res
= GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
;
388 _gsasl_kerberos_v5_client_encode (Gsasl_session
* sctx
,
392 char *output
, size_t * output_len
)
394 struct _Gsasl_kerberos_v5_client_state
*state
= mech_data
;
397 if (state
&& state
->sessionkey
&& state
->clientqop
& GSASL_QOP_AUTH_CONF
)
401 else if (state
&& state
->sessionkey
402 && state
->clientqop
& GSASL_QOP_AUTH_INT
)
404 res
= shishi_safe (state
->sh
, &state
->safe
);
405 if (res
!= SHISHI_OK
)
406 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
408 res
= shishi_safe_set_user_data (state
->sh
,
409 shishi_safe_safe (state
->safe
),
411 if (res
!= SHISHI_OK
)
412 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
414 res
= shishi_safe_build (state
->safe
, state
->sessionkey
);
415 if (res
!= SHISHI_OK
)
416 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
418 res
= shishi_safe_safe_der (state
->safe
, output
, output_len
);
419 if (res
!= SHISHI_OK
)
420 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
424 *output_len
= input_len
;
426 memcpy (output
, input
, input_len
);
434 _gsasl_kerberos_v5_client_decode (Gsasl_session
* sctx
,
438 char *output
, size_t * output_len
)
440 struct _Gsasl_kerberos_v5_client_state
*state
= mech_data
;
444 if (state
&& state
->sessionkey
&& state
->clientqop
& GSASL_QOP_AUTH_CONF
)
448 else if (state
&& state
->sessionkey
449 && state
->clientqop
& GSASL_QOP_AUTH_INT
)
455 *output_len
= input_len
;
457 memcpy (output
, input
, input_len
);
465 _gsasl_kerberos_v5_client_finish (Gsasl_session
* sctx
, void *mech_data
)
467 struct _Gsasl_kerberos_v5_client_state
*state
= mech_data
;
469 shishi_done (state
->sh
);
475 #endif /* USE_CLIENT */
481 struct _Gsasl_kerberos_v5_server_state
485 char serverhello
[BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
];
488 uint32_t servermaxbuf
;
491 uint32_t clientmaxbuf
;
496 char *serverhostname
;
498 Shishi_key
*userkey
; /* user's key derived with string2key */
499 Shishi_key
*sessionkey
; /* shared between client and server */
500 Shishi_key
*sessiontktkey
; /* known only by server */
507 _gsasl_kerberos_v5_server_init (Gsasl_ctx
* ctx
)
509 if (!shishi_check_version (SHISHI_VERSION
))
510 return GSASL_UNKNOWN_MECHANISM
;
516 _gsasl_kerberos_v5_server_start (Gsasl_session
* sctx
, void **mech_data
)
518 struct _Gsasl_kerberos_v5_server_state
*state
;
521 state
= malloc (sizeof (*state
));
523 return GSASL_MALLOC_ERROR
;
524 memset (state
, 0, sizeof (*state
));
526 state
->random
= (char *) malloc (RANDOM_LEN
);
527 if (state
->random
== NULL
)
528 return GSASL_MALLOC_ERROR
;
530 err
= shishi_init_server (&state
->sh
);
532 return GSASL_KERBEROS_V5_INIT_ERROR
;
534 err
= shishi_randomize (state
->sh
, state
->random
, RANDOM_LEN
);
536 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
538 /* This can be pretty much anything, the client will never have it. */
539 err
= shishi_key_random (state
->sh
, SHISHI_AES256_CTS_HMAC_SHA1_96
,
540 &state
->sessiontktkey
);
542 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
544 err
= shishi_as (state
->sh
, &state
->as
);
546 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
548 state
->firststep
= 1;
549 state
->serverqops
= GSASL_QOP_AUTH
| GSASL_QOP_AUTH_INT
;
557 _gsasl_kerberos_v5_server_step (Gsasl_session
* sctx
,
561 char *output
, size_t * output_len
)
563 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
564 Gsasl_server_callback_realm cb_realm
;
565 Gsasl_server_callback_qop cb_qop
;
566 Gsasl_server_callback_maxbuf cb_maxbuf
;
567 Gsasl_server_callback_cipher cb_cipher
;
568 Gsasl_server_callback_retrieve cb_retrieve
;
569 Gsasl_server_callback_service cb_service
;
570 unsigned char buf
[BUFSIZ
];
576 ctx
= gsasl_server_ctx_get (sctx
);
578 return GSASL_CANNOT_GET_CTX
;
580 cb_realm
= gsasl_server_callback_realm_get (ctx
);
581 cb_qop
= gsasl_server_callback_qop_get (ctx
);
582 cb_maxbuf
= gsasl_server_callback_maxbuf_get (ctx
);
583 cb_retrieve
= gsasl_server_callback_retrieve_get (ctx
);
584 cb_service
= gsasl_server_callback_service_get (ctx
);
585 if (cb_service
== NULL
)
586 return GSASL_NEED_SERVER_SERVICE_CALLBACK
;
588 if (state
->firststep
)
594 * The initial server packet should contain one octet containing
595 * a bit mask of supported security layers, four octets
596 * indicating the maximum cipher-text buffer size the server is
597 * able to receive (or 0 if no security layers are supported) in
598 * network byte order, and then 16 octets containing random data
599 * (see [4] on how random data might be generated).
601 * The security layers and their corresponding bit-masks are as
604 * Bit 0 No security layer
605 * Bit 1 Integrity (KRB-SAFE) protection
606 * Bit 2 Privacy (KRB-PRIV) protection
607 * Bit 3 Mutual authentication is required (AP option MUTUAL-
608 * REQUIRED must also be present).
610 * Other bit-masks may be defined in the future; bits which are
611 * not understood must be negotiated off.
614 if (output
&& *output_len
< BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
)
615 return GSASL_TOO_SMALL_BUFFER
;
617 p
= &state
->serverhello
[0];
620 state
->serverqops
= cb_qop (sctx
);
622 if (state
->serverqops
& GSASL_QOP_AUTH
)
623 *p
|= GSASL_QOP_AUTH
;
624 if (state
->serverqops
& GSASL_QOP_AUTH_INT
)
625 *p
|= GSASL_QOP_AUTH_INT
;
626 if (state
->serverqops
& GSASL_QOP_AUTH_CONF
)
627 *p
|= GSASL_QOP_AUTH_CONF
;
628 /* XXX we always require mutual authentication for now */
631 if (!(state
->serverqops
& ~GSASL_QOP_AUTH
))
632 state
->servermaxbuf
= 0;
634 state
->servermaxbuf
= cb_maxbuf (sctx
);
636 state
->servermaxbuf
= MAXBUF_DEFAULT
;
638 tmp
= htonl (state
->servermaxbuf
);
639 memcpy (&state
->serverhello
[BITMAP_LEN
], &tmp
, MAXBUF_LEN
);
640 memcpy (&state
->serverhello
[BITMAP_LEN
+ MAXBUF_LEN
],
641 state
->random
, RANDOM_LEN
);
644 memcpy (output
, state
->serverhello
, SERVER_HELLO_LEN
);
645 *output_len
= BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
;
647 state
->firststep
= 0;
649 return GSASL_NEEDS_MORE
;
654 /* Non-infrastructure mode */
656 if (*output_len
< 2048)
657 return GSASL_TOO_SMALL_BUFFER
;
659 if (shishi_as_req_der_set (state
->as
, input
, input_len
) == SHISHI_OK
)
664 tkt
= shishi_as_tkt (state
->as
);
666 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
671 err
= shishi_kdcreq_etype (state
->sh
,
672 shishi_as_req (state
->as
),
674 if (err
== SHISHI_OK
&& shishi_cipher_supported_p (etype
))
677 while (err
== SHISHI_OK
);
678 if (err
!= SHISHI_OK
)
681 /* XXX use a "preferred server kdc etype" from shishi instead? */
682 err
= shishi_key_random (state
->sh
, etype
, &state
->sessionkey
);
684 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
686 err
= shishi_tkt_key_set (tkt
, state
->sessionkey
);
688 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
690 buflen
= sizeof (buf
) - 1;
691 err
= shishi_kdcreq_cname_get (state
->sh
,
692 shishi_as_req (state
->as
),
694 if (err
!= SHISHI_OK
)
697 state
->username
= strdup (buf
);
699 buflen
= sizeof (buf
) - 1;
700 err
= shishi_kdcreq_realm_get (state
->sh
,
701 shishi_as_req (state
->as
),
703 if (err
!= SHISHI_OK
)
706 state
->userrealm
= strdup (buf
);
708 buflen
= sizeof (buf
) - 1;
709 err
= cb_retrieve (sctx
, state
->username
, NULL
, state
->userrealm
,
714 state
->password
= malloc (buflen
+ 1);
715 if (state
->password
== NULL
)
716 return GSASL_MALLOC_ERROR
;
718 err
= cb_retrieve (sctx
, state
->username
, NULL
, state
->userrealm
,
719 state
->password
, &buflen
);
722 state
->password
[buflen
] = '\0';
724 buflen
= sizeof (buf
) - 1;
727 err
= cb_realm (sctx
, buf
, &buflen
, 0);
734 state
->serverrealm
= strdup (buf
);
736 buflen
= sizeof (buf
) - 1;
737 err
= cb_service (sctx
, buf
, &buflen
, NULL
, NULL
);
741 state
->serverservice
= strdup (buf
);
743 buflen
= sizeof (buf
) - 1;
744 err
= cb_service (sctx
, NULL
, NULL
, buf
, &buflen
);
748 state
->serverhostname
= strdup (buf
);
750 /* XXX do some checking on realm and server name? Right now
751 we simply doesn't care about what client requested and
752 return a ticket for this server. This is bad. */
754 err
= shishi_tkt_clientrealm_set (tkt
, state
->userrealm
,
757 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
761 p
= malloc (strlen (state
->serverservice
) + strlen ("/") +
762 strlen (state
->serverhostname
) + 1);
764 return GSASL_MALLOC_ERROR
;
765 sprintf (p
, "%s/%s", state
->serverservice
, state
->serverhostname
);
766 err
= shishi_tkt_serverrealm_set (tkt
, state
->serverrealm
, p
);
769 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
772 buflen
= sizeof (buf
);
773 err
= shishi_as_derive_salt (state
->sh
,
774 shishi_as_req (state
->as
),
775 shishi_as_rep (state
->as
),
777 if (err
!= SHISHI_OK
)
780 err
= shishi_key_from_string (state
->sh
,
783 strlen (state
->password
),
784 buf
, buflen
, NULL
, &state
->userkey
);
785 if (err
!= SHISHI_OK
)
788 err
= shishi_tkt_build (tkt
, state
->sessiontktkey
);
790 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
792 err
= shishi_as_rep_build (state
->as
, state
->userkey
);
794 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
797 shishi_kdcreq_print (state
->sh
, stderr
, shishi_as_req (state
->as
));
798 shishi_encticketpart_print (state
->sh
, stderr
,
799 shishi_tkt_encticketpart (tkt
));
800 shishi_ticket_print (state
->sh
, stderr
, shishi_tkt_ticket (tkt
));
801 shishi_enckdcreppart_print (state
->sh
, stderr
,
802 shishi_tkt_enckdcreppart (state
->as
));
803 shishi_kdcrep_print (state
->sh
, stderr
, shishi_as_rep (state
->as
));
806 err
= shishi_as_rep_der (state
->as
, output
, output_len
);
808 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
810 return GSASL_NEEDS_MORE
;
812 else if ((asn1
= shishi_der2asn1_apreq (state
->sh
, input
, input_len
)))
816 err
= shishi_ap (state
->sh
, &state
->ap
);
818 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
820 shishi_ap_req_set (state
->ap
, asn1
);
822 err
= shishi_ap_req_process (state
->ap
, state
->sessiontktkey
);
824 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
827 shishi_apreq_print (state
->sh
, stderr
, shishi_ap_req (state
->ap
));
828 shishi_ticket_print (state
->sh
, stderr
,
829 shishi_tkt_ticket (shishi_ap_tkt (state
->ap
)));
830 shishi_authenticator_print (state
->sh
, stderr
,
831 shishi_ap_authenticator (state
->ap
));
834 buflen
= sizeof (buf
);
835 err
= shishi_authenticator_authorizationdata
836 (state
->sh
, shishi_ap_authenticator (state
->ap
),
837 &adtype
, buf
, &buflen
, 1);
839 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
841 if (adtype
!= 0xFF /* -1 in one-complements form */ ||
842 buflen
< CLIENT_HELLO_LEN
+ SERVER_HELLO_LEN
)
843 return GSASL_AUTHENTICATION_ERROR
;
846 unsigned char clientbitmap
;
848 memcpy (&clientbitmap
, &buf
[0], BITMAP_LEN
);
849 state
->clientqop
= 0;
850 if (clientbitmap
& GSASL_QOP_AUTH
)
851 state
->clientqop
|= GSASL_QOP_AUTH
;
852 if (clientbitmap
& GSASL_QOP_AUTH_INT
)
853 state
->clientqop
|= GSASL_QOP_AUTH_INT
;
854 if (clientbitmap
& GSASL_QOP_AUTH_CONF
)
855 state
->clientqop
|= GSASL_QOP_AUTH_CONF
;
856 if (clientbitmap
& MUTUAL
)
857 state
->clientmutual
= 1;
859 memcpy (&state
->clientmaxbuf
, &input
[BITMAP_LEN
], MAXBUF_LEN
);
860 state
->clientmaxbuf
= ntohl (state
->clientmaxbuf
);
862 if (!(state
->clientqop
& state
->serverqops
))
863 return GSASL_AUTHENTICATION_ERROR
;
865 /* XXX check clientmaxbuf too */
867 if (memcmp (&buf
[CLIENT_HELLO_LEN
],
868 state
->serverhello
, SERVER_HELLO_LEN
) != 0)
869 return GSASL_AUTHENTICATION_ERROR
;
877 key
= shishi_tkt_key (shishi_as_tkt (state
->as
));
879 shishi_cipher_defaultcksumtype (shishi_key_type (key
));
880 cksumlen
= sizeof (cksum
);
881 err
= shishi_checksum (state
->sh
, key
,
882 SHISHI_KEYUSAGE_APREQ_AUTHENTICATOR_CKSUM
,
883 cksumtype
, buf
, buflen
, cksum
, &cksumlen
);
884 if (err
!= SHISHI_OK
)
885 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
887 buflen
= sizeof (buf
);
888 err
= shishi_authenticator_cksum
890 shishi_ap_authenticator (state
->ap
), &cksumtype
, buf
, &buflen
);
891 if (err
!= SHISHI_OK
)
892 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
894 if (buflen
!= cksumlen
|| memcmp (buf
, cksum
, buflen
) != 0)
895 return GSASL_AUTHENTICATION_ERROR
;
898 /* XXX use authorization_id */
900 if (state
->clientmutual
)
902 err
= shishi_ap_rep_build (state
->ap
);
904 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
906 err
= shishi_ap_rep_der (state
->ap
, output
, output_len
);
908 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
918 /* XXX Currently we only handle AS-REQ and AP-REQ in
919 non-infrastructure mode. Supporting infrastructure mode is
920 simple, just send the AS-REQ to the KDC and wait for AS-REP
921 instead of creating AS-REP locally.
923 We should probably have a callback to decide policy:
924 1) non-infrastructure mode (NIM) only
925 2) infrastructure mode (IM) only
926 3) proxied infrastructure mode (PIM) only
927 4) NIM with fallback to IM (useful for local server overrides)
928 5) IM with fallback to NIM (useful for admins if KDC is offline)
929 6) ...etc with PIM too
931 return GSASL_NEED_SERVER_RETRIEVE_CALLBACK
;
935 return GSASL_NEEDS_MORE
;
939 _gsasl_kerberos_v5_server_encode (Gsasl_session
* sctx
,
943 char *output
, size_t * output_len
)
945 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
948 if (state
&& state
->sessionkey
&& state
->clientqop
& GSASL_QOP_AUTH_CONF
)
952 else if (state
&& state
->sessionkey
953 && state
->clientqop
& GSASL_QOP_AUTH_INT
)
955 res
= shishi_safe (state
->sh
, &state
->safe
);
956 if (res
!= SHISHI_OK
)
957 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
959 res
= shishi_safe_set_user_data (state
->sh
,
960 shishi_safe_safe (state
->safe
),
962 if (res
!= SHISHI_OK
)
963 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
965 res
= shishi_safe_build (state
->safe
, state
->sessionkey
);
966 if (res
!= SHISHI_OK
)
967 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
969 res
= shishi_safe_safe_der (state
->safe
, output
, output_len
);
970 if (res
!= SHISHI_OK
)
971 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
975 *output_len
= input_len
;
977 memcpy (output
, input
, input_len
);
985 _gsasl_kerberos_v5_server_decode (Gsasl_session
* sctx
,
989 char *output
, size_t * output_len
)
991 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
994 if (state
&& state
->sessionkey
&& state
->clientqop
& GSASL_QOP_AUTH_CONF
)
998 else if (state
&& state
->sessionkey
999 && state
->clientqop
& GSASL_QOP_AUTH_INT
)
1001 Shishi_asn1 asn1safe
;
1003 res
= shishi_safe (state
->sh
, &state
->safe
);
1004 if (res
!= SHISHI_OK
)
1005 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
1007 res
= shishi_safe_safe_der_set (state
->safe
, input
, input_len
);
1008 printf ("len %d err %d\n", input_len
, res
);
1009 if (res
!= SHISHI_OK
)
1010 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
1012 res
= shishi_safe_verify (state
->safe
, state
->sessionkey
);
1013 if (res
!= SHISHI_OK
)
1014 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
1016 res
= shishi_safe_user_data (state
->sh
, shishi_safe_safe (state
->safe
),
1017 output
, output_len
);
1018 if (res
!= SHISHI_OK
)
1019 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
1020 printf ("len=%d\n", *output_len
);
1025 *output_len
= input_len
;
1027 memcpy (output
, input
, input_len
);
1036 _gsasl_kerberos_v5_server_finish (Gsasl_session
* sctx
, void *mech_data
)
1038 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
1040 shishi_done (state
->sh
);
1041 if (state
->username
)
1042 free (state
->username
);
1043 if (state
->password
)
1044 free (state
->password
);
1046 free (state
->random
);
1051 #endif /* USE_SERVER */