/*	$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 */
