
/*---------------------------------------------------------------------------*/
/* ssl.h                                                                     */
/* copyright (c) innovaphone 2017                                            */
/*                                                                           */
/*---------------------------------------------------------------------------*/

#define OP_SSL_DONE            0
#define OP_SSL_NEED_READ      -1
#define OP_SSL_NEED_WRITE     -2
#define OP_SSL_ERROR          -3
#define OP_SSL_CLOSE          -4

#define SRTP_MASTER_KEY_KEY_LEN 16
#define SRTP_MASTER_KEY_SALT_LEN 14

class ISSLSocketContext : public ISocketContext {
public:
    virtual void EnableDTLS(bool useSrtp) override = 0;
    virtual void SetServerCertificate(const byte * cert, size_t certLen, const char * hostName = NULL) override = 0;
    virtual const byte * GetCertificateFingerprint(size_t * length) override = 0;
    virtual void DisableClientCertificate() override = 0;
    virtual void EnableServerCertificateCheck() override = 0;
    virtual void ClearTrustList() override = 0;
    virtual void AddTrustedCertificate(const byte * cert, size_t certLen) override = 0;
    virtual void RemoveTrustedCertificate(const byte * cert, size_t certLen) override = 0;
};

class USSLSocketContext {
public:
    virtual void ExtractSrtpKeys(byte * srtpKeys, const char * profile) = 0;
};

class CertificateSigningRequest : public ICertificateSigningRequest {
    char * privateKey;
    char * request;
    char * commonName;
    certificate_csr_type_t csrType;
    std::deque<std::string> dnsNames;

public:
    CertificateSigningRequest(const char * commonName, certificate_csr_type_t csrType);
    ~CertificateSigningRequest();

    void SetPrivateKeyPEM(const char * privateKey, size_t privateKeyLength);
    void SetRequestPEM(const char * request, size_t requestLength);

    void AddDnsName(const char * dnsName) override;
    certificate_key_length_t GetKeyLength() override;
    certificate_csr_type_t GetKeyType() override { return this->csrType; }
    const char * GetCommonName() override { return this->commonName; }
    const char * GetPrivateKeyPEM() override { return this->privateKey; }
    const char * GetRequestPEM() override { return this->request; }
    std::deque<std::string> & GetDnsNames() { return this->dnsNames; }
};

class CertificateInformation : public ICertificateInformation {
    char * commonName;
    char * issuer;
    char * fingerprintSHA256;
    char * signatureAlgorithm;
    int keyLength;
    certificate_key_type_t keyType;
    long64 notBefore;
    long64 notAfter;
    std::vector<char *> chainCertificates;
    std::vector<char *> dnsNames;
    std::vector<char *> ipAddresses;

public:
    CertificateInformation();
    ~CertificateInformation();

    void SetCommonName(char * commonName);
    void SetIssuer(char * issuer);
    void SetFingerprintSHA256(char * fingerprintSHA256);
    void SetSignatureAlgorithm(const char * signatureAlgorithm);
    void SetKeyLength(int keyLength);
    void SetNotBefore(long64 notBefore);
    void SetNotAfter(long64 notAfter);
    void SetKeyType(certificate_key_type_t keyType);
    void AddDnsName(const char * dnsName);
    void AddIpAddress(const char * ipAddress);
    void AddChainCertificate(char * pem);

    const char * GetCommonName() override { return this->commonName; }
    const char * GetIssuer() override { return this->issuer; }
    const char * GetChainCertificate(size_t index) override { return this->chainCertificates.size() > index ? this->chainCertificates[index] : nullptr; }
    const char * GetDnsName(size_t index) override { return this->dnsNames.size() > index ? this->dnsNames[index] : nullptr; }
    const char * GetIpAddress(size_t index) override { return this->ipAddresses.size() > index ? this->ipAddresses[index] : nullptr; }
    const char * GetFingerprintSHA256() override { return this->fingerprintSHA256; }
    const char * GetSignatureAlgorithm() override { return this->signatureAlgorithm; }
    int GetKeyLength() override { return this->keyLength; }
    size_t GetChainDepth() override { return this->chainCertificates.size(); }
    size_t GetDnsNamesCount() override { return this->dnsNames.size(); }
    size_t GetIpAddressesCount() override { return this->ipAddresses.size(); }
    long64 GetNotBefore() override { return this->notBefore; }
    long64 GetNotAfter() override { return this->notAfter; }
    certificate_key_type_t GetKeyType() override { return this->keyType; }
};

class ISSLProvider : public ICertificates {
public:
    static class ISSLProvider * SharedInstance();
    virtual class ISSLSocketContext * CreateSSLSocketContext(class IInstanceLog * const log) = 0;
    virtual class ISSLInstance * CreateSSLInstance(IInstanceLog * log, bool server, const char * remoteAddress, class ISocketContext * socketContext, const char * serverName = NULL) = 0;
    virtual certificate_error_t ValidateCertificate(class IInstanceLog * log, const byte * cert, size_t certLen, class ICertificateInformation * info = nullptr, bool privateKeyRequired = true, bool verifyChain = true) = 0;
    virtual bool CreateCertificateSigningRequest(class IInstanceLog * log, class ICertificateSigningRequest * iCsr) = 0;
    virtual byte * ConvertPEMToDER(class IInstanceLog * log, const char * pem, size_t & outLength) = 0;
    virtual char * ConvertDERToPEM(class IInstanceLog * log, const byte * der, size_t derLength) = 0;
    virtual byte * CertificateFingerprint(class IInstanceLog * log, const byte * cert, size_t certLen, size_t * length, fingerprint_t type = FINGERPRINT_SHA256) = 0;
    virtual void SetDefaultClientCertificate(class IInstanceLog * const log, const byte * cert, size_t certLen) = 0;
};

class ISSLInstance {
public:
    virtual ~ISSLInstance() {};
    virtual int DoHandshake() = 0;
    virtual int DoShutdown() = 0;
    virtual void SetShutdown() = 0;
    virtual int ReadDecoded(const void * buf, size_t bufSize) = 0;
    virtual int ReadEncoded(const void * buf, size_t bufSize) = 0;

    virtual int WriteDecoded(const void * buf, size_t len) = 0;
    virtual int WriteEncoded(const void * buf, size_t len) = 0;
    virtual bool DataPending() = 0;
    virtual size_t BytesToSend() = 0;
    virtual void SetMtu(size_t mtu) = 0;

    virtual void SetSSLContext(USSLSocketContext * ctx) = 0;
    
    virtual void GetSelectedALPNProtocol(const byte * & protocolList, size_t & protocolListLength) = 0;
};

