/*-
 * SSLsplit - transparent SSL/TLS interception
 * https://www.roe.ch/SSLsplit
 *
 * Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
 * All rights reserved.
 *
 * 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.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER 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 COPYRIGHT HOLDER 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.
 */

#ifndef SSL_H
#define SSL_H

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

/*
 * SHA0 was removed in OpenSSL 1.1.0, including OPENSSL_NO_SHA0.
 */
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(OPENSSL_NO_SHA0)
#define OPENSSL_NO_SHA0
#endif

#if OPENSSL_VERSION_NUMBER < 0x10100000L
#define ASN1_STRING_get0_data(value) ASN1_STRING_data(value)
#define SSL_is_server(ssl) (ssl->type != SSL_ST_CONNECT)
#define X509_get_signature_nid(x509) (OBJ_obj2nid(x509->sig_alg->algorithm))
int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *);
#endif

/*
 * The constructors returning a SSL_METHOD * were changed to return
 * a const SSL_METHOD * between 0.9.8 and 1.0.0.
 */
#if (OPENSSL_VERSION_NUMBER < 0x1000000fL)
#define CONST_SSL_METHOD SSL_METHOD
#else /* >= OpenSSL 1.0.0 */
#define CONST_SSL_METHOD const SSL_METHOD
#endif /* >= OpensSL 1.0.0 */


/*
 * SSL_OP_NO_* is used as an indication that OpenSSL is sufficiently recent
 * to have the respective protocol implemented.
 *
 * OPENSSL_NO_SSL2 indicates the complete removal of SSL 2.0 support.
 *
 * OPENSSL_NO_SSL3 indicates that no SSL 3.0 connections will be made by
 * default, but support is still present, unless OPENSSL_NO_SSL3_METHOD is
 * also defined.
 */
#if defined(SSL_OP_NO_SSLv2) && !defined(OPENSSL_NO_SSL2) && \
    defined(WITH_SSLV2)
#define HAVE_SSLV2
#endif /* SSL_OP_NO_SSLv2 && !OPENSSL_NO_SSL2 && WITH_SSLV2 */
#if defined(SSL_OP_NO_SSLv3) && !defined(OPENSSL_NO_SSL3_METHOD)
#define HAVE_SSLV3
#endif /* SSL_OP_NO_SSLv2 && !OPENSSL_NO_SSL3_METHOD */
#ifdef SSL_OP_NO_TLSv1
#define HAVE_TLSV10
#endif /* SSL_OP_NO_TLSv1 */
#ifdef SSL_OP_NO_TLSv1_1
#define HAVE_TLSV11
#endif /* SSL_OP_NO_TLSv1_1 */
#ifdef SSL_OP_NO_TLSv1_2
#define HAVE_TLSV12
#endif /* SSL_OP_NO_TLSv1_2 */

#ifdef HAVE_SSLV2
#define SSL2_S "ssl2 "
#else /* !HAVE_SSLV2 */
#define SSL2_S ""
#endif /* !HAVE_SSLV2 */
#ifdef HAVE_SSLV3
#define SSL3_S "ssl3 "
#else /* !HAVE_SSLV3 */
#define SSL3_S ""
#endif /* !HAVE_SSLV3 */
#ifdef HAVE_TLSV10
#define TLS10_S "tls10 "
#else /* !HAVE_TLSV10 */
#define TLS10_S ""
#endif /* !HAVE_TLSV10 */
#ifdef HAVE_TLSV11
#define TLS11_S "tls11 "
#else /* !HAVE_TLSV11 */
#define TLS11_S ""
#endif /* !HAVE_TLSV11 */
#ifdef HAVE_TLSV12
#define TLS12_S "tls12 "
#else /* !HAVE_TLSV12 */
#define TLS12_S ""
#endif /* !HAVE_TLSV12 */
#define SSL_PROTO_SUPPORT_S SSL2_S SSL3_S TLS10_S TLS11_S TLS12_S

#define SSL_KEY_IDSZ 20
#define SSL_X509_FPRSZ 20

void ssl_openssl_version(void);
int ssl_init(void);
int ssl_reinit(void);
void ssl_fini(void);

char * ssl_sha1_to_str(unsigned char *, int);

char * ssl_ssl_state_to_str(SSL *);
char * ssl_ssl_masterkey_to_str(SSL *);

DH * ssl_tmp_dh_callback(SSL *, int, int);
DH * ssl_dh_load(const char *);
void ssl_dh_refcount_inc(DH *);

EC_KEY * ssl_ec_by_name(const char *);

EVP_PKEY * ssl_key_load(const char *);
EVP_PKEY * ssl_key_genrsa(const int);

void ssl_key_refcount_inc(EVP_PKEY *);

int ssl_key_identifier_sha1(EVP_PKEY *, unsigned char *);
char * ssl_key_identifier(EVP_PKEY *, int);

int ssl_x509_v3ext_add(X509V3_CTX * ctx, X509 * crt, const char * k, const char * v);
int ssl_x509_v3ext_copy_by_nid(X509 *, X509 *, int);

int ssl_x509_serial_copyrand(X509 *, X509 *);
X509 * ssl_x509_forge(X509 *, EVP_PKEY *, X509 *, EVP_PKEY *, const char *, const char *, int);

X509 * ssl_x509_load(const char *);
char * ssl_x509_subject(const X509 * crt);
char * ssl_x509_issuer(const X509 * crt);
char * ssl_x509_subject_cn(X509 *, size_t *);

int ssl_x509_fingerprint_sha1(X509 *, unsigned char *);
char * ssl_x509_fingerprint(X509 *, int);
char ** ssl_x509_names(X509 *);
int ssl_x509_names_match(X509 *, const char *);
char * ssl_x509_names_to_str(X509 *);
char ** ssl_x509_aias(X509 *, const int);
char ** ssl_x509_ocsps(X509 *);
int ssl_x509_is_valid(X509 *);
char * ssl_x509_to_str(X509 *);
char * ssl_x509_to_pem(X509 *);
void ssl_x509_refcount_inc(X509 *);
char* ssl_x509_get_extension(X509 *cert, int ext_NID);
int ssl_x509_is_ev(const char* policy_oid);

int ssl_x509chain_load(X509 **, STACK_OF(X509) **, const char *);
void ssl_x509chain_use(SSL_CTX *, X509 *, STACK_OF(X509) *);

char * ssl_session_to_str(SSL_SESSION *);
int ssl_session_is_valid(SSL_SESSION *);

int ssl_is_ocspreq(const unsigned char *, size_t);

int ssl_tls_clienthello_parse(const unsigned char *, ssize_t, int,
	const unsigned char **, char **);

int ssl_dnsname_match(const char *, size_t, const char *, size_t);
char * ssl_wildcardify(const char *);
void ssl_chain_dump(const char *sni, const char *chain_type, STACK_OF(X509) *chain);

enum chello_parse_result
{
	CHELLO_PARSE_SUCCESS = 0,
	CHELLO_PARSE_INVALID_FORMAT = -1,
	CHELLO_PARSE_NOT_ENOUGH_BUFF = -2
};

struct ssl_version
{
	uint8_t minor;
	uint8_t major;
	uint16_t ossl_format;
};

struct ssl_chello
{
	struct ssl_version min_version;
	struct ssl_version max_version;

	char *sni;
	char *alpn;
	char *sign_algos;
	uint16_t sign_algos_len;
	char *supported_groups;
	uint16_t supported_groups_len;
	char *cipher_suites;
	uint16_t cipher_suites_len;
};
struct ssl_chello* ssl_chello_parse(const unsigned char* buff, size_t buff_len, enum chello_parse_result* result);

void ssl_chello_free(struct ssl_chello* chello);

void ssl_cipher_suites_to_name(const char *source, int source_len, char *result_common, size_t sz_common, char *result_tls13, size_t sz_tls13);


#endif /* !SSL_H */
