Line data Source code
1 : /* 2 : * Copyright (C) 2000-2012 Free Software Foundation, Inc. 3 : * 4 : * Author: Nikos Mavrogiannopoulos 5 : * 6 : * This file is part of GnuTLS. 7 : * 8 : * The GnuTLS is free software; you can redistribute it and/or 9 : * modify it under the terms of the GNU Lesser General Public License 10 : * as published by the Free Software Foundation; either version 2.1 of 11 : * the License, or (at your option) any later version. 12 : * 13 : * This library is distributed in the hope that it will be useful, but 14 : * WITHOUT ANY WARRANTY; without even the implied warranty of 15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 : * Lesser General Public License for more details. 17 : * 18 : * You should have received a copy of the GNU Lesser General Public License 19 : * along with this program. If not, see <https://www.gnu.org/licenses/> 20 : * 21 : */ 22 : 23 : /* This file contains functions that manipulate a database backend for 24 : * resumed sessions. 25 : */ 26 : 27 : #include "gnutls_int.h" 28 : #include "errors.h" 29 : #include <db.h> 30 : #include <session_pack.h> 31 : #include <datum.h> 32 : #include "ext/server_name.h" 33 : #include <intprops.h> 34 : 35 : /** 36 : * gnutls_db_set_retrieve_function: 37 : * @session: is a #gnutls_session_t type. 38 : * @retr_func: is the function. 39 : * 40 : * Sets the function that will be used to retrieve data from the 41 : * resumed sessions database. This function must return a 42 : * gnutls_datum_t containing the data on success, or a gnutls_datum_t 43 : * containing null and 0 on failure. 44 : * 45 : * The datum's data must be allocated using the function 46 : * gnutls_malloc(). 47 : * 48 : * The first argument to @retr_func will be null unless 49 : * gnutls_db_set_ptr() has been called. 50 : **/ 51 : void 52 11159 : gnutls_db_set_retrieve_function(gnutls_session_t session, 53 : gnutls_db_retr_func retr_func) 54 : { 55 11159 : session->internals.db_retrieve_func = retr_func; 56 11159 : } 57 : 58 : /** 59 : * gnutls_db_set_remove_function: 60 : * @session: is a #gnutls_session_t type. 61 : * @rem_func: is the function. 62 : * 63 : * Sets the function that will be used to remove data from the 64 : * resumed sessions database. This function must return 0 on success. 65 : * 66 : * The first argument to @rem_func will be null unless 67 : * gnutls_db_set_ptr() has been called. 68 : **/ 69 : void 70 11159 : gnutls_db_set_remove_function(gnutls_session_t session, 71 : gnutls_db_remove_func rem_func) 72 : { 73 11159 : session->internals.db_remove_func = rem_func; 74 11159 : } 75 : 76 : /** 77 : * gnutls_db_set_store_function: 78 : * @session: is a #gnutls_session_t type. 79 : * @store_func: is the function 80 : * 81 : * Sets the function that will be used to store data in the resumed 82 : * sessions database. This function must return 0 on success. 83 : * 84 : * The first argument to @store_func will be null unless 85 : * gnutls_db_set_ptr() has been called. 86 : **/ 87 : void 88 11159 : gnutls_db_set_store_function(gnutls_session_t session, 89 : gnutls_db_store_func store_func) 90 : { 91 11159 : session->internals.db_store_func = store_func; 92 11159 : } 93 : 94 : /** 95 : * gnutls_db_set_ptr: 96 : * @session: is a #gnutls_session_t type. 97 : * @ptr: is the pointer 98 : * 99 : * Sets the pointer that will be provided to db store, retrieve and 100 : * delete functions, as the first argument. 101 : **/ 102 11159 : void gnutls_db_set_ptr(gnutls_session_t session, void *ptr) 103 : { 104 11159 : session->internals.db_ptr = ptr; 105 11159 : } 106 : 107 : /** 108 : * gnutls_db_get_ptr: 109 : * @session: is a #gnutls_session_t type. 110 : * 111 : * Get db function pointer. 112 : * 113 : * Returns: the pointer that will be sent to db store, retrieve and 114 : * delete functions, as the first argument. 115 : **/ 116 0 : void *gnutls_db_get_ptr(gnutls_session_t session) 117 : { 118 0 : return session->internals.db_ptr; 119 : } 120 : 121 : /** 122 : * gnutls_db_set_cache_expiration: 123 : * @session: is a #gnutls_session_t type. 124 : * @seconds: is the number of seconds. 125 : * 126 : * Set the expiration time for resumed sessions. The default is 21600 127 : * (6 hours) at the time of writing. 128 : * 129 : * The maximum value that can be set using this function is 604800 130 : * (7 days). 131 : * 132 : **/ 133 147 : void gnutls_db_set_cache_expiration(gnutls_session_t session, int seconds) 134 : { 135 147 : session->internals.expire_time = seconds; 136 147 : if (session->internals.expire_time > 604800) 137 0 : session->internals.expire_time = 604800; 138 147 : } 139 : 140 : /** 141 : * gnutls_db_get_default_cache_expiration: 142 : * 143 : * Returns the expiration time (in seconds) of stored sessions for resumption. 144 : **/ 145 0 : unsigned gnutls_db_get_default_cache_expiration(void) 146 : { 147 0 : return DEFAULT_EXPIRE_TIME; 148 : } 149 : 150 : /** 151 : * gnutls_db_check_entry: 152 : * @session: is a #gnutls_session_t type. 153 : * @session_entry: is the session data (not key) 154 : * 155 : * This function has no effect. 156 : * 157 : * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has 158 : * expired or 0 otherwise. 159 : * 160 : * Deprecated: This function is deprecated. 161 : **/ 162 : int 163 0 : gnutls_db_check_entry(gnutls_session_t session, 164 : gnutls_datum_t session_entry) 165 : { 166 0 : return 0; 167 : } 168 : 169 : /** 170 : * gnutls_db_check_entry_time: 171 : * @entry: is a pointer to a #gnutls_datum_t type. 172 : * 173 : * This function returns the time that this entry was active. 174 : * It can be used for database entry expiration. 175 : * 176 : * Returns: The time this entry was created, or zero on error. 177 : **/ 178 513 : time_t gnutls_db_check_entry_time(gnutls_datum_t * entry) 179 : { 180 513 : uint32_t t; 181 513 : uint32_t magic; 182 : 183 513 : if (entry->size < 8) 184 0 : return gnutls_assert_val(0); 185 : 186 513 : magic = _gnutls_read_uint32(entry->data); 187 : 188 513 : if (magic != PACKED_SESSION_MAGIC) 189 0 : return gnutls_assert_val(0); 190 : 191 513 : t = _gnutls_read_uint32(&entry->data[4]); 192 : 193 513 : return t; 194 : } 195 : 196 : /** 197 : * gnutls_db_check_entry_expire_time: 198 : * @entry: is a pointer to a #gnutls_datum_t type. 199 : * 200 : * This function returns the time that this entry will expire. 201 : * It can be used for database entry expiration. 202 : * 203 : * Returns: The time this entry will expire, or zero on error. 204 : * 205 : * Since: 3.6.5 206 : **/ 207 5230 : time_t gnutls_db_check_entry_expire_time(gnutls_datum_t *entry) 208 : { 209 5230 : uint32_t t; 210 5230 : uint32_t e; 211 5230 : uint32_t magic; 212 : 213 5230 : if (entry->size < 12) 214 0 : return gnutls_assert_val(0); 215 : 216 5230 : magic = _gnutls_read_uint32(entry->data); 217 : 218 5230 : if (magic != PACKED_SESSION_MAGIC) 219 0 : return gnutls_assert_val(0); 220 : 221 5230 : t = _gnutls_read_uint32(&entry->data[4]); 222 5230 : e = _gnutls_read_uint32(&entry->data[8]); 223 : 224 5230 : if (INT_ADD_OVERFLOW(t, e)) 225 0 : return gnutls_assert_val(0); 226 : 227 5230 : return t + e; 228 : } 229 : 230 : /* Checks if both db_store and db_retrieve functions have 231 : * been set up. 232 : */ 233 7116 : static int db_func_is_ok(gnutls_session_t session) 234 : { 235 7116 : if (session->internals.db_store_func != NULL && 236 4133 : session->internals.db_retrieve_func != NULL) 237 : return 0; 238 : else 239 2983 : return GNUTLS_E_DB_ERROR; 240 : } 241 : 242 : /* Stores session data to the db backend. 243 : */ 244 : static int 245 5351 : store_session(gnutls_session_t session, 246 : gnutls_datum_t session_id, gnutls_datum_t session_data) 247 : { 248 5351 : int ret = 0; 249 : 250 5351 : if (db_func_is_ok(session) != 0) { 251 : return GNUTLS_E_DB_ERROR; 252 : } 253 : 254 3079 : if (session_data.data == NULL || session_data.size == 0) { 255 0 : gnutls_assert(); 256 0 : return GNUTLS_E_INVALID_SESSION; 257 : } 258 : 259 : /* if we can't read why bother writing? */ 260 3079 : ret = session->internals.db_store_func(session->internals.db_ptr, 261 : session_id, session_data); 262 : 263 3079 : return (ret == 0 ? ret : GNUTLS_E_DB_ERROR); 264 : } 265 : 266 5821 : int _gnutls_server_register_current_session(gnutls_session_t session) 267 : { 268 5821 : gnutls_datum_t key; 269 5821 : gnutls_datum_t content; 270 5821 : int ret = 0; 271 : 272 5821 : key.data = session->security_parameters.session_id; 273 5821 : key.size = session->security_parameters.session_id_size; 274 : 275 5821 : if (session->internals.resumable == RESUME_FALSE) { 276 0 : gnutls_assert(); 277 0 : return GNUTLS_E_INVALID_SESSION; 278 : } 279 : 280 5821 : if (session->security_parameters.session_id_size == 0) { 281 1 : gnutls_assert(); 282 1 : return GNUTLS_E_INVALID_SESSION; 283 : } 284 : 285 5820 : ret = _gnutls_session_pack(session, &content); 286 5820 : if (ret < 0) { 287 469 : gnutls_assert(); 288 469 : return ret; 289 : } 290 : 291 5351 : ret = store_session(session, key, content); 292 5351 : _gnutls_free_datum(&content); 293 : 294 5351 : return ret; 295 : } 296 : 297 1345 : int _gnutls_check_resumed_params(gnutls_session_t session) 298 : { 299 1345 : time_t timestamp = gnutls_time(0); 300 1345 : const version_entry_st *vers; 301 : 302 : /* check whether the session is expired */ 303 1345 : if (timestamp - 304 1345 : session->internals.resumed_security_parameters.timestamp > 305 1345 : session->internals.expire_time 306 1261 : || session->internals.resumed_security_parameters.timestamp > 307 : timestamp) 308 84 : return gnutls_assert_val(GNUTLS_E_EXPIRED); 309 : 310 : /* check various parameters applicable to resumption in TLS1.2 or earlier 311 : */ 312 1261 : vers = get_version(session); 313 1261 : if (!vers || !vers->tls13_sem) { 314 1087 : if (session->internals.resumed_security_parameters.ext_master_secret != 315 1087 : session->security_parameters.ext_master_secret) 316 278 : return gnutls_assert_val(GNUTLS_E_INVALID_SESSION); 317 : 318 810 : if (!_gnutls_server_name_matches_resumed(session)) 319 42 : return gnutls_assert_val(GNUTLS_E_INVALID_SESSION); 320 : } 321 : 322 : return 0; 323 : } 324 : 325 : int 326 11922 : _gnutls_server_restore_session(gnutls_session_t session, 327 : uint8_t * session_id, int session_id_size) 328 : { 329 11922 : gnutls_datum_t data; 330 11922 : gnutls_datum_t key; 331 11922 : int ret; 332 : 333 11922 : if (session_id == NULL || session_id_size == 0) { 334 10143 : gnutls_assert(); 335 10143 : return GNUTLS_E_INVALID_REQUEST; 336 : } 337 : 338 1779 : if (session->internals.premaster_set != 0) { /* hack for CISCO's DTLS-0.9 */ 339 14 : if (session_id_size == 340 14 : session->internals.resumed_security_parameters. 341 : session_id_size 342 14 : && memcmp(session_id, 343 : session->internals. 344 14 : resumed_security_parameters.session_id, 345 : session_id_size) == 0) 346 : return 0; 347 : } 348 : 349 1765 : key.data = session_id; 350 1765 : key.size = session_id_size; 351 : 352 1765 : if (db_func_is_ok(session) != 0) { 353 711 : gnutls_assert(); 354 711 : return GNUTLS_E_INVALID_SESSION; 355 : } 356 : 357 1054 : data = 358 1054 : session->internals.db_retrieve_func(session->internals.db_ptr, 359 : key); 360 : 361 1054 : if (data.data == NULL) { 362 382 : gnutls_assert(); 363 382 : return GNUTLS_E_INVALID_SESSION; 364 : } 365 : 366 672 : ret = gnutls_session_set_data(session, data.data, data.size); 367 672 : gnutls_free(data.data); 368 : 369 672 : if (ret < 0) { 370 0 : gnutls_assert(); 371 0 : return ret; 372 : } 373 : 374 : /* expiration check is performed inside */ 375 672 : ret = _gnutls_check_resumed_params(session); 376 672 : if (ret < 0) 377 200 : return gnutls_assert_val(ret); 378 : 379 : return 0; 380 : } 381 : 382 : /** 383 : * gnutls_db_remove_session: 384 : * @session: is a #gnutls_session_t type. 385 : * 386 : * This function will remove the current session data from the 387 : * session database. This will prevent future handshakes reusing 388 : * these session data. This function should be called if a session 389 : * was terminated abnormally, and before gnutls_deinit() is called. 390 : * 391 : * Normally gnutls_deinit() will remove abnormally terminated 392 : * sessions. 393 : **/ 394 0 : void gnutls_db_remove_session(gnutls_session_t session) 395 : { 396 0 : gnutls_datum_t session_id; 397 0 : int ret = 0; 398 : 399 0 : session_id.data = session->security_parameters.session_id; 400 0 : session_id.size = session->security_parameters.session_id_size; 401 : 402 0 : if (session->internals.db_remove_func == NULL) { 403 0 : gnutls_assert(); 404 0 : return /* GNUTLS_E_DB_ERROR */ ; 405 : } 406 : 407 0 : if (session_id.data == NULL || session_id.size == 0) { 408 0 : gnutls_assert(); 409 0 : return /* GNUTLS_E_INVALID_SESSION */ ; 410 : } 411 : 412 : /* if we can't read why bother writing? */ 413 0 : ret = session->internals.db_remove_func(session->internals.db_ptr, 414 : session_id); 415 0 : if (ret != 0) 416 0 : gnutls_assert(); 417 : }