1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17/* _ _ 18 * _ __ ___ ___ __| | ___ ___| | mod_ssl 19 * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL 20 * | | | | | | (_) | (_| | \__ \__ \ | 21 * |_| |_| |_|\___/ \__,_|___|___/___/_| 22 * |_____| 23 * ssl_scache.c 24 * Session Cache Abstraction 25 */ 26 /* ``Open-Source Software: generous 27 programmers from around the world all 28 join forces to help you shoot 29 yourself in the foot for free.'' 30 -- Unknown */ 31#include "ssl_private.h" 32#include "mod_status.h" 33 34/* _________________________________________________________________ 35** 36** Session Cache: Common Abstraction Layer 37** _________________________________________________________________ 38*/ 39 40apr_status_t ssl_scache_init(server_rec *s, apr_pool_t *p) 41{ 42 SSLModConfigRec *mc = myModConfig(s); 43 apr_status_t rv; 44 struct ap_socache_hints hints; 45 46 /* The very first invocation of this function will be the 47 * post_config invocation during server startup; do nothing for 48 * this first (and only the first) time through, since the pool 49 * will be immediately cleared anyway. For every subsequent 50 * invocation, initialize the configured cache. */ 51 if (ap_state_query(AP_SQ_MAIN_STATE) == AP_SQ_MS_CREATE_PRE_CONFIG) 52 return APR_SUCCESS; 53 54#ifdef HAVE_OCSP_STAPLING 55 if (mc->stapling_cache) { 56 memset(&hints, 0, sizeof hints); 57 hints.avg_obj_size = 1500; 58 hints.avg_id_len = 20; 59 hints.expiry_interval = 300; 60 61 rv = mc->stapling_cache->init(mc->stapling_cache_context, 62 "mod_ssl-stapling", &hints, s, p); 63 if (rv) { 64 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01872) 65 "Could not initialize stapling cache. Exiting."); 66 return ssl_die(s); 67 } 68 } 69#endif 70 71 /* 72 * Warn the user that he should use the session cache. 73 * But we can operate without it, of course. 74 */ 75 if (mc->sesscache == NULL) { 76 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(01873) 77 "Init: Session Cache is not configured " 78 "[hint: SSLSessionCache]"); 79 return APR_SUCCESS; 80 } 81 82 memset(&hints, 0, sizeof hints); 83 hints.avg_obj_size = 150; 84 hints.avg_id_len = 30; 85 hints.expiry_interval = 30; 86 87 rv = mc->sesscache->init(mc->sesscache_context, "mod_ssl-session", &hints, s, p); 88 if (rv) { 89 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(01874) 90 "Could not initialize session cache. Exiting."); 91 return ssl_die(s); 92 } 93 94 return APR_SUCCESS; 95} 96 97void ssl_scache_kill(server_rec *s) 98{ 99 SSLModConfigRec *mc = myModConfig(s); 100 101 if (mc->sesscache) { 102 mc->sesscache->destroy(mc->sesscache_context, s); 103 } 104 105#ifdef HAVE_OCSP_STAPLING 106 if (mc->stapling_cache) { 107 mc->stapling_cache->destroy(mc->stapling_cache_context, s); 108 } 109#endif 110 111} 112 113BOOL ssl_scache_store(server_rec *s, UCHAR *id, int idlen, 114 apr_time_t expiry, SSL_SESSION *sess, 115 apr_pool_t *p) 116{ 117 SSLModConfigRec *mc = myModConfig(s); 118 unsigned char encoded[SSL_SESSION_MAX_DER], *ptr; 119 unsigned int len; 120 apr_status_t rv; 121 122 /* Serialise the session. */ 123 len = i2d_SSL_SESSION(sess, NULL); 124 if (len > sizeof encoded) { 125 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01875) 126 "session is too big (%u bytes)", len); 127 return FALSE; 128 } 129 130 ptr = encoded; 131 len = i2d_SSL_SESSION(sess, &ptr); 132 133 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 134 ssl_mutex_on(s); 135 } 136 137 rv = mc->sesscache->store(mc->sesscache_context, s, id, idlen, 138 expiry, encoded, len, p); 139 140 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 141 ssl_mutex_off(s); 142 } 143 144 return rv == APR_SUCCESS ? TRUE : FALSE; 145} 146 147SSL_SESSION *ssl_scache_retrieve(server_rec *s, UCHAR *id, int idlen, 148 apr_pool_t *p) 149{ 150 SSLModConfigRec *mc = myModConfig(s); 151 unsigned char dest[SSL_SESSION_MAX_DER]; 152 unsigned int destlen = SSL_SESSION_MAX_DER; 153 const unsigned char *ptr; 154 apr_status_t rv; 155 156 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 157 ssl_mutex_on(s); 158 } 159 160 rv = mc->sesscache->retrieve(mc->sesscache_context, s, id, idlen, 161 dest, &destlen, p); 162 163 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 164 ssl_mutex_off(s); 165 } 166 167 if (rv != APR_SUCCESS) { 168 return NULL; 169 } 170 171 ptr = dest; 172 173 return d2i_SSL_SESSION(NULL, &ptr, destlen); 174} 175 176void ssl_scache_remove(server_rec *s, UCHAR *id, int idlen, 177 apr_pool_t *p) 178{ 179 SSLModConfigRec *mc = myModConfig(s); 180 181 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 182 ssl_mutex_on(s); 183 } 184 185 mc->sesscache->remove(mc->sesscache_context, s, id, idlen, p); 186 187 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 188 ssl_mutex_off(s); 189 } 190} 191 192/* _________________________________________________________________ 193** 194** SSL Extension to mod_status 195** _________________________________________________________________ 196*/ 197static int ssl_ext_status_hook(request_rec *r, int flags) 198{ 199 SSLModConfigRec *mc = myModConfig(r->server); 200 201 if (mc == NULL || flags & AP_STATUS_SHORT || mc->sesscache == NULL) 202 return OK; 203 204 ap_rputs("<hr>\n", r); 205 ap_rputs("<table cellspacing=0 cellpadding=0>\n", r); 206 ap_rputs("<tr><td bgcolor=\"#000000\">\n", r); 207 ap_rputs("<b><font color=\"#ffffff\" face=\"Arial,Helvetica\">SSL/TLS Session Cache Status:</font></b>\r", r); 208 ap_rputs("</td></tr>\n", r); 209 ap_rputs("<tr><td bgcolor=\"#ffffff\">\n", r); 210 211 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 212 ssl_mutex_on(r->server); 213 } 214 215 mc->sesscache->status(mc->sesscache_context, r, flags); 216 217 if (mc->sesscache->flags & AP_SOCACHE_FLAG_NOTMPSAFE) { 218 ssl_mutex_off(r->server); 219 } 220 221 ap_rputs("</td></tr>\n", r); 222 ap_rputs("</table>\n", r); 223 return OK; 224} 225 226void ssl_scache_status_register(apr_pool_t *p) 227{ 228 APR_OPTIONAL_HOOK(ap, status_hook, ssl_ext_status_hook, NULL, NULL, 229 APR_HOOK_MIDDLE); 230} 231 232