|
gsasl
1.7.6
|
00001 /* server.c --- DIGEST-MD5 mechanism from RFC 2831, server side. 00002 * Copyright (C) 2002-2012 Simon Josefsson 00003 * 00004 * This file is part of GNU SASL Library. 00005 * 00006 * GNU SASL Library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public License 00008 * as published by the Free Software Foundation; either version 2.1 of 00009 * the License, or (at your option) any later version. 00010 * 00011 * GNU SASL Library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with GNU SASL Library; if not, write to the Free 00018 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00019 * Boston, MA 02110-1301, USA. 00020 * 00021 */ 00022 00023 #ifdef HAVE_CONFIG_H 00024 #include "config.h" 00025 #endif 00026 00027 /* Get specification. */ 00028 #include "digest-md5.h" 00029 00030 /* Get malloc, free. */ 00031 #include <stdlib.h> 00032 00033 /* Get memcpy, strdup, strlen. */ 00034 #include <string.h> 00035 00036 /* Get tools. */ 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 /* The hex representation always contains lowercase alphabetic 00102 characters. See RFC 2831, 1.1. */ 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 /* Convert the hex string containing the secret to a byte array */ 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 /* Set realm. */ 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 /* Set QOP */ 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 /* We don't support confidentiality right now. */ 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 /* FIXME: cipher, maxbuf, more realms. */ 00198 00199 /* Create challenge. */ 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 /* Make sure response is consistent with challenge. */ 00214 if (digest_md5_validate (&state->challenge, &state->response) < 0) 00215 return GSASL_MECHANISM_PARSE_ERROR; 00216 00217 /* Store properties, from the client response. */ 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 /* Client provided username/realm in ISO-8859-1 form, 00226 convert it to UTF-8 since the library is all-UTF-8. */ 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 /* FIXME: cipher, maxbuf. */ 00244 00245 /* Compute secret. */ 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 /* Check client response. */ 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 /* Create finish token. */ 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 }
1.7.6.1