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 --- DIGEST-MD5 mechanism from RFC 2831, client side.
2  * Copyright (C) 2002-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  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 
27 /* Get specification. */
28 #include "digest-md5.h"
29 
30 /* Get malloc, free. */
31 #include <stdlib.h>
32 
33 /* Get memcpy, strlen. */
34 #include <string.h>
35 
36 #include "gc.h"
37 
38 /* Get tools. */
39 #include "nonascii.h"
40 #include "tokens.h"
41 #include "parser.h"
42 #include "printer.h"
43 #include "free.h"
44 #include "session.h"
45 #include "digesthmac.h"
46 #include "qop.h"
47 
48 #include "mechtools.h"
49 
50 #define CNONCE_ENTROPY_BYTES 16
51 
53 {
54  int step;
55  unsigned long readseqnum, sendseqnum;
64 };
66 
67 int
69  void **mech_data)
70 {
72  char nonce[CNONCE_ENTROPY_BYTES];
73  char *p;
74  int rc;
75 
77  if (rc != GSASL_OK)
78  return rc;
79 
81  if (rc != GSASL_OK)
82  return rc;
83 
84  state = calloc (1, sizeof (*state));
85  if (state == NULL)
86  {
87  free (p);
88  return GSASL_MALLOC_ERROR;
89  }
90 
91  state->response.cnonce = p;
92  state->response.nc = 1;
93 
94  *mech_data = state;
95 
96  return GSASL_OK;
97 }
98 
99 int
101  void *mech_data,
102  const char *input,
103  size_t input_len,
104  char **output, size_t *output_len)
105 {
106  _Gsasl_digest_md5_client_state *state = mech_data;
107  int rc, res;
108 
109  *output = NULL;
110  *output_len = 0;
111 
112  if (state->step == 0)
113  {
114  state->step++;
115  if (input_len == 0)
116  return GSASL_NEEDS_MORE;
117  }
118 
119  switch (state->step)
120  {
121  case 1:
122  {
123  if (digest_md5_parse_challenge (input, input_len,
124  &state->challenge) < 0)
126 
127  /* FIXME: How to let application know of remaining realms?
128  One idea, add a GSASL_REALM_COUNT property, and have the
129  GSASL_REALM be that many concatenated zero terminated realm
130  strings. Slightly hackish, though. Another cleaner
131  approach would be to add gsasl_property_set_array and
132  gsasl_property_get_array APIs, for those properties that
133  may be used multiple times. */
134  if (state->challenge.nrealms > 0)
135  gsasl_property_set (sctx, GSASL_REALM, state->challenge.realms[0]);
136  else
138 
139  /* FIXME: cipher, maxbuf. */
140 
141  /* Create response token. */
142  state->response.utf8 = 1;
143 
146 
147  {
148  const char *qop = gsasl_property_get (sctx, GSASL_QOP);
149 
150  if (!qop)
152  else if (strcmp (qop, "qop-int") == 0)
154  else if (strcmp (qop, "qop-auth") == 0)
156  else
157  /* We don't support confidentiality or unknown
158  keywords. */
160  }
161 
162  state->response.nonce = strdup (state->challenge.nonce);
163  if (!state->response.nonce)
164  return GSASL_MALLOC_ERROR;
165 
166  {
167  const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
168  const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
169  if (!service)
170  return GSASL_NO_SERVICE;
171  if (!hostname)
172  return GSASL_NO_HOSTNAME;
173  if (asprintf (&state->response.digesturi, "%s/%s",
174  service, hostname) < 0)
175  return GSASL_MALLOC_ERROR;
176  }
177 
178  {
179  const char *c;
180  char *tmp, *tmp2;
181 
183  if (!c)
184  return GSASL_NO_AUTHID;
185 
186  state->response.username = strdup (c);
187  if (!state->response.username)
188  return GSASL_MALLOC_ERROR;
189 
191  if (c)
192  {
193  state->response.authzid = strdup (c);
194  if (!state->response.authzid)
195  return GSASL_MALLOC_ERROR;
196  }
197 
200  if (c)
201  {
202  state->response.realm = strdup (c);
203  if (!state->response.realm)
204  return GSASL_MALLOC_ERROR;
205  }
206 
208  if (!c)
209  return GSASL_NO_PASSWORD;
210 
211  tmp2 = utf8tolatin1ifpossible (c);
212 
213  rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
214  state->response.realm ?
215  state->response.realm : "", tmp2);
216  free (tmp2);
217  if (rc < 0)
218  return GSASL_MALLOC_ERROR;
219 
220  rc = gc_md5 (tmp, strlen (tmp), state->secret);
221  free (tmp);
222  if (rc != GC_OK)
223  return GSASL_CRYPTO_ERROR;
224  }
225 
227  state->secret,
228  state->response.nonce,
229  state->response.nc,
230  state->response.cnonce,
231  state->response.qop,
232  state->response.authzid,
233  state->response.digesturi,
234  0,
235  state->response.cipher,
236  state->kic, state->kis, state->kcc, state->kcs);
237  if (rc)
238  return GSASL_CRYPTO_ERROR;
239 
240  *output = digest_md5_print_response (&state->response);
241  if (!*output)
243 
244  *output_len = strlen (*output);
245 
246  state->step++;
248  }
249  break;
250 
251  case 2:
252  {
253  char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
254 
255  if (digest_md5_parse_finish (input, input_len, &state->finish) < 0)
257 
258  res = digest_md5_hmac (check, state->secret,
259  state->response.nonce, state->response.nc,
260  state->response.cnonce, state->response.qop,
261  state->response.authzid,
262  state->response.digesturi, 1,
263  state->response.cipher, NULL, NULL, NULL,
264  NULL);
265  if (res != GSASL_OK)
266  break;
267 
268  if (strcmp (state->finish.rspauth, check) == 0)
269  res = GSASL_OK;
270  else
272  state->step++;
273  }
274  break;
275 
276  default:
278  break;
279  }
280 
281  return res;
282 }
283 
284 void
286  void *mech_data)
287 {
288  _Gsasl_digest_md5_client_state *state = mech_data;
289 
290  if (!state)
291  return;
292 
295  digest_md5_free_finish (&state->finish);
296 
297  free (state);
298 }
299 
300 int
302  void *mech_data,
303  const char *input,
304  size_t input_len,
305  char **output, size_t *output_len)
306 {
307  _Gsasl_digest_md5_client_state *state = mech_data;
308  int res;
309 
310  res = digest_md5_encode (input, input_len, output, output_len,
311  state->response.qop,
312  state->sendseqnum, state->kic);
313  if (res)
314  return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
315 
316  if (state->sendseqnum == 4294967295UL)
317  state->sendseqnum = 0;
318  else
319  state->sendseqnum++;
320 
321  return GSASL_OK;
322 }
323 
324 int
326  void *mech_data,
327  const char *input,
328  size_t input_len,
329  char **output, size_t *output_len)
330 {
331  _Gsasl_digest_md5_client_state *state = mech_data;
332  int res;
333 
334  res = digest_md5_decode (input, input_len, output, output_len,
335  state->response.qop,
336  state->readseqnum, state->kis);
337  if (res)
338  return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
339 
340  if (state->readseqnum == 4294967295UL)
341  state->readseqnum = 0;
342  else
343  state->readseqnum++;
344 
345  return GSASL_OK;
346 }
int gsasl_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop)
Definition: callback.c:75
int gsasl_nonce(char *data, size_t datalen)
Definition: crypto.c:38
int _gsasl_digest_md5_client_decode(Gsasl_session *sctx _GL_UNUSED, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: client.c:325
int _gsasl_digest_md5_client_encode(Gsasl_session *sctx _GL_UNUSED, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: client.c:301
int _gsasl_digest_md5_client_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: client.c:100
void _gsasl_digest_md5_client_finish(Gsasl_session *sctx _GL_UNUSED, void *mech_data)
Definition: client.c:285
#define CNONCE_ENTROPY_BYTES
Definition: client.c:50
int _gsasl_digest_md5_client_start(Gsasl_session *sctx _GL_UNUSED, void **mech_data)
Definition: client.c:68
void digest_md5_free_finish(digest_md5_finish *f)
Definition: free.c:59
void digest_md5_free_response(digest_md5_response *r)
Definition: free.c:46
void digest_md5_free_challenge(digest_md5_challenge *c)
Definition: free.c:33
int digest_md5_parse_challenge(const char *challenge, size_t len, digest_md5_challenge *out)
Definition: parser.c:569
int digest_md5_parse_finish(const char *finish, size_t len, digest_md5_finish *out)
Definition: parser.c:603
char * digest_md5_print_response(digest_md5_response *r)
Definition: printer.c:243
@ DIGEST_MD5_QOP_AUTH_INT
Definition: tokens.h:36
@ DIGEST_MD5_QOP_AUTH
Definition: tokens.h:35
#define DIGEST_MD5_RESPONSE_LENGTH
Definition: tokens.h:95
#define DIGEST_MD5_LENGTH
Definition: tokens.h:30
int digest_md5_hmac(char *output, char secret[16], const char *nonce, unsigned long nc, const char *cnonce, digest_md5_qop qop, const char *authzid, const char *digesturi, int rspauth, digest_md5_cipher cipher, char *kic, char *kis, char *kcc, char *kcs)
Definition: digesthmac.c:79
Gc_rc gc_md5(const void *in, size_t inlen, void *resbuf)
Definition: gc-gnulib.c:982
@ GC_OK
Definition: gc.h:27
int asprintf(char **resultp, const char *format,...)
Definition: asprintf.c:30
#define NULL
Definition: stddef.in.h:72
const char * gsasl_property_get(Gsasl_session *sctx, Gsasl_property prop)
Definition: property.c:263
void gsasl_property_set(Gsasl_session *sctx, Gsasl_property prop, const char *data)
Definition: property.c:158
@ 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_NO_PASSWORD
Definition: gsasl.h:188
@ GSASL_NO_SERVICE
Definition: gsasl.h:191
@ GSASL_MECHANISM_CALLED_TOO_MANY_TIMES
Definition: gsasl.h:174
@ GSASL_NO_HOSTNAME
Definition: gsasl.h:192
@ GSASL_NO_AUTHID
Definition: gsasl.h:186
@ GSASL_MECHANISM_PARSE_ERROR
Definition: gsasl.h:179
@ GSASL_CRYPTO_ERROR
Definition: gsasl.h:177
@ GSASL_INTEGRITY_ERROR
Definition: gsasl.h:181
const char * gsasl_property_fast(Gsasl_session *sctx, Gsasl_property prop)
Definition: property.c:226
@ GSASL_HOSTNAME
Definition: gsasl.h:340
@ GSASL_AUTHZID
Definition: gsasl.h:336
@ GSASL_QOP
Definition: gsasl.h:348
@ GSASL_SERVICE
Definition: gsasl.h:339
@ GSASL_QOPS
Definition: gsasl.h:347
@ GSASL_PASSWORD
Definition: gsasl.h:337
@ GSASL_REALM
Definition: gsasl.h:345
@ GSASL_AUTHID
Definition: gsasl.h:335
static gss_OID_desc tmp
Definition: gss-extra.c:38
int rc
Definition: error.c:42
unsigned char c
int res
Definition: mbrtowc-impl.h:45
const char * p
Definition: mbrtowc-impl.h:42
char * utf8tolatin1ifpossible(const char *passwd)
Definition: nonascii.c:69
const char * digest_md5_qops2qopstr(int qops)
Definition: qop.c:92
int digest_md5_decode(const char *input, size_t input_len, char **output, size_t *output_len, digest_md5_qop qop, unsigned long readseqnum, char key[16])
Definition: session.c:122
int digest_md5_encode(const char *input, size_t input_len, char **output, size_t *output_len, digest_md5_qop qop, unsigned long sendseqnum, char key[16])
Definition: session.c:48
int gsasl_base64_to(const char *in, size_t inlen, char **out, size_t *outlen)
Definition: base64.c:44
char * strdup(const char *s)
Definition: strdup.c:39
unsigned long sendseqnum
Definition: client.c:55
digest_md5_finish finish
Definition: client.c:63
unsigned long readseqnum
Definition: client.c:55
digest_md5_response response
Definition: client.c:62
digest_md5_challenge challenge
Definition: client.c:61
char ** realms
Definition: tokens.h:85
char rspauth[32+1]
Definition: tokens.h:148
char response[32+1]
Definition: tokens.h:139
digest_md5_qop qop
Definition: tokens.h:133
unsigned long nc
Definition: tokens.h:132
char * digesturi
Definition: tokens.h:134
digest_md5_cipher cipher
Definition: tokens.h:137