PolarSSL v1.2.9
ssl_cache.c
Go to the documentation of this file.
1 /*
2  * SSL session cache implementation
3  *
4  * Copyright (C) 2006-2012, Brainspark B.V.
5  *
6  * This file is part of PolarSSL (http://www.polarssl.org)
7  * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8  *
9  * All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25 /*
26  * These session callbacks use a simple chained list
27  * to store and retrieve the session information.
28  */
29 
30 #include "polarssl/config.h"
31 
32 #if defined(POLARSSL_SSL_CACHE_C)
33 
34 #include "polarssl/ssl_cache.h"
35 
36 #include <stdlib.h>
37 
38 void ssl_cache_init( ssl_cache_context *cache )
39 {
40  memset( cache, 0, sizeof( ssl_cache_context ) );
41 
44 }
45 
46 int ssl_cache_get( void *data, ssl_session *session )
47 {
48  time_t t = time( NULL );
49  ssl_cache_context *cache = (ssl_cache_context *) data;
50  ssl_cache_entry *cur, *entry;
51 
52  cur = cache->chain;
53  entry = NULL;
54 
55  while( cur != NULL )
56  {
57  entry = cur;
58  cur = cur->next;
59 
60  if( cache->timeout != 0 &&
61  (int) ( t - entry->timestamp ) > cache->timeout )
62  continue;
63 
64  if( session->ciphersuite != entry->session.ciphersuite ||
65  session->compression != entry->session.compression ||
66  session->length != entry->session.length )
67  continue;
68 
69  if( memcmp( session->id, entry->session.id,
70  entry->session.length ) != 0 )
71  continue;
72 
73  memcpy( session->master, entry->session.master, 48 );
74 
75  /*
76  * Restore peer certificate (without rest of the original chain)
77  */
78  if( entry->peer_cert.p != NULL )
79  {
80  session->peer_cert = (x509_cert *) malloc( sizeof(x509_cert) );
81  if( session->peer_cert == NULL )
82  return( 1 );
83 
84  memset( session->peer_cert, 0, sizeof(x509_cert) );
85  if( x509parse_crt( session->peer_cert, entry->peer_cert.p,
86  entry->peer_cert.len ) != 0 )
87  {
88  free( session->peer_cert );
89  session->peer_cert = NULL;
90  return( 1 );
91  }
92  }
93 
94  return( 0 );
95  }
96 
97  return( 1 );
98 }
99 
100 int ssl_cache_set( void *data, const ssl_session *session )
101 {
102  time_t t = time( NULL ), oldest = 0;
103  ssl_cache_context *cache = (ssl_cache_context *) data;
104  ssl_cache_entry *cur, *prv, *old = NULL;
105  int count = 0;
106 
107  cur = cache->chain;
108  prv = NULL;
109 
110  while( cur != NULL )
111  {
112  count++;
113 
114  if( cache->timeout != 0 &&
115  (int) ( t - cur->timestamp ) > cache->timeout )
116  {
117  cur->timestamp = t;
118  break; /* expired, reuse this slot, update timestamp */
119  }
120 
121  if( memcmp( session->id, cur->session.id, cur->session.length ) == 0 )
122  break; /* client reconnected, keep timestamp for session id */
123 
124  if( oldest == 0 || cur->timestamp < oldest )
125  {
126  oldest = cur->timestamp;
127  old = cur;
128  }
129 
130  prv = cur;
131  cur = cur->next;
132  }
133 
134  if( cur == NULL )
135  {
136  /*
137  * Reuse oldest entry if max_entries reached
138  */
139  if( old != NULL && count >= cache->max_entries )
140  {
141  cur = old;
142  memset( &cur->session, 0, sizeof(ssl_session) );
143  if( cur->peer_cert.p != NULL )
144  {
145  free( cur->peer_cert.p );
146  memset( &cur->peer_cert, 0, sizeof(x509_buf) );
147  }
148  }
149  else
150  {
151  cur = (ssl_cache_entry *) malloc( sizeof(ssl_cache_entry) );
152  if( cur == NULL )
153  return( 1 );
154 
155  memset( cur, 0, sizeof(ssl_cache_entry) );
156 
157  if( prv == NULL )
158  cache->chain = cur;
159  else
160  prv->next = cur;
161  }
162 
163  cur->timestamp = t;
164  }
165 
166  memcpy( &cur->session, session, sizeof( ssl_session ) );
167 
168  /*
169  * Store peer certificate
170  */
171  if( session->peer_cert != NULL )
172  {
173  cur->peer_cert.p = (unsigned char *) malloc( session->peer_cert->raw.len );
174  if( cur->peer_cert.p == NULL )
175  return( 1 );
176 
177  memcpy( cur->peer_cert.p, session->peer_cert->raw.p,
178  session->peer_cert->raw.len );
179  cur->peer_cert.len = session->peer_cert->raw.len;
180 
181  cur->session.peer_cert = NULL;
182  }
183 
184  return( 0 );
185 }
186 
187 void ssl_cache_set_timeout( ssl_cache_context *cache, int timeout )
188 {
189  if( timeout < 0 ) timeout = 0;
190 
191  cache->timeout = timeout;
192 }
193 
194 void ssl_cache_set_max_entries( ssl_cache_context *cache, int max )
195 {
196  if( max < 0 ) max = 0;
197 
198  cache->max_entries = max;
199 }
200 
201 void ssl_cache_free( ssl_cache_context *cache )
202 {
203  ssl_cache_entry *cur, *prv;
204 
205  cur = cache->chain;
206 
207  while( cur != NULL )
208  {
209  prv = cur;
210  cur = cur->next;
211 
212  ssl_session_free( &prv->session );
213 
214  if( prv->peer_cert.p != NULL )
215  free( prv->peer_cert.p );
216 
217  free( prv );
218  }
219 }
220 
221 #endif /* POLARSSL_SSL_CACHE_C */
size_t length
Definition: ssl.h:322
int ciphersuite
Definition: ssl.h:320
void ssl_cache_init(ssl_cache_context *cache)
Initialize an SSL cache context.
int compression
Definition: ssl.h:321
ssl_cache_entry * next
Definition: ssl_cache.h:52
unsigned char master[48]
Definition: ssl.h:324
x509_cert * peer_cert
Definition: ssl.h:325
#define SSL_CACHE_DEFAULT_TIMEOUT
Definition: ssl_cache.h:33
SSL session cache implementation.
x509_buf raw
The raw certificate data (DER).
Definition: x509.h:290
ssl_cache_entry * chain
Definition: ssl_cache.h:60
void ssl_session_free(ssl_session *session)
Free referenced items in an SSL session including the peer certificate and clear memory.
Configuration options (set of defines)
int ssl_cache_get(void *data, ssl_session *session)
Cache get callback implementation.
Container for an X.509 certificate.
Definition: x509.h:288
x509_buf peer_cert
Definition: ssl_cache.h:51
void ssl_cache_free(ssl_cache_context *cache)
Free referenced items in a cache context and clear memory.
unsigned char id[32]
Definition: ssl.h:323
Cache context.
Definition: ssl_cache.h:58
This structure is used for storing cache entries.
Definition: ssl_cache.h:47
int x509parse_crt(x509_cert *chain, const unsigned char *buf, size_t buflen)
Parse one or more certificates and add them to the chained list.
unsigned char * p
ASN1 data, e.g.
Definition: asn1.h:112
ssl_session session
Definition: ssl_cache.h:50
void ssl_cache_set_timeout(ssl_cache_context *cache, int timeout)
Set the cache timeout (Default: SSL_CACHE_DEFAULT_TIMEOUT (1 day))
Type-length-value structure that allows for ASN1 using DER.
Definition: asn1.h:108
size_t len
ASN1 length, e.g.
Definition: asn1.h:111
#define SSL_CACHE_DEFAULT_MAX_ENTRIES
Definition: ssl_cache.h:34
void ssl_cache_set_max_entries(ssl_cache_context *cache, int max)
Set the cache timeout (Default: SSL_CACHE_DEFAULT_MAX_ENTRIES (50))
time_t timestamp
Definition: ssl_cache.h:49
int ssl_cache_set(void *data, const ssl_session *session)
Cache set callback implementation.