/*
 * Copyright (c) 2003-2015
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 *
 * $Id: dacs_ssl.h 2791 2015-03-26 22:20:52Z brachman $
 */

#ifndef _DACS_SSL_H_
#define _DACS_SSL_H_

#include "dacs.h"

#include <sys/types.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#if defined(DACS_OS_SOLARIS)
#include <sys/filio.h>
#endif
#if defined(DACS_OS_CYGWIN)
#include <sys/termios.h>
#endif
#include <regex.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/x509v3.h>

#include "str.h"
#include "ds.h"
#include "net.h"

#ifndef ALLOC
#define ALLOC(OBJ)                   ((OBJ *) malloc(sizeof(OBJ)))
#endif

#ifndef ALLOC_N
#define ALLOC_N(OBJ, N)			((OBJ *) malloc(sizeof(OBJ) * (N)))
#endif

#ifndef DEFAULT_CIPHER_LIST
#define DEFAULT_CIPHER_LIST "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"
#endif

#ifndef DEFAULT_SERVER_PORT
#define DEFAULT_SERVER_PORT		"443"
#endif

#ifndef CA_CERT_FILE
#define CA_CERT_FILE	NULL
#endif

#ifndef CA_CERT_DIR
#define CA_CERT_DIR		NULL
#endif

#ifndef DEFAULT_RAND_SEED_FILE
#define DEFAULT_RAND_SEED_FILE		"/dev/urandom"
#endif

enum {
  RAND_SEED_BYTES = 1024,		/* Number of bytes required for seeding */
  BUF_SIZE        = 10240		/* SSL I/O buffer size, in bytes */
};

typedef struct Ssl_peer_match {
  char *regex_str;
  regex_t *regex;
} Ssl_peer_match;

typedef struct IO_state {
  int eof;
  int last_errno;
} IO_state;

typedef struct Ssl_conf {
  SSL *ssl;
  char *ca_cert_dir;
  char *ca_cert_file;
  char *cert_chain_file;
  char *cipher_list;
  char *rand_seed_file;
  char *key_file;
  int key_file_type;
  int use_default_verify_paths;
  int verify_depth;
  int verify_type;
  int verify_error;
  int verify_allow_self_signed;
  int buffer_output;
  Dsvec *peer_match_vec;
  int use_sni;
  int verbose_flag;
} Ssl_conf;

typedef ssize_t (*Ssl_io_callback)(void *, unsigned char *, size_t);

typedef struct Ssl_global_conf {
  X509_STORE *store;
  Ssl_conf *conf;
} Ssl_global_conf;

#ifdef __cplusplus
extern "C" {
#endif

extern int ssl_transfer(char *server, char *port, Ssl_conf *conf,
						Ssl_io_callback user_get_func, void *user_get_arg,
						Ssl_io_callback user_put_func, void *user_put_arg);
extern int ssl_server(char *hostname, char *port, Ssl_conf *conf,
					  Ssl_io_callback user_get_data, void *user_get_arg,
					  Ssl_io_callback user_put_data, void *user_put_arg);

extern SSL_CTX *ssl_setup_client_ctx(Ssl_conf *conf, char *servername);
extern Ssl_conf *ssl_init_defaults(Ssl_conf *conf);
extern ssize_t ssl_get_data(void *ctx, unsigned char *ptr, size_t len);
extern ssize_t ssl_put_data(void *ctx, unsigned char *ptr, size_t len);
extern int ssl_verify_callback(int ok, X509_STORE_CTX *ctx);
extern char *ssl_get_error_messages(void);
extern void ssl_transfer_data(SSL *ssl, Ssl_io_callback data_to_network,
							  void *to_ctx, Ssl_io_callback data_from_network,
							  void *from_ctx);
extern long ssl_post_connection_check(SSL *ssl, char *peer, Ssl_conf *conf);
extern int ssl_init(Ssl_conf *conf);

extern int ssl_printf(SSL *ssl, const char *fmt, ...);
extern int ssl_puts(SSL *ssl, char *str);
extern int ssl_gets(SSL *ssl, char *bufp, size_t buflen);
extern int ssl_eof(SSL *ssl);

#ifdef __cplusplus
}
#endif

#endif
