]> git.sesse.net Git - cubemap/blobdiff - config.cpp
Add server-side TLS support, through kTLS.
[cubemap] / config.cpp
index 2e680b818c111ca02490688cc3ac1bcb34365204..47118b48612e18bce0966c7bb696326532cf277e 100644 (file)
@@ -12,6 +12,8 @@
 #include <utility>
 #include <vector>
 
+#include "tlse.h"
+
 #include "acceptor.h"
 #include "config.h"
 #include "log.h"
@@ -174,6 +176,104 @@ bool fetch_config_int(const vector<ConfigLine> &config, const string &keyword, i
        return false;
 }
 
+bool load_file_to_string(const string &filename, size_t max_size, string *contents)
+{
+       contents->clear();
+
+       FILE *fp = fopen(filename.c_str(), "r");
+       if (fp == NULL) {
+               log_perror(filename.c_str());
+               return false;
+       }
+
+       char buf[4096];
+       while (!feof(fp)) {
+               size_t ret = fread(buf, 1, sizeof(buf), fp);
+               if (ret > 0) {
+                       contents->append(buf, buf + ret);
+               } else {
+                       if (ferror(fp)) {
+                               log_perror(filename.c_str());
+                               fclose(fp);
+                               return false;
+                       }
+                       assert(feof(fp));
+                       break;
+               }
+
+               if (contents->size() > max_size) {
+                       log(ERROR, "%s was longer than the maximum allowed %zu bytes", filename.c_str(), max_size);
+                       fclose(fp);
+                       return false;
+               }
+       }
+       fclose(fp);
+       return true;
+}
+
+bool parse_tls_parameters(const map<string, string> &parameters, AcceptorConfig *acceptor)
+{
+       bool has_cert = false, has_key = false;
+
+       map<string, string>::const_iterator tls_cert_it = parameters.find("tls_cert");
+       if (tls_cert_it != parameters.end()) {
+               if (!load_file_to_string(tls_cert_it->second, 1048576, &acceptor->certificate_chain)) {
+                       return false;
+               }
+
+               // Verify that the certificate is valid.
+               bool is_server = true;
+               TLSContext *server_context = tls_create_context(is_server, TLS_V12);
+               int num_cert = tls_load_certificates(
+                       server_context,
+                       reinterpret_cast<const unsigned char *>(acceptor->certificate_chain.data()),
+                       acceptor->certificate_chain.size());
+               if (num_cert < 0) {
+                       log_tls_error(tls_cert_it->second.c_str(), num_cert);
+                       tls_destroy_context(server_context);
+                       return false;
+               } else if (num_cert == 0) {
+                       log(ERROR, "%s did not contain any certificates", tls_cert_it->second.c_str());
+                       return false;
+               }
+               tls_destroy_context(server_context);
+               has_cert = true;
+       }
+
+       map<string, string>::const_iterator tls_key_it = parameters.find("tls_key");
+       if (tls_key_it != parameters.end()) {
+               if (!load_file_to_string(tls_key_it->second, 1048576, &acceptor->private_key)) {
+                       return false;
+               }
+
+               // Verify that the key is valid.
+               bool is_server = true;
+               TLSContext *server_context = tls_create_context(is_server, TLS_V12);
+               int num_keys = tls_load_private_key(
+                       server_context,
+                       reinterpret_cast<const unsigned char *>(acceptor->private_key.data()),
+                       acceptor->private_key.size());
+               if (num_keys < 0) {
+                       log_tls_error(tls_key_it->second.c_str(), num_keys);
+                       tls_destroy_context(server_context);
+                       return false;
+               } else if (num_keys == 0) {
+                       log(ERROR, "%s did not contain any private keys", tls_key_it->second.c_str());
+                       return false;
+               }
+               tls_destroy_context(server_context);
+               has_key = true;
+       }
+
+       if (has_cert != has_key) {
+               log(ERROR, "Only one of tls_cert= and tls_key= was given, needs zero or both");
+               return false;
+       }
+
+       return true;
+}
+
+
 bool parse_port(const ConfigLine &line, Config *config)
 {
        if (line.arguments.size() != 1) {
@@ -190,6 +290,9 @@ bool parse_port(const ConfigLine &line, Config *config)
        AcceptorConfig acceptor;
        acceptor.addr = create_any_address(port);
 
+       if (!parse_tls_parameters(line.parameters, &acceptor)) {
+               return false;
+       }
        config->acceptors.push_back(acceptor);
        return true;
 }
@@ -205,6 +308,9 @@ bool parse_listen(const ConfigLine &line, Config *config)
        if (!parse_hostport(line.arguments[0], &acceptor.addr)) {
                return false;
        }
+       if (!parse_tls_parameters(line.parameters, &acceptor)) {
+               return false;
+       }
        config->acceptors.push_back(acceptor);
        return true;
 }