add many comments

This commit is contained in:
kakwa 2016-09-11 22:01:22 +02:00
parent 1d53fdeb90
commit 96587d3461
3 changed files with 90 additions and 27 deletions

View File

@ -146,6 +146,9 @@ int rfc3161_handler(struct mg_connection *conn, void *context) {
bool is_tsq = 0;
// go through every headers to find Content-Type
// and check if it's set to "application/timestamp-query"
// if it's the case, set is_tsq (is time-stamp query) to True
for (int i = 0; i < request_info->num_headers; i++) {
const char *h_name = request_info->http_headers[i].name;
const char *h_value = request_info->http_headers[i].value;
@ -159,13 +162,22 @@ int rfc3161_handler(struct mg_connection *conn, void *context) {
char *serial_id = NULL;
// Send HTTP reply to the client
// Send HTTP reply to the client.
//
// If it's a time-stamp query.
if (is_tsq) {
// Recover query content from http request.
char *query = calloc(request_info->content_length, sizeof(char));
int query_len = mg_read(conn, query, request_info->content_length);
// Log the query as DEBUG log in hexadecimal format
log_hex(ct, LOG_DEBUG, "query hexdump content", (unsigned char *)query,
request_info->content_length);
// Get an OpenSSL TS_RESP_CTX (wrapped inside ts_resp_ctx_wrapper
// structure).
// get_ctxw recovers the first unused TS_RESP_CTX
// in the ct->ts_ctx_pool pool of TS_RESP_CTX.
// (TS_RESP_CTX are not thread safe)
ts_resp_ctx_wrapper *ctx_w = get_ctxw(ct);
if (ctx_w == NULL) {
resp_code = 500;
@ -173,56 +185,60 @@ int rfc3161_handler(struct mg_connection *conn, void *context) {
"Unable to get an OpenSSL ts_context in the pool");
} else {
// create the response
resp_code = create_response(ct, query, query_len, ctx_w->ts_ctx,
&content_length, &content, &serial_id);
// free the TS_RESP_CTX used
ctx_w->available = 1;
}
// respond according to create_response return code
switch (resp_code) {
case 200:
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/timestamp-reply\r\n"
"Content-Length: %d\r\n" // Always set Content-Length
"\r\n",
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Type: application/timestamp-reply\r\n"
"Content-Length: %d\r\n"
"\r\n",
(int)content_length);
mg_write(conn, content, content_length);
log_hex(ct, LOG_DEBUG, "response hexdump content", content,
content_length);
break;
case 400:
mg_printf(conn,
"HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 12\r\n" // Always set Content-Length
"\r\n"
"client error");
mg_printf(conn, "HTTP/1.1 400 Bad Request\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 12\r\n"
"\r\n"
"client error");
break;
default:
mg_printf(conn,
"HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 17\r\n" // Always set Content-Length
"\r\n"
"uts-server error");
mg_printf(conn, "HTTP/1.1 500 Internal Server Error\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 17\r\n"
"\r\n"
"uts-server error");
}
free(query);
free(content);
} else {
// default reply if we don't have a time-stamp request
resp_code = 200;
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 46\r\n" // Always set Content-Length
"\r\n"
"uts-server, a simple RFC 3161 timestamp server");
mg_printf(conn, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 46\r\n"
"\r\n"
"uts-server, a simple RFC 3161 timestamp server");
}
// initialize a serial_id if not created by create_response
if (serial_id == NULL) {
serial_id = calloc(9, sizeof(char));
serial_id = rand_string(serial_id, 8);
}
// some debugging logs
log_request_debug(request_info, serial_id, ct);
// end of some timer stuff
diff = clock() - start;
// log the request
log_request(request_info, serial_id, ct, resp_code,
(diff * 1000000 / CLOCKS_PER_SEC));
free(serial_id);

View File

@ -66,6 +66,7 @@ int add_oid_section(rfc3161_context *ct, CONF *conf) {
return 1;
}
// initialize OpenSSL global black magic...
void init_ssl() {
SSL_load_error_strings();
ERR_load_BIO_strings();
@ -73,6 +74,7 @@ void init_ssl() {
ERR_load_TS_strings();
}
// free OpenSSL global black magic...
void free_ssl() {
CONF_modules_unload(1);
EVP_cleanup();
@ -84,28 +86,41 @@ void free_ssl() {
OBJ_cleanup();
}
// recover a ts wrapper
// Recover a ts wrapper from a pool of TS_RESP_CTX.
// Used because TS_RESP_CTX is not thread safe.
ts_resp_ctx_wrapper *get_ctxw(rfc3161_context *ct) {
ts_resp_ctx_wrapper *ret = NULL;
// itarate on the 'numthreads' TS_RESP_CTX we have in the pool
// we have as much as TS_RESP_CTX as parallele handlers
for (int i = 0; i < ct->numthreads; i++) {
// wait until we have exclusive access to read and maybe
// write the ts_resp_ctx_wrapper structure.
pthread_mutex_lock(&ct->ts_ctx_pool[i].lock);
// if the TS_RESP_CTX is available,
// take it and mark it as reserved (available = 0)
if (ct->ts_ctx_pool[i].available) {
ct->ts_ctx_pool[i].available = 0;
ret = &(ct->ts_ctx_pool[i]);
// unlock the the ts_resp_ctx_wrapper
pthread_mutex_unlock(&ct->ts_ctx_pool[i].lock);
// return the ts_resp_ctx_wrapper
return ret;
}
// unlock in case the ts_resp_ctx_wrapper was not available
pthread_mutex_unlock(&ct->ts_ctx_pool[i].lock);
}
// default return if no TS_RESP_CTX wa available
return ret;
}
// create a TS_RESP_CTX (OpenSSL Time-Stamp Response Context)
TS_RESP_CTX *create_tsctx(rfc3161_context *ct, CONF *conf, const char *section,
const char *policy) {
unsigned long err_code;
unsigned long err_code_prev = 0;
TS_RESP_CTX *resp_ctx = NULL;
// recover the section defining the default tsa
if ((section = TS_CONF_get_tsa_section(conf, section)) == NULL) {
uts_logger(ct, LOG_ERR, "failed to get or use '%s' in section [ %s ]",
"default_tsa", "tsa");
@ -115,6 +130,7 @@ TS_RESP_CTX *create_tsctx(rfc3161_context *ct, CONF *conf, const char *section,
uts_logger(ct, LOG_ERR, "failed to initialize tsa context");
goto end;
}
// recover and set various parameters
TS_RESP_CTX_set_serial_cb(resp_ctx, serial_cb, NULL);
if (!TS_CONF_set_crypto_device(conf, section, NULL)) {
uts_logger(ct, LOG_ERR, "failed to get or use '%s' in section [ %s ]",
@ -189,6 +205,7 @@ TS_RESP_CTX *create_tsctx(rfc3161_context *ct, CONF *conf, const char *section,
}
return resp_ctx;
end:
// log the OpenSSL errors if any in case of error
while ((err_code = ERR_get_error())) {
if (err_code_prev != err_code) {
uts_logger(ct, LOG_DEBUG, "OpenSSL exception: '%s'",
@ -199,6 +216,7 @@ end:
}
err_code_prev = err_code;
}
// free the TS_RESP_CTX if initialization has faile
TS_RESP_CTX_free(resp_ctx);
return NULL;
}
@ -215,10 +233,13 @@ int create_response(rfc3161_context *ct, char *query, int query_len,
unsigned long err_code;
unsigned long err_code_prev = 0;
// create the input bio for OpenSSL containing the query
if ((query_bio = BIO_new_mem_buf(query, query_len)) == NULL) {
uts_logger(ct, LOG_ERR, "failed to parse query");
goto end;
}
// generate the response
if ((ts_response = TS_RESP_create_response(resp_ctx, query_bio)) == NULL) {
uts_logger(ct, LOG_ERR, "failed to create ts response");
goto end;
@ -252,6 +273,7 @@ end:
serial_hex = calloc(SERIAL_ID_SIZE, sizeof(char));
strncpy(serial_hex, " NO ID ", SERIAL_ID_SIZE + 2);
}
// get a short version of the serial (150 bits in hexa is a bit long)
strncpy(*serial_id, serial_hex, SERIAL_ID_SIZE);
@ -271,6 +293,7 @@ end:
bptr->data, *serial_id);
// emit logs according the return value
// and set the return code
long status = ASN1_INTEGER_get(ts_response->status_info->status);
switch (status) {
case TS_STATUS_GRANTED:
@ -312,7 +335,7 @@ end:
ret = 500;
}
// log the openssl errors
// log the OpenSSL errors if any
while ((err_code = ERR_get_error())) {
if (err_code_prev != err_code) {
ERR_load_TS_strings();
@ -331,6 +354,9 @@ end:
return ret;
}
// Build a random serial for each request.
// It's less painful to manage than an incremental serial stored in a file
// and a 150 bits size is more than enough to prevent collision.
static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data42) {
unsigned char data[150] = {0};
RAND_bytes(data, sizeof(data));

View File

@ -136,6 +136,7 @@ void skeleton_daemon() {
// openlog("uts-server", LOG_PID, LOG_DAEMON);
}
// log a binary blob as hexadecimal
void log_hex(rfc3161_context *ct, int priority, char *id,
unsigned char *content, int content_length) {
if (priority > ct->loglevel && !ct->stdout_dbg)
@ -154,22 +155,26 @@ void log_hex(rfc3161_context *ct, int priority, char *id,
free(out);
}
// logger function
void uts_logger(rfc3161_context *ct, int priority, char *fmt, ...) {
// ignore all messages less critical than the loglevel
// except if the debug flag is set
if (priority > ct->loglevel && !ct->stdout_dbg)
return;
// build the out log message
FILE *stream;
char *out;
size_t len;
stream = open_memstream(&out, &len);
va_list args;
va_start(args, fmt);
vfprintf(stream, fmt, args);
va_end(args);
fflush(stream);
fclose(stream);
// if in debugging mode, also log to stdout
if (ct->stdout_dbg) {
switch (priority) {
case LOG_EMERG:
@ -209,6 +214,7 @@ void uts_logger(rfc3161_context *ct, int priority, char *fmt, ...) {
free(out);
}
// OpenSSL file openner (use for opening the configuration file
static BIO *bio_open_default(rfc3161_context *ct, const char *filename,
int format) {
BIO *ret;
@ -229,6 +235,7 @@ static BIO *bio_open_default(rfc3161_context *ct, const char *filename,
return NULL;
}
// loading the configuration file and parsing it using the OpenSSL parser
static CONF *load_config_file(rfc3161_context *ct, const char *filename) {
long errorline = -1;
BIO *in;
@ -260,13 +267,18 @@ static CONF *load_config_file(rfc3161_context *ct, const char *filename) {
return NULL;
}
// initialize the rfc3161_context according to the conf_file content
int set_params(rfc3161_context *ct, char *conf_file, char *conf_wd) {
// chdir in configuration file directory
// (some parameters like certificates can be declared
// relatively to the configuration file).
chdir(conf_wd);
int ret = 1;
int http_counter = 0;
int numthreads = 42;
NCONF_free(ct->conf);
// load the configuration file
ct->conf = load_config_file(ct, conf_file);
if (ct->conf == NULL)
goto end;
@ -297,6 +309,7 @@ int set_params(rfc3161_context *ct, char *conf_file, char *conf_wd) {
;
}
}
// parse the options to get the civetweb options and a few other things
for (int i = 0; i < RFC3161_OPTIONS_LEN; i++) {
int type = rfc3161_options[i].type;
const char *name = rfc3161_options[i].name;
@ -311,6 +324,8 @@ int set_params(rfc3161_context *ct, char *conf_file, char *conf_wd) {
uts_logger(ct, LOG_DEBUG, "configuration param['%s'] = '%s'", name,
value);
switch (type) {
// if it's an http (civetweb) option, put it in the http_options buffer
// like civetweb is expected it.
case HTTP_OPTIONS:
if (value != NULL) {
ct->http_options[http_counter] = name;
@ -318,6 +333,8 @@ int set_params(rfc3161_context *ct, char *conf_file, char *conf_wd) {
ct->http_options[http_counter] = value;
http_counter++;
}
// recover the num_threads parameter as it's used to
// initialize the TS_RESP_CTX pool
if (strcmp(name, "num_threads") == 0)
numthreads = atoi(value);
break;
@ -331,6 +348,9 @@ int set_params(rfc3161_context *ct, char *conf_file, char *conf_wd) {
if (!add_oid_section(ct, ct->conf))
ret = 0;
// initialize the TS_RESP_CTX pool
// as TS_RESP_CTX is not thread safe,
// creates 'num_threads' TS_RESP_CTX (one per thread)
ct->ts_ctx_pool = calloc(numthreads, sizeof(ts_resp_ctx_wrapper));
ct->numthreads = numthreads;
for (int i = 0; i < numthreads; i++) {
@ -339,6 +359,7 @@ int set_params(rfc3161_context *ct, char *conf_file, char *conf_wd) {
if (ct->ts_ctx_pool[i].ts_ctx == NULL)
ret = 0;
}
// like any good daemon, return to '/' once the configuration is loaded
chdir("/");
return ret;