TLS for servers

In this section, we give a very short and quick description on how to enable SSL/TLS for a server (listening) connection - for example, HTTPS server.

  • Obtain SSL certificate file and private key file

  • In the event handler function, call mg_tls_init() on MG_EV_ACCEPT event:

    static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
      if (ev == MG_EV_ACCEPT) {
        struct mg_tls_opts opts = {
          .cert = "cert.pem",    // Certificate file
          .certkey = "key.pem",  // Private key file
        };
        mg_tls_init(c, &opts);
      }
      ...
    }
    
  • Rebuild your application with -DMG_ENABLE_MBEDTLS=1 or -DMG_ENABLE_OPENSSL=1, depending on what TLS library you use

Example build on Mac/Linux using mbedTLS:

$ cc main.c mongoose.c -DMG_ENABLE_MBEDTLS=1 -I$(MBEDTLS_DIR)/include -lmbedtls -lmbedcrypto -lmbedx509

Example build on Mac/Linux using OpenSSL:

$ cc main.c mongoose.c -DMG_ENABLE_OPENSSL=1 -I$(OPENSSL_DIR)/include -lssl -lcrypto

TLS for clients

In order to TLS-enable client connections,

  • Obtain SSL CA (Certificate Authority) file

  • In the event handler function, call mg_tls_init() on MG_EV_CONNECT event:

  • Rebuild your application with -DMG_ENABLE_MBEDTLS=1 or -DMG_ENABLE_OPENSSL=1, depending on what TLS library you use. See previous section for build examples

Certificates overview

TLS provides two major benefits:

  • traffic encryption, which makes it impossible to sniff and look inside the traffic, and
  • authentication, which makes it possible to one side of TLS connection verify the identity of the other side.

Here we're talking about the authentication. Authentication is implemented via certificates. A certificate has two parts - public and private. Talking in practical terms, three files are required to implement TLS authentication:

  • TLS certificate. This is a "public" part. For example, TLS-enabled server sends it to the client during TLS handshake
  • TLS private key. This is a "private" part
  • TLS Certificate Authority (CA) file. It is used for verification of the "public" certificate sent by a server

TLS certificates are obtained from services like Let's Encrypt. The other possibility is self-signed certificates, which are mainly used for development.

Self-signed certificates

It is possible to generate certificate files. Note that servers using those files will not be trusted by the browsers, because browsers use a pre-installed CA files and know nothing about your generated certificates.

A command below uses openssl command line tool to generate a self-signed server certificate and a key file:

$ openssl req  -nodes -new -x509  -keyout key.pem -out cert.pem

Two way TLS

Normally, when a client makes a connection to a TLS-enabled server, a server sends its certificate to the client and client verifies it using its own CA (Certificate Authority) file. This way a client authenticates a server.

In the most common situation, a client verifies a server, but a server does not verify a client. For example, browsers (clients) use a big CA file (or many CA files) to verify HTTPS servers.

Clients can also provide certificates during TLS handshake, and a server can verify it using a CA file. When both client and server use certificates, and verify the other side using CA file, is called two-way TLS. In order to implement two-way TLS, both client and server must have cert, certkey and ca specified in the mg_tls_opts:

static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  if (ev == MG_EV_CONNECT) {
    struct mg_str host = mg_url_host(s_url);
    if (mg_url_is_ssl(s_url)) {
      struct mg_tls_opts opts = {
        .ca = "ca.pem",         // CA file
        .cert = "cert.pem",     // Certificate file
        .certkey = "key.pem",   // Private key file
        .srvname = host,        // Only for client connections
      };
      mg_tls_init(c, &opts);
    }

Self-signed certificates

It is possible to generate ca.pem, and cert + key pairs for for both client and server for two-way (mutual) authentication. There how it is done using openssl command line tool:

# Common parameters
$ SUBJ="/C=IE/ST=Dublin/L=Docks/O=MyCompany/CN=howdy"

# Generate CA
$ openssl genrsa -out ca.key 2048
$ openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
  -subj /C=IE/ST=Dublin/L=Docks/O=mos/CN=me 

# Generate client cert
$ openssl genrsa -out client.key 2048
$ openssl req -new -key client.key -out client.csr -subj $SUBJ
$ openssl x509 -req -days 365 -in client.csr -CA ca.crt \
  -CAkey ca.key -set_serial 01 -out client.crt

# Generate server cert
$ openssl genrsa -out server.key 2048
$ openssl req -new -key server.key -out server.csr -subj $SUBJ
$ openssl x509 -req -days 365 -in server.csr -CA ca.crt \
  -CAkey ca.key -set_serial 01 -out server.crt