SSL/TLS connection

OpenBSD's netcat supports SSL/TLS connection, and uses libtls shipped by libressl under the hood. The -c option is used to denote using SSL/TLS:

int    usetls;                    /* use TLS */
case 'c':
        usetls = 1;

There is a simple example which demonstrates how to leverage netcat as an https client:

# nc -c https
GET / HTTP/1.1
Connection: close

HTTP/1.1 200 OK
Date: Fri, 21 Sep 2018 08:19:19 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html; charset=ISO-8859-1
P3P: CP="This is not a P3P policy! See for more info."
Server: gws
X-XSS-Protection: 1; mode=block
X-Frame-Options: SAMEORIGIN

The following is a sketch of how to use libtls to implement server and client:

(1) Initialization:
No matter netcat works as serve or client, the following code is common:

if (usetls) {
    if ((tls_cfg = tls_config_new()) == NULL)
        errx(1, "unable to allocate TLS config");
    if (Rflag && tls_config_set_ca_file(tls_cfg, Rflag) == -1)
        errx(1, "%s", tls_config_error(tls_cfg));
    if (Cflag && tls_config_set_cert_file(tls_cfg, Cflag) == -1)
        errx(1, "%s", tls_config_error(tls_cfg));
    if (Kflag && tls_config_set_key_file(tls_cfg, Kflag) == -1)
        errx(1, "%s", tls_config_error(tls_cfg));
    if (oflag && tls_config_set_ocsp_staple_file(tls_cfg, oflag) == -1)
        errx(1, "%s", tls_config_error(tls_cfg));
    if (tls_config_parse_protocols(&protocols, tls_protocols) == -1)
        errx(1, "invalid TLS protocols `%s'", tls_protocols);

tls_config_new() returns a new default configuration object. For other options and settings, I won't elaborate them here.

Then, as SSL/TLS server, tls_server() should be called and return a context object:

if ((tls_ctx = tls_server()) == NULL)
    errx(1, "tls server creation failed");

Similarly, client invokes tls_client():

if ((tls_ctx = tls_client()) == NULL)
    errx(1, "tls client creation failed");

Both server and client should associate configuration and context objects:

if (tls_configure(tls_ctx, tls_cfg) == -1)
    errx(1, "tls configuration failed (%s)",

(2) Next step is associating exist socket with SSL/TLS context object:
a) Server uses tls_accept_socket():

if (tls_accept_socket(tls_ctx, &tls_cctx, connfd) == -1) {
    warnx("tls accept failed (%s)", tls_error(tls_ctx));

b) Client uses tls_connect_socket():

if (tls_connect_socket(tls_ctx, s,
    tls_expectname ? tls_expectname : host) == -1) {
    errx(1, "tls connection failed (%s)",

(3) Read & Write:
After SSL/TLS connection is established, you can use tls_read() and tls_write to receive and send data. Different with read() and write() system calls, tls_read() and tls_write will process 2 more return values: TLS_WANT_POLLIN and TLS_WANT_POLLOUT. E.g.:

ret = fillbuf(pfd[POLL_STDIN].fd, stdinbuf,
            &stdinbufpos, NULL);
if (ret == TLS_WANT_POLLIN)
    pfd[POLL_STDIN].events = POLLIN;
else if (ret == TLS_WANT_POLLOUT)
    pfd[POLL_STDIN].events = POLLOUT;

results matching ""

    No results matching ""