Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/XRDP/common/   (X11 Server Version 0.10.6.1©)  Datei vom 7.6.2026 mit Größe 41 kB image not shown  

Quelle  ssl_calls.c

  Sprache: C
 

/**
 * xrdp: A Remote Desktop Protocol server.
 *
 * Copyright (C) Jay Sorg 2004-2014
 * Copyright (C) Idan Freiberg 2013-2014
 *
 * 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.
 *
 * ssl calls
 */


#if defined(HAVE_CONFIG_H)
#include <config_ac.h>
#endif

#include <stdlib.h> /* needed for openssl headers */
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rc4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dh.h>
#include <openssl/crypto.h>

#include "os_calls.h"
#include "string_calls.h"
#include "arch.h"
#include "ssl_calls.h"
#include "trans.h"
#include "log.h"

#define SSL_WANT_READ_WRITE_TIMEOUT 100

/*
 * Globals used by openssl 3 and later */

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
static EVP_MD *g_md_md5;    /* MD5 message digest */
static EVP_MD *g_md_sha1;   /* SHA1 message digest */
static EVP_CIPHER *g_cipher_des_ede3_cbc; /* DES3 CBC cipher */
static EVP_MAC *g_mac_hmac; /* HMAC MAC */
#endif

#if OPENSSL_VERSION_NUMBER >= 0x10101000L
#define HAS_KEYLOG_CALLBACK /* SSL_CTX_set_keylog_callback() is available */
static char *g_keylog_filename = NULL;
#endif

/* definition of ssl_tls */
struct ssl_tls
{
    SSL *ssl; /* SSL * */
    SSL_CTX *ctx; /* SSL_CTX * */
    char *cert;
    char *key;
    struct trans *trans;
    tintptr rwo; /* wait obj */
    int error_logged; /* Error has already been logged */
};

#if OPENSSL_VERSION_NUMBER < 0x10100000L
static inline HMAC_CTX *
HMAC_CTX_new(void)
{
    HMAC_CTX *hmac_ctx = g_new(HMAC_CTX, 1);
    HMAC_CTX_init(hmac_ctx);
    return hmac_ctx;
}

static inline void
HMAC_CTX_free(HMAC_CTX *hmac_ctx)
{
    HMAC_CTX_cleanup(hmac_ctx);
    g_free(hmac_ctx);
}

static inline void
RSA_get0_key(const RSA *key, const BIGNUM **n, const BIGNUM **e,
             const BIGNUM **d)
{
    *n = key->n;
    *d = key->d;
}

static inline int
DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
{
    /* If the fields p and g in d are NULL, the corresponding input
     * parameters MUST be non-NULL.  q may remain NULL.
     */

    if ((dh->p == NULL && p == NULL)
            || (dh->g == NULL && g == NULL))
    {
        return 0;
    }

    if (p != NULL)
    {
        BN_free(dh->p);
        dh->p = p;
    }
    if (q != NULL)
    {
        BN_free(dh->q);
        dh->q = q;
    }
    if (g != NULL)
    {
        BN_free(dh->g);
        dh->g = g;
    }

    if (q != NULL)
    {
        dh->length = BN_num_bits(q);
    }

    return 1;
}
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */



/*****************************************************************************/
static void
dump_error_stack(const char *prefix)
{
    /* Dump the error stack from the SSL library */
    unsigned long code;
    char buff[256];
    while ((code = ERR_get_error()) != 0L)
    {
        ERR_error_string_n(code, buff, sizeof(buff));
        LOG(LOG_LEVEL_ERROR, "%s: %s", prefix, buff);
    }
}

/*****************************************************************************/
/* As above, but used for TLS connection errors where only the first
   error is logged */

static void
dump_ssl_error_stack(struct ssl_tls *self)
{
    if (!self->error_logged)
    {
        dump_error_stack("SSL");
        self->error_logged = 1;
    }
}

/*****************************************************************************/
int
ssl_init(void)
{
    SSL_load_error_strings();
    SSL_library_init();

    return 0;
}

/*****************************************************************************/
int
ssl_finish(void)
{
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
    /* De-allocate any allocated globals
     * For OpenSSL 3, these can all safely be passed a NULL pointer */

    EVP_MD_free(g_md_md5);
    g_md_md5 = NULL;
    EVP_MD_free(g_md_sha1);
    g_md_sha1 = NULL;
    EVP_CIPHER_free(g_cipher_des_ede3_cbc);
    g_cipher_des_ede3_cbc = NULL;
    EVP_MAC_free(g_mac_hmac);
    g_mac_hmac = NULL;
#endif

#ifdef HAS_KEYLOG_CALLBACK
    free(g_keylog_filename);
    g_keylog_filename = NULL;
#endif
    return 0;
}

/*****************************************************************************/
int
ssl_set_pre_master_secret_logfile(const char *filename)
{
    int rv = 0;
#ifdef HAS_KEYLOG_CALLBACK
    int fd = -1;

    /* Remove any existing setting */
    free(g_keylog_filename);
    g_keylog_filename = NULL;

    if (filename == NULL || filename[0] == '\0')
    {
        /* all done */
    }
    else if (filename[0] != '/')
    {
        LOG(LOG_LEVEL_ERROR, "TLS pre-master log file must start with '/'");
    }
    else if ((fd = g_file_open_rw(filename)) < 0)
    {
        /* Can't open file for writing. We'll log a single error here
         * rather than lots of errors in the callback */

        LOG(LOG_LEVEL_ERROR, "Can't write TLS pre-master secrets to %s [%s]",
            filename, g_get_strerror());
    }
    else if (g_file_close(fd) != 0)
    {
        /* Ignore this one */
    }
    else if (g_chmod_hex(filename, 0x640) != 0)
    {
        LOG(LOG_LEVEL_WARNING, "Can't set expected permissions on %s [%s]",
            filename, g_get_strerror());

    }
    else if ((g_keylog_filename = g_strdup(filename)) == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "Out of memory setting TLS pre-master log");
    }
    else
    {
        rv = 1;
    }
#else
    LOG(LOG_LEVEL_WARNING,
        "This system is unable to log TLS pre-master secrets");
#endif
    return rv;
}

/*****************************************************************************/
/* Log the pre-master secret for debugging purposes */
#ifdef HAS_KEYLOG_CALLBACK
static void
log_pre_master_secret(const SSL *ssl, const char *line)
{
    if (g_keylog_filename != NULL && g_keylog_filename[0] == '/')
    {
        int fd = g_file_open_rw(g_keylog_filename);
        if (fd < 0)
        {
            LOG(LOG_LEVEL_ERROR, "Can't write pre-master secret to %s [ %s]",
                g_keylog_filename, g_get_strerror());
        }
        else
        {
            g_file_seek_end(fd, 0);
            g_file_write(fd, line, strlen(line));
            g_file_write(fd, "\n"1);
            (void)g_file_close(fd);
        }
    }
}
#endif // HAS_KEYLOG_CALLBACK

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

/* rc4 stuff
 *
 * For OpenSSL 3.0, the rc4 encryption algorithm is only provided by the
 * legacy provider (see crypto(7)). Since RC4 is so simple, we can implement
 * it directly rather than having to load the legacy provider.  This will
 * avoids problems if running on a system where openssl has been built
 * without the legacy provider */


#if OPENSSL_VERSION_NUMBER >= 0x30000000L
struct rc4_data
{
    /* See https://en.wikipedia.org/wiki/RC4 */
    unsigned char S[256];
    int i;
    int j;
};
#endif

/*****************************************************************************/
void *
ssl_rc4_info_create(void)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    return g_malloc(sizeof(RC4_KEY), 1);
#else
    return g_malloc(sizeof(struct rc4_data), 1);
#endif
}

/*****************************************************************************/
void
ssl_rc4_info_delete(void *rc4_info)
{
    g_free(rc4_info);
}

/*****************************************************************************/
void
ssl_rc4_set_key(void *rc4_info, const char *key, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    RC4_set_key((RC4_KEY *)rc4_info, len, (tui8 *)key);
#else
    unsigned char *S = ((struct rc4_data *)rc4_info)->S;
    int i;
    int j = 0;
    unsigned char t;
    for (i = 0 ; i < 256; ++i)
    {
        S[i] = i;
    }
    for (i = 0 ; i < 256; ++i)
    {
        j = (j + S[i] + key[i % len]) & 0xff;
        t = S[i];
        S[i] = S[j];
        S[j] = t;
    }
    ((struct rc4_data *)rc4_info)->i = 0;
    ((struct rc4_data *)rc4_info)->j = 0;
#endif
}

/*****************************************************************************/
void
ssl_rc4_crypt(void *rc4_info, char *data, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    RC4((RC4_KEY *)rc4_info, len, (tui8 *)data, (tui8 *)data);
#else
    unsigned char *S = ((struct rc4_data *)rc4_info)->S;
    int i = ((struct rc4_data *)rc4_info)->i;
    int j = ((struct rc4_data *)rc4_info)->j;
    unsigned char *p = (unsigned char *)data;
    unsigned char t;
    unsigned char k;

    /*
     * Do some loop-unrolling for performance. Here are the steps
     * for each byte */

#define RC4_ROUND \
    i = (i + 1) & 0xff; \
    j = (j + S[i]) & 0xff; \
    t = S[i]; \
    S[i] = S[j]; \
    S[j] = t; \
    k = S[(S[i] + S[j]) & 0xff]; \
    *p++ ^= k

    while (len >= 8)
    {
        RC4_ROUND;
        RC4_ROUND;
        RC4_ROUND;
        RC4_ROUND;
        RC4_ROUND;
        RC4_ROUND;
        RC4_ROUND;
        RC4_ROUND;
        len -= 8;
    }
    while (len-- > 0)
    {
        RC4_ROUND;
    }

    ((struct rc4_data *)rc4_info)->i = i;
    ((struct rc4_data *)rc4_info)->j = j;
#endif
}

/* sha1 stuff */

/*****************************************************************************/
void *
ssl_sha1_info_create(void)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    return g_malloc(sizeof(SHA_CTX), 1);
#else
    /*
     * If we can't get the digest loaded, there's a problem with the
     * library providers, so there's no point in us returning anything useful.
     * If we do load the digest, it's used later */

    if (g_md_sha1 == NULL)
    {
        if ((g_md_sha1 = EVP_MD_fetch(NULL, "sha1", NULL)) == NULL)
        {
            dump_error_stack("sha1");
            return NULL;
        }
    }

    return (void *)EVP_MD_CTX_new();
#endif
}

/*****************************************************************************/
void
ssl_sha1_info_delete(void *sha1_info)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    g_free(sha1_info);
#else
    EVP_MD_CTX_free((EVP_MD_CTX *)sha1_info);
#endif
}

/*****************************************************************************/
void
ssl_sha1_clear(void *sha1_info)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    SHA1_Init((SHA_CTX *)sha1_info);
#else
    if (sha1_info != NULL)
    {
        EVP_DigestInit_ex((EVP_MD_CTX *)sha1_info, g_md_sha1, NULL);
    }
#endif
}

/*****************************************************************************/
void
ssl_sha1_transform(void *sha1_info, const char *data, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    SHA1_Update((SHA_CTX *)sha1_info, data, len);
#else
    if (sha1_info != NULL)
    {
        EVP_DigestUpdate((EVP_MD_CTX *)sha1_info, data, len);
    }
#endif
}

/*****************************************************************************/
void
ssl_sha1_complete(void *sha1_info, char *data)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    SHA1_Final((tui8 *)data, (SHA_CTX *)sha1_info);
#else
    if (sha1_info != NULL)
    {
        EVP_DigestFinal_ex((EVP_MD_CTX *)sha1_info, (unsigned char *)data,
                           NULL);
    }
#endif
}

/* md5 stuff */

/*****************************************************************************/
void *
ssl_md5_info_create(void)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    return g_malloc(sizeof(MD5_CTX), 1);
#else
    /*
     * If we can't get the digest loaded, there's a problem with the
     * library providers, so there's no point in us returning anything useful.
     * If we do load the digest, it's used later */

    if (g_md_md5 == NULL)
    {
        if ((g_md_md5 = EVP_MD_fetch(NULL, "md5", NULL)) == NULL)
        {
            dump_error_stack("md5");
            return NULL;
        }
    }

    return (void *)EVP_MD_CTX_new();
#endif
}

/*****************************************************************************/
void
ssl_md5_info_delete(void *md5_info)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    g_free(md5_info);
#else
    EVP_MD_CTX_free((EVP_MD_CTX *)md5_info);
#endif
}

/*****************************************************************************/
void
ssl_md5_clear(void *md5_info)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    MD5_Init((MD5_CTX *)md5_info);
#else
    if (md5_info != NULL)
    {
        EVP_DigestInit_ex((EVP_MD_CTX *)md5_info, g_md_md5, NULL);
    }
#endif
}

/*****************************************************************************/
void
ssl_md5_transform(void *md5_info, const char *data, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    MD5_Update((MD5_CTX *)md5_info, data, len);
#else
    if (md5_info != NULL)
    {
        EVP_DigestUpdate((EVP_MD_CTX *)md5_info, data, len);
    }
#endif
}

/*****************************************************************************/
void
ssl_md5_complete(void *md5_info, char *data)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    MD5_Final((tui8 *)data, (MD5_CTX *)md5_info);
#else
    if (md5_info != NULL)
    {
        EVP_DigestFinal_ex((EVP_MD_CTX *)md5_info, (unsigned char *)data, NULL);
    }
#endif
}

/* FIPS stuff */

/*****************************************************************************/
void *
ssl_des3_encrypt_info_create(const char *key, const char *ivec)
{
    EVP_CIPHER_CTX *des3_ctx;
    const tui8 *lkey;
    const tui8 *livec;

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
    /*
     * For these versions of OpenSSL, there are no long-term guarantees the
     * DES3 cipher will be available. We'll try to load it here so we
     * can log any errors */

    if (g_cipher_des_ede3_cbc == NULL)
    {
        g_cipher_des_ede3_cbc = EVP_CIPHER_fetch(NULL, "des-ede3-cbc", NULL);
        if (g_cipher_des_ede3_cbc == NULL)
        {
            dump_error_stack("DES-EDE3-CBC");
            return NULL;
        }
    }
#endif

    des3_ctx = EVP_CIPHER_CTX_new();
    lkey = (const tui8 *) key;
    livec = (const tui8 *) ivec;
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    EVP_EncryptInit_ex(des3_ctx, EVP_des_ede3_cbc(), NULL, lkey, livec);
#else
    EVP_EncryptInit_ex(des3_ctx, g_cipher_des_ede3_cbc, NULL, lkey, livec);
#endif
    EVP_CIPHER_CTX_set_padding(des3_ctx, 0);
    return des3_ctx;
}

/*****************************************************************************/
void *
ssl_des3_decrypt_info_create(const char *key, const char *ivec)
{
    EVP_CIPHER_CTX *des3_ctx;
    const tui8 *lkey;
    const tui8 *livec;

#if OPENSSL_VERSION_NUMBER >= 0x30000000L
    /*
     * For these versions of OpenSSL, there are no long-term guarantees the
     * DES3 cipher will be available. We'll try to load it here so we
     * can log any errors */

    if (g_cipher_des_ede3_cbc == NULL)
    {
        g_cipher_des_ede3_cbc = EVP_CIPHER_fetch(NULL, "des-ede3-cbc", NULL);
        if (g_cipher_des_ede3_cbc == NULL)
        {
            dump_error_stack("DES-EDE3-CBC");
            return NULL;
        }
    }
#endif

    des3_ctx = EVP_CIPHER_CTX_new();
    lkey = (const tui8 *) key;
    livec = (const tui8 *) ivec;
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    EVP_DecryptInit_ex(des3_ctx, EVP_des_ede3_cbc(), NULL, lkey, livec);
#else
    EVP_DecryptInit_ex(des3_ctx, g_cipher_des_ede3_cbc, NULL, lkey, livec);
#endif
    EVP_CIPHER_CTX_set_padding(des3_ctx, 0);
    return des3_ctx;
}

/*****************************************************************************/
void
ssl_des3_info_delete(void *des3)
{
    EVP_CIPHER_CTX *des3_ctx;

    des3_ctx = (EVP_CIPHER_CTX *) des3;
    if (des3_ctx != 0)
    {
        EVP_CIPHER_CTX_free(des3_ctx);
    }
}

/*****************************************************************************/
int
ssl_des3_encrypt(void *des3, int length, const char *in_data, char *out_data)
{
    EVP_CIPHER_CTX *des3_ctx;
    int len;
    const tui8 *lin_data;
    tui8 *lout_data;

    des3_ctx = (EVP_CIPHER_CTX *) des3;
    if (des3_ctx != NULL)
    {
        lin_data = (const tui8 *) in_data;
        lout_data = (tui8 *) out_data;
        len = 0;
        EVP_EncryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
    }
    return 0;
}

/*****************************************************************************/
int
ssl_des3_decrypt(void *des3, int length, const char *in_data, char *out_data)
{
    EVP_CIPHER_CTX *des3_ctx;
    int len;
    const tui8 *lin_data;
    tui8 *lout_data;

    des3_ctx = (EVP_CIPHER_CTX *) des3;
    if (des3_ctx != NULL)
    {
        lin_data = (const tui8 *) in_data;
        lout_data = (tui8 *) out_data;
        len = 0;
        EVP_DecryptUpdate(des3_ctx, lout_data, &len, lin_data, length);
    }
    return 0;
}

/*****************************************************************************/
void *
ssl_hmac_info_create(void)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    return (HMAC_CTX *)HMAC_CTX_new();
#else
    /* Need a MAC algorithm loaded */
    if (g_mac_hmac == NULL)
    {
        if ((g_mac_hmac = EVP_MAC_fetch(NULL, "hmac", NULL)) == NULL)
        {
            dump_error_stack("hmac");
            return NULL;
        }
    }

    return (void *)EVP_MAC_CTX_new(g_mac_hmac);
#endif
}

/*****************************************************************************/
void
ssl_hmac_info_delete(void *hmac)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    HMAC_CTX *hmac_ctx;

    hmac_ctx = (HMAC_CTX *) hmac;
    if (hmac_ctx != 0)
    {
        HMAC_CTX_free(hmac_ctx);
    }
#else
    EVP_MAC_CTX_free((EVP_MAC_CTX *)hmac);
#endif
}

/*****************************************************************************/
void
ssl_hmac_sha1_init(void *hmac, const char *data, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    HMAC_CTX *hmac_ctx;

    hmac_ctx = (HMAC_CTX *) hmac;
    HMAC_Init_ex(hmac_ctx, data, len, EVP_sha1(), NULL);
#else
    if (hmac != NULL)
    {
        char digest[] = "sha1";
        OSSL_PARAM params[3];
        size_t n = 0;
        params[n++] = OSSL_PARAM_construct_utf8_string("digest", digest, 0);
        params[n++] = OSSL_PARAM_construct_end();
        if (EVP_MAC_init((EVP_MAC_CTX *)hmac, (unsigned char *)data,
                         len, params) == 0)
        {
            dump_error_stack("hmac-sha1");
        }
    }
#endif
}

/*****************************************************************************/
void
ssl_hmac_transform(void *hmac, const char *data, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    HMAC_CTX *hmac_ctx;
    const tui8 *ldata;

    hmac_ctx = (HMAC_CTX *) hmac;
    ldata = (const tui8 *) data;
    HMAC_Update(hmac_ctx, ldata, len);
#else
    if (hmac != NULL)
    {
        EVP_MAC_update((EVP_MAC_CTX *)hmac, (unsigned char *)data, len);
    }
#endif
}

/*****************************************************************************/
void
ssl_hmac_complete(void *hmac, char *data, int len)
{
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    HMAC_CTX *hmac_ctx;
    tui8 *ldata;
    tui32 llen;

    hmac_ctx = (HMAC_CTX *) hmac;
    ldata = (tui8 *) data;
    llen = len;
    HMAC_Final(hmac_ctx, ldata, &llen);
#else
    if (hmac != NULL)
    {
        EVP_MAC_final((EVP_MAC_CTX *)hmac, (unsigned char *)data, NULL, len);
    }
#endif
}

/*****************************************************************************/
static void
ssl_reverse_it(char *p, int len)
{
    int i;
    int j;
    char temp;

    i = 0;
    j = len - 1;

    while (i < j)
    {
        temp = p[i];
        p[i] = p[j];
        p[j] = temp;
        i++;
        j--;
    }
}

/*****************************************************************************/
int
ssl_mod_exp(char *out, int out_len, const char *in, int in_len,
            const char *mod, int mod_len, const char *exp, int exp_len)
{
    BN_CTX *ctx;
    BIGNUM *lmod;
    BIGNUM *lexp;
    BIGNUM *lin;
    BIGNUM *lout;
    int rv;
    char *l_out;
    char *l_in;
    char *l_mod;
    char *l_exp;

    l_out = (char *)g_malloc(out_len, 1);
    l_in = (char *)g_malloc(in_len, 1);
    l_mod = (char *)g_malloc(mod_len, 1);
    l_exp = (char *)g_malloc(exp_len, 1);
    g_memcpy(l_in, in, in_len);
    g_memcpy(l_mod, mod, mod_len);
    g_memcpy(l_exp, exp, exp_len);
    ssl_reverse_it(l_in, in_len);
    ssl_reverse_it(l_mod, mod_len);
    ssl_reverse_it(l_exp, exp_len);
    ctx = BN_CTX_new();
    lmod = BN_new();
    lexp = BN_new();
    lin = BN_new();
    lout = BN_new();
    BN_bin2bn((tui8 *)l_mod, mod_len, lmod);
    BN_bin2bn((tui8 *)l_exp, exp_len, lexp);
    BN_bin2bn((tui8 *)l_in, in_len, lin);
    BN_mod_exp(lout, lin, lexp, lmod, ctx);
    rv = BN_bn2bin(lout, (tui8 *)l_out);

    if (rv <= out_len)
    {
        ssl_reverse_it(l_out, rv);
        g_memcpy(out, l_out, out_len);
    }
    else
    {
        rv = 0;
    }

    BN_free(lin);
    BN_free(lout);
    BN_free(lexp);
    BN_free(lmod);
    BN_CTX_free(ctx);
    g_free(l_out);
    g_free(l_in);
    g_free(l_mod);
    g_free(l_exp);
    return rv;
}

/*****************************************************************************/
/* returns error
   generates a new rsa key
   exp is passed in and mod and pri are passed out */

int
ssl_gen_key_xrdp1(int key_size_in_bits, const char *exp, int exp_len,
                  char *mod, int mod_len, char *pri, int pri_len)
{
    BIGNUM *my_e;
    char *lexp;
    char *lmod;
    char *lpri;
    int error;
    int len;
    int diff;

    if ((exp_len != 4) || ((mod_len != 64) && (mod_len != 256)) ||
            ((pri_len != 64) && (pri_len != 256)))
    {
        return 1;
    }

    diff = 0;
    lexp = (char *)g_malloc(exp_len, 1);
    lmod = (char *)g_malloc(mod_len, 1);
    lpri = (char *)g_malloc(pri_len, 1);
    g_memcpy(lexp, exp, exp_len);
    ssl_reverse_it(lexp, exp_len);
    my_e = BN_new();
    BN_bin2bn((tui8 *)lexp, exp_len, my_e);

#if OPENSSL_VERSION_NUMBER < 0x30000000L
    const BIGNUM *n = NULL;
    const BIGNUM *d = NULL;
    RSA *my_key = RSA_new();
    error = RSA_generate_key_ex(my_key, key_size_in_bits, my_e, 0) == 0;

    /* After this call, n and d point directly into my_key, and are valid
     * until my_key is free'd */

    RSA_get0_key(my_key, &n, NULL, &d);
#else
    BIGNUM *n = NULL;
    BIGNUM *d = NULL;
    OSSL_PARAM params[] =
    {
        OSSL_PARAM_construct_int("bits", &key_size_in_bits),
        OSSL_PARAM_construct_end()
    };
    EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
    EVP_PKEY *pkey = NULL;

    if (pctx != NULL &&
            EVP_PKEY_keygen_init(pctx) > 0 &&
            EVP_PKEY_CTX_set_params(pctx, params) > 0 &&
            EVP_PKEY_generate(pctx, &pkey) > 0 &&
            EVP_PKEY_get_bn_param(pkey, "n", &n) > 0 &&
            EVP_PKEY_get_bn_param(pkey, "d", &d) > 0)
    {
        error = 0;
    }
    else
    {
        error = 1;
    }

    EVP_PKEY_CTX_free(pctx);
    EVP_PKEY_free(pkey);
#endif

    if (error == 0)
    {
        len = BN_num_bytes(n);
        error = (len < 1) || (len > mod_len);
        diff = mod_len - len;
    }

    if (error == 0)
    {
        BN_bn2bin(n, (tui8 *)(lmod + diff));
        ssl_reverse_it(lmod, mod_len);
    }

    if (error == 0)
    {
        len = BN_num_bytes(d);
        error = (len < 1) || (len > pri_len);
        diff = pri_len - len;
    }

    if (error == 0)
    {
        BN_bn2bin(d, (tui8 *)(lpri + diff));
        ssl_reverse_it(lpri, pri_len);
    }

    if (error == 0)
    {
        g_memcpy(mod, lmod, mod_len);
        g_memcpy(pri, lpri, pri_len);
    }

    BN_free(my_e);
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    RSA_free(my_key);
#else
    BN_free(n);
    BN_clear_free(d);
#endif
    g_free(lexp);
    g_free(lmod);
    g_free(lpri);
    return error;
}

/*****************************************************************************/
/** static DH parameter, can be used if no custom parameter is specified
see also
 * https://wiki.openssl.org/index.php/Diffie-Hellman_parameters
 * https://wiki.openssl.org/index.php/Manual:SSL_CTX_set_tmp_dh_callback(3)
 *
 * We dont do this for OpenSSL 3 - we use SSL_CTX_set_dh_auto() instead, as this
 * can cater for different key sizes on the certificate
*/

#if OPENSSL_VERSION_NUMBER < 0x30000000L
static DH *ssl_get_dh2236()
{
    static unsigned char dh2236_p[] =
    {
        0x0E, 0xF8, 0x69, 0x0B, 0x35, 0x2F, 0x62, 0x59, 0xF7, 0xAF, 0x4E, 0x19,
        0xB5, 0x9B, 0xD2, 0xEB, 0x33, 0x78, 0x1D, 0x43, 0x1D, 0xB6, 0xE4, 0xA3,
        0x63, 0x47, 0x6A, 0xD4, 0xA8, 0x28, 0x11, 0x8C, 0x3F, 0xC8, 0xF1, 0x32,
        0x2B, 0x5D, 0x9F, 0xF8, 0xA6, 0xCA, 0x21, 0x71, 0xDE, 0x30, 0xD7, 0xB5,
        0xD6, 0xA4, 0xC2, 0xEE, 0xC0, 0x49, 0x30, 0xE7, 0x8C, 0x9B, 0x1A, 0x5A,
        0x08, 0x2A, 0x11, 0x84, 0xE2, 0xC8, 0x36, 0x6C, 0xDC, 0x06, 0x79, 0x59,
        0x51, 0xA4, 0xA0, 0x8F, 0xE1, 0x20, 0x94, 0x80, 0xAC, 0x6D, 0xFD, 0x3B,
        0xA6, 0xA6, 0x70, 0x51, 0x93, 0x59, 0x28, 0x51, 0x54, 0xA3, 0xC5, 0x15,
        0x44, 0x2C, 0x12, 0xE7, 0x95, 0x62, 0x0E, 0x65, 0x2F, 0x8C, 0x0D, 0xF8,
        0x63, 0x52, 0x00, 0x2A, 0xA5, 0xD7, 0x59, 0xEF, 0x13, 0x18, 0x33, 0x25,
        0xBC, 0xAD, 0xC8, 0x0A, 0x72, 0x8D, 0x26, 0x63, 0xD5, 0xB3, 0xBC, 0x43,
        0x35, 0x0B, 0x5D, 0xC7, 0xCA, 0x45, 0x17, 0x06, 0x24, 0x71, 0xCA, 0x20,
        0x73, 0xE8, 0x18, 0xD3, 0x8E, 0xE9, 0xE9, 0x8F, 0x67, 0xC0, 0x2C, 0x14,
        0x7E, 0x41, 0x18, 0x6C, 0x74, 0x72, 0x56, 0x34, 0xC0, 0xDB, 0xDD, 0x85,
        0x8B, 0xE0, 0x99, 0xE8, 0x5E, 0xC8, 0xF7, 0xD1, 0x0C, 0xF8, 0x83, 0x34,
        0x37, 0x9E, 0x01, 0xDF, 0x1C, 0xD9, 0xE9, 0x95, 0xC1, 0x4C, 0x64, 0x37,
        0x9B, 0xF5, 0x8F, 0x99, 0x97, 0x55, 0x68, 0x2E, 0x23, 0xB0, 0x35, 0xF3,
        0xA5, 0x97, 0x92, 0xA0, 0x6D, 0xB4, 0xF8, 0xD8, 0x47, 0xCE, 0x3F, 0x0B,
        0x36, 0x0E, 0xEB, 0x13, 0x15, 0xFD, 0x4F, 0x98, 0x4F, 0x14, 0x26, 0xE2,
        0xAC, 0xD9, 0x42, 0xC6, 0x43, 0x8A, 0x95, 0x6B, 0x2B, 0x44, 0x38, 0x7F,
        0x60, 0x97, 0x77, 0xD8, 0x7C, 0x6F, 0x5D, 0x62, 0x7C, 0xE1, 0xC8, 0x83,
        0x12, 0x8B, 0x5E, 0x5E, 0xC7, 0x5E, 0xD5, 0x60, 0xF3, 0x2F, 0xFC, 0xFE,
        0x70, 0xAC, 0x58, 0x3A, 0x3C, 0x18, 0x15, 0x54, 0x84, 0xA8, 0xAA, 0x41,
        0x26, 0x7B, 0xE0, 0xA3,
    };
    static unsigned char dh2236_g[] =
    {
        0x02,
    };

    DH *dh = DH_new();
    if (dh == NULL)
    {
        return NULL;
    }

    BIGNUM *p = BN_bin2bn(dh2236_p, sizeof(dh2236_p), NULL);
    BIGNUM *g = BN_bin2bn(dh2236_g, sizeof(dh2236_g), NULL);
    if (p == NULL || g == NULL)
    {
        BN_free(p);
        BN_free(g);
        DH_free(dh);
        return NULL;
    }

    // p, g are freed later by DH_free()
    if (0 == DH_set0_pqg(dh, p, NULL, g))
    {
        BN_free(p);
        BN_free(g);
        DH_free(dh);
        return NULL;
    }

    return dh;
}
#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */

/*****************************************************************************/
struct ssl_tls *
ssl_tls_create(struct trans *trans, const char *key, const char *cert)
{
    struct ssl_tls *self;
    int pid;
    char buf[1024];

    self = (struct ssl_tls *) g_malloc(sizeof(struct ssl_tls), 1);
    if (self != NULL)
    {
        self->trans = trans;
        self->cert = (char *) cert;
        self->key = (char *) key;
        pid = g_getpid();
        g_snprintf(buf, 1024"xrdp_%8.8x_tls_rwo", pid);
        self->rwo = g_create_wait_obj(buf);
    }

    return self;
}
/*****************************************************************************/
static int
ssl_tls_log_error(struct ssl_tls *self, const char *func, int value)
{
    int result = 1;
    int ssl_error = SSL_get_error(self->ssl, value);

    if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE)
    {
        result = 0;
    }
    else if (!self->error_logged)
    {
        switch (ssl_error)
        {
            case SSL_ERROR_ZERO_RETURN:
                LOG(LOG_LEVEL_ERROR, "%s: Server closed TLS connection", func);
                break;

            case SSL_ERROR_SYSCALL:
                LOG(LOG_LEVEL_ERROR, "%s: I/O error", func);
                break;

            case SSL_ERROR_SSL:
                LOG(LOG_LEVEL_ERROR, "%s: Failure in SSL library "
                    "(protocol error?)", func);
                break;

            default:
                LOG(LOG_LEVEL_ERROR, "%s: Unknown SSL error", func);
                break;
        }

        dump_ssl_error_stack(self); /* Sets self->error_logged */
    }

    return result;
}

/**************************************************************************//**
 * Log an attempt to use an encrypted file
 *
 * For example, a private key could have a password set on it. We don't
 * support this.
 */
static int
log_encrypted_file_unsupported(char *buf, int size, int rwflag, void *u)
{
    LOG(LOG_LEVEL_ERROR, "Encryption is not supported for %s",
        (const char *)u);
    return -1/* See pem_password_cb(3ssl) */
}

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

int
ssl_tls_accept(struct ssl_tls *self, long ssl_protocols,
               const char *tls_ciphers)
{
    int connection_status;
    long options = 0;

    ERR_clear_error();

    /**
     * SSL_OP_NO_SSLv2
     * SSLv3 is used by, eg. Microsoft RDC for Mac OS X.
     */

    options |= SSL_OP_NO_SSLv2;

    /**
     * Disable SSL protocols not listed in ssl_protocols.
     */

    options |= ssl_protocols;


#if defined(SSL_OP_NO_COMPRESSION)
    /**
     * SSL_OP_NO_COMPRESSION:
     *
     * The Microsoft RDP server does not advertise support
     * for TLS compression, but alternative servers may support it.
     * This was observed between early versions of the FreeRDP server
     * and the FreeRDP client, and caused major performance issues,
     * which is why we're disabling it.
     */

    options |= SSL_OP_NO_COMPRESSION;
#endif

    /**
     * SSL_OP_TLS_BLOCK_PADDING_BUG:
     *
     * The Microsoft RDP server does *not* support TLS padding.
     * It absolutely needs to be disabled otherwise it won't work.
     */

    options |= SSL_OP_TLS_BLOCK_PADDING_BUG;

    /**
     * SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS:
     *
     * Just like TLS padding, the Microsoft RDP server does not
     * support empty fragments. This needs to be disabled.
     */

    options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;

    self->ctx = SSL_CTX_new(SSLv23_server_method());
    if (self->ctx == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "Unable to negotiate a TLS connection with the client");
        dump_ssl_error_stack(self);
        return 1;
    }

    /* set context options */
    SSL_CTX_set_mode(self->ctx,
                     SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER |
                     SSL_MODE_ENABLE_PARTIAL_WRITE);
    SSL_CTX_set_options(self->ctx, options);

    /* set DH parameters */
#if OPENSSL_VERSION_NUMBER < 0x30000000L
    DH *dh = ssl_get_dh2236();
    if (dh == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "Unable to generate DHE parameters for TLS");
        return 1;
    }

    if (SSL_CTX_set_tmp_dh(self->ctx, dh) != 1)
    {
        LOG(LOG_LEVEL_ERROR, "Unable to setup DHE parameters for TLS");
        dump_ssl_error_stack(self);
        return 1;
    }
    DH_free(dh); // ok to free, copied into ctx by SSL_CTX_set_tmp_dh()
#endif

#if (OPENSSL_VERSION_NUMBER >= 0x10000020L) && \
    OPENSSL_VERSION_NUMBER < (0x10100000L)
    // SSL_CTX_set_ecdh_auto() added in OpenSSL 1.0.2 and
    // removed for OpenSSL 1.1.0
    if (!SSL_CTX_set_ecdh_auto(self->ctx, 1))
    {
        LOG(LOG_LEVEL_WARNING, "TLS ecdh auto failed to be enabled");
    }
#endif

    if (g_strlen(tls_ciphers) > 1)
    {
        LOG(LOG_LEVEL_TRACE, "tls_ciphers=%s", tls_ciphers);
        if (SSL_CTX_set_cipher_list(self->ctx, tls_ciphers) == 0)
        {
            LOG(LOG_LEVEL_ERROR, "Invalid TLS cipher options %s", tls_ciphers);
            dump_ssl_error_stack(self);
            return 1;
        }
    }

    SSL_CTX_set_read_ahead(self->ctx, 0);

    /*
     * We don't currently handle encrypted private keys - set a callback
     * to tell the user if one is provided */

    SSL_CTX_set_default_passwd_cb(self->ctx, log_encrypted_file_unsupported);
    SSL_CTX_set_default_passwd_cb_userdata(self->ctx, self->key);

    if (SSL_CTX_use_PrivateKey_file(self->ctx, self->key, SSL_FILETYPE_PEM)
            <= 0)
    {
        LOG(LOG_LEVEL_ERROR, "Error loading TLS private key from %s", self->key);
        dump_ssl_error_stack(self);
        return 1;
    }
    SSL_CTX_set_default_passwd_cb(self->ctx, NULL);
    SSL_CTX_set_default_passwd_cb_userdata(self->ctx, NULL);

    if (SSL_CTX_use_certificate_chain_file(self->ctx, self->cert) <= 0)
    {
        LOG(LOG_LEVEL_ERROR, "Error loading TLS certificate chain from %s", self->cert);
        dump_ssl_error_stack(self);
        return 1;
    }

    /*
     * Don't call SSL_check_private_key() for openSSL prior to 1.0.2, as
     * certificate chains are not handled in the same way - see
     * SSL_CTX_check_private_key(3ssl) */

#if OPENSSL_VERSION_NUMBER >= 0x10002000L
    if (!SSL_CTX_check_private_key(self->ctx))
    {
        LOG(LOG_LEVEL_ERROR, "Private key %s and certificate %s do not match",
            self->key, self->cert);
        dump_ssl_error_stack(self);
        return 1;
    }
#endif

#ifdef HAS_KEYLOG_CALLBACK
    SSL_CTX_set_keylog_callback(self->ctx, log_pre_master_secret);
#endif // HAS_KEYLOG_CALLBACK

    self->ssl = SSL_new(self->ctx);

    if (self->ssl == NULL)
    {
        LOG(LOG_LEVEL_ERROR, "Unable to create an SSL structure");
        dump_ssl_error_stack(self);
        return 1;
    }

    if (SSL_set_fd(self->ssl, self->trans->sck) < 1)
    {
        LOG(LOG_LEVEL_ERROR, "Unable to set up an SSL structure on fd %d",
            (int)self->trans->sck);
        dump_ssl_error_stack(self);
        return 1;
    }

    while (1)
    {
        /*
         * Make sure the error queue is clear before (re-) attempting the
         * accept. If the accept is successful, the error queue will
         * remain clear for normal SSL operation */

        ERR_clear_error();

        connection_status = SSL_accept(self->ssl);

        if (connection_status <= 0)
        {
            if (ssl_tls_log_error(self, "SSL_accept", connection_status))
            {
                return 1;
            }
            /**
             * retry when SSL_get_error returns:
             *     SSL_ERROR_WANT_READ
             *     SSL_ERROR_WANT_WRITE
             */

            switch (SSL_get_error(self->ssl, connection_status))
            {
                case SSL_ERROR_WANT_READ:
                    g_sck_can_recv(self->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
                    break;
                case SSL_ERROR_WANT_WRITE:
                    g_sck_can_send(self->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
                    break;
            }
        }
        else
        {
            break;
        }
    }

    LOG(LOG_LEVEL_TRACE, "TLS connection accepted");

    return 0;
}

/*****************************************************************************/
/* returns error, */
int
ssl_tls_disconnect(struct ssl_tls *self)
{
    int status;

    if (self == NULL)
    {
        return 0;
    }
    if (self->ssl == NULL)
    {
        return 0;
    }
    status = SSL_shutdown(self->ssl);
    if (status != 1)
    {
        status = SSL_shutdown(self->ssl);
        if (status <= 0)
        {
            if (ssl_tls_log_error(self, "SSL_shutdown", status))
            {
                return 1;
            }
            /**
             * retry when SSL_get_error returns:
             *     SSL_ERROR_WANT_READ
             *     SSL_ERROR_WANT_WRITE
             */

        }
    }
    return 0;
}

/*****************************************************************************/
void
ssl_tls_delete(struct ssl_tls *self)
{
    if (self != NULL)
    {
        if (self->ssl)
        {
            SSL_free(self->ssl);
        }

        if (self->ctx)
        {
            SSL_CTX_free(self->ctx);
        }

        g_delete_wait_obj(self->rwo);

        g_free(self);
    }
}

/*****************************************************************************/
int
ssl_tls_read(struct ssl_tls *tls, char *data, int length)
{
    int status;
    int break_flag;

    while (1)
    {
        status = SSL_read(tls->ssl, data, length);

        switch (SSL_get_error(tls->ssl, status))
        {
            case SSL_ERROR_NONE:
                break_flag = 1;
                break;

            /**
             * retry when SSL_get_error returns:
             *     SSL_ERROR_WANT_READ
             *     SSL_ERROR_WANT_WRITE
             */

            case SSL_ERROR_WANT_READ:
                g_sck_can_recv(tls->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
                continue;
            case SSL_ERROR_WANT_WRITE:
                g_sck_can_send(tls->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
                continue;

            /* socket closed */
            case SSL_ERROR_ZERO_RETURN:
                return 0;

            default:
                ssl_tls_log_error(tls, "SSL_read", status);
                status = -1;
                break_flag = 1;
                break;
        }

        if (break_flag)
        {
            break;
        }
    }

    if (SSL_pending(tls->ssl) > 0)
    {
        g_set_wait_obj(tls->rwo);
    }

    return status;
}

/*****************************************************************************/
int
ssl_tls_write(struct ssl_tls *tls, const char *data, int length)
{
    int status;
    int break_flag;

    while (1)
    {
        status = SSL_write(tls->ssl, data, length);

        switch (SSL_get_error(tls->ssl, status))
        {
            case SSL_ERROR_NONE:
                break_flag = 1;
                break;

            /**
             * retry when SSL_get_error returns:
             *     SSL_ERROR_WANT_READ
             *     SSL_ERROR_WANT_WRITE
             */

            case SSL_ERROR_WANT_READ:
                g_sck_can_recv(tls->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
                continue;
            case SSL_ERROR_WANT_WRITE:
                g_sck_can_send(tls->trans->sck, SSL_WANT_READ_WRITE_TIMEOUT);
                continue;

            /* socket closed */
            case SSL_ERROR_ZERO_RETURN:
                return 0;

            default:
                ssl_tls_log_error(tls, "SSL_write", status);
                status = -1;
                break_flag = 1;
                break;
        }

        if (break_flag)
        {
            break;
        }
    }

    return status;
}

/*****************************************************************************/
/* returns boolean */
int
ssl_tls_can_recv(struct ssl_tls *tls, int sck, int millis)
{
    if (SSL_pending(tls->ssl) > 0)
    {
        return 1;
    }
    g_reset_wait_obj(tls->rwo);
    return g_sck_can_recv(sck, millis);
}

/*****************************************************************************/
const char *
ssl_get_version(const struct ssl_tls *ssl)
{
    return SSL_get_version(ssl->ssl);
}

/*****************************************************************************/
const char *
ssl_get_cipher_name(const struct ssl_tls *ssl)
{
    return SSL_get_cipher_name(ssl->ssl);
}

/*****************************************************************************/
tintptr
ssl_get_rwo(const struct ssl_tls *ssl)
{
    return ssl->rwo;
}

/*****************************************************************************/
int
ssl_get_protocols_from_string(const char *str, long *ssl_protocols)
{
    long protocols;
    long bad_protocols;
    int rv;

    if ((str == NULL) || (ssl_protocols == NULL))
    {
        return 1;
    }
    rv = 0;
    protocols = 0;
#if defined(SSL_OP_NO_SSLv3)
    protocols |= SSL_OP_NO_SSLv3;
#endif
#if defined(SSL_OP_NO_TLSv1)
    protocols |= SSL_OP_NO_TLSv1;
#endif
#if defined(SSL_OP_NO_TLSv1_1)
    protocols |= SSL_OP_NO_TLSv1_1;
#endif
#if defined(SSL_OP_NO_TLSv1_2)
    protocols |= SSL_OP_NO_TLSv1_2;
#endif
#if defined(SSL_OP_NO_TLSv1_3)
    protocols |= SSL_OP_NO_TLSv1_3;
#endif
    bad_protocols = protocols;
    if (g_pos(str, ",TLSv1.3,") >= 0)
    {
#if defined(SSL_OP_NO_TLSv1_3)
        LOG(LOG_LEVEL_DEBUG, "TLSv1.3 enabled");
        protocols &= ~SSL_OP_NO_TLSv1_3;
#else
        LOG(LOG_LEVEL_WARNING,
            "TLSv1.3 enabled by config, "
            "but not supported by system OpenSSL");
        rv |= (1 << 6);
#endif
    }
    if (g_pos(str, ",TLSv1.2,") >= 0)
    {
#if defined(SSL_OP_NO_TLSv1_2)
        LOG(LOG_LEVEL_DEBUG, "TLSv1.2 enabled");
        protocols &= ~SSL_OP_NO_TLSv1_2;
#else
        LOG(LOG_LEVEL_WARNING,
            "TLSv1.2 enabled by config, "
            "but not supported by system OpenSSL");
        rv |= (1 << 1);
#endif
    }
    if (g_pos(str, ",TLSv1.1,") >= 0)
    {
#if defined(SSL_OP_NO_TLSv1_1)
        LOG(LOG_LEVEL_DEBUG, "TLSv1.1 enabled");
        protocols &= ~SSL_OP_NO_TLSv1_1;
#else
        LOG(LOG_LEVEL_WARNING,
            "TLSv1.1 enabled by config, "
            "but not supported by system OpenSSL");
        rv |= (1 << 2);
#endif
    }
    if (g_pos(str, ",TLSv1,") >= 0)
    {
#if defined(SSL_OP_NO_TLSv1)
        LOG(LOG_LEVEL_DEBUG, "TLSv1 enabled");
        protocols &= ~SSL_OP_NO_TLSv1;
#else
        LOG(LOG_LEVEL_WARNING,
            "TLSv1 enabled by config, "
            "but not supported by system OpenSSL");
        rv |= (1 << 3);
#endif
    }
    if (g_pos(str, ",SSLv3,") >= 0)
    {
#if defined(SSL_OP_NO_SSLv3)
        LOG(LOG_LEVEL_DEBUG, "SSLv3 enabled");
        protocols &= ~SSL_OP_NO_SSLv3;
#else
        LOG(LOG_LEVEL_WARNING,
            "SSLv3 enabled by config, "
            "but not supported by system OpenSSL");
        rv |= (1 << 4);
#endif
    }
    if (protocols == bad_protocols)
    {
        LOG(LOG_LEVEL_WARNING, "No SSL/TLS protocols enabled. "
            "At least one protocol should be enabled to accept "
            "TLS connections.");
        rv |= (1 << 5);
    }
    *ssl_protocols = protocols;
    return rv;
}

/*****************************************************************************/
const char
*get_openssl_version()
{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
    return SSLeay_version(SSLEAY_VERSION);
#else
    return OpenSSL_version(OPENSSL_VERSION);
#endif

}


Messung V0.5 in Prozent
C=89 H=93 G=90

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet am  2026-07-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.