/* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
 * applicable.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef SSL_PRIVATE_H
#define SSL_PRIVATE_H

#define MOD_SSL_VERSION VERSION

#ifndef NUL
#define NUL '\0'
#endif
#ifndef UNSET
#define UNSET (-1)
#endif

/**
 * Provide reasonable defines for some types
 */
#ifndef BOOL
#define BOOL unsigned int
#endif
#ifndef UCHAR
#define UCHAR unsigned char
#endif

/**
 * Provide useful shorthands
 */
#define strEQ(s1,s2)     (strcmp(s1,s2)        == 0)
#define strNE(s1,s2)     (strcmp(s1,s2)        != 0)
#define strEQn(s1,s2,n)  (strncmp(s1,s2,n)     == 0)
#define strNEn(s1,s2,n)  (strncmp(s1,s2,n)     != 0)

#define strcEQ(s1,s2)    (strcasecmp(s1,s2)    == 0)
#define strcNE(s1,s2)    (strcasecmp(s1,s2)    != 0)
#define strcEQn(s1,s2,n) (strncasecmp(s1,s2,n) == 0)
#define strcNEn(s1,s2,n) (strncasecmp(s1,s2,n) != 0)

#define strIsEmpty(s)    (s == NULL || s[0] == NUL)

#define myConnConfigSet(c, val) c->sslconn = (SSLConnRec *) val
#define myConnConfig(c)  (SSLConnRec *) c->sslconn
#define myCtxConfig(sslconn, sc) (sslconn->is_proxy ? sc->proxy : sc->server)
#define mySrvConfig(srv) ((SSLSrvConfigRec *) ROVM_SSL_SERVER (srv))
#define myDirConfig(req) ((SSLDirConfigRec *) req->conn->ts->arg->dc)
#define myModConfig(srv) (mySrvConfig((srv)))->mc

#define myCtxVarSet(mc,num,val)  mc->rCtx.pV##num = val
#define myCtxVarGet(mc,num,type) (type)(mc->rCtx.pV##num)

/**
 * Defaults for the configuration
 */
#ifndef SSL_SESSION_CACHE_TIMEOUT
#define SSL_SESSION_CACHE_TIMEOUT  300
#endif

/**
 * Support for MM library
 */
#define SSL_MM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )

/**
 * Support for DBM library
 */
#define SSL_DBM_FILE_MODE ( APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD )

#if !defined(SSL_DBM_FILE_SUFFIX_DIR) && !defined(SSL_DBM_FILE_SUFFIX_PAG)
#if defined(DBM_SUFFIX)
#define SSL_DBM_FILE_SUFFIX_DIR DBM_SUFFIX
#define SSL_DBM_FILE_SUFFIX_PAG DBM_SUFFIX
#elif defined(__FreeBSD__) || (defined(DB_LOCK) && defined(DB_SHMEM))
#define SSL_DBM_FILE_SUFFIX_DIR ".db"
#define SSL_DBM_FILE_SUFFIX_PAG ".db"
#else
#define SSL_DBM_FILE_SUFFIX_DIR ".dir"
#define SSL_DBM_FILE_SUFFIX_PAG ".pag"
#endif
#endif

/**
 * Define the certificate algorithm types
 */

typedef int ssl_algo_t;

#define SSL_ALGO_UNKNOWN (0)
#define SSL_ALGO_RSA     (1<<0)
#define SSL_ALGO_DSA     (1<<1)
#define SSL_ALGO_ALL     (SSL_ALGO_RSA|SSL_ALGO_DSA)

#define SSL_AIDX_RSA     (0)
#define SSL_AIDX_DSA     (1)
#define SSL_AIDX_MAX     (2)

/**
 * Define IDs for the temporary RSA keys and DH params
 */

#define SSL_TMP_KEY_RSA_512  (0)
#define SSL_TMP_KEY_RSA_1024 (1)
#define SSL_TMP_KEY_DH_512   (2)
#define SSL_TMP_KEY_DH_1024  (3)
#define SSL_TMP_KEY_MAX      (4)

/**
 * Define the SSL options
 */
#define SSL_OPT_NONE           (0)
#define SSL_OPT_RELSET         (1<<0)
#define SSL_OPT_STDENVVARS     (1<<1)
#define SSL_OPT_EXPORTCERTDATA (1<<3)
#define SSL_OPT_FAKEBASICAUTH  (1<<4)
#define SSL_OPT_STRICTREQUIRE  (1<<5)
#define SSL_OPT_OPTRENEGOTIATE (1<<6)
#define SSL_OPT_ALL            (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE)
typedef int ssl_opt_t;

/**
 * Define the SSL Protocol options
 */
#define SSL_PROTOCOL_NONE  (0)
#define SSL_PROTOCOL_SSLV2 (1<<0)
#define SSL_PROTOCOL_SSLV3 (1<<1)
#define SSL_PROTOCOL_TLSV1 (1<<2)
#define SSL_PROTOCOL_ALL   (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1)
typedef int ssl_proto_t;

/**
 * Define the SSL session cache modes and structures
 */
typedef enum 
  {
    SSL_SCMODE_UNSET = UNSET,
    SSL_SCMODE_NONE  = 0,
    SSL_SCMODE_DBM   = 1,
    SSL_SCMODE_SHMCB = 3,
    SSL_SCMODE_DC    = 4,
    SSL_SCMODE_NONE_NOT_NULL = 5
  } ssl_scmode_t;

/**
 * Define the SSL mutex modes
 */
typedef enum 
  {
    SSL_MUTEXMODE_UNSET  = UNSET,
    SSL_MUTEXMODE_NONE   = 0,
    SSL_MUTEXMODE_USED   = 1
  } ssl_mutexmode_t;

/**
 * Define the SSL enabled state
 */
typedef enum
  {
    SSL_ENABLED_UNSET    = UNSET,
    SSL_ENABLED_FALSE    = 0,
    SSL_ENABLED_TRUE     = 1,
    SSL_ENABLED_OPTIONAL = 3
  } ssl_enabled_t;

/**
 * Define the SSL pass phrase dialog types
 */
typedef enum 
  {
    SSL_PPTYPE_UNSET   = UNSET,
    SSL_PPTYPE_BUILTIN = 0,
    SSL_PPTYPE_FILTER  = 1,
    SSL_PPTYPE_PIPE    = 2
  } ssl_pphrase_t;

/**
 * Define the Path Checking modes
 */
#define SSL_PCM_EXISTS     1
#define SSL_PCM_ISREG      2
#define SSL_PCM_ISDIR      4
#define SSL_PCM_ISNONZERO  8
typedef unsigned int ssl_pathcheck_t;

/**
 * Define the SSL verify levels
 */
typedef enum 
  {
    SSL_CVERIFY_UNSET           = UNSET,
    SSL_CVERIFY_NONE            = 0,
    SSL_CVERIFY_OPTIONAL        = 1,
    SSL_CVERIFY_REQUIRE         = 2,
    SSL_CVERIFY_OPTIONAL_NO_CA  = 3
  } ssl_verify_t;

#define SSL_VERIFY_PEER_STRICT \
     (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)

#ifndef X509_V_ERR_CERT_UNTRUSTED
#define X509_V_ERR_CERT_UNTRUSTED 27
#endif

#define ssl_verify_error_is_optional(errnum) \
   ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \
    || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \
    || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \
    || (errnum == X509_V_ERR_CERT_UNTRUSTED) \
    || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))

/**
 * Define the SSL requirement structure
 */
typedef struct 
{
  char     *cpExpr;
  ssl_expr *mpExpr;
} ssl_require_t;

/**
 * Define the SSL random number generator seeding source
 */
typedef enum 
  {
    SSL_RSCTX_STARTUP = 1,
    SSL_RSCTX_CONNECT = 2
  } ssl_rsctx_t;
typedef enum 
  {
    SSL_RSSRC_BUILTIN = 1,
    SSL_RSSRC_FILE    = 2,
    SSL_RSSRC_EXEC    = 3,
    SSL_RSSRC_EGD     = 4
  } ssl_rssrc_t;
typedef struct 
{
  ssl_rsctx_t  nCtx;
  ssl_rssrc_t  nSrc;
  char        *cpPath;
  int          nBytes;
} ssl_randseed_t;

/**
 * Define the structure of an ASN.1 anything
 */
typedef struct 
{
  long int       nData;
  unsigned char *cpData;
  rc_time_t      source_mtime;
} ssl_asn1_t;

/**
 * Define the mod_ssl per-module configuration structure
 * (i.e. the global configuration for each httpd process)
 */

typedef enum 
  {
    SSL_SHUTDOWN_TYPE_UNSET,
    SSL_SHUTDOWN_TYPE_STANDARD,
    SSL_SHUTDOWN_TYPE_UNCLEAN,
    SSL_SHUTDOWN_TYPE_ACCURATE
  } ssl_shutdown_type_e;

typedef struct 
{
  SSL *ssl;
  const char *client_dn;
  X509 *client_cert;
  ssl_shutdown_type_e shutdown_type;
  const char *verify_info;
  const char *verify_error;
  int verify_depth;
  int is_proxy;
  int disabled;
  int non_ssl_request;
} SSLConnRec;

typedef struct 
{
  pid_t           pid;
  rc_pool_t      *pPool;
  BOOL            bFixed;
  int             nSessionCacheMode;
  char           *szSessionCacheDataFile;
  int             nSessionCacheDataSize;
  rc_shm_t       *pSessionCacheDataMM;
  rc_rmm_t       *pSessionCacheDataRMM;
  void           *tSessionCacheDataTable;
  ssl_mutexmode_t nMutexMode;
  rc_lockmech_e   nMutexMech;
  const char     *szMutexFile;
  rc_global_mutex_t   *pMutex;
  rc_array_header_t   *aRandSeed;
  rc_hash_t      *tVHostKeys;
  void           *pTmpKeys[SSL_TMP_KEY_MAX];
  rc_hash_t      *tPublicCert;
  rc_hash_t      *tPrivateKey;
#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_INIT)
  const char     *szCryptoDevice;
#endif
  struct {
    void *pV1, *pV2, *pV3, *pV4, *pV5, *pV6, *pV7, *pV8, *pV9, *pV10;
  } rCtx;
} SSLModConfigRec;

/** public cert/private key */
typedef struct 
{
  /**
   * server only has 1-2 certs/keys
   * 1 RSA and/or 1 DSA
   */
  const char  *cert_files[SSL_AIDX_MAX];
  const char  *key_files[SSL_AIDX_MAX];
  X509        *certs[SSL_AIDX_MAX];
  EVP_PKEY    *keys[SSL_AIDX_MAX];
  
  /** Certificates which specify the set of CA names which should be
   * sent in the CertificateRequest message: */
  const char  *ca_name_path;
  const char  *ca_name_file;
} modssl_pk_server_t;

typedef struct 
{
  /** proxy can have any number of cert/key pairs */
  const char  *cert_file;
  const char  *cert_path;
  STACK_OF(X509_INFO) *certs;
} modssl_pk_proxy_t;

/** stuff related to authentication that can also be per-dir */
typedef struct 
{
  /** known/trusted CAs */
  const char  *ca_cert_path;
  const char  *ca_cert_file;
  
  const char  *cipher_suite;
  
  /** for client or downstream server authentication */
  int          verify_depth;
  ssl_verify_t verify_mode;
} modssl_auth_ctx_t;

typedef struct SSLSrvConfigRec SSLSrvConfigRec;

typedef struct 
{
  SSLSrvConfigRec *sc; /** pointer back to server config */
  SSL_CTX *ssl_ctx;
  
  /** we are one or the other */
  modssl_pk_server_t *pks;
  modssl_pk_proxy_t  *pkp;
  
  ssl_proto_t  protocol;
  
  /** config for handling encrypted keys */
  ssl_pphrase_t pphrase_dialog_type;
  const char   *pphrase_dialog_path;
  
  const char  *cert_chain;
  
  /** certificate revocation list */
  const char  *crl_path;
  const char  *crl_file;
  X509_STORE  *crl;
  
  modssl_auth_ctx_t auth;
} modssl_ctx_t;

struct SSLSrvConfigRec 
{
  SSLModConfigRec *mc;
  ssl_enabled_t    enabled;
  BOOL             proxy_enabled;
  const char      *vhost_id;
  int              vhost_id_len;
  int              session_cache_timeout;
  BOOL             cipher_server_pref;
  modssl_ctx_t    *server;
  modssl_ctx_t    *proxy;
};

/**
 * Define the mod_ssl per-directory configuration structure
 * (i.e. the local configuration for all <Directory>
 *  and .htaccess contexts)
 */
typedef struct 
{
  BOOL          bSSLRequired;
  apr_array_header_t *aRequirement;
  ssl_opt_t     nOptions;
  ssl_opt_t     nOptionsAdd;
  ssl_opt_t     nOptionsDel;
  const char   *szCipherSuite;
  ssl_verify_t  nVerifyClient;
  int           nVerifyDepth;
  const char   *szCACertificatePath;
  const char   *szCACertificateFile;
  const char   *szUserName;
} SSLDirConfigRec;

extern SSLSrvConfigRec *ssl_config_server_create (struct rovm *r, rc_pool_t *p);
extern SSLDirConfigRec *ssl_config_perdir_create (rc_pool_t *p, char *dir);

extern void ssl_scache_kill (struct rovm *r);
extern void ssl_scache_dbm_kill (struct rovm *r);
extern void ssl_scache_shmcb_kill (struct rovm *r);
extern int ssl_init_Module (struct rovm *r);
extern SSLModConfigRec *ssl_config_global_create (struct rovm *r);
extern void ssl_config_global_fix (SSLModConfigRec *mc);
extern char *ssl_util_vhostid (rc_pool_t *p, struct rovm *r);
extern void ssl_die (void);
extern void ssl_log_ssl_error (const char *file, int line, int level, struct rovm *r);
extern void ssl_util_thread_setup (rc_pool_t *p);
extern rc_file_t *ssl_util_ppopen (struct rovm *r, apr_pool_t *p, const char *cmd, const char * const *argv);
extern void ssl_util_ppclose (struct rovm *r, apr_pool_t *p, apr_file_t *fp);
extern int ssl_rand_seed (struct rovm *r, rc_pool_t *p, ssl_rsctx_t nCtx, char *prefix);
extern X509 *SSL_read_X509 (char* filename, X509 **x509, modssl_read_bio_cb_fn *cb);
extern void ssl_pphrase_Handle (struct rovm *r, apr_pool_t *p);
extern ssl_algo_t ssl_util_algotypeof (X509 *pCert, EVP_PKEY *pKey);
extern char *ssl_util_algotypestr (ssl_algo_t t);
extern unsigned char *ssl_asn1_table_set(apr_hash_t *table, const char *key, long int length);
extern ssl_asn1_t *ssl_asn1_table_get (apr_hash_t *table, const char *key);
extern void ssl_asn1_table_unset (apr_hash_t *table, const char *key);
extern const char *ssl_asn1_table_keyfmt (apr_pool_t *p, const char *id, int keytype);
extern const char *ssl_asn1_keystr(int keytype);
extern EVP_PKEY *SSL_read_PrivateKey (char* filename, EVP_PKEY **key, modssl_read_bio_cb_fn *cb, void *s);
extern char *ssl_util_readfilter (struct rovm *r, apr_pool_t *p, const char *cmd, const char * const *argv);
extern DH *ssl_dh_GetTmpParam(int nKeyLen);
extern DH *modssl_dh_configure (unsigned char *p, int plen, unsigned char *g, int glen);
extern int ssl_mutex_init (struct rovm *r, apr_pool_t *p);
extern int ssl_mutex_reinit(struct rovm *r, apr_pool_t *p);
extern int ssl_mutex_on (struct rovm *r);
extern int ssl_mutex_off (struct rovm *r);
extern void ssl_scache_init (struct rovm *r, apr_pool_t *p);
extern void ssl_scache_dbm_init (struct rovm *r, apr_pool_t *p);
extern void ssl_scache_shmcb_init(struct rovm *r, apr_pool_t *p);
extern int ssl_callback_NewSessionCacheEntry(SSL *ssl, SSL_SESSION *session);
extern SSL_SESSION *ssl_callback_GetSessionCacheEntry(SSL *ssl, unsigned char *id, int idlen, int *do_copy);
extern void ssl_callback_DelSessionCacheEntry(SSL_CTX *ctx, SSL_SESSION *session);
extern int modssl_session_get_time (SSL_SESSION *session);
extern BOOL ssl_scache_store (struct rovm *r, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess);
extern char *SSL_SESSION_id2sz(unsigned char *id, int idlen, char *str, int strsize);
extern SSL_SESSION *ssl_scache_retrieve(struct rovm *r, UCHAR *id, int idlen);
extern void ssl_scache_remove(struct rovm *r, UCHAR *id, int idlen);
extern BOOL ssl_scache_dbm_store (struct rovm *r, UCHAR *id, int idlen, time_t expiry, SSL_SESSION *sess);
extern BOOL ssl_scache_shmcb_store(struct rovm *r, UCHAR *id, int idlen, time_t timeout, SSL_SESSION * pSession);
extern SSL_SESSION *ssl_scache_dbm_retrieve (struct rovm *r, UCHAR *id, int idlen);
extern SSL_SESSION *ssl_scache_shmcb_retrieve (struct rovm *r, UCHAR *id, int idlen);
extern void ssl_scache_shmcb_remove (struct rovm *r, UCHAR *id, int idlen);
extern void ssl_scache_dbm_remove (struct rovm *r, UCHAR *id, int idlen);
extern RSA *ssl_callback_TmpRSA (SSL *ssl, int export, int keylen);
extern DH *ssl_callback_TmpDH(SSL *ssl, int export, int keylen);
extern void ssl_callback_LogTracingState(MODSSL_INFO_CB_ARG_TYPE ssl, int where, int rc);
struct conn_rec;
struct request_rec;
extern char *ssl_var_lookup (apr_pool_t *p, struct rovm *rovm, struct conn_rec *c, struct request_rec *r, char *var);
extern int ssl_callback_SSLVerify (int ok, X509_STORE_CTX *ctx);
extern void *SSL_get_app_data2(SSL *ssl);
extern int SSL_X509_STORE_lookup(X509_STORE *pStore, int nType, X509_NAME *pName, X509_OBJECT *pObj);
extern X509_STORE *SSL_X509_STORE_create(char *cpFile, char *cpPath);
extern int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, char *file, int skipfirst, modssl_read_bio_cb_fn *cb);
extern int ssl_callback_proxy_cert(SSL *ssl, MODSSL_CLIENT_CERT_CB_ARG_TYPE **x509, EVP_PKEY **pkey);
extern BOOL SSL_X509_INFO_load_file(apr_pool_t *ptemp, STACK_OF(X509_INFO) *sk, const char *filename);
extern BOOL SSL_X509_INFO_load_path(apr_pool_t *ptemp, STACK_OF(X509_INFO) *sk, const char *pathname);
extern BOOL SSL_X509_isSGC(X509 *cert);
extern BOOL SSL_X509_getBC(X509 *cert, int *ca, int *pathlen);
extern BOOL SSL_X509_getCN(apr_pool_t *p, X509 *xs, char **cppCN);
extern void SSL_init_app_data2_idx (void);

extern BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p);

extern const char *ssl_cmd_SSLPassPhraseDialog (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLSessionCache (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLSessionCacheTimeout (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLMutex (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLEngine (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLCipherSuite (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLCertificateFile (cmd_parms *cmd, void *dummy, const char *arg);
extern const char *ssl_cmd_SSLCertificateKeyFile (cmd_parms *cmd, void *dummy, const char *arg);

extern void SSL_set_app_data2(SSL *ssl, void *arg);
extern void ssl_init_Child (apr_pool_t *p, struct rovm *r);
extern int init_rovm_ssl (struct rovm *r);
extern int init_rovm_ssl_pre_config (struct rovm *r);
extern int SSL_smart_shutdown(SSL *ssl);

#endif
