Imported Upstream version 3.3.5
[platform/upstream/gnutls.git] / lib / gnutls_db.c
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 <http://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 "gnutls_errors.h"
29 #include <gnutls_db.h>
30 #include <gnutls_session_pack.h>
31 #include <gnutls_datum.h>
32
33 /**
34  * gnutls_db_set_retrieve_function:
35  * @session: is a #gnutls_session_t structure.
36  * @retr_func: is the function.
37  *
38  * Sets the function that will be used to retrieve data from the
39  * resumed sessions database.  This function must return a
40  * gnutls_datum_t containing the data on success, or a gnutls_datum_t
41  * containing null and 0 on failure.
42  *
43  * The datum's data must be allocated using the function
44  * gnutls_malloc().
45  *
46  * The first argument to @retr_func will be null unless
47  * gnutls_db_set_ptr() has been called.
48  **/
49 void
50 gnutls_db_set_retrieve_function(gnutls_session_t session,
51                                 gnutls_db_retr_func retr_func)
52 {
53         session->internals.db_retrieve_func = retr_func;
54 }
55
56 /**
57  * gnutls_db_set_remove_function:
58  * @session: is a #gnutls_session_t structure.
59  * @rem_func: is the function.
60  *
61  * Sets the function that will be used to remove data from the
62  * resumed sessions database. This function must return 0 on success.
63  *
64  * The first argument to @rem_func will be null unless
65  * gnutls_db_set_ptr() has been called.
66  **/
67 void
68 gnutls_db_set_remove_function(gnutls_session_t session,
69                               gnutls_db_remove_func rem_func)
70 {
71         session->internals.db_remove_func = rem_func;
72 }
73
74 /**
75  * gnutls_db_set_store_function:
76  * @session: is a #gnutls_session_t structure.
77  * @store_func: is the function
78  *
79  * Sets the function that will be used to store data in the resumed
80  * sessions database. This function must return 0 on success.
81  *
82  * The first argument to @store_func will be null unless
83  * gnutls_db_set_ptr() has been called.
84  **/
85 void
86 gnutls_db_set_store_function(gnutls_session_t session,
87                              gnutls_db_store_func store_func)
88 {
89         session->internals.db_store_func = store_func;
90 }
91
92 /**
93  * gnutls_db_set_ptr:
94  * @session: is a #gnutls_session_t structure.
95  * @ptr: is the pointer
96  *
97  * Sets the pointer that will be provided to db store, retrieve and
98  * delete functions, as the first argument.
99  **/
100 void gnutls_db_set_ptr(gnutls_session_t session, void *ptr)
101 {
102         session->internals.db_ptr = ptr;
103 }
104
105 /**
106  * gnutls_db_get_ptr:
107  * @session: is a #gnutls_session_t structure.
108  *
109  * Get db function pointer.
110  *
111  * Returns: the pointer that will be sent to db store, retrieve and
112  *   delete functions, as the first argument.
113  **/
114 void *gnutls_db_get_ptr(gnutls_session_t session)
115 {
116         return session->internals.db_ptr;
117 }
118
119 /**
120  * gnutls_db_set_cache_expiration:
121  * @session: is a #gnutls_session_t structure.
122  * @seconds: is the number of seconds.
123  *
124  * Set the expiration time for resumed sessions. The default is 3600
125  * (one hour) at the time of this writing.
126  **/
127 void gnutls_db_set_cache_expiration(gnutls_session_t session, int seconds)
128 {
129         session->internals.expire_time = seconds;
130 }
131
132 /**
133  * gnutls_db_get_default_cache_expiration:
134  *
135  * Returns the expiration time (in seconds) of stored sessions for resumption. 
136  **/
137 unsigned gnutls_db_get_default_cache_expiration(void)
138 {
139         return DEFAULT_EXPIRE_TIME;
140 }
141
142 /**
143  * gnutls_db_check_entry:
144  * @session: is a #gnutls_session_t structure.
145  * @session_entry: is the session data (not key)
146  *
147  * This function has no effect. 
148  *
149  * Returns: Returns %GNUTLS_E_EXPIRED, if the database entry has
150  *   expired or 0 otherwise.
151  **/
152 int
153 gnutls_db_check_entry(gnutls_session_t session,
154                       gnutls_datum_t session_entry)
155 {
156         return 0;
157 }
158
159 /**
160  * gnutls_db_check_entry_time:
161  * @entry: is a pointer to a #gnutls_datum_t structure.
162  * @t: is the time of the session handshake
163  *
164  * This function returns the time that this entry was active.
165  * It can be used for database entry expiration.
166  *
167  * Returns: The time this entry was created, or zero on error.
168  **/
169 time_t gnutls_db_check_entry_time(gnutls_datum_t * entry)
170 {
171         uint32_t t;
172         uint32_t magic;
173
174         if (entry->size < 8)
175                 return gnutls_assert_val(0);
176
177         magic = _gnutls_read_uint32(entry->data);
178
179         if (magic != PACKED_SESSION_MAGIC)
180                 return gnutls_assert_val(0);
181
182         t = _gnutls_read_uint32(&entry->data[4]);
183
184         return t;
185 }
186
187 /* Checks if both db_store and db_retrieve functions have
188  * been set up.
189  */
190 static int db_func_is_ok(gnutls_session_t session)
191 {
192         if (session->internals.db_store_func != NULL &&
193             session->internals.db_retrieve_func != NULL)
194                 return 0;
195         else
196                 return GNUTLS_E_DB_ERROR;
197 }
198
199 /* Stores session data to the db backend.
200  */
201 static int
202 store_session(gnutls_session_t session,
203               gnutls_datum_t session_id, gnutls_datum_t session_data)
204 {
205         int ret = 0;
206
207         if (db_func_is_ok(session) != 0) {
208                 return GNUTLS_E_DB_ERROR;
209         }
210
211         if (session_data.data == NULL || session_data.size == 0) {
212                 gnutls_assert();
213                 return GNUTLS_E_INVALID_SESSION;
214         }
215
216         /* if we can't read why bother writing? */
217         ret = session->internals.db_store_func(session->internals.db_ptr,
218                                                session_id, session_data);
219
220         return (ret == 0 ? ret : GNUTLS_E_DB_ERROR);
221 }
222
223 int _gnutls_server_register_current_session(gnutls_session_t session)
224 {
225         gnutls_datum_t key;
226         gnutls_datum_t content;
227         int ret = 0;
228
229         key.data = session->security_parameters.session_id;
230         key.size = session->security_parameters.session_id_size;
231
232         if (session->internals.resumable == RESUME_FALSE) {
233                 gnutls_assert();
234                 return GNUTLS_E_INVALID_SESSION;
235         }
236
237         if (session->security_parameters.session_id_size == 0) {
238                 gnutls_assert();
239                 return GNUTLS_E_INVALID_SESSION;
240         }
241
242         ret = _gnutls_session_pack(session, &content);
243         if (ret < 0) {
244                 gnutls_assert();
245                 return ret;
246         }
247
248         ret = store_session(session, key, content);
249         _gnutls_free_datum(&content);
250
251         return ret;
252 }
253
254 int
255 _gnutls_server_restore_session(gnutls_session_t session,
256                                uint8_t * session_id, int session_id_size)
257 {
258         gnutls_datum_t data;
259         gnutls_datum_t key;
260         int ret;
261
262         if (session_id == NULL || session_id_size == 0) {
263                 gnutls_assert();
264                 return GNUTLS_E_INVALID_REQUEST;
265         }
266
267         if (session->internals.premaster_set != 0) {    /* hack for CISCO's DTLS-0.9 */
268                 if (session_id_size ==
269                     session->internals.resumed_security_parameters.
270                     session_id_size
271                     && memcmp(session_id,
272                               session->internals.
273                               resumed_security_parameters.session_id,
274                               session_id_size) == 0)
275                         return 0;
276         }
277
278         key.data = session_id;
279         key.size = session_id_size;
280
281         if (db_func_is_ok(session) != 0) {
282                 gnutls_assert();
283                 return GNUTLS_E_INVALID_SESSION;
284         }
285
286         data =
287             session->internals.db_retrieve_func(session->internals.db_ptr,
288                                                 key);
289
290         if (data.data == NULL) {
291                 gnutls_assert();
292                 return GNUTLS_E_INVALID_SESSION;
293         }
294
295         /* expiration check is performed inside */
296         ret = gnutls_session_set_data(session, data.data, data.size);
297         gnutls_free(data.data);
298
299         if (ret < 0) {
300                 gnutls_assert();
301                 return ret;
302         }
303
304
305         return 0;
306 }
307
308 /**
309  * gnutls_db_remove_session:
310  * @session: is a #gnutls_session_t structure.
311  *
312  * This function will remove the current session data from the
313  * session database.  This will prevent future handshakes reusing
314  * these session data.  This function should be called if a session
315  * was terminated abnormally, and before gnutls_deinit() is called.
316  *
317  * Normally gnutls_deinit() will remove abnormally terminated
318  * sessions.
319  **/
320 void gnutls_db_remove_session(gnutls_session_t session)
321 {
322         gnutls_datum_t session_id;
323         int ret = 0;
324
325         session_id.data = session->security_parameters.session_id;
326         session_id.size = session->security_parameters.session_id_size;
327
328         if (session->internals.db_remove_func == NULL) {
329                 gnutls_assert();
330                 return /* GNUTLS_E_DB_ERROR */ ;
331         }
332
333         if (session_id.data == NULL || session_id.size == 0) {
334                 gnutls_assert();
335                 return /* GNUTLS_E_INVALID_SESSION */ ;
336         }
337
338         /* if we can't read why bother writing? */
339         ret = session->internals.db_remove_func(session->internals.db_ptr,
340                                                 session_id);
341         if (ret != 0)
342                 gnutls_assert();
343 }