00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include "config.h"
00025 #endif
00026
00027
00028 #include "digest-md5.h"
00029
00030
00031 #include <stdlib.h>
00032
00033
00034 #include <string.h>
00035
00036
00037 #include "nonascii.h"
00038 #include "tokens.h"
00039 #include "parser.h"
00040 #include "printer.h"
00041 #include "free.h"
00042 #include "session.h"
00043 #include "digesthmac.h"
00044 #include "validate.h"
00045 #include "qop.h"
00046
00047 #define NONCE_ENTROPY_BYTES 16
00048
00049 struct _Gsasl_digest_md5_server_state
00050 {
00051 int step;
00052 unsigned long readseqnum, sendseqnum;
00053 char secret[DIGEST_MD5_LENGTH];
00054 char kic[DIGEST_MD5_LENGTH];
00055 char kcc[DIGEST_MD5_LENGTH];
00056 char kis[DIGEST_MD5_LENGTH];
00057 char kcs[DIGEST_MD5_LENGTH];
00058 digest_md5_challenge challenge;
00059 digest_md5_response response;
00060 digest_md5_finish finish;
00061 };
00062 typedef struct _Gsasl_digest_md5_server_state _Gsasl_digest_md5_server_state;
00063
00064 int
00065 _gsasl_digest_md5_server_start (Gsasl_session * sctx, void **mech_data)
00066 {
00067 _Gsasl_digest_md5_server_state *state;
00068 char nonce[NONCE_ENTROPY_BYTES];
00069 char *p;
00070 int rc;
00071
00072 rc = gsasl_nonce (nonce, NONCE_ENTROPY_BYTES);
00073 if (rc != GSASL_OK)
00074 return rc;
00075
00076 rc = gsasl_base64_to (nonce, NONCE_ENTROPY_BYTES, &p, NULL);
00077 if (rc != GSASL_OK)
00078 return rc;
00079
00080 state = calloc (1, sizeof (*state));
00081 if (state == NULL)
00082 {
00083 free (p);
00084 return GSASL_MALLOC_ERROR;
00085 }
00086
00087 state->challenge.qops = DIGEST_MD5_QOP_AUTH;
00088 state->challenge.ciphers = 0;
00089
00090 state->challenge.nonce = p;
00091 state->challenge.utf8 = 1;
00092
00093 *mech_data = state;
00094
00095 return GSASL_OK;
00096 }
00097
00098 static char
00099 _gsasl_digest_md5_hexdigit_to_char (char hexdigit)
00100 {
00101
00102
00103
00104 if (hexdigit >= '0' && hexdigit <= '9')
00105 return hexdigit - '0';
00106 if (hexdigit >= 'a' && hexdigit <= 'z')
00107 return hexdigit - 'a' + 10;
00108
00109 return -1;
00110 }
00111
00112 static char
00113 _gsasl_digest_md5_hex_to_char (char u, char l)
00114 {
00115 return (char) (((unsigned char) _gsasl_digest_md5_hexdigit_to_char (u)) *
00116 16 + _gsasl_digest_md5_hexdigit_to_char (l));
00117 }
00118
00119 static int
00120 _gsasl_digest_md5_set_hashed_secret (char *secret, const char *hex_secret)
00121 {
00122
00123 const char *p;
00124 char *s;
00125
00126 if (!hex_secret)
00127 return GSASL_AUTHENTICATION_ERROR;
00128
00129 s = secret;
00130 p = hex_secret;
00131 while (*p)
00132 {
00133 *s = _gsasl_digest_md5_hex_to_char (p[0], p[1]);
00134 s++;
00135
00136 p += 2;
00137 }
00138
00139 return GSASL_OK;
00140 }
00141
00142 int
00143 _gsasl_digest_md5_server_step (Gsasl_session * sctx,
00144 void *mech_data,
00145 const char *input,
00146 size_t input_len,
00147 char **output, size_t * output_len)
00148 {
00149 _Gsasl_digest_md5_server_state *state = mech_data;
00150 int rc, res;
00151
00152 *output = NULL;
00153 *output_len = 0;
00154
00155 switch (state->step)
00156 {
00157 case 0:
00158
00159 {
00160 const char *c;
00161 c = gsasl_property_get (sctx, GSASL_REALM);
00162 if (c)
00163 {
00164 state->challenge.nrealms = 1;
00165
00166 state->challenge.realms =
00167 malloc (sizeof (*state->challenge.realms));
00168 if (!state->challenge.realms)
00169 return GSASL_MALLOC_ERROR;
00170
00171 state->challenge.realms[0] = strdup (c);
00172 if (!state->challenge.realms[0])
00173 return GSASL_MALLOC_ERROR;
00174 }
00175 }
00176
00177
00178 {
00179 const char *qopstr = gsasl_property_get (sctx, GSASL_QOPS);
00180
00181 if (qopstr)
00182 {
00183 int qops = digest_md5_qopstr2qops (qopstr);
00184
00185 if (qops == -1)
00186 return GSASL_MALLOC_ERROR;
00187
00188
00189 if (qops & DIGEST_MD5_QOP_AUTH_CONF)
00190 return GSASL_AUTHENTICATION_ERROR;
00191
00192 if (qops)
00193 state->challenge.qops = qops;
00194 }
00195 }
00196
00197
00198
00199
00200 *output = digest_md5_print_challenge (&state->challenge);
00201 if (!*output)
00202 return GSASL_AUTHENTICATION_ERROR;
00203
00204 *output_len = strlen (*output);
00205 state->step++;
00206 res = GSASL_NEEDS_MORE;
00207 break;
00208
00209 case 1:
00210 if (digest_md5_parse_response (input, input_len, &state->response) < 0)
00211 return GSASL_MECHANISM_PARSE_ERROR;
00212
00213
00214 if (digest_md5_validate (&state->challenge, &state->response) < 0)
00215 return GSASL_MECHANISM_PARSE_ERROR;
00216
00217
00218 if (state->response.utf8)
00219 {
00220 gsasl_property_set (sctx, GSASL_AUTHID, state->response.username);
00221 gsasl_property_set (sctx, GSASL_REALM, state->response.realm);
00222 }
00223 else
00224 {
00225
00226
00227 char *tmp;
00228
00229 tmp = latin1toutf8 (state->response.username);
00230 if (!tmp)
00231 return GSASL_MALLOC_ERROR;
00232 gsasl_property_set (sctx, GSASL_AUTHID, tmp);
00233 free (tmp);
00234
00235 tmp = latin1toutf8 (state->response.realm);
00236 if (!tmp)
00237 return GSASL_MALLOC_ERROR;
00238 gsasl_property_set (sctx, GSASL_REALM, tmp);
00239 free (tmp);
00240 }
00241 gsasl_property_set (sctx, GSASL_AUTHZID, state->response.authzid);
00242
00243
00244
00245
00246 {
00247 const char *passwd;
00248 const char *hashed_passwd;
00249
00250 hashed_passwd =
00251 gsasl_property_get (sctx, GSASL_DIGEST_MD5_HASHED_PASSWORD);
00252 if (hashed_passwd)
00253 {
00254 if (strlen (hashed_passwd) != (DIGEST_MD5_LENGTH * 2))
00255 return GSASL_AUTHENTICATION_ERROR;
00256
00257 rc = _gsasl_digest_md5_set_hashed_secret (state->secret,
00258 hashed_passwd);
00259 if (rc != GSASL_OK)
00260 return rc;
00261 }
00262 else if ((passwd = gsasl_property_get (sctx, GSASL_PASSWORD)) != NULL)
00263 {
00264 char *tmp, *tmp2;
00265
00266 tmp2 = utf8tolatin1ifpossible (passwd);
00267
00268 rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
00269 state->response.realm ?
00270 state->response.realm : "", tmp2);
00271 free (tmp2);
00272 if (rc < 0)
00273 return GSASL_MALLOC_ERROR;
00274
00275 rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
00276 free (tmp);
00277 if (rc != GSASL_OK)
00278 return rc;
00279
00280 memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
00281 free (tmp2);
00282 }
00283 else
00284 {
00285 return GSASL_NO_PASSWORD;
00286 }
00287 }
00288
00289
00290 {
00291 char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
00292
00293 rc = digest_md5_hmac (check, state->secret,
00294 state->response.nonce, state->response.nc,
00295 state->response.cnonce, state->response.qop,
00296 state->response.authzid,
00297 state->response.digesturi, 0,
00298 state->response.cipher,
00299 state->kic, state->kis, state->kcc, state->kcs);
00300 if (rc)
00301 return GSASL_AUTHENTICATION_ERROR;
00302
00303 if (strcmp (state->response.response, check) != 0)
00304 return GSASL_AUTHENTICATION_ERROR;
00305 }
00306
00307
00308 rc = digest_md5_hmac (state->finish.rspauth, state->secret,
00309 state->response.nonce, state->response.nc,
00310 state->response.cnonce, state->response.qop,
00311 state->response.authzid,
00312 state->response.digesturi, 1,
00313 state->response.cipher, NULL, NULL, NULL, NULL);
00314 if (rc)
00315 return GSASL_AUTHENTICATION_ERROR;
00316
00317 *output = digest_md5_print_finish (&state->finish);
00318 if (!*output)
00319 return GSASL_MALLOC_ERROR;
00320
00321 *output_len = strlen (*output);
00322
00323 state->step++;
00324 res = GSASL_OK;
00325 break;
00326
00327 default:
00328 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00329 break;
00330 }
00331
00332 return res;
00333 }
00334
00335 void
00336 _gsasl_digest_md5_server_finish (Gsasl_session * sctx, void *mech_data)
00337 {
00338 _Gsasl_digest_md5_server_state *state = mech_data;
00339
00340 if (!state)
00341 return;
00342
00343 digest_md5_free_challenge (&state->challenge);
00344 digest_md5_free_response (&state->response);
00345 digest_md5_free_finish (&state->finish);
00346
00347 free (state);
00348 }
00349
00350 int
00351 _gsasl_digest_md5_server_encode (Gsasl_session * sctx,
00352 void *mech_data,
00353 const char *input,
00354 size_t input_len,
00355 char **output, size_t * output_len)
00356 {
00357 _Gsasl_digest_md5_server_state *state = mech_data;
00358 int res;
00359
00360 res = digest_md5_encode (input, input_len, output, output_len,
00361 state->response.qop, state->sendseqnum,
00362 state->kis);
00363 if (res)
00364 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00365
00366 if (state->sendseqnum == 4294967295UL)
00367 state->sendseqnum = 0;
00368 else
00369 state->sendseqnum++;
00370
00371 return GSASL_OK;
00372 }
00373
00374 int
00375 _gsasl_digest_md5_server_decode (Gsasl_session * sctx,
00376 void *mech_data,
00377 const char *input,
00378 size_t input_len,
00379 char **output, size_t * output_len)
00380 {
00381 _Gsasl_digest_md5_server_state *state = mech_data;
00382 int res;
00383
00384 res = digest_md5_decode (input, input_len, output, output_len,
00385 state->response.qop, state->readseqnum,
00386 state->kic);
00387 if (res)
00388 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00389
00390 if (state->readseqnum == 4294967295UL)
00391 state->readseqnum = 0;
00392 else
00393 state->readseqnum++;
00394
00395 return GSASL_OK;
00396 }