1 /* server.c --- Experimental SASL mechanism KERBEROS_V5, server side.
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"
30 struct _Gsasl_kerberos_v5_server_state
34 char serverhello
[BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
];
37 uint32_t servermaxbuf
;
40 uint32_t clientmaxbuf
;
47 Shishi_key
*userkey
; /* user's key derived with string2key */
48 Shishi_key
*sessionkey
; /* shared between client and server */
49 Shishi_key
*sessiontktkey
; /* known only by server */
56 _gsasl_kerberos_v5_server_init (Gsasl_ctx
* ctx
)
58 if (!shishi_check_version (SHISHI_VERSION
))
59 return GSASL_UNKNOWN_MECHANISM
;
65 _gsasl_kerberos_v5_server_start (Gsasl_session
* sctx
, void **mech_data
)
67 struct _Gsasl_kerberos_v5_server_state
*state
;
70 state
= malloc (sizeof (*state
));
72 return GSASL_MALLOC_ERROR
;
73 memset (state
, 0, sizeof (*state
));
75 state
->random
= (char *) malloc (RANDOM_LEN
);
76 if (state
->random
== NULL
)
77 return GSASL_MALLOC_ERROR
;
79 err
= shishi_init_server (&state
->sh
);
81 return GSASL_KERBEROS_V5_INIT_ERROR
;
83 err
= shishi_randomize (state
->sh
, state
->random
, RANDOM_LEN
);
85 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
87 /* This can be pretty much anything, the client will never have it. */
88 err
= shishi_key_random (state
->sh
, SHISHI_AES256_CTS_HMAC_SHA1_96
,
89 &state
->sessiontktkey
);
91 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
93 err
= shishi_as (state
->sh
, &state
->as
);
95 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
98 state
->serverqops
= GSASL_QOP_AUTH
| GSASL_QOP_AUTH_INT
;
106 _gsasl_kerberos_v5_server_step (Gsasl_session
* sctx
,
110 char *output
, size_t * output_len
)
112 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
113 Gsasl_server_callback_realm cb_realm
;
114 Gsasl_server_callback_qop cb_qop
;
115 Gsasl_server_callback_maxbuf cb_maxbuf
;
116 Gsasl_server_callback_cipher cb_cipher
;
117 Gsasl_server_callback_retrieve cb_retrieve
;
118 Gsasl_server_callback_service cb_service
;
119 unsigned char buf
[BUFSIZ
];
125 ctx
= gsasl_server_ctx_get (sctx
);
127 return GSASL_CANNOT_GET_CTX
;
129 cb_realm
= gsasl_server_callback_realm_get (ctx
);
130 cb_qop
= gsasl_server_callback_qop_get (ctx
);
131 cb_maxbuf
= gsasl_server_callback_maxbuf_get (ctx
);
132 cb_retrieve
= gsasl_server_callback_retrieve_get (ctx
);
133 cb_service
= gsasl_server_callback_service_get (ctx
);
134 if (cb_service
== NULL
)
135 return GSASL_NEED_SERVER_SERVICE_CALLBACK
;
137 if (state
->firststep
)
143 * The initial server packet should contain one octet containing
144 * a bit mask of supported security layers, four octets
145 * indicating the maximum cipher-text buffer size the server is
146 * able to receive (or 0 if no security layers are supported) in
147 * network byte order, and then 16 octets containing random data
148 * (see [4] on how random data might be generated).
150 * The security layers and their corresponding bit-masks are as
153 * Bit 0 No security layer
154 * Bit 1 Integrity (KRB-SAFE) protection
155 * Bit 2 Privacy (KRB-PRIV) protection
156 * Bit 3 Mutual authentication is required (AP option MUTUAL-
157 * REQUIRED must also be present).
159 * Other bit-masks may be defined in the future; bits which are
160 * not understood must be negotiated off.
163 if (output
&& *output_len
< BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
)
164 return GSASL_TOO_SMALL_BUFFER
;
166 p
= &state
->serverhello
[0];
169 state
->serverqops
= cb_qop (sctx
);
171 if (state
->serverqops
& GSASL_QOP_AUTH
)
172 *p
|= GSASL_QOP_AUTH
;
173 if (state
->serverqops
& GSASL_QOP_AUTH_INT
)
174 *p
|= GSASL_QOP_AUTH_INT
;
175 if (state
->serverqops
& GSASL_QOP_AUTH_CONF
)
176 *p
|= GSASL_QOP_AUTH_CONF
;
177 /* XXX we always require mutual authentication for now */
180 if (!(state
->serverqops
& ~GSASL_QOP_AUTH
))
181 state
->servermaxbuf
= 0;
183 state
->servermaxbuf
= cb_maxbuf (sctx
);
185 state
->servermaxbuf
= MAXBUF_DEFAULT
;
187 tmp
= htonl (state
->servermaxbuf
);
188 memcpy (&state
->serverhello
[BITMAP_LEN
], &tmp
, MAXBUF_LEN
);
189 memcpy (&state
->serverhello
[BITMAP_LEN
+ MAXBUF_LEN
],
190 state
->random
, RANDOM_LEN
);
193 memcpy (output
, state
->serverhello
, SERVER_HELLO_LEN
);
194 *output_len
= BITMAP_LEN
+ MAXBUF_LEN
+ RANDOM_LEN
;
196 state
->firststep
= 0;
198 return GSASL_NEEDS_MORE
;
203 /* Non-infrastructure mode */
205 if (*output_len
< 2048)
206 return GSASL_TOO_SMALL_BUFFER
;
208 if (shishi_as_req_der_set (state
->as
, input
, input_len
) == SHISHI_OK
)
213 tkt
= shishi_as_tkt (state
->as
);
215 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
220 err
= shishi_kdcreq_etype (state
->sh
,
221 shishi_as_req (state
->as
),
223 if (err
== SHISHI_OK
&& shishi_cipher_supported_p (etype
))
226 while (err
== SHISHI_OK
);
227 if (err
!= SHISHI_OK
)
230 /* XXX use a "preferred server kdc etype" from shishi instead? */
231 err
= shishi_key_random (state
->sh
, etype
, &state
->sessionkey
);
233 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
235 err
= shishi_tkt_key_set (tkt
, state
->sessionkey
);
237 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
239 buflen
= sizeof (buf
) - 1;
240 err
= shishi_kdcreq_cname_get (state
->sh
,
241 shishi_as_req (state
->as
),
243 if (err
!= SHISHI_OK
)
246 state
->username
= strdup (buf
);
248 buflen
= sizeof (buf
) - 1;
249 err
= shishi_kdcreq_realm_get (state
->sh
,
250 shishi_as_req (state
->as
),
252 if (err
!= SHISHI_OK
)
255 state
->userrealm
= strdup (buf
);
257 buflen
= sizeof (buf
) - 1;
258 err
= cb_retrieve (sctx
, state
->username
, NULL
, state
->userrealm
,
263 state
->password
= malloc (buflen
+ 1);
264 if (state
->password
== NULL
)
265 return GSASL_MALLOC_ERROR
;
267 err
= cb_retrieve (sctx
, state
->username
, NULL
, state
->userrealm
,
268 state
->password
, &buflen
);
271 state
->password
[buflen
] = '\0';
273 buflen
= sizeof (buf
) - 1;
276 err
= cb_realm (sctx
, buf
, &buflen
, 0);
283 state
->serverrealm
= strdup (buf
);
285 buflen
= sizeof (buf
) - 1;
286 err
= cb_service (sctx
, buf
, &buflen
, NULL
, NULL
);
290 state
->serverservice
= strdup (buf
);
292 buflen
= sizeof (buf
) - 1;
293 err
= cb_service (sctx
, NULL
, NULL
, buf
, &buflen
);
297 state
->serverhostname
= strdup (buf
);
299 /* XXX do some checking on realm and server name? Right now
300 we simply doesn't care about what client requested and
301 return a ticket for this server. This is bad. */
303 err
= shishi_tkt_clientrealm_set (tkt
, state
->userrealm
,
306 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
310 p
= malloc (strlen (state
->serverservice
) + strlen ("/") +
311 strlen (state
->serverhostname
) + 1);
313 return GSASL_MALLOC_ERROR
;
314 sprintf (p
, "%s/%s", state
->serverservice
, state
->serverhostname
);
315 err
= shishi_tkt_serverrealm_set (tkt
, state
->serverrealm
, p
);
318 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
321 buflen
= sizeof (buf
);
322 err
= shishi_as_derive_salt (state
->sh
,
323 shishi_as_req (state
->as
),
324 shishi_as_rep (state
->as
),
326 if (err
!= SHISHI_OK
)
329 err
= shishi_key_from_string (state
->sh
,
332 strlen (state
->password
),
333 buf
, buflen
, NULL
, &state
->userkey
);
334 if (err
!= SHISHI_OK
)
337 err
= shishi_tkt_build (tkt
, state
->sessiontktkey
);
339 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
341 err
= shishi_as_rep_build (state
->as
, state
->userkey
);
343 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
346 shishi_kdcreq_print (state
->sh
, stderr
, shishi_as_req (state
->as
));
347 shishi_encticketpart_print (state
->sh
, stderr
,
348 shishi_tkt_encticketpart (tkt
));
349 shishi_ticket_print (state
->sh
, stderr
, shishi_tkt_ticket (tkt
));
350 shishi_enckdcreppart_print (state
->sh
, stderr
,
351 shishi_tkt_enckdcreppart (state
->as
));
352 shishi_kdcrep_print (state
->sh
, stderr
, shishi_as_rep (state
->as
));
355 err
= shishi_as_rep_der (state
->as
, output
, output_len
);
357 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
359 return GSASL_NEEDS_MORE
;
361 else if ((asn1
= shishi_der2asn1_apreq (state
->sh
, input
, input_len
)))
365 err
= shishi_ap (state
->sh
, &state
->ap
);
367 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
369 shishi_ap_req_set (state
->ap
, asn1
);
371 err
= shishi_ap_req_process (state
->ap
, state
->sessiontktkey
);
373 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
376 shishi_apreq_print (state
->sh
, stderr
, shishi_ap_req (state
->ap
));
377 shishi_ticket_print (state
->sh
, stderr
,
378 shishi_tkt_ticket (shishi_ap_tkt (state
->ap
)));
379 shishi_authenticator_print (state
->sh
, stderr
,
380 shishi_ap_authenticator (state
->ap
));
383 buflen
= sizeof (buf
);
384 err
= shishi_authenticator_authorizationdata
385 (state
->sh
, shishi_ap_authenticator (state
->ap
),
386 &adtype
, buf
, &buflen
, 1);
388 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
390 if (adtype
!= 0xFF /* -1 in one-complements form */ ||
391 buflen
< CLIENT_HELLO_LEN
+ SERVER_HELLO_LEN
)
392 return GSASL_AUTHENTICATION_ERROR
;
395 unsigned char clientbitmap
;
397 memcpy (&clientbitmap
, &buf
[0], BITMAP_LEN
);
398 state
->clientqop
= 0;
399 if (clientbitmap
& GSASL_QOP_AUTH
)
400 state
->clientqop
|= GSASL_QOP_AUTH
;
401 if (clientbitmap
& GSASL_QOP_AUTH_INT
)
402 state
->clientqop
|= GSASL_QOP_AUTH_INT
;
403 if (clientbitmap
& GSASL_QOP_AUTH_CONF
)
404 state
->clientqop
|= GSASL_QOP_AUTH_CONF
;
405 if (clientbitmap
& MUTUAL
)
406 state
->clientmutual
= 1;
408 memcpy (&state
->clientmaxbuf
, &input
[BITMAP_LEN
], MAXBUF_LEN
);
409 state
->clientmaxbuf
= ntohl (state
->clientmaxbuf
);
411 if (!(state
->clientqop
& state
->serverqops
))
412 return GSASL_AUTHENTICATION_ERROR
;
414 /* XXX check clientmaxbuf too */
416 if (memcmp (&buf
[CLIENT_HELLO_LEN
],
417 state
->serverhello
, SERVER_HELLO_LEN
) != 0)
418 return GSASL_AUTHENTICATION_ERROR
;
426 key
= shishi_tkt_key (shishi_as_tkt (state
->as
));
428 shishi_cipher_defaultcksumtype (shishi_key_type (key
));
429 cksumlen
= sizeof (cksum
);
430 err
= shishi_checksum (state
->sh
, key
,
431 SHISHI_KEYUSAGE_APREQ_AUTHENTICATOR_CKSUM
,
432 cksumtype
, buf
, buflen
, cksum
, &cksumlen
);
433 if (err
!= SHISHI_OK
)
434 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
436 buflen
= sizeof (buf
);
437 err
= shishi_authenticator_cksum
439 shishi_ap_authenticator (state
->ap
), &cksumtype
, buf
, &buflen
);
440 if (err
!= SHISHI_OK
)
441 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
443 if (buflen
!= cksumlen
|| memcmp (buf
, cksum
, buflen
) != 0)
444 return GSASL_AUTHENTICATION_ERROR
;
447 /* XXX use authorization_id */
449 if (state
->clientmutual
)
451 err
= shishi_ap_rep_build (state
->ap
);
453 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
455 err
= shishi_ap_rep_der (state
->ap
, output
, output_len
);
457 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
467 /* XXX Currently we only handle AS-REQ and AP-REQ in
468 non-infrastructure mode. Supporting infrastructure mode is
469 simple, just send the AS-REQ to the KDC and wait for AS-REP
470 instead of creating AS-REP locally.
472 We should probably have a callback to decide policy:
473 1) non-infrastructure mode (NIM) only
474 2) infrastructure mode (IM) only
475 3) proxied infrastructure mode (PIM) only
476 4) NIM with fallback to IM (useful for local server overrides)
477 5) IM with fallback to NIM (useful for admins if KDC is offline)
478 6) ...etc with PIM too
480 return GSASL_NEED_SERVER_RETRIEVE_CALLBACK
;
484 return GSASL_NEEDS_MORE
;
488 _gsasl_kerberos_v5_server_encode (Gsasl_session
* sctx
,
492 char *output
, size_t * output_len
)
494 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
497 if (state
&& state
->sessionkey
&& state
->clientqop
& GSASL_QOP_AUTH_CONF
)
499 return GSASL_INTEGRITY_ERROR
;
501 else if (state
&& state
->sessionkey
502 && state
->clientqop
& GSASL_QOP_AUTH_INT
)
504 res
= shishi_safe (state
->sh
, &state
->safe
);
505 if (res
!= SHISHI_OK
)
506 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
508 res
= shishi_safe_set_user_data (state
->sh
,
509 shishi_safe_safe (state
->safe
),
511 if (res
!= SHISHI_OK
)
512 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
514 res
= shishi_safe_build (state
->safe
, state
->sessionkey
);
515 if (res
!= SHISHI_OK
)
516 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
518 res
= shishi_safe_safe_der (state
->safe
, output
, output_len
);
519 if (res
!= SHISHI_OK
)
520 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
524 *output_len
= input_len
;
525 *output
= malloc (input_len
);
527 return GSASL_MALLOC_ERROR
;
528 memcpy (*output
, input
, input_len
);
535 _gsasl_kerberos_v5_server_decode (Gsasl_session
* sctx
,
539 char *output
, size_t * output_len
)
541 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
544 if (state
&& state
->sessionkey
&& state
->clientqop
& GSASL_QOP_AUTH_CONF
)
546 return GSASL_INTEGRITY_ERROR
;
548 else if (state
&& state
->sessionkey
549 && state
->clientqop
& GSASL_QOP_AUTH_INT
)
551 Shishi_asn1 asn1safe
;
553 res
= shishi_safe (state
->sh
, &state
->safe
);
554 if (res
!= SHISHI_OK
)
555 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
557 res
= shishi_safe_safe_der_set (state
->safe
, input
, input_len
);
558 if (res
!= SHISHI_OK
)
559 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
561 res
= shishi_safe_verify (state
->safe
, state
->sessionkey
);
562 if (res
!= SHISHI_OK
)
563 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
565 res
= shishi_safe_user_data (state
->sh
, shishi_safe_safe (state
->safe
),
567 if (res
!= SHISHI_OK
)
568 return GSASL_KERBEROS_V5_INTERNAL_ERROR
;
574 *output_len
= input_len
;
575 *output
= malloc (input_len
);
577 return GSASL_MALLOC_ERROR
;
578 memcpy (*output
, input
, input_len
);
586 _gsasl_kerberos_v5_server_finish (Gsasl_session
* sctx
, void *mech_data
)
588 struct _Gsasl_kerberos_v5_server_state
*state
= mech_data
;
590 shishi_done (state
->sh
);
592 free (state
->username
);
594 free (state
->password
);
596 free (state
->random
);