Clean up #include mess by creating internal.h.
[gsasl.git] / lib / digest-md5.c
blob7de16f2337708fbb5268e6ad0ea5079ce5408452
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
41 #ifdef HAVE_NETINET_IN_H
42 #include <netinet/in.h>
43 #endif
45 #define NONCE_ENTROPY_BITS 64
46 #define CNONCE_ENTROPY_BITS 64
48 #define DELIM ", "
49 #define REALM_PRE "realm=\""
50 #define REALM_POST "\"" DELIM
51 #define NONCE_PRE "nonce=\""
52 #define NONCE_POST "\"" DELIM
53 #define QOP_LIST_PRE "qop=\""
54 #define QOP_LIST_POST "\"" DELIM
55 #ifdef DONT_WORKAROUND_CYRUS_SASL_BUG
56 #define QOP_DELIM DELIM
57 #else
58 #define QOP_DELIM ","
59 #endif
60 #define QOP_AUTH "auth"
61 #define QOP_AUTH_INT "auth-int"
62 #define QOP_AUTH_CONF "auth-conf"
63 #define MAXBUF_PRE "maxbuf="
64 #define MAXBUF_POST DELIM
65 #define DEFAULT_CHARSET "utf-8"
66 #define CHARSET "charset=" DEFAULT_CHARSET DELIM
67 #define DEFAULT_ALGORITHM "md5-sess"
68 #define ALGORITHM "algorithm=" DEFAULT_ALGORITHM DELIM
69 #define CIPHER_PRE "cipher=\""
70 #define CIPHER_DELIM DELIM
71 #define CIPHER_DES "des"
72 #define CIPHER_3DES "3des"
73 #define CIPHER_RC4_40 "rc4-40"
74 #define CIPHER_RC4 "rc4"
75 #define CIPHER_RC4_56 "rc4-56"
76 #define CIPHER_AES "aes"
77 #ifdef DONT_WORKAROUND_CYRUS_SASL_BUG
78 #define CIPHER_POST "\"" DELIM
79 #else
80 #define CIPHER_POST "\""
81 #endif
83 #define USERNAME_PRE "username=\""
84 #define USERNAME_POST "\"" DELIM
85 #define CNONCE_PRE "cnonce=\""
86 #define CNONCE_POST "\"" DELIM
87 #define NONCE_COUNT_PRE "nc="
88 #define NONCE_COUNT_POST DELIM
89 #define QOP_PRE "qop="
90 #define QOP_POST DELIM
91 #define RESPONSE_PRE "response="
92 #define RESPONSE_POST "" DELIM
93 #define AUTHZID_PRE "authzid=\""
94 #define AUTHZID_POST "\"" DELIM
95 #define DIGEST_URI_PRE "digest-uri=\""
96 #define DIGEST_URI_POST "\"" DELIM
98 #define RSPAUTH_PRE "rspauth="
99 #define RSPAUTH_POST ""
101 #define A2_PRE "AUTHENTICATE:"
102 #define A2_POST ":00000000000000000000000000000000"
103 #define COLON ":"
104 #define NCLEN 8
105 #define MD5LEN 16
106 #define SASL_INTEGRITY_PREFIX_LENGTH 4
107 #define MACLEN 16
108 #define MAC_DATA_LEN 4
109 #define MAC_HMAC_LEN 10
110 #define MAC_MSG_TYPE "\x00\x01"
111 #define MAC_MSG_TYPE_LEN 2
112 #define MAC_SEQNUM_LEN 4
113 #define MAXBUF_DEFAULT 65536
114 #define RESPONSE_LENGTH 32
115 #define RSPAUTH_LENGTH RESPONSE_LENGTH
116 #define DERIVE_CLIENT_INTEGRITY_KEY_STRING "Digest session key to client-to-server signing key magic constant"
117 #define DERIVE_SERVER_INTEGRITY_KEY_STRING "Digest session key to server-to-client signing key magic constant"
118 #define DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING "Digest H(A1) to client-to-server sealing key magic constant"
119 #define DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING "Digest H(A1) to server-to-client sealing key magic constant"
122 #define CLIENT_PRINT_OUTPUT 0
123 #define SERVER_PRINT_OUTPUT 0
125 enum
127 /* the order must match the following struct */
128 CHALLENGE_REALM = 0,
129 CHALLENGE_NONCE,
130 CHALLENGE_QOP,
131 CHALLENGE_STALE,
132 CHALLENGE_MAXBUF,
133 CHALLENGE_CHARSET,
134 CHALLENGE_ALGORITHM,
135 CHALLENGE_CIPHER
138 const char *digest_challenge_opts[] = {
139 /* the order must match the previous enum */
140 "realm",
141 "nonce",
142 "qop",
143 "stale",
144 "maxbuf",
145 "charset",
146 "algorithm",
147 "cipher",
148 NULL
151 enum
153 /* the order must match the following struct */
154 RESPONSE_USERNAME = 0,
155 RESPONSE_REALM,
156 RESPONSE_NONCE,
157 RESPONSE_CNONCE,
158 RESPONSE_NC,
159 RESPONSE_QOP,
160 RESPONSE_DIGEST_URI,
161 RESPONSE_RESPONSE,
162 RESPONSE_MAXBUF,
163 RESPONSE_CHARSET,
164 RESPONSE_CIPHER,
165 RESPONSE_AUTHZID
168 const char *digest_response_opts[] = {
169 /* the order must match the previous enum */
170 "username",
171 "realm",
172 "nonce",
173 "cnonce",
174 "nc",
175 "qop",
176 "digest-uri",
177 "response",
178 "maxbuf",
179 "charset",
180 "cipher",
181 "authzid",
182 NULL
185 enum
187 /* the order must match the following struct */
188 RESPONSEAUTH_RSPAUTH = 0
191 const char *digest_responseauth_opts[] = {
192 /* the order must match the previous enum */
193 "rspauth",
194 NULL
197 enum
199 /* the order must match the following struct */
200 QOP_AUTH_OPTION = 0,
201 QOP_AUTH_INT_OPTION,
202 QOP_AUTH_CONF_OPTION
205 const char *qop_opts[] = {
206 /* the order must match the previous enum */
207 QOP_AUTH,
208 QOP_AUTH_INT,
209 QOP_AUTH_CONF,
210 NULL
213 enum
215 /* the order must match the following struct */
216 CIPHER_DES_OPTION = 0,
217 CIPHER_3DES_OPTION,
218 CIPHER_RC4_OPTION,
219 CIPHER_RC4_40_OPTION,
220 CIPHER_RC4_56_OPTION,
221 CIPHER_AES_OPTION
224 const char *cipher_opts[] = {
225 /* the order must match the previous enum */
226 CIPHER_DES,
227 CIPHER_3DES,
228 CIPHER_RC4,
229 CIPHER_RC4_40,
230 CIPHER_RC4_56,
231 CIPHER_AES,
232 NULL
235 /* Parse comma separate list into words.
236 Copyright (C) 1996, 1997, 1999 Free Software Foundation, Inc.
237 From the GNU C Library, under GNU LGPL version 2.1.
238 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
239 Modified for Libgsasl by Simon Josefsson <simon@josefsson.org>
240 Copyright (C) 2002 Simon Josefsson
242 Parse comma separated suboption from *OPTIONP and match against
243 strings in TOKENS. If found return index and set *VALUEP to
244 optional value introduced by an equal sign. If the suboption is
245 not part of TOKENS return in *VALUEP beginning of unknown
246 suboption. On exit *OPTIONP is set to the beginning of the next
247 token or at the terminating NUL character. */
248 static int
249 _gsasl_getsubopt (optionp, tokens, valuep)
250 char **optionp;
251 char *const *tokens;
252 char **valuep;
254 char *endp, *vstart;
255 int cnt;
256 int inside_quote = 0;
258 if (**optionp == '\0')
259 return -1;
261 /* Find end of next token. */
262 endp = *optionp;
263 while (*endp != '\0' && (inside_quote || (!inside_quote && *endp != ',')))
265 if (*endp == '"')
266 inside_quote = !inside_quote;
267 endp++;
270 /* Find start of value. */
271 vstart = memchr (*optionp, '=', endp - *optionp);
272 if (vstart == NULL)
273 vstart = endp;
275 /* Try to match the characters between *OPTIONP and VSTART against
276 one of the TOKENS. */
277 for (cnt = 0; tokens[cnt] != NULL; ++cnt)
278 if (memcmp (*optionp, tokens[cnt], vstart - *optionp) == 0
279 && tokens[cnt][vstart - *optionp] == '\0')
281 /* We found the current option in TOKENS. */
282 *valuep = vstart != endp ? vstart + 1 : NULL;
284 while (*valuep && (**valuep == ' ' ||
285 **valuep == '\t' ||
286 **valuep == '\r' ||
287 **valuep == '\n' || **valuep == '"'))
288 (*valuep)++;
290 if (*endp != '\0')
291 *endp++ = '\0';
292 *optionp = endp;
293 endp -= 2;
294 while (*endp == ' ' ||
295 *endp == '\t' ||
296 *endp == '\r' || *endp == '\n' || *endp == '"')
297 *endp-- = '\0';
298 while (**optionp == ' ' ||
299 **optionp == '\t' || **optionp == '\r' || **optionp == '\n')
300 (*optionp)++;
302 return cnt;
305 /* The current suboption does not match any option. */
306 *valuep = *optionp;
308 if (*endp != '\0')
309 *endp++ = '\0';
310 *optionp = endp;
311 while (**optionp == ' ' ||
312 **optionp == '\t' || **optionp == '\r' || **optionp == '\n')
313 (*optionp)++;
315 return -1;
318 static int
319 _gsasl_digest (char *output, /* must have 2*MD5LEN available bytes */
320 unsigned char secret[MD5LEN], unsigned char *nonce, uint32_t nc, char *cnonce, int qop, char *authzid, char *digesturi, char *a2string, /* "AUTHENTICATE:" or ":" */
321 int cipher, /* used by kcc and kcs */
322 char *kic, /* output client integrity key, may be NULL */
323 char *kis, /* output server integrity key, may be NULL */
324 char *kcc, /* output client confidentiality key, may be NULL */
325 char *kcs) /* output server confidentiality key, may be NULL */
327 char nchex[NCLEN + 1];
328 char a1hexhash[2 * MD5LEN];
329 char a2hexhash[2 * MD5LEN];
330 GCRY_MD_HD md5h;
331 unsigned char *hash;
332 int i;
334 /* A1 */
336 md5h = gcry_md_open (GCRY_MD_MD5, 0);
337 if (md5h == NULL)
338 return GSASL_GCRYPT_ERROR;
340 gcry_md_write (md5h, secret, MD5LEN);
341 gcry_md_write (md5h, COLON, strlen (COLON));
342 gcry_md_write (md5h, nonce, strlen (nonce));
343 gcry_md_write (md5h, COLON, strlen (COLON));
344 gcry_md_write (md5h, cnonce, strlen (cnonce));
345 if (authzid && strlen (authzid) > 0)
347 gcry_md_write (md5h, COLON, strlen (COLON));
348 gcry_md_write (md5h, authzid, strlen (authzid));
351 hash = gcry_md_read (md5h, GCRY_MD_MD5);
352 if (hash == NULL)
353 return GSASL_GCRYPT_ERROR;
355 if (kic)
357 GCRY_MD_HD md5h2;
358 char *hash2;
360 md5h2 = gcry_md_open (GCRY_MD_MD5, 0);
361 if (md5h2 == NULL)
362 return GSASL_GCRYPT_ERROR;
364 gcry_md_write (md5h2, hash, MD5LEN);
365 gcry_md_write (md5h2, DERIVE_CLIENT_INTEGRITY_KEY_STRING,
366 strlen (DERIVE_CLIENT_INTEGRITY_KEY_STRING));
368 hash2 = gcry_md_read (md5h2, GCRY_MD_MD5);
369 if (hash2 == NULL)
370 return GSASL_GCRYPT_ERROR;
372 memcpy (kic, hash2, MD5LEN);
374 gcry_md_close (md5h2);
377 if (kcc)
379 GCRY_MD_HD md5h2;
380 char *hash2;
381 int n;
383 md5h2 = gcry_md_open (GCRY_MD_MD5, 0);
384 if (md5h2 == NULL)
385 return GSASL_GCRYPT_ERROR;
387 if (cipher == GSASL_CIPHER_RC4_40)
388 n = 5;
389 else if (cipher == GSASL_CIPHER_RC4_56)
390 n = 7;
391 else
392 n = MD5LEN;
393 gcry_md_write (md5h2, hash, n);
394 gcry_md_write (md5h2, DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING,
395 strlen (DERIVE_CLIENT_CONFIDENTIALITY_KEY_STRING));
397 hash2 = gcry_md_read (md5h2, GCRY_MD_MD5);
398 if (hash2 == NULL)
399 return GSASL_GCRYPT_ERROR;
401 memcpy (kcc, hash2, MD5LEN);
403 gcry_md_close (md5h2);
406 if (kis)
408 GCRY_MD_HD md5h2;
409 char *hash2;
411 md5h2 = gcry_md_open (GCRY_MD_MD5, 0);
412 if (md5h2 == NULL)
413 return GSASL_GCRYPT_ERROR;
415 gcry_md_write (md5h2, hash, MD5LEN);
416 gcry_md_write (md5h2, DERIVE_SERVER_INTEGRITY_KEY_STRING,
417 strlen (DERIVE_SERVER_INTEGRITY_KEY_STRING));
419 hash2 = gcry_md_read (md5h2, GCRY_MD_MD5);
420 if (hash2 == NULL)
421 return GSASL_GCRYPT_ERROR;
423 memcpy (kis, hash2, MD5LEN);
425 gcry_md_close (md5h2);
428 if (kcs)
430 GCRY_MD_HD md5h2;
431 char *hash2;
432 int n;
434 md5h2 = gcry_md_open (GCRY_MD_MD5, 0);
435 if (md5h2 == NULL)
436 return GSASL_GCRYPT_ERROR;
438 if (cipher == GSASL_CIPHER_RC4_40)
439 n = 5;
440 else if (cipher == GSASL_CIPHER_RC4_56)
441 n = 7;
442 else
443 n = MD5LEN;
444 gcry_md_write (md5h2, hash, n);
445 gcry_md_write (md5h2, DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING,
446 strlen (DERIVE_SERVER_CONFIDENTIALITY_KEY_STRING));
448 hash2 = gcry_md_read (md5h2, GCRY_MD_MD5);
449 if (hash2 == NULL)
450 return GSASL_GCRYPT_ERROR;
452 memcpy (kcs, hash2, MD5LEN);
454 gcry_md_close (md5h2);
457 for (i = 0; i < MD5LEN; i++)
459 a1hexhash[2 * i + 1] = HEXCHAR (hash[i]);
460 a1hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
462 gcry_md_close (md5h);
464 /* A2 */
466 md5h = gcry_md_open (GCRY_MD_MD5, 0);
467 if (md5h == NULL)
468 return GSASL_GCRYPT_ERROR;
470 gcry_md_write (md5h, a2string, strlen (a2string));
471 gcry_md_write (md5h, digesturi, strlen (digesturi));
472 if (qop & GSASL_QOP_AUTH_INT || qop & GSASL_QOP_AUTH_CONF)
474 gcry_md_write (md5h, A2_POST, strlen (A2_POST));
477 hash = gcry_md_read (md5h, GCRY_MD_MD5);
478 if (hash == NULL)
479 return GSASL_GCRYPT_ERROR;
481 for (i = 0; i < MD5LEN; i++)
483 a2hexhash[2 * i + 1] = HEXCHAR (hash[i]);
484 a2hexhash[2 * i + 0] = HEXCHAR (hash[i] >> 4);
486 gcry_md_close (md5h);
488 /* response_value */
490 md5h = gcry_md_open (GCRY_MD_MD5, 0);
491 if (md5h == NULL)
492 return GSASL_GCRYPT_ERROR;
494 gcry_md_write (md5h, a1hexhash, 2 * MD5LEN);
495 gcry_md_write (md5h, COLON, strlen (COLON));
496 gcry_md_write (md5h, nonce, strlen (nonce));
497 gcry_md_write (md5h, COLON, strlen (COLON));
498 sprintf (nchex, "%0*x", NCLEN, nc);
499 gcry_md_write (md5h, nchex, strlen (nchex));
500 gcry_md_write (md5h, COLON, strlen (COLON));
501 gcry_md_write (md5h, cnonce, strlen (cnonce));
502 gcry_md_write (md5h, COLON, strlen (COLON));
503 if (qop & GSASL_QOP_AUTH_CONF)
504 gcry_md_write (md5h, QOP_AUTH_CONF, strlen (QOP_AUTH_CONF));
505 else if (qop & GSASL_QOP_AUTH_INT)
506 gcry_md_write (md5h, QOP_AUTH_INT, strlen (QOP_AUTH_INT));
507 else if (qop & GSASL_QOP_AUTH)
508 gcry_md_write (md5h, QOP_AUTH, strlen (QOP_AUTH));
509 gcry_md_write (md5h, COLON, strlen (COLON));
510 gcry_md_write (md5h, a2hexhash, 2 * MD5LEN);
512 hash = gcry_md_read (md5h, GCRY_MD_MD5);
513 if (hash == NULL)
514 return GSASL_GCRYPT_ERROR;
516 for (i = 0; i < MD5LEN; i++)
518 output[2 * i + 1] = HEXCHAR (hash[i]);
519 output[2 * i + 0] = HEXCHAR (hash[i] >> 4);
521 gcry_md_close (md5h);
523 return GSASL_OK;
526 /* Client */
528 struct _Gsasl_digest_md5_client_state
530 int step;
531 unsigned char secret[MD5LEN];
532 unsigned char *nonce;
533 uint32_t nc;
534 unsigned char cnonce[2 * CNONCE_ENTROPY_BITS / 8 + 1];
535 Gsasl_qop qop;
536 Gsasl_cipher cipher;
537 unsigned char *authzid;
538 unsigned char *digesturi;
539 unsigned char response[RESPONSE_LENGTH + 1];
540 uint32_t readseqnum, sendseqnum;
541 unsigned char kic[MD5LEN];
542 unsigned char kcc[MD5LEN];
543 unsigned char kis[MD5LEN];
544 unsigned char kcs[MD5LEN];
546 typedef struct _Gsasl_digest_md5_client_state _Gsasl_digest_md5_client_state;
549 _gsasl_digest_md5_client_init (Gsasl_ctx * ctx)
551 int res;
553 if (gcry_check_version (GCRYPT_VERSION) == NULL)
554 return GSASL_GCRYPT_ERROR;
556 res = gcry_control (GCRYCTL_INIT_SECMEM, 512, 0);
557 if (res != GCRYERR_SUCCESS)
558 return GSASL_GCRYPT_ERROR;
560 return GSASL_OK;
563 void
564 _gsasl_digest_md5_client_done (Gsasl_ctx * ctx)
566 return;
570 _gsasl_digest_md5_client_start (Gsasl_session_ctx * cctx, void **mech_data)
572 _Gsasl_digest_md5_client_state *state;
573 Gsasl_ctx *ctx;
575 ctx = gsasl_client_ctx_get (cctx);
576 if (ctx == NULL)
577 return GSASL_CANNOT_GET_CTX;
579 if (gsasl_client_callback_authentication_id_get (ctx) == NULL)
580 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
582 if (gsasl_client_callback_password_get (ctx) == NULL)
583 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
585 state = (_Gsasl_digest_md5_client_state *) malloc (sizeof (*state));
586 if (state == NULL)
587 return GSASL_MALLOC_ERROR;
589 state->step = 0;
590 state->nonce = NULL;
591 state->nc = 1;
592 state->cipher = 0;
593 state->qop = GSASL_QOP_AUTH;
594 state->authzid = NULL;
595 state->digesturi = NULL;
596 state->readseqnum = 0;
597 state->sendseqnum = 0;
599 *mech_data = state;
601 return GSASL_OK;
605 _gsasl_digest_md5_client_step (Gsasl_session_ctx * cctx,
606 void *mech_data,
607 const char *input,
608 size_t input_len,
609 char *output, size_t * output_len)
611 _Gsasl_digest_md5_client_state *state = mech_data;
612 Gsasl_client_callback_authorization_id cb_authorization_id;
613 Gsasl_client_callback_authentication_id cb_authentication_id;
614 Gsasl_client_callback_password cb_password;
615 Gsasl_client_callback_service cb_service;
616 Gsasl_client_callback_qop cb_qop;
617 Gsasl_client_callback_maxbuf cb_maxbuf;
618 char *subopts;
619 char *value;
620 Gsasl_ctx *ctx;
621 int outlen;
622 int res, i;
624 ctx = gsasl_client_ctx_get (cctx);
625 if (ctx == NULL)
626 return GSASL_CANNOT_GET_CTX;
628 cb_qop = gsasl_client_callback_qop_get (ctx);
629 cb_authorization_id = gsasl_client_callback_authorization_id_get (ctx);
630 cb_maxbuf = gsasl_client_callback_maxbuf_get (ctx);
632 cb_authentication_id = gsasl_client_callback_authentication_id_get (ctx);
633 if (cb_authentication_id == NULL)
634 return GSASL_NEED_CLIENT_AUTHENTICATION_ID_CALLBACK;
636 cb_password = gsasl_client_callback_password_get (ctx);
637 if (cb_password == NULL)
638 return GSASL_NEED_CLIENT_PASSWORD_CALLBACK;
640 cb_service = gsasl_client_callback_service_get (ctx);
641 if (cb_service == NULL)
642 return GSASL_NEED_CLIENT_SERVICE_CALLBACK;
644 if (*output_len < 1)
645 return GSASL_TOO_SMALL_BUFFER;
647 strcpy (output, "");
648 outlen = 0;
650 #if CLIENT_PRINT_OUTPUT
651 if (input && input_len > 0)
652 fprintf (stderr, "%s\n", input);
653 #endif
655 switch (state->step)
657 case 0:
658 state->step++;
659 if (input_len == 0)
661 *output_len = 0;
662 return GSASL_NEEDS_MORE;
664 /* fall through */
666 case 1:
668 char **realm = NULL;
669 size_t nrealm = 0;
670 int maxbuf = MAXBUF_DEFAULT;
671 char *zinput = NULL;
673 if (input == NULL || input_len == 0)
674 return GSASL_MECHANISM_PARSE_ERROR;
676 zinput = malloc (input_len + 1);
677 if (zinput == NULL)
678 return GSASL_MALLOC_ERROR;
679 memcpy (zinput, input, input_len);
680 zinput[input_len] = '\0';
682 gcry_randomize (state->cnonce, CNONCE_ENTROPY_BITS / 8,
683 GCRY_WEAK_RANDOM);
684 for (i = 0; i < CNONCE_ENTROPY_BITS / 8; i++)
686 state->cnonce[CNONCE_ENTROPY_BITS / 8 + i] =
687 HEXCHAR (state->cnonce[i]);
688 state->cnonce[i] = HEXCHAR (state->cnonce[i] >> 4);
690 state->cnonce[2 * CNONCE_ENTROPY_BITS / 8] = '\0';
692 subopts = zinput;
693 while (*subopts != '\0')
694 switch (_gsasl_getsubopt (&subopts, digest_challenge_opts, &value))
696 case CHALLENGE_REALM:
697 if (nrealm == 0)
698 realm = (char **) malloc (sizeof (*realm));
699 else
700 realm = realloc (realm, (nrealm + 1) * sizeof (*realm));
701 if (realm == NULL)
703 res = GSASL_MALLOC_ERROR;
704 goto done;
706 realm[nrealm] = strdup (value);
707 nrealm++;
708 break;
710 case CHALLENGE_NONCE:
711 if (state->nonce != NULL)
713 res = GSASL_MECHANISM_PARSE_ERROR;
714 goto done;
716 state->nonce = strdup (value);
717 break;
719 case CHALLENGE_QOP:
721 char *subsubopts;
722 char *val;
724 state->qop = 0;
725 subsubopts = value;
726 while (*subsubopts != '\0')
727 switch (_gsasl_getsubopt (&subsubopts, qop_opts, &val))
729 case QOP_AUTH_OPTION:
730 state->qop |= GSASL_QOP_AUTH;
731 break;
733 case QOP_AUTH_INT_OPTION:
734 state->qop |= GSASL_QOP_AUTH_INT;
735 break;
737 case QOP_AUTH_CONF_OPTION:
738 state->qop |= GSASL_QOP_AUTH_CONF;
739 break;
741 default:
742 /* Ignore unknown qop */
743 break;
746 break;
748 case CHALLENGE_STALE:
749 printf ("XXX stale: %s\n", value);
750 break;
752 case CHALLENGE_MAXBUF:
753 maxbuf = strtol (value, NULL, 10);
754 break;
756 case CHALLENGE_CHARSET:
757 if (strcmp (DEFAULT_CHARSET, value) != 0)
759 res = GSASL_MECHANISM_PARSE_ERROR;
760 goto done;
762 break;
764 case CHALLENGE_ALGORITHM:
765 if (strcmp (DEFAULT_ALGORITHM, value) != 0)
767 res = GSASL_MECHANISM_PARSE_ERROR;
768 goto done;
770 break;
772 case CHALLENGE_CIPHER:
774 char *subsubopts;
775 char *val;
777 if (state->cipher)
779 res = GSASL_MECHANISM_PARSE_ERROR;
780 goto done;
783 subsubopts = value;
784 while (*subsubopts != '\0')
785 switch (_gsasl_getsubopt (&subsubopts, cipher_opts, &val))
787 case CIPHER_DES_OPTION:
788 state->cipher |= GSASL_CIPHER_DES;
789 break;
791 case CIPHER_3DES_OPTION:
792 state->cipher |= GSASL_CIPHER_3DES;
793 break;
795 case CIPHER_RC4_OPTION:
796 state->cipher |= GSASL_CIPHER_RC4;
797 break;
799 case CIPHER_RC4_40_OPTION:
800 state->cipher |= GSASL_CIPHER_RC4_40;
801 break;
803 case CIPHER_RC4_56_OPTION:
804 state->cipher |= GSASL_CIPHER_RC4_56;
805 break;
807 case CIPHER_AES_OPTION:
808 state->cipher |= GSASL_CIPHER_AES;
809 break;
811 default:
812 /* Ignoring unknown cipher. */
813 break;
816 break;
818 default:
819 /* Ignoring unknown parameter. */
820 break;
822 if (state->qop == 0 || state->nonce == NULL ||
823 (state->qop & GSASL_QOP_AUTH_CONF &&
824 !(state->cipher & GSASL_CIPHER_3DES)))
826 res = GSASL_MECHANISM_PARSE_ERROR;
827 goto done;
829 if (cb_qop)
830 state->qop = cb_qop (cctx, state->qop);
831 else
832 state->qop = state->qop;
833 if (cb_authorization_id)
835 size_t authzidlen;
837 res = cb_authorization_id (cctx, NULL, &authzidlen);
838 if (res != GSASL_OK)
839 goto done;
840 state->authzid = (char *) malloc (authzidlen + 1);
841 if (state->authzid == NULL)
843 res = GSASL_MALLOC_ERROR;
844 goto done;
846 res = cb_authorization_id (cctx, state->authzid, &authzidlen);
847 if (res != GSASL_OK)
848 goto done;
849 state->authzid[authzidlen] = '\0';
851 /* username */
853 int usernamelen;
855 res = cb_authentication_id (cctx, NULL, &usernamelen);
856 if (res != GSASL_OK)
857 goto done;
859 if (outlen +
860 strlen (USERNAME_PRE) +
861 usernamelen + strlen (USERNAME_POST) >= *output_len)
863 res = GSASL_TOO_SMALL_BUFFER;
864 goto done;
867 strcat (output, USERNAME_PRE);
868 outlen += strlen (USERNAME_PRE);
870 res = cb_authentication_id (cctx, &output[outlen], &usernamelen);
871 if (res != GSASL_OK)
872 goto done;
873 outlen += usernamelen;
875 strcat (output, USERNAME_POST);
876 outlen += strlen (USERNAME_POST);
878 /* realm */
879 if (nrealm > 0)
881 if (outlen +
882 strlen (REALM_PRE) +
883 strlen (realm[0]) + strlen (REALM_POST) >= *output_len)
885 res = GSASL_TOO_SMALL_BUFFER;
886 goto done;
889 strcat (output, REALM_PRE);
890 outlen += strlen (REALM_PRE);
892 strcat (output, realm[0]);
893 outlen += strlen (realm[0]);
895 strcat (output, REALM_POST);
896 outlen += strlen (REALM_POST);
898 /* nonce */
900 if (outlen +
901 strlen (NONCE_PRE) +
902 strlen (state->nonce) + strlen (NONCE_POST) >= *output_len)
904 res = GSASL_TOO_SMALL_BUFFER;
905 goto done;
908 strcat (output, NONCE_PRE);
909 outlen += strlen (NONCE_PRE);
911 strcat (output, state->nonce);
912 outlen += strlen (state->nonce);
914 strcat (output, NONCE_POST);
915 outlen += strlen (NONCE_POST);
917 /* cnonce */
919 if (outlen +
920 strlen (CNONCE_PRE) +
921 strlen (state->cnonce) + strlen (CNONCE_POST) >= *output_len)
923 res = GSASL_TOO_SMALL_BUFFER;
924 goto done;
927 strcat (output, CNONCE_PRE);
928 outlen += strlen (CNONCE_PRE);
930 strcat (output, state->cnonce);
931 outlen += strlen (state->cnonce);
933 strcat (output, CNONCE_POST);
934 outlen += strlen (CNONCE_POST);
936 /* nonce-count */
938 if (outlen +
939 strlen (NONCE_COUNT_PRE) +
940 NCLEN + strlen (NONCE_COUNT_POST) >= *output_len)
942 res = GSASL_TOO_SMALL_BUFFER;
943 goto done;
946 strcat (output, NONCE_COUNT_PRE);
947 outlen += strlen (NONCE_COUNT_PRE);
949 sprintf (output + outlen, "%0*x", NCLEN, state->nc);
950 outlen += NCLEN;
952 strcat (output, NONCE_COUNT_POST);
953 outlen += strlen (NONCE_COUNT_POST);
955 /* qop */
957 char *qopstr;
959 if (state->qop & GSASL_QOP_AUTH_CONF)
960 qopstr = QOP_AUTH_CONF;
961 else if (state->qop & GSASL_QOP_AUTH_INT)
962 qopstr = QOP_AUTH_INT;
963 else if (state->qop & GSASL_QOP_AUTH)
964 qopstr = QOP_AUTH;
966 if (outlen +
967 strlen (QOP_PRE) +
968 strlen (qopstr) + strlen (QOP_POST) >= *output_len)
970 res = GSASL_TOO_SMALL_BUFFER;
971 goto done;
974 strcat (output, QOP_PRE);
975 outlen += strlen (QOP_PRE);
977 strcat (output, qopstr);
978 outlen += strlen (qopstr);
980 strcat (output, QOP_POST);
981 outlen += strlen (QOP_POST);
983 /* digest-uri */
985 size_t servicelen = 0;
986 size_t hostnamelen = 0;
987 size_t servicenamelen = 0;
988 size_t len;
990 res = cb_service (cctx, NULL, &servicelen,
991 NULL, &hostnamelen, NULL, &servicenamelen);
992 if (res != GSASL_OK)
993 goto done;
994 len = servicelen + strlen ("/") + hostnamelen +
995 (servicenamelen > 0 ? strlen ("/") + servicenamelen : 0) + 1;
996 state->digesturi = malloc (len);
997 if (state->digesturi == NULL)
999 res = GSASL_MALLOC_ERROR;
1000 goto done;
1002 res = cb_service (cctx, state->digesturi, &servicelen,
1003 state->digesturi + 1 + servicelen, &hostnamelen,
1004 (servicenamelen > 0 ?
1005 state->digesturi + 1 + servicelen + 1 +
1006 hostnamelen : NULL), &servicenamelen);
1007 if (res != GSASL_OK)
1008 goto done;
1009 state->digesturi[servicelen] = '/';
1010 state->digesturi[servicelen + 1 + hostnamelen] = '/';
1011 state->digesturi[len - 1] = '\0';
1013 if (outlen +
1014 strlen (DIGEST_URI_PRE) +
1015 len + strlen (DIGEST_URI_POST) >= *output_len)
1017 res = GSASL_TOO_SMALL_BUFFER;
1018 goto done;
1021 strcat (output, DIGEST_URI_PRE);
1022 outlen += strlen (DIGEST_URI_PRE);
1024 strcat (output, state->digesturi);
1025 outlen += strlen (state->digesturi);
1027 strcat (output, DIGEST_URI_POST);
1028 outlen += strlen (DIGEST_URI_POST);
1030 /* response */
1032 GCRY_MD_HD md5h;
1033 unsigned char *tmp;
1034 size_t len;
1036 if (outlen +
1037 strlen (RESPONSE_PRE) +
1038 RESPONSE_LENGTH + strlen (RESPONSE_POST) >= *output_len)
1040 res = GSASL_TOO_SMALL_BUFFER;
1041 goto done;
1044 strcat (output, RESPONSE_PRE);
1045 outlen += strlen (RESPONSE_PRE);
1047 md5h = gcry_md_open (GCRY_MD_MD5, 0);
1048 if (md5h == NULL)
1050 res = GSASL_GCRYPT_ERROR;
1051 goto done;
1053 len = *output_len - outlen;
1054 res = cb_authentication_id (cctx, output + outlen, &len);
1055 if (res != GSASL_OK)
1056 goto done;
1058 gcry_md_write (md5h, output + outlen, len);
1059 gcry_md_write (md5h, COLON, strlen (COLON));
1060 if (nrealm > 0)
1061 gcry_md_write (md5h, realm[0], strlen (realm[0]));
1062 gcry_md_write (md5h, COLON, strlen (COLON));
1064 len = *output_len - outlen;
1065 /* XXX? password stored in callee's output buffer */
1066 res = cb_password (cctx, output + outlen, &len);
1067 if (res != GSASL_OK)
1068 goto done;
1069 tmp = stringprep_utf8_nfkc_normalize (output + outlen, len);
1070 if (tmp == NULL)
1072 res = GSASL_UNICODE_NORMALIZATION_ERROR;
1073 goto done;
1075 gcry_md_write (md5h, tmp, strlen (tmp));
1076 free (tmp);
1077 if (res != GCRYERR_SUCCESS)
1079 res = GSASL_GCRYPT_ERROR;
1080 goto done;
1083 tmp = gcry_md_read (md5h, GCRY_MD_MD5);
1084 if (tmp == NULL)
1086 res = GSASL_GCRYPT_ERROR;
1087 goto done;
1089 memcpy (state->secret, tmp, MD5LEN);
1090 gcry_md_close (md5h);
1092 res = _gsasl_digest (state->response, state->secret,
1093 state->nonce, state->nc, state->cnonce,
1094 state->qop, state->authzid,
1095 state->digesturi, A2_PRE,
1096 state->cipher,
1097 state->kic, state->kis,
1098 state->kcc, state->kcs);
1099 if (res != GSASL_OK)
1100 goto done;
1101 state->response[RESPONSE_LENGTH] = '\0';
1102 memcpy (output + outlen, state->response, RESPONSE_LENGTH + 1);
1103 outlen += RESPONSE_LENGTH;
1105 strcat (output, RESPONSE_POST);
1106 outlen += strlen (RESPONSE_POST);
1108 if (cb_maxbuf
1109 && (maxbuf = cb_maxbuf (cctx, maxbuf)) != MAXBUF_DEFAULT)
1111 if (outlen + strlen (MAXBUF_PRE) +
1112 /* XXX don't require -lm, how? */
1113 1 + floor (log10 (INT_MAX)) +
1114 strlen (MAXBUF_POST) >= *output_len)
1116 res = GSASL_TOO_SMALL_BUFFER;
1117 goto done;
1120 strcat (output, MAXBUF_PRE);
1121 outlen += strlen (MAXBUF_PRE);
1123 sprintf (&output[outlen], "%d", maxbuf);
1124 outlen += strlen (&output[outlen]);
1126 strcat (output, MAXBUF_POST);
1127 outlen += strlen (MAXBUF_POST);
1129 /* cipher */
1130 if (state->qop & GSASL_QOP_AUTH_CONF)
1132 char *cipherstr;
1134 if (state->cipher & GSASL_CIPHER_AES)
1135 cipherstr = CIPHER_AES;
1136 else if (state->cipher & GSASL_CIPHER_3DES)
1137 cipherstr = CIPHER_3DES;
1138 else if (state->cipher & GSASL_CIPHER_DES)
1139 cipherstr = CIPHER_DES;
1140 else if (state->cipher & GSASL_CIPHER_RC4)
1141 cipherstr = CIPHER_RC4;
1142 else if (state->cipher & GSASL_CIPHER_RC4_56)
1143 cipherstr = CIPHER_RC4_56;
1144 else if (state->cipher & GSASL_CIPHER_RC4_40)
1145 cipherstr = CIPHER_RC4_40;
1147 if (outlen +
1148 strlen (CIPHER_PRE) +
1149 strlen (cipherstr) + strlen (CIPHER_POST) >= *output_len)
1151 res = GSASL_TOO_SMALL_BUFFER;
1152 goto done;
1155 strcat (output, CIPHER_PRE);
1156 outlen += strlen (CIPHER_PRE);
1158 strcat (output, cipherstr);
1159 outlen += strlen (cipherstr);
1161 strcat (output, CIPHER_POST);
1162 outlen += strlen (CIPHER_POST);
1164 /* authzid */
1165 if (state->authzid && strlen (state->authzid) > 0)
1167 if (outlen +
1168 strlen (AUTHZID_PRE) +
1169 strlen (state->authzid) +
1170 strlen (AUTHZID_POST) >= *output_len)
1172 res = GSASL_TOO_SMALL_BUFFER;
1173 goto done;
1176 strcat (output, AUTHZID_PRE);
1177 outlen += strlen (AUTHZID_PRE);
1179 strcat (output, state->authzid);
1180 outlen += strlen (state->authzid);
1182 strcat (output, AUTHZID_POST);
1183 outlen += strlen (AUTHZID_POST);
1186 res = GSASL_NEEDS_MORE;
1187 done:
1188 if (realm)
1189 free (realm);
1190 if (zinput)
1191 free (zinput);
1193 *output_len = outlen;
1194 state->step++;
1195 break;
1197 case 2:
1199 char *zinput = NULL;
1201 if (input_len == 0)
1203 *output_len = 0;
1204 res = GSASL_MECHANISM_PARSE_ERROR;
1205 break;
1208 if (input && input_len > 0)
1210 zinput = malloc (input_len + 1);
1211 if (zinput == NULL)
1212 return GSASL_MALLOC_ERROR;
1213 memcpy (zinput, input, input_len);
1214 zinput[input_len] = '\0';
1217 res = GSASL_AUTHENTICATION_ERROR;
1218 subopts = zinput;
1219 while (*subopts != '\0')
1220 switch (_gsasl_getsubopt (&subopts,
1221 digest_responseauth_opts, &value))
1223 case RESPONSEAUTH_RSPAUTH:
1224 res = _gsasl_digest (output + outlen, state->secret,
1225 state->nonce, state->nc,
1226 state->cnonce, state->qop,
1227 state->authzid, state->digesturi, COLON,
1228 state->cipher, NULL, NULL, NULL, NULL);
1229 if (res != GSASL_OK)
1230 break;
1232 if (memcmp (value, output + outlen, RESPONSE_LENGTH) == 0)
1233 res = GSASL_OK;
1234 else
1235 res = GSASL_AUTHENTICATION_ERROR;
1236 break;
1238 default:
1239 /* Unknown suboption. */
1240 break;
1242 free (zinput);
1244 *output_len = 0;
1245 state->step++;
1246 break;
1248 default:
1249 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
1250 break;
1253 #if CLIENT_PRINT_OUTPUT
1254 if (output && *output_len > 0)
1255 fprintf (stderr, "%s\n", output);
1256 #endif
1258 return res;
1262 _gsasl_digest_md5_client_finish (Gsasl_session_ctx * cctx, void *mech_data)
1264 _Gsasl_digest_md5_client_state *state = mech_data;
1266 if (state->authzid)
1267 free (state->authzid);
1268 if (state->nonce)
1269 free (state->nonce);
1270 if (state->digesturi)
1271 free (state->digesturi);
1272 free (state);
1274 return GSASL_OK;
1278 _gsasl_digest_md5_client_encode (Gsasl_session_ctx * xctx,
1279 void *mech_data,
1280 const char *input,
1281 size_t input_len,
1282 char *output, size_t * output_len)
1284 _Gsasl_digest_md5_client_state *state = mech_data;
1285 int res;
1287 if (state == NULL || state->step != 3)
1289 *output_len = input_len;
1290 if (output)
1291 memcpy (output, input, input_len);
1292 return GSASL_OK;
1295 if (state->qop & GSASL_QOP_AUTH_CONF)
1299 else if (state->qop & GSASL_QOP_AUTH_INT)
1301 GCRY_MD_HD md5h;
1302 char *hash;
1303 uint32_t tmp;
1305 if (MAC_DATA_LEN + input_len + MAC_HMAC_LEN +
1306 MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN > *output_len)
1307 return GSASL_TOO_SMALL_BUFFER;
1309 md5h = gcry_md_open (GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
1310 if (md5h == NULL)
1311 return GSASL_GCRYPT_ERROR;
1313 res = gcry_md_setkey (md5h, state->kic, MD5LEN);
1314 if (res != GCRYERR_SUCCESS)
1315 return GSASL_GCRYPT_ERROR;
1317 tmp = htonl (state->sendseqnum);
1318 gcry_md_write (md5h, (unsigned char*) &tmp, MAC_SEQNUM_LEN);
1319 gcry_md_write (md5h, input, input_len);
1321 hash = gcry_md_read (md5h, GCRY_MD_MD5);
1322 if (hash == NULL)
1323 return GSASL_GCRYPT_ERROR;
1325 if (output)
1327 *output_len = MAC_DATA_LEN;
1328 memcpy (output + *output_len, input, input_len);
1329 *output_len += input_len;
1330 memcpy (output + *output_len, hash, MAC_HMAC_LEN);
1331 *output_len += MAC_HMAC_LEN;
1332 memcpy (output + *output_len, MAC_MSG_TYPE, MAC_MSG_TYPE_LEN);
1333 *output_len += MAC_MSG_TYPE_LEN;
1334 tmp = htonl (state->sendseqnum);
1335 memcpy (output + *output_len, &tmp, MAC_SEQNUM_LEN);
1336 *output_len += MAC_SEQNUM_LEN;
1337 tmp = htonl (*output_len - MAC_DATA_LEN);
1338 memcpy (output, &tmp, MAC_DATA_LEN);
1339 state->sendseqnum++;
1341 else
1342 *output_len = MAC_DATA_LEN + input_len + MAC_HMAC_LEN
1343 + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
1345 gcry_md_close (md5h);
1348 return GSASL_OK;
1352 _gsasl_digest_md5_client_decode (Gsasl_session_ctx * xctx,
1353 void *mech_data,
1354 const char *input,
1355 size_t input_len,
1356 char *output, size_t * output_len)
1358 _Gsasl_digest_md5_client_state *state = mech_data;
1360 if (state == NULL || state->step != 3)
1362 *output_len = input_len;
1363 if (output)
1364 memcpy (output, input, input_len);
1365 return GSASL_OK;
1368 if (state->qop & GSASL_QOP_AUTH_CONF)
1372 else if (state->qop & GSASL_QOP_AUTH_INT)
1374 GCRY_MD_HD md5h;
1375 char *hash;
1376 uint32_t len, tmp;
1377 int res;
1379 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH)
1380 return GSASL_NEEDS_MORE;
1382 len = ntohl (*(uint32_t *) input);
1384 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH + len)
1385 return GSASL_NEEDS_MORE;
1387 len -= MAC_HMAC_LEN + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
1389 md5h = gcry_md_open (GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
1390 if (md5h == NULL)
1391 return GSASL_GCRYPT_ERROR;
1393 res = gcry_md_setkey (md5h, state->kis, MD5LEN);
1394 if (res != GCRYERR_SUCCESS)
1395 return GSASL_GCRYPT_ERROR;
1397 tmp = htonl (state->readseqnum);
1399 gcry_md_write (md5h, (unsigned char*)&tmp, SASL_INTEGRITY_PREFIX_LENGTH);
1400 gcry_md_write (md5h, input + MAC_DATA_LEN, len);
1402 hash = gcry_md_read (md5h, GCRY_MD_MD5);
1403 if (hash == NULL)
1404 return GSASL_GCRYPT_ERROR;
1406 if (memcmp
1407 (hash,
1408 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN -
1409 MAC_HMAC_LEN, MAC_HMAC_LEN) == 0
1410 && memcmp (MAC_MSG_TYPE,
1411 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN,
1412 MAC_MSG_TYPE_LEN) == 0
1413 && memcmp (&tmp, input + input_len - MAC_SEQNUM_LEN,
1414 MAC_SEQNUM_LEN) == 0)
1416 *output_len = len;
1417 if (output)
1419 memcpy (output, input + MAC_DATA_LEN, len);
1420 state->readseqnum++;
1423 else
1424 return GSASL_INTEGRITY_ERROR;
1426 gcry_md_close (md5h);
1429 return GSASL_OK;
1432 /* Server */
1434 struct _Gsasl_digest_md5_server_state
1436 int step;
1437 char nonce[NONCE_ENTROPY_BITS / 8];
1438 Gsasl_qop qop;
1439 Gsasl_cipher cipher;
1440 uint32_t readseqnum, sendseqnum;
1441 unsigned char kic[MD5LEN];
1442 unsigned char kcc[MD5LEN];
1443 unsigned char kis[MD5LEN];
1444 unsigned char kcs[MD5LEN];
1446 typedef struct _Gsasl_digest_md5_server_state _Gsasl_digest_md5_server_state;
1449 _gsasl_digest_md5_server_init (Gsasl_ctx * ctx)
1451 if (gcry_check_version (GCRYPT_VERSION) == NULL)
1452 return GSASL_GCRYPT_ERROR;
1454 return GSASL_OK;
1457 void
1458 _gsasl_digest_md5_server_done (Gsasl_ctx * ctx)
1460 return;
1464 _gsasl_digest_md5_server_start (Gsasl_session_ctx * sctx, void **mech_data)
1466 _Gsasl_digest_md5_server_state *state;
1467 Gsasl_server_callback_retrieve cb_retrieve;
1468 Gsasl_server_callback_digest_md5 cb_digest_md5;
1469 Gsasl_ctx *ctx;
1471 ctx = gsasl_server_ctx_get (sctx);
1472 if (ctx == NULL)
1473 return GSASL_CANNOT_GET_CTX;
1475 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
1476 cb_digest_md5 = gsasl_server_callback_digest_md5_get (ctx);
1478 if (gsasl_server_callback_digest_md5_get (ctx) == NULL &&
1479 gsasl_server_callback_retrieve_get (ctx) == NULL)
1480 return GSASL_NEED_SERVER_DIGEST_MD5_CALLBACK;
1482 state = (_Gsasl_digest_md5_server_state *) malloc (sizeof (*state));
1483 if (state == NULL)
1484 return GSASL_MALLOC_ERROR;
1486 state->step = 0;
1487 state->qop = GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF;
1488 state->cipher = GSASL_CIPHER_DES | GSASL_CIPHER_3DES | GSASL_CIPHER_RC4 |
1489 GSASL_CIPHER_RC4_40 | GSASL_CIPHER_RC4_56 | GSASL_CIPHER_AES;
1490 gcry_randomize (state->nonce, NONCE_ENTROPY_BITS / 8, GCRY_WEAK_RANDOM);
1491 state->readseqnum = 0;
1492 state->sendseqnum = 0;
1494 *mech_data = state;
1496 return GSASL_OK;
1500 _gsasl_digest_md5_server_step (Gsasl_session_ctx * sctx,
1501 void *mech_data,
1502 const char *input,
1503 size_t input_len,
1504 char *output, size_t * output_len)
1506 _Gsasl_digest_md5_server_state *state = mech_data;
1507 Gsasl_server_callback_realm cb_realm;
1508 Gsasl_server_callback_qop cb_qop;
1509 Gsasl_server_callback_maxbuf cb_maxbuf;
1510 Gsasl_server_callback_cipher cb_cipher;
1511 Gsasl_server_callback_retrieve cb_retrieve;
1512 Gsasl_server_callback_digest_md5 cb_digest_md5;
1513 Gsasl_ctx *ctx;
1514 int res;
1515 int outlen;
1516 int maxbuf;
1518 ctx = gsasl_server_ctx_get (sctx);
1519 if (ctx == NULL)
1520 return GSASL_CANNOT_GET_CTX;
1522 cb_realm = gsasl_server_callback_realm_get (ctx);
1523 cb_qop = gsasl_server_callback_qop_get (ctx);
1524 cb_maxbuf = gsasl_server_callback_maxbuf_get (ctx);
1525 cb_cipher = gsasl_server_callback_cipher_get (ctx);
1526 cb_retrieve = gsasl_server_callback_retrieve_get (ctx);
1527 cb_digest_md5 = gsasl_server_callback_digest_md5_get (ctx);
1529 if (gsasl_server_callback_digest_md5_get (ctx) == NULL &&
1530 gsasl_server_callback_retrieve_get (ctx) == NULL)
1531 return GSASL_NEED_SERVER_DIGEST_MD5_CALLBACK;
1533 if (*output_len < 1)
1534 return GSASL_TOO_SMALL_BUFFER;
1536 strcpy (output, "");
1537 outlen = 0;
1539 #if SERVER_PRINT_OUTPUT
1540 if (input && input_len > 0)
1541 fprintf (stderr, "%s\n", input);
1542 #endif
1544 switch (state->step)
1546 case 0:
1547 if (cb_realm)
1549 int i;
1550 size_t realmlen;
1552 realmlen = *output_len;
1553 for (i = 0; cb_realm (sctx, NULL, &realmlen, i) == GSASL_OK; i++)
1555 if (outlen + strlen (REALM_PRE) +
1556 realmlen + strlen (REALM_POST) >= *output_len)
1557 return GSASL_TOO_SMALL_BUFFER;
1559 strcat (output, REALM_PRE);
1560 outlen += strlen (REALM_PRE);
1562 cb_realm (sctx, &output[outlen], &realmlen, i);
1563 outlen += realmlen;
1564 output[outlen] = '\0';
1566 strcat (output, REALM_POST);
1567 outlen += strlen (REALM_POST);
1569 realmlen = *output_len - outlen;
1572 /* nonce */
1574 int i;
1576 if (outlen + strlen (NONCE_PRE) +
1577 2 * NONCE_ENTROPY_BITS / 8 + strlen (NONCE_POST) >= *output_len)
1578 return GSASL_TOO_SMALL_BUFFER;
1580 strcat (output, NONCE_PRE);
1581 outlen += strlen (NONCE_PRE);
1583 for (i = 0; i < NONCE_ENTROPY_BITS / 8; i++)
1585 output[outlen + 2 * i + 1] = HEXCHAR (state->nonce[i]);
1586 output[outlen + 2 * i + 0] = HEXCHAR (state->nonce[i] >> 4);
1588 output[outlen + 2 * NONCE_ENTROPY_BITS / 8] = '\0';
1589 outlen += 2 * NONCE_ENTROPY_BITS / 8;
1591 strcat (output, NONCE_POST);
1592 outlen += strlen (NONCE_POST);
1594 /* qop */
1596 if (outlen +
1597 strlen (QOP_LIST_PRE) +
1598 strlen (QOP_AUTH) +
1599 strlen (QOP_AUTH_INT) +
1600 strlen (QOP_AUTH_CONF) + strlen (QOP_LIST_POST) >= *output_len)
1601 return GSASL_TOO_SMALL_BUFFER;
1603 if (cb_qop)
1604 state->qop = cb_qop (sctx);
1606 if (state->qop &
1607 (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
1609 strcat (output, QOP_LIST_PRE);
1610 outlen += strlen (QOP_LIST_PRE);
1613 if (state->qop & GSASL_QOP_AUTH)
1615 strcat (output, QOP_AUTH);
1616 outlen += strlen (QOP_AUTH);
1618 strcat (output, QOP_DELIM);
1619 outlen += strlen (QOP_DELIM);
1622 if (state->qop & GSASL_QOP_AUTH_INT)
1624 strcat (output, QOP_AUTH_INT);
1625 outlen += strlen (QOP_AUTH_INT);
1627 strcat (output, QOP_DELIM);
1628 outlen += strlen (QOP_DELIM);
1631 if (state->qop & GSASL_QOP_AUTH_CONF)
1633 strcat (output, QOP_AUTH_CONF);
1634 outlen += strlen (QOP_AUTH_CONF);
1637 if (state->qop &
1638 (GSASL_QOP_AUTH | GSASL_QOP_AUTH_INT | GSASL_QOP_AUTH_CONF))
1640 strcat (output, QOP_LIST_POST);
1641 outlen += strlen (QOP_LIST_POST);
1644 /* maxbuf */
1645 if (cb_maxbuf && (maxbuf = cb_maxbuf (sctx)) != MAXBUF_DEFAULT)
1647 if (outlen + strlen (MAXBUF_PRE) +
1648 /* XXX don't require -lm, how? */
1649 1 + floor (log10 (INT_MAX)) +
1650 strlen (MAXBUF_POST) >= *output_len)
1651 return GSASL_TOO_SMALL_BUFFER;
1653 strcat (output, MAXBUF_PRE);
1654 outlen += strlen (MAXBUF_PRE);
1656 sprintf (&output[outlen], "%d", maxbuf);
1657 outlen += strlen (&output[outlen]);
1659 strcat (output, MAXBUF_POST);
1660 outlen += strlen (MAXBUF_POST);
1662 /* charset */
1664 if (outlen + strlen (CHARSET) >= *output_len)
1665 return GSASL_TOO_SMALL_BUFFER;
1667 strcat (output, CHARSET);
1668 outlen += strlen (CHARSET);
1670 /* algorithm */
1672 if (outlen + strlen (ALGORITHM) >= *output_len)
1673 return GSASL_TOO_SMALL_BUFFER;
1675 strcat (output, ALGORITHM);
1676 outlen += strlen (ALGORITHM);
1678 /* cipher */
1680 if (outlen +
1681 strlen (CIPHER_PRE) +
1682 strlen (CIPHER_DES) +
1683 strlen (CIPHER_DELIM) +
1684 strlen (CIPHER_3DES) +
1685 strlen (CIPHER_DELIM) +
1686 strlen (CIPHER_RC4) +
1687 strlen (CIPHER_DELIM) +
1688 strlen (CIPHER_RC4_40) +
1689 strlen (CIPHER_DELIM) +
1690 strlen (CIPHER_RC4_56) +
1691 strlen (CIPHER_DELIM) +
1692 strlen (CIPHER_AES) +
1693 strlen (CIPHER_DELIM) + strlen (CIPHER_POST) >= *output_len)
1694 return GSASL_TOO_SMALL_BUFFER;
1696 if (cb_cipher)
1697 state->cipher = cb_cipher (sctx);
1699 strcat (output, CIPHER_PRE);
1700 outlen += strlen (CIPHER_PRE);
1702 if (state->cipher & GSASL_CIPHER_DES)
1704 strcat (output, CIPHER_DES);
1705 outlen += strlen (CIPHER_DES);
1707 strcat (output, CIPHER_DELIM);
1708 outlen += strlen (CIPHER_DELIM);
1711 if (state->cipher & GSASL_CIPHER_3DES)
1713 strcat (output, CIPHER_3DES);
1714 outlen += strlen (CIPHER_3DES);
1716 strcat (output, CIPHER_DELIM);
1717 outlen += strlen (CIPHER_DELIM);
1720 if (state->cipher & GSASL_CIPHER_RC4)
1722 strcat (output, CIPHER_RC4);
1723 outlen += strlen (CIPHER_RC4);
1725 strcat (output, CIPHER_DELIM);
1726 outlen += strlen (CIPHER_DELIM);
1729 if (state->cipher & GSASL_CIPHER_RC4_40)
1731 strcat (output, CIPHER_RC4_40);
1732 outlen += strlen (CIPHER_RC4_40);
1734 strcat (output, CIPHER_DELIM);
1735 outlen += strlen (CIPHER_DELIM);
1738 if (state->cipher & GSASL_CIPHER_RC4_56)
1740 strcat (output, CIPHER_RC4_56);
1741 outlen += strlen (CIPHER_RC4_56);
1743 strcat (output, CIPHER_DELIM);
1744 outlen += strlen (CIPHER_DELIM);
1747 if (state->cipher & GSASL_CIPHER_AES)
1749 strcat (output, CIPHER_AES);
1750 outlen += strlen (CIPHER_AES);
1752 strcat (output, CIPHER_DELIM);
1753 outlen += strlen (CIPHER_DELIM);
1756 strcat (output, CIPHER_POST);
1757 outlen += strlen (CIPHER_POST);
1759 *output_len = outlen;
1760 state->step++;
1761 res = GSASL_NEEDS_MORE;
1762 break;
1764 case 1:
1766 unsigned char *nonce = NULL;
1767 char *cnonce = NULL;
1768 uint32_t nc = 0;
1769 char *authzid = NULL;
1770 char *digesturi = NULL;
1771 const char *subopts, *value;
1772 unsigned char *realm = NULL;
1773 unsigned char *username = NULL;
1774 unsigned char *response = NULL;
1775 char *zinput = NULL;
1776 Gsasl_qop qop = 0;
1777 int maxbuf = MAXBUF_DEFAULT;
1778 int cipher = 0;
1779 int i;
1780 GCRY_MD_HD md5h = NULL;
1781 unsigned char secret[MD5LEN];
1783 if (input_len == 0)
1784 return GSASL_MECHANISM_PARSE_ERROR;
1786 if (input && input_len > 0)
1788 zinput = malloc (input_len + 1);
1789 if (zinput == NULL)
1790 return GSASL_MALLOC_ERROR;
1791 memcpy (zinput, input, input_len);
1792 zinput[input_len] = '\0';
1795 subopts = zinput;
1796 while (*subopts != '\0')
1797 switch (_gsasl_getsubopt (&subopts, digest_response_opts, &value))
1799 case RESPONSE_USERNAME:
1800 if (username != NULL)
1802 res = GSASL_MECHANISM_PARSE_ERROR;
1803 goto done;
1805 username = strdup (value);
1806 break;
1808 case RESPONSE_REALM:
1809 if (realm != NULL)
1811 res = GSASL_MECHANISM_PARSE_ERROR;
1812 goto done;
1814 realm = strdup (value);
1815 break;
1817 case RESPONSE_NONCE:
1818 if (nonce != NULL)
1820 res = GSASL_MECHANISM_PARSE_ERROR;
1821 goto done;
1823 nonce = strdup (value);
1824 res = GSASL_OK;
1825 for (i = 0; i < MIN (strlen (nonce), NONCE_ENTROPY_BITS / 8);
1826 i++)
1827 if ((nonce[2 * i + 1] != HEXCHAR (state->nonce[i]))
1828 || (nonce[2 * i + 0] != HEXCHAR (state->nonce[i] >> 4)))
1829 res = GSASL_MECHANISM_PARSE_ERROR;
1830 if (res != GSASL_OK)
1831 goto done;
1832 break;
1834 case RESPONSE_CNONCE:
1835 if (cnonce != NULL)
1837 res = GSASL_MECHANISM_PARSE_ERROR;
1838 goto done;
1840 cnonce = strdup (value);
1841 break;
1843 case RESPONSE_NC:
1844 if (nc != 0)
1846 res = GSASL_MECHANISM_PARSE_ERROR;
1847 goto done;
1849 nc = strtoul (value, NULL, 16);
1850 break;
1852 case RESPONSE_QOP:
1853 if (strcmp (value, QOP_AUTH) == 0)
1854 qop = GSASL_QOP_AUTH;
1855 else if (strcmp (value, QOP_AUTH_INT) == 0)
1856 qop = GSASL_QOP_AUTH_INT;
1857 else if (strcmp (value, QOP_AUTH_CONF) == 0)
1858 qop = GSASL_QOP_AUTH_CONF;
1859 else
1861 res = GSASL_MECHANISM_PARSE_ERROR;
1862 goto done;
1864 if (!(state->qop & qop))
1866 res = GSASL_MECHANISM_PARSE_ERROR;
1867 goto done;
1869 state->qop = qop;
1870 break;
1872 case RESPONSE_DIGEST_URI:
1873 if (digesturi != NULL)
1875 res = GSASL_MECHANISM_PARSE_ERROR;
1876 goto done;
1878 digesturi = strdup (value);
1879 break;
1881 case RESPONSE_RESPONSE:
1882 if (response != NULL)
1884 res = GSASL_MECHANISM_PARSE_ERROR;
1885 goto done;
1887 response = strdup (value);
1888 break;
1890 case RESPONSE_MAXBUF:
1891 maxbuf = strtol (value, NULL, 10);
1892 break;
1894 case RESPONSE_CHARSET:
1895 if (strcmp (DEFAULT_CHARSET, value) != 0)
1897 res = GSASL_MECHANISM_PARSE_ERROR;
1898 goto done;
1900 break;
1902 case RESPONSE_CIPHER:
1903 if (cipher != 0)
1905 res = GSASL_MECHANISM_PARSE_ERROR;
1906 goto done;
1908 if (strcmp (value, CIPHER_AES) == 0)
1909 cipher = GSASL_CIPHER_AES;
1910 else if (strcmp (value, CIPHER_3DES) == 0)
1911 cipher = GSASL_CIPHER_3DES;
1912 else if (strcmp (value, CIPHER_DES) == 0)
1913 cipher = GSASL_CIPHER_DES;
1914 else if (strcmp (value, CIPHER_RC4) == 0)
1915 cipher = GSASL_CIPHER_RC4;
1916 else if (strcmp (value, CIPHER_RC4_40) == 0)
1917 cipher = GSASL_CIPHER_RC4_40;
1918 else if (strcmp (value, CIPHER_RC4_56) == 0)
1919 cipher = GSASL_CIPHER_RC4_56;
1920 else
1922 res = GSASL_MECHANISM_PARSE_ERROR;
1923 goto done;
1925 if (!(state->cipher & cipher))
1927 res = GSASL_MECHANISM_PARSE_ERROR;
1928 goto done;
1930 state->cipher = cipher;
1931 break;
1933 case RESPONSE_AUTHZID:
1934 if (authzid != NULL)
1936 res = GSASL_MECHANISM_PARSE_ERROR;
1937 goto done;
1939 authzid = strdup (value);
1940 break;
1942 default:
1943 /* Ignoring unknown parameter. */
1944 break;
1947 if (username == NULL || nonce == NULL ||
1948 cnonce == NULL || response == NULL ||
1949 (state->qop & GSASL_QOP_AUTH_CONF && state->cipher == 0))
1951 res = GSASL_MECHANISM_PARSE_ERROR;
1952 goto done;
1955 if (outlen +
1956 strlen (RSPAUTH_PRE) +
1957 RESPONSE_LENGTH + strlen (RSPAUTH_POST) >= *output_len)
1959 res = GSASL_TOO_SMALL_BUFFER;
1960 goto done;
1962 if (cb_retrieve)
1964 unsigned char *tmp;
1965 size_t keylen;
1966 char *key;
1967 char *normkey;
1969 res = cb_retrieve (sctx, username, authzid, realm, NULL, &keylen);
1970 if (res != GSASL_OK)
1971 goto done;
1972 key = malloc (keylen);
1973 if (key == NULL)
1975 res = GSASL_MALLOC_ERROR;
1976 goto done;
1978 res = cb_retrieve (sctx, username, authzid, realm, key, &keylen);
1979 if (res != GSASL_OK)
1981 free (key);
1982 goto done;
1984 normkey = stringprep_utf8_nfkc_normalize (key, keylen);
1985 free (key);
1986 if (normkey == NULL)
1988 res = GSASL_UNICODE_NORMALIZATION_ERROR;
1989 goto done;
1992 md5h = gcry_md_open (GCRY_MD_MD5, 0);
1993 if (md5h == NULL)
1995 res = GSASL_GCRYPT_ERROR;
1996 goto done;
1998 gcry_md_write (md5h, username, strlen (username));
1999 gcry_md_write (md5h, COLON, strlen (COLON));
2000 if (realm)
2001 gcry_md_write (md5h, realm, strlen (realm));
2002 gcry_md_write (md5h, COLON, strlen (COLON));
2003 gcry_md_write (md5h, normkey, strlen (normkey));
2005 tmp = gcry_md_read (md5h, GCRY_MD_MD5);
2006 if (tmp == NULL)
2008 res = GSASL_GCRYPT_ERROR;
2009 goto done;
2011 memcpy (secret, tmp, MD5LEN);
2013 else /* if (cb_digest_md5) */
2015 /* XXX? secret hash stored in callee's output buffer */
2016 res = cb_digest_md5 (sctx, username, realm, output + outlen);
2017 if (res != GSASL_OK)
2018 goto done;
2020 memcpy (secret, output + outlen, MD5LEN);
2023 /* verify response */
2024 res = _gsasl_digest (output + outlen, secret,
2025 nonce, nc, cnonce, state->qop, authzid,
2026 digesturi, A2_PRE,
2027 state->cipher, NULL, NULL, NULL, NULL);
2028 if (res != GSASL_OK)
2029 goto done;
2031 if (memcmp (response, output + outlen, RESPONSE_LENGTH) != 0)
2033 res = GSASL_AUTHENTICATION_ERROR;
2034 goto done;
2037 output[outlen] = '\0';
2039 /* XXX check more things here. digest-uri?,
2040 nc etc. nonce, which is the most important, is checked
2041 above. */
2043 /* generate rspauth */
2045 strcat (output, RSPAUTH_PRE);
2046 outlen += strlen (RSPAUTH_PRE);
2048 res = _gsasl_digest (output + outlen, secret,
2049 nonce, nc, cnonce, state->qop, authzid,
2050 digesturi, COLON,
2051 state->cipher,
2052 state->kic, state->kis, state->kcc, state->kcs);
2053 if (res != GSASL_OK)
2054 goto done;
2055 outlen += RSPAUTH_LENGTH;
2057 strcat (output, RSPAUTH_POST);
2058 outlen += strlen (RSPAUTH_POST);
2060 if (md5h)
2061 gcry_md_close (md5h);
2063 res = GSASL_NEEDS_MORE;
2064 done:
2065 if (username)
2066 free (username);
2067 if (authzid)
2068 free (authzid);
2069 if (response)
2070 free (response);
2071 if (digesturi)
2072 free (digesturi);
2073 if (nonce)
2074 free (nonce);
2075 if (cnonce)
2076 free (cnonce);
2077 if (realm)
2078 free (realm);
2079 if (zinput)
2080 free (zinput);
2082 *output_len = outlen;
2083 state->step++;
2084 break;
2086 case 2:
2087 *output_len = 0;
2088 state->step++;
2089 res = GSASL_OK;
2090 break;
2092 default:
2093 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
2094 break;
2097 #if SERVER_PRINT_OUTPUT
2098 if (output && *output_len > 0)
2099 fprintf (stderr, "%s\n", output);
2100 #endif
2102 return res;
2106 _gsasl_digest_md5_server_finish (Gsasl_session_ctx * sctx, void *mech_data)
2108 _Gsasl_digest_md5_server_state *state = mech_data;
2110 free (state);
2112 return GSASL_OK;
2116 _gsasl_digest_md5_server_encode (Gsasl_session_ctx * xctx,
2117 void *mech_data,
2118 const char *input,
2119 size_t input_len,
2120 char *output, size_t * output_len)
2122 _Gsasl_digest_md5_server_state *state = mech_data;
2123 int res;
2125 if (state == NULL || state->step != 3)
2127 *output_len = input_len;
2128 if (output)
2129 memcpy (output, input, input_len);
2130 return GSASL_OK;
2133 if (state->qop & GSASL_QOP_AUTH_CONF)
2137 else if (state->qop & GSASL_QOP_AUTH_INT)
2139 GCRY_MD_HD md5h;
2140 char *hash;
2141 uint32_t tmp;
2143 if (MAC_DATA_LEN + input_len + MAC_HMAC_LEN +
2144 MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN > *output_len)
2145 return GSASL_TOO_SMALL_BUFFER;
2147 md5h = gcry_md_open (GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
2148 if (md5h == NULL)
2149 return GSASL_GCRYPT_ERROR;
2151 res = gcry_md_setkey (md5h, state->kis, MD5LEN);
2152 if (res != GCRYERR_SUCCESS)
2153 return GSASL_GCRYPT_ERROR;
2155 tmp = htonl (state->sendseqnum);
2156 gcry_md_write (md5h, (unsigned char*)&tmp, MAC_SEQNUM_LEN);
2157 gcry_md_write (md5h, input, input_len);
2159 hash = gcry_md_read (md5h, GCRY_MD_MD5);
2160 if (hash == NULL)
2161 return GSASL_GCRYPT_ERROR;
2163 if (output)
2165 *output_len = MAC_DATA_LEN;
2166 memcpy (output + *output_len, input, input_len);
2167 *output_len += input_len;
2168 memcpy (output + *output_len, hash, MAC_HMAC_LEN);
2169 *output_len += MAC_HMAC_LEN;
2170 memcpy (output + *output_len, MAC_MSG_TYPE, MAC_MSG_TYPE_LEN);
2171 *output_len += MAC_MSG_TYPE_LEN;
2172 tmp = htonl (state->sendseqnum);
2173 memcpy (output + *output_len, &tmp, MAC_SEQNUM_LEN);
2174 *output_len += MAC_SEQNUM_LEN;
2175 tmp = htonl (*output_len - MAC_DATA_LEN);
2176 memcpy (output, &tmp, MAC_DATA_LEN);
2177 state->sendseqnum++;
2179 else
2180 *output_len = MAC_DATA_LEN + input_len + MAC_HMAC_LEN
2181 + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
2183 gcry_md_close (md5h);
2186 return GSASL_OK;
2190 _gsasl_digest_md5_server_decode (Gsasl_session_ctx * xctx,
2191 void *mech_data,
2192 const char *input,
2193 size_t input_len,
2194 char *output, size_t * output_len)
2196 _Gsasl_digest_md5_server_state *state = mech_data;
2198 if (state == NULL || state->step != 3)
2200 *output_len = input_len;
2201 if (output)
2202 memcpy (output, input, input_len);
2203 return GSASL_OK;
2206 if (state->qop & GSASL_QOP_AUTH_CONF)
2210 else if (state->qop & GSASL_QOP_AUTH_INT)
2212 GCRY_MD_HD md5h;
2213 char *hash;
2214 uint32_t len, tmp;
2215 int res;
2217 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH)
2218 return GSASL_NEEDS_MORE;
2220 len = ntohl (*(uint32_t *) input);
2222 if (input_len < SASL_INTEGRITY_PREFIX_LENGTH + len)
2223 return GSASL_NEEDS_MORE;
2225 len -= MAC_HMAC_LEN + MAC_MSG_TYPE_LEN + MAC_SEQNUM_LEN;
2227 md5h = gcry_md_open (GCRY_MD_MD5, GCRY_MD_FLAG_HMAC);
2228 if (md5h == NULL)
2229 return GSASL_GCRYPT_ERROR;
2231 res = gcry_md_setkey (md5h, state->kic, MD5LEN);
2232 if (res != GCRYERR_SUCCESS)
2233 return GSASL_GCRYPT_ERROR;
2235 tmp = htonl (state->readseqnum);
2237 gcry_md_write (md5h, (unsigned char*)&tmp, SASL_INTEGRITY_PREFIX_LENGTH);
2238 gcry_md_write (md5h, input + MAC_DATA_LEN, len);
2240 hash = gcry_md_read (md5h, GCRY_MD_MD5);
2241 if (hash == NULL)
2242 return GSASL_GCRYPT_ERROR;
2244 if (memcmp
2245 (hash,
2246 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN -
2247 MAC_HMAC_LEN, MAC_HMAC_LEN) == 0
2248 && memcmp (MAC_MSG_TYPE,
2249 input + input_len - MAC_SEQNUM_LEN - MAC_MSG_TYPE_LEN,
2250 MAC_MSG_TYPE_LEN) == 0
2251 && memcmp (&tmp, input + input_len - MAC_SEQNUM_LEN,
2252 MAC_SEQNUM_LEN) == 0)
2254 *output_len = len;
2255 if (output)
2257 memcpy (output, input + MAC_DATA_LEN, len);
2258 state->readseqnum++;
2261 else
2262 return GSASL_INTEGRITY_ERROR;
2264 gcry_md_close (md5h);
2267 return GSASL_OK;
2270 #endif /* USE_DIGEST_MD5 */