mirror of
https://github.com/kakwa/uts-server
synced 2025-01-05 19:33:33 +01:00
Merge branch 'master' of https://github.com/kakwa/uts-server
This commit is contained in:
commit
4e8693da48
@ -12,9 +12,9 @@ set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -DUTS_VERSION='\"${VERSION}\"'")
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
|
||||
|
||||
find_package(libasyncd REQUIRED)
|
||||
MESSAGE( STATUS "Find Header Directory for libasyncd: " ${LIBASYNCD_INCLUDE_DIR})
|
||||
MESSAGE( STATUS "Find Dynamic Library for libasyncd: " ${LIBASYNCD_LIBRARIES})
|
||||
find_package(libcivetweb REQUIRED)
|
||||
MESSAGE( STATUS "Find Header Directory for libcivetweb: " ${LIBCIVETWEB_INCLUDE_DIR})
|
||||
MESSAGE( STATUS "Find Dynamic Library for libcivetweb: " ${LIBCIVETWEB_LIBRARIES})
|
||||
|
||||
find_package(OpenSSL REQUIRED)
|
||||
MESSAGE( STATUS "OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
|
||||
@ -22,7 +22,7 @@ MESSAGE( STATUS "OpenSSL libraries: ${OPENSSL_LIBRARIES}")
|
||||
|
||||
include_directories(
|
||||
./inc/
|
||||
${LIBASYNCD_INCLUDE_DIR}
|
||||
${LIBCIVETWEB_INCLUDE_DIR}
|
||||
${OPENSSL_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
@ -30,10 +30,11 @@ add_executable(uts-server
|
||||
src/cmd/uts-server.c
|
||||
src/lib/rfc3161.c
|
||||
src/lib/utils.c
|
||||
src/lib/ini.c
|
||||
)
|
||||
|
||||
target_link_libraries(uts-server
|
||||
${LIBASYNCD_LIBRARIES}
|
||||
${LIBCIVETWEB_LIBRARIES}
|
||||
${OPENSSL_LIBRARIES}
|
||||
)
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
if (NOT LIBASYNCD_LIBRARIES)
|
||||
find_path(LIBASYNCD_INCLUDE_DIR asyncd.h ${_LIBASYNCD_PATHS} PATH_SUFFIXES include include/asyncd/)
|
||||
endif ()
|
||||
|
||||
if (NOT LIBASYNCD_LIBRARIES)
|
||||
find_library(LIBASYNCD_LIBRARIES NAMES asyncd ${_LIBASYNCD_PATHS} PATH_SUFFIXES lib)
|
||||
endif ()
|
7
cmake/Findlibcivetweb.cmake
Executable file
7
cmake/Findlibcivetweb.cmake
Executable file
@ -0,0 +1,7 @@
|
||||
if (NOT LIBCIVETWEB_LIBRARIES)
|
||||
find_path(LIBCIVETWEB_INCLUDE_DIR civetweb.h ${_LIBCIVETWEB_PATHS} PATH_SUFFIXES include include/civetweb/)
|
||||
endif ()
|
||||
|
||||
if (NOT LIBCIVETWEB_LIBRARIES)
|
||||
find_library(LIBCIVETWEB_LIBRARIES NAMES civetweb ${_LIBCIVETWEB_PATHS} PATH_SUFFIXES lib)
|
||||
endif ()
|
93
inc/ini.h
Normal file
93
inc/ini.h
Normal file
@ -0,0 +1,93 @@
|
||||
/* inih -- simple .INI file parser
|
||||
|
||||
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||
home page for more info:
|
||||
|
||||
https://github.com/benhoyt/inih
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __INI_H__
|
||||
#define __INI_H__
|
||||
|
||||
/* Make this header file easier to include in C++ code */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* Typedef for prototype of handler function. */
|
||||
typedef int (*ini_handler)(void* user, const char* section,
|
||||
const char* name, const char* value);
|
||||
|
||||
/* Typedef for prototype of fgets-style reader function. */
|
||||
typedef char* (*ini_reader)(char* str, int num, void* stream);
|
||||
|
||||
/* Parse given INI-style file. May have [section]s, name=value pairs
|
||||
(whitespace stripped), and comments starting with ';' (semicolon). Section
|
||||
is "" if name=value pair parsed before any section heading. name:value
|
||||
pairs are also supported as a concession to Python's configparser.
|
||||
|
||||
For each name=value pair parsed, call handler function with given user
|
||||
pointer as well as section, name, and value (data only valid for duration
|
||||
of handler call). Handler should return nonzero on success, zero on error.
|
||||
|
||||
Returns 0 on success, line number of first error on parse error (doesn't
|
||||
stop on first error), -1 on file open error, or -2 on memory allocation
|
||||
error (only when INI_USE_STACK is zero).
|
||||
*/
|
||||
int ini_parse(const char* filename, ini_handler handler, void* user);
|
||||
|
||||
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
|
||||
close the file when it's finished -- the caller must do that. */
|
||||
int ini_parse_file(FILE* file, ini_handler handler, void* user);
|
||||
|
||||
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
|
||||
filename. Used for implementing custom or string-based I/O. */
|
||||
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
void* user);
|
||||
|
||||
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
||||
configparser. If allowed, ini_parse() will call the handler with the same
|
||||
name for each subsequent line parsed. */
|
||||
#ifndef INI_ALLOW_MULTILINE
|
||||
#define INI_ALLOW_MULTILINE 1
|
||||
#endif
|
||||
|
||||
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
|
||||
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
|
||||
#ifndef INI_ALLOW_BOM
|
||||
#define INI_ALLOW_BOM 1
|
||||
#endif
|
||||
|
||||
/* Nonzero to allow inline comments (with valid inline comment characters
|
||||
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
|
||||
Python 3.2+ configparser behaviour. */
|
||||
#ifndef INI_ALLOW_INLINE_COMMENTS
|
||||
#define INI_ALLOW_INLINE_COMMENTS 1
|
||||
#endif
|
||||
#ifndef INI_INLINE_COMMENT_PREFIXES
|
||||
#define INI_INLINE_COMMENT_PREFIXES ";"
|
||||
#endif
|
||||
|
||||
/* Nonzero to use stack, zero to use heap (malloc/free). */
|
||||
#ifndef INI_USE_STACK
|
||||
#define INI_USE_STACK 1
|
||||
#endif
|
||||
|
||||
/* Stop parsing on first error (default is to keep parsing). */
|
||||
#ifndef INI_STOP_ON_FIRST_ERROR
|
||||
#define INI_STOP_ON_FIRST_ERROR 0
|
||||
#endif
|
||||
|
||||
/* Maximum line length for any line in INI file. */
|
||||
#ifndef INI_MAX_LINE
|
||||
#define INI_MAX_LINE 200
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INI_H__ */
|
194
src/lib/ini.c
Normal file
194
src/lib/ini.c
Normal file
@ -0,0 +1,194 @@
|
||||
/* inih -- simple .INI file parser
|
||||
|
||||
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||
home page for more info:
|
||||
|
||||
https://github.com/benhoyt/inih
|
||||
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ini.h"
|
||||
|
||||
#if !INI_USE_STACK
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#define MAX_SECTION 50
|
||||
#define MAX_NAME 50
|
||||
|
||||
/* Strip whitespace chars off end of given string, in place. Return s. */
|
||||
static char* rstrip(char* s)
|
||||
{
|
||||
char* p = s + strlen(s);
|
||||
while (p > s && isspace((unsigned char)(*--p)))
|
||||
*p = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
/* Return pointer to first non-whitespace char in given string. */
|
||||
static char* lskip(const char* s)
|
||||
{
|
||||
while (*s && isspace((unsigned char)(*s)))
|
||||
s++;
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
/* Return pointer to first char (of chars) or inline comment in given string,
|
||||
or pointer to null at end of string if neither found. Inline comment must
|
||||
be prefixed by a whitespace character to register as a comment. */
|
||||
static char* find_chars_or_comment(const char* s, const char* chars)
|
||||
{
|
||||
#if INI_ALLOW_INLINE_COMMENTS
|
||||
int was_space = 0;
|
||||
while (*s && (!chars || !strchr(chars, *s)) &&
|
||||
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
|
||||
was_space = isspace((unsigned char)(*s));
|
||||
s++;
|
||||
}
|
||||
#else
|
||||
while (*s && (!chars || !strchr(chars, *s))) {
|
||||
s++;
|
||||
}
|
||||
#endif
|
||||
return (char*)s;
|
||||
}
|
||||
|
||||
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
|
||||
static char* strncpy0(char* dest, const char* src, size_t size)
|
||||
{
|
||||
strncpy(dest, src, size);
|
||||
dest[size - 1] = '\0';
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||
void* user)
|
||||
{
|
||||
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||
#if INI_USE_STACK
|
||||
char line[INI_MAX_LINE];
|
||||
#else
|
||||
char* line;
|
||||
#endif
|
||||
char section[MAX_SECTION] = "";
|
||||
char prev_name[MAX_NAME] = "";
|
||||
|
||||
char* start;
|
||||
char* end;
|
||||
char* name;
|
||||
char* value;
|
||||
int lineno = 0;
|
||||
int error = 0;
|
||||
|
||||
#if !INI_USE_STACK
|
||||
line = (char*)malloc(INI_MAX_LINE);
|
||||
if (!line) {
|
||||
return -2;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Scan through stream line by line */
|
||||
while (reader(line, INI_MAX_LINE, stream) != NULL) {
|
||||
lineno++;
|
||||
|
||||
start = line;
|
||||
#if INI_ALLOW_BOM
|
||||
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
|
||||
(unsigned char)start[1] == 0xBB &&
|
||||
(unsigned char)start[2] == 0xBF) {
|
||||
start += 3;
|
||||
}
|
||||
#endif
|
||||
start = lskip(rstrip(start));
|
||||
|
||||
if (*start == ';' || *start == '#') {
|
||||
/* Per Python configparser, allow both ; and # comments at the
|
||||
start of a line */
|
||||
}
|
||||
#if INI_ALLOW_MULTILINE
|
||||
else if (*prev_name && *start && start > line) {
|
||||
/* Non-blank line with leading whitespace, treat as continuation
|
||||
of previous name's value (as per Python configparser). */
|
||||
if (!handler(user, section, prev_name, start) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
#endif
|
||||
else if (*start == '[') {
|
||||
/* A "[section]" line */
|
||||
end = find_chars_or_comment(start + 1, "]");
|
||||
if (*end == ']') {
|
||||
*end = '\0';
|
||||
strncpy0(section, start + 1, sizeof(section));
|
||||
*prev_name = '\0';
|
||||
}
|
||||
else if (!error) {
|
||||
/* No ']' found on section line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
else if (*start) {
|
||||
/* Not a comment, must be a name[=:]value pair */
|
||||
end = find_chars_or_comment(start, "=:");
|
||||
if (*end == '=' || *end == ':') {
|
||||
*end = '\0';
|
||||
name = rstrip(start);
|
||||
value = lskip(end + 1);
|
||||
#if INI_ALLOW_INLINE_COMMENTS
|
||||
end = find_chars_or_comment(value, NULL);
|
||||
if (*end)
|
||||
*end = '\0';
|
||||
#endif
|
||||
rstrip(value);
|
||||
|
||||
/* Valid name[=:]value pair found, call handler */
|
||||
strncpy0(prev_name, name, sizeof(prev_name));
|
||||
if (!handler(user, section, name, value) && !error)
|
||||
error = lineno;
|
||||
}
|
||||
else if (!error) {
|
||||
/* No '=' or ':' found on name[=:]value line */
|
||||
error = lineno;
|
||||
}
|
||||
}
|
||||
|
||||
#if INI_STOP_ON_FIRST_ERROR
|
||||
if (error)
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !INI_USE_STACK
|
||||
free(line);
|
||||
#endif
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse_file(FILE* file, ini_handler handler, void* user)
|
||||
{
|
||||
return ini_parse_stream((ini_reader)fgets, file, handler, user);
|
||||
}
|
||||
|
||||
/* See documentation in header file. */
|
||||
int ini_parse(const char* filename, ini_handler handler, void* user)
|
||||
{
|
||||
FILE* file;
|
||||
int error;
|
||||
|
||||
file = fopen(filename, "r");
|
||||
if (!file)
|
||||
return -1;
|
||||
error = ini_parse_file(file, handler, user);
|
||||
fclose(file);
|
||||
return error;
|
||||
}
|
@ -1,3 +1,13 @@
|
||||
/*
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <civetweb.h>
|
||||
#include <openssl/opensslconf.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@ -7,38 +17,400 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <asyncd/asyncd.h>
|
||||
|
||||
int ts_http_respond(short event, ad_conn_t *conn, void *userdata) {
|
||||
if (event & AD_EVENT_READ) {
|
||||
if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
|
||||
ad_http_response(conn, 200, "text/html", "Hello World", 11);
|
||||
return ad_http_is_keepalive_request(conn) ? AD_DONE : AD_CLOSE;
|
||||
}
|
||||
}
|
||||
return AD_OK;
|
||||
}
|
||||
/* Name of config entry that defines the OID file. */
|
||||
# define ENV_OID_FILE "oid_file"
|
||||
|
||||
int http_default_handler(short event, ad_conn_t *conn, void *userdata) {
|
||||
if (event & AD_EVENT_READ) {
|
||||
if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
|
||||
ad_http_response(conn, 501, "text/html", "Not implemented", 15);
|
||||
return AD_CLOSE; // Close connection.
|
||||
}
|
||||
}
|
||||
return AD_OK;
|
||||
static ASN1_OBJECT *txt2obj(const char *oid);
|
||||
static CONF *load_config_file(const char *configfile);
|
||||
|
||||
/* Reply related functions. */
|
||||
static int reply_command(CONF *conf, char *section, char *engine,
|
||||
char *queryfile, char *passin, char *inkey,
|
||||
const EVP_MD *md, char *signer, char *chain,
|
||||
const char *policy, char *in, int token_in,
|
||||
char *out, int token_out, int text);
|
||||
static TS_RESP *read_PKCS7(BIO *in_bio);
|
||||
static TS_RESP *create_response(CONF *conf, const char *section, char *engine,
|
||||
char *queryfile, char *passin,
|
||||
char *inkey, const EVP_MD *md, char *signer,
|
||||
char *chain, const char *policy);
|
||||
static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data);
|
||||
static ASN1_INTEGER *next_serial(const char *serialfile);
|
||||
static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial);
|
||||
|
||||
# define B_FORMAT_TEXT 0x8000
|
||||
# define FORMAT_UNDEF 0
|
||||
# define FORMAT_TEXT (1 | B_FORMAT_TEXT) /* Generic text */
|
||||
# define FORMAT_ASN1 4 /* ASN.1/DER */
|
||||
|
||||
|
||||
/*
|
||||
int ts_http_respond(short event, ad_conn_t *conn, void *userdata) {
|
||||
if (event & AD_EVENT_READ) {
|
||||
if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
|
||||
ad_http_response(conn, 200, "text/html", "Hello World", 11);
|
||||
return ad_http_is_keepalive_request(conn) ? AD_DONE : AD_CLOSE;
|
||||
}
|
||||
}
|
||||
return AD_OK;
|
||||
}
|
||||
|
||||
int http_default_handler(short event, ad_conn_t *conn, void *userdata) {
|
||||
if (event & AD_EVENT_READ) {
|
||||
if (ad_http_get_status(conn) == AD_HTTP_REQ_DONE) {
|
||||
ad_http_response(conn, 501, "text/html", "Not implemented", 15);
|
||||
return AD_CLOSE; // Close connection.
|
||||
}
|
||||
}
|
||||
return AD_OK;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// This function will be called by civetweb on every new request.
|
||||
static int begin_request_handler(struct mg_connection *conn)
|
||||
{
|
||||
const struct mg_request_info *request_info = mg_get_request_info(conn);
|
||||
char content[100];
|
||||
|
||||
// Prepare the message we're going to send
|
||||
int content_length = snprintf(content, sizeof(content),
|
||||
"Hello from civetweb! Remote port: %d",
|
||||
request_info->remote_port);
|
||||
|
||||
// Send HTTP reply to the client
|
||||
mg_printf(conn,
|
||||
"HTTP/1.1 200 OK\r\n"
|
||||
"Content-Type: text/plain\r\n"
|
||||
"Content-Length: %d\r\n" // Always set Content-Length
|
||||
"\r\n"
|
||||
"%s",
|
||||
content_length, content);
|
||||
|
||||
// Returning non-zero tells civetweb that our function has replied to
|
||||
// the client, and civetweb should not send client any more data.
|
||||
return 1;
|
||||
}
|
||||
|
||||
int http_server_start() {
|
||||
//SSL_load_error_strings();
|
||||
//SSL_library_init();
|
||||
ad_log_level(AD_LOG_DEBUG);
|
||||
ad_server_t *server = ad_server_new();
|
||||
ad_server_set_option(server, "server.port", "8888");
|
||||
//ad_server_set_ssl_ctx(server,
|
||||
// ad_server_ssl_ctx_create_simple("ssl.cert", "ssl.pkey"));
|
||||
ad_server_register_hook(server, ad_http_handler, NULL); // HTTP Parser is also a hook.
|
||||
ad_server_register_hook_on_method(server, "GET", ts_http_respond, NULL);
|
||||
ad_server_register_hook(server, http_default_handler, NULL);
|
||||
return ad_server_start(server);
|
||||
struct mg_context *ctx;
|
||||
struct mg_callbacks callbacks;
|
||||
|
||||
// List of options. Last element must be NULL.
|
||||
const char *options[] = {"listening_ports", "8080", NULL};
|
||||
|
||||
// Prepare callbacks structure. We have only one callback, the rest are NULL.
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.begin_request = begin_request_handler;
|
||||
|
||||
// Start the web server.
|
||||
ctx = mg_start(&callbacks, NULL, options);
|
||||
|
||||
// Wait until user hits "enter". Server is running in separate thread.
|
||||
// Navigating to http://localhost:8080 will invoke begin_request_handler().
|
||||
getchar();
|
||||
|
||||
// Stop the server.
|
||||
mg_stop(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configuration file-related function definitions.
|
||||
*/
|
||||
|
||||
static ASN1_OBJECT *txt2obj(const char *oid)
|
||||
{
|
||||
ASN1_OBJECT *oid_obj = NULL;
|
||||
|
||||
if ((oid_obj = OBJ_txt2obj(oid, 0)) == NULL)
|
||||
// BIO_printf(bio_err, "cannot convert %s to OID\n", oid);
|
||||
|
||||
return oid_obj;
|
||||
}
|
||||
|
||||
//static CONF *load_config_file(const char *configfile)
|
||||
//{
|
||||
// CONF *conf = app_load_config(configfile);
|
||||
//
|
||||
// if (conf != NULL) {
|
||||
// const char *p;
|
||||
//
|
||||
//// BIO_printf(bio_err, "Using configuration from %s\n", configfile);
|
||||
// p = NCONF_get_string(conf, NULL, ENV_OID_FILE);
|
||||
// if (p != NULL) {
|
||||
// BIO *oid_bio = BIO_new_file(p, "r");
|
||||
// if (!oid_bio)
|
||||
// ERR_print_errors(bio_err);
|
||||
// else {
|
||||
// OBJ_create_objects(oid_bio);
|
||||
// BIO_free_all(oid_bio);
|
||||
// }
|
||||
// } else
|
||||
// ERR_clear_error();
|
||||
// if (!add_oid_section(conf))
|
||||
// ERR_print_errors(bio_err);
|
||||
// }
|
||||
// return conf;
|
||||
//}
|
||||
|
||||
/*
|
||||
* Reply-related method definitions.
|
||||
*/
|
||||
|
||||
static int reply_command(CONF *conf, char *section, char *engine,
|
||||
char *queryfile, char *passin, char *inkey,
|
||||
const EVP_MD *md, char *signer, char *chain,
|
||||
const char *policy, char *in, int token_in,
|
||||
char *out, int token_out, int text)
|
||||
{
|
||||
int ret = 0;
|
||||
TS_RESP *response = NULL;
|
||||
BIO *in_bio = NULL;
|
||||
BIO *query_bio = NULL;
|
||||
BIO *inkey_bio = NULL;
|
||||
BIO *signer_bio = NULL;
|
||||
BIO *out_bio = NULL;
|
||||
BIO *bio_err;
|
||||
|
||||
if (in != NULL) {
|
||||
if ((in_bio = BIO_new_file(in, "rb")) == NULL)
|
||||
goto end;
|
||||
if (token_in) {
|
||||
response = read_PKCS7(in_bio);
|
||||
} else {
|
||||
response = d2i_TS_RESP_bio(in_bio, NULL);
|
||||
}
|
||||
} else {
|
||||
response = create_response(conf, section, engine, queryfile,
|
||||
passin, inkey, md, signer, chain, policy);
|
||||
// if (response)
|
||||
// BIO_printf(bio_err, "Response has been generated.\n");
|
||||
// else
|
||||
// BIO_printf(bio_err, "Response is not generated.\n");
|
||||
}
|
||||
if (response == NULL)
|
||||
goto end;
|
||||
|
||||
/* Write response. */
|
||||
if (text) {
|
||||
// if ((out_bio = bio_open_default(out, 'w', FORMAT_TEXT)) == NULL)
|
||||
// goto end;
|
||||
if (token_out) {
|
||||
TS_TST_INFO *tst_info = TS_RESP_get_tst_info(response);
|
||||
if (!TS_TST_INFO_print_bio(out_bio, tst_info))
|
||||
goto end;
|
||||
} else {
|
||||
if (!TS_RESP_print_bio(out_bio, response))
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
// if ((out_bio = bio_open_default(out, 'w', FORMAT_ASN1)) == NULL)
|
||||
// goto end;
|
||||
if (token_out) {
|
||||
PKCS7 *token = TS_RESP_get_token(response);
|
||||
if (!i2d_PKCS7_bio(out_bio, token))
|
||||
goto end;
|
||||
} else {
|
||||
if (!i2d_TS_RESP_bio(out_bio, response))
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
ERR_print_errors(bio_err);
|
||||
BIO_free_all(in_bio);
|
||||
BIO_free_all(query_bio);
|
||||
BIO_free_all(inkey_bio);
|
||||
BIO_free_all(signer_bio);
|
||||
BIO_free_all(out_bio);
|
||||
TS_RESP_free(response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Reads a PKCS7 token and adds default 'granted' status info to it. */
|
||||
static TS_RESP *read_PKCS7(BIO *in_bio)
|
||||
{
|
||||
int ret = 0;
|
||||
PKCS7 *token = NULL;
|
||||
TS_TST_INFO *tst_info = NULL;
|
||||
TS_RESP *resp = NULL;
|
||||
TS_STATUS_INFO *si = NULL;
|
||||
|
||||
if ((token = d2i_PKCS7_bio(in_bio, NULL)) == NULL)
|
||||
goto end;
|
||||
if ((tst_info = PKCS7_to_TS_TST_INFO(token)) == NULL)
|
||||
goto end;
|
||||
if ((resp = TS_RESP_new()) == NULL)
|
||||
goto end;
|
||||
if ((si = TS_STATUS_INFO_new()) == NULL)
|
||||
goto end;
|
||||
// if (!TS_STATUS_INFO_set_status(si, TS_STATUS_GRANTED))
|
||||
// goto end;
|
||||
if (!TS_RESP_set_status_info(resp, si))
|
||||
goto end;
|
||||
TS_RESP_set_tst_info(resp, token, tst_info);
|
||||
token = NULL; /* Ownership is lost. */
|
||||
tst_info = NULL; /* Ownership is lost. */
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
PKCS7_free(token);
|
||||
TS_TST_INFO_free(tst_info);
|
||||
if (!ret) {
|
||||
TS_RESP_free(resp);
|
||||
resp = NULL;
|
||||
}
|
||||
TS_STATUS_INFO_free(si);
|
||||
return resp;
|
||||
}
|
||||
|
||||
static TS_RESP *create_response(CONF *conf, const char *section, char *engine,
|
||||
char *queryfile, char *passin,
|
||||
char *inkey, const EVP_MD *md, char *signer,
|
||||
char *chain, const char *policy)
|
||||
{
|
||||
int ret = 0;
|
||||
TS_RESP *response = NULL;
|
||||
BIO *query_bio = NULL;
|
||||
TS_RESP_CTX *resp_ctx = NULL;
|
||||
|
||||
if ((query_bio = BIO_new_file(queryfile, "rb")) == NULL)
|
||||
goto end;
|
||||
if ((section = TS_CONF_get_tsa_section(conf, section)) == NULL)
|
||||
goto end;
|
||||
if ((resp_ctx = TS_RESP_CTX_new()) == NULL)
|
||||
goto end;
|
||||
if (!TS_CONF_set_serial(conf, section, serial_cb, resp_ctx))
|
||||
goto end;
|
||||
# ifndef OPENSSL_NO_ENGINE
|
||||
if (!TS_CONF_set_crypto_device(conf, section, engine))
|
||||
goto end;
|
||||
# endif
|
||||
if (!TS_CONF_set_signer_cert(conf, section, signer, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_certs(conf, section, chain, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_signer_key(conf, section, inkey, passin, resp_ctx))
|
||||
goto end;
|
||||
|
||||
// if (md) {
|
||||
// if (!TS_RESP_CTX_set_signer_digest(resp_ctx, md))
|
||||
// goto end;
|
||||
// } else if (!TS_CONF_set_signer_digest(conf, section, NULL, resp_ctx)) {
|
||||
// goto end;
|
||||
// }
|
||||
|
||||
if (!TS_CONF_set_def_policy(conf, section, policy, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_policies(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_digests(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_accuracy(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_clock_precision_digits(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_ordering(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_tsa_name(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if (!TS_CONF_set_ess_cert_id_chain(conf, section, resp_ctx))
|
||||
goto end;
|
||||
if ((response = TS_RESP_create_response(resp_ctx, query_bio)) == NULL)
|
||||
goto end;
|
||||
ret = 1;
|
||||
|
||||
end:
|
||||
if (!ret) {
|
||||
TS_RESP_free(response);
|
||||
response = NULL;
|
||||
}
|
||||
TS_RESP_CTX_free(resp_ctx);
|
||||
BIO_free_all(query_bio);
|
||||
return response;
|
||||
}
|
||||
|
||||
static ASN1_INTEGER *serial_cb(TS_RESP_CTX *ctx, void *data)
|
||||
{
|
||||
const char *serial_file = (const char *)data;
|
||||
ASN1_INTEGER *serial = next_serial(serial_file);
|
||||
|
||||
if (!serial) {
|
||||
TS_RESP_CTX_set_status_info(ctx, TS_STATUS_REJECTION,
|
||||
"Error during serial number "
|
||||
"generation.");
|
||||
TS_RESP_CTX_add_failure_info(ctx, TS_INFO_ADD_INFO_NOT_AVAILABLE);
|
||||
} else
|
||||
save_ts_serial(serial_file, serial);
|
||||
|
||||
return serial;
|
||||
}
|
||||
|
||||
static ASN1_INTEGER *next_serial(const char *serialfile)
|
||||
{
|
||||
int ret = 0;
|
||||
BIO *in = NULL;
|
||||
ASN1_INTEGER *serial = NULL;
|
||||
BIGNUM *bn = NULL;
|
||||
|
||||
if ((serial = ASN1_INTEGER_new()) == NULL)
|
||||
goto err;
|
||||
|
||||
if ((in = BIO_new_file(serialfile, "r")) == NULL) {
|
||||
ERR_clear_error();
|
||||
// BIO_printf(bio_err, "Warning: could not open file %s for "
|
||||
// "reading, using serial number: 1\n", serialfile);
|
||||
if (!ASN1_INTEGER_set(serial, 1))
|
||||
goto err;
|
||||
} else {
|
||||
char buf[1024];
|
||||
if (!a2i_ASN1_INTEGER(in, serial, buf, sizeof(buf))) {
|
||||
// BIO_printf(bio_err, "unable to load number from %s\n",
|
||||
// serialfile);
|
||||
goto err;
|
||||
}
|
||||
if ((bn = ASN1_INTEGER_to_BN(serial, NULL)) == NULL)
|
||||
goto err;
|
||||
ASN1_INTEGER_free(serial);
|
||||
serial = NULL;
|
||||
if (!BN_add_word(bn, 1))
|
||||
goto err;
|
||||
if ((serial = BN_to_ASN1_INTEGER(bn, NULL)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
ret = 1;
|
||||
|
||||
err:
|
||||
if (!ret) {
|
||||
ASN1_INTEGER_free(serial);
|
||||
serial = NULL;
|
||||
}
|
||||
BIO_free_all(in);
|
||||
BN_free(bn);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static int save_ts_serial(const char *serialfile, ASN1_INTEGER *serial)
|
||||
{
|
||||
int ret = 0;
|
||||
BIO *out = NULL;
|
||||
|
||||
if ((out = BIO_new_file(serialfile, "w")) == NULL)
|
||||
goto err;
|
||||
if (i2a_ASN1_INTEGER(out, serial) <= 0)
|
||||
goto err;
|
||||
if (BIO_puts(out, "\n") <= 0)
|
||||
goto err;
|
||||
ret = 1;
|
||||
err:
|
||||
if (!ret)
|
||||
// BIO_printf(bio_err, "could not save serial number to %s\n",
|
||||
// serialfile);
|
||||
BIO_free_all(out);
|
||||
return ret;
|
||||
}
|
||||
|
1
vendor/civetweb
vendored
Submodule
1
vendor/civetweb
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 016535194f6dba8e534b6eec6b9d433e6fb0a9b2
|
0
vendor/libasyncd/.keep
vendored
0
vendor/libasyncd/.keep
vendored
0
vendor/qlibc/.keep
vendored
0
vendor/qlibc/.keep
vendored
Loading…
x
Reference in New Issue
Block a user