00001
00002
00003
00004
00005
00006
00007
00008
00009 #include "klone_conf.h"
00010 #include <sys/types.h>
00011 #include <sys/stat.h>
00012 #include <stdlib.h>
00013 #include <time.h>
00014 #include <unistd.h>
00015 #include <fcntl.h>
00016 #include <u/libu.h>
00017 #include <klone/session.h>
00018 #include <klone/request.h>
00019 #include <klone/response.h>
00020 #include <klone/vars.h>
00021 #include <klone/utils.h>
00022 #include <klone/emb.h>
00023 #include <klone/ses_prv.h>
00024 #include <klone/codecs.h>
00025 #ifdef SSL_ON
00026 #include <openssl/hmac.h>
00027 #include <openssl/rand.h>
00028 #endif
00029 #ifdef SSL_CYASSL
00030 #include <config.h>
00031 #include <types.h>
00032 #include <ctc_hmac.h>
00033 #include <ctc_aes.h>
00034 #define EVP_MAX_MD_SIZE 64
00035 #endif
00036
00037 #define KL1_CLISES_DATA "KL1_CLISES_DATA"
00038 #define KL1_CLISES_MTIME "KL1_CLISES_MTIME"
00039 #define KL1_CLISES_HMAC "KL1_CLISES_HMAC"
00040 #define KL1_CLISES_IV "KL1_CLISES_IV"
00041
00042 enum { HMAC_HEX_SIZE = 2*EVP_MAX_MD_SIZE + 1 };
00043
00044
00045 static int session_client_hmac(HMAC_CTX *ctx, char *hmac, size_t hmac_sz,
00046 const char *data, const char *sid, const char *mtime, const char *hex_iv)
00047 {
00048 char mac[EVP_MAX_MD_SIZE];
00049 int mac_len;
00050
00051 dbg_err_if (ctx == NULL);
00052 dbg_err_if (hmac == NULL);
00053 dbg_err_if (data == NULL);
00054 dbg_err_if (sid == NULL);
00055 dbg_err_if (mtime == NULL);
00056
00057
00058 #if SSL_OPENSSL
00059
00060 dbg_err_if(hmac_sz < EVP_MAX_MD_SIZE*2 + 1);
00061
00062
00063 HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
00064 HMAC_Update(ctx, data, strlen(data));
00065 HMAC_Update(ctx, sid, strlen(sid));
00066 HMAC_Update(ctx, mtime, strlen(mtime));
00067 if(hex_iv)
00068 HMAC_Update(ctx, hex_iv, strlen(hex_iv));
00069 HMAC_Final(ctx, mac, &mac_len);
00070 #endif
00071
00072 #ifdef SSL_CYASSL
00073 HmacUpdate(ctx, (const byte*)data, strlen(data));
00074 HmacUpdate(ctx, (const byte*)sid, strlen(sid));
00075 HmacUpdate(ctx, (const byte*)mtime, strlen(mtime));
00076 if(hex_iv)
00077 HmacUpdate(ctx, (const byte*)hex_iv, strlen(hex_iv));
00078 HmacFinal(ctx, (byte*)mac);
00079
00080 if (ctx->macType == MD5)
00081 mac_len = MD5_DIGEST_SIZE;
00082 else if (ctx->macType == SHA)
00083 mac_len = SHA_DIGEST_SIZE;
00084 else
00085 crit_err("unknown hash");
00086 #endif
00087
00088
00089 dbg_err_if(u_hexncpy(hmac, mac, mac_len, HEXCPY_ENCODE) <= 0);
00090
00091 return 0;
00092 err:
00093 return -1;
00094 }
00095
00096 static int session_client_save(session_t *ss)
00097 {
00098
00099 enum {
00100 MTIME_SIZE = 32,
00101 BUF_SIZE = COOKIE_MAX_SIZE + EVP_MAX_BLOCK_LENGTH + 96
00102 };
00103 session_opt_t *so = ss->so;
00104 char hmac[HMAC_HEX_SIZE], ebuf[BUF_SIZE], mtime[MTIME_SIZE];
00105 char *buf = NULL, cipher_iv_hex[CIPHER_IV_LEN * 2 + 1];
00106 size_t sz;
00107 time_t now;
00108
00109 dbg_err_if (ss == NULL);
00110
00111 #ifdef SSL_ON
00112 if(ss->so->encrypt)
00113 {
00114
00115 #ifdef SSL_OPENSSL
00116 dbg_err_if(!RAND_pseudo_bytes(ss->so->cipher_iv, CIPHER_IV_LEN));
00117 #endif
00118
00119 #ifdef SSL_CYASSL
00120 dbg_err_if(!RAND_bytes(ss->so->cipher_iv, CIPHER_IV_LEN));
00121 #endif
00122
00123
00124 dbg_err_if(u_hexncpy(cipher_iv_hex, ss->so->cipher_iv, CIPHER_IV_LEN,
00125 HEXCPY_ENCODE) <= 0);
00126 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_IV, cipher_iv_hex,
00127 0, NULL, NULL, 0));
00128 }
00129 #endif
00130
00131
00132 dbg_err_if(session_prv_save_to_buf(ss, &buf, &sz));
00133
00134 warn_err_ifm(sz > COOKIE_MAX_SIZE,
00135 "session data too big for client-side sessions");
00136
00137
00138 dbg_err_if(u_hexncpy(ebuf, buf, sz, HEXCPY_ENCODE) <= 0);
00139
00140 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_DATA, ebuf, 0, NULL,
00141 NULL, 0));
00142
00143
00144 dbg_err_sif ((now = time(NULL)) == (time_t) -1);
00145 dbg_err_if (u_snprintf(mtime, sizeof mtime, "%d", (ss->mtime = (int) now)));
00146 dbg_err_if (response_set_cookie(ss->rs, KL1_CLISES_MTIME, mtime, 0, NULL,
00147 NULL, 0));
00148
00149
00150 dbg_err_if(session_client_hmac(&so->hmac_ctx, hmac, HMAC_HEX_SIZE,
00151 ebuf, ss->id, mtime, ss->so->encrypt ? cipher_iv_hex : NULL));
00152
00153
00154 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_HMAC, hmac, 0, NULL,
00155 NULL, 0));
00156
00157 u_free(buf);
00158
00159 return 0;
00160 err:
00161 if(buf)
00162 u_free(buf);
00163 return ~0;
00164 }
00165
00166 static int session_client_load(session_t *ss)
00167 {
00168 session_opt_t *so = ss->so;
00169 char hmac[HMAC_HEX_SIZE], buf[COOKIE_MAX_SIZE];
00170 const char *cli_ebuf, *cli_hmac, *cli_mtime, *cli_iv;
00171 ssize_t c;
00172
00173 dbg_err_if (ss == NULL);
00174
00175
00176 cli_ebuf = request_get_cookie(ss->rq, KL1_CLISES_DATA);
00177 cli_mtime = request_get_cookie(ss->rq, KL1_CLISES_MTIME);
00178 cli_hmac = request_get_cookie(ss->rq, KL1_CLISES_HMAC);
00179 cli_iv = request_get_cookie(ss->rq, KL1_CLISES_IV);
00180
00181
00182 dbg_err_if(cli_ebuf == NULL || cli_mtime == NULL || cli_hmac == NULL);
00183
00184
00185
00186 dbg_err_if(session_client_hmac(&so->hmac_ctx, hmac, HMAC_HEX_SIZE,
00187 cli_ebuf, ss->id, cli_mtime, ss->so->encrypt ? cli_iv : NULL));
00188
00189
00190 if(strcmp(hmac, cli_hmac))
00191 {
00192 session_remove(ss);
00193 warn_err("HMAC don't match, rejecting session data");
00194 }
00195
00196
00197
00198
00199 dbg_err_if((c = u_hexncpy(ss->so->cipher_iv, cli_iv, strlen(cli_iv),
00200 HEXCPY_DECODE)) <= 0);
00201
00202
00203 ss->mtime = strtoul(cli_mtime, NULL, 0);
00204
00205 dbg_err_if(strlen(cli_ebuf) > COOKIE_MAX_SIZE);
00206
00207
00208 dbg_err_if((c = u_hexncpy(buf, cli_ebuf, strlen(cli_ebuf),
00209 HEXCPY_DECODE)) <= 0);
00210
00211
00212 dbg_err_if(session_prv_load_from_buf(ss, buf, c));
00213
00214 return 0;
00215 err:
00216 return ~0;
00217 }
00218
00219 static int session_client_term(session_t *ss)
00220 {
00221 u_unused_args(ss);
00222 return 0;
00223 }
00224
00225 static int session_client_remove(session_t *ss)
00226 {
00227 dbg_err_if (ss == NULL);
00228
00229
00230 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_DATA, NULL, 0, NULL,
00231 NULL, 0));
00232 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_MTIME, NULL, 0, NULL,
00233 NULL, 0));
00234 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_HMAC, NULL, 0, NULL,
00235 NULL, 0));
00236 dbg_err_if(response_set_cookie(ss->rs, KL1_CLISES_IV, NULL, 0, NULL,
00237 NULL, 0));
00238
00239 return 0;
00240 err:
00241 return ~0;
00242 }
00243
00244 int session_client_create(session_opt_t *so, request_t *rq, response_t *rs,
00245 session_t **pss)
00246 {
00247 session_t *ss = NULL;
00248
00249 dbg_err_if (rq == NULL);
00250 dbg_err_if (rs == NULL);
00251 dbg_err_if (pss == NULL);
00252 dbg_err_if (so == NULL);
00253
00254 ss = u_zalloc(sizeof(session_t));
00255 dbg_err_if(ss == NULL);
00256
00257 ss->load = session_client_load;
00258 ss->save = session_client_save;
00259 ss->remove = session_client_remove;
00260 ss->term = session_client_term;
00261 ss->mtime = time(0);
00262 ss->so = so;
00263
00264 dbg_err_if(session_prv_init(ss, rq, rs));
00265
00266 *pss = ss;
00267
00268 return 0;
00269 err:
00270 if(ss)
00271 session_free(ss);
00272 return ~0;
00273 }
00274
00275
00276 int session_client_module_init(u_config_t *config, session_opt_t *so)
00277 {
00278 u_config_t *c;
00279 const char *v;
00280
00281
00282 dbg_err_if (so == NULL);
00283
00284
00285 so->hash = EVP_sha1();
00286
00287
00288 if(!so->encrypt)
00289 warn("encryption is required for client side session");
00290 so->encrypt = 1;
00291
00292 if(config && !u_config_get_subkey(config, "client", &c))
00293 {
00294 if((v = u_config_get_subkey_value(c, "hash_function")) != NULL)
00295 {
00296 if(!strcasecmp(v, "md5"))
00297 so->hash = EVP_md5();
00298 else if(!strcasecmp(v, "sha1"))
00299 so->hash = EVP_sha1();
00300 #ifdef SSL_OPENSSL
00301 else if(!strcasecmp(v, "ripemd160"))
00302 so->hash = EVP_ripemd160();
00303 #endif
00304 else
00305 warn_err("config error: bad hash_function");
00306 }
00307 }
00308
00309 #ifdef SSL_OPENSSL
00310
00311 HMAC_CTX_init(&so->hmac_ctx);
00312
00313
00314 dbg_err_if(!RAND_bytes(so->hmac_key, HMAC_KEY_LEN));
00315
00316
00317 HMAC_Init_ex(&so->hmac_ctx, so->hmac_key, HMAC_KEY_LEN, so->hash, NULL);
00318 #endif
00319
00320 #ifdef SSL_CYASSL
00321
00322 dbg_err_if(!RAND_bytes(so->hmac_key, HMAC_KEY_LEN));
00323
00324 if(strcmp(so->hash, "MD5") == 0)
00325 HmacSetKey(&so->hmac_ctx, MD5, so->hmac_key, HMAC_KEY_LEN);
00326 else if(strcmp(so->hash, "SHA") == 0)
00327 HmacSetKey(&so->hmac_ctx, SHA, so->hmac_key, HMAC_KEY_LEN);
00328 #endif
00329
00330 return 0;
00331 err:
00332 return ~0;
00333 }
00334
00335