/*      $NetBSD: tls.h,v 1.3 2018/02/08 17:45:29 christos Exp $ */

/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Martin Sch�tte.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*        This product includes software developed by the NetBSD
*        Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
*    contributors may be used to endorse or promote products derived
*    from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* tls.h
*
*/
#ifndef _TLS_H
#define _TLS_H
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/pem.h>
#include <openssl/dh.h>

/* initial size for TLS inbuf, minimum prefix + linelength
* guaranteed to be accepted */
#define TLS_MIN_LINELENGTH         (2048 + 5)
/* usually the inbuf is enlarged as needed and then kept.
* if bigger than TLS_PERSIST_LINELENGTH, then shrink
* to TLS_LARGE_LINELENGTH immediately  */
#define TLS_LARGE_LINELENGTH      8192
#define TLS_PERSIST_LINELENGTH   32768

/* timeout to call non-blocking TLS operations again */
#define TLS_RETRY_EVENT_USEC 20000

/* reconnect to lost server after n sec (initial value) */
#define TLS_RECONNECT_SEC 10
/* backoff connection attempts */
#define TLS_RECONNECT_BACKOFF_FACTOR 15/10
#define TLS_RECONNECT_BACKOFF(x)     (x) = (x) * TLS_RECONNECT_BACKOFF_FACTOR
/* abandon connection attempts after n sec
* This has to be <= 5h (with 10sec initial interval),
* otherwise a daily SIGHUP from newsylog will reset
* all timers and the giveup time will never be reached
*
* set here: 2h, reached after ca. 7h of reconnecting
*/
#define TLS_RECONNECT_GIVEUP         60*60*2

/* default algorithm for certificate fingerprints */
#define DEFAULT_FINGERPRINT_ALG "sha-1"

/* default X.509 files */
#define DEFAULT_X509_CERTFILE "/etc/openssl/default.crt"
#define DEFAULT_X509_KEYFILE "/etc/openssl/default.key"

/* options for peer certificate verification */
#define X509VERIFY_ALWAYS       0
#define X509VERIFY_IFPRESENT    1
#define X509VERIFY_NONE         2

/* attributes for self-generated keys/certificates */
#define TLS_GENCERT_BITS     1024
#define TLS_GENCERT_SERIAL      1
#define TLS_GENCERT_DAYS    5*365

/* TLS connection states */
#define ST_NONE       0
#define ST_TLS_EST    1
#define ST_TCP_EST    2
#define ST_CONNECTING 3
#define ST_ACCEPTING  4
#define ST_READING    5
#define ST_WRITING    6
#define ST_EOF        7
#define ST_CLOSING0   8
#define ST_CLOSING1   9
#define ST_CLOSING2  10

/* backlog for listen */
#define TLSBACKLOG 4
/* close TLS connection after multiple 'soft' errors */
#define TLS_MAXERRORCOUNT 4

/*
* holds TLS related settings for one connection to be
* included in the SSL object and available in callbacks
*
* Many fields have a slightly different semantic for
* incoming and outgoing connections:
* - for outgoing connections it contains the values from syslog.conf and
*   the server's cert is checked against these values by check_peer_cert()
* - for incoming connections it is not used for checking, instead
*   dispatch_tls_accept() fills in the connected hostname/port and
*   check_peer_cert() fills in subject and fingerprint from the peer cert
*/
struct tls_conn_settings {
       unsigned      send_queue:1, /* currently sending buffer      */
                     errorcount:4, /* counter [0;TLS_MAXERRORCOUNT] */
                     accepted:1,   /* workaround cf. check_peer_cert*/
                     shutdown:1,   /* fast connection close on exit */
                     x509verify:2, /* kind of validation needed     */
                     incoming:1,   /* set if we are server          */
                     state:4;      /* outgoing connection state     */
       struct event *event;        /* event for read/write activity */
       struct event *retryevent;   /* event for retries             */
       SSL          *sslptr;       /* active SSL object             */
       char         *hostname;     /* hostname or IP we connect to  */
       char         *port;         /* service name or port number   */
       char         *subject;      /* configured hostname in cert   */
       char         *fingerprint;  /* fingerprint of peer cert      */
       char         *certfile;     /* filename of peer cert         */
       unsigned      reconnect;    /* seconds between reconnects    */
};

/* argument struct only used for tls_send() */
struct tls_send_msg {
       struct filed     *f;
       struct buf_queue *qentry;
       char             *line;      /* formatted message */
       size_t            linelen;
       size_t            offset;    /* in case of partial writes */
};

/* return values for TLS_examine_error() */
#define TLS_OK          0        /* no real problem, just ignore */
#define TLS_RETRY_READ  1        /* just retry, non-blocking operation not finished yet */
#define TLS_RETRY_WRITE 2        /* just retry, non-blocking operation not finished yet */
#define TLS_TEMP_ERROR  4        /* recoverable error condition, but try again */
#define TLS_PERM_ERROR  8        /* non-recoverable error condition, closed TLS and socket */

/* global TLS setup and utility */
char *init_global_TLS_CTX(void);
struct socketEvent *socksetup_tls(const int, const char *, const char *);
int check_peer_cert(int, X509_STORE_CTX *);
int accept_cert(const char* , struct tls_conn_settings *, char *, char *);
int deny_cert(struct tls_conn_settings *, char *, char *);
bool read_certfile(X509 **, const char *);
bool write_x509files(EVP_PKEY *, X509 *, const char *, const char *);
bool mk_x509_cert(X509 **, EVP_PKEY **, int, int, int);
bool x509_cert_add_subjectAltName(X509 *, X509V3_CTX *);
int tls_examine_error(const char *, const SSL *, struct tls_conn_settings *, const int);

bool get_fingerprint(const X509 *, char **, const char *);
bool get_commonname(X509 *, char **);
bool match_hostnames(X509 *, const char *, const char *);
bool match_fingerprint(const X509 *, const char *);
bool match_certfile(const X509 *, const char *);

/* configuration & parsing */
bool parse_tls_destination(const char *, struct filed *, size_t);
/* event callbacks */
void dispatch_socket_accept(int, short, void *);
void dispatch_tls_accept(int, short, void *);
void dispatch_tls_read(int, short, void *);
void dispatch_tls_send(int, short, void *);
void dispatch_tls_eof(int, short, void *);
void dispatch_SSL_connect(int, short, void *);
void dispatch_SSL_shutdown(int, short, void *);
void dispatch_force_tls_reconnect(int, short, void *);

bool tls_connect(struct tls_conn_settings *);
void tls_reconnect(int, short, void *);
bool tls_send(struct filed *, char *, size_t, struct buf_queue*);
void tls_split_messages(struct TLS_Incoming_Conn *);

void free_tls_conn(struct tls_conn_settings *);
void free_tls_sslptr(struct tls_conn_settings *);
void free_tls_send_msg(struct tls_send_msg *);

#endif /* !_TLS_H */