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 "qop.h"
00045
00046 #define CNONCE_ENTROPY_BYTES 16
00047
00048 struct _Gsasl_digest_md5_client_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_client_state _Gsasl_digest_md5_client_state;
00062
00063 int
00064 _gsasl_digest_md5_client_start (Gsasl_session * sctx, void **mech_data)
00065 {
00066 _Gsasl_digest_md5_client_state *state;
00067 char nonce[CNONCE_ENTROPY_BYTES];
00068 char *p;
00069 int rc;
00070
00071 rc = gsasl_nonce (nonce, CNONCE_ENTROPY_BYTES);
00072 if (rc != GSASL_OK)
00073 return rc;
00074
00075 rc = gsasl_base64_to (nonce, CNONCE_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->response.cnonce = p;
00087 state->response.nc = 1;
00088
00089 *mech_data = state;
00090
00091 return GSASL_OK;
00092 }
00093
00094 int
00095 _gsasl_digest_md5_client_step (Gsasl_session * sctx,
00096 void *mech_data,
00097 const char *input,
00098 size_t input_len,
00099 char **output, size_t * output_len)
00100 {
00101 _Gsasl_digest_md5_client_state *state = mech_data;
00102 int rc, res;
00103
00104 *output = NULL;
00105 *output_len = 0;
00106
00107 switch (state->step)
00108 {
00109 case 0:
00110 state->step++;
00111 if (input_len == 0)
00112 return GSASL_NEEDS_MORE;
00113
00114
00115 case 1:
00116 {
00117 if (digest_md5_parse_challenge (input, input_len,
00118 &state->challenge) < 0)
00119 return GSASL_MECHANISM_PARSE_ERROR;
00120
00121
00122
00123
00124
00125
00126
00127
00128 if (state->challenge.nrealms > 0)
00129 gsasl_property_set (sctx, GSASL_REALM, state->challenge.realms[0]);
00130 else
00131 gsasl_property_set (sctx, GSASL_REALM, NULL);
00132
00133
00134
00135
00136 state->response.utf8 = 1;
00137
00138 gsasl_property_set (sctx, GSASL_QOPS,
00139 digest_md5_qops2qopstr (state->challenge.qops));
00140
00141 {
00142 const char *qop = gsasl_property_get (sctx, GSASL_QOP);
00143
00144 if (!qop)
00145 state->response.qop = GSASL_QOP_AUTH;
00146 else if (strcmp (qop, "qop-int") == 0)
00147 state->response.qop = GSASL_QOP_AUTH_INT;
00148 else if (strcmp (qop, "qop-auth") == 0)
00149 state->response.qop = GSASL_QOP_AUTH;
00150 else
00151
00152
00153 return GSASL_AUTHENTICATION_ERROR;
00154 }
00155
00156 state->response.nonce = strdup (state->challenge.nonce);
00157 if (!state->response.nonce)
00158 return GSASL_MALLOC_ERROR;
00159
00160 {
00161 const char *service = gsasl_property_get (sctx, GSASL_SERVICE);
00162 const char *hostname = gsasl_property_get (sctx, GSASL_HOSTNAME);
00163 if (!service)
00164 return GSASL_NO_SERVICE;
00165 if (!hostname)
00166 return GSASL_NO_HOSTNAME;
00167 if (asprintf (&state->response.digesturi, "%s/%s",
00168 service, hostname) < 0)
00169 return GSASL_MALLOC_ERROR;
00170 }
00171
00172 {
00173 const char *c;
00174 char *tmp, *tmp2;
00175
00176 c = gsasl_property_get (sctx, GSASL_AUTHID);
00177 if (!c)
00178 return GSASL_NO_AUTHID;
00179
00180 state->response.username = strdup (c);
00181 if (!state->response.username)
00182 return GSASL_MALLOC_ERROR;
00183
00184 c = gsasl_property_get (sctx, GSASL_AUTHZID);
00185 if (c)
00186 {
00187 state->response.authzid = strdup (c);
00188 if (!state->response.authzid)
00189 return GSASL_MALLOC_ERROR;
00190 }
00191
00192 gsasl_callback (NULL, sctx, GSASL_REALM);
00193 c = gsasl_property_fast (sctx, GSASL_REALM);
00194 if (c)
00195 {
00196 state->response.realm = strdup (c);
00197 if (!state->response.realm)
00198 return GSASL_MALLOC_ERROR;
00199 }
00200
00201 c = gsasl_property_get (sctx, GSASL_PASSWORD);
00202 if (!c)
00203 return GSASL_NO_PASSWORD;
00204
00205 tmp2 = utf8tolatin1ifpossible (c);
00206
00207 rc = asprintf (&tmp, "%s:%s:%s", state->response.username,
00208 state->response.realm ?
00209 state->response.realm : "", tmp2);
00210 free (tmp2);
00211 if (rc < 0)
00212 return GSASL_MALLOC_ERROR;
00213
00214 rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
00215 free (tmp);
00216 if (rc != GSASL_OK)
00217 return rc;
00218 memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
00219 free (tmp2);
00220 }
00221
00222 rc = digest_md5_hmac (state->response.response,
00223 state->secret,
00224 state->response.nonce,
00225 state->response.nc,
00226 state->response.cnonce,
00227 state->response.qop,
00228 state->response.authzid,
00229 state->response.digesturi,
00230 0,
00231 state->response.cipher,
00232 state->kic, state->kis, state->kcc, state->kcs);
00233 if (rc)
00234 return GSASL_CRYPTO_ERROR;
00235
00236 *output = digest_md5_print_response (&state->response);
00237 if (!*output)
00238 return GSASL_AUTHENTICATION_ERROR;
00239
00240 *output_len = strlen (*output);
00241
00242 state->step++;
00243 res = GSASL_NEEDS_MORE;
00244 }
00245 break;
00246
00247 case 2:
00248 {
00249 char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
00250
00251 if (digest_md5_parse_finish (input, input_len, &state->finish) < 0)
00252 return GSASL_MECHANISM_PARSE_ERROR;
00253
00254 res = digest_md5_hmac (check, state->secret,
00255 state->response.nonce, state->response.nc,
00256 state->response.cnonce, state->response.qop,
00257 state->response.authzid,
00258 state->response.digesturi, 1,
00259 state->response.cipher, NULL, NULL, NULL,
00260 NULL);
00261 if (res != GSASL_OK)
00262 break;
00263
00264 if (strcmp (state->finish.rspauth, check) == 0)
00265 res = GSASL_OK;
00266 else
00267 res = GSASL_AUTHENTICATION_ERROR;
00268 state->step++;
00269 }
00270 break;
00271
00272 default:
00273 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00274 break;
00275 }
00276
00277 return res;
00278 }
00279
00280 void
00281 _gsasl_digest_md5_client_finish (Gsasl_session * sctx, void *mech_data)
00282 {
00283 _Gsasl_digest_md5_client_state *state = mech_data;
00284
00285 if (!state)
00286 return;
00287
00288 digest_md5_free_challenge (&state->challenge);
00289 digest_md5_free_response (&state->response);
00290 digest_md5_free_finish (&state->finish);
00291
00292 free (state);
00293 }
00294
00295 int
00296 _gsasl_digest_md5_client_encode (Gsasl_session * sctx,
00297 void *mech_data,
00298 const char *input,
00299 size_t input_len,
00300 char **output, size_t * output_len)
00301 {
00302 _Gsasl_digest_md5_client_state *state = mech_data;
00303 int res;
00304
00305 res = digest_md5_encode (input, input_len, output, output_len,
00306 state->response.qop,
00307 state->sendseqnum, state->kic);
00308 if (res)
00309 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00310
00311 if (state->sendseqnum == 4294967295UL)
00312 state->sendseqnum = 0;
00313 else
00314 state->sendseqnum++;
00315
00316 return GSASL_OK;
00317 }
00318
00319 int
00320 _gsasl_digest_md5_client_decode (Gsasl_session * sctx,
00321 void *mech_data,
00322 const char *input,
00323 size_t input_len,
00324 char **output, size_t * output_len)
00325 {
00326 _Gsasl_digest_md5_client_state *state = mech_data;
00327 int res;
00328
00329 res = digest_md5_decode (input, input_len, output, output_len,
00330 state->response.qop,
00331 state->readseqnum, state->kis);
00332 if (res)
00333 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00334
00335 if (state->readseqnum == 4294967295UL)
00336 state->readseqnum = 0;
00337 else
00338 state->readseqnum++;
00339
00340 return GSASL_OK;
00341 }