- Timestamp:
- Sep 19, 2011, 11:58:43 PM (12 years ago)
- Branches:
- asyncio, debian/master, debian/stretch-backports, jessie-backports, main, master, msva, proxy-ticket, upstream
- Children:
- c7c2ad2
- Parents:
- 6223319
- Location:
- src
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
src/gnutls_cache.c
r6223319 re183628 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Portions Copyright 2008 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 45 46 46 47 char *mgs_session_id2sz(unsigned char *id, int idlen, 47 char *str, int strsize) 48 { 49 char *cp; 50 int n; 51 52 cp = str; 53 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 54 apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]); 55 cp += 2; 56 } 57 *cp = '\0'; 58 return str; 59 } 60 48 char *str, int strsize) { 49 char *cp; 50 int n; 51 52 cp = str; 53 for (n = 0; n < idlen && n < GNUTLS_MAX_SESSION_ID; n++) { 54 apr_snprintf(cp, strsize - (cp - str), "%02X", id[n]); 55 cp += 2; 56 } 57 *cp = '\0'; 58 return str; 59 } 61 60 62 61 /* Name the Session ID as: … … 65 64 */ 66 65 static int mgs_session_id2dbm(conn_rec * c, unsigned char *id, int idlen, 67 apr_datum_t * dbmkey) 68 { 69 char buf[STR_SESSION_LEN]; 70 char *sz; 71 72 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf)); 73 if (sz == NULL) 74 return -1; 75 76 dbmkey->dptr = 77 apr_psprintf(c->pool, "%s:%d.%s", 78 c->base_server->server_hostname, 79 c->base_server->port, sz); 80 dbmkey->dsize = strlen(dbmkey->dptr); 81 82 return 0; 66 apr_datum_t * dbmkey) { 67 char buf[STR_SESSION_LEN]; 68 char *sz; 69 70 sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf)); 71 if (sz == NULL) 72 return -1; 73 74 dbmkey->dptr = 75 apr_psprintf(c->pool, "%s:%d.%s", 76 c->base_server->server_hostname, 77 c->base_server->port, sz); 78 dbmkey->dsize = strlen(dbmkey->dptr); 79 80 return 0; 83 81 } 84 82 85 83 #define CTIME "%b %d %k:%M:%S %Y %Z" 86 char *mgs_time2sz(time_t in_time, char *str, int strsize) 87 {88 89 90 91 92 93 94 95 96 97 84 85 char *mgs_time2sz(time_t in_time, char *str, int strsize) { 86 apr_time_exp_t vtm; 87 apr_size_t ret_size; 88 apr_time_t t; 89 90 91 apr_time_ansi_put(&t, in_time); 92 apr_time_exp_gmt(&vtm, t); 93 apr_strftime(str, &ret_size, strsize - 1, CTIME, &vtm); 94 95 return str; 98 96 } 99 97 100 98 #if HAVE_APR_MEMCACHE 99 101 100 /* Name the Session ID as: 102 101 * server:port.SessionID 103 102 * to disallow resuming sessions on different servers 104 103 */ 105 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) 106 { 107 char buf[STR_SESSION_LEN]; 108 char *sz; 109 110 sz = mgs_session_id2sz(id, idlen, buf, sizeof(buf)); 111 if (sz == NULL) 112 return NULL; 113 114 return apr_psprintf(c->pool, MC_TAG "%s:%d.%s", 115 c->base_server->server_hostname, 116 c->base_server->port, sz); 104 static char *mgs_session_id2mc(conn_rec * c, unsigned char *id, int idlen) { 105 char buf[STR_SESSION_LEN]; 106 char *sz; 107 108 sz = mgs_session_id2sz(id, idlen, buf, sizeof (buf)); 109 if (sz == NULL) 110 return NULL; 111 112 return apr_psprintf(c->pool, MC_TAG "%s:%d.%s", 113 c->base_server->server_hostname, 114 c->base_server->port, sz); 117 115 } 118 116 … … 126 124 127 125 static int mc_cache_child_init(apr_pool_t * p, server_rec * s, 128 mgs_srvconf_rec * sc) 129 { 130 apr_status_t rv = APR_SUCCESS; 131 int thread_limit = 0; 132 int nservers = 0; 133 char *cache_config; 134 char *split; 135 char *tok; 136 137 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); 138 139 /* Find all the servers in the first run to get a total count */ 140 cache_config = apr_pstrdup(p, sc->cache_config); 141 split = apr_strtok(cache_config, " ", &tok); 142 while (split) { 143 nservers++; 144 split = apr_strtok(NULL, " ", &tok); 145 } 146 147 rv = apr_memcache_create(p, nservers, 0, &mc); 148 if (rv != APR_SUCCESS) { 149 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 150 "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 151 nservers); 152 return rv; 153 } 154 155 /* Now add each server to the memcache */ 156 cache_config = apr_pstrdup(p, sc->cache_config); 157 split = apr_strtok(cache_config, " ", &tok); 158 while (split) { 159 apr_memcache_server_t *st; 160 char *host_str; 161 char *scope_id; 162 apr_port_t port; 163 164 rv = apr_parse_addr_port(&host_str, &scope_id, &port, 165 split, p); 166 if (rv != APR_SUCCESS) { 167 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 168 "[gnutls_cache] Failed to Parse Server: '%s'", 169 split); 170 return rv; 171 } 172 173 if (host_str == NULL) { 174 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 175 "[gnutls_cache] Failed to Parse Server, " 176 "no hostname specified: '%s'", split); 177 return rv; 178 } 179 180 if (port == 0) { 181 port = 11211; /* default port */ 182 } 183 184 /* Should Max Conns be (thread_limit / nservers) ? */ 185 rv = apr_memcache_server_create(p, 186 host_str, port, 187 0, 188 1, thread_limit, 600, &st); 189 if (rv != APR_SUCCESS) { 190 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 191 "[gnutls_cache] Failed to Create Server: %s:%d", 192 host_str, port); 193 return rv; 194 } 195 196 rv = apr_memcache_add_server(mc, st); 197 if (rv != APR_SUCCESS) { 198 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 199 "[gnutls_cache] Failed to Add Server: %s:%d", 200 host_str, port); 201 return rv; 202 } 203 204 split = apr_strtok(NULL, " ", &tok); 205 } 206 return rv; 126 mgs_srvconf_rec * sc) { 127 apr_status_t rv = APR_SUCCESS; 128 int thread_limit = 0; 129 int nservers = 0; 130 char *cache_config; 131 char *split; 132 char *tok; 133 134 ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); 135 136 /* Find all the servers in the first run to get a total count */ 137 cache_config = apr_pstrdup(p, sc->cache_config); 138 split = apr_strtok(cache_config, " ", &tok); 139 while (split) { 140 nservers++; 141 split = apr_strtok(NULL, " ", &tok); 142 } 143 144 rv = apr_memcache_create(p, nservers, 0, &mc); 145 if (rv != APR_SUCCESS) { 146 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 147 "[gnutls_cache] Failed to create Memcache Object of '%d' size.", 148 nservers); 149 return rv; 150 } 151 152 /* Now add each server to the memcache */ 153 cache_config = apr_pstrdup(p, sc->cache_config); 154 split = apr_strtok(cache_config, " ", &tok); 155 while (split) { 156 apr_memcache_server_t *st; 157 char *host_str; 158 char *scope_id; 159 apr_port_t port; 160 161 rv = apr_parse_addr_port(&host_str, &scope_id, &port, 162 split, p); 163 if (rv != APR_SUCCESS) { 164 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 165 "[gnutls_cache] Failed to Parse Server: '%s'", 166 split); 167 return rv; 168 } 169 170 if (host_str == NULL) { 171 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 172 "[gnutls_cache] Failed to Parse Server, " 173 "no hostname specified: '%s'", split); 174 return rv; 175 } 176 177 if (port == 0) { 178 port = 11211; /* default port */ 179 } 180 181 /* Should Max Conns be (thread_limit / nservers) ? */ 182 rv = apr_memcache_server_create(p, 183 host_str, port, 184 0, 185 1, thread_limit, 600, &st); 186 if (rv != APR_SUCCESS) { 187 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 188 "[gnutls_cache] Failed to Create Server: %s:%d", 189 host_str, port); 190 return rv; 191 } 192 193 rv = apr_memcache_add_server(mc, st); 194 if (rv != APR_SUCCESS) { 195 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, s, 196 "[gnutls_cache] Failed to Add Server: %s:%d", 197 host_str, port); 198 return rv; 199 } 200 201 split = apr_strtok(NULL, " ", &tok); 202 } 203 return rv; 207 204 } 208 205 209 206 static int mc_cache_store(void *baton, gnutls_datum_t key, 210 gnutls_datum_t data) 211 { 212 apr_status_t rv = APR_SUCCESS; 213 mgs_handle_t *ctxt = baton; 214 char *strkey = NULL; 215 apr_uint32_t timeout; 216 217 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 218 if (!strkey) 219 return -1; 220 221 timeout = apr_time_sec(ctxt->sc->cache_timeout); 222 223 rv = apr_memcache_set(mc, strkey,(char *)data.data, data.size, timeout, 224 0); 225 226 if (rv != APR_SUCCESS) { 227 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, 228 ctxt->c->base_server, 229 "[gnutls_cache] error setting key '%s' " 230 "with %d bytes of data", strkey, data.size); 231 return -1; 232 } 233 234 return 0; 235 } 236 237 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) 238 { 239 apr_status_t rv = APR_SUCCESS; 240 mgs_handle_t *ctxt = baton; 241 char *strkey = NULL; 242 char *value; 243 apr_size_t value_len; 244 gnutls_datum_t data = { NULL, 0 }; 245 246 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 247 if (!strkey) { 248 return data; 249 } 250 251 rv = apr_memcache_getp(mc, ctxt->c->pool, strkey, 252 &value, &value_len, NULL); 253 254 if (rv != APR_SUCCESS) { 207 gnutls_datum_t data) { 208 apr_status_t rv = APR_SUCCESS; 209 mgs_handle_t *ctxt = baton; 210 char *strkey = NULL; 211 apr_uint32_t timeout; 212 213 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 214 if (!strkey) 215 return -1; 216 217 timeout = apr_time_sec(ctxt->sc->cache_timeout); 218 219 rv = apr_memcache_set(mc, strkey, (char *) data.data, data.size, timeout, 220 0); 221 222 if (rv != APR_SUCCESS) { 223 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, 224 ctxt->c->base_server, 225 "[gnutls_cache] error setting key '%s' " 226 "with %d bytes of data", strkey, data.size); 227 return -1; 228 } 229 230 return 0; 231 } 232 233 static gnutls_datum_t mc_cache_fetch(void *baton, gnutls_datum_t key) { 234 apr_status_t rv = APR_SUCCESS; 235 mgs_handle_t *ctxt = baton; 236 char *strkey = NULL; 237 char *value; 238 apr_size_t value_len; 239 gnutls_datum_t data = {NULL, 0}; 240 241 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 242 if (!strkey) { 243 return data; 244 } 245 246 rv = apr_memcache_getp(mc, ctxt->c->pool, strkey, 247 &value, &value_len, NULL); 248 249 if (rv != APR_SUCCESS) { 255 250 #if MOD_GNUTLS_DEBUG 256 257 258 259 251 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 252 ctxt->c->base_server, 253 "[gnutls_cache] error fetching key '%s' ", 254 strkey); 260 255 #endif 261 data.size = 0; 262 data.data = NULL; 263 return data; 264 } 265 266 /* TODO: Eliminate this memcpy. gnutls-- */ 267 data.data = gnutls_malloc(value_len); 268 if (data.data == NULL) 269 return data; 270 271 data.size = value_len; 272 memcpy(data.data, value, value_len); 273 274 return data; 275 } 276 277 static int mc_cache_delete(void *baton, gnutls_datum_t key) 278 { 279 apr_status_t rv = APR_SUCCESS; 280 mgs_handle_t *ctxt = baton; 281 char *strkey = NULL; 282 283 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 284 if (!strkey) 285 return -1; 286 287 rv = apr_memcache_delete(mc, strkey, 0); 288 289 if (rv != APR_SUCCESS) { 290 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 291 ctxt->c->base_server, 292 "[gnutls_cache] error deleting key '%s' ", 293 strkey); 294 return -1; 295 } 296 297 return 0; 256 data.size = 0; 257 data.data = NULL; 258 return data; 259 } 260 261 /* TODO: Eliminate this memcpy. gnutls-- */ 262 data.data = gnutls_malloc(value_len); 263 if (data.data == NULL) 264 return data; 265 266 data.size = value_len; 267 memcpy(data.data, value, value_len); 268 269 return data; 270 } 271 272 static int mc_cache_delete(void *baton, gnutls_datum_t key) { 273 apr_status_t rv = APR_SUCCESS; 274 mgs_handle_t *ctxt = baton; 275 char *strkey = NULL; 276 277 strkey = mgs_session_id2mc(ctxt->c, key.data, key.size); 278 if (!strkey) 279 return -1; 280 281 rv = apr_memcache_delete(mc, strkey, 0); 282 283 if (rv != APR_SUCCESS) { 284 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 285 ctxt->c->base_server, 286 "[gnutls_cache] error deleting key '%s' ", 287 strkey); 288 return -1; 289 } 290 291 return 0; 298 292 } 299 293 300 294 #endif /* have_apr_memcache */ 301 295 302 const char *db_type(mgs_srvconf_rec * sc) 303 { 304 if (sc->cache_type == mgs_cache_gdbm) 305 return "gdbm"; 306 else 307 return "db"; 296 const char *db_type(mgs_srvconf_rec * sc) { 297 if (sc->cache_type == mgs_cache_gdbm) 298 return "gdbm"; 299 else 300 return "db"; 308 301 } 309 302 310 303 #define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD ) 311 304 312 static void dbm_cache_expire(mgs_handle_t * ctxt) 313 { 314 apr_status_t rv; 315 apr_dbm_t *dbm; 316 apr_datum_t dbmkey; 317 apr_datum_t dbmval; 318 apr_time_t now; 319 apr_time_t dtime; 320 apr_pool_t *spool; 321 int total, deleted; 322 323 now = apr_time_now(); 324 325 if (now - ctxt->sc->last_cache_check < 326 (ctxt->sc->cache_timeout) / 2) 327 return; 328 329 ctxt->sc->last_cache_check = now; 330 331 apr_pool_create(&spool, ctxt->c->pool); 332 333 total = 0; 334 deleted = 0; 335 336 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 337 ctxt->sc->cache_config, APR_DBM_RWCREATE, 338 SSL_DBM_FILE_MODE, spool); 339 if (rv != APR_SUCCESS) { 340 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 341 ctxt->c->base_server, 342 "[gnutls_cache] error opening cache searcher '%s'", 343 ctxt->sc->cache_config); 344 apr_pool_destroy(spool); 345 return; 346 } 347 348 apr_dbm_firstkey(dbm, &dbmkey); 349 while (dbmkey.dptr != NULL) { 350 apr_dbm_fetch(dbm, dbmkey, &dbmval); 351 if (dbmval.dptr != NULL 352 && dbmval.dsize >= sizeof(apr_time_t)) { 353 memcpy(&dtime, dbmval.dptr, sizeof(apr_time_t)); 354 355 if (now >= dtime) { 356 apr_dbm_delete(dbm, dbmkey); 357 deleted++; 358 } 359 apr_dbm_freedatum(dbm, dbmval); 360 } else { 361 apr_dbm_delete(dbm, dbmkey); 362 deleted++; 363 } 364 total++; 365 apr_dbm_nextkey(dbm, &dbmkey); 366 } 367 apr_dbm_close(dbm); 368 369 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 370 ctxt->c->base_server, 371 "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d", 372 ctxt->sc->cache_config, deleted, total - deleted); 373 374 apr_pool_destroy(spool); 375 376 return; 377 } 378 379 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) 380 { 381 gnutls_datum_t data = { NULL, 0 }; 382 apr_dbm_t *dbm; 383 apr_datum_t dbmkey; 384 apr_datum_t dbmval; 385 mgs_handle_t *ctxt = baton; 386 apr_status_t rv; 387 388 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 389 return data; 390 391 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 392 ctxt->sc->cache_config, APR_DBM_READONLY, 393 SSL_DBM_FILE_MODE, ctxt->c->pool); 394 if (rv != APR_SUCCESS) { 395 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 396 ctxt->c->base_server, 397 "[gnutls_cache] error opening cache '%s'", 398 ctxt->sc->cache_config); 399 return data; 400 } 401 402 rv = apr_dbm_fetch(dbm, dbmkey, &dbmval); 403 404 if (rv != APR_SUCCESS) { 405 apr_dbm_close(dbm); 406 return data; 407 } 408 409 if (dbmval.dptr == NULL || dbmval.dsize <= sizeof(apr_time_t)) { 410 apr_dbm_freedatum(dbm, dbmval); 411 apr_dbm_close(dbm); 412 return data; 413 } 414 415 data.size = dbmval.dsize - sizeof(apr_time_t); 416 417 data.data = gnutls_malloc(data.size); 418 if (data.data == NULL) { 419 apr_dbm_freedatum(dbm, dbmval); 420 apr_dbm_close(dbm); 421 return data; 422 } 423 424 memcpy(data.data, dbmval.dptr + sizeof(apr_time_t), data.size); 425 426 apr_dbm_freedatum(dbm, dbmval); 427 apr_dbm_close(dbm); 428 429 return data; 305 static void dbm_cache_expire(mgs_handle_t * ctxt) { 306 apr_status_t rv; 307 apr_dbm_t *dbm; 308 apr_datum_t dbmkey; 309 apr_datum_t dbmval; 310 apr_time_t now; 311 apr_time_t dtime; 312 apr_pool_t *spool; 313 int total, deleted; 314 315 now = apr_time_now(); 316 317 if (now - ctxt->sc->last_cache_check < 318 (ctxt->sc->cache_timeout) / 2) 319 return; 320 321 ctxt->sc->last_cache_check = now; 322 323 apr_pool_create(&spool, ctxt->c->pool); 324 325 total = 0; 326 deleted = 0; 327 328 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 329 ctxt->sc->cache_config, APR_DBM_RWCREATE, 330 SSL_DBM_FILE_MODE, spool); 331 if (rv != APR_SUCCESS) { 332 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 333 ctxt->c->base_server, 334 "[gnutls_cache] error opening cache searcher '%s'", 335 ctxt->sc->cache_config); 336 apr_pool_destroy(spool); 337 return; 338 } 339 340 apr_dbm_firstkey(dbm, &dbmkey); 341 while (dbmkey.dptr != NULL) { 342 apr_dbm_fetch(dbm, dbmkey, &dbmval); 343 if (dbmval.dptr != NULL 344 && dbmval.dsize >= sizeof (apr_time_t)) { 345 memcpy(&dtime, dbmval.dptr, sizeof (apr_time_t)); 346 347 if (now >= dtime) { 348 apr_dbm_delete(dbm, dbmkey); 349 deleted++; 350 } 351 apr_dbm_freedatum(dbm, dbmval); 352 } else { 353 apr_dbm_delete(dbm, dbmkey); 354 deleted++; 355 } 356 total++; 357 apr_dbm_nextkey(dbm, &dbmkey); 358 } 359 apr_dbm_close(dbm); 360 361 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 362 ctxt->c->base_server, 363 "[gnutls_cache] Cleaned up cache '%s'. Deleted %d and left %d", 364 ctxt->sc->cache_config, deleted, total - deleted); 365 366 apr_pool_destroy(spool); 367 368 return; 369 } 370 371 static gnutls_datum_t dbm_cache_fetch(void *baton, gnutls_datum_t key) { 372 gnutls_datum_t data = {NULL, 0}; 373 apr_dbm_t *dbm; 374 apr_datum_t dbmkey; 375 apr_datum_t dbmval; 376 mgs_handle_t *ctxt = baton; 377 apr_status_t rv; 378 379 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 380 return data; 381 382 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 383 ctxt->sc->cache_config, APR_DBM_READONLY, 384 SSL_DBM_FILE_MODE, ctxt->c->pool); 385 if (rv != APR_SUCCESS) { 386 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 387 ctxt->c->base_server, 388 "[gnutls_cache] error opening cache '%s'", 389 ctxt->sc->cache_config); 390 return data; 391 } 392 393 rv = apr_dbm_fetch(dbm, dbmkey, &dbmval); 394 395 if (rv != APR_SUCCESS) { 396 apr_dbm_close(dbm); 397 return data; 398 } 399 400 if (dbmval.dptr == NULL || dbmval.dsize <= sizeof (apr_time_t)) { 401 apr_dbm_freedatum(dbm, dbmval); 402 apr_dbm_close(dbm); 403 return data; 404 } 405 406 data.size = dbmval.dsize - sizeof (apr_time_t); 407 408 data.data = gnutls_malloc(data.size); 409 if (data.data == NULL) { 410 apr_dbm_freedatum(dbm, dbmval); 411 apr_dbm_close(dbm); 412 return data; 413 } 414 415 memcpy(data.data, dbmval.dptr + sizeof (apr_time_t), data.size); 416 417 apr_dbm_freedatum(dbm, dbmval); 418 apr_dbm_close(dbm); 419 420 return data; 430 421 } 431 422 432 423 static int dbm_cache_store(void *baton, gnutls_datum_t key, 433 gnutls_datum_t data) 434 { 435 apr_dbm_t *dbm; 436 apr_datum_t dbmkey; 437 apr_datum_t dbmval; 438 mgs_handle_t *ctxt = baton; 439 apr_status_t rv; 440 apr_time_t expiry; 441 apr_pool_t *spool; 442 443 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 444 return -1; 445 446 /* we expire dbm only on every store 447 */ 448 dbm_cache_expire(ctxt); 449 450 apr_pool_create(&spool, ctxt->c->pool); 451 452 /* create DBM value */ 453 dbmval.dsize = data.size + sizeof(apr_time_t); 454 dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize); 455 456 expiry = apr_time_now() + ctxt->sc->cache_timeout; 457 458 memcpy((char *) dbmval.dptr, &expiry, sizeof(apr_time_t)); 459 memcpy((char *) dbmval.dptr + sizeof(apr_time_t), 460 data.data, data.size); 461 462 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 463 ctxt->sc->cache_config, APR_DBM_RWCREATE, 464 SSL_DBM_FILE_MODE, ctxt->c->pool); 465 if (rv != APR_SUCCESS) { 466 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 467 ctxt->c->base_server, 468 "[gnutls_cache] error opening cache '%s'", 469 ctxt->sc->cache_config); 470 apr_pool_destroy(spool); 471 return -1; 472 } 473 474 rv = apr_dbm_store(dbm, dbmkey, dbmval); 475 476 if (rv != APR_SUCCESS) { 477 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 478 ctxt->c->base_server, 479 "[gnutls_cache] error storing in cache '%s'", 480 ctxt->sc->cache_config); 481 apr_dbm_close(dbm); 482 apr_pool_destroy(spool); 483 return -1; 484 } 485 486 apr_dbm_close(dbm); 487 488 apr_pool_destroy(spool); 489 490 return 0; 491 } 492 493 static int dbm_cache_delete(void *baton, gnutls_datum_t key) 494 { 495 apr_dbm_t *dbm; 496 apr_datum_t dbmkey; 497 mgs_handle_t *ctxt = baton; 498 apr_status_t rv; 499 500 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 501 return -1; 502 503 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 504 ctxt->sc->cache_config, APR_DBM_RWCREATE, 505 SSL_DBM_FILE_MODE, ctxt->c->pool); 506 if (rv != APR_SUCCESS) { 507 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 508 ctxt->c->base_server, 509 "[gnutls_cache] error opening cache '%s'", 510 ctxt->sc->cache_config); 511 return -1; 512 } 513 514 rv = apr_dbm_delete(dbm, dbmkey); 515 516 if (rv != APR_SUCCESS) { 517 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 518 ctxt->c->base_server, 519 "[gnutls_cache] error deleting from cache '%s'", 520 ctxt->sc->cache_config); 521 apr_dbm_close(dbm); 522 return -1; 523 } 524 525 apr_dbm_close(dbm); 526 527 return 0; 424 gnutls_datum_t data) { 425 apr_dbm_t *dbm; 426 apr_datum_t dbmkey; 427 apr_datum_t dbmval; 428 mgs_handle_t *ctxt = baton; 429 apr_status_t rv; 430 apr_time_t expiry; 431 apr_pool_t *spool; 432 433 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 434 return -1; 435 436 /* we expire dbm only on every store 437 */ 438 dbm_cache_expire(ctxt); 439 440 apr_pool_create(&spool, ctxt->c->pool); 441 442 /* create DBM value */ 443 dbmval.dsize = data.size + sizeof (apr_time_t); 444 dbmval.dptr = (char *) apr_palloc(spool, dbmval.dsize); 445 446 expiry = apr_time_now() + ctxt->sc->cache_timeout; 447 448 memcpy((char *) dbmval.dptr, &expiry, sizeof (apr_time_t)); 449 memcpy((char *) dbmval.dptr + sizeof (apr_time_t), 450 data.data, data.size); 451 452 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 453 ctxt->sc->cache_config, APR_DBM_RWCREATE, 454 SSL_DBM_FILE_MODE, ctxt->c->pool); 455 if (rv != APR_SUCCESS) { 456 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 457 ctxt->c->base_server, 458 "[gnutls_cache] error opening cache '%s'", 459 ctxt->sc->cache_config); 460 apr_pool_destroy(spool); 461 return -1; 462 } 463 464 rv = apr_dbm_store(dbm, dbmkey, dbmval); 465 466 if (rv != APR_SUCCESS) { 467 ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, 468 ctxt->c->base_server, 469 "[gnutls_cache] error storing in cache '%s'", 470 ctxt->sc->cache_config); 471 apr_dbm_close(dbm); 472 apr_pool_destroy(spool); 473 return -1; 474 } 475 476 apr_dbm_close(dbm); 477 478 apr_pool_destroy(spool); 479 480 return 0; 481 } 482 483 static int dbm_cache_delete(void *baton, gnutls_datum_t key) { 484 apr_dbm_t *dbm; 485 apr_datum_t dbmkey; 486 mgs_handle_t *ctxt = baton; 487 apr_status_t rv; 488 489 if (mgs_session_id2dbm(ctxt->c, key.data, key.size, &dbmkey) < 0) 490 return -1; 491 492 rv = apr_dbm_open_ex(&dbm, db_type(ctxt->sc), 493 ctxt->sc->cache_config, APR_DBM_RWCREATE, 494 SSL_DBM_FILE_MODE, ctxt->c->pool); 495 if (rv != APR_SUCCESS) { 496 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 497 ctxt->c->base_server, 498 "[gnutls_cache] error opening cache '%s'", 499 ctxt->sc->cache_config); 500 return -1; 501 } 502 503 rv = apr_dbm_delete(dbm, dbmkey); 504 505 if (rv != APR_SUCCESS) { 506 ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, 507 ctxt->c->base_server, 508 "[gnutls_cache] error deleting from cache '%s'", 509 ctxt->sc->cache_config); 510 apr_dbm_close(dbm); 511 return -1; 512 } 513 514 apr_dbm_close(dbm); 515 516 return 0; 528 517 } 529 518 530 519 static int dbm_cache_post_config(apr_pool_t * p, server_rec * s, 531 mgs_srvconf_rec * sc) 532 { 533 apr_status_t rv; 534 apr_dbm_t *dbm; 535 const char *path1; 536 const char *path2; 537 538 rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config, 539 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p); 540 541 if (rv != APR_SUCCESS) { 542 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, 543 "GnuTLS: Cannot create DBM Cache at `%s'", 544 sc->cache_config); 545 return rv; 546 } 547 548 apr_dbm_close(dbm); 549 550 apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1, 551 &path2); 552 553 /* The Following Code takes logic directly from mod_ssl's DBM Cache */ 520 mgs_srvconf_rec * sc) { 521 apr_status_t rv; 522 apr_dbm_t *dbm; 523 const char *path1; 524 const char *path2; 525 526 rv = apr_dbm_open_ex(&dbm, db_type(sc), sc->cache_config, 527 APR_DBM_RWCREATE, SSL_DBM_FILE_MODE, p); 528 529 if (rv != APR_SUCCESS) { 530 ap_log_error(APLOG_MARK, APLOG_ERR, rv, s, 531 "GnuTLS: Cannot create DBM Cache at `%s'", 532 sc->cache_config); 533 return rv; 534 } 535 536 apr_dbm_close(dbm); 537 538 apr_dbm_get_usednames_ex(p, db_type(sc), sc->cache_config, &path1, 539 &path2); 540 541 /* The Following Code takes logic directly from mod_ssl's DBM Cache */ 554 542 #if !defined(OS2) && !defined(WIN32) && !defined(BEOS) && !defined(NETWARE) 555 556 557 558 559 560 561 543 /* Running as Root */ 544 if (path1 && geteuid() == 0) { 545 chown(path1, ap_unixd_config.user_id, -1); 546 if (path2 != NULL) { 547 chown(path2, ap_unixd_config.user_id, -1); 548 } 549 } 562 550 #endif 563 551 564 552 return rv; 565 553 } 566 554 567 555 int mgs_cache_post_config(apr_pool_t * p, server_rec * s, 568 mgs_srvconf_rec * sc) 569 { 570 if (sc->cache_type == mgs_cache_dbm 571 || sc->cache_type == mgs_cache_gdbm) { 572 return dbm_cache_post_config(p, s, sc); 573 } 574 return 0; 556 mgs_srvconf_rec * sc) { 557 if (sc->cache_type == mgs_cache_dbm 558 || sc->cache_type == mgs_cache_gdbm) { 559 return dbm_cache_post_config(p, s, sc); 560 } 561 return 0; 575 562 } 576 563 577 564 int mgs_cache_child_init(apr_pool_t * p, server_rec * s, 578 mgs_srvconf_rec * sc) 579 { 580 if (sc->cache_type == mgs_cache_dbm 581 || sc->cache_type == mgs_cache_gdbm) { 582 return 0; 583 } 565 mgs_srvconf_rec * sc) { 566 if (sc->cache_type == mgs_cache_dbm 567 || sc->cache_type == mgs_cache_gdbm) { 568 return 0; 569 } 584 570 #if HAVE_APR_MEMCACHE 585 586 587 571 else if (sc->cache_type == mgs_cache_memcache) { 572 return mc_cache_child_init(p, s, sc); 573 } 588 574 #endif 589 575 return 0; 590 576 } 591 577 592 578 #include <assert.h> 593 579 594 int mgs_cache_session_init(mgs_handle_t * ctxt) 595 { 596 if (ctxt->sc->cache_type == mgs_cache_dbm 597 || ctxt->sc->cache_type == mgs_cache_gdbm) { 598 gnutls_db_set_retrieve_function(ctxt->session, 599 dbm_cache_fetch); 600 gnutls_db_set_remove_function(ctxt->session, 601 dbm_cache_delete); 602 gnutls_db_set_store_function(ctxt->session, 603 dbm_cache_store); 604 gnutls_db_set_ptr(ctxt->session, ctxt); 605 } 580 int mgs_cache_session_init(mgs_handle_t * ctxt) { 581 if (ctxt->sc->cache_type == mgs_cache_dbm 582 || ctxt->sc->cache_type == mgs_cache_gdbm) { 583 gnutls_db_set_retrieve_function(ctxt->session, 584 dbm_cache_fetch); 585 gnutls_db_set_remove_function(ctxt->session, 586 dbm_cache_delete); 587 gnutls_db_set_store_function(ctxt->session, 588 dbm_cache_store); 589 gnutls_db_set_ptr(ctxt->session, ctxt); 590 } 606 591 #if HAVE_APR_MEMCACHE 607 608 609 610 611 612 613 614 615 592 else if (ctxt->sc->cache_type == mgs_cache_memcache) { 593 gnutls_db_set_retrieve_function(ctxt->session, 594 mc_cache_fetch); 595 gnutls_db_set_remove_function(ctxt->session, 596 mc_cache_delete); 597 gnutls_db_set_store_function(ctxt->session, 598 mc_cache_store); 599 gnutls_db_set_ptr(ctxt->session, ctxt); 600 } 616 601 #endif 617 602 618 619 } 603 return 0; 604 } -
src/gnutls_config.c
r6223319 re183628 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Copyright 2007 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 20 21 21 22 static int load_datum_from_file(apr_pool_t * pool, 22 const char *file, gnutls_datum_t * data) 23 { 24 apr_file_t *fp; 25 apr_finfo_t finfo; 26 apr_status_t rv; 27 apr_size_t br = 0; 28 29 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, 30 APR_OS_DEFAULT, pool); 31 if (rv != APR_SUCCESS) { 32 return rv; 33 } 34 35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 36 37 if (rv != APR_SUCCESS) { 38 return rv; 39 } 40 41 data->data = apr_palloc(pool, finfo.size + 1); 42 rv = apr_file_read_full(fp, data->data, finfo.size, &br); 43 44 if (rv != APR_SUCCESS) { 45 return rv; 46 } 47 apr_file_close(fp); 48 49 data->data[br] = '\0'; 50 data->size = br; 51 52 return 0; 23 const char *file, gnutls_datum_t * data) { 24 apr_file_t *fp; 25 apr_finfo_t finfo; 26 apr_status_t rv; 27 apr_size_t br = 0; 28 29 rv = apr_file_open(&fp, file, APR_READ | APR_BINARY, 30 APR_OS_DEFAULT, pool); 31 if (rv != APR_SUCCESS) { 32 return rv; 33 } 34 35 rv = apr_file_info_get(&finfo, APR_FINFO_SIZE, fp); 36 37 if (rv != APR_SUCCESS) { 38 return rv; 39 } 40 41 data->data = apr_palloc(pool, finfo.size + 1); 42 rv = apr_file_read_full(fp, data->data, finfo.size, &br); 43 44 if (rv != APR_SUCCESS) { 45 return rv; 46 } 47 apr_file_close(fp); 48 49 data->data[br] = '\0'; 50 data->size = br; 51 52 return 0; 53 53 } 54 54 55 55 const char *mgs_set_dh_file(cmd_parms * parms, void *dummy, 56 const char *arg) 57 { 58 int ret; 59 gnutls_datum_t data; 60 const char *file; 61 apr_pool_t *spool; 62 mgs_srvconf_rec *sc = 63 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 64 module_config, 65 &gnutls_module); 66 67 apr_pool_create(&spool, parms->pool); 68 69 file = ap_server_root_relative(spool, arg); 70 71 if (load_datum_from_file(spool, file, &data) != 0) { 72 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 73 "DH params '%s'", file); 74 } 75 76 ret = gnutls_dh_params_init(&sc->dh_params); 77 if (ret < 0) { 78 return apr_psprintf(parms->pool, 79 "GnuTLS: Failed to initialize" 80 ": (%d) %s", ret, 81 gnutls_strerror(ret)); 82 } 83 84 ret = 85 gnutls_dh_params_import_pkcs3(sc->dh_params, &data, 86 GNUTLS_X509_FMT_PEM); 87 if (ret < 0) { 88 return apr_psprintf(parms->pool, 89 "GnuTLS: Failed to Import " 90 "DH params '%s': (%d) %s", file, ret, 91 gnutls_strerror(ret)); 92 } 93 94 apr_pool_destroy(spool); 95 96 return NULL; 56 const char *arg) { 57 int ret; 58 gnutls_datum_t data; 59 const char *file; 60 apr_pool_t *spool; 61 mgs_srvconf_rec *sc = 62 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 63 module_config, 64 &gnutls_module); 65 66 apr_pool_create(&spool, parms->pool); 67 68 file = ap_server_root_relative(spool, arg); 69 70 if (load_datum_from_file(spool, file, &data) != 0) { 71 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 72 "DH params '%s'", file); 73 } 74 75 ret = gnutls_dh_params_init(&sc->dh_params); 76 if (ret < 0) { 77 return apr_psprintf(parms->pool, 78 "GnuTLS: Failed to initialize" 79 ": (%d) %s", ret, 80 gnutls_strerror(ret)); 81 } 82 83 ret = 84 gnutls_dh_params_import_pkcs3(sc->dh_params, &data, 85 GNUTLS_X509_FMT_PEM); 86 if (ret < 0) { 87 return apr_psprintf(parms->pool, 88 "GnuTLS: Failed to Import " 89 "DH params '%s': (%d) %s", file, ret, 90 gnutls_strerror(ret)); 91 } 92 93 apr_pool_destroy(spool); 94 95 return NULL; 97 96 } 98 97 99 98 const char *mgs_set_rsa_export_file(cmd_parms * parms, void *dummy, 100 const char *arg) 101 { 102 int ret; 103 gnutls_datum_t data; 104 const char *file; 105 apr_pool_t *spool; 106 mgs_srvconf_rec *sc = 107 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 108 module_config, 109 &gnutls_module); 110 111 apr_pool_create(&spool, parms->pool); 112 113 file = ap_server_root_relative(spool, arg); 114 115 if (load_datum_from_file(spool, file, &data) != 0) { 116 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 117 "RSA params '%s'", file); 118 } 119 120 ret = gnutls_rsa_params_init(&sc->rsa_params); 121 if (ret < 0) { 122 return apr_psprintf(parms->pool, 123 "GnuTLS: Failed to initialize" 124 ": (%d) %s", ret, 125 gnutls_strerror(ret)); 126 } 127 128 ret = 129 gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data, 130 GNUTLS_X509_FMT_PEM); 131 if (ret != 0) { 132 return apr_psprintf(parms->pool, 133 "GnuTLS: Failed to Import " 134 "RSA params '%s': (%d) %s", file, ret, 135 gnutls_strerror(ret)); 136 } 137 138 apr_pool_destroy(spool); 139 return NULL; 140 } 141 99 const char *arg) { 100 int ret; 101 gnutls_datum_t data; 102 const char *file; 103 apr_pool_t *spool; 104 mgs_srvconf_rec *sc = 105 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 106 module_config, 107 &gnutls_module); 108 109 apr_pool_create(&spool, parms->pool); 110 111 file = ap_server_root_relative(spool, arg); 112 113 if (load_datum_from_file(spool, file, &data) != 0) { 114 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 115 "RSA params '%s'", file); 116 } 117 118 ret = gnutls_rsa_params_init(&sc->rsa_params); 119 if (ret < 0) { 120 return apr_psprintf(parms->pool, 121 "GnuTLS: Failed to initialize" 122 ": (%d) %s", ret, 123 gnutls_strerror(ret)); 124 } 125 126 ret = 127 gnutls_rsa_params_import_pkcs1(sc->rsa_params, &data, 128 GNUTLS_X509_FMT_PEM); 129 if (ret != 0) { 130 return apr_psprintf(parms->pool, 131 "GnuTLS: Failed to Import " 132 "RSA params '%s': (%d) %s", file, ret, 133 gnutls_strerror(ret)); 134 } 135 136 apr_pool_destroy(spool); 137 return NULL; 138 } 142 139 143 140 const char *mgs_set_cert_file(cmd_parms * parms, void *dummy, 144 const char *arg) 145 { 146 int ret; 147 gnutls_datum_t data; 148 const char *file; 149 apr_pool_t *spool; 150 mgs_srvconf_rec *sc = 151 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 152 module_config, 153 &gnutls_module); 154 apr_pool_create(&spool, parms->pool); 155 156 file = ap_server_root_relative(spool, arg); 157 158 if (load_datum_from_file(spool, file, &data) != 0) { 159 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 160 "Certificate '%s'", file); 161 } 162 163 sc->certs_x509_num = MAX_CHAIN_SIZE; 164 ret = 165 gnutls_x509_crt_list_import(sc->certs_x509, 166 &sc->certs_x509_num, &data, 167 GNUTLS_X509_FMT_PEM, 0); 168 if (ret < 0) { 169 return apr_psprintf(parms->pool, 170 "GnuTLS: Failed to Import " 171 "Certificate '%s': (%d) %s", file, ret, 172 gnutls_strerror(ret)); 173 } 174 175 apr_pool_destroy(spool); 176 return NULL; 141 const char *arg) { 142 int ret; 143 gnutls_datum_t data; 144 const char *file; 145 apr_pool_t *spool; 146 mgs_srvconf_rec *sc = 147 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 148 module_config, 149 &gnutls_module); 150 apr_pool_create(&spool, parms->pool); 151 152 file = ap_server_root_relative(spool, arg); 153 154 if (load_datum_from_file(spool, file, &data) != 0) { 155 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 156 "Certificate '%s'", file); 157 } 158 159 sc->certs_x509_num = MAX_CHAIN_SIZE; 160 ret = 161 gnutls_x509_crt_list_import(sc->certs_x509, 162 &sc->certs_x509_num, &data, 163 GNUTLS_X509_FMT_PEM, 0); 164 if (ret < 0) { 165 return apr_psprintf(parms->pool, 166 "GnuTLS: Failed to Import " 167 "Certificate '%s': (%d) %s", file, ret, 168 gnutls_strerror(ret)); 169 } 170 171 apr_pool_destroy(spool); 172 return NULL; 177 173 } 178 174 179 175 const char *mgs_set_key_file(cmd_parms * parms, void *dummy, 180 const char *arg) 181 { 182 int ret; 183 gnutls_datum_t data; 184 const char *file; 185 apr_pool_t *spool; 186 mgs_srvconf_rec *sc = 187 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 188 module_config, 189 &gnutls_module); 190 apr_pool_create(&spool, parms->pool); 191 192 file = ap_server_root_relative(spool, arg); 193 194 if (load_datum_from_file(spool, file, &data) != 0) { 195 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 196 "Private Key '%s'", file); 197 } 198 199 ret = gnutls_x509_privkey_init(&sc->privkey_x509); 200 if (ret < 0) { 201 return apr_psprintf(parms->pool, 202 "GnuTLS: Failed to initialize" 203 ": (%d) %s", ret, 204 gnutls_strerror(ret)); 205 } 206 207 ret = 208 gnutls_x509_privkey_import(sc->privkey_x509, &data, 209 GNUTLS_X509_FMT_PEM); 210 211 if (ret < 0) 212 ret = 213 gnutls_x509_privkey_import_pkcs8(sc->privkey_x509, 214 &data, 215 GNUTLS_X509_FMT_PEM, 216 NULL, 217 GNUTLS_PKCS_PLAIN); 218 219 if (ret < 0) { 220 return apr_psprintf(parms->pool, 221 "GnuTLS: Failed to Import " 222 "Private Key '%s': (%d) %s", file, ret, 223 gnutls_strerror(ret)); 224 } 225 apr_pool_destroy(spool); 226 return NULL; 176 const char *arg) { 177 int ret; 178 gnutls_datum_t data; 179 const char *file; 180 apr_pool_t *spool; 181 mgs_srvconf_rec *sc = 182 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 183 module_config, 184 &gnutls_module); 185 apr_pool_create(&spool, parms->pool); 186 187 file = ap_server_root_relative(spool, arg); 188 189 if (load_datum_from_file(spool, file, &data) != 0) { 190 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 191 "Private Key '%s'", file); 192 } 193 194 ret = gnutls_x509_privkey_init(&sc->privkey_x509); 195 if (ret < 0) { 196 return apr_psprintf(parms->pool, 197 "GnuTLS: Failed to initialize" 198 ": (%d) %s", ret, 199 gnutls_strerror(ret)); 200 } 201 202 ret = 203 gnutls_x509_privkey_import(sc->privkey_x509, &data, 204 GNUTLS_X509_FMT_PEM); 205 206 if (ret < 0) 207 ret = 208 gnutls_x509_privkey_import_pkcs8(sc->privkey_x509, 209 &data, 210 GNUTLS_X509_FMT_PEM, 211 NULL, 212 GNUTLS_PKCS_PLAIN); 213 214 if (ret < 0) { 215 return apr_psprintf(parms->pool, 216 "GnuTLS: Failed to Import " 217 "Private Key '%s': (%d) %s", file, ret, 218 gnutls_strerror(ret)); 219 } 220 apr_pool_destroy(spool); 221 return NULL; 227 222 } 228 223 229 224 const char *mgs_set_pgpcert_file(cmd_parms * parms, void *dummy, 230 const char *arg) 231 { 232 int ret; 233 gnutls_datum_t data; 234 const char *file; 235 apr_pool_t *spool; 236 mgs_srvconf_rec *sc = 237 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 238 module_config, 239 &gnutls_module); 240 apr_pool_create(&spool, parms->pool); 241 242 file = ap_server_root_relative(spool, arg); 243 244 if (load_datum_from_file(spool, file, &data) != 0) { 245 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 246 "Certificate '%s'", file); 247 } 248 249 ret = gnutls_openpgp_crt_init(&sc->cert_pgp); 250 if (ret < 0) { 251 return apr_psprintf(parms->pool, "GnuTLS: Failed to Init " 252 "PGP Certificate: (%d) %s", ret, 253 gnutls_strerror(ret)); 254 } 255 256 ret = 257 gnutls_openpgp_crt_import(sc->cert_pgp, &data, 258 GNUTLS_OPENPGP_FMT_BASE64); 259 if (ret < 0) { 260 return apr_psprintf(parms->pool, 261 "GnuTLS: Failed to Import " 262 "PGP Certificate '%s': (%d) %s", file, 263 ret, gnutls_strerror(ret)); 264 } 265 266 apr_pool_destroy(spool); 267 return NULL; 225 const char *arg) { 226 int ret; 227 gnutls_datum_t data; 228 const char *file; 229 apr_pool_t *spool; 230 mgs_srvconf_rec *sc = 231 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 232 module_config, 233 &gnutls_module); 234 apr_pool_create(&spool, parms->pool); 235 236 file = ap_server_root_relative(spool, arg); 237 238 if (load_datum_from_file(spool, file, &data) != 0) { 239 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 240 "Certificate '%s'", file); 241 } 242 243 ret = gnutls_openpgp_crt_init(&sc->cert_pgp); 244 if (ret < 0) { 245 return apr_psprintf(parms->pool, "GnuTLS: Failed to Init " 246 "PGP Certificate: (%d) %s", ret, 247 gnutls_strerror(ret)); 248 } 249 250 ret = 251 gnutls_openpgp_crt_import(sc->cert_pgp, &data, 252 GNUTLS_OPENPGP_FMT_BASE64); 253 if (ret < 0) { 254 return apr_psprintf(parms->pool, 255 "GnuTLS: Failed to Import " 256 "PGP Certificate '%s': (%d) %s", file, 257 ret, gnutls_strerror(ret)); 258 } 259 260 apr_pool_destroy(spool); 261 return NULL; 268 262 } 269 263 270 264 const char *mgs_set_pgpkey_file(cmd_parms * parms, void *dummy, 271 const char *arg) 272 { 273 int ret; 274 gnutls_datum_t data; 275 const char *file; 276 apr_pool_t *spool; 277 mgs_srvconf_rec *sc = 278 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 279 module_config, 280 &gnutls_module); 281 apr_pool_create(&spool, parms->pool); 282 283 file = ap_server_root_relative(spool, arg); 284 285 if (load_datum_from_file(spool, file, &data) != 0) { 286 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 287 "Private Key '%s'", file); 288 } 289 290 ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp); 291 if (ret < 0) { 292 return apr_psprintf(parms->pool, 293 "GnuTLS: Failed to initialize" 294 ": (%d) %s", ret, 295 gnutls_strerror(ret)); 296 } 297 298 ret = 299 gnutls_openpgp_privkey_import(sc->privkey_pgp, &data, 300 GNUTLS_OPENPGP_FMT_BASE64, NULL, 301 0); 302 if (ret != 0) { 303 return apr_psprintf(parms->pool, 304 "GnuTLS: Failed to Import " 305 "PGP Private Key '%s': (%d) %s", file, 306 ret, gnutls_strerror(ret)); 307 } 308 apr_pool_destroy(spool); 309 return NULL; 265 const char *arg) { 266 int ret; 267 gnutls_datum_t data; 268 const char *file; 269 apr_pool_t *spool; 270 mgs_srvconf_rec *sc = 271 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 272 module_config, 273 &gnutls_module); 274 apr_pool_create(&spool, parms->pool); 275 276 file = ap_server_root_relative(spool, arg); 277 278 if (load_datum_from_file(spool, file, &data) != 0) { 279 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 280 "Private Key '%s'", file); 281 } 282 283 ret = gnutls_openpgp_privkey_init(&sc->privkey_pgp); 284 if (ret < 0) { 285 return apr_psprintf(parms->pool, 286 "GnuTLS: Failed to initialize" 287 ": (%d) %s", ret, 288 gnutls_strerror(ret)); 289 } 290 291 ret = 292 gnutls_openpgp_privkey_import(sc->privkey_pgp, &data, 293 GNUTLS_OPENPGP_FMT_BASE64, NULL, 294 0); 295 if (ret != 0) { 296 return apr_psprintf(parms->pool, 297 "GnuTLS: Failed to Import " 298 "PGP Private Key '%s': (%d) %s", file, 299 ret, gnutls_strerror(ret)); 300 } 301 apr_pool_destroy(spool); 302 return NULL; 310 303 } 311 304 312 305 const char *mgs_set_tickets(cmd_parms * parms, void *dummy, 313 const char *arg) 314 { 315 mgs_srvconf_rec *sc = 316 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 317 module_config, 318 &gnutls_module); 319 320 sc->tickets = 0; 321 if (strcasecmp("on", arg) == 0) { 322 sc->tickets = 1; 323 } 324 325 return NULL; 306 const char *arg) { 307 mgs_srvconf_rec *sc = 308 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 309 module_config, 310 &gnutls_module); 311 312 sc->tickets = 0; 313 if (strcasecmp("on", arg) == 0) { 314 sc->tickets = 1; 315 } 316 317 return NULL; 326 318 } 327 319 … … 330 322 331 323 const char *mgs_set_srp_tpasswd_file(cmd_parms * parms, void *dummy, 332 const char *arg) 333 { 334 mgs_srvconf_rec *sc = 335 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 336 module_config, 337 &gnutls_module); 338 339 sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg); 340 341 return NULL; 324 const char *arg) { 325 mgs_srvconf_rec *sc = 326 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 327 module_config, 328 &gnutls_module); 329 330 sc->srp_tpasswd_file = ap_server_root_relative(parms->pool, arg); 331 332 return NULL; 342 333 } 343 334 344 335 const char *mgs_set_srp_tpasswd_conf_file(cmd_parms * parms, void *dummy, 345 const char *arg) 346 { 347 mgs_srvconf_rec *sc = 348 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 349 module_config, 350 &gnutls_module); 351 352 sc->srp_tpasswd_conf_file = 353 ap_server_root_relative(parms->pool, arg); 354 355 return NULL; 336 const char *arg) { 337 mgs_srvconf_rec *sc = 338 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 339 module_config, 340 &gnutls_module); 341 342 sc->srp_tpasswd_conf_file = 343 ap_server_root_relative(parms->pool, arg); 344 345 return NULL; 356 346 } 357 347 … … 359 349 360 350 const char *mgs_set_cache(cmd_parms * parms, void *dummy, 361 const char *type, const char *arg) 362 { 363 const char *err; 364 mgs_srvconf_rec *sc = 365 ap_get_module_config(parms->server->module_config, 366 &gnutls_module); 367 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 368 return err; 369 } 370 371 if (strcasecmp("none", type) == 0) { 372 sc->cache_type = mgs_cache_none; 373 sc->cache_config = NULL; 374 return NULL; 375 } else if (strcasecmp("dbm", type) == 0) { 376 sc->cache_type = mgs_cache_dbm; 377 } else if (strcasecmp("gdbm", type) == 0) { 378 sc->cache_type = mgs_cache_gdbm; 379 } 351 const char *type, const char *arg) { 352 const char *err; 353 mgs_srvconf_rec *sc = 354 ap_get_module_config(parms->server->module_config, 355 &gnutls_module); 356 if ((err = ap_check_cmd_context(parms, GLOBAL_ONLY))) { 357 return err; 358 } 359 360 if (strcasecmp("none", type) == 0) { 361 sc->cache_type = mgs_cache_none; 362 sc->cache_config = NULL; 363 return NULL; 364 } else if (strcasecmp("dbm", type) == 0) { 365 sc->cache_type = mgs_cache_dbm; 366 } else if (strcasecmp("gdbm", type) == 0) { 367 sc->cache_type = mgs_cache_gdbm; 368 } 380 369 #if HAVE_APR_MEMCACHE 381 382 383 370 else if (strcasecmp("memcache", type) == 0) { 371 sc->cache_type = mgs_cache_memcache; 372 } 384 373 #endif 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 374 else { 375 return "Invalid Type for GnuTLSCache!"; 376 } 377 378 if (arg == NULL) 379 return "Invalid argument 2 for GnuTLSCache!"; 380 381 if (sc->cache_type == mgs_cache_dbm 382 || sc->cache_type == mgs_cache_gdbm) { 383 sc->cache_config = 384 ap_server_root_relative(parms->pool, arg); 385 } else { 386 sc->cache_config = apr_pstrdup(parms->pool, arg); 387 } 388 389 return NULL; 401 390 } 402 391 403 392 const char *mgs_set_cache_timeout(cmd_parms * parms, void *dummy, 404 const char *arg) 405 { 406 int argint; 407 mgs_srvconf_rec *sc = 408 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 409 module_config, 410 &gnutls_module); 411 412 argint = atoi(arg); 413 414 if (argint < 0) { 415 return "GnuTLSCacheTimeout: Invalid argument"; 416 } else if (argint == 0) { 417 sc->cache_timeout = 0; 418 } else { 419 sc->cache_timeout = apr_time_from_sec(argint); 420 } 421 422 return NULL; 393 const char *arg) { 394 int argint; 395 mgs_srvconf_rec *sc = 396 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 397 module_config, 398 &gnutls_module); 399 400 argint = atoi(arg); 401 402 if (argint < 0) { 403 return "GnuTLSCacheTimeout: Invalid argument"; 404 } else if (argint == 0) { 405 sc->cache_timeout = 0; 406 } else { 407 sc->cache_timeout = apr_time_from_sec(argint); 408 } 409 410 return NULL; 423 411 } 424 412 425 413 const char *mgs_set_client_verify(cmd_parms * parms, void *dummy, 426 const char *arg) 427 { 428 int mode; 429 430 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { 431 mode = GNUTLS_CERT_IGNORE; 432 } else if (strcasecmp("optional", arg) == 0 433 || strcasecmp("request", arg) == 0) { 434 mode = GNUTLS_CERT_REQUEST; 435 } else if (strcasecmp("require", arg) == 0) { 436 mode = GNUTLS_CERT_REQUIRE; 437 } else { 438 return "GnuTLSClientVerify: Invalid argument"; 439 } 440 441 /* This was set from a directory context */ 442 if (parms->path) { 443 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy; 444 dc->client_verify_mode = mode; 445 } else { 446 mgs_srvconf_rec *sc = 447 (mgs_srvconf_rec *) 448 ap_get_module_config(parms->server->module_config, 449 &gnutls_module); 450 sc->client_verify_mode = mode; 451 } 452 453 return NULL; 414 const char *arg) { 415 int mode; 416 417 if (strcasecmp("none", arg) == 0 || strcasecmp("ignore", arg) == 0) { 418 mode = GNUTLS_CERT_IGNORE; 419 } else if (strcasecmp("optional", arg) == 0 420 || strcasecmp("request", arg) == 0) { 421 mode = GNUTLS_CERT_REQUEST; 422 } else if (strcasecmp("require", arg) == 0) { 423 mode = GNUTLS_CERT_REQUIRE; 424 } else { 425 return "GnuTLSClientVerify: Invalid argument"; 426 } 427 428 /* This was set from a directory context */ 429 if (parms->path) { 430 mgs_dirconf_rec *dc = (mgs_dirconf_rec *) dummy; 431 dc->client_verify_mode = mode; 432 } else { 433 mgs_srvconf_rec *sc = 434 (mgs_srvconf_rec *) 435 ap_get_module_config(parms->server->module_config, 436 &gnutls_module); 437 sc->client_verify_mode = mode; 438 } 439 440 return NULL; 454 441 } 455 442 456 443 #define INIT_CA_SIZE 128 444 457 445 const char *mgs_set_client_ca_file(cmd_parms * parms, void *dummy, 458 const char *arg) 459 { 460 int rv; 461 const char *file; 462 apr_pool_t *spool; 463 gnutls_datum_t data; 464 465 mgs_srvconf_rec *sc = 466 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 467 module_config, 468 &gnutls_module); 469 apr_pool_create(&spool, parms->pool); 470 471 file = ap_server_root_relative(spool, arg); 472 473 if (load_datum_from_file(spool, file, &data) != 0) { 474 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 475 "Client CA File '%s'", file); 476 } 477 478 sc->ca_list_size = INIT_CA_SIZE; 479 sc->ca_list = malloc(sc->ca_list_size * sizeof(*sc->ca_list)); 480 if (sc->ca_list == NULL) { 481 return apr_psprintf(parms->pool, 482 "mod_gnutls: Memory allocation error"); 483 } 484 485 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size, 486 &data, GNUTLS_X509_FMT_PEM, 487 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); 488 if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) { 489 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 490 "Client CA File '%s': (%d) %s", file, 491 rv, gnutls_strerror(rv)); 492 } 493 494 if (INIT_CA_SIZE < sc->ca_list_size) { 495 sc->ca_list = 496 realloc(sc->ca_list, 497 sc->ca_list_size * sizeof(*sc->ca_list)); 498 if (sc->ca_list == NULL) { 499 return apr_psprintf(parms->pool, 500 "mod_gnutls: Memory allocation error"); 501 } 502 503 /* re-read */ 504 rv = gnutls_x509_crt_list_import(sc->ca_list, 505 &sc->ca_list_size, &data, 506 GNUTLS_X509_FMT_PEM, 0); 507 508 if (rv < 0) { 509 return apr_psprintf(parms->pool, 510 "GnuTLS: Failed to load " 511 "Client CA File '%s': (%d) %s", 512 file, rv, gnutls_strerror(rv)); 513 } 514 } 515 516 apr_pool_destroy(spool); 517 return NULL; 446 const char *arg) { 447 int rv; 448 const char *file; 449 apr_pool_t *spool; 450 gnutls_datum_t data; 451 452 mgs_srvconf_rec *sc = 453 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 454 module_config, 455 &gnutls_module); 456 apr_pool_create(&spool, parms->pool); 457 458 file = ap_server_root_relative(spool, arg); 459 460 if (load_datum_from_file(spool, file, &data) != 0) { 461 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 462 "Client CA File '%s'", file); 463 } 464 465 sc->ca_list_size = INIT_CA_SIZE; 466 sc->ca_list = malloc(sc->ca_list_size * sizeof (*sc->ca_list)); 467 if (sc->ca_list == NULL) { 468 return apr_psprintf(parms->pool, 469 "mod_gnutls: Memory allocation error"); 470 } 471 472 rv = gnutls_x509_crt_list_import(sc->ca_list, &sc->ca_list_size, 473 &data, GNUTLS_X509_FMT_PEM, 474 GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED); 475 if (rv < 0 && rv != GNUTLS_E_SHORT_MEMORY_BUFFER) { 476 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 477 "Client CA File '%s': (%d) %s", file, 478 rv, gnutls_strerror(rv)); 479 } 480 481 if (INIT_CA_SIZE < sc->ca_list_size) { 482 sc->ca_list = 483 realloc(sc->ca_list, 484 sc->ca_list_size * sizeof (*sc->ca_list)); 485 if (sc->ca_list == NULL) { 486 return apr_psprintf(parms->pool, 487 "mod_gnutls: Memory allocation error"); 488 } 489 490 /* re-read */ 491 rv = gnutls_x509_crt_list_import(sc->ca_list, 492 &sc->ca_list_size, &data, 493 GNUTLS_X509_FMT_PEM, 0); 494 495 if (rv < 0) { 496 return apr_psprintf(parms->pool, 497 "GnuTLS: Failed to load " 498 "Client CA File '%s': (%d) %s", 499 file, rv, gnutls_strerror(rv)); 500 } 501 } 502 503 apr_pool_destroy(spool); 504 return NULL; 518 505 } 519 506 520 507 const char *mgs_set_keyring_file(cmd_parms * parms, void *dummy, 521 const char *arg) 522 { 523 int rv; 524 const char *file; 525 apr_pool_t *spool; 526 gnutls_datum_t data; 527 528 mgs_srvconf_rec *sc = 529 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 530 module_config, 531 &gnutls_module); 532 apr_pool_create(&spool, parms->pool); 533 534 file = ap_server_root_relative(spool, arg); 535 536 if (load_datum_from_file(spool, file, &data) != 0) { 537 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 538 "Keyring File '%s'", file); 539 } 540 541 rv = gnutls_openpgp_keyring_init(&sc->pgp_list); 542 if (rv < 0) { 543 return apr_psprintf(parms->pool, 544 "GnuTLS: Failed to initialize" 545 "keyring: (%d) %s", rv, 546 gnutls_strerror(rv)); 547 } 548 549 rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, 550 GNUTLS_OPENPGP_FMT_BASE64); 551 if (rv < 0) { 552 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 553 "Keyring File '%s': (%d) %s", file, rv, 554 gnutls_strerror(rv)); 555 } 556 557 apr_pool_destroy(spool); 558 return NULL; 508 const char *arg) { 509 int rv; 510 const char *file; 511 apr_pool_t *spool; 512 gnutls_datum_t data; 513 514 mgs_srvconf_rec *sc = 515 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 516 module_config, 517 &gnutls_module); 518 apr_pool_create(&spool, parms->pool); 519 520 file = ap_server_root_relative(spool, arg); 521 522 if (load_datum_from_file(spool, file, &data) != 0) { 523 return apr_psprintf(parms->pool, "GnuTLS: Error Reading " 524 "Keyring File '%s'", file); 525 } 526 527 rv = gnutls_openpgp_keyring_init(&sc->pgp_list); 528 if (rv < 0) { 529 return apr_psprintf(parms->pool, 530 "GnuTLS: Failed to initialize" 531 "keyring: (%d) %s", rv, 532 gnutls_strerror(rv)); 533 } 534 535 rv = gnutls_openpgp_keyring_import(sc->pgp_list, &data, 536 GNUTLS_OPENPGP_FMT_BASE64); 537 if (rv < 0) { 538 return apr_psprintf(parms->pool, "GnuTLS: Failed to load " 539 "Keyring File '%s': (%d) %s", file, rv, 540 gnutls_strerror(rv)); 541 } 542 543 apr_pool_destroy(spool); 544 return NULL; 559 545 } 560 546 561 547 const char *mgs_set_enabled(cmd_parms * parms, void *dummy, 562 const char *arg) 563 { 564 mgs_srvconf_rec *sc = 565 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 566 module_config, 567 &gnutls_module); 568 if (!strcasecmp(arg, "On")) { 569 sc->enabled = GNUTLS_ENABLED_TRUE; 570 } else if (!strcasecmp(arg, "Off")) { 571 sc->enabled = GNUTLS_ENABLED_FALSE; 572 } else { 573 return "GnuTLSEnable must be set to 'On' or 'Off'"; 574 } 575 576 return NULL; 548 const char *arg) { 549 mgs_srvconf_rec *sc = 550 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 551 module_config, 552 &gnutls_module); 553 if (!strcasecmp(arg, "On")) { 554 sc->enabled = GNUTLS_ENABLED_TRUE; 555 } else if (!strcasecmp(arg, "Off")) { 556 sc->enabled = GNUTLS_ENABLED_FALSE; 557 } else { 558 return "GnuTLSEnable must be set to 'On' or 'Off'"; 559 } 560 561 return NULL; 577 562 } 578 563 579 564 const char *mgs_set_export_certificates_enabled(cmd_parms * parms, 580 void *dummy, 581 const char *arg) 582 { 583 mgs_srvconf_rec *sc = 584 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 585 module_config, 586 &gnutls_module); 587 if (!strcasecmp(arg, "On")) { 588 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE; 589 } else if (!strcasecmp(arg, "Off")) { 590 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE; 591 } else { 592 return 593 "GnuTLSExportCertificates must be set to 'On' or 'Off'"; 594 } 595 596 return NULL; 597 } 598 565 void *dummy, 566 const char *arg) { 567 mgs_srvconf_rec *sc = 568 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 569 module_config, 570 &gnutls_module); 571 if (!strcasecmp(arg, "On")) { 572 sc->export_certificates_enabled = GNUTLS_ENABLED_TRUE; 573 } else if (!strcasecmp(arg, "Off")) { 574 sc->export_certificates_enabled = GNUTLS_ENABLED_FALSE; 575 } else { 576 return 577 "GnuTLSExportCertificates must be set to 'On' or 'Off'"; 578 } 579 580 return NULL; 581 } 599 582 600 583 const char *mgs_set_priorities(cmd_parms * parms, void *dummy, 601 const char *arg) 602 { 603 int ret; 604 const char *err; 605 mgs_srvconf_rec *sc = 606 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 607 module_config, 608 &gnutls_module); 609 610 611 ret = gnutls_priority_init(&sc->priorities, arg, &err); 612 if (ret < 0) { 613 if (ret == GNUTLS_E_INVALID_REQUEST) 614 return apr_psprintf(parms->pool, 615 "GnuTLS: Syntax error parsing priorities string at: %s", 616 err); 617 return "Error setting priorities"; 618 } 619 620 return NULL; 621 } 622 623 void *mgs_config_server_create(apr_pool_t * p, server_rec * s) 624 { 625 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof(*sc)); 626 int ret; 627 628 sc->enabled = GNUTLS_ENABLED_FALSE; 629 630 ret = gnutls_certificate_allocate_credentials(&sc->certs); 631 if (ret < 0) { 632 return apr_psprintf(p, "GnuTLS: Failed to initialize" 633 ": (%d) %s", ret, 634 gnutls_strerror(ret)); 635 } 636 637 ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds); 638 if (ret < 0) { 639 return apr_psprintf(p, "GnuTLS: Failed to initialize" 640 ": (%d) %s", ret, 641 gnutls_strerror(ret)); 642 } 584 const char *arg) { 585 int ret; 586 const char *err; 587 mgs_srvconf_rec *sc = 588 (mgs_srvconf_rec *) ap_get_module_config(parms->server-> 589 module_config, 590 &gnutls_module); 591 592 593 ret = gnutls_priority_init(&sc->priorities, arg, &err); 594 if (ret < 0) { 595 if (ret == GNUTLS_E_INVALID_REQUEST) 596 return apr_psprintf(parms->pool, 597 "GnuTLS: Syntax error parsing priorities string at: %s", 598 err); 599 return "Error setting priorities"; 600 } 601 602 return NULL; 603 } 604 605 void *mgs_config_server_create(apr_pool_t * p, server_rec * s) { 606 mgs_srvconf_rec *sc = apr_pcalloc(p, sizeof (*sc)); 607 int ret; 608 609 sc->enabled = GNUTLS_ENABLED_FALSE; 610 611 ret = gnutls_certificate_allocate_credentials(&sc->certs); 612 if (ret < 0) { 613 return apr_psprintf(p, "GnuTLS: Failed to initialize" 614 ": (%d) %s", ret, 615 gnutls_strerror(ret)); 616 } 617 618 ret = gnutls_anon_allocate_server_credentials(&sc->anon_creds); 619 if (ret < 0) { 620 return apr_psprintf(p, "GnuTLS: Failed to initialize" 621 ": (%d) %s", ret, 622 gnutls_strerror(ret)); 623 } 643 624 #ifdef ENABLE_SRP 644 645 646 647 648 649 650 651 652 625 ret = gnutls_srp_allocate_server_credentials(&sc->srp_creds); 626 if (ret < 0) { 627 return apr_psprintf(p, "GnuTLS: Failed to initialize" 628 ": (%d) %s", ret, 629 gnutls_strerror(ret)); 630 } 631 632 sc->srp_tpasswd_conf_file = NULL; 633 sc->srp_tpasswd_file = NULL; 653 634 #endif 654 635 655 sc->privkey_x509 = NULL; 656 memset(sc->certs_x509, 0, sizeof(sc->certs_x509)); 657 sc->certs_x509_num = 0; 658 sc->cache_timeout = apr_time_from_sec(300); 659 sc->cache_type = mgs_cache_none; 660 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 661 sc->tickets = 1; /* by default enable session tickets */ 662 663 sc->client_verify_mode = GNUTLS_CERT_IGNORE; 664 665 return sc; 666 } 667 668 void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv) 669 { 670 mgs_dirconf_rec *new; 671 /* mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */ 672 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv; 673 674 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof(mgs_dirconf_rec)); 675 new->client_verify_mode = add->client_verify_mode; 676 return new; 677 } 678 679 void *mgs_config_dir_create(apr_pool_t * p, char *dir) 680 { 681 mgs_dirconf_rec *dc = apr_palloc(p, sizeof(*dc)); 682 dc->client_verify_mode = -1; 683 return dc; 684 } 636 sc->privkey_x509 = NULL; 637 memset(sc->certs_x509, 0, sizeof (sc->certs_x509)); 638 sc->certs_x509_num = 0; 639 sc->cache_timeout = apr_time_from_sec(300); 640 sc->cache_type = mgs_cache_none; 641 sc->cache_config = ap_server_root_relative(p, "conf/gnutls_cache"); 642 sc->tickets = 1; /* by default enable session tickets */ 643 644 sc->client_verify_mode = GNUTLS_CERT_IGNORE; 645 646 return sc; 647 } 648 649 void *mgs_config_dir_merge(apr_pool_t * p, void *basev, void *addv) { 650 mgs_dirconf_rec *new; 651 /* mgs_dirconf_rec *base = (mgs_dirconf_rec *) basev; */ 652 mgs_dirconf_rec *add = (mgs_dirconf_rec *) addv; 653 654 new = (mgs_dirconf_rec *) apr_pcalloc(p, sizeof (mgs_dirconf_rec)); 655 new->client_verify_mode = add->client_verify_mode; 656 return new; 657 } 658 659 void *mgs_config_dir_create(apr_pool_t * p, char *dir) { 660 mgs_dirconf_rec *dc = apr_palloc(p, sizeof (*dc)); 661 dc->client_verify_mode = -1; 662 return dc; 663 } -
src/gnutls_hooks.c
r6223319 re183628 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Copyright 2007 Nikos Mavrogiannopoulos 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 4 5 * 5 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 22 23 23 24 #if APR_HAS_THREADS 24 # 25 #if GNUTLS_VERSION_MAJOR <= 2 && GNUTLS_VERSION_MINOR < 11 25 26 #include <gcrypt.h> 26 27 GCRY_THREAD_OPTION_PTHREAD_IMPL; 27 # 28 #endif 28 29 #endif 29 30 … … 37 38 38 39 static int mpm_is_threaded; 39 static gnutls_datum session_ticket_key = { NULL, 0};40 static gnutls_datum session_ticket_key = {NULL, 0}; 40 41 41 42 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt); 42 43 /* use side==0 for server and side==1 for client */ 43 44 static void mgs_add_common_cert_vars(request_rec * r, 44 45 45 gnutls_x509_crt_t cert, int side, 46 int export_certificates_enabled); 46 47 static void mgs_add_common_pgpcert_vars(request_rec * r, 47 gnutls_openpgp_crt_t cert, 48 int side, 49 int export_certificates_enabled); 50 51 static apr_status_t mgs_cleanup_pre_config(void *data) 52 { 53 gnutls_free(session_ticket_key.data); 54 session_ticket_key.data = NULL; 55 session_ticket_key.size = 0; 56 gnutls_global_deinit(); 57 return APR_SUCCESS; 48 gnutls_openpgp_crt_t cert, 49 int side, 50 int export_certificates_enabled); 51 52 static apr_status_t mgs_cleanup_pre_config(void *data) { 53 gnutls_free(session_ticket_key.data); 54 session_ticket_key.data = NULL; 55 session_ticket_key.size = 0; 56 gnutls_global_deinit(); 57 return APR_SUCCESS; 58 58 } 59 59 60 60 #if MOD_GNUTLS_DEBUG 61 static void gnutls_debug_log_all(int level, const char *str) 62 {63 61 62 static void gnutls_debug_log_all(int level, const char *str) { 63 apr_file_printf(debug_log_fp, "<%d> %s\n", level, str); 64 64 } 65 65 66 66 #define _gnutls_log apr_file_printf 67 67 #else 68 # 68 #define _gnutls_log(...) 69 69 #endif 70 70 71 71 int 72 72 mgs_hook_pre_config(apr_pool_t * pconf, 73 apr_pool_t * plog, apr_pool_t * ptemp) 74 { 75 int ret; 73 apr_pool_t * plog, apr_pool_t * ptemp) { 74 int ret; 76 75 77 76 #if MOD_GNUTLS_DEBUG 78 79 80 81 82 83 84 85 86 87 77 apr_file_open(&debug_log_fp, "/tmp/gnutls_debug", 78 APR_APPEND | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, 79 pconf); 80 81 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 82 83 gnutls_global_set_log_level(9); 84 gnutls_global_set_log_function(gnutls_debug_log_all); 85 _gnutls_log(debug_log_fp, "gnutls: %s\n", 86 gnutls_check_version(NULL)); 88 87 #endif 89 88 90 89 #if APR_HAS_THREADS 91 90 ap_mpm_query(AP_MPMQ_IS_THREADED, &mpm_is_threaded); 92 91 #if (GNUTLS_VERSION_MAJOR == 2 && GNUTLS_VERSION_MINOR < 11) || GNUTLS_VERSION_MAJOR < 2 93 94 95 96 92 if (mpm_is_threaded) { 93 gcry_control(GCRYCTL_SET_THREAD_CBS, 94 &gcry_threads_pthread); 95 } 97 96 #endif 98 97 #else 99 mpm_is_threaded = 0; 100 #endif 101 102 103 if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) { 104 _gnutls_log(debug_log_fp, 105 "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", 106 LIBGNUTLS_VERSION, gnutls_check_version(NULL)); 107 return -3; 108 } 109 110 ret = gnutls_global_init(); 111 if (ret < 0) { 112 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n", 113 gnutls_strerror(ret)); 114 return -3; 115 } 116 117 ret = gnutls_session_ticket_key_generate(&session_ticket_key); 118 if (ret < 0) { 119 _gnutls_log(debug_log_fp, 120 "gnutls_session_ticket_key_generate: %s\n", 121 gnutls_strerror(ret)); 122 } 123 124 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 125 apr_pool_cleanup_null); 126 127 128 return OK; 129 } 130 131 static int mgs_select_virtual_server_cb(gnutls_session_t session) 132 { 133 mgs_handle_t *ctxt; 134 mgs_srvconf_rec *tsc; 135 int ret; 136 int cprio[2]; 137 138 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 139 140 ctxt = gnutls_transport_get_ptr(session); 141 142 /* find the virtual server */ 143 tsc = mgs_find_sni_server(session); 144 145 if (tsc != NULL) 146 ctxt->sc = tsc; 147 148 gnutls_certificate_server_set_request(session, 149 ctxt-> 150 sc->client_verify_mode); 151 152 /* set the new server credentials 153 */ 154 155 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, 156 ctxt->sc->certs); 157 158 gnutls_credentials_set(session, GNUTLS_CRD_ANON, 159 ctxt->sc->anon_creds); 98 mpm_is_threaded = 0; 99 #endif 100 101 102 if (gnutls_check_version(LIBGNUTLS_VERSION) == NULL) { 103 _gnutls_log(debug_log_fp, 104 "gnutls_check_version() failed. Required: gnutls-%s Found: gnutls-%s\n", 105 LIBGNUTLS_VERSION, gnutls_check_version(NULL)); 106 return -3; 107 } 108 109 ret = gnutls_global_init(); 110 if (ret < 0) { 111 _gnutls_log(debug_log_fp, "gnutls_global_init: %s\n", 112 gnutls_strerror(ret)); 113 return -3; 114 } 115 116 ret = gnutls_session_ticket_key_generate(&session_ticket_key); 117 if (ret < 0) { 118 _gnutls_log(debug_log_fp, 119 "gnutls_session_ticket_key_generate: %s\n", 120 gnutls_strerror(ret)); 121 } 122 123 apr_pool_cleanup_register(pconf, NULL, mgs_cleanup_pre_config, 124 apr_pool_cleanup_null); 125 126 127 return OK; 128 } 129 130 static int mgs_select_virtual_server_cb(gnutls_session_t session) { 131 mgs_handle_t *ctxt; 132 mgs_srvconf_rec *tsc; 133 int ret; 134 int cprio[2]; 135 136 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 137 138 ctxt = gnutls_transport_get_ptr(session); 139 140 /* find the virtual server */ 141 tsc = mgs_find_sni_server(session); 142 143 if (tsc != NULL) 144 ctxt->sc = tsc; 145 146 gnutls_certificate_server_set_request(session, 147 ctxt-> 148 sc->client_verify_mode); 149 150 /* set the new server credentials 151 */ 152 153 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, 154 ctxt->sc->certs); 155 156 gnutls_credentials_set(session, GNUTLS_CRD_ANON, 157 ctxt->sc->anon_creds); 160 158 161 159 #ifdef ENABLE_SRP 162 if (ctxt->sc->srp_tpasswd_conf_file != NULL 163 && ctxt->sc->srp_tpasswd_file != NULL) { 164 gnutls_credentials_set(session, GNUTLS_CRD_SRP, 165 ctxt->sc->srp_creds); 166 } 167 #endif 168 169 /* update the priorities - to avoid negotiating a ciphersuite that is not 170 * enabled on this virtual server. Note that here we ignore the version 171 * negotiation. 172 */ 173 ret = gnutls_priority_set(session, ctxt->sc->priorities); 174 /* actually it shouldn't fail since we have checked at startup */ 175 if (ret < 0) 176 return ret; 177 178 /* If both certificate types are not present disallow them from 179 * being negotiated. 180 */ 181 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) { 182 cprio[0] = GNUTLS_CRT_X509; 183 cprio[1] = 0; 184 gnutls_certificate_type_set_priority(session, cprio); 185 } else if (ctxt->sc->cert_pgp != NULL 186 && ctxt->sc->certs_x509[0] == NULL) { 187 cprio[0] = GNUTLS_CRT_OPENPGP; 188 cprio[1] = 0; 189 gnutls_certificate_type_set_priority(session, cprio); 190 } 191 192 return 0; 193 } 194 195 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) 196 { 197 mgs_handle_t *ctxt; 198 199 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 200 ctxt = gnutls_transport_get_ptr(session); 201 202 if (ctxt == NULL) 203 return GNUTLS_E_INTERNAL_ERROR; 204 205 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { 206 ret->type = GNUTLS_CRT_X509; 207 ret->ncerts = ctxt->sc->certs_x509_num; 208 ret->deinit_all = 0; 209 210 ret->cert.x509 = ctxt->sc->certs_x509; 211 ret->key.x509 = ctxt->sc->privkey_x509; 212 213 return 0; 214 } else if (gnutls_certificate_type_get(session) == 215 GNUTLS_CRT_OPENPGP) { 216 ret->type = GNUTLS_CRT_OPENPGP; 217 ret->ncerts = 1; 218 ret->deinit_all = 0; 219 220 ret->cert.pgp = ctxt->sc->cert_pgp; 221 ret->key.pgp = ctxt->sc->privkey_pgp; 222 223 return 0; 224 225 } 226 227 return GNUTLS_E_INTERNAL_ERROR; 160 if (ctxt->sc->srp_tpasswd_conf_file != NULL 161 && ctxt->sc->srp_tpasswd_file != NULL) { 162 gnutls_credentials_set(session, GNUTLS_CRD_SRP, 163 ctxt->sc->srp_creds); 164 } 165 #endif 166 167 /* update the priorities - to avoid negotiating a ciphersuite that is not 168 * enabled on this virtual server. Note that here we ignore the version 169 * negotiation. 170 */ 171 ret = gnutls_priority_set(session, ctxt->sc->priorities); 172 /* actually it shouldn't fail since we have checked at startup */ 173 if (ret < 0) 174 return ret; 175 176 /* If both certificate types are not present disallow them from 177 * being negotiated. 178 */ 179 if (ctxt->sc->certs_x509[0] != NULL && ctxt->sc->cert_pgp == NULL) { 180 cprio[0] = GNUTLS_CRT_X509; 181 cprio[1] = 0; 182 gnutls_certificate_type_set_priority(session, cprio); 183 } else if (ctxt->sc->cert_pgp != NULL 184 && ctxt->sc->certs_x509[0] == NULL) { 185 cprio[0] = GNUTLS_CRT_OPENPGP; 186 cprio[1] = 0; 187 gnutls_certificate_type_set_priority(session, cprio); 188 } 189 190 return 0; 191 } 192 193 static int cert_retrieve_fn(gnutls_session_t session, gnutls_retr_st * ret) { 194 mgs_handle_t *ctxt; 195 196 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 197 ctxt = gnutls_transport_get_ptr(session); 198 199 if (ctxt == NULL) 200 return GNUTLS_E_INTERNAL_ERROR; 201 202 if (gnutls_certificate_type_get(session) == GNUTLS_CRT_X509) { 203 ret->type = GNUTLS_CRT_X509; 204 ret->ncerts = ctxt->sc->certs_x509_num; 205 ret->deinit_all = 0; 206 207 ret->cert.x509 = ctxt->sc->certs_x509; 208 ret->key.x509 = ctxt->sc->privkey_x509; 209 210 return 0; 211 } else if (gnutls_certificate_type_get(session) == 212 GNUTLS_CRT_OPENPGP) { 213 ret->type = GNUTLS_CRT_OPENPGP; 214 ret->ncerts = 1; 215 ret->deinit_all = 0; 216 217 ret->cert.pgp = ctxt->sc->cert_pgp; 218 ret->key.pgp = ctxt->sc->privkey_pgp; 219 220 return 0; 221 222 } 223 224 return GNUTLS_E_INTERNAL_ERROR; 228 225 } 229 226 230 227 /* 2048-bit group parameters from SRP specification */ 231 228 const char static_dh_params[] = "-----BEGIN DH PARAMETERS-----\n" 232 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n"233 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n"234 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n"235 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n"236 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n"237 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n"238 "-----END DH PARAMETERS-----\n";229 "MIIBBwKCAQCsa9tBMkqam/Fm3l4TiVgvr3K2ZRmH7gf8MZKUPbVgUKNzKcu0oJnt\n" 230 "gZPgdXdnoT3VIxKrSwMxDc1/SKnaBP1Q6Ag5ae23Z7DPYJUXmhY6s2YaBfvV+qro\n" 231 "KRipli8Lk7hV+XmT7Jde6qgNdArb9P90c1nQQdXDPqcdKB5EaxR3O8qXtDoj+4AW\n" 232 "dr0gekNsZIHx0rkHhxdGGludMuaI+HdIVEUjtSSw1X1ep3onddLs+gMs+9v1L7N4\n" 233 "YWAnkATleuavh05zA85TKZzMBBx7wwjYKlaY86jQw4JxrjX46dv7tpS1yAPYn3rk\n" 234 "Nd4jbVJfVHWbZeNy/NaO8g+nER+eSv9zAgEC\n" 235 "-----END DH PARAMETERS-----\n"; 239 236 240 237 /* Read the common name or the alternative name of the certificate. … … 244 241 */ 245 242 static int read_crt_cn(server_rec * s, apr_pool_t * p, 246 gnutls_x509_crt_t cert, char **cert_cn) 247 { 248 int rv = 0, i; 249 size_t data_len; 250 251 252 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 253 *cert_cn = NULL; 254 255 data_len = 0; 256 rv = gnutls_x509_crt_get_dn_by_oid(cert, 257 GNUTLS_OID_X520_COMMON_NAME, 258 0, 0, NULL, &data_len); 259 260 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 261 *cert_cn = apr_palloc(p, data_len); 262 rv = gnutls_x509_crt_get_dn_by_oid(cert, 263 GNUTLS_OID_X520_COMMON_NAME, 264 0, 0, *cert_cn, 265 &data_len); 266 } else { /* No CN return subject alternative name */ 267 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 268 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 269 s->server_hostname, s->port); 270 rv = 0; 271 /* read subject alternative name */ 272 for (i = 0; !(rv < 0); i++) { 273 data_len = 0; 274 rv = gnutls_x509_crt_get_subject_alt_name(cert, i, 275 NULL, 276 &data_len, 277 NULL); 278 279 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER 280 && data_len > 1) { 281 /* FIXME: not very efficient. What if we have several alt names 282 * before DNSName? 283 */ 284 *cert_cn = apr_palloc(p, data_len + 1); 285 286 rv = gnutls_x509_crt_get_subject_alt_name 287 (cert, i, *cert_cn, &data_len, NULL); 288 (*cert_cn)[data_len] = 0; 289 290 if (rv == GNUTLS_SAN_DNSNAME) 291 break; 292 } 293 } 294 } 295 296 return rv; 243 gnutls_x509_crt_t cert, char **cert_cn) { 244 int rv = 0, i; 245 size_t data_len; 246 247 248 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 249 *cert_cn = NULL; 250 251 data_len = 0; 252 rv = gnutls_x509_crt_get_dn_by_oid(cert, 253 GNUTLS_OID_X520_COMMON_NAME, 254 0, 0, NULL, &data_len); 255 256 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 257 *cert_cn = apr_palloc(p, data_len); 258 rv = gnutls_x509_crt_get_dn_by_oid(cert, 259 GNUTLS_OID_X520_COMMON_NAME, 260 0, 0, *cert_cn, 261 &data_len); 262 } else { /* No CN return subject alternative name */ 263 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, 264 "No common name found in certificate for '%s:%d'. Looking for subject alternative name...", 265 s->server_hostname, s->port); 266 rv = 0; 267 /* read subject alternative name */ 268 for (i = 0; !(rv < 0); i++) { 269 data_len = 0; 270 rv = gnutls_x509_crt_get_subject_alt_name(cert, i, 271 NULL, 272 &data_len, 273 NULL); 274 275 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER 276 && data_len > 1) { 277 /* FIXME: not very efficient. What if we have several alt names 278 * before DNSName? 279 */ 280 *cert_cn = apr_palloc(p, data_len + 1); 281 282 rv = gnutls_x509_crt_get_subject_alt_name 283 (cert, i, *cert_cn, &data_len, NULL); 284 (*cert_cn)[data_len] = 0; 285 286 if (rv == GNUTLS_SAN_DNSNAME) 287 break; 288 } 289 } 290 } 291 292 return rv; 297 293 } 298 294 299 295 static int read_pgpcrt_cn(server_rec * s, apr_pool_t * p, 300 gnutls_openpgp_crt_t cert, char **cert_cn) 301 { 302 int rv = 0; 303 size_t data_len; 304 305 306 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 307 *cert_cn = NULL; 308 309 data_len = 0; 310 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); 311 312 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 313 *cert_cn = apr_palloc(p, data_len); 314 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, 315 &data_len); 316 } else { /* No CN return subject alternative name */ 317 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 318 "No name found in PGP certificate for '%s:%d'.", 319 s->server_hostname, s->port); 320 } 321 322 return rv; 323 } 324 296 gnutls_openpgp_crt_t cert, char **cert_cn) { 297 int rv = 0; 298 size_t data_len; 299 300 301 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 302 *cert_cn = NULL; 303 304 data_len = 0; 305 rv = gnutls_openpgp_crt_get_name(cert, 0, NULL, &data_len); 306 307 if (rv == GNUTLS_E_SHORT_MEMORY_BUFFER && data_len > 1) { 308 *cert_cn = apr_palloc(p, data_len); 309 rv = gnutls_openpgp_crt_get_name(cert, 0, *cert_cn, 310 &data_len); 311 } else { /* No CN return subject alternative name */ 312 ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, 313 "No name found in PGP certificate for '%s:%d'.", 314 s->server_hostname, s->port); 315 } 316 317 return rv; 318 } 325 319 326 320 int 327 321 mgs_hook_post_config(apr_pool_t * p, apr_pool_t * plog, 328 apr_pool_t * ptemp, server_rec * base_server) 329 { 330 int rv; 331 server_rec *s; 332 gnutls_dh_params_t dh_params = NULL; 333 gnutls_rsa_params_t rsa_params = NULL; 334 mgs_srvconf_rec *sc; 335 mgs_srvconf_rec *sc_base; 336 void *data = NULL; 337 int first_run = 0; 338 const char *userdata_key = "mgs_init"; 339 340 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 341 apr_pool_userdata_get(&data, userdata_key, 342 base_server->process->pool); 343 if (data == NULL) { 344 first_run = 1; 345 apr_pool_userdata_set((const void *) 1, userdata_key, 346 apr_pool_cleanup_null, 347 base_server->process->pool); 348 } 349 350 351 s = base_server; 352 sc_base = 353 (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 354 &gnutls_module); 355 356 gnutls_dh_params_init(&dh_params); 357 358 if (sc_base->dh_params == NULL) { 359 gnutls_datum pdata = { 360 (void *) static_dh_params, 361 sizeof(static_dh_params) 362 }; 363 /* loading defaults */ 364 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 365 GNUTLS_X509_FMT_PEM); 366 367 if (rv < 0) { 368 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 369 "GnuTLS: Unable to load DH Params: (%d) %s", 370 rv, gnutls_strerror(rv)); 371 exit(rv); 372 } 373 } else 374 dh_params = sc_base->dh_params; 375 376 if (sc_base->rsa_params != NULL) 377 rsa_params = sc_base->rsa_params; 378 379 /* else not an error but RSA-EXPORT ciphersuites are not available 380 */ 381 382 rv = mgs_cache_post_config(p, s, sc_base); 383 if (rv != 0) { 384 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 385 "GnuTLS: Post Config for GnuTLSCache Failed." 386 " Shutting Down."); 387 exit(-1); 388 } 389 390 for (s = base_server; s; s = s->next) { 391 void *load = NULL; 392 sc = (mgs_srvconf_rec *) 393 ap_get_module_config(s->module_config, &gnutls_module); 394 sc->cache_type = sc_base->cache_type; 395 sc->cache_config = sc_base->cache_config; 396 397 /* Check if the priorities have been set */ 398 if (sc->priorities == NULL 399 && sc->enabled == GNUTLS_ENABLED_TRUE) { 400 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 401 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!", 402 s->server_hostname, s->port); 403 exit(-1); 404 } 405 406 /* Check if DH or RSA params have been set per host */ 407 if (sc->rsa_params != NULL) 408 load = sc->rsa_params; 409 else if (rsa_params) 410 load = rsa_params; 411 412 if (load != NULL) 413 gnutls_certificate_set_rsa_export_params(sc->certs, 414 load); 415 416 417 load = NULL; 418 if (sc->dh_params != NULL) 419 load = sc->dh_params; 420 else if (dh_params) 421 load = dh_params; 422 423 if (load != NULL) { /* not needed but anyway */ 424 gnutls_certificate_set_dh_params(sc->certs, load); 425 gnutls_anon_set_server_dh_params(sc->anon_creds, 426 load); 427 } 428 429 gnutls_certificate_server_set_retrieve_function(sc->certs, 430 cert_retrieve_fn); 322 apr_pool_t * ptemp, server_rec * base_server) { 323 int rv; 324 server_rec *s; 325 gnutls_dh_params_t dh_params = NULL; 326 gnutls_rsa_params_t rsa_params = NULL; 327 mgs_srvconf_rec *sc; 328 mgs_srvconf_rec *sc_base; 329 void *data = NULL; 330 int first_run = 0; 331 const char *userdata_key = "mgs_init"; 332 333 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 334 apr_pool_userdata_get(&data, userdata_key, 335 base_server->process->pool); 336 if (data == NULL) { 337 first_run = 1; 338 apr_pool_userdata_set((const void *) 1, userdata_key, 339 apr_pool_cleanup_null, 340 base_server->process->pool); 341 } 342 343 344 s = base_server; 345 sc_base = 346 (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 347 &gnutls_module); 348 349 gnutls_dh_params_init(&dh_params); 350 351 if (sc_base->dh_params == NULL) { 352 gnutls_datum pdata = { 353 (void *) static_dh_params, 354 sizeof (static_dh_params) 355 }; 356 /* loading defaults */ 357 rv = gnutls_dh_params_import_pkcs3(dh_params, &pdata, 358 GNUTLS_X509_FMT_PEM); 359 360 if (rv < 0) { 361 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 362 "GnuTLS: Unable to load DH Params: (%d) %s", 363 rv, gnutls_strerror(rv)); 364 exit(rv); 365 } 366 } else 367 dh_params = sc_base->dh_params; 368 369 if (sc_base->rsa_params != NULL) 370 rsa_params = sc_base->rsa_params; 371 372 /* else not an error but RSA-EXPORT ciphersuites are not available 373 */ 374 375 rv = mgs_cache_post_config(p, s, sc_base); 376 if (rv != 0) { 377 ap_log_error(APLOG_MARK, APLOG_STARTUP, rv, s, 378 "GnuTLS: Post Config for GnuTLSCache Failed." 379 " Shutting Down."); 380 exit(-1); 381 } 382 383 for (s = base_server; s; s = s->next) { 384 void *load = NULL; 385 sc = (mgs_srvconf_rec *) 386 ap_get_module_config(s->module_config, &gnutls_module); 387 sc->cache_type = sc_base->cache_type; 388 sc->cache_config = sc_base->cache_config; 389 390 /* Check if the priorities have been set */ 391 if (sc->priorities == NULL 392 && sc->enabled == GNUTLS_ENABLED_TRUE) { 393 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 394 "GnuTLS: Host '%s:%d' is missing the GnuTLSPriorities directive!", 395 s->server_hostname, s->port); 396 exit(-1); 397 } 398 399 /* Check if DH or RSA params have been set per host */ 400 if (sc->rsa_params != NULL) 401 load = sc->rsa_params; 402 else if (rsa_params) 403 load = rsa_params; 404 405 if (load != NULL) 406 gnutls_certificate_set_rsa_export_params(sc->certs, 407 load); 408 409 410 load = NULL; 411 if (sc->dh_params != NULL) 412 load = sc->dh_params; 413 else if (dh_params) 414 load = dh_params; 415 416 if (load != NULL) { /* not needed but anyway */ 417 gnutls_certificate_set_dh_params(sc->certs, load); 418 gnutls_anon_set_server_dh_params(sc->anon_creds, 419 load); 420 } 421 422 gnutls_certificate_server_set_retrieve_function(sc->certs, 423 cert_retrieve_fn); 431 424 432 425 #ifdef ENABLE_SRP 433 if (sc->srp_tpasswd_conf_file != NULL 434 && sc->srp_tpasswd_file != NULL) { 435 rv = gnutls_srp_set_server_credentials_file 436 (sc->srp_creds, sc->srp_tpasswd_file, 437 sc->srp_tpasswd_conf_file); 438 439 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) { 440 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 441 s, 442 "[GnuTLS] - Host '%s:%d' is missing a " 443 "SRP password or conf File!", 444 s->server_hostname, s->port); 445 exit(-1); 446 } 447 } 448 #endif 449 450 if (sc->certs_x509[0] == NULL && 451 sc->cert_pgp == NULL && 452 sc->enabled == GNUTLS_ENABLED_TRUE) { 453 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 454 "[GnuTLS] - Host '%s:%d' is missing a " 455 "Certificate File!", 456 s->server_hostname, s->port); 457 exit(-1); 458 } 459 460 if (sc->enabled == GNUTLS_ENABLED_TRUE && 461 ((sc->certs_x509[0] != NULL 462 && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL 463 && sc->privkey_pgp 464 == NULL))) { 465 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 466 "[GnuTLS] - Host '%s:%d' is missing a " 467 "Private Key File!", 468 s->server_hostname, s->port); 469 exit(-1); 470 } 471 472 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 473 rv = read_crt_cn(s, p, sc->certs_x509[0], 474 &sc->cert_cn); 475 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */ 476 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, 477 &sc->cert_cn); 478 479 if (rv < 0) { 480 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 481 s, 482 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 483 s->server_hostname, s->port); 484 sc->cert_cn = NULL; 485 continue; 486 } 487 } 488 } 489 490 491 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 492 493 return OK; 494 } 495 496 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) 497 { 498 apr_status_t rv = APR_SUCCESS; 499 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 500 &gnutls_module); 501 502 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 503 if (sc->cache_type != mgs_cache_none) { 504 rv = mgs_cache_child_init(p, s, sc); 505 if (rv != APR_SUCCESS) { 506 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 507 "[GnuTLS] - Failed to run Cache Init"); 508 } 509 } 510 } 511 512 const char *mgs_hook_http_scheme(const request_rec * r) 513 { 514 mgs_srvconf_rec *sc; 515 516 if (r == NULL) 517 return NULL; 518 519 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 520 server->module_config, 521 &gnutls_module); 522 523 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 524 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 525 return NULL; 526 } 527 528 return "https"; 529 } 530 531 apr_port_t mgs_hook_default_port(const request_rec * r) 532 { 533 mgs_srvconf_rec *sc; 534 535 if (r == NULL) 536 return 0; 537 538 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 539 server->module_config, 540 &gnutls_module); 541 542 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 543 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 544 return 0; 545 } 546 547 return 443; 426 if (sc->srp_tpasswd_conf_file != NULL 427 && sc->srp_tpasswd_file != NULL) { 428 rv = gnutls_srp_set_server_credentials_file 429 (sc->srp_creds, sc->srp_tpasswd_file, 430 sc->srp_tpasswd_conf_file); 431 432 if (rv < 0 && sc->enabled == GNUTLS_ENABLED_TRUE) { 433 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 434 s, 435 "[GnuTLS] - Host '%s:%d' is missing a " 436 "SRP password or conf File!", 437 s->server_hostname, s->port); 438 exit(-1); 439 } 440 } 441 #endif 442 443 if (sc->certs_x509[0] == NULL && 444 sc->cert_pgp == NULL && 445 sc->enabled == GNUTLS_ENABLED_TRUE) { 446 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 447 "[GnuTLS] - Host '%s:%d' is missing a " 448 "Certificate File!", 449 s->server_hostname, s->port); 450 exit(-1); 451 } 452 453 if (sc->enabled == GNUTLS_ENABLED_TRUE && 454 ((sc->certs_x509[0] != NULL 455 && sc->privkey_x509 == NULL) || (sc->cert_pgp != NULL 456 && sc->privkey_pgp 457 == NULL))) { 458 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, s, 459 "[GnuTLS] - Host '%s:%d' is missing a " 460 "Private Key File!", 461 s->server_hostname, s->port); 462 exit(-1); 463 } 464 465 if (sc->enabled == GNUTLS_ENABLED_TRUE) { 466 rv = read_crt_cn(s, p, sc->certs_x509[0], 467 &sc->cert_cn); 468 if (rv < 0 && sc->cert_pgp != NULL) /* try openpgp certificate */ 469 rv = read_pgpcrt_cn(s, p, sc->cert_pgp, 470 &sc->cert_cn); 471 472 if (rv < 0) { 473 ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, 474 s, 475 "[GnuTLS] - Cannot find a certificate for host '%s:%d'!", 476 s->server_hostname, s->port); 477 sc->cert_cn = NULL; 478 continue; 479 } 480 } 481 } 482 483 484 ap_add_version_component(p, "mod_gnutls/" MOD_GNUTLS_VERSION); 485 486 return OK; 487 } 488 489 void mgs_hook_child_init(apr_pool_t * p, server_rec * s) { 490 apr_status_t rv = APR_SUCCESS; 491 mgs_srvconf_rec *sc = ap_get_module_config(s->module_config, 492 &gnutls_module); 493 494 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 495 if (sc->cache_type != mgs_cache_none) { 496 rv = mgs_cache_child_init(p, s, sc); 497 if (rv != APR_SUCCESS) { 498 ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s, 499 "[GnuTLS] - Failed to run Cache Init"); 500 } 501 } 502 } 503 504 const char *mgs_hook_http_scheme(const request_rec * r) { 505 mgs_srvconf_rec *sc; 506 507 if (r == NULL) 508 return NULL; 509 510 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 511 server->module_config, 512 &gnutls_module); 513 514 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 515 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 516 return NULL; 517 } 518 519 return "https"; 520 } 521 522 apr_port_t mgs_hook_default_port(const request_rec * r) { 523 mgs_srvconf_rec *sc; 524 525 if (r == NULL) 526 return 0; 527 528 sc = (mgs_srvconf_rec *) ap_get_module_config(r-> 529 server->module_config, 530 &gnutls_module); 531 532 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 533 if (sc->enabled == GNUTLS_ENABLED_FALSE) { 534 return 0; 535 } 536 537 return 443; 548 538 } 549 539 … … 551 541 552 542 #if USING_2_1_RECENT 543 553 544 typedef struct { 554 555 556 545 mgs_handle_t *ctxt; 546 mgs_srvconf_rec *sc; 547 const char *sni_name; 557 548 } vhost_cb_rec; 558 549 559 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) 560 { 561 mgs_srvconf_rec *tsc; 562 vhost_cb_rec *x = baton; 563 564 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 565 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 566 &gnutls_module); 567 568 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 569 return 0; 570 } 571 572 /* The CN can contain a * -- this will match those too. */ 573 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 574 /* found a match */ 550 static int vhost_cb(void *baton, conn_rec * conn, server_rec * s) { 551 mgs_srvconf_rec *tsc; 552 vhost_cb_rec *x = baton; 553 554 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 555 tsc = (mgs_srvconf_rec *) ap_get_module_config(s->module_config, 556 &gnutls_module); 557 558 if (tsc->enabled != GNUTLS_ENABLED_TRUE || tsc->cert_cn == NULL) { 559 return 0; 560 } 561 562 /* The CN can contain a * -- this will match those too. */ 563 if (ap_strcasecmp_match(x->sni_name, tsc->cert_cn) == 0) { 564 /* found a match */ 575 565 #if MOD_GNUTLS_DEBUG 576 577 578 579 580 #endif 581 582 583 584 585 586 587 588 589 590 566 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 567 x->ctxt->c->base_server, 568 "GnuTLS: Virtual Host CB: " 569 "'%s' == '%s'", tsc->cert_cn, x->sni_name); 570 #endif 571 /* Because we actually change the server used here, we need to reset 572 * things like ClientVerify. 573 */ 574 x->sc = tsc; 575 /* Shit. Crap. Dammit. We *really* should rehandshake here, as our 576 * certificate structure *should* change when the server changes. 577 * acccckkkkkk. 578 */ 579 return 1; 580 } else { 591 581 #if MOD_GNUTLS_DEBUG 592 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 593 x->ctxt->c->base_server, 594 "GnuTLS: Virtual Host CB: " 595 "'%s' != '%s'", tsc->cert_cn, x->sni_name); 596 #endif 597 598 } 599 return 0; 600 } 601 #endif 602 603 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) 604 { 605 int rv; 606 unsigned int sni_type; 607 size_t data_len = MAX_HOST_LEN; 608 char sni_name[MAX_HOST_LEN]; 609 mgs_handle_t *ctxt; 582 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 583 x->ctxt->c->base_server, 584 "GnuTLS: Virtual Host CB: " 585 "'%s' != '%s'", tsc->cert_cn, x->sni_name); 586 #endif 587 588 } 589 return 0; 590 } 591 #endif 592 593 mgs_srvconf_rec *mgs_find_sni_server(gnutls_session_t session) { 594 int rv; 595 unsigned int sni_type; 596 size_t data_len = MAX_HOST_LEN; 597 char sni_name[MAX_HOST_LEN]; 598 mgs_handle_t *ctxt; 610 599 #if USING_2_1_RECENT 611 600 vhost_cb_rec cbx; 612 601 #else 613 614 615 #endif 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 602 server_rec *s; 603 mgs_srvconf_rec *tsc; 604 #endif 605 606 if (session == NULL) 607 return NULL; 608 609 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 610 ctxt = gnutls_transport_get_ptr(session); 611 612 rv = gnutls_server_name_get(ctxt->session, sni_name, 613 &data_len, &sni_type, 0); 614 615 if (rv != 0) { 616 return NULL; 617 } 618 619 if (sni_type != GNUTLS_NAME_DNS) { 620 ap_log_error(APLOG_MARK, APLOG_CRIT, 0, 621 ctxt->c->base_server, 622 "GnuTLS: Unknown type '%d' for SNI: " 623 "'%s'", sni_type, sni_name); 624 return NULL; 625 } 637 626 638 627 /** … … 641 630 */ 642 631 #if USING_2_1_RECENT 643 644 645 646 647 648 649 650 632 cbx.ctxt = ctxt; 633 cbx.sc = NULL; 634 cbx.sni_name = sni_name; 635 636 rv = ap_vhost_iterate_given_conn(ctxt->c, vhost_cb, &cbx); 637 if (rv == 1) { 638 return cbx.sc; 639 } 651 640 #else 652 653 654 655 656 657 658 659 641 for (s = ap_server_conf; s; s = s->next) { 642 643 tsc = 644 (mgs_srvconf_rec *) 645 ap_get_module_config(s->module_config, &gnutls_module); 646 if (tsc->enabled != GNUTLS_ENABLED_TRUE) { 647 continue; 648 } 660 649 #if MOD_GNUTLS_DEBUG 661 662 663 664 665 666 667 668 669 #endif 670 671 650 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 651 ctxt->c->base_server, 652 "GnuTLS: sni-x509 cn: %s/%d pk: %s s: 0x%08X s->n: 0x%08X sc: 0x%08X", 653 tsc->cert_cn, rv, 654 gnutls_pk_algorithm_get_name 655 (gnutls_x509_privkey_get_pk_algorithm 656 (ctxt->sc->privkey_x509)), (unsigned int) s, 657 (unsigned int) s->next, (unsigned int) tsc); 658 #endif 659 /* The CN can contain a * -- this will match those too. */ 660 if (ap_strcasecmp_match(sni_name, tsc->cert_cn) == 0) { 672 661 #if MOD_GNUTLS_DEBUG 673 674 675 676 677 678 #endif 679 680 681 682 #endif 683 662 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, 663 ctxt->c->base_server, 664 "GnuTLS: Virtual Host: " 665 "'%s' == '%s'", tsc->cert_cn, 666 sni_name); 667 #endif 668 return tsc; 669 } 670 } 671 #endif 672 return NULL; 684 673 } 685 674 686 675 687 676 static const int protocol_priority[] = { 688 677 GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 689 678 }; 690 679 691 692 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) 693 { 694 mgs_handle_t *ctxt; 695 mgs_srvconf_rec *sc = 696 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 697 module_config, 698 &gnutls_module); 699 700 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 701 ctxt = apr_pcalloc(pool, sizeof(*ctxt)); 702 ctxt->c = c; 703 ctxt->sc = sc; 704 ctxt->status = 0; 705 706 ctxt->input_rc = APR_SUCCESS; 707 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc); 708 ctxt->input_cbuf.length = 0; 709 710 ctxt->output_rc = APR_SUCCESS; 711 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc); 712 ctxt->output_blen = 0; 713 ctxt->output_length = 0; 714 715 gnutls_init(&ctxt->session, GNUTLS_SERVER); 716 if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) 717 gnutls_session_ticket_enable_server(ctxt->session, 718 &session_ticket_key); 719 720 /* because we don't set any default priorities here (we set later at 721 * the user hello callback) we need to at least set this in order for 722 * gnutls to be able to read packets. 723 */ 724 gnutls_protocol_set_priority(ctxt->session, protocol_priority); 725 726 gnutls_handshake_set_post_client_hello_function(ctxt->session, 727 mgs_select_virtual_server_cb); 728 729 mgs_cache_session_init(ctxt); 730 731 return ctxt; 732 } 733 734 int mgs_hook_pre_connection(conn_rec * c, void *csd) 735 { 736 mgs_handle_t *ctxt; 737 mgs_srvconf_rec *sc; 738 739 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 740 741 if (c == NULL) { 742 return DECLINED; 743 } 744 745 sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 746 module_config, 747 &gnutls_module); 748 749 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 750 return DECLINED; 751 } 752 753 if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip,c->local_ip) == 0) { 680 static mgs_handle_t *create_gnutls_handle(apr_pool_t * pool, conn_rec * c) { 681 mgs_handle_t *ctxt; 682 mgs_srvconf_rec *sc = 683 (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 684 module_config, 685 &gnutls_module); 686 687 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 688 ctxt = apr_pcalloc(pool, sizeof (*ctxt)); 689 ctxt->c = c; 690 ctxt->sc = sc; 691 ctxt->status = 0; 692 693 ctxt->input_rc = APR_SUCCESS; 694 ctxt->input_bb = apr_brigade_create(c->pool, c->bucket_alloc); 695 ctxt->input_cbuf.length = 0; 696 697 ctxt->output_rc = APR_SUCCESS; 698 ctxt->output_bb = apr_brigade_create(c->pool, c->bucket_alloc); 699 ctxt->output_blen = 0; 700 ctxt->output_length = 0; 701 702 gnutls_init(&ctxt->session, GNUTLS_SERVER); 703 if (session_ticket_key.data != NULL && ctxt->sc->tickets != 0) 704 gnutls_session_ticket_enable_server(ctxt->session, 705 &session_ticket_key); 706 707 /* because we don't set any default priorities here (we set later at 708 * the user hello callback) we need to at least set this in order for 709 * gnutls to be able to read packets. 710 */ 711 gnutls_protocol_set_priority(ctxt->session, protocol_priority); 712 713 gnutls_handshake_set_post_client_hello_function(ctxt->session, 714 mgs_select_virtual_server_cb); 715 716 mgs_cache_session_init(ctxt); 717 718 return ctxt; 719 } 720 721 int mgs_hook_pre_connection(conn_rec * c, void *csd) { 722 mgs_handle_t *ctxt; 723 mgs_srvconf_rec *sc; 724 725 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 726 727 if (c == NULL) { 728 return DECLINED; 729 } 730 731 sc = (mgs_srvconf_rec *) ap_get_module_config(c->base_server-> 732 module_config, 733 &gnutls_module); 734 735 if (!(sc && (sc->enabled == GNUTLS_ENABLED_TRUE))) { 736 return DECLINED; 737 } 738 739 if (c->remote_addr->hostname || apr_strnatcmp(c->remote_ip, c->local_ip) == 0) { 754 740 /* Connection initiated by Apache (mod_proxy) => ignore */ 755 return OK; 756 } 757 758 ctxt = create_gnutls_handle(c->pool, c); 759 760 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 761 762 gnutls_transport_set_pull_function(ctxt->session, 763 mgs_transport_read); 764 gnutls_transport_set_push_function(ctxt->session, 765 mgs_transport_write); 766 gnutls_transport_set_ptr(ctxt->session, ctxt); 767 768 ctxt->input_filter = 769 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 770 ctxt->output_filter = 771 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 772 773 return OK; 774 } 775 776 int mgs_hook_fixups(request_rec * r) 777 { 778 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 779 char buf[AP_IOBUFSIZE]; 780 const char *tmp; 781 size_t len; 782 mgs_handle_t *ctxt; 783 int rv = OK; 784 785 if (r == NULL) 786 return DECLINED; 787 788 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 789 apr_table_t *env = r->subprocess_env; 790 791 ctxt = 792 ap_get_module_config(r->connection->conn_config, 793 &gnutls_module); 794 795 if (!ctxt || ctxt->session == NULL) { 796 return DECLINED; 797 } 798 799 apr_table_setn(env, "HTTPS", "on"); 800 801 apr_table_setn(env, "SSL_VERSION_LIBRARY", 802 "GnuTLS/" LIBGNUTLS_VERSION); 803 apr_table_setn(env, "SSL_VERSION_INTERFACE", 804 "mod_gnutls/" MOD_GNUTLS_VERSION); 805 806 apr_table_setn(env, "SSL_PROTOCOL", 807 gnutls_protocol_get_name(gnutls_protocol_get_version 808 (ctxt->session))); 809 810 /* should have been called SSL_CIPHERSUITE instead */ 811 apr_table_setn(env, "SSL_CIPHER", 812 gnutls_cipher_suite_get_name(gnutls_kx_get 813 (ctxt->session), 814 gnutls_cipher_get 815 (ctxt->session), 816 gnutls_mac_get 817 (ctxt->session))); 818 819 apr_table_setn(env, "SSL_COMPRESS_METHOD", 820 gnutls_compression_get_name(gnutls_compression_get 821 (ctxt->session))); 741 return OK; 742 } 743 744 ctxt = create_gnutls_handle(c->pool, c); 745 746 ap_set_module_config(c->conn_config, &gnutls_module, ctxt); 747 748 gnutls_transport_set_pull_function(ctxt->session, 749 mgs_transport_read); 750 gnutls_transport_set_push_function(ctxt->session, 751 mgs_transport_write); 752 gnutls_transport_set_ptr(ctxt->session, ctxt); 753 754 ctxt->input_filter = 755 ap_add_input_filter(GNUTLS_INPUT_FILTER_NAME, ctxt, NULL, c); 756 ctxt->output_filter = 757 ap_add_output_filter(GNUTLS_OUTPUT_FILTER_NAME, ctxt, NULL, c); 758 759 return OK; 760 } 761 762 int mgs_hook_fixups(request_rec * r) { 763 unsigned char sbuf[GNUTLS_MAX_SESSION_ID]; 764 char buf[AP_IOBUFSIZE]; 765 const char *tmp; 766 size_t len; 767 mgs_handle_t *ctxt; 768 int rv = OK; 769 770 if (r == NULL) 771 return DECLINED; 772 773 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 774 apr_table_t *env = r->subprocess_env; 775 776 ctxt = 777 ap_get_module_config(r->connection->conn_config, 778 &gnutls_module); 779 780 if (!ctxt || ctxt->session == NULL) { 781 return DECLINED; 782 } 783 784 apr_table_setn(env, "HTTPS", "on"); 785 786 apr_table_setn(env, "SSL_VERSION_LIBRARY", 787 "GnuTLS/" LIBGNUTLS_VERSION); 788 apr_table_setn(env, "SSL_VERSION_INTERFACE", 789 "mod_gnutls/" MOD_GNUTLS_VERSION); 790 791 apr_table_setn(env, "SSL_PROTOCOL", 792 gnutls_protocol_get_name(gnutls_protocol_get_version 793 (ctxt->session))); 794 795 /* should have been called SSL_CIPHERSUITE instead */ 796 apr_table_setn(env, "SSL_CIPHER", 797 gnutls_cipher_suite_get_name(gnutls_kx_get 798 (ctxt->session), 799 gnutls_cipher_get 800 (ctxt->session), 801 gnutls_mac_get 802 (ctxt->session))); 803 804 apr_table_setn(env, "SSL_COMPRESS_METHOD", 805 gnutls_compression_get_name(gnutls_compression_get 806 (ctxt->session))); 822 807 823 808 #ifdef ENABLE_SRP 824 tmp = gnutls_srp_server_get_username(ctxt->session); 825 apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : ""); 826 #endif 827 828 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL) 829 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 830 831 unsigned int key_size = 832 8 * 833 gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)); 834 tmp = apr_psprintf(r->pool, "%u", key_size); 835 836 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 837 838 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 839 840 apr_table_setn(env, "SSL_CIPHER_EXPORT", 841 (key_size <= 40) ? "true" : "false"); 842 843 len = sizeof(sbuf); 844 gnutls_session_get_id(ctxt->session, sbuf, &len); 845 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 846 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 847 848 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 849 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, 850 ctxt-> 851 sc->export_certificates_enabled); 852 else if (gnutls_certificate_type_get(ctxt->session) == 853 GNUTLS_CRT_OPENPGP) 854 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, 855 ctxt-> 856 sc->export_certificates_enabled); 857 858 return rv; 859 } 860 861 int mgs_hook_authz(request_rec * r) 862 { 863 int rv; 864 mgs_handle_t *ctxt; 865 mgs_dirconf_rec *dc; 866 867 if (r == NULL) 868 return DECLINED; 869 870 dc = ap_get_module_config(r->per_dir_config, &gnutls_module); 871 872 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 873 ctxt = 874 ap_get_module_config(r->connection->conn_config, 875 &gnutls_module); 876 877 if (!ctxt || ctxt->session == NULL) { 878 return DECLINED; 879 } 880 881 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 882 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 883 "GnuTLS: Directory set to Ignore Client Certificate!"); 884 } else { 885 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 886 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 887 "GnuTLS: Attempting to rehandshake with peer. %d %d", 888 ctxt->sc->client_verify_mode, 889 dc->client_verify_mode); 890 891 /* If we already have a client certificate, there's no point in 892 * re-handshaking... */ 893 rv = mgs_cert_verify(r, ctxt); 894 if (rv != DECLINED && rv != HTTP_FORBIDDEN) 895 return rv; 896 897 gnutls_certificate_server_set_request 898 (ctxt->session, dc->client_verify_mode); 899 900 if (mgs_rehandshake(ctxt) != 0) { 901 return HTTP_FORBIDDEN; 902 } 903 } else if (ctxt->sc->client_verify_mode == 904 GNUTLS_CERT_IGNORE) { 809 tmp = gnutls_srp_server_get_username(ctxt->session); 810 apr_table_setn(env, "SSL_SRP_USER", (tmp != NULL) ? tmp : ""); 811 #endif 812 813 if (apr_table_get(env, "SSL_CLIENT_VERIFY") == NULL) 814 apr_table_setn(env, "SSL_CLIENT_VERIFY", "NONE"); 815 816 unsigned int key_size = 817 8 * 818 gnutls_cipher_get_key_size(gnutls_cipher_get(ctxt->session)); 819 tmp = apr_psprintf(r->pool, "%u", key_size); 820 821 apr_table_setn(env, "SSL_CIPHER_USEKEYSIZE", tmp); 822 823 apr_table_setn(env, "SSL_CIPHER_ALGKEYSIZE", tmp); 824 825 apr_table_setn(env, "SSL_CIPHER_EXPORT", 826 (key_size <= 40) ? "true" : "false"); 827 828 len = sizeof (sbuf); 829 gnutls_session_get_id(ctxt->session, sbuf, &len); 830 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 831 apr_table_setn(env, "SSL_SESSION_ID", apr_pstrdup(r->pool, tmp)); 832 833 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 834 mgs_add_common_cert_vars(r, ctxt->sc->certs_x509[0], 0, 835 ctxt-> 836 sc->export_certificates_enabled); 837 else if (gnutls_certificate_type_get(ctxt->session) == 838 GNUTLS_CRT_OPENPGP) 839 mgs_add_common_pgpcert_vars(r, ctxt->sc->cert_pgp, 0, 840 ctxt-> 841 sc->export_certificates_enabled); 842 843 return rv; 844 } 845 846 int mgs_hook_authz(request_rec * r) { 847 int rv; 848 mgs_handle_t *ctxt; 849 mgs_dirconf_rec *dc; 850 851 if (r == NULL) 852 return DECLINED; 853 854 dc = ap_get_module_config(r->per_dir_config, &gnutls_module); 855 856 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 857 ctxt = 858 ap_get_module_config(r->connection->conn_config, 859 &gnutls_module); 860 861 if (!ctxt || ctxt->session == NULL) { 862 return DECLINED; 863 } 864 865 if (dc->client_verify_mode == GNUTLS_CERT_IGNORE) { 866 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 867 "GnuTLS: Directory set to Ignore Client Certificate!"); 868 } else { 869 if (ctxt->sc->client_verify_mode < dc->client_verify_mode) { 870 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 871 "GnuTLS: Attempting to rehandshake with peer. %d %d", 872 ctxt->sc->client_verify_mode, 873 dc->client_verify_mode); 874 875 /* If we already have a client certificate, there's no point in 876 * re-handshaking... */ 877 rv = mgs_cert_verify(r, ctxt); 878 if (rv != DECLINED && rv != HTTP_FORBIDDEN) 879 return rv; 880 881 gnutls_certificate_server_set_request 882 (ctxt->session, dc->client_verify_mode); 883 884 if (mgs_rehandshake(ctxt) != 0) { 885 return HTTP_FORBIDDEN; 886 } 887 } else if (ctxt->sc->client_verify_mode == 888 GNUTLS_CERT_IGNORE) { 905 889 #if MOD_GNUTLS_DEBUG 906 907 908 #endif 909 910 911 912 913 914 915 916 917 918 919 890 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 891 "GnuTLS: Peer is set to IGNORE"); 892 #endif 893 return DECLINED; 894 } 895 rv = mgs_cert_verify(r, ctxt); 896 if (rv != DECLINED && 897 (rv != HTTP_FORBIDDEN || 898 dc->client_verify_mode == GNUTLS_CERT_REQUIRE)) { 899 return rv; 900 } 901 } 902 903 return DECLINED; 920 904 } 921 905 … … 929 913 */ 930 914 #define MGS_SIDE ((side==0)?"SSL_SERVER":"SSL_CLIENT") 915 931 916 static void 932 917 mgs_add_common_cert_vars(request_rec * r, gnutls_x509_crt_t cert, int side, 933 int export_certificates_enabled) 934 { 935 unsigned char sbuf[64]; /* buffer to hold serials */ 936 char buf[AP_IOBUFSIZE]; 937 const char *tmp; 938 char *tmp2; 939 size_t len; 940 int ret, i; 941 942 if (r == NULL) 943 return; 944 945 apr_table_t *env = r->subprocess_env; 946 947 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 948 if (export_certificates_enabled != 0) { 949 char cert_buf[10 * 1024]; 950 len = sizeof(cert_buf); 951 952 if (gnutls_x509_crt_export 953 (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) 954 apr_table_setn(env, 955 apr_pstrcat(r->pool, MGS_SIDE, 956 "_CERT", NULL), 957 apr_pstrmemdup(r->pool, cert_buf, 958 len)); 959 960 } 961 962 len = sizeof(buf); 963 gnutls_x509_crt_get_dn(cert, buf, &len); 964 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL), 965 apr_pstrmemdup(r->pool, buf, len)); 966 967 len = sizeof(buf); 968 gnutls_x509_crt_get_issuer_dn(cert, buf, &len); 969 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL), 970 apr_pstrmemdup(r->pool, buf, len)); 971 972 len = sizeof(sbuf); 973 gnutls_x509_crt_get_serial(cert, sbuf, &len); 974 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 975 apr_table_setn(env, 976 apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL), 977 apr_pstrdup(r->pool, tmp)); 978 979 ret = gnutls_x509_crt_get_version(cert); 980 if (ret > 0) 981 apr_table_setn(env, 982 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 983 NULL), apr_psprintf(r->pool, 984 "%u", ret)); 985 986 apr_table_setn(env, 987 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 988 "X.509"); 989 990 tmp = 991 mgs_time2sz(gnutls_x509_crt_get_expiration_time 992 (cert), buf, sizeof(buf)); 993 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 994 apr_pstrdup(r->pool, tmp)); 995 996 tmp = 997 mgs_time2sz(gnutls_x509_crt_get_activation_time 998 (cert), buf, sizeof(buf)); 999 apr_table_setn(env, 1000 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1001 apr_pstrdup(r->pool, tmp)); 1002 1003 ret = gnutls_x509_crt_get_signature_algorithm(cert); 1004 if (ret >= 0) { 1005 apr_table_setn(env, 1006 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", 1007 NULL), 1008 gnutls_sign_algorithm_get_name(ret)); 1009 } 1010 1011 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL); 1012 if (ret >= 0) { 1013 apr_table_setn(env, 1014 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1015 NULL), 1016 gnutls_pk_algorithm_get_name(ret)); 1017 } 1018 1019 /* export all the alternative names (DNS, RFC822 and URI) */ 1020 for (i = 0; !(ret < 0); i++) { 1021 len = 0; 1022 ret = gnutls_x509_crt_get_subject_alt_name(cert, i, 1023 NULL, &len, 1024 NULL); 1025 1026 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) { 1027 tmp2 = apr_palloc(r->pool, len + 1); 1028 1029 ret = 1030 gnutls_x509_crt_get_subject_alt_name(cert, i, 1031 tmp2, 1032 &len, 1033 NULL); 1034 tmp2[len] = 0; 1035 1036 if (ret == GNUTLS_SAN_DNSNAME) { 1037 apr_table_setn(env, 1038 apr_psprintf(r->pool, 1039 "%s_S_AN%u", 1040 MGS_SIDE, i), 1041 apr_psprintf(r->pool, 1042 "DNSNAME:%s", 1043 tmp2)); 1044 } else if (ret == GNUTLS_SAN_RFC822NAME) { 1045 apr_table_setn(env, 1046 apr_psprintf(r->pool, 1047 "%s_S_AN%u", 1048 MGS_SIDE, i), 1049 apr_psprintf(r->pool, 1050 "RFC822NAME:%s", 1051 tmp2)); 1052 } else if (ret == GNUTLS_SAN_URI) { 1053 apr_table_setn(env, 1054 apr_psprintf(r->pool, 1055 "%s_S_AN%u", 1056 MGS_SIDE, i), 1057 apr_psprintf(r->pool, 1058 "URI:%s", 1059 tmp2)); 1060 } else { 1061 apr_table_setn(env, 1062 apr_psprintf(r->pool, 1063 "%s_S_AN%u", 1064 MGS_SIDE, i), 1065 "UNSUPPORTED"); 1066 } 1067 } 1068 } 918 int export_certificates_enabled) { 919 unsigned char sbuf[64]; /* buffer to hold serials */ 920 char buf[AP_IOBUFSIZE]; 921 const char *tmp; 922 char *tmp2; 923 size_t len; 924 int ret, i; 925 926 if (r == NULL) 927 return; 928 929 apr_table_t *env = r->subprocess_env; 930 931 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 932 if (export_certificates_enabled != 0) { 933 char cert_buf[10 * 1024]; 934 len = sizeof (cert_buf); 935 936 if (gnutls_x509_crt_export 937 (cert, GNUTLS_X509_FMT_PEM, cert_buf, &len) >= 0) 938 apr_table_setn(env, 939 apr_pstrcat(r->pool, MGS_SIDE, 940 "_CERT", NULL), 941 apr_pstrmemdup(r->pool, cert_buf, 942 len)); 943 944 } 945 946 len = sizeof (buf); 947 gnutls_x509_crt_get_dn(cert, buf, &len); 948 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_S_DN", NULL), 949 apr_pstrmemdup(r->pool, buf, len)); 950 951 len = sizeof (buf); 952 gnutls_x509_crt_get_issuer_dn(cert, buf, &len); 953 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_I_DN", NULL), 954 apr_pstrmemdup(r->pool, buf, len)); 955 956 len = sizeof (sbuf); 957 gnutls_x509_crt_get_serial(cert, sbuf, &len); 958 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 959 apr_table_setn(env, 960 apr_pstrcat(r->pool, MGS_SIDE, "_M_SERIAL", NULL), 961 apr_pstrdup(r->pool, tmp)); 962 963 ret = gnutls_x509_crt_get_version(cert); 964 if (ret > 0) 965 apr_table_setn(env, 966 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 967 NULL), apr_psprintf(r->pool, 968 "%u", ret)); 969 970 apr_table_setn(env, 971 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 972 "X.509"); 973 974 tmp = 975 mgs_time2sz(gnutls_x509_crt_get_expiration_time 976 (cert), buf, sizeof (buf)); 977 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 978 apr_pstrdup(r->pool, tmp)); 979 980 tmp = 981 mgs_time2sz(gnutls_x509_crt_get_activation_time 982 (cert), buf, sizeof (buf)); 983 apr_table_setn(env, 984 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 985 apr_pstrdup(r->pool, tmp)); 986 987 ret = gnutls_x509_crt_get_signature_algorithm(cert); 988 if (ret >= 0) { 989 apr_table_setn(env, 990 apr_pstrcat(r->pool, MGS_SIDE, "_A_SIG", 991 NULL), 992 gnutls_sign_algorithm_get_name(ret)); 993 } 994 995 ret = gnutls_x509_crt_get_pk_algorithm(cert, NULL); 996 if (ret >= 0) { 997 apr_table_setn(env, 998 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 999 NULL), 1000 gnutls_pk_algorithm_get_name(ret)); 1001 } 1002 1003 /* export all the alternative names (DNS, RFC822 and URI) */ 1004 for (i = 0; !(ret < 0); i++) { 1005 len = 0; 1006 ret = gnutls_x509_crt_get_subject_alt_name(cert, i, 1007 NULL, &len, 1008 NULL); 1009 1010 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && len > 1) { 1011 tmp2 = apr_palloc(r->pool, len + 1); 1012 1013 ret = 1014 gnutls_x509_crt_get_subject_alt_name(cert, i, 1015 tmp2, 1016 &len, 1017 NULL); 1018 tmp2[len] = 0; 1019 1020 if (ret == GNUTLS_SAN_DNSNAME) { 1021 apr_table_setn(env, 1022 apr_psprintf(r->pool, 1023 "%s_S_AN%u", 1024 MGS_SIDE, i), 1025 apr_psprintf(r->pool, 1026 "DNSNAME:%s", 1027 tmp2)); 1028 } else if (ret == GNUTLS_SAN_RFC822NAME) { 1029 apr_table_setn(env, 1030 apr_psprintf(r->pool, 1031 "%s_S_AN%u", 1032 MGS_SIDE, i), 1033 apr_psprintf(r->pool, 1034 "RFC822NAME:%s", 1035 tmp2)); 1036 } else if (ret == GNUTLS_SAN_URI) { 1037 apr_table_setn(env, 1038 apr_psprintf(r->pool, 1039 "%s_S_AN%u", 1040 MGS_SIDE, i), 1041 apr_psprintf(r->pool, 1042 "URI:%s", 1043 tmp2)); 1044 } else { 1045 apr_table_setn(env, 1046 apr_psprintf(r->pool, 1047 "%s_S_AN%u", 1048 MGS_SIDE, i), 1049 "UNSUPPORTED"); 1050 } 1051 } 1052 } 1069 1053 } 1070 1054 1071 1055 static void 1072 1056 mgs_add_common_pgpcert_vars(request_rec * r, gnutls_openpgp_crt_t cert, 1073 int side, int export_certificates_enabled) 1074 { 1075 unsigned char sbuf[64]; /* buffer to hold serials */ 1076 char buf[AP_IOBUFSIZE]; 1077 const char *tmp; 1078 size_t len; 1079 int ret; 1080 1081 if (r == NULL) 1082 return; 1083 1084 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1085 apr_table_t *env = r->subprocess_env; 1086 1087 if (export_certificates_enabled != 0) { 1088 char cert_buf[10 * 1024]; 1089 len = sizeof(cert_buf); 1090 1091 if (gnutls_openpgp_crt_export 1092 (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) 1093 apr_table_setn(env, 1094 apr_pstrcat(r->pool, MGS_SIDE, 1095 "_CERT", NULL), 1096 apr_pstrmemdup(r->pool, cert_buf, 1097 len)); 1098 1099 } 1100 1101 len = sizeof(buf); 1102 gnutls_openpgp_crt_get_name(cert, 0, buf, &len); 1103 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), 1104 apr_pstrmemdup(r->pool, buf, len)); 1105 1106 len = sizeof(sbuf); 1107 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); 1108 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof(buf)); 1109 apr_table_setn(env, 1110 apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", 1111 NULL), apr_pstrdup(r->pool, tmp)); 1112 1113 ret = gnutls_openpgp_crt_get_version(cert); 1114 if (ret > 0) 1115 apr_table_setn(env, 1116 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 1117 NULL), apr_psprintf(r->pool, 1118 "%u", ret)); 1119 1120 apr_table_setn(env, 1121 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 1122 "OPENPGP"); 1123 1124 tmp = 1125 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time 1126 (cert), buf, sizeof(buf)); 1127 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 1128 apr_pstrdup(r->pool, tmp)); 1129 1130 tmp = 1131 mgs_time2sz(gnutls_openpgp_crt_get_creation_time 1132 (cert), buf, sizeof(buf)); 1133 apr_table_setn(env, 1134 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1135 apr_pstrdup(r->pool, tmp)); 1136 1137 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); 1138 if (ret >= 0) { 1139 apr_table_setn(env, 1140 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1141 NULL), 1142 gnutls_pk_algorithm_get_name(ret)); 1143 } 1057 int side, int export_certificates_enabled) { 1058 unsigned char sbuf[64]; /* buffer to hold serials */ 1059 char buf[AP_IOBUFSIZE]; 1060 const char *tmp; 1061 size_t len; 1062 int ret; 1063 1064 if (r == NULL) 1065 return; 1066 1067 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1068 apr_table_t *env = r->subprocess_env; 1069 1070 if (export_certificates_enabled != 0) { 1071 char cert_buf[10 * 1024]; 1072 len = sizeof (cert_buf); 1073 1074 if (gnutls_openpgp_crt_export 1075 (cert, GNUTLS_OPENPGP_FMT_BASE64, cert_buf, &len) >= 0) 1076 apr_table_setn(env, 1077 apr_pstrcat(r->pool, MGS_SIDE, 1078 "_CERT", NULL), 1079 apr_pstrmemdup(r->pool, cert_buf, 1080 len)); 1081 1082 } 1083 1084 len = sizeof (buf); 1085 gnutls_openpgp_crt_get_name(cert, 0, buf, &len); 1086 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_NAME", NULL), 1087 apr_pstrmemdup(r->pool, buf, len)); 1088 1089 len = sizeof (sbuf); 1090 gnutls_openpgp_crt_get_fingerprint(cert, sbuf, &len); 1091 tmp = mgs_session_id2sz(sbuf, len, buf, sizeof (buf)); 1092 apr_table_setn(env, 1093 apr_pstrcat(r->pool, MGS_SIDE, "_FINGERPRINT", 1094 NULL), apr_pstrdup(r->pool, tmp)); 1095 1096 ret = gnutls_openpgp_crt_get_version(cert); 1097 if (ret > 0) 1098 apr_table_setn(env, 1099 apr_pstrcat(r->pool, MGS_SIDE, "_M_VERSION", 1100 NULL), apr_psprintf(r->pool, 1101 "%u", ret)); 1102 1103 apr_table_setn(env, 1104 apr_pstrcat(r->pool, MGS_SIDE, "_CERT_TYPE", NULL), 1105 "OPENPGP"); 1106 1107 tmp = 1108 mgs_time2sz(gnutls_openpgp_crt_get_expiration_time 1109 (cert), buf, sizeof (buf)); 1110 apr_table_setn(env, apr_pstrcat(r->pool, MGS_SIDE, "_V_END", NULL), 1111 apr_pstrdup(r->pool, tmp)); 1112 1113 tmp = 1114 mgs_time2sz(gnutls_openpgp_crt_get_creation_time 1115 (cert), buf, sizeof (buf)); 1116 apr_table_setn(env, 1117 apr_pstrcat(r->pool, MGS_SIDE, "_V_START", NULL), 1118 apr_pstrdup(r->pool, tmp)); 1119 1120 ret = gnutls_openpgp_crt_get_pk_algorithm(cert, NULL); 1121 if (ret >= 0) { 1122 apr_table_setn(env, 1123 apr_pstrcat(r->pool, MGS_SIDE, "_A_KEY", 1124 NULL), 1125 gnutls_pk_algorithm_get_name(ret)); 1126 } 1144 1127 1145 1128 } 1146 1129 1147 1130 /* TODO: Allow client sending a X.509 certificate chain */ 1148 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) 1149 { 1150 const gnutls_datum_t *cert_list;1151 unsigned int cert_list_size, status;1152 int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret;1153 unsigned int ch_size = 0; 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 } 1131 static int mgs_cert_verify(request_rec * r, mgs_handle_t * ctxt) { 1132 const gnutls_datum_t *cert_list; 1133 unsigned int cert_list_size, status; 1134 int rv = GNUTLS_E_NO_CERTIFICATE_FOUND, ret; 1135 unsigned int ch_size = 0; 1136 1137 union { 1138 gnutls_x509_crt_t x509[MAX_CHAIN_SIZE]; 1139 gnutls_openpgp_crt_t pgp; 1140 } cert; 1141 apr_time_t expiration_time, cur_time; 1142 1143 if (r == NULL || ctxt == NULL || ctxt->session == NULL) 1144 return HTTP_FORBIDDEN; 1145 1146 _gnutls_log(debug_log_fp, "%s: %d\n", __func__, __LINE__); 1147 cert_list = 1148 gnutls_certificate_get_peers(ctxt->session, &cert_list_size); 1149 1150 if (cert_list == NULL || cert_list_size == 0) { 1151 /* It is perfectly OK for a client not to send a certificate if on REQUEST mode 1152 */ 1153 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST) 1154 return OK; 1155 1156 /* no certificate provided by the client, but one was required. */ 1157 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1158 "GnuTLS: Failed to Verify Peer: " 1159 "Client did not submit a certificate"); 1160 return HTTP_FORBIDDEN; 1161 } 1162 1163 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1164 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1165 "GnuTLS: A Chain of %d certificate(s) was provided for validation", 1166 cert_list_size); 1167 1168 for (ch_size = 0; ch_size < cert_list_size; ch_size++) { 1169 gnutls_x509_crt_init(&cert.x509[ch_size]); 1170 rv = gnutls_x509_crt_import(cert.x509[ch_size], 1171 &cert_list[ch_size], 1172 GNUTLS_X509_FMT_DER); 1173 // When failure to import, leave the loop 1174 if (rv != GNUTLS_E_SUCCESS) { 1175 if (ch_size < 1) { 1176 ap_log_rerror(APLOG_MARK, 1177 APLOG_INFO, 0, r, 1178 "GnuTLS: Failed to Verify Peer: " 1179 "Failed to import peer certificates."); 1180 ret = HTTP_FORBIDDEN; 1181 goto exit; 1182 } 1183 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1184 "GnuTLS: Failed to import some peer certificates. Using %d certificates", 1185 ch_size); 1186 rv = GNUTLS_E_SUCCESS; 1187 break; 1188 } 1189 } 1190 } else if (gnutls_certificate_type_get(ctxt->session) == 1191 GNUTLS_CRT_OPENPGP) { 1192 if (cert_list_size > 1) { 1193 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1194 "GnuTLS: Failed to Verify Peer: " 1195 "Chained Client Certificates are not supported."); 1196 return HTTP_FORBIDDEN; 1197 } 1198 1199 gnutls_openpgp_crt_init(&cert.pgp); 1200 rv = gnutls_openpgp_crt_import(cert.pgp, &cert_list[0], 1201 GNUTLS_OPENPGP_FMT_RAW); 1202 1203 } else 1204 return HTTP_FORBIDDEN; 1205 1206 if (rv < 0) { 1207 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1208 "GnuTLS: Failed to Verify Peer: " 1209 "Failed to import peer certificates."); 1210 ret = HTTP_FORBIDDEN; 1211 goto exit; 1212 } 1213 1214 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1215 apr_time_ansi_put(&expiration_time, 1216 gnutls_x509_crt_get_expiration_time 1217 (cert.x509[0])); 1218 1219 ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, 1220 "GnuTLS: Verifying list of %d certificate(s)", 1221 ch_size); 1222 rv = gnutls_x509_crt_list_verify(cert.x509, ch_size, 1223 ctxt->sc->ca_list, 1224 ctxt->sc->ca_list_size, 1225 NULL, 0, 0, &status); 1226 } else { 1227 apr_time_ansi_put(&expiration_time, 1228 gnutls_openpgp_crt_get_expiration_time 1229 (cert.pgp)); 1230 1231 rv = gnutls_openpgp_crt_verify_ring(cert.pgp, 1232 ctxt->sc->pgp_list, 0, 1233 &status); 1234 } 1235 1236 if (rv < 0) { 1237 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1238 "GnuTLS: Failed to Verify Peer certificate: (%d) %s", 1239 rv, gnutls_strerror(rv)); 1240 if (rv == GNUTLS_E_NO_CERTIFICATE_FOUND) 1241 ap_log_rerror(APLOG_MARK, APLOG_EMERG, 0, r, 1242 "GnuTLS: No certificate was found for verification. Did you set the GnuTLSX509CAFile or GnuTLSPGPKeyringFile directives?"); 1243 ret = HTTP_FORBIDDEN; 1244 goto exit; 1245 } 1246 1247 /* TODO: X509 CRL Verification. */ 1248 /* May add later if anyone needs it. 1249 */ 1250 /* ret = gnutls_x509_crt_check_revocation(crt, crl_list, crl_list_size); */ 1251 1252 cur_time = apr_time_now(); 1253 1254 if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) { 1255 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1256 "GnuTLS: Could not find Signer for Peer Certificate"); 1257 } 1258 1259 if (status & GNUTLS_CERT_SIGNER_NOT_CA) { 1260 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1261 "GnuTLS: Peer's Certificate signer is not a CA"); 1262 } 1263 1264 if (status & GNUTLS_CERT_INSECURE_ALGORITHM) { 1265 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1266 "GnuTLS: Peer's Certificate is using insecure algorithms"); 1267 } 1268 1269 if (status & GNUTLS_CERT_EXPIRED 1270 || status & GNUTLS_CERT_NOT_ACTIVATED) { 1271 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1272 "GnuTLS: Peer's Certificate signer is expired or not yet activated"); 1273 } 1274 1275 if (status & GNUTLS_CERT_INVALID) { 1276 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1277 "GnuTLS: Peer Certificate is invalid."); 1278 } else if (status & GNUTLS_CERT_REVOKED) { 1279 ap_log_rerror(APLOG_MARK, APLOG_INFO, 0, r, 1280 "GnuTLS: Peer Certificate is revoked."); 1281 } 1282 1283 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) 1284 mgs_add_common_cert_vars(r, cert.x509[0], 1, 1285 ctxt-> 1286 sc->export_certificates_enabled); 1287 else if (gnutls_certificate_type_get(ctxt->session) == 1288 GNUTLS_CRT_OPENPGP) 1289 mgs_add_common_pgpcert_vars(r, cert.pgp, 1, 1290 ctxt-> 1291 sc->export_certificates_enabled); 1292 1293 { 1294 /* days remaining */ 1295 unsigned long remain = 1296 (apr_time_sec(expiration_time) - 1297 apr_time_sec(cur_time)) / 86400; 1298 apr_table_setn(r->subprocess_env, "SSL_CLIENT_V_REMAIN", 1299 apr_psprintf(r->pool, "%lu", remain)); 1300 } 1301 1302 if (status == 0) { 1303 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", 1304 "SUCCESS"); 1305 ret = OK; 1306 } else { 1307 apr_table_setn(r->subprocess_env, "SSL_CLIENT_VERIFY", 1308 "FAILED"); 1309 if (ctxt->sc->client_verify_mode == GNUTLS_CERT_REQUEST) 1310 ret = OK; 1311 else 1312 ret = HTTP_FORBIDDEN; 1313 } 1314 1315 exit: 1316 if (gnutls_certificate_type_get(ctxt->session) == GNUTLS_CRT_X509) { 1317 int i; 1318 for (i = 0; i < ch_size; i++) { 1319 gnutls_x509_crt_deinit(cert.x509[i]); 1320 } 1321 } else if (gnutls_certificate_type_get(ctxt->session) == 1322 GNUTLS_CRT_OPENPGP) 1323 gnutls_openpgp_crt_deinit(cert.pgp); 1324 return ret; 1325 1326 1327 } -
src/gnutls_io.c
r6223319 re183628 1 1 /** 2 2 * Copyright 2004-2005 Paul Querna 3 * Copyright 2008 Nikos Mavrogiannopoulos 4 * Copyright 2011 Dash Shendy 3 5 * 4 6 * Licensed under the Apache License, Version 2.0 (the "License"); … … 33 35 34 36 static apr_status_t gnutls_io_filter_error(ap_filter_t * f, 35 apr_bucket_brigade * bb, 36 apr_status_t status) 37 { 38 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx; 39 apr_bucket *bucket; 40 41 switch (status) { 42 case HTTP_BAD_REQUEST: 43 /* log the situation */ 44 ap_log_error(APLOG_MARK, APLOG_INFO, 0, 45 f->c->base_server, 46 "GnuTLS handshake failed: HTTP spoken on HTTPS port; " 47 "trying to send HTML error page"); 48 49 ctxt->status = -1; 50 51 /* fake the request line */ 52 bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); 53 break; 54 55 default: 56 return status; 57 } 58 59 APR_BRIGADE_INSERT_TAIL(bb, bucket); 60 bucket = apr_bucket_eos_create(f->c->bucket_alloc); 61 APR_BRIGADE_INSERT_TAIL(bb, bucket); 62 63 return APR_SUCCESS; 64 } 65 66 static int char_buffer_read(mgs_char_buffer_t * buffer, char *in, int inl) 67 { 68 if (!buffer->length) { 69 return 0; 70 } 71 72 if (buffer->length > inl) { 73 /* we have have enough to fill the caller's buffer */ 74 memmove(in, buffer->value, inl); 75 buffer->value += inl; 76 buffer->length -= inl; 77 } else { 78 /* swallow remainder of the buffer */ 79 memmove(in, buffer->value, buffer->length); 80 inl = buffer->length; 81 buffer->value = NULL; 82 buffer->length = 0; 83 } 84 85 return inl; 86 } 87 88 static int char_buffer_write(mgs_char_buffer_t * buffer, char *in, int inl) 89 { 90 buffer->value = in; 91 buffer->length = inl; 92 return inl; 37 apr_bucket_brigade * bb, 38 apr_status_t status) { 39 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx; 40 apr_bucket *bucket; 41 42 switch (status) { 43 case HTTP_BAD_REQUEST: 44 /* log the situation */ 45 ap_log_error(APLOG_MARK, APLOG_INFO, 0, 46 f->c->base_server, 47 "GnuTLS handshake failed: HTTP spoken on HTTPS port; " 48 "trying to send HTML error page"); 49 50 ctxt->status = -1; 51 52 /* fake the request line */ 53 bucket = HTTP_ON_HTTPS_PORT_BUCKET(f->c->bucket_alloc); 54 break; 55 56 default: 57 return status; 58 } 59 60 APR_BRIGADE_INSERT_TAIL(bb, bucket); 61 bucket = apr_bucket_eos_create(f->c->bucket_alloc); 62 APR_BRIGADE_INSERT_TAIL(bb, bucket); 63 64 return APR_SUCCESS; 65 } 66 67 static int char_buffer_read(mgs_char_buffer_t * buffer, char *in, int inl) { 68 if (!buffer->length) { 69 return 0; 70 } 71 72 if (buffer->length > inl) { 73 /* we have have enough to fill the caller's buffer */ 74 memmove(in, buffer->value, inl); 75 buffer->value += inl; 76 buffer->length -= inl; 77 } else { 78 /* swallow remainder of the buffer */ 79 memmove(in, buffer->value, buffer->length); 80 inl = buffer->length; 81 buffer->value = NULL; 82 buffer->length = 0; 83 } 84 85 return inl; 86 } 87 88 static int char_buffer_write(mgs_char_buffer_t * buffer, char *in, int inl) { 89 buffer->value = in; 90 buffer->length = inl; 91 return inl; 93 92 } 94 93 … … 99 98 */ 100 99 static apr_status_t brigade_consume(apr_bucket_brigade * bb, 101 apr_read_type_e block, 102 char *c, apr_size_t * len) 103 { 104 apr_size_t actual = 0; 105 apr_status_t status = APR_SUCCESS; 106 107 while (!APR_BRIGADE_EMPTY(bb)) { 108 apr_bucket *b = APR_BRIGADE_FIRST(bb); 109 const char *str; 110 apr_size_t str_len; 111 apr_size_t consume; 112 113 /* Justin points out this is an http-ism that might 114 * not fit if brigade_consume is added to APR. Perhaps 115 * apr_bucket_read(eos_bucket) should return APR_EOF? 116 * Then this becomes mainline instead of a one-off. 117 */ 118 if (APR_BUCKET_IS_EOS(b)) { 119 status = APR_EOF; 120 break; 121 } 122 123 /* The reason I'm not offering brigade_consume yet 124 * across to apr-util is that the following call 125 * illustrates how borked that API really is. For 126 * this sort of case (caller provided buffer) it 127 * would be much more trivial for apr_bucket_consume 128 * to do all the work that follows, based on the 129 * particular characteristics of the bucket we are 130 * consuming here. 131 */ 132 status = apr_bucket_read(b, &str, &str_len, block); 133 134 if (status != APR_SUCCESS) { 135 if (APR_STATUS_IS_EOF(status)) { 136 /* This stream bucket was consumed */ 137 apr_bucket_delete(b); 138 continue; 139 } 140 break; 141 } 142 143 if (str_len > 0) { 144 /* Do not block once some data has been consumed */ 145 block = APR_NONBLOCK_READ; 146 147 /* Assure we don't overflow. */ 148 consume = 149 (str_len + actual > 150 *len) ? *len - actual : str_len; 151 152 memcpy(c, str, consume); 153 154 c += consume; 155 actual += consume; 156 157 if (consume >= b->length) { 158 /* This physical bucket was consumed */ 159 apr_bucket_delete(b); 160 } else { 161 /* Only part of this physical bucket was consumed */ 162 b->start += consume; 163 b->length -= consume; 164 } 165 } else if (b->length == 0) { 166 apr_bucket_delete(b); 167 } 168 169 /* This could probably be actual == *len, but be safe from stray 170 * photons. */ 171 if (actual >= *len) { 172 break; 173 } 174 } 175 176 *len = actual; 177 return status; 178 } 179 100 apr_read_type_e block, 101 char *c, apr_size_t * len) { 102 apr_size_t actual = 0; 103 apr_status_t status = APR_SUCCESS; 104 105 while (!APR_BRIGADE_EMPTY(bb)) { 106 apr_bucket *b = APR_BRIGADE_FIRST(bb); 107 const char *str; 108 apr_size_t str_len; 109 apr_size_t consume; 110 111 /* Justin points out this is an http-ism that might 112 * not fit if brigade_consume is added to APR. Perhaps 113 * apr_bucket_read(eos_bucket) should return APR_EOF? 114 * Then this becomes mainline instead of a one-off. 115 */ 116 if (APR_BUCKET_IS_EOS(b)) { 117 status = APR_EOF; 118 break; 119 } 120 121 /* The reason I'm not offering brigade_consume yet 122 * across to apr-util is that the following call 123 * illustrates how borked that API really is. For 124 * this sort of case (caller provided buffer) it 125 * would be much more trivial for apr_bucket_consume 126 * to do all the work that follows, based on the 127 * particular characteristics of the bucket we are 128 * consuming here. 129 */ 130 status = apr_bucket_read(b, &str, &str_len, block); 131 132 if (status != APR_SUCCESS) { 133 if (APR_STATUS_IS_EOF(status)) { 134 /* This stream bucket was consumed */ 135 apr_bucket_delete(b); 136 continue; 137 } 138 break; 139 } 140 141 if (str_len > 0) { 142 /* Do not block once some data has been consumed */ 143 block = APR_NONBLOCK_READ; 144 145 /* Assure we don't overflow. */ 146 consume = 147 (str_len + actual > 148 *len) ? *len - actual : str_len; 149 150 memcpy(c, str, consume); 151 152 c += consume; 153 actual += consume; 154 155 if (consume >= b->length) { 156 /* This physical bucket was consumed */ 157 apr_bucket_delete(b); 158 } else { 159 /* Only part of this physical bucket was consumed */ 160 b->start += consume; 161 b->length -= consume; 162 } 163 } else if (b->length == 0) { 164 apr_bucket_delete(b); 165 } 166 167 /* This could probably be actual == *len, but be safe from stray 168 * photons. */ 169 if (actual >= *len) { 170 break; 171 } 172 } 173 174 *len = actual; 175 return status; 176 } 180 177 181 178 static apr_status_t gnutls_io_input_read(mgs_handle_t * ctxt, 182 char *buf, apr_size_t * len) 183 { 184 apr_size_t wanted = *len; 185 apr_size_t bytes = 0; 186 int rc; 187 188 *len = 0; 189 190 /* If we have something leftover from last time, try that first. */ 191 if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) { 192 *len = bytes; 193 if (ctxt->input_mode == AP_MODE_SPECULATIVE) { 194 /* We want to rollback this read. */ 195 if (ctxt->input_cbuf.length > 0) { 196 ctxt->input_cbuf.value -= bytes; 197 ctxt->input_cbuf.length += bytes; 198 } else { 199 char_buffer_write(&ctxt->input_cbuf, buf, 200 (int) bytes); 201 } 202 return APR_SUCCESS; 203 } 204 /* This could probably be *len == wanted, but be safe from stray 205 * photons. 206 */ 207 if (*len >= wanted) { 208 return APR_SUCCESS; 209 } 210 if (ctxt->input_mode == AP_MODE_GETLINE) { 211 if (memchr(buf, APR_ASCII_LF, *len)) { 212 return APR_SUCCESS; 213 } 214 } else { 215 /* Down to a nonblock pattern as we have some data already 216 */ 217 ctxt->input_block = APR_NONBLOCK_READ; 218 } 219 } 220 221 if (ctxt->session == NULL) { 222 return APR_EGENERAL; 223 } 224 225 while (1) { 226 227 rc = gnutls_record_recv(ctxt->session, buf + bytes, 228 wanted - bytes); 229 230 if (rc > 0) { 231 *len += rc; 232 if (ctxt->input_mode == AP_MODE_SPECULATIVE) { 233 /* We want to rollback this read. */ 234 char_buffer_write(&ctxt->input_cbuf, buf, 235 rc); 236 } 237 return ctxt->input_rc; 238 } else if (rc == 0) { 239 /* If EAGAIN, we will loop given a blocking read, 240 * otherwise consider ourselves at EOF. 241 */ 242 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc) 243 || APR_STATUS_IS_EINTR(ctxt->input_rc)) { 244 /* Already read something, return APR_SUCCESS instead. 245 * On win32 in particular, but perhaps on other kernels, 246 * a blocking call isn't 'always' blocking. 247 */ 248 if (*len > 0) { 249 ctxt->input_rc = APR_SUCCESS; 250 break; 251 } 252 if (ctxt->input_block == APR_NONBLOCK_READ) { 253 break; 254 } 255 } else { 256 if (*len > 0) { 257 ctxt->input_rc = APR_SUCCESS; 258 } else { 259 ctxt->input_rc = APR_EOF; 260 } 261 break; 262 } 263 } else { /* (rc < 0) */ 264 265 if (rc == GNUTLS_E_REHANDSHAKE) { 266 /* A client has asked for a new Hankshake. Currently, we don't do it */ 267 ap_log_error(APLOG_MARK, APLOG_INFO, 268 ctxt->input_rc, 269 ctxt->c->base_server, 270 "GnuTLS: Error reading data. Client Requested a New Handshake." 271 " (%d) '%s'", rc, 272 gnutls_strerror(rc)); 273 } else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { 274 rc = gnutls_alert_get(ctxt->session); 275 ap_log_error(APLOG_MARK, APLOG_INFO, 276 ctxt->input_rc, 277 ctxt->c->base_server, 278 "GnuTLS: Warning Alert From Client: " 279 " (%d) '%s'", rc, 280 gnutls_alert_get_name(rc)); 281 } else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { 282 rc = gnutls_alert_get(ctxt->session); 283 ap_log_error(APLOG_MARK, APLOG_INFO, 284 ctxt->input_rc, 285 ctxt->c->base_server, 286 "GnuTLS: Fatal Alert From Client: " 287 "(%d) '%s'", rc, 288 gnutls_alert_get_name(rc)); 289 ctxt->input_rc = APR_EGENERAL; 290 break; 291 } else { 292 /* Some Other Error. Report it. Die. */ 293 if (gnutls_error_is_fatal(rc)) { 294 ap_log_error(APLOG_MARK, 295 APLOG_INFO, 296 ctxt->input_rc, 297 ctxt->c->base_server, 298 "GnuTLS: Error reading data. (%d) '%s'", 299 rc, 300 gnutls_strerror(rc)); 301 } else if (*len > 0) { 302 ctxt->input_rc = APR_SUCCESS; 303 break; 304 } 305 } 306 307 if (ctxt->input_rc == APR_SUCCESS) { 308 ctxt->input_rc = APR_EGENERAL; 309 } 310 break; 311 } 312 } 313 return ctxt->input_rc; 179 char *buf, apr_size_t * len) { 180 apr_size_t wanted = *len; 181 apr_size_t bytes = 0; 182 int rc; 183 184 *len = 0; 185 186 /* If we have something leftover from last time, try that first. */ 187 if ((bytes = char_buffer_read(&ctxt->input_cbuf, buf, wanted))) { 188 *len = bytes; 189 if (ctxt->input_mode == AP_MODE_SPECULATIVE) { 190 /* We want to rollback this read. */ 191 if (ctxt->input_cbuf.length > 0) { 192 ctxt->input_cbuf.value -= bytes; 193 ctxt->input_cbuf.length += bytes; 194 } else { 195 char_buffer_write(&ctxt->input_cbuf, buf, 196 (int) bytes); 197 } 198 return APR_SUCCESS; 199 } 200 /* This could probably be *len == wanted, but be safe from stray 201 * photons. 202 */ 203 if (*len >= wanted) { 204 return APR_SUCCESS; 205 } 206 if (ctxt->input_mode == AP_MODE_GETLINE) { 207 if (memchr(buf, APR_ASCII_LF, *len)) { 208 return APR_SUCCESS; 209 } 210 } else { 211 /* Down to a nonblock pattern as we have some data already 212 */ 213 ctxt->input_block = APR_NONBLOCK_READ; 214 } 215 } 216 217 if (ctxt->session == NULL) { 218 return APR_EGENERAL; 219 } 220 221 while (1) { 222 223 rc = gnutls_record_recv(ctxt->session, buf + bytes, 224 wanted - bytes); 225 226 if (rc > 0) { 227 *len += rc; 228 if (ctxt->input_mode == AP_MODE_SPECULATIVE) { 229 /* We want to rollback this read. */ 230 char_buffer_write(&ctxt->input_cbuf, buf, 231 rc); 232 } 233 return ctxt->input_rc; 234 } else if (rc == 0) { 235 /* If EAGAIN, we will loop given a blocking read, 236 * otherwise consider ourselves at EOF. 237 */ 238 if (APR_STATUS_IS_EAGAIN(ctxt->input_rc) 239 || APR_STATUS_IS_EINTR(ctxt->input_rc)) { 240 /* Already read something, return APR_SUCCESS instead. 241 * On win32 in particular, but perhaps on other kernels, 242 * a blocking call isn't 'always' blocking. 243 */ 244 if (*len > 0) { 245 ctxt->input_rc = APR_SUCCESS; 246 break; 247 } 248 if (ctxt->input_block == APR_NONBLOCK_READ) { 249 break; 250 } 251 } else { 252 if (*len > 0) { 253 ctxt->input_rc = APR_SUCCESS; 254 } else { 255 ctxt->input_rc = APR_EOF; 256 } 257 break; 258 } 259 } else { /* (rc < 0) */ 260 261 if (rc == GNUTLS_E_REHANDSHAKE) { 262 /* A client has asked for a new Hankshake. Currently, we don't do it */ 263 ap_log_error(APLOG_MARK, APLOG_INFO, 264 ctxt->input_rc, 265 ctxt->c->base_server, 266 "GnuTLS: Error reading data. Client Requested a New Handshake." 267 " (%d) '%s'", rc, 268 gnutls_strerror(rc)); 269 } else if (rc == GNUTLS_E_WARNING_ALERT_RECEIVED) { 270 rc = gnutls_alert_get(ctxt->session); 271 ap_log_error(APLOG_MARK, APLOG_INFO, 272 ctxt->input_rc, 273 ctxt->c->base_server, 274 "GnuTLS: Warning Alert From Client: " 275 " (%d) '%s'", rc, 276 gnutls_alert_get_name(rc)); 277 } else if (rc == GNUTLS_E_FATAL_ALERT_RECEIVED) { 278 rc = gnutls_alert_get(ctxt->session); 279 ap_log_error(APLOG_MARK, APLOG_INFO, 280 ctxt->input_rc, 281 ctxt->c->base_server, 282 "GnuTLS: Fatal Alert From Client: " 283 "(%d) '%s'", rc, 284 gnutls_alert_get_name(rc)); 285 ctxt->input_rc = APR_EGENERAL; 286 break; 287 } else { 288 /* Some Other Error. Report it. Die. */ 289 if (gnutls_error_is_fatal(rc)) { 290 ap_log_error(APLOG_MARK, 291 APLOG_INFO, 292 ctxt->input_rc, 293 ctxt->c->base_server, 294 "GnuTLS: Error reading data. (%d) '%s'", 295 rc, 296 gnutls_strerror(rc)); 297 } else if (*len > 0) { 298 ctxt->input_rc = APR_SUCCESS; 299 break; 300 } 301 } 302 303 if (ctxt->input_rc == APR_SUCCESS) { 304 ctxt->input_rc = APR_EGENERAL; 305 } 306 break; 307 } 308 } 309 return ctxt->input_rc; 314 310 } 315 311 316 312 static apr_status_t gnutls_io_input_getline(mgs_handle_t * ctxt, 317 char *buf, apr_size_t * len) 318 { 319 const char *pos = NULL; 320 apr_status_t status; 321 apr_size_t tmplen = *len, buflen = *len, offset = 0; 322 323 *len = 0; 324 325 while (tmplen > 0) { 326 status = gnutls_io_input_read(ctxt, buf + offset, &tmplen); 327 328 if (status != APR_SUCCESS) { 329 return status; 330 } 331 332 *len += tmplen; 333 334 if ((pos = memchr(buf, APR_ASCII_LF, *len))) { 335 break; 336 } 337 338 offset += tmplen; 339 tmplen = buflen - offset; 340 } 341 342 if (pos) { 343 char *value; 344 int length; 345 apr_size_t bytes = pos - buf; 346 347 bytes += 1; 348 value = buf + bytes; 349 length = *len - bytes; 350 351 char_buffer_write(&ctxt->input_cbuf, value, length); 352 353 *len = bytes; 354 } 355 356 return APR_SUCCESS; 313 char *buf, apr_size_t * len) { 314 const char *pos = NULL; 315 apr_status_t status; 316 apr_size_t tmplen = *len, buflen = *len, offset = 0; 317 318 *len = 0; 319 320 while (tmplen > 0) { 321 status = gnutls_io_input_read(ctxt, buf + offset, &tmplen); 322 323 if (status != APR_SUCCESS) { 324 return status; 325 } 326 327 *len += tmplen; 328 329 if ((pos = memchr(buf, APR_ASCII_LF, *len))) { 330 break; 331 } 332 333 offset += tmplen; 334 tmplen = buflen - offset; 335 } 336 337 if (pos) { 338 char *value; 339 int length; 340 apr_size_t bytes = pos - buf; 341 342 bytes += 1; 343 value = buf + bytes; 344 length = *len - bytes; 345 346 char_buffer_write(&ctxt->input_cbuf, value, length); 347 348 *len = bytes; 349 } 350 351 return APR_SUCCESS; 357 352 } 358 353 359 354 #define HANDSHAKE_MAX_TRIES 1024 360 static int gnutls_do_handshake(mgs_handle_t * ctxt) 361 {362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 355 356 static int gnutls_do_handshake(mgs_handle_t * ctxt) { 357 int ret; 358 int errcode; 359 int maxtries = HANDSHAKE_MAX_TRIES; 360 361 if (ctxt->status != 0 || ctxt->session == NULL) { 362 return -1; 363 } 364 365 tryagain: 366 do { 367 ret = gnutls_handshake(ctxt->session); 368 maxtries--; 369 } while ((ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) 370 && maxtries > 0); 371 372 if (maxtries < 1) { 373 ctxt->status = -1; 379 374 #if USING_2_1_RECENT 380 381 375 ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, ctxt->c, 376 "GnuTLS: Handshake Failed. Hit Maximum Attempts"); 382 377 #else 383 384 385 378 ap_log_error(APLOG_MARK, APLOG_ERR, 0, 379 ctxt->c->base_server, 380 "GnuTLS: Handshake Failed. Hit Maximum Attempts"); 386 381 #endif 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 382 if (ctxt->session) { 383 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, 384 gnutls_error_to_alert 385 (GNUTLS_E_INTERNAL_ERROR, NULL)); 386 gnutls_deinit(ctxt->session); 387 } 388 ctxt->session = NULL; 389 return -1; 390 } 391 392 if (ret < 0) { 393 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED 394 || ret == GNUTLS_E_FATAL_ALERT_RECEIVED) { 395 errcode = gnutls_alert_get(ctxt->session); 396 ap_log_error(APLOG_MARK, APLOG_INFO, 0, 397 ctxt->c->base_server, 398 "GnuTLS: Hanshake Alert (%d) '%s'.", 399 errcode, 400 gnutls_alert_get_name(errcode)); 401 } 402 403 if (!gnutls_error_is_fatal(ret)) { 404 ap_log_error(APLOG_MARK, APLOG_INFO, 0, 405 ctxt->c->base_server, 406 "GnuTLS: Non-Fatal Handshake Error: (%d) '%s'", 407 ret, gnutls_strerror(ret)); 408 goto tryagain; 409 } 415 410 #if USING_2_1_RECENT 416 417 418 411 ap_log_cerror(APLOG_MARK, APLOG_INFO, 0, ctxt->c, 412 "GnuTLS: Handshake Failed (%d) '%s'", ret, 413 gnutls_strerror(ret)); 419 414 #else 420 421 422 423 415 ap_log_error(APLOG_MARK, APLOG_INFO, 0, 416 ctxt->c->base_server, 417 "GnuTLS: Handshake Failed (%d) '%s'", ret, 418 gnutls_strerror(ret)); 424 419 #endif 425 ctxt->status = -1; 426 if (ctxt->session) { 427 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, 428 gnutls_error_to_alert(ret, 429 NULL)); 430 gnutls_deinit(ctxt->session); 431 } 432 ctxt->session = NULL; 433 return ret; 434 } else { 435 /* all done with the handshake */ 436 ctxt->status = 1; 437 /* If the session was resumed, we did not set the correct 438 * server_rec in ctxt->sc. Go Find it. (ick!) 439 */ 440 if (gnutls_session_is_resumed(ctxt->session)) { 441 mgs_srvconf_rec *sc; 442 sc = mgs_find_sni_server(ctxt->session); 443 if (sc) { 444 ctxt->sc = sc; 445 } 446 } 447 return 0; 448 } 449 } 450 451 int mgs_rehandshake(mgs_handle_t * ctxt) 452 { 453 int rv; 454 455 if (ctxt->session == NULL) 456 return -1; 457 458 rv = gnutls_rehandshake(ctxt->session); 459 460 if (rv != 0) { 461 /* the client did not want to rehandshake. goodbye */ 462 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, 463 ctxt->c->base_server, 464 "GnuTLS: Client Refused Rehandshake request."); 465 return -1; 466 } 467 468 ctxt->status = 0; 469 470 rv = gnutls_do_handshake(ctxt); 471 472 return rv; 473 } 474 420 ctxt->status = -1; 421 if (ctxt->session) { 422 gnutls_alert_send(ctxt->session, GNUTLS_AL_FATAL, 423 gnutls_error_to_alert(ret, 424 NULL)); 425 gnutls_deinit(ctxt->session); 426 } 427 ctxt->session = NULL; 428 return ret; 429 } else { 430 /* all done with the handshake */ 431 ctxt->status = 1; 432 /* If the session was resumed, we did not set the correct 433 * server_rec in ctxt->sc. Go Find it. (ick!) 434 */ 435 if (gnutls_session_is_resumed(ctxt->session)) { 436 mgs_srvconf_rec *sc; 437 sc = mgs_find_sni_server(ctxt->session); 438 if (sc) { 439 ctxt->sc = sc; 440 } 441 } 442 return 0; 443 } 444 } 445 446 int mgs_rehandshake(mgs_handle_t * ctxt) { 447 int rv; 448 449 if (ctxt->session == NULL) 450 return -1; 451 452 rv = gnutls_rehandshake(ctxt->session); 453 454 if (rv != 0) { 455 /* the client did not want to rehandshake. goodbye */ 456 ap_log_error(APLOG_MARK, APLOG_WARNING, 0, 457 ctxt->c->base_server, 458 "GnuTLS: Client Refused Rehandshake request."); 459 return -1; 460 } 461 462 ctxt->status = 0; 463 464 rv = gnutls_do_handshake(ctxt); 465 466 return rv; 467 } 475 468 476 469 apr_status_t mgs_filter_input(ap_filter_t * f, 477 apr_bucket_brigade * bb, 478 ap_input_mode_t mode, 479 apr_read_type_e block, apr_off_t readbytes) 480 { 481 apr_status_t status = APR_SUCCESS; 482 mgs_handle_t *ctxt = (mgs_handle_t *) f->ctx; 483 apr_size_t len = sizeof(ctxt->input_buffer); 484 485 if (f->c->aborted) { 486 apr_bucket *bucket = 487 apr_bucket_eos_create(f->c->bucket_alloc); 488 APR_BRIGADE_INSERT_TAIL(bb, bucket); 489 return APR_ECONNABORTED; 490 } 491 492 if (ctxt->status == 0) { 493 gnutls_do_handshake(ctxt); 494 } 495 496 if (ctxt->status < 0) { 497 return ap_get_brigade(f->next, bb, mode, block, readbytes); 498 } 499 500 /* XXX: we don't currently support anything other than these modes. */ 501 if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE && 502 mode != AP_MODE_SPECULATIVE && mode != AP_MODE_INIT) { 503 return APR_ENOTIMPL; 504 } 505 506 ctxt->input_mode = mode; 507 ctxt->input_block = block; 508 509 if (ctxt->input_mode == AP_MODE_READBYTES || 510 ctxt->input_mode == AP_MODE_SPECULATIVE) { 511 /* Err. This is bad. readbytes *can* be a 64bit int! len.. is NOT */ 512 if (readbytes < len) { 513 len = (apr_size_t) readbytes; 514 } 515 status = 516 gnutls_io_input_read(ctxt, ctxt->input_buffer, &len); 517 } else if (ctxt->input_mode == AP_MODE_GETLINE) { 518 status = 519 gnutls_io_input_getline(ctxt, ctxt->input_buffer, 520 &len); 521 } else { 522 /* We have no idea what you are talking about, so return an error. */ 523 return APR_ENOTIMPL; 524 } 525 526 if (status != APR_SUCCESS) { 527 return gnutls_io_filter_error(f, bb, status); 528 } 529 530 /* Create a transient bucket out of the decrypted data. */ 531 if (len > 0) { 532 apr_bucket *bucket = 533 apr_bucket_transient_create(ctxt->input_buffer, len, 534 f->c->bucket_alloc); 535 APR_BRIGADE_INSERT_TAIL(bb, bucket); 536 } 537 538 return status; 539 } 540 541 static ssize_t write_flush(mgs_handle_t * ctxt) 542 { 543 apr_bucket *e; 544 545 if (!(ctxt->output_blen || ctxt->output_length)) { 546 ctxt->output_rc = APR_SUCCESS; 547 return 1; 548 } 549 550 if (ctxt->output_blen) { 551 e = apr_bucket_transient_create(ctxt->output_buffer, 552 ctxt->output_blen, 553 ctxt->output_bb-> 554 bucket_alloc); 555 /* we filled this buffer first so add it to the 556 * * head of the brigade 557 * */ 558 APR_BRIGADE_INSERT_HEAD(ctxt->output_bb, e); 559 ctxt->output_blen = 0; 560 } 561