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