diff options
Diffstat (limited to 'src/lib/libssl/ssl_sess.c')
| -rw-r--r-- | src/lib/libssl/ssl_sess.c | 431 |
1 files changed, 297 insertions, 134 deletions
diff --git a/src/lib/libssl/ssl_sess.c b/src/lib/libssl/ssl_sess.c index 8212600e40..6424f775e2 100644 --- a/src/lib/libssl/ssl_sess.c +++ b/src/lib/libssl/ssl_sess.c | |||
| @@ -57,60 +57,57 @@ | |||
| 57 | */ | 57 | */ |
| 58 | 58 | ||
| 59 | #include <stdio.h> | 59 | #include <stdio.h> |
| 60 | #include "lhash.h" | 60 | #include <openssl/lhash.h> |
| 61 | #include "rand.h" | 61 | #include <openssl/rand.h> |
| 62 | #include "ssl_locl.h" | 62 | #include "ssl_locl.h" |
| 63 | 63 | ||
| 64 | #ifndef NOPROTO | ||
| 65 | static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); | 64 | static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s); |
| 66 | static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s); | 65 | static void SSL_SESSION_list_add(SSL_CTX *ctx,SSL_SESSION *s); |
| 67 | #else | 66 | static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck); |
| 68 | static void SSL_SESSION_list_remove(); | ||
| 69 | static void SSL_SESSION_list_add(); | ||
| 70 | #endif | ||
| 71 | |||
| 72 | static ssl_session_num=0; | ||
| 73 | static STACK *ssl_session_meth=NULL; | ||
| 74 | 67 | ||
| 75 | SSL_SESSION *SSL_get_session(ssl) | 68 | SSL_SESSION *SSL_get_session(SSL *ssl) |
| 76 | SSL *ssl; | 69 | /* aka SSL_get0_session; gets 0 objects, just returns a copy of the pointer */ |
| 77 | { | 70 | { |
| 78 | return(ssl->session); | 71 | return(ssl->session); |
| 79 | } | 72 | } |
| 80 | 73 | ||
| 81 | int SSL_SESSION_get_ex_new_index(argl,argp,new_func,dup_func,free_func) | 74 | SSL_SESSION *SSL_get1_session(SSL *ssl) |
| 82 | long argl; | 75 | /* variant of SSL_get_session: caller really gets something */ |
| 83 | char *argp; | 76 | { |
| 84 | int (*new_func)(); | 77 | SSL_SESSION *sess; |
| 85 | int (*dup_func)(); | 78 | /* Need to lock this all up rather than just use CRYPTO_add so that |
| 86 | void (*free_func)(); | 79 | * somebody doesn't free ssl->session between when we check it's |
| 87 | { | 80 | * non-null and when we up the reference count. */ |
| 88 | ssl_session_num++; | 81 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_SESSION); |
| 89 | return(CRYPTO_get_ex_new_index(ssl_session_num-1, | 82 | sess = ssl->session; |
| 90 | &ssl_session_meth, | 83 | if(sess) |
| 91 | argl,argp,new_func,dup_func,free_func)); | 84 | sess->references++; |
| 92 | } | 85 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_SESSION); |
| 93 | 86 | return(sess); | |
| 94 | int SSL_SESSION_set_ex_data(s,idx,arg) | 87 | } |
| 95 | SSL_SESSION *s; | 88 | |
| 96 | int idx; | 89 | int SSL_SESSION_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func, |
| 97 | char *arg; | 90 | CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func) |
| 91 | { | ||
| 92 | return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_SSL_SESSION, argl, argp, | ||
| 93 | new_func, dup_func, free_func); | ||
| 94 | } | ||
| 95 | |||
| 96 | int SSL_SESSION_set_ex_data(SSL_SESSION *s, int idx, void *arg) | ||
| 98 | { | 97 | { |
| 99 | return(CRYPTO_set_ex_data(&s->ex_data,idx,arg)); | 98 | return(CRYPTO_set_ex_data(&s->ex_data,idx,arg)); |
| 100 | } | 99 | } |
| 101 | 100 | ||
| 102 | char *SSL_SESSION_get_ex_data(s,idx) | 101 | void *SSL_SESSION_get_ex_data(SSL_SESSION *s, int idx) |
| 103 | SSL_SESSION *s; | ||
| 104 | int idx; | ||
| 105 | { | 102 | { |
| 106 | return(CRYPTO_get_ex_data(&s->ex_data,idx)); | 103 | return(CRYPTO_get_ex_data(&s->ex_data,idx)); |
| 107 | } | 104 | } |
| 108 | 105 | ||
| 109 | SSL_SESSION *SSL_SESSION_new() | 106 | SSL_SESSION *SSL_SESSION_new(void) |
| 110 | { | 107 | { |
| 111 | SSL_SESSION *ss; | 108 | SSL_SESSION *ss; |
| 112 | 109 | ||
| 113 | ss=(SSL_SESSION *)Malloc(sizeof(SSL_SESSION)); | 110 | ss=(SSL_SESSION *)OPENSSL_malloc(sizeof(SSL_SESSION)); |
| 114 | if (ss == NULL) | 111 | if (ss == NULL) |
| 115 | { | 112 | { |
| 116 | SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE); | 113 | SSLerr(SSL_F_SSL_SESSION_NEW,ERR_R_MALLOC_FAILURE); |
| @@ -118,26 +115,64 @@ SSL_SESSION *SSL_SESSION_new() | |||
| 118 | } | 115 | } |
| 119 | memset(ss,0,sizeof(SSL_SESSION)); | 116 | memset(ss,0,sizeof(SSL_SESSION)); |
| 120 | 117 | ||
| 118 | ss->verify_result = 1; /* avoid 0 (= X509_V_OK) just in case */ | ||
| 121 | ss->references=1; | 119 | ss->references=1; |
| 122 | ss->timeout=60*5+4; /* 5 minute timeout by default */ | 120 | ss->timeout=60*5+4; /* 5 minute timeout by default */ |
| 123 | ss->time=time(NULL); | 121 | ss->time=time(NULL); |
| 124 | ss->prev=NULL; | 122 | ss->prev=NULL; |
| 125 | ss->next=NULL; | 123 | ss->next=NULL; |
| 126 | CRYPTO_new_ex_data(ssl_session_meth,(char *)ss,&ss->ex_data); | 124 | ss->compress_meth=0; |
| 125 | CRYPTO_new_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); | ||
| 127 | return(ss); | 126 | return(ss); |
| 128 | } | 127 | } |
| 129 | 128 | ||
| 130 | int ssl_get_new_session(s, session) | 129 | /* Even with SSLv2, we have 16 bytes (128 bits) of session ID space. SSLv3/TLSv1 |
| 131 | SSL *s; | 130 | * has 32 bytes (256 bits). As such, filling the ID with random gunk repeatedly |
| 132 | int session; | 131 | * until we have no conflict is going to complete in one iteration pretty much |
| 132 | * "most" of the time (btw: understatement). So, if it takes us 10 iterations | ||
| 133 | * and we still can't avoid a conflict - well that's a reasonable point to call | ||
| 134 | * it quits. Either the RAND code is broken or someone is trying to open roughly | ||
| 135 | * very close to 2^128 (or 2^256) SSL sessions to our server. How you might | ||
| 136 | * store that many sessions is perhaps a more interesting question ... */ | ||
| 137 | |||
| 138 | #define MAX_SESS_ID_ATTEMPTS 10 | ||
| 139 | static int def_generate_session_id(const SSL *ssl, unsigned char *id, | ||
| 140 | unsigned int *id_len) | ||
| 141 | { | ||
| 142 | unsigned int retry = 0; | ||
| 143 | do | ||
| 144 | RAND_pseudo_bytes(id, *id_len); | ||
| 145 | while(SSL_has_matching_session_id(ssl, id, *id_len) && | ||
| 146 | (++retry < MAX_SESS_ID_ATTEMPTS)); | ||
| 147 | if(retry < MAX_SESS_ID_ATTEMPTS) | ||
| 148 | return 1; | ||
| 149 | /* else - woops a session_id match */ | ||
| 150 | /* XXX We should also check the external cache -- | ||
| 151 | * but the probability of a collision is negligible, and | ||
| 152 | * we could not prevent the concurrent creation of sessions | ||
| 153 | * with identical IDs since we currently don't have means | ||
| 154 | * to atomically check whether a session ID already exists | ||
| 155 | * and make a reservation for it if it does not | ||
| 156 | * (this problem applies to the internal cache as well). | ||
| 157 | */ | ||
| 158 | return 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | int ssl_get_new_session(SSL *s, int session) | ||
| 133 | { | 162 | { |
| 163 | /* This gets used by clients and servers. */ | ||
| 164 | |||
| 165 | unsigned int tmp; | ||
| 134 | SSL_SESSION *ss=NULL; | 166 | SSL_SESSION *ss=NULL; |
| 167 | GEN_SESSION_CB cb = def_generate_session_id; | ||
| 135 | 168 | ||
| 136 | if ((ss=SSL_SESSION_new()) == NULL) return(0); | 169 | if ((ss=SSL_SESSION_new()) == NULL) return(0); |
| 137 | 170 | ||
| 138 | /* If the context has a default timeout, use it */ | 171 | /* If the context has a default timeout, use it */ |
| 139 | if (s->ctx->session_timeout != 0) | 172 | if (s->ctx->session_timeout == 0) |
| 140 | ss->timeout=SSL_get_default_timeout(s); | 173 | ss->timeout=SSL_get_default_timeout(s); |
| 174 | else | ||
| 175 | ss->timeout=s->ctx->session_timeout; | ||
| 141 | 176 | ||
| 142 | if (s->session != NULL) | 177 | if (s->session != NULL) |
| 143 | { | 178 | { |
| @@ -147,7 +182,7 @@ int session; | |||
| 147 | 182 | ||
| 148 | if (session) | 183 | if (session) |
| 149 | { | 184 | { |
| 150 | if (s->version == SSL2_CLIENT_VERSION) | 185 | if (s->version == SSL2_VERSION) |
| 151 | { | 186 | { |
| 152 | ss->ssl_version=SSL2_VERSION; | 187 | ss->ssl_version=SSL2_VERSION; |
| 153 | ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH; | 188 | ss->session_id_length=SSL2_SSL_SESSION_ID_LENGTH; |
| @@ -168,18 +203,46 @@ int session; | |||
| 168 | SSL_SESSION_free(ss); | 203 | SSL_SESSION_free(ss); |
| 169 | return(0); | 204 | return(0); |
| 170 | } | 205 | } |
| 171 | 206 | /* Choose which callback will set the session ID */ | |
| 172 | for (;;) | 207 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); |
| 208 | if(s->generate_session_id) | ||
| 209 | cb = s->generate_session_id; | ||
| 210 | else if(s->ctx->generate_session_id) | ||
| 211 | cb = s->ctx->generate_session_id; | ||
| 212 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); | ||
| 213 | /* Choose a session ID */ | ||
| 214 | tmp = ss->session_id_length; | ||
| 215 | if(!cb(s, ss->session_id, &tmp)) | ||
| 216 | { | ||
| 217 | /* The callback failed */ | ||
| 218 | SSLerr(SSL_F_SSL_GET_NEW_SESSION, | ||
| 219 | SSL_R_SSL_SESSION_ID_CALLBACK_FAILED); | ||
| 220 | SSL_SESSION_free(ss); | ||
| 221 | return(0); | ||
| 222 | } | ||
| 223 | /* Don't allow the callback to set the session length to zero. | ||
| 224 | * nor set it higher than it was. */ | ||
| 225 | if(!tmp || (tmp > ss->session_id_length)) | ||
| 226 | { | ||
| 227 | /* The callback set an illegal length */ | ||
| 228 | SSLerr(SSL_F_SSL_GET_NEW_SESSION, | ||
| 229 | SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH); | ||
| 230 | SSL_SESSION_free(ss); | ||
| 231 | return(0); | ||
| 232 | } | ||
| 233 | /* If the session length was shrunk and we're SSLv2, pad it */ | ||
| 234 | if((tmp < ss->session_id_length) && (s->version == SSL2_VERSION)) | ||
| 235 | memset(ss->session_id + tmp, 0, ss->session_id_length - tmp); | ||
| 236 | else | ||
| 237 | ss->session_id_length = tmp; | ||
| 238 | /* Finally, check for a conflict */ | ||
| 239 | if(SSL_has_matching_session_id(s, ss->session_id, | ||
| 240 | ss->session_id_length)) | ||
| 173 | { | 241 | { |
| 174 | SSL_SESSION *r; | 242 | SSLerr(SSL_F_SSL_GET_NEW_SESSION, |
| 175 | 243 | SSL_R_SSL_SESSION_ID_CONFLICT); | |
| 176 | RAND_bytes(ss->session_id,ss->session_id_length); | 244 | SSL_SESSION_free(ss); |
| 177 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); | 245 | return(0); |
| 178 | r=(SSL_SESSION *)lh_retrieve(s->ctx->sessions, | ||
| 179 | (char *)ss); | ||
| 180 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); | ||
| 181 | if (r == NULL) break; | ||
| 182 | /* else - woops a session_id match */ | ||
| 183 | } | 246 | } |
| 184 | } | 247 | } |
| 185 | else | 248 | else |
| @@ -187,58 +250,100 @@ int session; | |||
| 187 | ss->session_id_length=0; | 250 | ss->session_id_length=0; |
| 188 | } | 251 | } |
| 189 | 252 | ||
| 253 | memcpy(ss->sid_ctx,s->sid_ctx,s->sid_ctx_length); | ||
| 254 | ss->sid_ctx_length=s->sid_ctx_length; | ||
| 190 | s->session=ss; | 255 | s->session=ss; |
| 191 | ss->ssl_version=s->version; | 256 | ss->ssl_version=s->version; |
| 257 | ss->verify_result = X509_V_OK; | ||
| 192 | 258 | ||
| 193 | return(1); | 259 | return(1); |
| 194 | } | 260 | } |
| 195 | 261 | ||
| 196 | int ssl_get_prev_session(s,session_id,len) | 262 | int ssl_get_prev_session(SSL *s, unsigned char *session_id, int len) |
| 197 | SSL *s; | ||
| 198 | unsigned char *session_id; | ||
| 199 | int len; | ||
| 200 | { | 263 | { |
| 264 | /* This is used only by servers. */ | ||
| 265 | |||
| 201 | SSL_SESSION *ret=NULL,data; | 266 | SSL_SESSION *ret=NULL,data; |
| 267 | int fatal = 0; | ||
| 202 | 268 | ||
| 203 | /* conn_init();*/ | ||
| 204 | data.ssl_version=s->version; | 269 | data.ssl_version=s->version; |
| 205 | data.session_id_length=len; | 270 | data.session_id_length=len; |
| 206 | if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) | 271 | if (len > SSL_MAX_SSL_SESSION_ID_LENGTH) |
| 207 | return(0); | 272 | goto err; |
| 208 | memcpy(data.session_id,session_id,len);; | 273 | memcpy(data.session_id,session_id,len); |
| 209 | 274 | ||
| 210 | if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) | 275 | if (!(s->ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP)) |
| 211 | { | 276 | { |
| 212 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); | 277 | CRYPTO_r_lock(CRYPTO_LOCK_SSL_CTX); |
| 213 | ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,(char *)&data); | 278 | ret=(SSL_SESSION *)lh_retrieve(s->ctx->sessions,&data); |
| 279 | if (ret != NULL) | ||
| 280 | /* don't allow other threads to steal it: */ | ||
| 281 | CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); | ||
| 214 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); | 282 | CRYPTO_r_unlock(CRYPTO_LOCK_SSL_CTX); |
| 215 | } | 283 | } |
| 216 | 284 | ||
| 217 | if (ret == NULL) | 285 | if (ret == NULL) |
| 218 | { | 286 | { |
| 219 | int copy=1; | 287 | int copy=1; |
| 220 | 288 | ||
| 221 | s->ctx->sess_miss++; | 289 | s->ctx->stats.sess_miss++; |
| 222 | ret=NULL; | 290 | ret=NULL; |
| 223 | if ((s->ctx->get_session_cb != NULL) && | 291 | if (s->ctx->get_session_cb != NULL |
| 224 | ((ret=s->ctx->get_session_cb(s,session_id,len,©)) | 292 | && (ret=s->ctx->get_session_cb(s,session_id,len,©)) |
| 225 | != NULL)) | 293 | != NULL) |
| 226 | { | 294 | { |
| 227 | s->ctx->sess_cb_hit++; | 295 | s->ctx->stats.sess_cb_hit++; |
| 296 | |||
| 297 | /* Increment reference count now if the session callback | ||
| 298 | * asks us to do so (note that if the session structures | ||
| 299 | * returned by the callback are shared between threads, | ||
| 300 | * it must handle the reference count itself [i.e. copy == 0], | ||
| 301 | * or things won't be thread-safe). */ | ||
| 302 | if (copy) | ||
| 303 | CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); | ||
| 228 | 304 | ||
| 229 | /* The following should not return 1, otherwise, | 305 | /* The following should not return 1, otherwise, |
| 230 | * things are very strange */ | 306 | * things are very strange */ |
| 231 | SSL_CTX_add_session(s->ctx,ret); | 307 | SSL_CTX_add_session(s->ctx,ret); |
| 232 | /* auto free it */ | ||
| 233 | if (!copy) | ||
| 234 | SSL_SESSION_free(ret); | ||
| 235 | } | 308 | } |
| 236 | if (ret == NULL) return(0); | 309 | if (ret == NULL) |
| 310 | goto err; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* Now ret is non-NULL, and we own one of its reference counts. */ | ||
| 314 | |||
| 315 | if((s->verify_mode&SSL_VERIFY_PEER) | ||
| 316 | && (!s->sid_ctx_length || ret->sid_ctx_length != s->sid_ctx_length | ||
| 317 | || memcmp(ret->sid_ctx,s->sid_ctx,ret->sid_ctx_length))) | ||
| 318 | { | ||
| 319 | /* We've found the session named by the client, but we don't | ||
| 320 | * want to use it in this context. */ | ||
| 321 | |||
| 322 | if (s->sid_ctx_length == 0) | ||
| 323 | { | ||
| 324 | /* application should have used SSL[_CTX]_set_session_id_context | ||
| 325 | * -- we could tolerate this and just pretend we never heard | ||
| 326 | * of this session, but then applications could effectively | ||
| 327 | * disable the session cache by accident without anyone noticing */ | ||
| 328 | |||
| 329 | SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED); | ||
| 330 | fatal = 1; | ||
| 331 | goto err; | ||
| 332 | } | ||
| 333 | else | ||
| 334 | { | ||
| 335 | #if 0 /* The client cannot always know when a session is not appropriate, | ||
| 336 | * so we shouldn't generate an error message. */ | ||
| 337 | |||
| 338 | SSLerr(SSL_F_SSL_GET_PREV_SESSION,SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT); | ||
| 339 | #endif | ||
| 340 | goto err; /* treat like cache miss */ | ||
| 341 | } | ||
| 237 | } | 342 | } |
| 238 | 343 | ||
| 239 | if (ret->cipher == NULL) | 344 | if (ret->cipher == NULL) |
| 240 | { | 345 | { |
| 241 | char buf[5],*p; | 346 | unsigned char buf[5],*p; |
| 242 | unsigned long l; | 347 | unsigned long l; |
| 243 | 348 | ||
| 244 | p=buf; | 349 | p=buf; |
| @@ -249,25 +354,28 @@ int len; | |||
| 249 | else | 354 | else |
| 250 | ret->cipher=ssl_get_cipher_by_char(s,&(buf[1])); | 355 | ret->cipher=ssl_get_cipher_by_char(s,&(buf[1])); |
| 251 | if (ret->cipher == NULL) | 356 | if (ret->cipher == NULL) |
| 252 | return(0); | 357 | goto err; |
| 253 | } | 358 | } |
| 254 | 359 | ||
| 360 | |||
| 361 | #if 0 /* This is way too late. */ | ||
| 362 | |||
| 255 | /* If a thread got the session, then 'swaped', and another got | 363 | /* If a thread got the session, then 'swaped', and another got |
| 256 | * it and then due to a time-out decided to 'Free' it we could | 364 | * it and then due to a time-out decided to 'OPENSSL_free' it we could |
| 257 | * be in trouble. So I'll increment it now, then double decrement | 365 | * be in trouble. So I'll increment it now, then double decrement |
| 258 | * later - am I speaking rubbish?. */ | 366 | * later - am I speaking rubbish?. */ |
| 259 | CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); | 367 | CRYPTO_add(&ret->references,1,CRYPTO_LOCK_SSL_SESSION); |
| 368 | #endif | ||
| 260 | 369 | ||
| 261 | if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */ | 370 | if ((long)(ret->time+ret->timeout) < (long)time(NULL)) /* timeout */ |
| 262 | { | 371 | { |
| 263 | s->ctx->sess_timeout++; | 372 | s->ctx->stats.sess_timeout++; |
| 264 | /* remove it from the cache */ | 373 | /* remove it from the cache */ |
| 265 | SSL_CTX_remove_session(s->ctx,ret); | 374 | SSL_CTX_remove_session(s->ctx,ret); |
| 266 | SSL_SESSION_free(ret); /* again to actually Free it */ | 375 | goto err; |
| 267 | return(0); | ||
| 268 | } | 376 | } |
| 269 | 377 | ||
| 270 | s->ctx->sess_hit++; | 378 | s->ctx->stats.sess_hit++; |
| 271 | 379 | ||
| 272 | /* ret->time=time(NULL); */ /* rezero timeout? */ | 380 | /* ret->time=time(NULL); */ /* rezero timeout? */ |
| 273 | /* again, just leave the session | 381 | /* again, just leave the session |
| @@ -276,37 +384,64 @@ int len; | |||
| 276 | if (s->session != NULL) | 384 | if (s->session != NULL) |
| 277 | SSL_SESSION_free(s->session); | 385 | SSL_SESSION_free(s->session); |
| 278 | s->session=ret; | 386 | s->session=ret; |
| 387 | s->verify_result = s->session->verify_result; | ||
| 279 | return(1); | 388 | return(1); |
| 389 | |||
| 390 | err: | ||
| 391 | if (ret != NULL) | ||
| 392 | SSL_SESSION_free(ret); | ||
| 393 | if (fatal) | ||
| 394 | return -1; | ||
| 395 | else | ||
| 396 | return 0; | ||
| 280 | } | 397 | } |
| 281 | 398 | ||
| 282 | int SSL_CTX_add_session(ctx,c) | 399 | int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) |
| 283 | SSL_CTX *ctx; | ||
| 284 | SSL_SESSION *c; | ||
| 285 | { | 400 | { |
| 286 | int ret=0; | 401 | int ret=0; |
| 287 | SSL_SESSION *s; | 402 | SSL_SESSION *s; |
| 288 | 403 | ||
| 289 | /* conn_init(); */ | 404 | /* add just 1 reference count for the SSL_CTX's session cache |
| 405 | * even though it has two ways of access: each session is in a | ||
| 406 | * doubly linked list and an lhash */ | ||
| 290 | CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION); | 407 | CRYPTO_add(&c->references,1,CRYPTO_LOCK_SSL_SESSION); |
| 408 | /* if session c is in already in cache, we take back the increment later */ | ||
| 291 | 409 | ||
| 292 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | 410 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
| 293 | s=(SSL_SESSION *)lh_insert(ctx->sessions,(char *)c); | 411 | s=(SSL_SESSION *)lh_insert(ctx->sessions,c); |
| 294 | 412 | ||
| 295 | /* Put on the end of the queue unless it is already in the cache */ | 413 | /* s != NULL iff we already had a session with the given PID. |
| 414 | * In this case, s == c should hold (then we did not really modify | ||
| 415 | * ctx->sessions), or we're in trouble. */ | ||
| 416 | if (s != NULL && s != c) | ||
| 417 | { | ||
| 418 | /* We *are* in trouble ... */ | ||
| 419 | SSL_SESSION_list_remove(ctx,s); | ||
| 420 | SSL_SESSION_free(s); | ||
| 421 | /* ... so pretend the other session did not exist in cache | ||
| 422 | * (we cannot handle two SSL_SESSION structures with identical | ||
| 423 | * session ID in the same cache, which could happen e.g. when | ||
| 424 | * two threads concurrently obtain the same session from an external | ||
| 425 | * cache) */ | ||
| 426 | s = NULL; | ||
| 427 | } | ||
| 428 | |||
| 429 | /* Put at the head of the queue unless it is already in the cache */ | ||
| 296 | if (s == NULL) | 430 | if (s == NULL) |
| 297 | SSL_SESSION_list_add(ctx,c); | 431 | SSL_SESSION_list_add(ctx,c); |
| 298 | 432 | ||
| 299 | /* If the same session if is being 're-added', Free the old | ||
| 300 | * one when the last person stops using it. | ||
| 301 | * This will also work if it is alread in the cache. | ||
| 302 | * The references will go up and then down :-) */ | ||
| 303 | if (s != NULL) | 433 | if (s != NULL) |
| 304 | { | 434 | { |
| 305 | SSL_SESSION_free(s); | 435 | /* existing cache entry -- decrement previously incremented reference |
| 436 | * count because it already takes into account the cache */ | ||
| 437 | |||
| 438 | SSL_SESSION_free(s); /* s == c */ | ||
| 306 | ret=0; | 439 | ret=0; |
| 307 | } | 440 | } |
| 308 | else | 441 | else |
| 309 | { | 442 | { |
| 443 | /* new cache entry -- remove old ones if cache has become too large */ | ||
| 444 | |||
| 310 | ret=1; | 445 | ret=1; |
| 311 | 446 | ||
| 312 | if (SSL_CTX_sess_get_cache_size(ctx) > 0) | 447 | if (SSL_CTX_sess_get_cache_size(ctx) > 0) |
| @@ -314,11 +449,11 @@ SSL_SESSION *c; | |||
| 314 | while (SSL_CTX_sess_number(ctx) > | 449 | while (SSL_CTX_sess_number(ctx) > |
| 315 | SSL_CTX_sess_get_cache_size(ctx)) | 450 | SSL_CTX_sess_get_cache_size(ctx)) |
| 316 | { | 451 | { |
| 317 | if (!SSL_CTX_remove_session(ctx, | 452 | if (!remove_session_lock(ctx, |
| 318 | ctx->session_cache_tail)) | 453 | ctx->session_cache_tail, 0)) |
| 319 | break; | 454 | break; |
| 320 | else | 455 | else |
| 321 | ctx->sess_cache_full++; | 456 | ctx->stats.sess_cache_full++; |
| 322 | } | 457 | } |
| 323 | } | 458 | } |
| 324 | } | 459 | } |
| @@ -326,24 +461,27 @@ SSL_SESSION *c; | |||
| 326 | return(ret); | 461 | return(ret); |
| 327 | } | 462 | } |
| 328 | 463 | ||
| 329 | int SSL_CTX_remove_session(ctx,c) | 464 | int SSL_CTX_remove_session(SSL_CTX *ctx, SSL_SESSION *c) |
| 330 | SSL_CTX *ctx; | 465 | { |
| 331 | SSL_SESSION *c; | 466 | return remove_session_lock(ctx, c, 1); |
| 467 | } | ||
| 468 | |||
| 469 | static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *c, int lck) | ||
| 332 | { | 470 | { |
| 333 | SSL_SESSION *r; | 471 | SSL_SESSION *r; |
| 334 | int ret=0; | 472 | int ret=0; |
| 335 | 473 | ||
| 336 | if ((c != NULL) && (c->session_id_length != 0)) | 474 | if ((c != NULL) && (c->session_id_length != 0)) |
| 337 | { | 475 | { |
| 338 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | 476 | if(lck) CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
| 339 | r=(SSL_SESSION *)lh_delete(ctx->sessions,(char *)c); | 477 | if ((r = (SSL_SESSION *)lh_retrieve(ctx->sessions,c)) == c) |
| 340 | if (r != NULL) | ||
| 341 | { | 478 | { |
| 342 | ret=1; | 479 | ret=1; |
| 480 | r=(SSL_SESSION *)lh_delete(ctx->sessions,c); | ||
| 343 | SSL_SESSION_list_remove(ctx,c); | 481 | SSL_SESSION_list_remove(ctx,c); |
| 344 | } | 482 | } |
| 345 | 483 | ||
| 346 | CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); | 484 | if(lck) CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); |
| 347 | 485 | ||
| 348 | if (ret) | 486 | if (ret) |
| 349 | { | 487 | { |
| @@ -358,11 +496,13 @@ SSL_SESSION *c; | |||
| 358 | return(ret); | 496 | return(ret); |
| 359 | } | 497 | } |
| 360 | 498 | ||
| 361 | void SSL_SESSION_free(ss) | 499 | void SSL_SESSION_free(SSL_SESSION *ss) |
| 362 | SSL_SESSION *ss; | ||
| 363 | { | 500 | { |
| 364 | int i; | 501 | int i; |
| 365 | 502 | ||
| 503 | if(ss == NULL) | ||
| 504 | return; | ||
| 505 | |||
| 366 | i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION); | 506 | i=CRYPTO_add(&ss->references,-1,CRYPTO_LOCK_SSL_SESSION); |
| 367 | #ifdef REF_PRINT | 507 | #ifdef REF_PRINT |
| 368 | REF_PRINT("SSL_SESSION",ss); | 508 | REF_PRINT("SSL_SESSION",ss); |
| @@ -376,21 +516,19 @@ SSL_SESSION *ss; | |||
| 376 | } | 516 | } |
| 377 | #endif | 517 | #endif |
| 378 | 518 | ||
| 379 | CRYPTO_free_ex_data(ssl_session_meth,(char *)ss,&ss->ex_data); | 519 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_SSL_SESSION, ss, &ss->ex_data); |
| 380 | 520 | ||
| 381 | memset(ss->key_arg,0,SSL_MAX_KEY_ARG_LENGTH); | 521 | memset(ss->key_arg,0,SSL_MAX_KEY_ARG_LENGTH); |
| 382 | memset(ss->master_key,0,SSL_MAX_MASTER_KEY_LENGTH); | 522 | memset(ss->master_key,0,SSL_MAX_MASTER_KEY_LENGTH); |
| 383 | memset(ss->session_id,0,SSL_MAX_SSL_SESSION_ID_LENGTH); | 523 | memset(ss->session_id,0,SSL_MAX_SSL_SESSION_ID_LENGTH); |
| 384 | if (ss->cert != NULL) ssl_cert_free(ss->cert); | 524 | if (ss->sess_cert != NULL) ssl_sess_cert_free(ss->sess_cert); |
| 385 | if (ss->peer != NULL) X509_free(ss->peer); | 525 | if (ss->peer != NULL) X509_free(ss->peer); |
| 386 | if (ss->ciphers != NULL) sk_free(ss->ciphers); | 526 | if (ss->ciphers != NULL) sk_SSL_CIPHER_free(ss->ciphers); |
| 387 | memset(ss,0,sizeof(*ss)); | 527 | memset(ss,0,sizeof(*ss)); |
| 388 | Free(ss); | 528 | OPENSSL_free(ss); |
| 389 | } | 529 | } |
| 390 | 530 | ||
| 391 | int SSL_set_session(s, session) | 531 | int SSL_set_session(SSL *s, SSL_SESSION *session) |
| 392 | SSL *s; | ||
| 393 | SSL_SESSION *session; | ||
| 394 | { | 532 | { |
| 395 | int ret=0; | 533 | int ret=0; |
| 396 | SSL_METHOD *meth; | 534 | SSL_METHOD *meth; |
| @@ -410,14 +548,29 @@ SSL_SESSION *session; | |||
| 410 | { | 548 | { |
| 411 | if (!SSL_set_ssl_method(s,meth)) | 549 | if (!SSL_set_ssl_method(s,meth)) |
| 412 | return(0); | 550 | return(0); |
| 413 | session->timeout=SSL_get_default_timeout(s); | 551 | if (s->ctx->session_timeout == 0) |
| 552 | session->timeout=SSL_get_default_timeout(s); | ||
| 553 | else | ||
| 554 | session->timeout=s->ctx->session_timeout; | ||
| 414 | } | 555 | } |
| 415 | 556 | ||
| 557 | #ifndef OPENSSL_NO_KRB5 | ||
| 558 | if (s->kssl_ctx && !s->kssl_ctx->client_princ && | ||
| 559 | session->krb5_client_princ_len > 0) | ||
| 560 | { | ||
| 561 | s->kssl_ctx->client_princ = (char *)malloc(session->krb5_client_princ_len + 1); | ||
| 562 | memcpy(s->kssl_ctx->client_princ,session->krb5_client_princ, | ||
| 563 | session->krb5_client_princ_len); | ||
| 564 | s->kssl_ctx->client_princ[session->krb5_client_princ_len] = '\0'; | ||
| 565 | } | ||
| 566 | #endif /* OPENSSL_NO_KRB5 */ | ||
| 567 | |||
| 416 | /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/ | 568 | /* CRYPTO_w_lock(CRYPTO_LOCK_SSL);*/ |
| 417 | CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION); | 569 | CRYPTO_add(&session->references,1,CRYPTO_LOCK_SSL_SESSION); |
| 418 | if (s->session != NULL) | 570 | if (s->session != NULL) |
| 419 | SSL_SESSION_free(s->session); | 571 | SSL_SESSION_free(s->session); |
| 420 | s->session=session; | 572 | s->session=session; |
| 573 | s->verify_result = s->session->verify_result; | ||
| 421 | /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/ | 574 | /* CRYPTO_w_unlock(CRYPTO_LOCK_SSL);*/ |
| 422 | ret=1; | 575 | ret=1; |
| 423 | } | 576 | } |
| @@ -428,42 +581,59 @@ SSL_SESSION *session; | |||
| 428 | SSL_SESSION_free(s->session); | 581 | SSL_SESSION_free(s->session); |
| 429 | s->session=NULL; | 582 | s->session=NULL; |
| 430 | } | 583 | } |
| 584 | |||
| 585 | meth=s->ctx->method; | ||
| 586 | if (meth != s->method) | ||
| 587 | { | ||
| 588 | if (!SSL_set_ssl_method(s,meth)) | ||
| 589 | return(0); | ||
| 590 | } | ||
| 591 | ret=1; | ||
| 431 | } | 592 | } |
| 432 | return(ret); | 593 | return(ret); |
| 433 | } | 594 | } |
| 434 | 595 | ||
| 435 | long SSL_SESSION_set_timeout(s,t) | 596 | long SSL_SESSION_set_timeout(SSL_SESSION *s, long t) |
| 436 | SSL_SESSION *s; | ||
| 437 | long t; | ||
| 438 | { | 597 | { |
| 439 | if (s == NULL) return(0); | 598 | if (s == NULL) return(0); |
| 440 | s->timeout=t; | 599 | s->timeout=t; |
| 441 | return(1); | 600 | return(1); |
| 442 | } | 601 | } |
| 443 | 602 | ||
| 444 | long SSL_SESSION_get_timeout(s) | 603 | long SSL_SESSION_get_timeout(SSL_SESSION *s) |
| 445 | SSL_SESSION *s; | ||
| 446 | { | 604 | { |
| 447 | if (s == NULL) return(0); | 605 | if (s == NULL) return(0); |
| 448 | return(s->timeout); | 606 | return(s->timeout); |
| 449 | } | 607 | } |
| 450 | 608 | ||
| 451 | long SSL_SESSION_get_time(s) | 609 | long SSL_SESSION_get_time(SSL_SESSION *s) |
| 452 | SSL_SESSION *s; | ||
| 453 | { | 610 | { |
| 454 | if (s == NULL) return(0); | 611 | if (s == NULL) return(0); |
| 455 | return(s->time); | 612 | return(s->time); |
| 456 | } | 613 | } |
| 457 | 614 | ||
| 458 | long SSL_SESSION_set_time(s,t) | 615 | long SSL_SESSION_set_time(SSL_SESSION *s, long t) |
| 459 | SSL_SESSION *s; | ||
| 460 | long t; | ||
| 461 | { | 616 | { |
| 462 | if (s == NULL) return(0); | 617 | if (s == NULL) return(0); |
| 463 | s->time=t; | 618 | s->time=t; |
| 464 | return(t); | 619 | return(t); |
| 465 | } | 620 | } |
| 466 | 621 | ||
| 622 | long SSL_CTX_set_timeout(SSL_CTX *s, long t) | ||
| 623 | { | ||
| 624 | long l; | ||
| 625 | if (s == NULL) return(0); | ||
| 626 | l=s->session_timeout; | ||
| 627 | s->session_timeout=t; | ||
| 628 | return(l); | ||
| 629 | } | ||
| 630 | |||
| 631 | long SSL_CTX_get_timeout(SSL_CTX *s) | ||
| 632 | { | ||
| 633 | if (s == NULL) return(0); | ||
| 634 | return(s->session_timeout); | ||
| 635 | } | ||
| 636 | |||
| 467 | typedef struct timeout_param_st | 637 | typedef struct timeout_param_st |
| 468 | { | 638 | { |
| 469 | SSL_CTX *ctx; | 639 | SSL_CTX *ctx; |
| @@ -471,15 +641,13 @@ typedef struct timeout_param_st | |||
| 471 | LHASH *cache; | 641 | LHASH *cache; |
| 472 | } TIMEOUT_PARAM; | 642 | } TIMEOUT_PARAM; |
| 473 | 643 | ||
| 474 | static void timeout(s,p) | 644 | static void timeout(SSL_SESSION *s, TIMEOUT_PARAM *p) |
| 475 | SSL_SESSION *s; | ||
| 476 | TIMEOUT_PARAM *p; | ||
| 477 | { | 645 | { |
| 478 | if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */ | 646 | if ((p->time == 0) || (p->time > (s->time+s->timeout))) /* timeout */ |
| 479 | { | 647 | { |
| 480 | /* The reason we don't call SSL_CTX_remove_session() is to | 648 | /* The reason we don't call SSL_CTX_remove_session() is to |
| 481 | * save on locking overhead */ | 649 | * save on locking overhead */ |
| 482 | lh_delete(p->cache,(char *)s); | 650 | lh_delete(p->cache,s); |
| 483 | SSL_SESSION_list_remove(p->ctx,s); | 651 | SSL_SESSION_list_remove(p->ctx,s); |
| 484 | s->not_resumable=1; | 652 | s->not_resumable=1; |
| 485 | if (p->ctx->remove_session_cb != NULL) | 653 | if (p->ctx->remove_session_cb != NULL) |
| @@ -488,27 +656,26 @@ TIMEOUT_PARAM *p; | |||
| 488 | } | 656 | } |
| 489 | } | 657 | } |
| 490 | 658 | ||
| 491 | void SSL_CTX_flush_sessions(s,t) | 659 | static IMPLEMENT_LHASH_DOALL_ARG_FN(timeout, SSL_SESSION *, TIMEOUT_PARAM *) |
| 492 | SSL_CTX *s; | 660 | |
| 493 | long t; | 661 | void SSL_CTX_flush_sessions(SSL_CTX *s, long t) |
| 494 | { | 662 | { |
| 495 | unsigned long i; | 663 | unsigned long i; |
| 496 | TIMEOUT_PARAM tp; | 664 | TIMEOUT_PARAM tp; |
| 497 | 665 | ||
| 498 | tp.ctx=s; | 666 | tp.ctx=s; |
| 499 | tp.cache=SSL_CTX_sessions(s); | 667 | tp.cache=s->sessions; |
| 500 | if (tp.cache == NULL) return; | 668 | if (tp.cache == NULL) return; |
| 501 | tp.time=t; | 669 | tp.time=t; |
| 502 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); | 670 | CRYPTO_w_lock(CRYPTO_LOCK_SSL_CTX); |
| 503 | i=tp.cache->down_load; | 671 | i=tp.cache->down_load; |
| 504 | tp.cache->down_load=0; | 672 | tp.cache->down_load=0; |
| 505 | lh_doall_arg(tp.cache,(void (*)())timeout,(char *)&tp); | 673 | lh_doall_arg(tp.cache, LHASH_DOALL_ARG_FN(timeout), &tp); |
| 506 | tp.cache->down_load=i; | 674 | tp.cache->down_load=i; |
| 507 | CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); | 675 | CRYPTO_w_unlock(CRYPTO_LOCK_SSL_CTX); |
| 508 | } | 676 | } |
| 509 | 677 | ||
| 510 | int ssl_clear_bad_session(s) | 678 | int ssl_clear_bad_session(SSL *s) |
| 511 | SSL *s; | ||
| 512 | { | 679 | { |
| 513 | if ( (s->session != NULL) && | 680 | if ( (s->session != NULL) && |
| 514 | !(s->shutdown & SSL_SENT_SHUTDOWN) && | 681 | !(s->shutdown & SSL_SENT_SHUTDOWN) && |
| @@ -522,9 +689,7 @@ SSL *s; | |||
| 522 | } | 689 | } |
| 523 | 690 | ||
| 524 | /* locked by SSL_CTX in the calling function */ | 691 | /* locked by SSL_CTX in the calling function */ |
| 525 | static void SSL_SESSION_list_remove(ctx,s) | 692 | static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *s) |
| 526 | SSL_CTX *ctx; | ||
| 527 | SSL_SESSION *s; | ||
| 528 | { | 693 | { |
| 529 | if ((s->next == NULL) || (s->prev == NULL)) return; | 694 | if ((s->next == NULL) || (s->prev == NULL)) return; |
| 530 | 695 | ||
| @@ -557,9 +722,7 @@ SSL_SESSION *s; | |||
| 557 | s->prev=s->next=NULL; | 722 | s->prev=s->next=NULL; |
| 558 | } | 723 | } |
| 559 | 724 | ||
| 560 | static void SSL_SESSION_list_add(ctx,s) | 725 | static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *s) |
| 561 | SSL_CTX *ctx; | ||
| 562 | SSL_SESSION *s; | ||
| 563 | { | 726 | { |
| 564 | if ((s->next != NULL) && (s->prev != NULL)) | 727 | if ((s->next != NULL) && (s->prev != NULL)) |
| 565 | SSL_SESSION_list_remove(ctx,s); | 728 | SSL_SESSION_list_remove(ctx,s); |
