00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #if 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 "tokens.h"
00038 #include "parser.h"
00039 #include "printer.h"
00040 #include "free.h"
00041 #include "session.h"
00042 #include "digesthmac.h"
00043
00044 #define CNONCE_ENTROPY_BYTES 16
00045
00046 struct _Gsasl_digest_md5_client_state
00047 {
00048 int step;
00049 unsigned long readseqnum, sendseqnum;
00050 char secret[DIGEST_MD5_LENGTH];
00051 char kic[DIGEST_MD5_LENGTH];
00052 char kcc[DIGEST_MD5_LENGTH];
00053 char kis[DIGEST_MD5_LENGTH];
00054 char kcs[DIGEST_MD5_LENGTH];
00055 digest_md5_challenge challenge;
00056 digest_md5_response response;
00057 digest_md5_finish finish;
00058 };
00059 typedef struct _Gsasl_digest_md5_client_state _Gsasl_digest_md5_client_state;
00060
00061 int
00062 _gsasl_digest_md5_client_start (Gsasl_session * sctx, void **mech_data)
00063 {
00064 _Gsasl_digest_md5_client_state *state;
00065 char nonce[CNONCE_ENTROPY_BYTES];
00066 char *p;
00067 int rc;
00068
00069 rc = gsasl_nonce (nonce, CNONCE_ENTROPY_BYTES);
00070 if (rc != GSASL_OK)
00071 return rc;
00072
00073 rc = gsasl_base64_to (nonce, CNONCE_ENTROPY_BYTES, &p, NULL);
00074 if (rc != GSASL_OK)
00075 return rc;
00076
00077 state = calloc (1, sizeof (*state));
00078 if (state == NULL)
00079 {
00080 free (p);
00081 return GSASL_MALLOC_ERROR;
00082 }
00083
00084 state->response.cnonce = p;
00085 state->response.nc = 1;
00086
00087 *mech_data = state;
00088
00089 return GSASL_OK;
00090 }
00091
00092 int
00093 _gsasl_digest_md5_client_step (Gsasl_session * sctx,
00094 void *mech_data,
00095 const char *input,
00096 size_t input_len,
00097 char **output, size_t * output_len)
00098 {
00099 _Gsasl_digest_md5_client_state *state = mech_data;
00100 int rc, res;
00101
00102 *output = NULL;
00103 *output_len = 0;
00104
00105 switch (state->step)
00106 {
00107 case 0:
00108 state->step++;
00109 if (input_len == 0)
00110 return GSASL_NEEDS_MORE;
00111
00112
00113 case 1:
00114 {
00115 if (digest_md5_parse_challenge (input, input_len,
00116 &state->challenge) < 0)
00117 return GSASL_MECHANISM_PARSE_ERROR;
00118
00119
00120
00121
00122
00123
00124
00125
00126 if (state->challenge.nrealms > 0)
00127 gsasl_property_set (sctx, GSASL_REALM, state->challenge.realms[0]);
00128 else
00129 gsasl_property_set (sctx, GSASL_REALM, NULL);
00130
00131
00132
00133
00134 state->response.utf8 = 1;
00135 state->response.qop = 1;
00136
00137 state->response.nonce = strdup (state->challenge.nonce);
00138 if (!state->response.nonce)
00139 return GSASL_MALLOC_ERROR;
00140
00141 {
00142 const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
00143 const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00144 if (!service)
00145 return GSASL_NO_SERVICE;
00146 if (!hostname)
00147 return GSASL_NO_HOSTNAME;
00148 if (asprintf (&state->response.digesturi, "%s/%s",
00149 service, hostname) < 0)
00150 return GSASL_MALLOC_ERROR;
00151 }
00152
00153 {
00154 const char *c;
00155 char *tmp, *tmp2;
00156
00157 c = gsasl_property_get (sctx, GSASL_AUTHID);
00158 if (!c)
00159 return GSASL_NO_AUTHID;
00160
00161 state->response.username = strdup (c);
00162 if (!state->response.username)
00163 return GSASL_MALLOC_ERROR;
00164
00165 c = gsasl_property_get (sctx, GSASL_AUTHZID);
00166 if (c)
00167 {
00168 state->response.authzid = strdup (c);
00169 if (!state->response.authzid)
00170 return GSASL_MALLOC_ERROR;
00171 }
00172
00173 gsasl_callback (NULL, sctx, GSASL_REALM);
00174 c = gsasl_property_fast (sctx, GSASL_REALM);
00175 if (c)
00176 {
00177 state->response.realm = strdup (c);
00178 if (!state->response.realm)
00179 return GSASL_MALLOC_ERROR;
00180 }
00181
00182 c = gsasl_property_get (sctx, GSASL_PASSWORD);
00183 if (!c)
00184 return GSASL_NO_PASSWORD;
00185
00186 if (asprintf (&tmp, "%s:%s:%s", state->response.username,
00187 state->response.realm ?
00188 state->response.realm : "", c) < 0)
00189 return GSASL_MALLOC_ERROR;
00190
00191 rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
00192 free (tmp);
00193 if (rc != GSASL_OK)
00194 return rc;
00195 memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
00196 free (tmp2);
00197 }
00198
00199 rc = digest_md5_hmac (state->response.response,
00200 state->secret,
00201 state->response.nonce,
00202 state->response.nc,
00203 state->response.cnonce,
00204 state->response.qop,
00205 state->response.authzid,
00206 state->response.digesturi,
00207 0,
00208 state->response.cipher,
00209 state->kic, state->kis, state->kcc, state->kcs);
00210 if (rc)
00211 return GSASL_CRYPTO_ERROR;
00212
00213 *output = digest_md5_print_response (&state->response);
00214 if (!*output)
00215 return GSASL_AUTHENTICATION_ERROR;
00216
00217 *output_len = strlen (*output);
00218
00219 state->step++;
00220 res = GSASL_NEEDS_MORE;
00221 }
00222 break;
00223
00224 case 2:
00225 {
00226 char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
00227
00228 if (digest_md5_parse_finish (input, input_len, &state->finish) < 0)
00229 return GSASL_MECHANISM_PARSE_ERROR;
00230
00231 res = digest_md5_hmac (check, state->secret,
00232 state->response.nonce, state->response.nc,
00233 state->response.cnonce, state->response.qop,
00234 state->response.authzid,
00235 state->response.digesturi, 1,
00236 state->response.cipher, NULL, NULL, NULL,
00237 NULL);
00238 if (res != GSASL_OK)
00239 break;
00240
00241 if (strcmp (state->finish.rspauth, check) == 0)
00242 res = GSASL_OK;
00243 else
00244 res = GSASL_AUTHENTICATION_ERROR;
00245 state->step++;
00246 }
00247 break;
00248
00249 default:
00250 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00251 break;
00252 }
00253
00254 return res;
00255 }
00256
00257 void
00258 _gsasl_digest_md5_client_finish (Gsasl_session * sctx, void *mech_data)
00259 {
00260 _Gsasl_digest_md5_client_state *state = mech_data;
00261
00262 if (!state)
00263 return;
00264
00265 digest_md5_free_challenge (&state->challenge);
00266 digest_md5_free_response (&state->response);
00267 digest_md5_free_finish (&state->finish);
00268
00269 free (state);
00270 }
00271
00272 int
00273 _gsasl_digest_md5_client_encode (Gsasl_session * sctx,
00274 void *mech_data,
00275 const char *input,
00276 size_t input_len,
00277 char **output, size_t * output_len)
00278 {
00279 _Gsasl_digest_md5_client_state *state = mech_data;
00280 int res;
00281
00282 res = digest_md5_encode (input, input_len, output, output_len,
00283 state->response.qop,
00284 state->sendseqnum, state->kic);
00285 if (res)
00286 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00287
00288 if (state->sendseqnum == 4294967295UL)
00289 state->sendseqnum = 0;
00290 else
00291 state->sendseqnum++;
00292
00293 return GSASL_OK;
00294 }
00295
00296 int
00297 _gsasl_digest_md5_client_decode (Gsasl_session * sctx,
00298 void *mech_data,
00299 const char *input,
00300 size_t input_len,
00301 char **output, size_t * output_len)
00302 {
00303 _Gsasl_digest_md5_client_state *state = mech_data;
00304 int res;
00305
00306 res = digest_md5_decode (input, input_len, output, output_len,
00307 state->response.qop,
00308 state->readseqnum, state->kis);
00309 if (res)
00310 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00311
00312 if (state->readseqnum == 4294967295UL)
00313 state->readseqnum = 0;
00314 else
00315 state->readseqnum++;
00316
00317 return GSASL_OK;
00318 }