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 #include "validate.h"
00044
00045 #define NONCE_ENTROPY_BYTES 16
00046
00047 struct _Gsasl_digest_md5_server_state
00048 {
00049 int step;
00050 unsigned long readseqnum, sendseqnum;
00051 char secret[DIGEST_MD5_LENGTH];
00052 char kic[DIGEST_MD5_LENGTH];
00053 char kcc[DIGEST_MD5_LENGTH];
00054 char kis[DIGEST_MD5_LENGTH];
00055 char kcs[DIGEST_MD5_LENGTH];
00056 digest_md5_challenge challenge;
00057 digest_md5_response response;
00058 digest_md5_finish finish;
00059 };
00060 typedef struct _Gsasl_digest_md5_server_state _Gsasl_digest_md5_server_state;
00061
00062 int
00063 _gsasl_digest_md5_server_start (Gsasl_session * sctx, void **mech_data)
00064 {
00065 _Gsasl_digest_md5_server_state *state;
00066 char nonce[NONCE_ENTROPY_BYTES];
00067 char *p;
00068 int rc;
00069
00070 rc = gsasl_nonce (nonce, NONCE_ENTROPY_BYTES);
00071 if (rc != GSASL_OK)
00072 return rc;
00073
00074 rc = gsasl_base64_to (nonce, NONCE_ENTROPY_BYTES, &p, NULL);
00075 if (rc != GSASL_OK)
00076 return rc;
00077
00078 state = calloc (1, sizeof (*state));
00079 if (state == NULL)
00080 {
00081 free (p);
00082 return GSASL_MALLOC_ERROR;
00083 }
00084
00085 state->challenge.qops = DIGEST_MD5_QOP_AUTH | DIGEST_MD5_QOP_AUTH_INT;
00086 state->challenge.ciphers = 0;
00087
00088 state->challenge.nonce = p;
00089 state->challenge.utf8 = 1;
00090
00091 *mech_data = state;
00092
00093 return GSASL_OK;
00094 }
00095
00096 int
00097 _gsasl_digest_md5_server_step (Gsasl_session * sctx,
00098 void *mech_data,
00099 const char *input,
00100 size_t input_len,
00101 char **output, size_t * output_len)
00102 {
00103 _Gsasl_digest_md5_server_state *state = mech_data;
00104 int rc, res;
00105
00106 *output = NULL;
00107 *output_len = 0;
00108
00109 switch (state->step)
00110 {
00111 case 0:
00112
00113 {
00114 const char *c;
00115 c = gsasl_property_get (sctx, GSASL_REALM);
00116 if (c)
00117 {
00118 state->challenge.nrealms = 1;
00119
00120 state->challenge.realms =
00121 malloc (sizeof (*state->challenge.realms));
00122 if (!state->challenge.realms)
00123 return GSASL_MALLOC_ERROR;
00124
00125 state->challenge.realms[0] = strdup (c);
00126 if (!state->challenge.realms[0])
00127 return GSASL_MALLOC_ERROR;
00128 }
00129 }
00130
00131
00132
00133
00134 *output = digest_md5_print_challenge (&state->challenge);
00135 if (!*output)
00136 return GSASL_AUTHENTICATION_ERROR;
00137
00138 *output_len = strlen (*output);
00139 state->step++;
00140 res = GSASL_NEEDS_MORE;
00141 break;
00142
00143 case 1:
00144 if (digest_md5_parse_response (input, input_len, &state->response) < 0)
00145 return GSASL_MECHANISM_PARSE_ERROR;
00146
00147
00148 if (digest_md5_validate (&state->challenge, &state->response) < 0)
00149 return GSASL_MECHANISM_PARSE_ERROR;
00150
00151
00152 gsasl_property_set (sctx, GSASL_AUTHID, state->response.username);
00153 gsasl_property_set (sctx, GSASL_AUTHZID, state->response.authzid);
00154 gsasl_property_set (sctx, GSASL_REALM, state->response.realm);
00155
00156
00157
00158
00159
00160 {
00161 const char *c;
00162 char *tmp, *tmp2;
00163
00164 c = gsasl_property_get (sctx, GSASL_PASSWORD);
00165 if (!c)
00166 return GSASL_NO_PASSWORD;
00167
00168 if (asprintf (&tmp, "%s:%s:%s", state->response.username,
00169 state->response.realm ?
00170 state->response.realm : "", c) < 0)
00171 return GSASL_MALLOC_ERROR;
00172
00173 rc = gsasl_md5 (tmp, strlen (tmp), &tmp2);
00174 free (tmp);
00175 if (rc != GSASL_OK)
00176 return rc;
00177 memcpy (state->secret, tmp2, DIGEST_MD5_LENGTH);
00178 free (tmp2);
00179 }
00180
00181
00182 {
00183 char check[DIGEST_MD5_RESPONSE_LENGTH + 1];
00184
00185 rc = digest_md5_hmac (check, state->secret,
00186 state->response.nonce, state->response.nc,
00187 state->response.cnonce, state->response.qop,
00188 state->response.authzid,
00189 state->response.digesturi, 0,
00190 state->response.cipher, NULL, NULL, NULL, NULL);
00191 if (rc)
00192 return GSASL_AUTHENTICATION_ERROR;
00193
00194 if (strcmp (state->response.response, check) != 0)
00195 return GSASL_AUTHENTICATION_ERROR;
00196 }
00197
00198
00199 rc = digest_md5_hmac (state->finish.rspauth, state->secret,
00200 state->response.nonce, state->response.nc,
00201 state->response.cnonce, state->response.qop,
00202 state->response.authzid,
00203 state->response.digesturi, 1,
00204 state->response.cipher, NULL, NULL, NULL, NULL);
00205 if (rc)
00206 return GSASL_AUTHENTICATION_ERROR;
00207
00208 *output = digest_md5_print_finish (&state->finish);
00209 if (!*output)
00210 return GSASL_MALLOC_ERROR;
00211
00212 *output_len = strlen (*output);
00213
00214 state->step++;
00215 res = GSASL_NEEDS_MORE;
00216 break;
00217
00218 case 2:
00219 *output_len = 0;
00220 state->step++;
00221 res = GSASL_OK;
00222 break;
00223
00224 default:
00225 res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
00226 break;
00227 }
00228
00229 return res;
00230 }
00231
00232 void
00233 _gsasl_digest_md5_server_finish (Gsasl_session * sctx, void *mech_data)
00234 {
00235 _Gsasl_digest_md5_server_state *state = mech_data;
00236
00237 if (!state)
00238 return;
00239
00240 digest_md5_free_challenge (&state->challenge);
00241 digest_md5_free_response (&state->response);
00242 digest_md5_free_finish (&state->finish);
00243
00244 free (state);
00245 }
00246
00247 int
00248 _gsasl_digest_md5_server_encode (Gsasl_session * sctx,
00249 void *mech_data,
00250 const char *input,
00251 size_t input_len,
00252 char **output, size_t * output_len)
00253 {
00254 _Gsasl_digest_md5_server_state *state = mech_data;
00255 int res;
00256
00257 res = digest_md5_encode (input, input_len, output, output_len,
00258 state->response.qop, state->sendseqnum,
00259 state->kis);
00260 if (res)
00261 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00262
00263 if (state->sendseqnum == 4294967295UL)
00264 state->sendseqnum = 0;
00265 else
00266 state->sendseqnum++;
00267
00268 return GSASL_OK;
00269 }
00270
00271 int
00272 _gsasl_digest_md5_server_decode (Gsasl_session * sctx,
00273 void *mech_data,
00274 const char *input,
00275 size_t input_len,
00276 char **output, size_t * output_len)
00277 {
00278 _Gsasl_digest_md5_server_state *state = mech_data;
00279 int res;
00280
00281 res = digest_md5_decode (input, input_len, output, output_len,
00282 state->response.qop, state->readseqnum,
00283 state->kic);
00284 if (res)
00285 return res == -2 ? GSASL_NEEDS_MORE : GSASL_INTEGRITY_ERROR;
00286
00287 if (state->readseqnum == 4294967295UL)
00288 state->readseqnum = 0;
00289 else
00290 state->readseqnum++;
00291
00292 return GSASL_OK;
00293 }