enhanced httpd to accept a document root specified of the secure nwad prefixed with https://.

moved ssl context initialization for server from the httpd structure to the server structure
This commit is contained in:
hyung-hwan 2014-10-16 12:30:20 +00:00
parent c9d23a0d8b
commit a97cce7d70
5 changed files with 112 additions and 56 deletions

View File

@ -156,6 +156,7 @@ struct loccfg_t
{ {
ROOT_TYPE_PATH = 0, ROOT_TYPE_PATH = 0,
ROOT_TYPE_NWAD, ROOT_TYPE_NWAD,
ROOT_TYPE_NWAD_SECURE,
ROOT_TYPE_RELOC, ROOT_TYPE_RELOC,
ROOT_TYPE_ERROR ROOT_TYPE_ERROR
} root_type; } root_type;
@ -234,9 +235,9 @@ struct server_xtn_t
{ {
int nodir; /* no directory listing */ int nodir; /* no directory listing */
int num; int num; /* the server number in the xli configuration */
qse_nwad_t bind; qse_nwad_t bind; /* binding address */
int secure; int secure; /* ssl */
qse_mchar_t* scfg[SCFG_MAX]; qse_mchar_t* scfg[SCFG_MAX];
qse_httpd_serverstd_makersrc_t orgmakersrc; qse_httpd_serverstd_makersrc_t orgmakersrc;
@ -590,8 +591,11 @@ static int get_server_root (
switch (loccfg->root_type) switch (loccfg->root_type)
{ {
case ROOT_TYPE_NWAD_SECURE:
root->u.proxy.flags |= QSE_HTTPD_RSRC_PROXY_DST_SECURE;
/* fall thru */
case ROOT_TYPE_NWAD: case ROOT_TYPE_NWAD:
/* simple forwarding. it's not controlled by proxy.http or proxy.connect */ /* simple forwarding. it's not controlled by proxy.http, proxy.https or proxy.connect */
root->type = QSE_HTTPD_SERVERSTD_ROOT_PROXY; root->type = QSE_HTTPD_SERVERSTD_ROOT_PROXY;
root->u.proxy.dst.nwad = loccfg->root.nwad; root->u.proxy.dst.nwad = loccfg->root.nwad;
@ -1679,6 +1683,7 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list
{ {
/* check if the root value is special */ /* check if the root value is special */
const qse_mchar_t* root = cfg->xcfg[XCFG_ROOT]; const qse_mchar_t* root = cfg->xcfg[XCFG_ROOT];
int proto_len = 0;
if (root[0] == QSE_MT('<') && QSE_ISMDIGIT(root[1])) if (root[0] == QSE_MT('<') && QSE_ISMDIGIT(root[1]))
{ {
@ -1722,16 +1727,31 @@ static int load_loccfg (qse_httpd_t* httpd, qse_xli_t* xli, qse_xli_list_t* list
goto done; goto done;
} }
} }
root = cfg->xcfg[XCFG_ROOT];
}
else
{
if (qse_mbszcasecmp (root, QSE_MT("http://"), (proto_len = 7)) == 0 ||
qse_mbszcasecmp (root, QSE_MT("https://"), (proto_len = 8)) == 0)
{
root += proto_len;
}
else
{
proto_len = 0;
}
} }
if (qse_mbstonwad (cfg->xcfg[XCFG_ROOT], &cfg->root.nwad) >= 0) if (qse_mbstonwad (root, &cfg->root.nwad) >= 0)
{ {
if (cfg->root.nwad.type != QSE_NWAD_IN4 && cfg->root.nwad.type != QSE_NWAD_IN6) if (cfg->root.nwad.type != QSE_NWAD_IN4 && cfg->root.nwad.type != QSE_NWAD_IN6)
{ {
qse_printf (QSE_T("ERROR: invalid address for root - [%hs]\n"), cfg->xcfg[XCFG_ROOT]); qse_printf (QSE_T("ERROR: invalid address for root - [%hs]\n"), cfg->xcfg[XCFG_ROOT]);
return -1; return -1;
} }
cfg->root_type = ROOT_TYPE_NWAD;
cfg->root_type = (proto_len == 8)? ROOT_TYPE_NWAD_SECURE: ROOT_TYPE_NWAD;
goto done; goto done;
} }
} }

View File

@ -137,6 +137,7 @@ server-default {
#################################################################### ####################################################################
proxy { proxy {
http = yes; # yes/on, no/off http = yes; # yes/on, no/off
https = yes; # yes/on, no/off
connect = yes; # yes/on, no/off connect = yes; # yes/on, no/off
intercept = yes; # yes/proxy/on, local, no/off, intercept = yes; # yes/proxy/on, local, no/off,
upgrade = yes; # yes/on, no/off upgrade = yes; # yes/on, no/off

View File

@ -674,7 +674,7 @@ struct qse_httpd_server_t
qse_httpd_server_dope_t dope; qse_httpd_server_dope_t dope;
/* set by server.open callback */ /* set by server.open callback */
qse_httpd_hnd_t handle; qse_httpd_hnd_t handle;
/* private */ /* private */
qse_httpd_t* httpd; qse_httpd_t* httpd;

View File

@ -135,6 +135,10 @@ struct server_xtn_t
qse_httpd_serverstd_makersrc_t makersrc; qse_httpd_serverstd_makersrc_t makersrc;
qse_httpd_serverstd_freersrc_t freersrc; qse_httpd_serverstd_freersrc_t freersrc;
#if defined(HAVE_SSL)
SSL_CTX* ssl_ctx;
#endif
/* temporary buffer to handle authorization */ /* temporary buffer to handle authorization */
qse_mcstr_t auth; qse_mcstr_t auth;
}; };
@ -577,7 +581,6 @@ typedef struct httpd_xtn_t httpd_xtn_t;
struct httpd_xtn_t struct httpd_xtn_t
{ {
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
SSL_CTX* ssl_client_ctx;
SSL_CTX* ssl_peer_ctx; SSL_CTX* ssl_peer_ctx;
#endif #endif
qse_httpd_ecb_t ecb; qse_httpd_ecb_t ecb;
@ -586,15 +589,12 @@ struct httpd_xtn_t
}; };
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server) static int init_server_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server)
{ {
/* BUG BUG BUG. SSL context for client must exist inside the seerver, i guess */ SSL_CTX* ssl_ctx = QSE_NULL;
SSL_CTX* client_ctx = QSE_NULL;
httpd_xtn_t* xtn;
server_xtn_t* server_xtn; server_xtn_t* server_xtn;
qse_httpd_serverstd_ssl_t ssl; qse_httpd_serverstd_ssl_t ssl;
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, server); server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, server);
if (server_xtn->query (httpd, server, QSE_HTTPD_SERVERSTD_SSL, QSE_NULL, &ssl) <= -1) if (server_xtn->query (httpd, server, QSE_HTTPD_SERVERSTD_SSL, QSE_NULL, &ssl) <= -1)
@ -604,23 +604,23 @@ static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server)
if (ssl.certfile == QSE_NULL || ssl.keyfile == QSE_NULL) if (ssl.certfile == QSE_NULL || ssl.keyfile == QSE_NULL)
{ {
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); httpd->errnum = QSE_HTTPD_EINVAL;
goto oops; goto oops;
} }
client_ctx = SSL_CTX_new (SSLv23_server_method()); ssl_ctx = SSL_CTX_new (SSLv23_server_method());
if (!client_ctx) if (!ssl_ctx)
{ {
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM); httpd->errnum = QSE_HTTPD_ESYSERR;
goto oops; goto oops;
} }
/*SSL_CTX_set_info_callback(ctx,ssl_info_callback);*/ /*SSL_CTX_set_info_callback(ctx,ssl_info_callback);*/
if (SSL_CTX_use_certificate_file (client_ctx, ssl.certfile, SSL_FILETYPE_PEM) == 0 || if (SSL_CTX_use_certificate_file (ssl_ctx, ssl.certfile, SSL_FILETYPE_PEM) == 0 ||
SSL_CTX_use_PrivateKey_file (client_ctx, ssl.keyfile, SSL_FILETYPE_PEM) == 0 || SSL_CTX_use_PrivateKey_file (ssl_ctx, ssl.keyfile, SSL_FILETYPE_PEM) == 0 ||
SSL_CTX_check_private_key (client_ctx) == 0 /*|| SSL_CTX_check_private_key (ssl_ctx) == 0 /*||
SSL_CTX_use_certificate_chain_file (client_ctx, chainfile) == 0*/) SSL_CTX_use_certificate_chain_file (ssl_ctx, chainfile) == 0*/)
{ {
if (httpd->opt.trait & QSE_HTTPD_LOGACT) if (httpd->opt.trait & QSE_HTTPD_LOGACT)
{ {
@ -632,29 +632,29 @@ static int init_xtn_ssl (qse_httpd_t* httpd, qse_httpd_server_t* server)
httpd->opt.rcb.logact (httpd, &msg); httpd->opt.rcb.logact (httpd, &msg);
} }
qse_httpd_seterrnum (httpd, QSE_HTTPD_EINVAL); /* TODO: define a better error code */ httpd->errnum = QSE_HTTPD_ESYSERR; /* TODO: define a better error code */
goto oops; goto oops;
} }
/* TODO: SSL_CTX_set_verify(); SSL_CTX_set_verify_depth() */ /* TODO: SSL_CTX_set_verify(); SSL_CTX_set_verify_depth() */
/* TODO: CRYPTO_set_id_callback (); */ /* TODO: CRYPTO_set_id_callback (); */
/* TODO: CRYPTO_set_locking_callback (); */ /* TODO: CRYPTO_set_locking_callback (); */
SSL_CTX_set_read_ahead (client_ctx, 0); SSL_CTX_set_read_ahead (ssl_ctx, 0);
xtn->ssl_client_ctx = client_ctx; server_xtn->ssl_ctx = ssl_ctx;
return 0; return 0;
oops: oops:
if (client_ctx) SSL_CTX_free (client_ctx); if (ssl_ctx) SSL_CTX_free (ssl_ctx);
return -1; return -1;
} }
static void fini_xtn_ssl (httpd_xtn_t* xtn) static void fini_server_ssl (server_xtn_t* xtn)
{ {
/* TODO: CRYPTO_set_id_callback (QSE_NULL); */ /* TODO: CRYPTO_set_id_callback (QSE_NULL); */
/* TODO: CRYPTO_set_locking_callback (QSE_NULL); */ /* TODO: CRYPTO_set_locking_callback (QSE_NULL); */
SSL_CTX_free (xtn->ssl_client_ctx); SSL_CTX_free (xtn->ssl_ctx);
} }
static int init_xtn_peer_ssl (qse_httpd_t* httpd) static int init_xtn_peer_ssl (qse_httpd_t* httpd)
@ -667,13 +667,11 @@ static int init_xtn_peer_ssl (qse_httpd_t* httpd)
peer_ctx = SSL_CTX_new (SSLv23_client_method()); peer_ctx = SSL_CTX_new (SSLv23_client_method());
if (!peer_ctx) if (!peer_ctx)
{ {
qse_httpd_seterrnum (httpd, QSE_HTTPD_ENOMEM); httpd->errnum = QSE_HTTPD_ESYSERR;
goto oops; goto oops;
} }
xtn->ssl_peer_ctx = peer_ctx; xtn->ssl_peer_ctx = peer_ctx;
printf ("SSL PEER CTX ============>%p\n", xtn->ssl_peer_ctx);
return 0; return 0;
oops: oops:
@ -698,7 +696,6 @@ static void cleanup_standard_httpd (qse_httpd_t* httpd)
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
if (xtn->ssl_peer_ctx) fini_xtn_peer_ssl (xtn); if (xtn->ssl_peer_ctx) fini_xtn_peer_ssl (xtn);
if (xtn->ssl_client_ctx) fini_xtn_ssl (xtn);
#endif #endif
#if defined(USE_LTDL) #if defined(USE_LTDL)
@ -713,11 +710,14 @@ qse_httpd_t* qse_httpd_openstd (qse_size_t xtnsize)
qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize)
{ {
qse_httpd_t* httpd; qse_httpd_t* httpd = QSE_NULL;
httpd_xtn_t* xtn; httpd_xtn_t* xtn = QSE_NULL;
#if defined(USE_LTDL)
int lt_dlinited = 0;
#endif
httpd = qse_httpd_open (mmgr, QSE_SIZEOF(httpd_xtn_t) + xtnsize); httpd = qse_httpd_open (mmgr, QSE_SIZEOF(httpd_xtn_t) + xtnsize);
if (httpd == QSE_NULL) return QSE_NULL; if (httpd == QSE_NULL) goto oops;
xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd);
@ -726,11 +726,12 @@ qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize)
* lt_dlexit() shuts down libltdl if it's called as many times as * lt_dlexit() shuts down libltdl if it's called as many times as
* corresponding lt_dlinit(). so it's safe to call lt_dlinit() * corresponding lt_dlinit(). so it's safe to call lt_dlinit()
* and lt_dlexit() at the library level. */ * and lt_dlexit() at the library level. */
if (lt_dlinit () != 0) if (lt_dlinit () != 0) goto oops;
{ lt_dlinited = 1;
qse_httpd_close (httpd); #endif
return QSE_NULL;
} #if defined(HAVE_SSL)
if (init_xtn_peer_ssl (httpd) <= -1) goto oops;
#endif #endif
set_httpd_callbacks (httpd); set_httpd_callbacks (httpd);
@ -739,6 +740,16 @@ qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize)
qse_httpd_pushecb (httpd, &xtn->ecb); qse_httpd_pushecb (httpd, &xtn->ecb);
return httpd; return httpd;
oops:
#if defined(HAVE_SSL)
if (xtn && xtn->ssl_peer_ctx) fini_xtn_peer_ssl (xtn);
#endif
#if defined(USE_LTDL)
if (lt_dlinited) lt_dlexit ();
#endif
if (httpd) qse_httpd_close (httpd);
return QSE_NULL;
} }
void* qse_httpd_getxtnstd (qse_httpd_t* httpd) void* qse_httpd_getxtnstd (qse_httpd_t* httpd)
@ -1169,11 +1180,7 @@ static int peer_open (qse_httpd_t* httpd, qse_httpd_peer_t* peer)
if (peer->flags & QSE_HTTPD_PEER_SECURE) if (peer->flags & QSE_HTTPD_PEER_SECURE)
{ {
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
if (!xtn->ssl_peer_ctx) QSE_ASSERT (xtn->ssl_peer_ctx != QSE_NULL);
{
/* TODO: peer ssl initialization doesn't have to be delayed... */
if (init_xtn_peer_ssl (httpd) <= -1) goto oops;
}
ssl = SSL_new (xtn->ssl_peer_ctx); ssl = SSL_new (xtn->ssl_peer_ctx);
if (ssl == QSE_NULL) if (ssl == QSE_NULL)
@ -2212,19 +2219,18 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
#if defined(HAVE_SSL) #if defined(HAVE_SSL)
int ret; int ret;
SSL* ssl; SSL* ssl;
httpd_xtn_t* xtn; server_xtn_t* server_xtn;
xtn = (httpd_xtn_t*) qse_httpd_getxtn (httpd); server_xtn = (server_xtn_t*)qse_httpd_getserverxtn (httpd, client->server);
if (!xtn->ssl_client_ctx)
if (!server_xtn->ssl_ctx)
{ {
/* delayed initialization of ssl */ /* performed the delayed ssl initialization */
if (init_xtn_ssl (httpd, client->server) <= -1) if (init_server_ssl (httpd, client->server) <= -1) return -1;
{
return -1;
}
} }
QSE_ASSERT (xtn->ssl_client_ctx != QSE_NULL); QSE_ASSERT (server_xtn->ssl_ctx != QSE_NULL);
QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl)); QSE_ASSERT (QSE_SIZEOF(client->handle2) >= QSE_SIZEOF(ssl));
if (HANDLE_TO_SSL(client->handle2)) if (HANDLE_TO_SSL(client->handle2))
@ -2233,14 +2239,19 @@ static int client_accepted (qse_httpd_t* httpd, qse_httpd_client_t* client)
} }
else else
{ {
ssl = SSL_new (xtn->ssl_client_ctx); ssl = SSL_new (server_xtn->ssl_ctx);
if (ssl == QSE_NULL) return -1; if (ssl == QSE_NULL)
{
httpd->errnum = QSE_HTTPD_ESYSERR;
return -1;
}
client->handle2 = SSL_TO_HANDLE(ssl); client->handle2 = SSL_TO_HANDLE(ssl);
if (SSL_set_fd (ssl, client->handle) == 0) if (SSL_set_fd (ssl, client->handle) == 0)
{ {
/* don't free ssl here since client_closed() /* don't free ssl here since client_closed()
* will free it */ * will free it */
httpd->errnum = QSE_HTTPD_ESYSERR;
return -1; return -1;
} }
@ -3335,6 +3346,10 @@ static void detach_server (qse_httpd_t* httpd, qse_httpd_server_t* server)
server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server); server_xtn = (server_xtn_t*) qse_httpd_getserverxtn (httpd, server);
if (server_xtn->detach) server_xtn->detach (httpd, server); if (server_xtn->detach) server_xtn->detach (httpd, server);
if (server_xtn->auth.ptr) QSE_MMGR_FREE (httpd->mmgr, server_xtn->auth.ptr); if (server_xtn->auth.ptr) QSE_MMGR_FREE (httpd->mmgr, server_xtn->auth.ptr);
#if defined(HAVE_SSL)
if (server_xtn->ssl_ctx) fini_server_ssl (server_xtn);
#endif
} }
struct mime_tab_t struct mime_tab_t
@ -3481,19 +3496,39 @@ qse_httpd_server_t* qse_httpd_attachserverstd (
server_xtn_t* server_xtn; server_xtn_t* server_xtn;
xdope = *dope; xdope = *dope;
/* detach_server() is called when the server is detached */
xdope.detach = detach_server; xdope.detach = detach_server;
xserver = qse_httpd_attachserver (httpd, &xdope, QSE_SIZEOF(*server_xtn) + xtnsize); xserver = qse_httpd_attachserver (httpd, &xdope, QSE_SIZEOF(*server_xtn) + xtnsize);
if (xserver == QSE_NULL) return QSE_NULL; if (xserver == QSE_NULL) return QSE_NULL;
server_xtn = qse_httpd_getserverxtn (httpd, xserver); server_xtn = qse_httpd_getserverxtn (httpd, xserver);
QSE_MEMSET (server_xtn, 0, QSE_SIZEOF(*server_xtn));
/* chain the original detach function */
server_xtn->detach = dope->detach; server_xtn->detach = dope->detach;
server_xtn->query = query_server; server_xtn->query = query_server;
server_xtn->makersrc = make_resource; server_xtn->makersrc = make_resource;
server_xtn->freersrc = free_resource; server_xtn->freersrc = free_resource;
/* init_server_ssl() queries the server instance for the SSL key and cert files.
* the standard query handler 'query_server' returns failure for this.
* the actual handler can be set with qse_httpd_setserverstdopt().
* calling init_server_ssl() causes server attachment to fail for this reason.
* so initialization of ssl must be delayed. So the call is commented out.
if (init_server_ssl (httpd, xserver) <= -1)
{
/ * reset server_xtn->detach as i want detach_server() to
* skip calling dope->detach. dope->detach should be called
* upon detachment only if qse_httpd_attachserverstd() has
* been successful. * /
server_xtn->detach = QSE_NULL;
qse_httpd_detachserver (httpd, xserver);
xserver = QSE_NULL;
}
*/
return xserver; return xserver;
} }

View File

@ -1635,7 +1635,7 @@ int qse_httpd_loop (qse_httpd_t* httpd)
if (httpd->server.list.head == QSE_NULL) if (httpd->server.list.head == QSE_NULL)
{ {
httpd->errnum = QSE_HTTPD_EINVAL; httpd->errnum = QSE_HTTPD_ENOSVR;
return -1; return -1;
} }