Skip to content
Permalink
Browse files

Add optional config ssl_certificate_file (#1291)

* added ssl_certificate_file config option

* Only try to load files from alternate file if not already loaded, only log errors if not found in either

* Updated README.SSL.md, help changes, and mushcnf.dst
  • Loading branch information...
grapenut authored and shawnw committed Mar 22, 2019
1 parent bd76a5e commit 73277663b82ad1e8f722c71cae52caf2ded99d4d
Showing with 94 additions and 27 deletions.
  1. +37 −16 README.SSL.md
  2. +9 −0 game/mushcnf.dst
  3. +1 −0 game/txt/hlp/pennv188.hlp
  4. +3 −1 hdrs/conf.h
  5. +1 −1 hdrs/myssl.h
  6. +1 −0 hdrs/ssl_slave.h
  7. +3 −0 src/conf.c
  8. +1 −1 src/game.c
  9. +36 −7 src/myssl.c
  10. +1 −0 src/ssl_master.c
  11. +1 −1 src/ssl_slave.c
@@ -1,6 +1,6 @@
% Use SSL with PennMUSH
%
% Revised: 04 Jan 2018
% Revised: 20 Mar 2019

Introduction
============
@@ -18,8 +18,8 @@ The following features are supported:
* Use of digest routines in the crytpo library for encrypting
passwords and the digest() function.

An SSL overview
===============
I. An SSL overview
==================

When an SSL client connects to an SSL server, it performs a
"handshake" that looks something like this:
@@ -44,8 +44,8 @@ its list of trusted CAs, and may perform other verification.
Once session keys have been exchanged, the client and server can
communicate secure from eavesdropping.

Compiling with OpenSSL
======================
II. Compiling with OpenSSL
==========================

What to install
---------------
@@ -88,8 +88,8 @@ as they did before, with the only change being that they won't get
booted on a `@shutdown/reboot`. It's transparent to the player and the
game.

MUSH configuration overview
===========================
III. MUSH configuration overview
================================

mush.cnf includes a number of directives that control SSL configuration:

@@ -112,7 +112,13 @@ mush.cnf includes a number of directives that control SSL configuration:

: Specifies the name of the file (relative to the
game/ directory if it's not an absolute path) that contains the MUSH
server's certificate and private key. See section IV below.
server's private key. See section IV below.

`ssl_certificate_file`

: Specifies the name of the file (relative to the
game/ directory if it's not an absolute path) that contains the MUSH
server's certificate. See section IV below.

`ssl_ca_file`

@@ -136,24 +142,31 @@ mush.cnf includes a number of directives that control SSL configuration:
the MUSH server will require clients to present valid (that is,
signed by a CA for which ssl_ca_file holds a certificate)
certificates in order to connect. As no mud clients currently do
this, you probably want it off. See section V below.
this, you probably want it off. See section IV below.

`socket_file`

: The path to a file to use as a unix domain socket
used for talking to the optional SSL connection proxy.

Installing a server certificate
===============================
IV. Installing a server certificate
===================================

SSL support requires that the MUSH present a server certificate
(except as discussed below). You must create a file containing the
certificate and the associated private key (stripped of any passphrase
protection) and point the `ssl_private_key_file` directive at this
file. This file should only be readable by the MUSH account!
certificate and point the `ssl_certificate_file` directive at this file.
Then create another file with the associated private key (stripped of
any passphrase protection) and point the `ssl_private_key_file`
directive at this file. For backwards compatibility, you may concatenate
the certificate and private key into the same file and reference the
single combined file with either directive.

How do you get such a certificate and private key? Here are the steps
you can use with openssl's command-line tool:
**These files should only be readable by the MUSH user account!**

How do you get such a certificate and private key?
--------------------------------------------------

**Here are the steps you can use with OpenSSL's command-line tool:**

1. Generate a certificate signing request (mymush.csr) and a private
key (temp.key). You will be asked to answer several questions.
@@ -190,6 +203,14 @@ unless the user manually installs the certificate in their client and
configures it to be trusted. How to do that is beyond the scope of
this document, and highly client-dependent.

**OR use `certbot` to obtain free signed certificates from Let's Encrypt:**

Let's Encrypt is a certificate authority that provides short-term signed
certificates for free. The `certbot` command-line utility automates the
process of obtaining new certificates and renewing expired certificates.
See <https://certbot.eff.org> for instructions on running `certbot` and
find their FAQ at <https://certbot.eff.org/faq/>.

Another option is to skip the use of a certificate altogether. If you
don't provide an `ssl_private_key_file`, the server will only accept
connections from clients that are willing to use the anonymous
@@ -230,8 +230,17 @@ ssl_ip_addr
# owner. If this is commented out, the server will not present a
# certificate, so clients that attempt to authenticate the server
# will fail.
# You may also load the certificate and private key individually
# from separate files by using the ssl_certificate_file option below.
ssl_private_key_file server-key.crt

# The file containing the MUSH server's certificate. For backwards
# compatibility you may concatenate the certificate and key files
# together and place them in ssl_private_key_file, OR you may keep
# them as separate files and load the private key from
# ssl_private_key_file and the certficate from ssl_certficate_file.
ssl_certificate_file server-cert.crt

# A file containing one or more certificates of certifying authorities
# that the server should trust to certify clients who connect and
# present certificates.
@@ -44,6 +44,7 @@ Minor Changes:
* Add ‘–disable-socket-quota’ option for our test suite. [GM]
* The list of color definitions used with ansi(), colors(), etc. is now kept in game/txt/colors.json. [SW]
* Sqlite3 updated to 3.25.1. Biggest user-visible change is support for window functions. [SW]
* Added configuration option 'ssl_certificate_file' allowing SSL certificates and private keys to be split into separate files. [grapenut, 1291]

Softcode:

@@ -340,7 +340,9 @@ struct options_table {
int chunk_migrate_amount; /**< Number of attrs to migrate each second */
char attr_compression[256]; /**< How to compress attribute text in-memory */
int read_remote_desc; /**< Can players read DESCRIBE attribute remotely? */
char ssl_private_key_file[FILE_PATH_LEN]; /**< File to load the server's cert
char ssl_private_key_file[FILE_PATH_LEN]; /**< File to load the server's key
from */
char ssl_certificate_file[FILE_PATH_LEN]; /**< File to load the server's cert
from */
char ssl_ca_file[FILE_PATH_LEN]; /**< File to load the CA certs from */
char ssl_ca_dir[FILE_PATH_LEN]; /**< Directory to load the CA certs from */
@@ -11,7 +11,7 @@

#include <openssl/ssl.h>

SSL_CTX *ssl_init(char *private_key_file, char *ca_file, char *ca_dir,
SSL_CTX *ssl_init(char *private_key_file, char *certificate_file, char *ca_file, char *ca_dir,
int req_client_cert);
SSL *ssl_setup_socket(int sock);
void ssl_close_connection(SSL *ssl);
@@ -19,6 +19,7 @@ struct ssl_slave_config {
int ssl_port;
int websock_port;
char private_key_file[FILE_PATH_LEN];
char certificate_file[FILE_PATH_LEN];
char ca_file[FILE_PATH_LEN];
char ca_dir[FILE_PATH_LEN];
int require_client_cert;
@@ -322,6 +322,8 @@ PENNCONF conftable[] = {
#ifdef HAVE_SSL
{"ssl_private_key_file", cf_str, options.ssl_private_key_file,
sizeof options.ssl_private_key_file, 0, "files"},
{"ssl_certificate_file", cf_str, options.ssl_certificate_file,
sizeof options.ssl_certificate_file, 0, "files"},
{"ssl_ca_file", cf_str, options.ssl_ca_file, sizeof options.ssl_ca_file, 0,
"files"},
{"ssl_ca_dir", cf_str, options.ssl_ca_dir, sizeof options.ssl_ca_dir, 0,
@@ -1332,6 +1334,7 @@ conf_default_set(void)
options.read_remote_desc = 0;
#ifdef HAVE_SSL
strcpy(options.ssl_private_key_file, "");
strcpy(options.ssl_certificate_file, "");
strcpy(options.ssl_ca_file, "");
strcpy(options.ssl_ca_dir, "");
options.ssl_require_client_cert = 0;
@@ -808,7 +808,7 @@ init_game_postdb(const char *conf)

/* Set up ssl */
#ifndef SSL_SLAVE
if (!ssl_init(options.ssl_private_key_file, options.ssl_ca_file,
if (!ssl_init(options.ssl_private_key_file, options.ssl_certificate_file, options.ssl_ca_file,
options.ssl_ca_dir, options.ssl_require_client_cert)) {
do_rawlog(LT_ERR, "SSL initialization failure");
options.ssl_port = 0; /* Disable ssl */
@@ -192,7 +192,7 @@ generate_seed(uint64_t seeds[])
* \return pointer to SSL context object.
*/
SSL_CTX *
ssl_init(char *private_key_file, char *ca_file, char *ca_dir,
ssl_init(char *private_key_file, char *certificate_file, char *ca_file, char *ca_dir,
int req_client_cert)
{
const SSL_METHOD
@@ -203,6 +203,9 @@ ssl_init(char *private_key_file, char *ca_file, char *ca_dir,
pcg32_random_t rand_state;
uint64_t seeds[2];
bool seeded = false;

bool foundKey = false;
bool foundCert = false;

if (!bio_err) {
if (!SSL_library_init())
@@ -254,16 +257,42 @@ ssl_init(char *private_key_file, char *ca_file, char *ca_dir,

/* Load keys/certs */
if (private_key_file && *private_key_file) {
if (!SSL_CTX_use_certificate_chain_file(ctx, private_key_file)) {
ssl_errordump("Unable to load server certificate - only anonymous "
"ciphers supported.");
if (SSL_CTX_use_certificate_chain_file(ctx, private_key_file)) {
foundCert = true;
}
if (!SSL_CTX_use_PrivateKey_file(ctx, private_key_file, SSL_FILETYPE_PEM)) {
ssl_errordump(
"Unable to load private key - only anonymous ciphers supported.");
if (SSL_CTX_use_PrivateKey_file(ctx, private_key_file, SSL_FILETYPE_PEM)) {
foundKey = true;
}
}

/* Load keys/certs from alternative file */
/* Should really load the key from one file and the cert from another */
/* but since the older behavior is to load them from the same file we */
/* will try to load both from both files to avoid user confusion */
if (certificate_file && *certificate_file) {
if (!foundCert) {
if (SSL_CTX_use_certificate_chain_file(ctx, certificate_file)) {
foundCert = true;
}
}

if (!foundKey) {
if (SSL_CTX_use_PrivateKey_file(ctx, certificate_file, SSL_FILETYPE_PEM)) {
foundKey = true;
}
}
}

/* Add a log entry if we didn't find a certificate or key in either file */
if (!foundCert) {
ssl_errordump("Unable to load server certificate - only anonymous "
"ciphers supported.");
}

if (!foundKey) {
ssl_errordump("Unable to load private key - only anonymous ciphers supported.");
}

/* Load trusted CAs */
if ((ca_file && *ca_file) || (ca_dir && *ca_dir)) {
if (!SSL_CTX_load_verify_locations(ctx,
@@ -150,6 +150,7 @@ make_ssl_slave(void)
cf.normal_port = options.port;
cf.ssl_port = options.ssl_port;
strcpy(cf.private_key_file, options.ssl_private_key_file);
strcpy(cf.certificate_file, options.ssl_certificate_file);
strcpy(cf.ca_file, options.ssl_ca_file);
strcpy(cf.ca_dir, options.ssl_ca_dir);
cf.require_client_cert = options.ssl_require_client_cert;
@@ -569,7 +569,7 @@ main(int argc __attribute__((__unused__)),
}
#endif

if (!ssl_init(cf.private_key_file, cf.ca_file, cf.ca_dir,
if (!ssl_init(cf.private_key_file, cf.certificate_file, cf.ca_file, cf.ca_dir,
cf.require_client_cert)) {
errputs(stderr, "SSL initialization failure!");
exit(EXIT_FAILURE);

0 comments on commit 7327766

Please sign in to comment.
You can’t perform that action at this time.