ssl_cache.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * SSL session cache implementation
  3. *
  4. * Copyright The Mbed TLS Contributors
  5. * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  6. */
  7. /*
  8. * These session callbacks use a simple chained list
  9. * to store and retrieve the session information.
  10. */
  11. #include "common.h"
  12. #if defined(MBEDTLS_SSL_CACHE_C)
  13. #include "mbedtls/platform.h"
  14. #include "mbedtls/error.h"
  15. #include "mbedtls/ssl_cache.h"
  16. #include "mbedtls/ssl_internal.h"
  17. #include <string.h>
  18. void mbedtls_ssl_cache_init(mbedtls_ssl_cache_context *cache)
  19. {
  20. memset(cache, 0, sizeof(mbedtls_ssl_cache_context));
  21. cache->timeout = MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT;
  22. cache->max_entries = MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES;
  23. #if defined(MBEDTLS_THREADING_C)
  24. mbedtls_mutex_init(&cache->mutex);
  25. #endif
  26. }
  27. int mbedtls_ssl_cache_get(void *data, mbedtls_ssl_session *session)
  28. {
  29. int ret = MBEDTLS_ERR_SSL_CACHE_ENTRY_NOT_FOUND;
  30. #if defined(MBEDTLS_HAVE_TIME)
  31. mbedtls_time_t t = mbedtls_time(NULL);
  32. #endif
  33. mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
  34. mbedtls_ssl_cache_entry *cur, *entry;
  35. #if defined(MBEDTLS_THREADING_C)
  36. if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
  37. return ret;
  38. }
  39. #endif
  40. cur = cache->chain;
  41. entry = NULL;
  42. while (cur != NULL) {
  43. entry = cur;
  44. cur = cur->next;
  45. #if defined(MBEDTLS_HAVE_TIME)
  46. if (cache->timeout != 0 &&
  47. (int) (t - entry->timestamp) > cache->timeout) {
  48. continue;
  49. }
  50. #endif
  51. if (session->id_len != entry->session.id_len ||
  52. memcmp(session->id, entry->session.id,
  53. entry->session.id_len) != 0) {
  54. continue;
  55. }
  56. ret = mbedtls_ssl_session_copy(session, &entry->session);
  57. if (ret != 0) {
  58. goto exit;
  59. }
  60. #if defined(MBEDTLS_X509_CRT_PARSE_C) && \
  61. defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
  62. /*
  63. * Restore peer certificate (without rest of the original chain)
  64. */
  65. if (entry->peer_cert.p != NULL) {
  66. /* `session->peer_cert` is NULL after the call to
  67. * mbedtls_ssl_session_copy(), because cache entries
  68. * have the `peer_cert` field set to NULL. */
  69. if ((session->peer_cert = mbedtls_calloc(1,
  70. sizeof(mbedtls_x509_crt))) == NULL) {
  71. ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
  72. goto exit;
  73. }
  74. mbedtls_x509_crt_init(session->peer_cert);
  75. if ((ret = mbedtls_x509_crt_parse(session->peer_cert, entry->peer_cert.p,
  76. entry->peer_cert.len)) != 0) {
  77. mbedtls_free(session->peer_cert);
  78. session->peer_cert = NULL;
  79. goto exit;
  80. }
  81. }
  82. #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
  83. ret = 0;
  84. goto exit;
  85. }
  86. exit:
  87. #if defined(MBEDTLS_THREADING_C)
  88. if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
  89. ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR;
  90. }
  91. #endif
  92. return ret;
  93. }
  94. int mbedtls_ssl_cache_set(void *data, const mbedtls_ssl_session *session)
  95. {
  96. int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
  97. #if defined(MBEDTLS_HAVE_TIME)
  98. mbedtls_time_t t = mbedtls_time(NULL), oldest = 0;
  99. mbedtls_ssl_cache_entry *old = NULL;
  100. #endif
  101. mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data;
  102. mbedtls_ssl_cache_entry *cur, *prv;
  103. int count = 0;
  104. #if defined(MBEDTLS_THREADING_C)
  105. if ((ret = mbedtls_mutex_lock(&cache->mutex)) != 0) {
  106. return ret;
  107. }
  108. #endif
  109. cur = cache->chain;
  110. prv = NULL;
  111. while (cur != NULL) {
  112. count++;
  113. #if defined(MBEDTLS_HAVE_TIME)
  114. if (cache->timeout != 0 &&
  115. (int) (t - cur->timestamp) > cache->timeout) {
  116. cur->timestamp = t;
  117. break; /* expired, reuse this slot, update timestamp */
  118. }
  119. #endif
  120. if (memcmp(session->id, cur->session.id, cur->session.id_len) == 0) {
  121. break; /* client reconnected, keep timestamp for session id */
  122. }
  123. #if defined(MBEDTLS_HAVE_TIME)
  124. if (oldest == 0 || cur->timestamp < oldest) {
  125. oldest = cur->timestamp;
  126. old = cur;
  127. }
  128. #endif
  129. prv = cur;
  130. cur = cur->next;
  131. }
  132. if (cur == NULL) {
  133. #if defined(MBEDTLS_HAVE_TIME)
  134. /*
  135. * Reuse oldest entry if max_entries reached
  136. */
  137. if (count >= cache->max_entries) {
  138. if (old == NULL) {
  139. /* This should only happen on an ill-configured cache
  140. * with max_entries == 0. */
  141. ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
  142. goto exit;
  143. }
  144. cur = old;
  145. }
  146. #else /* MBEDTLS_HAVE_TIME */
  147. /*
  148. * Reuse first entry in chain if max_entries reached,
  149. * but move to last place
  150. */
  151. if (count >= cache->max_entries) {
  152. if (cache->chain == NULL) {
  153. ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
  154. goto exit;
  155. }
  156. cur = cache->chain;
  157. cache->chain = cur->next;
  158. cur->next = NULL;
  159. prv->next = cur;
  160. }
  161. #endif /* MBEDTLS_HAVE_TIME */
  162. else {
  163. /*
  164. * max_entries not reached, create new entry
  165. */
  166. cur = mbedtls_calloc(1, sizeof(mbedtls_ssl_cache_entry));
  167. if (cur == NULL) {
  168. ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
  169. goto exit;
  170. }
  171. if (prv == NULL) {
  172. cache->chain = cur;
  173. } else {
  174. prv->next = cur;
  175. }
  176. }
  177. #if defined(MBEDTLS_HAVE_TIME)
  178. cur->timestamp = t;
  179. #endif
  180. }
  181. #if defined(MBEDTLS_X509_CRT_PARSE_C) && \
  182. defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
  183. /*
  184. * If we're reusing an entry, free its certificate first
  185. */
  186. if (cur->peer_cert.p != NULL) {
  187. mbedtls_free(cur->peer_cert.p);
  188. memset(&cur->peer_cert, 0, sizeof(mbedtls_x509_buf));
  189. }
  190. #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
  191. /* Copy the entire session; this temporarily makes a copy of the
  192. * X.509 CRT structure even though we only want to store the raw CRT.
  193. * This inefficiency will go away as soon as we implement on-demand
  194. * parsing of CRTs, in which case there's no need for the `peer_cert`
  195. * field anymore in the first place, and we're done after this call. */
  196. ret = mbedtls_ssl_session_copy(&cur->session, session);
  197. if (ret != 0) {
  198. goto exit;
  199. }
  200. #if defined(MBEDTLS_X509_CRT_PARSE_C) && \
  201. defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
  202. /* If present, free the X.509 structure and only store the raw CRT data. */
  203. if (cur->session.peer_cert != NULL) {
  204. cur->peer_cert.p =
  205. mbedtls_calloc(1, cur->session.peer_cert->raw.len);
  206. if (cur->peer_cert.p == NULL) {
  207. ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
  208. goto exit;
  209. }
  210. memcpy(cur->peer_cert.p,
  211. cur->session.peer_cert->raw.p,
  212. cur->session.peer_cert->raw.len);
  213. cur->peer_cert.len = session->peer_cert->raw.len;
  214. mbedtls_x509_crt_free(cur->session.peer_cert);
  215. mbedtls_free(cur->session.peer_cert);
  216. cur->session.peer_cert = NULL;
  217. }
  218. #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
  219. ret = 0;
  220. exit:
  221. #if defined(MBEDTLS_THREADING_C)
  222. if (mbedtls_mutex_unlock(&cache->mutex) != 0) {
  223. ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR;
  224. }
  225. #endif
  226. return ret;
  227. }
  228. #if defined(MBEDTLS_HAVE_TIME)
  229. void mbedtls_ssl_cache_set_timeout(mbedtls_ssl_cache_context *cache, int timeout)
  230. {
  231. if (timeout < 0) {
  232. timeout = 0;
  233. }
  234. cache->timeout = timeout;
  235. }
  236. #endif /* MBEDTLS_HAVE_TIME */
  237. void mbedtls_ssl_cache_set_max_entries(mbedtls_ssl_cache_context *cache, int max)
  238. {
  239. if (max < 0) {
  240. max = 0;
  241. }
  242. cache->max_entries = max;
  243. }
  244. void mbedtls_ssl_cache_free(mbedtls_ssl_cache_context *cache)
  245. {
  246. mbedtls_ssl_cache_entry *cur, *prv;
  247. cur = cache->chain;
  248. while (cur != NULL) {
  249. prv = cur;
  250. cur = cur->next;
  251. mbedtls_ssl_session_free(&prv->session);
  252. #if defined(MBEDTLS_X509_CRT_PARSE_C) && \
  253. defined(MBEDTLS_SSL_KEEP_PEER_CERTIFICATE)
  254. mbedtls_free(prv->peer_cert.p);
  255. #endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_KEEP_PEER_CERTIFICATE */
  256. mbedtls_free(prv);
  257. }
  258. #if defined(MBEDTLS_THREADING_C)
  259. mbedtls_mutex_free(&cache->mutex);
  260. #endif
  261. cache->chain = NULL;
  262. }
  263. #endif /* MBEDTLS_SSL_CACHE_C */