mirror of
https://github.com/kakwa/uts-server
synced 2024-11-05 01:08:51 +01:00
add many comments
This commit is contained in:
parent
5eec6c6f27
commit
c2d0bdfecb
@ -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,16 +185,18 @@ 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"
|
||||
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
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n",
|
||||
(int)content_length);
|
||||
mg_write(conn, content, content_length);
|
||||
@ -190,39 +204,41 @@ int rfc3161_handler(struct mg_connection *conn, void *context) {
|
||||
content_length);
|
||||
break;
|
||||
case 400:
|
||||
mg_printf(conn,
|
||||
"HTTP/1.1 400 Bad Request\r\n"
|
||||
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
|
||||
"Content-Length: 12\r\n"
|
||||
"\r\n"
|
||||
"client error");
|
||||
break;
|
||||
default:
|
||||
mg_printf(conn,
|
||||
"HTTP/1.1 500 Internal Server Error\r\n"
|
||||
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
|
||||
"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"
|
||||
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
|
||||
"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);
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user