/*****************************************************************************/
/*
                                 Sesola.h
*/
/*****************************************************************************/

#ifndef SESOLA_H_LOADED
#define SESOLA_H_LOADED 1

#include "wasd.h"

/******************/
/* general macros */
/******************/

/* include which variety of SSL CGI variables */
#define SESOLA_CGI_VAR_NONE            1
#define SESOLA_CGI_VAR_APACHE_MOD_SSL  2
#define SESOLA_CGI_VAR_PURVEYOR        3

/* wait a maximum of five minutes for a private key password to be supplied */
#define SESOLA_PKPASSWD_REQUEST_SECONDS 300

/* number of attempts to get correct password */
#define SESOLA_PKPASSWD_ATTEMPTS 3

/* local client certificate verification macros (see [.SSL]SSL.H) */
#define SESOLA_VERIFY_PEER_NONE        0x00
/* SSL_VERIFY_PEER */
#define SESOLA_VERIFY_PEER_OPTIONAL    0x01
/* SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT */
#define SESOLA_VERIFY_PEER_REQUIRED    0x03

/* mask off the lower 8 OpenSSL verify bits removing the WASD bits */
#define SESOLA_VERIFY_PEER_MASK        0x0ff
/* do not alter certificate processing, just a callback (AST delivery) */
#define SESOLA_VERIFY_AST              0x100
/* use the peer certificate for authentication */
/* SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | 0x200 */
#define SESOLA_VERIFY_PEER_AUTH        0x203 

/* the OpenSSL definitions are only required for the SSL modules */
#ifndef SESOLA_REQUIRED
#  undef SESOLA
#endif

/*******************************/
/* always used data structures */
/*******************************/

typedef struct SesolaServiceStruct SESOLA_CONTEXT;

struct SesolaServiceStruct
{
   BOOL  VerifyCA,
         VerifyPeer;

   int  Version;

   char  *CaFilePtr,
         *CertFilePtr,
         *CipherListPtr,
         *KeyFilePtr,
         *VersionStringPtr;

   char  CaFile [128],
         CertFile [128],
         CipherList [128],
         KeyFile [128],
         VersionString [16];

   /* this will be cast using (SSL_CTX*) in Sesola.C */
   void  *SslCtx;
};

/***************************************/
#ifdef SESOLA  /* secure sockets layer */
/***************************************/

/* OpenSSL 0.9.6 has a typedef boolean - work around this */
#ifdef boolean
#  undef boolean
#  define BOOL int
#endif /* boolean */

/* OpenSSL header files (0.9.3ff) */
#include "openssl/err.h"
#include "openssl/X509.h"
#include "openssl/ssl.h"
#include "openssl/bio.h"
#include "openssl/buffer.h"
#include "openssl/crypto.h"

/* not defined anywhere in OpenSSL but the "1024*10" seems common %^) */
#define SSL_SESSION_MAX_DER (1024*10)

/**********/
/* macros */
/**********/

#define SESOLA_DEFAULT_VERIFY_DEPTH        10
#define SESOLA_DEFAULT_CACHE_SIZE         128  /* OpenSSL cache entries */
#define SESOLA_DEFAULT_CACHE_RECORD_MAX    32  /* WASD shared cache entries */
#define SESOLA_DEFAULT_CACHE_RECORD_SIZE 1024  /* bytes */
#define SESOLA_DEFAULT_CACHE_TIMEOUT        5  /* minutes */

#define SESOLA_SSLV2    0x01
#define SESOLA_SSLV3    0x02
#define SESOLA_TLSV1    0x04

#define APACHE_MOD_SSL_VERSION_INTERFACE SoftwareID
#define APACHE_MOD_SSL_SERVER_CERT 0

/* indicate by return status that an AST is in progress */
#define SESOLA_VERIFY_PEER_PENDING     0x0fffffca

/*******************/
/* data structures */
/*******************/

#ifndef __VAX
#   pragma member_alignment __save
#   pragma member_alignment
#endif

typedef struct SesolaStruct SESOLA_STRUCT;

struct SesolaStruct
{
   /* OpenSSL structures */
   SSL  *SslPtr;
   BIO  *BioPtr;
   BIO  *BioSslPtr;
   SSL_CTX  *SslCtx;
   X509  *ClientCertPtr;

   REQUEST_STRUCT  *RequestPtr;
   PROXY_TASK  *ProxyTaskPtr;

   /*
       These "in-progress" flags are to provide an additional indication of
       when a OpenSSL routine has used non-blocking I/O.  Only valid within
       the single AST-delivery context (i.e. to be checked immediately after
       using an OpenSSL function, before returning out of the current AST
       delivery context), because as soon as the I/O AST is delivered the
       approriate flags will be reset.
   */
   BOOL  CertVerifyFailed,
         HTTPduringHandshake,
         ReadInProgress,
         ReadCompleted,
         WriteInProgress,
         WriteCompleted,
         X509optionalNoCa;

   int  /* sort of a 'state' flag */
        AcceptState,
        /* simple count of how many times verify callback has been called */
        CertVerifyCallbackCount,
        /* depth client certificates are to be verified to */
        CertVerifyDepth,
        /* value of verify type initially passed to the function */
        CertVerifyMode,
        /* size of read data buffer (for AST routine) */
        ReadDataSize,
        /* sort of a 'state' flag */
        RenegotiateState,
        /* sort of a 'state' flag */
        ReportClientCertState,
        /* [LT:integer] value stored until needed */
        SessionLifetimeMinutes,
        /* [TO:integer] value stored until needed */
        SessionTimeoutMinutes,
        /* sort of a 'state' flag */
        ShutdownState,
        /* number of characters to be written to network */
        WriteDataLength;

   unsigned short  /* channel used for network reads/writes */
                   NetChannel;

   char  /* pointer to read data buffer (for AST routine use) */
         *ReadDataPtr,
         /* pointer to raw (encrypted) data read from network */
         *ReadWatchDataPtr,
         /* pointer to write data buffer (for AST routine use) */
         *WriteDataPtr,
         /* pointer to hold position between parses of the X509 param="" */
         *X509ConditionalPtr;

   char  /* buffer this information when getting a client certificate */
         ReportVirtualHostPort [128],
         /* source of X.509 remote-user, record from subject DN of cert */
         X509RemoteUserDnRecord [16];

   /* I/O status blocks */
   IO_SB  ReadIOsb,
                  WriteIOsb;

   /* SSL post-processing, stores the pointer to the AST routine */
   GENERAL_AST  ClientCertAstFunction,
                ReadAstFunction,
                ReadSesolaFunction,
                ReportNextTaskFunction,
                WriteAstFunction,
                WriteSesolaFunction;
};


typedef struct SesolaSessionCacheRecordStruct SESOLA_SESSION_CREC;

struct SesolaSessionCacheRecordStruct
{
    int  SessDataLength,
         SessIdLength,
         TimeoutTickSecond;
    unsigned long  CachedBinTime [2];
    unsigned char  SessId [SSL_MAX_SSL_SESSION_ID_LENGTH];

    /* session DER is stored from here onwards */
    char  SessData [];
};

typedef struct SesolaGblSecStruct SESOLA_GBLSEC;

struct SesolaGblSecStruct
{
   unsigned long  GblSecVersion,
                  GblSecLength;

   int  CacheHitCount,
        CacheMissCount,
        CacheRecordCount,
        CacheReuseCount,
        CacheTimeoutCount;
   unsigned long  SinceBinTime [2];

    /* session cache records are stored from this point onwards */
   char  CacheRecordPool [];
};

#ifndef __VAX
#   pragma member_alignment __restore
#endif

/***********************/
/* function prototypes */
/***********************/

/* SESOLA.C */

int SesolaCertVerifyCallback (int, void*);
char* SesolaCertFingerprint (void*, EVP_MD*(*)(void), char*, int);
SesolaControlReloadCA ();
SesolaError (REQUEST_STRUCT*, char*);
int SesolaPrivateKeyPasswd (char*, int, int, void*);
SesolaInit ();
SesolaInitService (SERVICE_STRUCT*, SERVICE_STRUCT*);
char* SesolaParseCertDn (char*, char*);
SesolaReport (REQUEST_STRUCT*, REQUEST_AST, char*);
SesolaReportCA (REQUEST_STRUCT*, REQUEST_AST, char*);
SesolaReportFormatCertName (char*, char*, int);
SesolaSessionId (SSL*);
char* SesolaVersion ();
SesolaWatchPeek (REQUEST_STRUCT*, REQUEST_STRUCT*);
int SesolaWatchBioCallback (BIO*, int, char*, int, long, long);
SesolaWatchErrors (SESOLA_STRUCT*);
SesolaWatchInfoCallback (SSL*, int, int);
SesolaWatchSession (SESOLA_STRUCT*);

/* SESOLACACHE.C */

int SesolaCacheInit ();
int SesolaCacheAddRecord (SSL*, SSL_SESSION*);
SSL_SESSION* SesolaCacheFindRecord (SSL*, unsigned char*, int, int*);
SesolaCacheGblSecInit ();
int SesolaCacheRemoveRecord (SSL_CTX*, SSL_SESSION*);
int SesolaCacheStats (REQUEST_STRUCT*);

/* SESOLACGI.C */

SesolaCgiGenerateVariables (REQUEST_STRUCT*, int);
SesolaCgiVariablesApacheModSsl (REQUEST_STRUCT*, int);
SesolaCgiVariablesPurveyor (REQUEST_STRUCT*, int);

/* SESOLACLIENT.C */

int SesolaClientCert (REQUEST_STRUCT*, int, REQUEST_AST);
int SesolaClientCertConditional (REQUEST_STRUCT*, char*);
SesolaClientCertRenegotiate (REQUEST_STRUCT*);

/* SESOLANET.C */

SesolaNetThisIsSSL (SESOLA_STRUCT*);
SesolaNetClientBegin (PROXY_TASK*);
SesolaNetClientConnect (PROXY_TASK*);
SesolaNetClientEnd (PROXY_TASK*);
SesolaNetClientFree (PROXY_TASK*);
SesolaNetRead (SESOLA_STRUCT*, GENERAL_AST, char*, int);
SesolaNetRequestAccept (REQUEST_STRUCT*);
SesolaNetRequestBegin (REQUEST_STRUCT*);
SesolaNetRequestEnd (REQUEST_STRUCT*);
SesolaNetRequestFree (REQUEST_STRUCT*);
SesolaNetWrite (SESOLA_STRUCT*, GENERAL_AST, char*, int);
SesolaNetSockethasBeenClosed (SESOLA_STRUCT*);
int Sesola_read (BIO*, char*, int);
int Sesola_read_ast (SESOLA_STRUCT*);
int Sesola_write (BIO*, char*, int);
int Sesola_write_ast (SESOLA_STRUCT*);
int Sesola_puts (BIO*, char*);
int Sesola_gets (BIO*, char*, int);
long Sesola_ctrl (BIO*, int, long, char*);
int Sesola_new (BIO*);
int Sesola_free (BIO*);
BIO_METHOD *BIO_s_Sesola();

/*********************/
#else  /* not SESOLA */
/*********************/

BOOL SesolaInitClientService (SERVICE_STRUCT *);
SesolaCgiGenerateVariables (REQUEST_STRUCT*, int);
SesolaNetSocketHasBeenClosed (void*);

/* these need to be here only for WATCH.C to resolve the references */
int Sesola_read_ast (void*);
int Sesola_write_ast (void*);

/************************/
#endif  /* ifdef SESOLA */
/************************/

#endif /* SESOLA_H_LOADED */

/*****************************************************************************/

