ASSL(3)

NAME
assl - agglomerated SSL

SYNOPSIS
#include <assl.h>
void
assl_initialize(void);
void
assl_set_log_callback(void (*log_cb)(int severity, const char *message));
struct assl_context *
assl_alloc_context(enum assl_method method, int flags);
void
assl_set_cert_flags(int flags);
int
assl_load_file_certs(struct assl_context *ctx, const char *ca, const char *cert, const char *key);
void *
assl_load_file_certs_to_mem(const char *ca, const char *cert, const char *key);
int
assl_use_mem_certs(struct assl_context *c, void *token);
int
assl_connect(struct assl_context *ctx, const char *host, const char *port, int flags);
int
assl_event_connect(struct assl_context *ctx, const char *host, const char *port, int flags, struct event_base *ev_base , void, (*rd_cb)(int,, short,, void, *)", void (*wr_cb)(int, short, void *), void *cb_arg);
int
assl_serve(const char *host, const char *port, int flags, void (*callback)(int sock), void (*intr_cb)(void));
struct assl_serve_ctx *
assl_event_serve(const char *host, const char *port, int flags, struct event_base *ev_base, void (*cb_fn)(int, short, void *), void *cb_arg);
void
assl_event_serve_stop(struct assl_serve_ctx *ctx);
int
assl_accept(struct assl_context *ctx, int sock);
int
assl_event_accept(struct assl_context *ctx, struct event_base *ev_base, int s, void (*rd_cb)(int, short, void *), void (*wr_cb)(int, short, void *), void *cb_arg);
ssize_t
assl_read(struct assl_context *ctx, void *buf, size_t nbytes);
ssize_t
assl_write(struct assl_context *ctx, void *buf, size_t nbytes);
ssize_t
assl_gets(struct assl_context *ctx, char *buf, int size);
ssize_t
assl_puts(struct assl_context *ctx, char *buf, int send_nul);
int
assl_poll(struct assl_context *ctx, int mseconds, short event, short *revents);
void
assl_event_enable_write(struct assl_context *ctx);
void
assl_event_disable_write(struct assl_context *ctx);
int
assl_destroy_mem_certs(void *token);
int
assl_close(struct assl_context *ctx);
int
assl_event_close(struct assl_context *ctx);
void
assl_fatalx(const char *errstr);
void
assl_warnx(const char *errstr);

DESCRIPTION
assl_initialize() prepares the library for first use. This function must be called before any other function is called.

assl_set_log_callback() may be used to prevent functions such as assl_warnx() and assl_fatalx() from writing to stderr in a daemon by providing a logging callback. The callback will be called with the error message message and a severity of one of the following types:
ASSL_LOG_MSG
    Informational message.
ASSL_LOG_WARN
    Non fatal error.
ASSL_LOG_ERR
    Fatal error.

assl_alloc_context() allocates an assl context. A context contains all SSL/TLS connection specific details. The method parameter indicates what SSL/TLS type and version to use for the context. Possible method values are:
ASSL_M_SSLV2
    SSL V2 client or server connection.
ASSL_M_SSLV2_CLIENT
    SSL V2 client connection.
ASSL_M_SSLV2_SERVER
    SSL V2 server connection.
ASSL_M_SSLV3
    SSL V3 client or server connection.
ASSL_M_SSLV3_CLIENT
    SSL V3 client connection.
ASSL_M_SSLV3_SERVER
    SSL V3 server connection.
ASSL_M_TLSV1
    TLS V1 client or server connection.
ASSL_M_TLSV1_CLIENT
    TLS V1 client connection.
ASSL_M_TLSV1_SERVER
    TLS V1 server connection.
ASSL_M_ALL
    Any version of a client or server connection.
ASSL_M_ALL_CLIENT
    Any version of a client connection.
ASSL_M_ALL_SERVER
    Any version of a server connection.

If flags is set to ASSL_F_CHILD then assl_fatalx() will halt execution using _exit(2) instead of exit(3) per fork(2) requirement. This flag shall be set for all forked contexts.

If flags is set to ASSL_F_DONT_VERIFY then the library will not perform peer certificate verification. This is to accommodate clients that don't wish to use certificates. Using this flag will result in less secure code and should therefore be used with caution.

If flags is set to ASSL_F_DONT_ENCRYPT then the library will not encrypt network traffic. Combining ASSL_F_DONT_VERIFY with ASSL_F_DONT_ENCRYPT creates an anonymous connection just like libc would. The only difference being that the SSL handshake is always performed. This obviously defeats all encryption and authentication and should only be used on a "secure" network. The reason this support exists is to facilitate a single library to perform all network traffic.

The function will return NULL to indicate failure.

assl_set_cert_flags() sets global flags for certificate verification. If ASSL_GF_IGNORE_SELF_SIGNED is set than the library will ignore self signed certificates. If ASSL_GF_IGNORE_EXPIRED is set than the library will ignore expired certificates. This function should be only called once, right after assl_initialize. Note that due to OpenSSL limitations these flags can not be set per assl_context.

assl_load_file_certs() loads all required keys and certificates to authenticate a client or server. cert and key contain the certificate and key required to authenticate the calling machine to the remote machine. ca contains the Certificate Authority certificate. All files must be provided in PEM format. The cert is validated against the key. The function returns a non-zero value to indicate failure.

assl_load_file_certs_to_mem() preloads all required keys and certificates to authenticate a client or server to memory for use at a later time. This functionality is provided to enable programs that require privilege dropping. This function can be called multiple times to load additional certificates to memory. The function returns an opaque non NULL token to identify the certificates at a later time. cert and key contain the certificate and key required to authenticate the calling machine to the remote machine. ca contains the Certificate Authority certificate. All files must be provided in PEM format. The function returns a NULL value to indicate failure.

assl_use_mem_certs() assign in memory certificates identified by token to the provided context. Note that multiple contexts can use the same in memory certificates provided that assl_destroy_mem_certs isn't called.

assl_connect() tries to establish an SSL/TLS connection to a host and port. The function returns a non-zero value to indicate failure. More precisely, 1 for libc failures and -1 for openssl(1) failures. The caller is responsible for calling assl_close() to unwind the context. If flags is set to ASSL_F_NONBLOCK then the socket will be set up as non-blocking. If flags is set to ASSL_F_KEEPALIVE then the socket will enable keepalive packets on the connection.

The assl_event_connect() is like assl_connect(), however it sets up libevent read and write callback functions rd_cb and wr_cb on the libevent base ev_base. cb_arg will be passed the the callback function when it is invoked.

assl_serve() is a blocking function that sets up a listening socket that waits for incoming connections on host and port. Once an incoming connection is detected it will call callback with the appropriate socket. It is the responsibility of the callback function to either fork and set up a context. Both host and port can be NULL. In the host case the server will listen on all possible IP addresses and in the port case the server will listen on port 4433. The flags parameter is a bitwise field and can be set to:
ASSL_F_NONBLOCK
    Set the socket to non-block.
ASSL_F_KEEPALIVE
    Enable the periodic transmission of messages on a connect socket.
ASSL_F_LOWDELAY
    Enable the lowdelay type of service on the socket.
ASSL_F_THROUGHPUT
    Enable the throughput type of service on the socket.
ASSL_F_CLOSE_SOCKET
    Close the socket upon return from the callback. This is to facilitate forking applications.
To make assl_serve() exit set the global variable assl_stop_serving to true and interrupt the underlying poll(2) function. If intr_cb is non-NULL it will be called when the underlying functions are interrupted with EINTR.

assl_event_serve() is a non-blocking function that sets up a listening socket for incoming connections on host and port It performs its operation via libevent callbacks in the libevent event loop denotes by ev_base which should be intialized prior to calling assl_event_serve(). flags has the same meaning as in assl_serve(). cb_fn will be called with the file descriptor and cb_arg when the listening socket is contacted the code then can fork or perform required configuration and accept the connection using assl_event_serve().

assl_event_serve_stop() will close the listen socket established by assl_event_serve().

assl_accept() is the equivalent of the accept(2) function with the added SSL/TLS handshake and certificate validation functionality. This function should be called from the callback to assl_serve() after a context has been allocated in said function. The function returns a non-zero value to indicate failure.

assl_event_accept() will configure libevent read and write callback functions for the accepted socket for the ev_base event loop. By default the write event will not be enabled and can be toggled with assl_event_enable_write() and assl_event_disable_write() when the write socket is found not be be accepting all of the written data.

assl_read() will read nbytes into buf from the ctx socket. In blocking mode the function will not return until nbytes have been read or an error condition occurred. In non-blocking mode the function will return -1 and errno = EAGAIN to indicate that there was no data ready to read. All other errors simply return -1. Upon success the function returns the number of bytes read. If the connection has been terminated the function will return 0.

assl_write() will write nbytes from buf to the ctx socket. In blocking mode the function will not return until nbytes have been written or an error condition occurred. In non-blocking mode the function will return -1 and errno = EAGAIN to indicate that data could not be written immediately. All other errors simply return -1. Upon success the function returns the number of bytes written. If the connection has been terminated the function will return 0.

assl_gets() reads at most size - 1 from the given context. Reading stops when a newline character is found. In non-blocking mode the function will return -1 and errno = EAGAIN to indicate that data could not be read immediately. All other errors simply return -1. Upon success the function returns the number of bytes read. If the connection has been terminated the function will return 0.

assl_puts() writes the NUL terminated string pointed at in buf to the context. If the send_nul flag is set then the NUL character is written to the context as well. In non-blocking mode the function will return -1 and errno = EAGAIN to indicate that data could not be written immediately. All other errors simply return -1. Upon success the function returns the number of bytes written. If the connection has been terminated the function will return 0.

assl_poll() polls the socket in ctx for up to mseconds milliseconds for event to occur. An mseconds timeout of 0 will return immediately and INFTIM will block indefinitely. If revents is not NULL it returns the revents field from the pollfd structure as returned by the poll(2) command. assl_poll() returns 0 to indicate a timeout condition, -1 for error conditions and 1 for success. The return value of 1 really is the number of file descriptors that are ready and this mimics the poll(2) semantics.

assl_event_enable_write() should be called when using libevent and assl_write() returns -1 or partially completed write, to schedule the completion of the write. Calling code must perform any necessary buffering. Can also be used if calling code has queued data that is to be written by buffer handling code. assl_event_disable_write() should be called when all buffered data has been accepted by assl_write() and no more data is available to send, used in conjunction with assl_event_enable_write().

assl_destroy_mem_certs() clears and frees in memory certificates identified by the token.

assl_close() function terminates all connections and unwinds all resources, including context memory. Do not use the context pointer after calling this function. It is recommended to set the context pointer to NULL after this call.

assl_event_close() function terminates assl_event_accept() and assl_event_connect() connections and unwinds all resources, including context memory. Do not use the context pointer after calling this function. It is recommended to set the context pointer to NULL after this call.

assl_fatalx() prints errstr and exits. If the library is compiled with ASSL_NO_FANCY_ERRORS then it will not record the calling stack. The error handling code is not thread or re-entrant safe. It was written to accommodate finite state machines instead.

assl_warnx() prints errstr and returns.

EXAMPLES
The following code fragment illustrates the client case:

    #include "assl.h"
    int
    main(int argc, char *argv[])
    {
    	struct assl_context	*c;
    	assl_initialize();
    	c = assl_alloc_context(ASSL_M_TLSV1_CLIENT, 0);
    	if (c == NULL)
    		assl_fatalx("assl_alloc_context");
    	if (assl_load_file_certs(c, "../ca/ca.crt",
    	    "client/client.crt", "client/private/client.key"))
    		assl_fatalx("assl_load_certs");
    	if (assl_connect(c, "localhost", ASSL_DEFAULT_PORT,
    	    ASSL_F_BLOCK))
    		assl_fatalx("assl_connect");
    	return (0);
    }

The following code fragment illustrates the server case:

    #include "assl.h"
    void			serve_callback(int);
    void
    serve_callback(int s)
    {
    	struct assl_context	*c;
    	c = assl_alloc_context(ASSL_M_TLSV1_SERVER, 0);
    	if (c == NULL)
    		assl_fatalx("assl_alloc_context");
    	if (assl_load_file_certs(c, "../ca/ca.crt",
    	    "server/server.crt", "server/private/server.key"))
    		assl_fatalx("assl_load_file_certs");
    	if (assl_accept(c, s))
    		assl_fatalx("assl_accept");
    	errx(1, "do something!");
    }
    int
    main(int argc, char *argv[])
    {
    	assl_initialize();
    	assl_serve(NULL, ASSL_DEFAULT_PORT,
    	    ASSL_F_BLOCK, serve_callback, NULL);
    	return (0);
    }

DON'T SEE ALSO
openssl(1)

HISTORY
-nosplit

assl was written by Marco Peereboom <marco@peereboom.us> in order to hide the awful OpenSSL API. It strives to reuse openssl(1) APIs and provide a much simpler and sane interface for programmers that are interested in writing applications that require the SSL/TLS protocol for secure communications.

Once the API solidifies, individual functions can be replaced with code that does not rely on openssl(1)