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)  

client.c
Go to the documentation of this file.
1 /* client.c --- Experimental SASL mechanism KERBEROS_V5, client 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 step;
35  int clientqop;
39  Shishi *sh;
40  Shishi_tkt *tkt;
41  Shishi_as *as;
42  Shishi_ap *ap;
43  Shishi_key *sessionkey;
44  Shishi_safe *safe;
45 };
46 
47 int
49 {
50  if (!shishi_check_version (SHISHI_VERSION))
52 
53  return GSASL_OK;
54 }
55 
56 int
58 {
59  struct _Gsasl_kerberos_v5_client_state *state;
60  Gsasl_ctx *ctx;
61  int err;
62 
63  state = malloc (sizeof (*state));
64  if (state == NULL)
65  return GSASL_MALLOC_ERROR;
66 
67  memset (state, 0, sizeof (*state));
68 
69  err = shishi_init (&state->sh);
70  if (err)
72 
73  state->step = 0;
75 
76  *mech_data = state;
77 
78  return GSASL_OK;
79 }
80 
81 #define STEP_FIRST 0
82 #define STEP_NONINFRA_SEND_ASREQ 1
83 #define STEP_NONINFRA_WAIT_ASREP 2
84 #define STEP_NONINFRA_SEND_APREQ 3
85 #define STEP_NONINFRA_WAIT_APREP 4
86 #define STEP_SUCCESS 5
87 
88 int
90  void *mech_data,
91  const char *input,
92  size_t input_len,
93  char *output, size_t *output_len)
94 {
95  struct _Gsasl_kerberos_v5_client_state *state = mech_data;
96  Gsasl_client_callback_authentication_id cb_authentication_id;
97  Gsasl_client_callback_authorization_id cb_authorization_id;
100  Gsasl_client_callback_password cb_password;
103  Gsasl_ctx *ctx;
104  int res;
105  int len;
106 
107  ctx = gsasl_client_ctx_get (sctx);
108  if (ctx == NULL)
109  return GSASL_CANNOT_GET_CTX;
110 
111  /* These are optional */
112  cb_realm = gsasl_client_callback_realm_get (ctx);
113  cb_service = gsasl_client_callback_service_get (ctx);
114  cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
115  cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
116  cb_qop = gsasl_client_callback_qop_get (ctx);
117  cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);
118 
119  /* Only optionally needed in infrastructure mode */
120  cb_password = gsasl_client_callback_password_get (ctx);
121  if (cb_password == NULL)
123 
124  /* I think we really need this one */
125  cb_service = gsasl_client_callback_service_get (ctx);
126  if (cb_service == NULL)
128 
129  switch (state->step)
130  {
131  case STEP_FIRST:
132  if (input == NULL)
133  {
134  *output_len = 0;
135  return GSASL_NEEDS_MORE;
136  }
137 
138  if (input_len != SERVER_HELLO_LEN)
140 
141  memcpy (state->serverhello, input, input_len);
142 
143  {
144  unsigned char serverbitmap;
145 
146  memcpy (&serverbitmap, input, BITMAP_LEN);
147  state->serverqops = 0;
148  if (serverbitmap & GSASL_QOP_AUTH)
149  state->serverqops |= GSASL_QOP_AUTH;
150  if (serverbitmap & GSASL_QOP_AUTH_INT)
151  state->serverqops |= GSASL_QOP_AUTH_INT;
152  if (serverbitmap & GSASL_QOP_AUTH_CONF)
154  if (serverbitmap & MUTUAL)
155  state->servermutual = 1;
156  }
157  memcpy (&state->servermaxbuf, &input[BITMAP_LEN], MAXBUF_LEN);
158  state->servermaxbuf = ntohl (state->servermaxbuf);
159 
160  if (cb_qop)
161  state->clientqop = cb_qop (sctx, state->serverqops);
162 
163  if (!(state->serverqops & state->clientqop &
166 
167  /* XXX for now we require server authentication */
168  if (!state->servermutual)
170 
171  /* Decide policy here: non-infrastructure, infrastructure or proxy.
172  *
173  * A callback to decide should be added, but without the default
174  * should be:
175  *
176  * IF shishi_tktset_get_for_server() THEN
177  * INFRASTRUCTURE MODE
178  * ELSE IF shishi_realm_for_server(server) THEN
179  * PROXY INFRASTRUCTURE (then fallback to NIM?)
180  * ELSE
181  * NON-INFRASTRUCTURE MODE
182  */
183  state->step = STEP_NONINFRA_SEND_APREQ; /* only NIM for now.. */
184  /* fall through */
185 
187  res = shishi_as (state->sh, &state->as);
188  if (res)
190 
191  if (cb_authentication_id) /* Shishi defaults to one otherwise */
192  {
193  len = *output_len - 1;
194  res = cb_authentication_id (sctx, output, &len);
195  if (res != GSASL_OK)
196  return res;
197  output[len] = '\0';
198 
199  res = shishi_kdcreq_set_cname (state->sh, shishi_as_req (state->as),
200  SHISHI_NT_UNKNOWN, output);
201  if (res != GSASL_OK)
202  return res;
203  }
204 
205  if (cb_realm)
206  {
207  len = *output_len - 1;
208  res = cb_realm (sctx, output, &len);
209  if (res != GSASL_OK)
210  return res;
211  }
212  else
213  len = 0;
214 
215  output[len] = '\0';
216  res = shishi_kdcreq_set_realm (state->sh, shishi_as_req (state->as),
217  output);
218  if (res != GSASL_OK)
219  return res;
220 
221  if (cb_service)
222  {
223  char *sname[3];
224  size_t servicelen = 0;
225  size_t hostnamelen = 0;
226 
227  res = cb_service (sctx, NULL, &servicelen, NULL, &hostnamelen,
228  /* XXX support servicename a'la DIGEST-MD5 too? */
229  NULL, NULL);
230  if (res != GSASL_OK)
231  return res;
232 
233  if (*output_len < servicelen + 1 + hostnamelen + 1)
234  return GSASL_TOO_SMALL_BUFFER;
235 
236  sname[0] = &output[0];
237  sname[1] = &output[servicelen + 2];
238  sname[2] = NULL;
239 
240  res = cb_service (sctx, sname[0], &servicelen,
241  sname[1], &hostnamelen, NULL, NULL);
242  if (res != GSASL_OK)
243  return res;
244 
245  sname[0][servicelen] = '\0';
246  sname[1][hostnamelen] = '\0';
247 
248  res = shishi_kdcreq_set_sname (state->sh, shishi_as_req (state->as),
249  SHISHI_NT_UNKNOWN, sname);
250  if (res != GSASL_OK)
251  return res;
252  }
253 
254  /* XXX query application for encryption types and set the etype
255  field? Already configured by shishi though... */
256 
257  res = shishi_a2d (state->sh, shishi_as_req (state->as),
258  output, output_len);
259  if (res != SHISHI_OK)
261 
263 
265  break;
266 
268  if (shishi_as_rep_der_set (state->as, input, input_len) != SHISHI_OK)
270 
271  /* XXX? password stored in callee's output buffer */
272  len = *output_len - 1;
273  res = cb_password (sctx, output, &len);
274  if (res != GSASL_OK && res != GSASL_NEEDS_MORE)
275  return res;
276  output[len] = '\0';
277 
278  res = shishi_as_rep_process (state->as, NULL, output);
279  if (res != SHISHI_OK)
281 
283  /* fall through */
284 
286  if (*output_len <= CLIENT_HELLO_LEN + SERVER_HELLO_LEN)
287  return GSASL_TOO_SMALL_BUFFER;
288 
289  if (!(state->clientqop & ~GSASL_QOP_AUTH))
290  state->clientmaxbuf = 0;
291  else if (cb_maxbuf)
292  state->clientmaxbuf = cb_maxbuf (sctx, state->servermaxbuf);
293  else
294  state->clientmaxbuf = MAXBUF_DEFAULT;
295 
296  /* XXX for now we require server authentication */
297  output[0] = state->clientqop | MUTUAL;
298  {
299  uint32_t tmp;
300 
301  tmp = ntohl (state->clientmaxbuf);
302  memcpy (&output[BITMAP_LEN], &tmp, MAXBUF_LEN);
303  }
304  memcpy (&output[CLIENT_HELLO_LEN], state->serverhello,
306 
307  if (cb_authorization_id)
308  {
309  len = *output_len - CLIENT_HELLO_LEN + SERVER_HELLO_LEN;
310  res = cb_authorization_id (sctx, &output[CLIENT_HELLO_LEN +
311  SERVER_HELLO_LEN], &len);
312  }
313  else
314  len = 0;
315 
317  res = shishi_ap_tktoptionsdata (state->sh,
318  &state->ap,
319  shishi_as_tkt (state->as),
320  SHISHI_APOPTIONS_MUTUAL_REQUIRED,
321  output, len);
322  if (res != SHISHI_OK)
324 
325  res = shishi_authenticator_add_authorizationdata
326  (state->sh, shishi_ap_authenticator (state->ap), -1, output, len);
327  if (res != SHISHI_OK)
329 
330  /* XXX set realm in AP-REQ and Authenticator */
331 
332  res = shishi_ap_req_der (state->ap, output, output_len);
333  if (res != SHISHI_OK)
335 
337 
339  break;
340 
342  if (shishi_ap_rep_der_set (state->ap, input, input_len) != SHISHI_OK)
344 
345  res = shishi_ap_rep_verify (state->ap);
346  if (res != SHISHI_OK)
348 
349  state->step = STEP_SUCCESS;
350 
351  /* XXX support AP session keys */
352  state->sessionkey = shishi_tkt_key (shishi_as_tkt (state->as));
353 
354  *output_len = 0;
355  res = GSASL_OK;
356  break;
357 
358  default:
360  break;
361  }
362 
363  return res;
364 }
365 
366 int
368  void *mech_data,
369  const char *input,
370  size_t input_len,
371  char **output, size_t *output_len)
372 {
373  struct _Gsasl_kerberos_v5_client_state *state = mech_data;
374  int res;
375 
376  if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
377  {
378  return GSASL_INTEGRITY_ERROR;
379  }
380  else if (state && state->sessionkey
381  && state->clientqop & GSASL_QOP_AUTH_INT)
382  {
383  res = shishi_safe (state->sh, &state->safe);
384  if (res != SHISHI_OK)
386 
387  res = shishi_safe_set_user_data (state->sh,
388  shishi_safe_safe (state->safe),
389  input, input_len);
390  if (res != SHISHI_OK)
392 
393  res = shishi_safe_build (state->safe, state->sessionkey);
394  if (res != SHISHI_OK)
396 
397  res = shishi_safe_safe_der (state->safe, output, output_len);
398  if (res != SHISHI_OK)
400  }
401  else
402  {
403  *output_len = input_len;
404  *output = malloc (input_len);
405  if (!*output)
406  return GSASL_MALLOC_ERROR;
407  memcpy (*output, input, input_len);
408  }
409 
410  return GSASL_OK;
411 }
412 
413 int
415  void *mech_data,
416  const char *input,
417  size_t input_len,
418  char *output, size_t *output_len)
419 {
420  struct _Gsasl_kerberos_v5_client_state *state = mech_data;
421 
422  if (state && state->sessionkey && state->clientqop & GSASL_QOP_AUTH_CONF)
423  {
424  return GSASL_INTEGRITY_ERROR;
425  }
426  else if (state && state->sessionkey
427  && state->clientqop & GSASL_QOP_AUTH_INT)
428  {
429  return GSASL_INTEGRITY_ERROR;
430  }
431  else
432  {
433  *output_len = input_len;
434  *output = malloc (input_len);
435  if (!*output)
436  return GSASL_MALLOC_ERROR;
437  memcpy (*output, input, input_len);
438  }
439 
440  return GSASL_OK;
441 }
442 
443 int
445 {
446  struct _Gsasl_kerberos_v5_client_state *state = mech_data;
447 
448  shishi_done (state->sh);
449  free (state);
450 
451  return GSASL_OK;
452 }
#define NULL
Definition: stddef.in.h:72
#define uint32_t
Definition: stdint.in.h:168
int(* Gsasl_client_callback_password)(Gsasl_session *sctx, char *out, size_t *outlen)
Definition: gsasl-compat.h:166
size_t(* Gsasl_client_callback_maxbuf)(Gsasl_session *sctx, size_t servermaxbuf)
Definition: gsasl-compat.h:182
int(* Gsasl_client_callback_realm)(Gsasl_session *sctx, char *out, size_t *outlen)
Definition: gsasl-compat.h:184
GSASL_API Gsasl_client_callback_authorization_id gsasl_client_callback_authorization_id_get(Gsasl *ctx)
Definition: obsolete.c:714
GSASL_API Gsasl_client_callback_realm gsasl_client_callback_realm_get(Gsasl *ctx)
Definition: obsolete.c:1060
GSASL_API Gsasl_client_callback_service gsasl_client_callback_service_get(Gsasl *ctx)
Definition: obsolete.c:889
@ GSASL_CANNOT_GET_CTX
Definition: gsasl-compat.h:40
@ GSASL_TOO_SMALL_BUFFER
Definition: gsasl-compat.h:36
@ GSASL_NEED_CLIENT_SERVICE_CALLBACK
Definition: gsasl-compat.h:47
@ GSASL_NEED_CLIENT_PASSWORD_CALLBACK
Definition: gsasl-compat.h:42
GSASL_API Gsasl * gsasl_client_ctx_get(Gsasl_session *sctx)
Definition: obsolete.c:315
int(* Gsasl_client_callback_service)(Gsasl_session *sctx, char *service, size_t *servicelen, char *hostname, size_t *hostnamelen, char *servicename, size_t *servicenamelen)
Definition: gsasl-compat.h:173
Gsasl_qop(* Gsasl_client_callback_qop)(Gsasl_session *sctx, Gsasl_qop serverqops)
Definition: gsasl-compat.h:180
int(* Gsasl_client_callback_authorization_id)(Gsasl_session *sctx, char *out, size_t *outlen)
Definition: gsasl-compat.h:163
GSASL_API Gsasl_client_callback_qop gsasl_client_callback_qop_get(Gsasl *ctx)
Definition: obsolete.c:973
GSASL_API Gsasl_client_callback_maxbuf gsasl_client_callback_maxbuf_get(Gsasl *ctx)
Definition: obsolete.c:1018
int(* Gsasl_client_callback_authentication_id)(Gsasl_session *sctx, char *out, size_t *outlen)
Definition: gsasl-compat.h:160
GSASL_API Gsasl_client_callback_password gsasl_client_callback_password_get(Gsasl *ctx)
Definition: obsolete.c:757
GSASL_API Gsasl_client_callback_authentication_id gsasl_client_callback_authentication_id_get(Gsasl *ctx)
Definition: obsolete.c:671
@ 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_MECHANISM_CALLED_TOO_MANY_TIMES
Definition: gsasl.h:174
@ GSASL_MECHANISM_PARSE_ERROR
Definition: gsasl.h:179
@ 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
#define STEP_NONINFRA_SEND_ASREQ
Definition: client.c:82
int _gsasl_kerberos_v5_client_encode(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: client.c:367
#define STEP_NONINFRA_WAIT_ASREP
Definition: client.c:83
int _gsasl_kerberos_v5_client_start(Gsasl_session *sctx, void **mech_data)
Definition: client.c:57
int _gsasl_kerberos_v5_client_init(Gsasl_ctx *ctx)
Definition: client.c:48
#define STEP_FIRST
Definition: client.c:81
int _gsasl_kerberos_v5_client_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char *output, size_t *output_len)
Definition: client.c:89
#define STEP_NONINFRA_SEND_APREQ
Definition: client.c:84
int _gsasl_kerberos_v5_client_decode(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char *output, size_t *output_len)
Definition: client.c:414
int _gsasl_kerberos_v5_client_finish(Gsasl_session *sctx, void *mech_data)
Definition: client.c:444
#define STEP_SUCCESS
Definition: client.c:86
#define STEP_NONINFRA_WAIT_APREP
Definition: client.c:85
int res
Definition: mbrtowc-impl.h:45
#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
Definition: internal.h:41