Initial release, version 0.0.0.
[gsasl.git] / lib / digest-md5.c
blob2e26f76378fc0a9c81de5cbd5ba3ae8868406816
1 /* digest-md5.c implementation of SASL mechanism DIGEST-MD5 from RFC 2831
2 * Copyright (C) 2002 Simon Josefsson
3 * Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc. (getsubopt)
5 * This file is part of libgsasl.
7 * Libgsasl is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libgsasl is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with libgsasl; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "internal.h"
25 #ifdef USE_DIGEST_MD5
27 #include <gcrypt.h>
28 #ifdef HAVE_MATH_H
29 #include <math.h>
30 #endif
31 #ifdef HAVE_LIMITS_H
32 #include <limits.h>
33 #endif
34 #if HAVE_INTTYPES_H
35 # include <inttypes.h>
36 #else
37 # if HAVE_STDINT_H
38 # include <stdint.h>
39 # endif
40 #endif
42 #define NONCE_ENTROPY_BITS 64
43 #define CNONCE_ENTROPY_BITS 64
45 #define DELIM ", "
46 #define REALM_PRE "realm=\""
47 #define REALM_POST "\"" DELIM
48 #define NONCE_PRE "nonce=\""
49 #define NONCE_POST "\"" DELIM
50 #define QOP_LIST_PRE "qop=\""
51 #define QOP_LIST_POST "\"" DELIM
52 #define QOP_DELIM DELIM
53 #define QOP_AUTH "auth"
54 #define QOP_AUTH_INT "auth-int"
55 #define QOP_AUTH_CONF "auth-conf"
56 #define MAXBUF_PRE "maxbuf="
57 #define MAXBUF_POST DELIM
58 #define DEFAULT_CHARSET "utf-8"
59 #define CHARSET "charset=" DEFAULT_CHARSET DELIM
60 #define DEFAULT_ALGORITHM "md5-sess"
61 #define ALGORITHM "algorithm=" DEFAULT_ALGORITHM DELIM
62 #define CIPHER_PRE "cipher=\""
63 #define CIPHER_DELIM DELIM
64 #define CIPHER_DES "des"
65 #define CIPHER_3DES "3des"
66 #define CIPHER_RC4_40 "rc4-40"
67 #define CIPHER_RC4 "rc4"
68 #define CIPHER_RC4_56 "rc4-56"
69 #define CIPHER_AES "aes"
70 #define CIPHER_POST "\"" DELIM
72 #define USERNAME_PRE "username=\""
73 #define USERNAME_POST "\"" DELIM
74 #define CNONCE_PRE "cnonce=\""
75 #define CNONCE_POST "\"" DELIM
76 #define NONCE_COUNT_PRE "nc="
77 #define NONCE_COUNT_POST DELIM
78 #define QOP_PRE "qop="
79 #define QOP_POST DELIM
80 #define RESPONSE_PRE "response="
81 #define RESPONSE_POST "" DELIM
82 #define AUTHZID_PRE "authzid=\""
83 #define AUTHZID_POST "\"" DELIM
84 #define DIGEST_URI_PRE "digest-uri=\""
85 #define DIGEST_URI_POST "\"" DELIM
87 #define RSPAUTH_PRE "rspauth="
88 #define RSPAUTH_POST ""
90 #define A2_PRE "AUTHENTICATE:"
91 #define A2_POST ":00000000000000000000000000000000"
92 #define COLON ":"
93 #define NCLEN 8
94 #define MD5LEN 16
95 #define MAXBUF_DEFAULT 65536
96 #define RESPONSE_LENGTH 32
97 #define RSPAUTH_LENGTH RESPONSE_LENGTH
99 #define PRINT_OUTPUT 0
101 enum
103 /* the order must match the following struct */
104 CHALLENGE_REALM = 0,
105 CHALLENGE_NONCE,
106 CHALLENGE_QOP,
107 CHALLENGE_STALE,
108 CHALLENGE_MAXBUF,
109 CHALLENGE_CHARSET,
110 CHALLENGE_ALGORITHM,
111 CHALLENGE_CIPHER
114 const char *digest_challenge_opts[] =
116 /* the order must match the previous enum */
117 "realm",
118 "nonce",
119 "qop",
120 "stale",
121 "maxbuf",
122 "charset",
123 "algorithm",
124 "cipher",
125 NULL
128 enum
130 /* the order must match the following struct */
131 RESPONSE_USERNAME = 0,
132 RESPONSE_REALM,
133 RESPONSE_NONCE,
134 RESPONSE_CNONCE,
135 RESPONSE_NC,
136 RESPONSE_QOP,
137 RESPONSE_DIGEST_URI,
138 RESPONSE_RESPONSE,
139 RESPONSE_MAXBUF,
140 RESPONSE_CHARSET,
141 RESPONSE_CIPHER,
142 RESPONSE_AUTHZID
145 const char *digest_response_opts[] =
147 /* the order must match the previous enum */
148 "username",
149 "realm",
150 "nonce",
151 "cnonce",
152 "nc",
153 "qop",
154 "digest-uri",
155 "response",
156 "maxbuf",
157 "charset",
158 "cipher",
159 "authzid",
160 NULL
163 enum
165 /* the order must match the following struct */
166 RESPONSEAUTH_RSPAUTH = 0
169 const char *digest_responseauth_opts[] =
171 /* the order must match the previous enum */
172 "rspauth",
173 NULL
176 enum
178 /* the order must match the following struct */
179 QOP_AUTH_OPTION = 0,
180 QOP_AUTH_INT_OPTION,
181 QOP_AUTH_CONF_OPTION
184 const char *qop_opts[] =
186 /* the order must match the previous enum */
187 QOP_AUTH,
188 QOP_AUTH_INT,
189 QOP_AUTH_CONF,
190 NULL
193 enum
195 /* the order must match the following struct */
196 CIPHER_DES_OPTION = 0,
197 CIPHER_3DES_OPTION,
198 CIPHER_RC4_OPTION,
199 CIPHER_RC4_40_OPTION,
200 CIPHER_RC4_56_OPTION,
201 CIPHER_AES_OPTION
204 const char *cipher_opts[] =
206 /* the order must match the previous enum */
207 CIPHER_DES,
208 CIPHER_3DES,
209 CIPHER_RC4,
210 CIPHER_RC4_40,
211 CIPHER_RC4_56,
212 CIPHER_AES,
213 NULL
216 /* Parse comma separate list into words.
217 Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
218 From the GNU C Library, under GNU LGPL version 2.1.
219 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
220 Modified for Libgsasl by Simon Josefsson <simon@josefsson.org>
221 Copyright (C) 2002 Simon Josefsson
223 Parse comma separated suboption from *OPTIONP and match against
224 strings in TOKENS. If found return index and set *VALUEP to
225 optional value introduced by an equal sign. If the suboption is
226 not part of TOKENS return in *VALUEP beginning of unknown
227 suboption. On exit *OPTIONP is set to the beginning of the next
228 token or at the terminating NUL character. */
229 static int
230 _gsasl_getsubopt (optionp, tokens, valuep)
231 char **optionp;
232 char *const *tokens;
233 char **valuep;
235 char *endp, *vstart;
236 int cnt;
237 int inside_quote = 0;
239 if (**optionp == '\0')
240 return -1;
242 /* Find end of next token. */
243 endp = *optionp;
244 while (*endp != '\0' && (inside_quote || (!inside_quote && *endp != ',')))
246 if (*endp == '"')
247 inside_quote = !inside_quote;
248 endp++;
251 /* Find start of value. */
252 vstart = memchr (*optionp, '=', endp - *optionp);
253 if (vstart == NULL)
254 vstart = endp;
256 /* Try to match the characters between *OPTIONP and VSTART against
257 one of the TOKENS. */
258 for (cnt = 0; tokens[cnt] != NULL; ++cnt)
259 if (memcmp (*optionp, tokens[cnt], vstart - *optionp) == 0
260 && tokens[cnt][vstart - *optionp] == '\0')
262 /* We found the current option in TOKENS. */
263 *valuep = vstart != endp ? vstart + 1 : NULL;
265 while (*valuep && (**valuep == ' ' ||
266 **valuep == '\t' ||
267 **valuep == '\r' ||
268 **valuep == '\n' ||
269 **valuep == '"'))
270 (*valuep)++;
272 if (*endp != '\0')
273 *endp++ = '\0';
274 *optionp = endp;
275 endp -= 2;
276 while (*endp == ' ' ||
277 *endp == '\t' ||
278 *endp == '\r' ||
279 *endp == '\n' ||
280 *endp == '"')
281 *endp-- = '\0';
282 while (**optionp == ' ' ||
283 **optionp == '\t' ||
284 **optionp == '\r' ||
285 **optionp == '\n')
286 (*optionp)++;
288 return cnt;
291 /* The current suboption does not match any option. */
292 *valuep = *optionp;
294 if (*endp != '\0')
295 *endp++ = '\0';
296 *optionp = endp;
297 while (**optionp == ' ' ||
298 **optionp == '\t' ||
299 **optionp == '\r' ||
300 **optionp == '\n')
301 (*optionp)++;
303 return -1;
306 static int
307 _gsasl_digest (char *output, /* must have 2*MD5LEN available bytes */
308 unsigned char secret[MD5LEN],
309 unsigned char *nonce,
310 uint32_t nc,
311 char *cnonce,
312 int qop,
313 char *authzid,
314 char *digesturi,
315 char *a2string) /* "AUTHENTICATE:" or ":" */
317 char nchex[NCLEN+1];
318 char a1hexhash[2*MD5LEN];
319 char a2hexhash[2*MD5LEN];
320 GCRY_MD_HD md5h;
321 unsigned char *hash;
322 int i;
324 /* A1 */
326 md5h = gcry_md_open (GCRY_MD_MD5, 0);
327 if (md5h == NULL)
328 return GSASL_GCRYPT_ERROR;
330 gcry_md_write (md5h, secret, MD5LEN);
331 gcry_md_write (md5h, COLON, strlen(COLON));
332 gcry_md_write (md5h, nonce, strlen(nonce));
333 gcry_md_write (md5h, COLON, strlen(COLON));
334 gcry_md_write (md5h, cnonce, strlen(cnonce));
335 if (authzid && strlen(authzid) > 0)
337 gcry_md_write (md5h, COLON, strlen(COLON));
338 gcry_md_write (md5h, authzid, strlen(authzid));
341 hash = gcry_md_read (md5h, GCRY_MD_MD5);
342 if (hash == NULL)
343 return GSASL_GCRYPT_ERROR;
345 for (i = 0; i < MD5LEN; i++)
347 a1hexhash[2*i + 1] = HEXCHAR(hash[i]);
348 a1hexhash[2*i + 0] = HEXCHAR(hash[i] >> 4);
350 gcry_md_close(md5h);
352 /* A2 */
354 md5h = gcry_md_open (GCRY_MD_MD5, 0);
355 if (md5h == NULL)
356 return GSASL_GCRYPT_ERROR;
358 gcry_md_write (md5h, a2string, strlen(a2string));
359 gcry_md_write (md5h, digesturi, strlen(digesturi));
360 if (qop & GSASL_QOP_AUTH_INT || qop & GSASL_QOP_AUTH_CONF)
362 gcry_md_write (md5h, A2_POST, strlen(A2_POST));
365 hash = gcry_md_read (md5h, GCRY_MD_MD5);
366 if (hash == NULL)
367 return GSASL_GCRYPT_ERROR;
369 for (i = 0; i < MD5LEN; i++)
371 a2hexhash[2*i + 1] = HEXCHAR(hash[i]);
372 a2hexhash[2*i + 0] = HEXCHAR(hash[i] >> 4);
374 gcry_md_close(md5h);
376 /* response_value */
378 md5h = gcry_md_open (GCRY_MD_MD5, 0);
379 if (md5h == NULL)
380 return GSASL_GCRYPT_ERROR;
382 gcry_md_write (md5h, a1hexhash, 2*MD5LEN);
383 gcry_md_write (md5h, COLON, strlen(COLON));
384 gcry_md_write (md5h, nonce, strlen(nonce));
385 gcry_md_write (md5h, COLON, strlen(COLON));
386 sprintf(nchex, "%0*x", NCLEN, nc);
387 gcry_md_write (md5h, nchex, strlen(nchex));
388 gcry_md_write (md5h, COLON, strlen(COLON));
389 gcry_md_write (md5h, cnonce, strlen(cnonce));
390 gcry_md_write (md5h, COLON, strlen(COLON));
391 if (qop & GSASL_QOP_AUTH)
392 gcry_md_write (md5h, QOP_AUTH, strlen(QOP_AUTH));
393 else if (qop & GSASL_QOP_AUTH_INT)
394 gcry_md_write (md5h, QOP_AUTH_INT, strlen(QOP_AUTH_INT));
395 else if (qop & GSASL_QOP_AUTH_CONF)
396 gcry_md_write (md5h, QOP_AUTH_CONF, strlen(QOP_AUTH_CONF));
397 gcry_md_write (md5h, COLON, strlen(COLON));
398 gcry_md_write (md5h, a2hexhash, 2*MD5LEN);
400 hash = gcry_md_read (md5h, GCRY_MD_MD5);
401 if (hash == NULL)
402 return GSASL_GCRYPT_ERROR;
404 for (i = 0; i < MD5LEN; i++)
406 output[2*i + 1] = HEXCHAR(hash[i]);
407 output[2*i + 0] = HEXCHAR(hash[i] >> 4);
409 gcry_md_close(md5h);
411 return GSASL_OK;
414 /* Client */
416 struct _Gsasl_digest_md5_client_state {
417 int step;
418 unsigned char secret[MD5LEN];
419 unsigned char *nonce;
420 uint32_t nc;
421 unsigned char cnonce[2*CNONCE_ENTROPY_BITS/8+1];
422 Gsasl_qop qop;
423 unsigned char *authzid;
424 unsigned char *digesturi;
425 unsigned char response[RESPONSE_LENGTH+1];
427 typedef struct _Gsasl_digest_md5_client_state _Gsasl_digest_md5_client_state;
430 _gsasl_digest_md5_client_init (Gsasl_ctx *ctx)
432 int res;
434 if (gcry_check_version(GCRYPT_VERSION) == NULL)
435 return GSASL_GCRYPT_ERROR;
437 res = gcry_control (GCRYCTL_INIT_SECMEM, 512, 0);
438 if (res != GCRYERR_SUCCESS)
439 return GSASL_GCRYPT_ERROR;
441 return GSASL_OK;
444 void
445 _gsasl_digest_md5_client_done (Gsasl_ctx *ctx)
447 return;
451 _gsasl_digest_md5_client_start (Gsasl_session_ctx *cctx,
452 void **mech_data)
454 _Gsasl_digest_md5_client_state *state;
455 Gsasl_ctx *ctx;
457 ctx = gsasl_client_ctx_get (cctx);
458 if (ctx == NULL)
459 return GSASL_CANNOT_GET_CTX;
461 if (gsasl_client_callback_authentication_id_get (ctx) == NULL)
462 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
464 if (gsasl_client_callback_password_get (ctx) == NULL)
465 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
467 state = (_Gsasl_digest_md5_client_state*) malloc(sizeof(*state));
468 if (state == NULL)
469 return GSASL_MALLOC_ERROR;
471 state->step = 0;
472 state->nonce = NULL;
473 state->nc = 1;
474 state->qop = GSASL_QOP_AUTH;
475 state->authzid = NULL;
476 state->digesturi = NULL;
478 *mech_data = state;
480 return GSASL_OK;
484 _gsasl_digest_md5_client_step (Gsasl_session_ctx *cctx,
485 void *mech_data,
486 const char *input,
487 size_t input_len,
488 char *output,
489 size_t *output_len)
491 _Gsasl_digest_md5_client_state *state = mech_data;
492 Gsasl_client_callback_authorization_id cb_authorization_id;
493 Gsasl_client_callback_authentication_id cb_authentication_id;
494 Gsasl_client_callback_password cb_password;
495 Gsasl_client_callback_service cb_service;
496 Gsasl_client_callback_qop cb_qop;
497 Gsasl_client_callback_maxbuf cb_maxbuf;
498 char *subopts;
499 char *value;
500 Gsasl_ctx *ctx;
501 int outlen;
502 int res, i;
504 ctx = gsasl_client_ctx_get (cctx);
505 if (ctx == NULL)
506 return GSASL_CANNOT_GET_CTX;
508 cb_qop = gsasl_client_callback_qop_get (ctx);
509 cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
510 cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);
512 cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
513 if (cb_authentication_id == NULL)
514 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
516 cb_password = gsasl_client_callback_password_get (ctx);
517 if (cb_password == NULL)
518 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
520 cb_service = gsasl_client_callback_service_get (ctx);
521 if (cb_service == NULL)
522 return GSASL_NEED_CLIENT_SERVICE_CALLBACK;
524 if (*output_len < 1)
525 return GSASL_TOO_SMALL_BUFFER;
527 strcpy(output, "");
528 outlen = 0;
530 #if PRINT_OUTPUT
531 if (input && input_len > 0)
532 puts(input);
533 #endif
535 switch (state->step)
537 case 0:
539 char **realm = NULL;
540 size_t nrealm = 0;
541 int maxbuf = MAXBUF_DEFAULT;
542 int cipher = 0;
544 if (input_len == 0)
546 *output_len = 0;
547 return GSASL_NEEDS_MORE;
550 gcry_randomize (state->cnonce, CNONCE_ENTROPY_BITS/8,GCRY_WEAK_RANDOM);
551 for (i = 0; i < CNONCE_ENTROPY_BITS/8; i++)
553 state->cnonce[CNONCE_ENTROPY_BITS/8 + i] =
554 HEXCHAR(state->cnonce[i]);
555 state->cnonce[i] = HEXCHAR(state->cnonce[i] >> 4);
557 state->cnonce[2*CNONCE_ENTROPY_BITS/8] = '\0';
559 subopts = input;
560 while (*subopts != '\0')
561 switch (_gsasl_getsubopt (&subopts, digest_challenge_opts, &value))
563 case CHALLENGE_REALM:
564 if (nrealm == 0)
565 realm = (char**) malloc(sizeof(*realm));
566 else
567 realm = realloc(realm, (nrealm + 1) * sizeof(*realm));
568 if (realm == NULL)
570 res = GSASL_MALLOC_ERROR;
571 goto done;
573 realm[nrealm] = strdup(value);
574 nrealm++;
575 break;
577 case CHALLENGE_NONCE:
578 if (state->nonce != NULL)
580 res = GSASL_MECHANISM_PARSE_ERROR;
581 goto done;
583 state->nonce = strdup(value);
584 break;
586 case CHALLENGE_QOP:
588 char *subsubopts;
589 char *val;
591 state->qop = 0;
592 subsubopts = value;
593 while (*subsubopts != '\0')
594 switch (_gsasl_getsubopt (&subsubopts, qop_opts, &val))
596 case QOP_AUTH_OPTION:
597 state->qop |= GSASL_QOP_AUTH;
598 break;
600 case QOP_AUTH_INT_OPTION:
601 state->qop |= GSASL_QOP_AUTH_INT;
602 break;
604 case QOP_AUTH_CONF_OPTION:
605 state->qop |= GSASL_QOP_AUTH_CONF;
606 break;
608 default:
609 /* Ignore unknown qop */
610 break;
613 break;
615 case CHALLENGE_STALE:
616 printf("XXX stale: %s\n", value);
617 break;
619 case CHALLENGE_MAXBUF:
620 maxbuf = strtol(value, NULL, 10);
621 break;
623 case CHALLENGE_CHARSET:
624 if (strcmp(DEFAULT_CHARSET, value) != 0)
626 res = GSASL_MECHANISM_PARSE_ERROR;
627 goto done;
629 break;
631 case CHALLENGE_ALGORITHM:
632 if (strcmp(DEFAULT_ALGORITHM, value) != 0)
634 res = GSASL_MECHANISM_PARSE_ERROR;
635 goto done;
637 break;
639 case CHALLENGE_CIPHER:
641 char *subsubopts;
642 char *val;
644 subsubopts = value;
645 while (*subsubopts != '\0')
646 switch (_gsasl_getsubopt (&subsubopts, cipher_opts, &val))
648 case CIPHER_DES_OPTION:
649 cipher |= GSASL_CIPHER_DES;
650 break;
652 case CIPHER_3DES_OPTION:
653 cipher |= GSASL_CIPHER_3DES;
654 break;
656 case CIPHER_RC4_OPTION:
657 cipher |= GSASL_CIPHER_RC4;
658 break;
660 case CIPHER_RC4_40_OPTION:
661 cipher |= GSASL_CIPHER_RC4_40;
662 break;
664 case CIPHER_RC4_56_OPTION:
665 cipher |= GSASL_CIPHER_RC4_56;
666 break;
668 case CIPHER_AES_OPTION:
669 cipher |= GSASL_CIPHER_AES;
670 break;
672 default:
673 /* Ignoring unknown cipher. */
674 break;
677 break;
679 default:
680 /* Ignoring unknown parameter. */
681 break;
683 if (state->qop == 0 || cipher == 0 || state->nonce == NULL)
685 res = GSASL_MECHANISM_PARSE_ERROR;
686 goto done;
688 if (cb_qop)
689 state->qop = cb_qop (cctx, state->qop);
690 else
691 state->qop = GSASL_QOP_AUTH;
692 if (cb_authorization_id)
694 size_t authzidlen;
696 res = cb_authorization_id (cctx, NULL, &authzidlen);
697 if (res != GSASL_OK)
698 goto done;
699 state->authzid = (char*) malloc(authzidlen+1);
700 if (state->authzid == NULL)
702 res = GSASL_MALLOC_ERROR;
703 goto done;
705 res = cb_authorization_id (cctx, state->authzid, &authzidlen);
706 if (res != GSASL_OK)
707 goto done;
708 state->authzid[authzidlen] = '\0';
710 /* username */
712 int usernamelen;
714 res = cb_authentication_id (cctx, NULL, &usernamelen);
715 if (res != GSASL_OK)
716 goto done;
718 if (outlen +
719 strlen(USERNAME_PRE) +
720 usernamelen +
721 strlen(USERNAME_POST) >= *output_len)
723 res = GSASL_TOO_SMALL_BUFFER;
724 goto done;
727 strcat(output, USERNAME_PRE);
728 outlen += strlen(USERNAME_PRE);
730 res = cb_authentication_id (cctx, &output[outlen], &usernamelen);
731 if (res != GSASL_OK)
732 goto done;
733 outlen += usernamelen;
735 strcat(output, USERNAME_POST);
736 outlen += strlen(USERNAME_POST);
738 /* realm */
739 if (nrealm > 0)
741 if (outlen +
742 strlen(REALM_PRE) +
743 strlen(realm[0]) +
744 strlen(REALM_POST) >= *output_len)
746 res = GSASL_TOO_SMALL_BUFFER;
747 goto done;
750 strcat(output, REALM_PRE);
751 outlen += strlen(REALM_PRE);
753 strcat(output, realm[0]);
754 outlen += strlen(realm[0]);
756 strcat(output, REALM_POST);
757 outlen += strlen(REALM_POST);
759 /* nonce */
761 if (outlen +
762 strlen(NONCE_PRE) +
763 strlen(state->nonce) +
764 strlen(NONCE_POST) >= *output_len)
766 res = GSASL_TOO_SMALL_BUFFER;
767 goto done;
770 strcat(output, NONCE_PRE);
771 outlen += strlen(NONCE_PRE);
773 strcat(output, state->nonce);
774 outlen += strlen(state->nonce);
776 strcat(output, NONCE_POST);
777 outlen += strlen(NONCE_POST);
779 /* cnonce */
781 if (outlen +
782 strlen(CNONCE_PRE) +
783 strlen(state->cnonce) +
784 strlen(CNONCE_POST) >= *output_len)
786 res = GSASL_TOO_SMALL_BUFFER;
787 goto done;
790 strcat(output, CNONCE_PRE);
791 outlen += strlen(CNONCE_PRE);
793 strcat(output, state->cnonce);
794 outlen += strlen(state->cnonce);
796 strcat(output, CNONCE_POST);
797 outlen += strlen(CNONCE_POST);
799 /* nonce-count */
801 if (outlen +
802 strlen(NONCE_COUNT_PRE) +
803 NCLEN +
804 strlen(NONCE_COUNT_POST) >= *output_len)
806 res = GSASL_TOO_SMALL_BUFFER;
807 goto done;
810 strcat(output, NONCE_COUNT_PRE);
811 outlen += strlen(NONCE_COUNT_PRE);
813 sprintf(output+outlen, "%0*x", NCLEN, state->nc);
814 outlen += NCLEN;
816 strcat(output, NONCE_COUNT_POST);
817 outlen += strlen(NONCE_COUNT_POST);
819 /* qop */
821 char *qopstr;
823 if (state->qop & GSASL_QOP_AUTH)
824 qopstr = QOP_AUTH;
825 else if (state->qop & GSASL_QOP_AUTH_INT)
826 qopstr = QOP_AUTH_INT;
827 else if (state->qop & GSASL_QOP_AUTH_CONF)
828 qopstr = QOP_AUTH_CONF;
830 if (outlen +
831 strlen(QOP_PRE) +
832 strlen(qopstr) +
833 strlen(QOP_POST) >= *output_len)
835 res = GSASL_TOO_SMALL_BUFFER;
836 goto done;
839 strcat(output, QOP_PRE);
840 outlen += strlen(QOP_PRE);
842 strcat(output, qopstr);
843 outlen += strlen(qopstr);
845 strcat(output, QOP_POST);
846 outlen += strlen(QOP_POST);
848 /* digest-uri */
850 char *service = NULL;
851 size_t servicelen = 0;
852 char *hostname = NULL;
853 size_t hostnamelen = 0;
854 char *servicename = NULL;
855 size_t servicenamelen = 0;
856 size_t len;
858 res = cb_service (cctx, NULL, &servicelen,
859 NULL, &hostnamelen,
860 NULL, &servicenamelen);
861 if (res != GSASL_OK)
862 goto done;
863 len = servicelen + strlen("/") + hostnamelen +
864 (servicenamelen > 0 ? strlen("/") + servicenamelen : 0) + 1;
865 state->digesturi = malloc(len);
866 if (state->digesturi == NULL)
868 res = GSASL_MALLOC_ERROR;
869 goto done;
871 res = cb_service (cctx, state->digesturi, &servicelen,
872 state->digesturi + 1 + servicelen, &hostnamelen,
873 (servicenamelen > 0 ?
874 state->digesturi + 1 + servicelen + 1 +
875 hostnamelen : NULL), &servicenamelen);
876 if (res != GSASL_OK)
877 goto done;
878 state->digesturi[servicelen] = '/';
879 state->digesturi[servicelen + 1 + hostnamelen] = '/';
880 state->digesturi[len-1] = '\0';
882 if (outlen +
883 strlen(DIGEST_URI_PRE) +
884 len +
885 strlen(DIGEST_URI_POST) >= *output_len)
887 res = GSASL_TOO_SMALL_BUFFER;
888 goto done;
891 strcat(output, DIGEST_URI_PRE);
892 outlen += strlen(DIGEST_URI_PRE);
894 strcat(output, state->digesturi);
895 outlen += strlen(state->digesturi);
897 strcat(output, DIGEST_URI_POST);
898 outlen += strlen(DIGEST_URI_POST);
900 /* response */
902 GCRY_MD_HD md5h;
903 unsigned char *tmp;
904 char *normpassword;
905 size_t len;
907 if (outlen +
908 strlen(RESPONSE_PRE) +
909 RESPONSE_LENGTH +
910 strlen(RESPONSE_POST) >= *output_len)
912 res = GSASL_TOO_SMALL_BUFFER;
913 goto done;
916 strcat(output, RESPONSE_PRE);
917 outlen += strlen(RESPONSE_PRE);
919 md5h = gcry_md_open (GCRY_MD_MD5, 0);
920 if (md5h == NULL)
922 res = GSASL_GCRYPT_ERROR;
923 goto done;
925 len = *output_len - outlen;
926 res = cb_authentication_id (cctx, output+outlen, &len);
927 if (res != GSASL_OK)
928 goto done;
930 gcry_md_write (md5h, output+outlen, len);
931 gcry_md_write (md5h, COLON, strlen(COLON));
932 if (nrealm > 0)
933 gcry_md_write (md5h, realm[0], strlen(realm[0]));
934 gcry_md_write (md5h, COLON, strlen(COLON));
936 len = *output_len - outlen;
937 /* XXX? password stored in callee's output buffer */
938 res = cb_password (cctx, output+outlen, &len);
939 if (res != GSASL_OK)
940 goto done;
941 tmp = gsasl_utf8_nfkc_normalize (output+outlen, len);
942 if (tmp == NULL)
944 res = GSASL_UNICODE_NORMALIZATION_ERROR;
945 goto done;
947 gcry_md_write (md5h, tmp, strlen(tmp));
948 free(tmp);
949 if (res != GCRYERR_SUCCESS)
950 return GSASL_GCRYPT_ERROR;
952 tmp = gcry_md_read (md5h, GCRY_MD_MD5);
953 if (tmp == NULL)
955 res = GSASL_GCRYPT_ERROR;
956 goto done;
958 memcpy(state->secret, tmp, MD5LEN);
959 gcry_md_close(md5h);
961 res = _gsasl_digest (state->response, state->secret,
962 state->nonce, state->nc, state->cnonce,
963 state->qop, state->authzid,
964 state->digesturi, A2_PRE);
965 if (res != GSASL_OK)
966 goto done;
967 state->response[RESPONSE_LENGTH] = '\0';
968 memcpy(output+outlen, state->response, RESPONSE_LENGTH+1);
969 outlen += RESPONSE_LENGTH;
971 strcat(output, RESPONSE_POST);
972 outlen += strlen(RESPONSE_POST);
974 if (cb_maxbuf && (maxbuf = cb_maxbuf(cctx, maxbuf)) != MAXBUF_DEFAULT)
976 if (outlen +
977 strlen(MAXBUF_PRE) +
978 /* XXX don't require -lm, how? */
979 1+floor(log10(INT_MAX)) +
980 strlen(MAXBUF_POST) >= *output_len)
981 return GSASL_TOO_SMALL_BUFFER;
983 strcat(output, MAXBUF_PRE);
984 outlen += strlen(MAXBUF_PRE);
986 sprintf(&output[outlen], "%d", maxbuf);
987 outlen += strlen(&output[outlen]);
989 strcat(output, MAXBUF_POST);
990 outlen += strlen(MAXBUF_POST);
992 /* authzid */
993 if (state->authzid && strlen(state->authzid) > 0)
995 if (outlen +
996 strlen(AUTHZID_PRE) +
997 strlen(state->authzid) +
998 strlen(AUTHZID_POST) >= *output_len)
1000 res = GSASL_TOO_SMALL_BUFFER;
1001 goto done;
1004 strcat(output, AUTHZID_PRE);
1005 outlen += strlen(AUTHZID_PRE);
1007 strcat(output, state->authzid);
1008 outlen += strlen(state->authzid);
1010 strcat(output, AUTHZID_POST);
1011 outlen += strlen(AUTHZID_POST);
1014 res = GSASL_NEEDS_MORE;
1015 done:
1016 if (realm)
1017 free (realm);
1019 *output_len = outlen;
1020 state->step++;
1021 break;
1023 case 1:
1024 if (input_len == 0)
1026 *output_len = 0;
1027 res = GSASL_MECHANISM_PARSE_ERROR;
1028 break;
1031 res = GSASL_AUTHENTICATION_ERROR;
1032 subopts = input;
1033 while (*subopts != '\0')
1034 switch (_gsasl_getsubopt (&subopts, digest_responseauth_opts, &value))
1036 case RESPONSEAUTH_RSPAUTH:
1037 res = _gsasl_digest (output+outlen, state->secret,
1038 state->nonce, state->nc,
1039 state->cnonce, state->qop,
1040 state->authzid, state->digesturi, COLON);
1041 if (res != GSASL_OK)
1042 break;
1044 if (memcmp(value, output + outlen, RESPONSE_LENGTH) == 0)
1045 res = GSASL_OK;
1046 else
1047 res = GSASL_AUTHENTICATION_ERROR;
1048 break;
1050 default:
1051 /* Unknown suboption. */
1052 break;
1054 *output_len = 0;
1055 state->step++;
1056 break;
1058 default:
1059 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
1060 break;
1063 #if PRINT_OUTPUT
1064 if (output && *output_len > 0)
1065 puts(output);
1066 #endif
1068 return res;
1072 _gsasl_digest_md5_client_finish (Gsasl_session_ctx *cctx,
1073 void *mech_data)
1075 _Gsasl_digest_md5_client_state *state = mech_data;
1077 if (state->authzid)
1078 free (state->authzid);
1079 if (state->nonce)
1080 free (state->nonce);
1081 if (state->digesturi)
1082 free (state->digesturi);
1083 free(state);
1085 return GSASL_OK;
1088 /* Server */
1090 struct _Gsasl_digest_md5_server_state {
1091 int step;
1092 char nonce[NONCE_ENTROPY_BITS/8];
1094 typedef struct _Gsasl_digest_md5_server_state _Gsasl_digest_md5_server_state;
1097 _gsasl_digest_md5_server_init (Gsasl_ctx *ctx)
1099 if (gcry_check_version(GCRYPT_VERSION) == NULL)
1100 return GSASL_GCRYPT_ERROR;
1102 return GSASL_OK;
1105 void
1106 _gsasl_digest_md5_server_done (Gsasl_ctx *ctx)
1108 return;
1112 _gsasl_digest_md5_server_start (Gsasl_session_ctx *sctx,
1113 void **mech_data)
1115 _Gsasl_digest_md5_server_state *state;
1116 Gsasl_server_callback_retrieve cb_retrieve;
1117 Gsasl_server_callback_digest_md5 cb_digest_md5;
1118 Gsasl_ctx *ctx;
1120 ctx = gsasl_server_ctx_get (sctx);
1121 if (ctx == NULL)
1122 return GSASL_CANNOT_GET_CTX;
1124 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
1125 cb_digest_md5 = gsasl_server_callback_digest_md5_get (ctx);
1127 if (gsasl_server_callback_digest_md5_get (ctx) == NULL &&
1128 gsasl_server_callback_retrieve_get (ctx) == NULL)
1129 return GSASL_NEED_SERVER_DIGEST_MD5_CALLBACK;
1131 state = (_Gsasl_digest_md5_server_state*) malloc(sizeof(*state));
1132 if (state == NULL)
1133 return GSASL_MALLOC_ERROR;
1135 state->step = 0;
1136 gcry_randomize (state->nonce, NONCE_ENTROPY_BITS/8, GCRY_WEAK_RANDOM);
1138 *mech_data = state;
1140 return GSASL_OK;
1144 _gsasl_digest_md5_server_step (Gsasl_session_ctx *sctx,
1145 void *mech_data,
1146 const char *input,
1147 size_t input_len,
1148 char *output,
1149 size_t *output_len)
1151 _Gsasl_digest_md5_server_state *state = mech_data;
1152 Gsasl_server_callback_realm cb_realm;
1153 Gsasl_server_callback_qop cb_qop;
1154 Gsasl_server_callback_maxbuf cb_maxbuf;
1155 Gsasl_server_callback_cipher cb_cipher;
1156 Gsasl_server_callback_retrieve cb_retrieve;
1157 Gsasl_server_callback_digest_md5 cb_digest_md5;
1158 Gsasl_ctx *ctx;
1159 int res;
1160 int outlen;
1161 int maxbuf;
1163 ctx = gsasl_server_ctx_get (sctx);
1164 if (ctx == NULL)
1165 return GSASL_CANNOT_GET_CTX;
1167 cb_realm = gsasl_server_callback_realm_get (ctx);
1168 cb_qop = gsasl_server_callback_qop_get (ctx);
1169 cb_maxbuf = gsasl_server_callback_maxbuf_get (ctx);
1170 cb_cipher = gsasl_server_callback_cipher_get (ctx);
1171 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
1172 cb_digest_md5 = gsasl_server_callback_digest_md5_get (ctx);
1174 if (gsasl_server_callback_digest_md5_get (ctx) == NULL &&
1175 gsasl_server_callback_retrieve_get (ctx) == NULL)
1176 return GSASL_NEED_SERVER_DIGEST_MD5_CALLBACK;
1178 if (*output_len < 1)
1179 return GSASL_TOO_SMALL_BUFFER;
1181 strcpy(output, "");
1182 outlen = 0;
1184 #if PRINT_OUTPUT
1185 if (input && input_len > 0)
1186 puts(input);
1187 #endif
1189 switch (state->step)
1191 case 0:
1192 if (cb_realm)
1194 int i;
1195 size_t realmlen;
1197 realmlen = *output_len;
1198 for (i = 0; cb_realm(sctx, NULL, &realmlen, i) == GSASL_OK; i++)
1200 if (outlen + strlen(REALM_PRE) +
1201 realmlen + strlen(REALM_POST) >= *output_len)
1202 return GSASL_TOO_SMALL_BUFFER;
1204 strcat(output, REALM_PRE);
1205 outlen += strlen(REALM_PRE);
1207 cb_realm(sctx, &output[outlen], &realmlen, i);
1208 outlen += realmlen;
1209 output[outlen] = '\0';
1211 strcat(output, REALM_POST);
1212 outlen += strlen(REALM_POST);
1214 realmlen = *output_len - outlen;
1217 /* nonce */
1219 int i;
1221 if (outlen + strlen(NONCE_PRE) +
1222 2 * NONCE_ENTROPY_BITS/8 + strlen(NONCE_POST) >= *output_len)
1223 return GSASL_TOO_SMALL_BUFFER;
1225 strcat(output, NONCE_PRE);
1226 outlen += strlen(NONCE_PRE);
1228 for (i = 0; i < NONCE_ENTROPY_BITS/8; i++)
1230 output[outlen + 2*i + 1] = HEXCHAR(state->nonce[i]);
1231 output[outlen + 2*i + 0] = HEXCHAR(state->nonce[i] >> 4);
1233 output[outlen + 2 * NONCE_ENTROPY_BITS/8] = '\0';
1234 outlen += 2 * NONCE_ENTROPY_BITS/8;
1236 strcat(output, NONCE_POST);
1237 outlen += strlen(NONCE_POST);
1239 /* qop */
1241 Gsasl_qop qop;
1243 if (outlen +
1244 strlen(QOP_LIST_PRE) +
1245 strlen(QOP_AUTH) +
1246 strlen(QOP_AUTH_INT) +
1247 strlen(QOP_AUTH_CONF) +
1248 strlen(QOP_LIST_POST) >= *output_len)
1249 return GSASL_TOO_SMALL_BUFFER;
1251 if (cb_qop)
1252 qop = cb_qop(sctx);
1253 else
1254 qop = GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF;
1256 strcat(output, QOP_LIST_PRE);
1257 outlen += strlen(QOP_LIST_PRE);
1259 if (qop & GSASL_QOP_AUTH)
1261 strcat(output, QOP_AUTH);
1262 outlen += strlen(QOP_AUTH);
1264 strcat(output, QOP_DELIM);
1265 outlen += strlen(QOP_DELIM);
1268 if (qop & GSASL_QOP_AUTH_INT)
1270 strcat(output, QOP_AUTH_INT);
1271 outlen += strlen(QOP_AUTH_INT);
1273 strcat(output, QOP_DELIM);
1274 outlen += strlen(QOP_DELIM);
1277 if (qop & GSASL_QOP_AUTH_CONF)
1279 strcat(output, QOP_AUTH_CONF);
1280 outlen += strlen(QOP_AUTH_CONF);
1283 strcat(output, QOP_LIST_POST);
1284 outlen += strlen(QOP_LIST_POST);
1286 /* maxbuf */
1287 if (cb_maxbuf && (maxbuf = cb_maxbuf(sctx)) != MAXBUF_DEFAULT)
1289 if (outlen +
1290 strlen(MAXBUF_PRE) +
1291 /* XXX don't require -lm, how? */
1292 1+floor(log10(INT_MAX)) +
1293 strlen(MAXBUF_POST) >= *output_len)
1294 return GSASL_TOO_SMALL_BUFFER;
1296 strcat(output, MAXBUF_PRE);
1297 outlen += strlen(MAXBUF_PRE);
1299 sprintf(&output[outlen], "%d", maxbuf);
1300 outlen += strlen(&output[outlen]);
1302 strcat(output, MAXBUF_POST);
1303 outlen += strlen(MAXBUF_POST);
1305 /* charset */
1307 if (outlen + strlen(CHARSET) >= *output_len)
1308 return GSASL_TOO_SMALL_BUFFER;
1310 strcat(output, CHARSET);
1311 outlen += strlen(CHARSET);
1313 /* algorithm */
1315 if (outlen + strlen(ALGORITHM) >= *output_len)
1316 return GSASL_TOO_SMALL_BUFFER;
1318 strcat(output, ALGORITHM);
1319 outlen += strlen(ALGORITHM);
1321 /* cipher */
1323 Gsasl_cipher cipher;
1325 if (outlen +
1326 strlen(CIPHER_PRE) +
1327 strlen(CIPHER_DES) +
1328 strlen(CIPHER_DELIM) +
1329 strlen(CIPHER_3DES) +
1330 strlen(CIPHER_DELIM) +
1331 strlen(CIPHER_RC4) +
1332 strlen(CIPHER_DELIM) +
1333 strlen(CIPHER_RC4_40) +
1334 strlen(CIPHER_DELIM) +
1335 strlen(CIPHER_RC4_56) +
1336 strlen(CIPHER_DELIM) +
1337 strlen(CIPHER_AES) +
1338 strlen(CIPHER_DELIM) +
1339 strlen(CIPHER_POST) >= *output_len)
1340 return GSASL_TOO_SMALL_BUFFER;
1342 if (cb_cipher)
1343 cipher = cb_cipher(sctx);
1344 else
1345 cipher = GSASL_CIPHER_DES | GSASL_CIPHER_3DES | GSASL_CIPHER_RC4 |
1346 GSASL_CIPHER_RC4_40 | GSASL_CIPHER_RC4_56 | GSASL_CIPHER_AES;
1348 strcat(output, CIPHER_PRE);
1349 outlen += strlen(CIPHER_PRE);
1351 if (cipher & GSASL_CIPHER_DES)
1353 strcat(output, CIPHER_DES);
1354 outlen += strlen(CIPHER_DES);
1356 strcat(output, CIPHER_DELIM);
1357 outlen += strlen(CIPHER_DELIM);
1360 if (cipher & GSASL_CIPHER_3DES)
1362 strcat(output, CIPHER_3DES);
1363 outlen += strlen(CIPHER_3DES);
1365 strcat(output, CIPHER_DELIM);
1366 outlen += strlen(CIPHER_DELIM);
1369 if (cipher & GSASL_CIPHER_RC4)
1371 strcat(output, CIPHER_RC4);
1372 outlen += strlen(CIPHER_RC4);
1374 strcat(output, CIPHER_DELIM);
1375 outlen += strlen(CIPHER_DELIM);
1378 if (cipher & GSASL_CIPHER_RC4_40)
1380 strcat(output, CIPHER_RC4_40);
1381 outlen += strlen(CIPHER_RC4_40);
1383 strcat(output, CIPHER_DELIM);
1384 outlen += strlen(CIPHER_DELIM);
1387 if (cipher & GSASL_CIPHER_RC4_56)
1389 strcat(output, CIPHER_RC4_56);
1390 outlen += strlen(CIPHER_RC4_56);
1392 strcat(output, CIPHER_DELIM);
1393 outlen += strlen(CIPHER_DELIM);
1396 if (cipher & GSASL_CIPHER_AES)
1398 strcat(output, CIPHER_AES);
1399 outlen += strlen(CIPHER_AES);
1401 strcat(output, CIPHER_DELIM);
1402 outlen += strlen(CIPHER_DELIM);
1405 strcat(output, CIPHER_POST);
1406 outlen += strlen(CIPHER_POST);
1408 *output_len = outlen;
1409 state->step++;
1410 res = GSASL_NEEDS_MORE;
1411 break;
1413 case 1:
1415 unsigned char *nonce = NULL;
1416 char *cnonce = NULL;
1417 uint32_t nc = 0;
1418 char *authzid = NULL;
1419 char *digesturi = NULL;
1420 const char *subopts, *value;
1421 unsigned char *realm = NULL;
1422 unsigned char *username = NULL;
1423 unsigned char *response = NULL;
1424 int maxbuf = MAXBUF_DEFAULT;
1425 int qop = GSASL_QOP_AUTH;
1426 int cipher = 0;
1427 int i;
1428 GCRY_MD_HD md5h = NULL;
1429 unsigned char secret[MD5LEN];
1431 if (input_len == 0)
1433 *output_len = 0;
1434 return GSASL_MECHANISM_PARSE_ERROR;
1437 subopts = input;
1438 while (*subopts != '\0')
1439 switch (_gsasl_getsubopt (&subopts, digest_response_opts, &value))
1441 case RESPONSE_USERNAME:
1442 if (username != NULL)
1444 res = GSASL_MECHANISM_PARSE_ERROR;
1445 goto done;
1447 username = strdup(value);
1448 break;
1450 case RESPONSE_REALM:
1451 if (realm != NULL)
1453 res = GSASL_MECHANISM_PARSE_ERROR;
1454 goto done;
1456 realm = strdup(value);
1457 break;
1459 case RESPONSE_NONCE:
1460 if (nonce != NULL)
1462 res = GSASL_MECHANISM_PARSE_ERROR;
1463 goto done;
1465 nonce = strdup(value);
1466 res = GSASL_OK;
1467 for (i = 0; i < MIN(strlen(value), NONCE_ENTROPY_BITS/8); i++)
1468 if ((nonce[2*i + 1] != HEXCHAR(state->nonce[i])) ||
1469 (nonce[2*i + 0] != HEXCHAR(state->nonce[i] >> 4)))
1470 res = GSASL_MECHANISM_PARSE_ERROR;
1471 if (res != GSASL_OK)
1472 goto done;
1473 break;
1475 case RESPONSE_CNONCE:
1476 if (cnonce != NULL)
1478 res = GSASL_MECHANISM_PARSE_ERROR;
1479 goto done;
1481 cnonce = strdup(value);
1482 break;
1484 case RESPONSE_NC:
1485 if (nc != 0)
1487 res = GSASL_MECHANISM_PARSE_ERROR;
1488 goto done;
1490 nc = strtoul(value, NULL, 16);
1491 break;
1493 case RESPONSE_QOP:
1494 if (strcmp(value, QOP_AUTH) == 0)
1495 qop = GSASL_QOP_AUTH;
1496 else if (strcmp(value, QOP_AUTH_INT) == 0)
1497 qop = GSASL_QOP_AUTH_INT;
1498 else if (strcmp(value, QOP_AUTH_CONF) == 0)
1499 qop = GSASL_QOP_AUTH_CONF;
1500 else
1502 res = GSASL_MECHANISM_PARSE_ERROR;
1503 goto done;
1505 break;
1507 case RESPONSE_DIGEST_URI:
1508 if (digesturi != NULL)
1510 res = GSASL_MECHANISM_PARSE_ERROR;
1511 goto done;
1513 digesturi = strdup(value);
1514 break;
1516 case RESPONSE_RESPONSE:
1517 if (response != NULL)
1519 res = GSASL_MECHANISM_PARSE_ERROR;
1520 goto done;
1522 response = strdup(value);
1523 break;
1525 case RESPONSE_MAXBUF:
1526 maxbuf = strtol(value, NULL, 10);
1527 break;
1529 case RESPONSE_CHARSET:
1530 if (strcmp(DEFAULT_CHARSET, value) != 0)
1532 res = GSASL_MECHANISM_PARSE_ERROR;
1533 goto done;
1535 break;
1537 case RESPONSE_CIPHER:
1538 if (cipher != 0)
1540 res = GSASL_MECHANISM_PARSE_ERROR;
1541 goto done;
1543 if (strcmp(value, CIPHER_DES) == 0)
1544 cipher = GSASL_CIPHER_DES;
1545 else if (strcmp(value, CIPHER_3DES) == 0)
1546 cipher = GSASL_CIPHER_3DES;
1547 else if (strcmp(value, CIPHER_RC4) == 0)
1548 cipher = GSASL_CIPHER_RC4;
1549 else if (strcmp(value, CIPHER_RC4_40) == 0)
1550 cipher = GSASL_CIPHER_RC4_40;
1551 else if (strcmp(value, CIPHER_RC4_56) == 0)
1552 cipher = GSASL_CIPHER_RC4_56;
1553 else if (strcmp(value, CIPHER_AES) == 0)
1554 cipher = GSASL_CIPHER_AES;
1555 else
1557 res = GSASL_MECHANISM_PARSE_ERROR;
1558 goto done;
1560 break;
1562 case RESPONSE_AUTHZID:
1563 if (authzid != NULL)
1565 res = GSASL_MECHANISM_PARSE_ERROR;
1566 goto done;
1568 authzid = strdup(value);
1569 break;
1571 default:
1572 /* Ignoring unknown parameter. */
1573 break;
1576 if (username == NULL || nonce == NULL ||
1577 cnonce == NULL || response == NULL ||
1578 (qop == GSASL_QOP_AUTH_CONF && cipher == 0))
1580 res = GSASL_MECHANISM_PARSE_ERROR;
1581 goto done;
1584 if (outlen +
1585 strlen(RSPAUTH_PRE) +
1586 RESPONSE_LENGTH +
1587 strlen(RSPAUTH_POST) >= *output_len)
1589 res = GSASL_TOO_SMALL_BUFFER;
1590 goto done;
1592 if (cb_retrieve)
1594 unsigned char *tmp;
1595 size_t len;
1596 size_t keylen;
1597 char *key;
1598 char *normkey;
1600 res = cb_retrieve(sctx, username, authzid, realm, NULL, &keylen);
1601 if (res != GSASL_OK)
1602 goto done;
1603 key = malloc(keylen);
1604 if (key == NULL)
1606 res = GSASL_MALLOC_ERROR;
1607 goto done;
1609 res = cb_retrieve(sctx, username, authzid, realm, key, &keylen);
1610 if (res != GSASL_OK)
1612 free(key);
1613 goto done;
1615 normkey = gsasl_utf8_nfkc_normalize (key, keylen);
1616 free(key);
1617 if (normkey == NULL)
1619 res = GSASL_UNICODE_NORMALIZATION_ERROR;
1620 goto done;
1623 md5h = gcry_md_open (GCRY_MD_MD5, 0);
1624 if (md5h == NULL)
1626 res = GSASL_GCRYPT_ERROR;
1627 goto done;
1629 gcry_md_write (md5h, username, strlen(username));
1630 gcry_md_write (md5h, COLON, strlen(COLON));
1631 if (realm)
1632 gcry_md_write (md5h, realm, strlen(realm));
1633 gcry_md_write (md5h, COLON, strlen(COLON));
1634 gcry_md_write (md5h, normkey, strlen(normkey));
1636 tmp = gcry_md_read (md5h, GCRY_MD_MD5);
1637 if (tmp == NULL)
1639 res = GSASL_GCRYPT_ERROR;
1640 goto done;
1642 memcpy(secret, tmp, MD5LEN);
1644 else /* if (cb_digest_md5) */
1646 /* XXX? secret hash stored in callee's output buffer */
1647 res = cb_digest_md5 (sctx, username, realm, output+outlen);
1648 if (res != GSASL_OK)
1649 goto done;
1651 memcpy(secret, output+outlen, MD5LEN);
1654 /* verify response */
1655 res = _gsasl_digest (output+outlen, secret,
1656 nonce, nc, cnonce, qop, authzid,
1657 digesturi, A2_PRE);
1658 if (res != GSASL_OK)
1659 goto done;
1661 if (memcmp(response, output + outlen, RESPONSE_LENGTH) != 0)
1663 res = GSASL_AUTHENTICATION_ERROR;
1664 goto done;
1667 output[outlen] = '\0';
1669 /* XXX check more things here. digest-uri? valid qop, cipher,
1670 nc etc. nonce, which is the most important, is checked
1671 above. */
1673 /* generate rspauth */
1675 strcat(output, RSPAUTH_PRE);
1676 outlen += strlen(RSPAUTH_PRE);
1678 res = _gsasl_digest (output+outlen, secret,
1679 nonce, nc, cnonce, qop, authzid,
1680 digesturi, COLON);
1681 if (res != GSASL_OK)
1682 goto done;
1683 outlen += RSPAUTH_LENGTH;
1685 strcat(output, RSPAUTH_POST);
1686 outlen += strlen(RSPAUTH_POST);
1688 if (md5h)
1689 gcry_md_close(md5h);
1691 res = GSASL_NEEDS_MORE;
1692 done:
1693 if (username)
1694 free(username);
1695 if (authzid)
1696 free(authzid);
1697 if (response)
1698 free(response);
1699 if (digesturi)
1700 free(digesturi);
1701 if (nonce)
1702 free(nonce);
1703 if (cnonce)
1704 free(cnonce);
1705 if (realm)
1706 free(realm);
1708 *output_len = outlen;
1709 state->step++;
1710 break;
1712 case 2:
1713 *output_len = 0;
1714 state->step++;
1715 res = GSASL_OK;
1716 break;
1718 default:
1719 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
1720 break;
1723 #if PRINT_OUTPUT
1724 if (output && *output_len > 0)
1725 puts(output);
1726 #endif
1728 return res;
1732 _gsasl_digest_md5_server_finish (Gsasl_session_ctx *sctx,
1733 void *mech_data)
1735 _Gsasl_digest_md5_server_state *state = mech_data;
1737 free(state);
1739 return GSASL_OK;
1742 #endif /* USE_DIGEST_MD5 */