gsasl  1.10.0
About: GNU SASL is an implementation of the Simple Authentication and Security Layer (SASL). Development version.
  Fossies Dox: gsasl-1.10.0.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

server.c
Go to the documentation of this file.
1 /* server.c --- Experimental SASL mechanism KERBEROS_V5, server side.
2  * Copyright (C) 2003-2021 Simon Josefsson
3  *
4  * This file is part of GNU SASL Library.
5  *
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.
10  *
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.
15  *
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.
20  *
21  * NB! Shishi is licensed under GPL, so linking GSASL with it require
22  * that you follow the GPL for GSASL as well.
23  *
24  */
25 
26 #include "kerberos_v5.h"
27 
28 #include "shared.h"
29 
31 {
32  int firststep;
33  Shishi *sh;
35  char *random;
38  int clientqop;
41  char *username;
42  char *userrealm;
43  char *serverrealm;
46  char *password;
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 */
50  Shishi_ap *ap;
51  Shishi_as *as;
52  Shishi_safe *safe;
53 };
54 
55 int
57 {
58  if (!shishi_check_version (SHISHI_VERSION))
60 
61  return GSASL_OK;
62 }
63 
64 int
66 {
67  struct _Gsasl_kerberos_v5_server_state *state;
68  int err;
69 
70  state = malloc (sizeof (*state));
71  if (state == NULL)
72  return GSASL_MALLOC_ERROR;
73  memset (state, 0, sizeof (*state));
74 
75  state->random = (char *) malloc (RANDOM_LEN);
76  if (state->random == NULL)
77  return GSASL_MALLOC_ERROR;
78 
79  err = shishi_init_server (&state->sh);
80  if (err)
82 
83  err = shishi_randomize (state->sh, state->random, RANDOM_LEN);
84  if (err)
86 
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);
90  if (err)
92 
93  err = shishi_as (state->sh, &state->as);
94  if (err)
96 
97  state->firststep = 1;
99 
100  *mech_data = state;
101 
102  return GSASL_OK;
103 }
104 
105 int
107  void *mech_data,
108  const char *input,
109  size_t input_len,
110  char *output, size_t *output_len)
111 {
112  struct _Gsasl_kerberos_v5_server_state *state = mech_data;
117  Gsasl_server_callback_retrieve cb_retrieve;
119  unsigned char buf[BUFSIZ];
120  size_t buflen;
121  Gsasl_ctx *ctx;
122  ASN1_TYPE asn1;
123  int err;
124 
125  ctx = gsasl_server_ctx_get (sctx);
126  if (ctx == NULL)
127  return GSASL_CANNOT_GET_CTX;
128 
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)
136 
137  if (state->firststep)
138  {
139  uint32_t tmp;
140  unsigned char *p;
141 
142  /*
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).
149  *
150  * The security layers and their corresponding bit-masks are as
151  * follows:
152  *
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).
158  *
159  * Other bit-masks may be defined in the future; bits which are
160  * not understood must be negotiated off.
161  *
162  */
163  if (output && *output_len < BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN)
164  return GSASL_TOO_SMALL_BUFFER;
165 
166  p = &state->serverhello[0];
167 
168  if (cb_qop)
169  state->serverqops = cb_qop (sctx);
170  *p = 0;
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)
177  /* XXX we always require mutual authentication for now */
178  *p |= MUTUAL;
179 
180  if (!(state->serverqops & ~GSASL_QOP_AUTH))
181  state->servermaxbuf = 0;
182  else if (cb_maxbuf)
183  state->servermaxbuf = cb_maxbuf (sctx);
184  else
185  state->servermaxbuf = MAXBUF_DEFAULT;
186 
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);
191 
192  if (output)
193  memcpy (output, state->serverhello, SERVER_HELLO_LEN);
194  *output_len = BITMAP_LEN + MAXBUF_LEN + RANDOM_LEN;
195 
196  state->firststep = 0;
197 
198  return GSASL_NEEDS_MORE;
199  }
200 
201  if (cb_retrieve)
202  {
203  /* Non-infrastructure mode */
204 
205  if (*output_len < 2048)
206  return GSASL_TOO_SMALL_BUFFER;
207 
208  if (shishi_as_req_der_set (state->as, input, input_len) == SHISHI_OK)
209  {
210  Shishi_tkt *tkt;
211  int etype, i;
212 
213  tkt = shishi_as_tkt (state->as);
214  if (!tkt)
216 
217  i = 1;
218  do
219  {
220  err = shishi_kdcreq_etype (state->sh,
221  shishi_as_req (state->as),
222  &etype, i);
223  if (err == SHISHI_OK && shishi_cipher_supported_p (etype))
224  break;
225  }
226  while (err == SHISHI_OK);
227  if (err != SHISHI_OK)
228  return err;
229 
230  /* XXX use a "preferred server kdc etype" from shishi instead? */
231  err = shishi_key_random (state->sh, etype, &state->sessionkey);
232  if (err)
234 
235  err = shishi_tkt_key_set (tkt, state->sessionkey);
236  if (err)
238 
239  buflen = sizeof (buf) - 1;
240  err = shishi_kdcreq_cname_get (state->sh,
241  shishi_as_req (state->as),
242  buf, &buflen);
243  if (err != SHISHI_OK)
244  return err;
245  buf[buflen] = '\0';
246  state->username = strdup (buf);
247 
248  buflen = sizeof (buf) - 1;
249  err = shishi_kdcreq_realm_get (state->sh,
250  shishi_as_req (state->as),
251  buf, &buflen);
252  if (err != SHISHI_OK)
253  return err;
254  buf[buflen] = '\0';
255  state->userrealm = strdup (buf);
256 
257  buflen = sizeof (buf) - 1;
258  err = cb_retrieve (sctx, state->username, NULL, state->userrealm,
259  NULL, &buflen);
260  if (err != GSASL_OK)
261  return err;
262 
263  state->password = malloc (buflen + 1);
264  if (state->password == NULL)
265  return GSASL_MALLOC_ERROR;
266 
267  err = cb_retrieve (sctx, state->username, NULL, state->userrealm,
268  state->password, &buflen);
269  if (err != GSASL_OK)
270  return err;
271  state->password[buflen] = '\0';
272 
273  buflen = sizeof (buf) - 1;
274  if (cb_realm)
275  {
276  err = cb_realm (sctx, buf, &buflen, 0);
277  if (err != GSASL_OK)
278  return err;
279  }
280  else
281  buflen = 0;
282  buf[buflen] = '\0';
283  state->serverrealm = strdup (buf);
284 
285  buflen = sizeof (buf) - 1;
286  err = cb_service (sctx, buf, &buflen, NULL, NULL);
287  if (err != GSASL_OK)
288  return err;
289  buf[buflen] = '\0';
290  state->serverservice = strdup (buf);
291 
292  buflen = sizeof (buf) - 1;
293  err = cb_service (sctx, NULL, NULL, buf, &buflen);
294  if (err != GSASL_OK)
295  return err;
296  buf[buflen] = '\0';
297  state->serverhostname = strdup (buf);
298 
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. */
302 
303  err = shishi_tkt_clientrealm_set (tkt, state->userrealm,
304  state->username);
305  if (err)
307 
308  {
309  char *p;
310  p = malloc (strlen (state->serverservice) + strlen ("/") +
311  strlen (state->serverhostname) + 1);
312  if (p == NULL)
313  return GSASL_MALLOC_ERROR;
314  sprintf (p, "%s/%s", state->serverservice, state->serverhostname);
315  err = shishi_tkt_serverrealm_set (tkt, state->serverrealm, p);
316  free (p);
317  if (err)
319  }
320 
321  buflen = sizeof (buf);
322  err = shishi_as_derive_salt (state->sh,
323  shishi_as_req (state->as),
324  shishi_as_rep (state->as),
325  buf, &buflen);
326  if (err != SHISHI_OK)
327  return err;
328 
329  err = shishi_key_from_string (state->sh,
330  etype,
331  state->password,
332  strlen (state->password),
333  buf, buflen, NULL, &state->userkey);
334  if (err != SHISHI_OK)
335  return err;
336 
337  err = shishi_tkt_build (tkt, state->sessiontktkey);
338  if (err)
340 
341  err = shishi_as_rep_build (state->as, state->userkey);
342  if (err)
344 
345 #if DEBUG
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));
353 #endif
354 
355  err = shishi_as_rep_der (state->as, output, output_len);
356  if (err)
358 
359  return GSASL_NEEDS_MORE;
360  }
361  else if ((asn1 = shishi_der2asn1_apreq (state->sh, input, input_len)))
362  {
363  int adtype;
364 
365  err = shishi_ap (state->sh, &state->ap);
366  if (err)
368 
369  shishi_ap_req_set (state->ap, asn1);
370 
371  err = shishi_ap_req_process (state->ap, state->sessiontktkey);
372  if (err)
374 
375 #if DEBUG
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));
381 #endif
382 
383  buflen = sizeof (buf);
384  err = shishi_authenticator_authorizationdata
385  (state->sh, shishi_ap_authenticator (state->ap),
386  &adtype, buf, &buflen, 1);
387  if (err)
389 
390  if (adtype != 0xFF /* -1 in one-complements form */ ||
393 
394  {
395  unsigned char clientbitmap;
396 
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;
407  }
408  memcpy (&state->clientmaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
409  state->clientmaxbuf = ntohl (state->clientmaxbuf);
410 
411  if (!(state->clientqop & state->serverqops))
413 
414  /* XXX check clientmaxbuf too */
415 
416  if (memcmp (&buf[CLIENT_HELLO_LEN],
417  state->serverhello, SERVER_HELLO_LEN) != 0)
419 
420  {
421  char cksum[BUFSIZ];
422  int cksumlen;
423  int cksumtype;
424  Shishi_key *key;
425 
426  key = shishi_tkt_key (shishi_as_tkt (state->as));
427  cksumtype =
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)
435 
436  buflen = sizeof (buf);
437  err = shishi_authenticator_cksum
438  (state->sh,
439  shishi_ap_authenticator (state->ap), &cksumtype, buf, &buflen);
440  if (err != SHISHI_OK)
442 
443  if (buflen != cksumlen || memcmp (buf, cksum, buflen) != 0)
445  }
446 
447  /* XXX use authorization_id */
448 
449  if (state->clientmutual)
450  {
451  err = shishi_ap_rep_build (state->ap);
452  if (err)
454 
455  err = shishi_ap_rep_der (state->ap, output, output_len);
456  if (err)
458  }
459  else
460  *output_len = 0;
461 
462  return GSASL_OK;
463  }
464  }
465  else
466  {
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.
471 
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
479  */
481  }
482 
483  *output_len = 0;
484  return GSASL_NEEDS_MORE;
485 }
486 
487 int
489  void *mech_data,
490  const char *input,
491  size_t input_len,
492  char *output, size_t *output_len)
493 {
494  struct _Gsasl_kerberos_v5_server_state *state = mech_data;
495  int res;
496 
497  if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
498  {
499  return GSASL_INTEGRITY_ERROR;
500  }
501  else if (state && state->sessionkey
502  && state->clientqop & GSASL_QOP_AUTH_INT)
503  {
504  res = shishi_safe (state->sh, &state->safe);
505  if (res != SHISHI_OK)
507 
508  res = shishi_safe_set_user_data (state->sh,
509  shishi_safe_safe (state->safe),
510  input, input_len);
511  if (res != SHISHI_OK)
513 
514  res = shishi_safe_build (state->safe, state->sessionkey);
515  if (res != SHISHI_OK)
517 
518  res = shishi_safe_safe_der (state->safe, output, output_len);
519  if (res != SHISHI_OK)
521  }
522  else
523  {
524  *output_len = input_len;
525  *output = malloc (input_len);
526  if (!*output)
527  return GSASL_MALLOC_ERROR;
528  memcpy (*output, input, input_len);
529  }
530 
531  return GSASL_OK;
532 }
533 
534 int
536  void *mech_data,
537  const char *input,
538  size_t input_len,
539  char *output, size_t *output_len)
540 {
541  struct _Gsasl_kerberos_v5_server_state *state = mech_data;
542  int res;
543 
544  if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
545  {
546  return GSASL_INTEGRITY_ERROR;
547  }
548  else if (state && state->sessionkey
549  && state->clientqop & GSASL_QOP_AUTH_INT)
550  {
551  Shishi_asn1 asn1safe;
552 
553  res = shishi_safe (state->sh, &state->safe);
554  if (res != SHISHI_OK)
556 
557  res = shishi_safe_safe_der_set (state->safe, input, input_len);
558  if (res != SHISHI_OK)
560 
561  res = shishi_safe_verify (state->safe, state->sessionkey);
562  if (res != SHISHI_OK)
564 
565  res = shishi_safe_user_data (state->sh, shishi_safe_safe (state->safe),
566  output, output_len);
567  if (res != SHISHI_OK)
569 
570  return GSASL_OK;
571  }
572  else
573  {
574  *output_len = input_len;
575  *output = malloc (input_len);
576  if (!*output)
577  return GSASL_MALLOC_ERROR;
578  memcpy (*output, input, input_len);
579  }
580 
581 
582  return GSASL_OK;
583 }
584 
585 int
587 {
588  struct _Gsasl_kerberos_v5_server_state *state = mech_data;
589 
590  shishi_done (state->sh);
591 
592  free (state->username);
593  free (state->password);
594  free (state->random);
595  free (state);
596 
597  return GSASL_OK;
598 }
#define NULL
Definition: stddef.in.h:72
#define uint32_t
Definition: stdint.in.h:168
GSASL_API Gsasl_server_callback_qop gsasl_server_callback_qop_get(Gsasl *ctx)
Definition: obsolete.c:1401
size_t(* Gsasl_server_callback_maxbuf)(Gsasl_session *sctx)
Definition: gsasl-compat.h:222
Gsasl_qop(* Gsasl_server_callback_qop)(Gsasl_session *sctx)
Definition: gsasl-compat.h:221
int(* Gsasl_server_callback_service)(Gsasl_session *sctx, char *service, size_t *servicelen, char *hostname, size_t *hostnamelen)
Definition: gsasl-compat.h:211
@ GSASL_CANNOT_GET_CTX
Definition: gsasl-compat.h:40
@ GSASL_TOO_SMALL_BUFFER
Definition: gsasl-compat.h:36
@ GSASL_NEED_SERVER_RETRIEVE_CALLBACK
Definition: gsasl-compat.h:57
@ GSASL_NEED_SERVER_SERVICE_CALLBACK
Definition: gsasl-compat.h:55
int(* Gsasl_server_callback_retrieve)(Gsasl_session *sctx, const char *authentication_id, const char *authorization_id, const char *realm, char *key, size_t *keylen)
Definition: gsasl-compat.h:186
GSASL_API Gsasl_server_callback_realm gsasl_server_callback_realm_get(Gsasl *ctx)
Definition: obsolete.c:1358
GSASL_API Gsasl * gsasl_server_ctx_get(Gsasl_session *sctx)
Definition: obsolete.c:372
GSASL_API Gsasl_server_callback_service gsasl_server_callback_service_get(Gsasl *ctx)
Definition: obsolete.c:1628
Gsasl_cipher(* Gsasl_server_callback_cipher)(Gsasl_session *sctx)
Definition: gsasl-compat.h:223
GSASL_API Gsasl_server_callback_retrieve gsasl_server_callback_retrieve_get(Gsasl *ctx)
Definition: obsolete.c:1146
GSASL_API Gsasl_server_callback_maxbuf gsasl_server_callback_maxbuf_get(Gsasl *ctx)
Definition: obsolete.c:1446
int(* Gsasl_server_callback_realm)(Gsasl_session *sctx, char *out, size_t *outlen, size_t nth)
Definition: gsasl-compat.h:219
@ GSASL_QOP_AUTH_CONF
Definition: gsasl.h:237
@ GSASL_QOP_AUTH
Definition: gsasl.h:235
@ GSASL_QOP_AUTH_INT
Definition: gsasl.h:236
@ GSASL_KERBEROS_V5_INIT_ERROR
Definition: gsasl.h:207
@ GSASL_OK
Definition: gsasl.h:171
@ GSASL_AUTHENTICATION_ERROR
Definition: gsasl.h:180
@ GSASL_NEEDS_MORE
Definition: gsasl.h:172
@ GSASL_MALLOC_ERROR
Definition: gsasl.h:175
@ GSASL_KERBEROS_V5_INTERNAL_ERROR
Definition: gsasl.h:208
@ GSASL_INTEGRITY_ERROR
Definition: gsasl.h:181
@ GSASL_UNKNOWN_MECHANISM
Definition: gsasl.h:173
static gss_OID_desc tmp
Definition: gss-extra.c:38
int _gsasl_kerberos_v5_server_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char *output, size_t *output_len)
Definition: server.c:106
int _gsasl_kerberos_v5_server_init(Gsasl_ctx *ctx)
Definition: server.c:56
int _gsasl_kerberos_v5_server_start(Gsasl_session *sctx, void **mech_data)
Definition: server.c:65
int _gsasl_kerberos_v5_server_encode(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char *output, size_t *output_len)
Definition: server.c:488
int _gsasl_kerberos_v5_server_finish(Gsasl_session *sctx, void *mech_data)
Definition: server.c:586
int _gsasl_kerberos_v5_server_decode(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char *output, size_t *output_len)
Definition: server.c:535
int res
Definition: mbrtowc-impl.h:45
const char * p
Definition: mbrtowc-impl.h:42
char buf[4]
Definition: mbrtowc-impl.h:39
#define CLIENT_HELLO_LEN
Definition: shared.h:40
#define BITMAP_LEN
Definition: shared.h:34
#define MAXBUF_LEN
Definition: shared.h:35
#define SERVER_HELLO_LEN
Definition: shared.h:39
#define MUTUAL
Definition: shared.h:37
#define MAXBUF_DEFAULT
Definition: shared.h:42
#define RANDOM_LEN
Definition: shared.h:36
char * strdup(const char *s)
Definition: strdup.c:39
Definition: internal.h:41
Shishi_key * sessiontktkey
Definition: server.c:49