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 --- DIGEST-MD5 mechanism from RFC 2831, server 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, strdup, 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 "validate.h"
47 #include "qop.h"
48 
49 #include "mechtools.h"
50 
51 #define NONCE_ENTROPY_BYTES 16
52 
54 {
55  int step;
56  unsigned long readseqnum, sendseqnum;
65 };
67 
68 int
70  void **mech_data)
71 {
73  char nonce[NONCE_ENTROPY_BYTES];
74  char *p;
75  int rc;
76 
78  if (rc != GSASL_OK)
79  return rc;
80 
82  if (rc != GSASL_OK)
83  return rc;
84 
85  state = calloc (1, sizeof (*state));
86  if (state == NULL)
87  {
88  free (p);
89  return GSASL_MALLOC_ERROR;
90  }
91 
93  state->challenge.ciphers = 0;
94 
95  state->challenge.nonce = p;
96  state->challenge.utf8 = 1;
97 
98  *mech_data = state;
99 
100  return GSASL_OK;
101 }
102 
103 static char
105 {
106  /* The hex representation always contains lowercase alphabetic
107  characters. See RFC 2831, 1.1. */
108 
109  if (hexdigit >= '0' && hexdigit <= '9')
110  return hexdigit - '0';
111  if (hexdigit >= 'a' && hexdigit <= 'z')
112  return hexdigit - 'a' + 10;
113 
114  return -1;
115 }
116 
117 static char
119 {
120  return (char) (((unsigned char) _gsasl_digest_md5_hexdigit_to_char (u)) *
122 }
123 
124 static int
125 _gsasl_digest_md5_set_hashed_secret (char *secret, const char *hex_secret)
126 {
127  /* Convert the hex string containing the secret to a byte array */
128  const char *p;
129  char *s;
130 
131  if (!hex_secret)
133 
134  s = secret;
135  p = hex_secret;
136  while (*p)
137  {
138  *s = _gsasl_digest_md5_hex_to_char (p[0], p[1]);
139  s++;
140 
141  p += 2;
142  }
143 
144  return GSASL_OK;
145 }
146 
147 int
149  void *mech_data,
150  const char *input,
151  size_t input_len,
152  char **output, size_t *output_len)
153 {
154  _Gsasl_digest_md5_server_state *state = mech_data;
155  int rc, res;
156 
157  *output = NULL;
158  *output_len = 0;
159 
160  switch (state->step)
161  {
162  case 0:
163  /* Set realm. */
164  {
165  const char *c;
166  c = gsasl_property_get (sctx, GSASL_REALM);
167  if (c)
168  {
169  state->challenge.nrealms = 1;
170 
171  state->challenge.realms =
172  malloc (sizeof (*state->challenge.realms));
173  if (!state->challenge.realms)
174  return GSASL_MALLOC_ERROR;
175 
176  state->challenge.realms[0] = strdup (c);
177  if (!state->challenge.realms[0])
178  return GSASL_MALLOC_ERROR;
179  }
180  }
181 
182  /* Set QOP */
183  {
184  const char *qopstr = gsasl_property_get (sctx, GSASL_QOPS);
185 
186  if (qopstr)
187  {
188  int qops = digest_md5_qopstr2qops (qopstr);
189 
190  if (qops == -1)
191  return GSASL_MALLOC_ERROR;
192 
193  /* We don't support confidentiality right now. */
194  if (qops & DIGEST_MD5_QOP_AUTH_CONF)
196 
197  if (qops)
198  state->challenge.qops = qops;
199  }
200  }
201 
202  /* FIXME: cipher, maxbuf, more realms. */
203 
204  /* Create challenge. */
205  *output = digest_md5_print_challenge (&state->challenge);
206  if (!*output)
208 
209  *output_len = strlen (*output);
210  state->step++;
212  break;
213 
214  case 1:
215  if (digest_md5_parse_response (input, input_len, &state->response) < 0)
217 
218  /* Make sure response is consistent with challenge. */
219  if (digest_md5_validate (&state->challenge, &state->response) < 0)
221 
222  /* Store properties, from the client response. */
223  if (state->response.utf8)
224  {
227  }
228  else
229  {
230  /* Client provided username/realm in ISO-8859-1 form,
231  convert it to UTF-8 since the library is all-UTF-8. */
232  char *tmp;
233 
234  tmp = latin1toutf8 (state->response.username);
235  if (!tmp)
236  return GSASL_MALLOC_ERROR;
238  free (tmp);
239 
240  tmp = latin1toutf8 (state->response.realm);
241  if (!tmp)
242  return GSASL_MALLOC_ERROR;
244  free (tmp);
245  }
247 
248  /* FIXME: cipher, maxbuf. */
249 
250  /* Compute secret. */
251  {
252  const char *passwd;
253  const char *hashed_passwd;
254 
255  hashed_passwd =
257  if (hashed_passwd)
258  {
259  if (strlen (hashed_passwd) != (DIGEST_MD5_LENGTH * 2))
261 
263  hashed_passwd);
264  if (rc != GSASL_OK)
265  return rc;
266  }
267  else if ((passwd = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
268  {
269  char *tmp, *tmp2;
270 
271  tmp2 = utf8tolatin1ifpossible (passwd);
272 
273  rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
274  state->response.realm ?
275  state->response.realm : "", tmp2);
276  free (tmp2);
277  if (rc < 0)
278  return GSASL_MALLOC_ERROR;
279 
280  rc = gc_md5 (tmp, strlen (tmp), state->secret);
281  free (tmp);
282  if (rc != GC_OK)
283  return GSASL_CRYPTO_ERROR;
284  }
285  else
286  {
287  return GSASL_NO_PASSWORD;
288  }
289  }
290 
291  /* Check client response. */
292  {
293  char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
294 
295  rc = digest_md5_hmac (check, state->secret,
296  state->response.nonce, state->response.nc,
297  state->response.cnonce, state->response.qop,
298  state->response.authzid,
299  state->response.digesturi, 0,
300  state->response.cipher,
301  state->kic, state->kis, state->kcc, state->kcs);
302  if (rc)
304 
305  if (strcmp (state->response.response, check) != 0)
307  }
308 
309  /* Create finish token. */
310  rc = digest_md5_hmac (state->finish.rspauth, state->secret,
311  state->response.nonce, state->response.nc,
312  state->response.cnonce, state->response.qop,
313  state->response.authzid,
314  state->response.digesturi, 1,
315  state->response.cipher, NULL, NULL, NULL, NULL);
316  if (rc)
318 
319  *output = digest_md5_print_finish (&state->finish);
320  if (!*output)
321  return GSASL_MALLOC_ERROR;
322 
323  *output_len = strlen (*output);
324 
325  state->step++;
326  res = GSASL_OK;
327  break;
328 
329  default:
331  break;
332  }
333 
334  return res;
335 }
336 
337 void
339  void *mech_data)
340 {
341  _Gsasl_digest_md5_server_state *state = mech_data;
342 
343  if (!state)
344  return;
345 
348  digest_md5_free_finish (&state->finish);
349 
350  free (state);
351 }
352 
353 int
355  void *mech_data,
356  const char *input,
357  size_t input_len,
358  char **output, size_t *output_len)
359 {
360  _Gsasl_digest_md5_server_state *state = mech_data;
361  int res;
362 
363  res = digest_md5_encode (input, input_len, output, output_len,
364  state->response.qop, state->sendseqnum,
365  state->kis);
366  if (res)
367  return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
368 
369  if (state->sendseqnum == 4294967295UL)
370  state->sendseqnum = 0;
371  else
372  state->sendseqnum++;
373 
374  return GSASL_OK;
375 }
376 
377 int
379  void *mech_data,
380  const char *input,
381  size_t input_len,
382  char **output, size_t *output_len)
383 {
384  _Gsasl_digest_md5_server_state *state = mech_data;
385  int res;
386 
387  res = digest_md5_decode (input, input_len, output, output_len,
388  state->response.qop, state->readseqnum,
389  state->kic);
390  if (res)
391  return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
392 
393  if (state->readseqnum == 4294967295UL)
394  state->readseqnum = 0;
395  else
396  state->readseqnum++;
397 
398  return GSASL_OK;
399 }
int gsasl_nonce(char *data, size_t datalen)
Definition: crypto.c:38
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_response(const char *response, size_t len, digest_md5_response *out)
Definition: parser.c:586
char * digest_md5_print_finish(digest_md5_finish *finish)
Definition: printer.c:388
char * digest_md5_print_challenge(digest_md5_challenge *c)
Definition: printer.c:74
int _gsasl_digest_md5_server_start(Gsasl_session *sctx _GL_UNUSED, void **mech_data)
Definition: server.c:69
int _gsasl_digest_md5_server_step(Gsasl_session *sctx, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: server.c:148
int _gsasl_digest_md5_server_decode(Gsasl_session *sctx _GL_UNUSED, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: server.c:378
#define NONCE_ENTROPY_BYTES
Definition: server.c:51
static int _gsasl_digest_md5_set_hashed_secret(char *secret, const char *hex_secret)
Definition: server.c:125
static char _gsasl_digest_md5_hex_to_char(char u, char l)
Definition: server.c:118
static char _gsasl_digest_md5_hexdigit_to_char(char hexdigit)
Definition: server.c:104
void _gsasl_digest_md5_server_finish(Gsasl_session *sctx _GL_UNUSED, void *mech_data)
Definition: server.c:338
int _gsasl_digest_md5_server_encode(Gsasl_session *sctx _GL_UNUSED, void *mech_data, const char *input, size_t input_len, char **output, size_t *output_len)
Definition: server.c:354
@ DIGEST_MD5_QOP_AUTH_CONF
Definition: tokens.h:37
@ 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_validate(digest_md5_challenge *c, digest_md5_response *r)
Definition: validate.c:116
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_MECHANISM_CALLED_TOO_MANY_TIMES
Definition: gsasl.h:174
@ GSASL_MECHANISM_PARSE_ERROR
Definition: gsasl.h:179
@ GSASL_CRYPTO_ERROR
Definition: gsasl.h:177
@ GSASL_INTEGRITY_ERROR
Definition: gsasl.h:181
@ GSASL_DIGEST_MD5_HASHED_PASSWORD
Definition: gsasl.h:346
@ GSASL_AUTHZID
Definition: gsasl.h:336
@ 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 * latin1toutf8(const char *str)
Definition: nonascii.c:41
char * utf8tolatin1ifpossible(const char *passwd)
Definition: nonascii.c:69
int digest_md5_qopstr2qops(const char *qopstr)
Definition: qop.c:37
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: server.c:56
digest_md5_finish finish
Definition: server.c:64
unsigned long readseqnum
Definition: server.c:56
digest_md5_challenge challenge
Definition: server.c:62
digest_md5_response response
Definition: server.c:63
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