commit
02838e530f
3 changed files with 114 additions and 33 deletions
|
@ -88,7 +88,7 @@
|
|||
static int httpPromoteToSSL(struct HttpConnection *http, const char *buf,
|
||||
int len) {
|
||||
if (http->ssl->enabled && !http->sslHndl) {
|
||||
debug("Switching to SSL (replaying %d+%d bytes)",
|
||||
debug("SSL: switching to SSL (replaying %d+%d bytes)",
|
||||
http->partialLength, len);
|
||||
if (http->partial && len > 0) {
|
||||
check(http->partial = realloc(http->partial,
|
||||
|
@ -102,6 +102,8 @@ static int httpPromoteToSSL(struct HttpConnection *http, const char *buf,
|
|||
http->partial ? http->partialLength : len);
|
||||
if (http->sslHndl) {
|
||||
check(!rc);
|
||||
// Reset renegotiations count for connections promoted to SSL.
|
||||
http->ssl->renegotiationCount = 0;
|
||||
SSL_set_app_data(http->sslHndl, http);
|
||||
}
|
||||
free(http->partial);
|
||||
|
@ -138,6 +140,13 @@ static ssize_t httpRead(struct HttpConnection *http, char *buf, ssize_t len) {
|
|||
break;
|
||||
}
|
||||
dcheck(!ERR_peek_error());
|
||||
|
||||
// Shutdown SSL connection, if client initiated renegotiation.
|
||||
if (http->ssl->renegotiationCount > 1) {
|
||||
debug("SSL: connection shutdown due to client initiated renegotiation!");
|
||||
rc = 0;
|
||||
errno = EINVAL;
|
||||
}
|
||||
} else {
|
||||
rc = NOINTR(read(http->fd, buf, len));
|
||||
}
|
||||
|
|
107
libhttp/ssl.c
107
libhttp/ssl.c
|
@ -102,15 +102,20 @@ BIO * (*BIO_new)(BIO_METHOD *);
|
|||
BIO * (*BIO_new_socket)(int, int);
|
||||
BIO * (*BIO_pop)(BIO *);
|
||||
BIO * (*BIO_push)(BIO *, BIO *);
|
||||
#if defined(HAVE_OPENSSL_EC)
|
||||
void (*EC_KEY_free)(EC_KEY *);
|
||||
EC_KEY * (*EC_KEY_new_by_curve_name)(int);
|
||||
#endif
|
||||
void (*ERR_clear_error)(void);
|
||||
void (*ERR_clear_error)(void);
|
||||
unsigned long (*ERR_peek_error)(void);
|
||||
unsigned long (*ERR_peek_error)(void);
|
||||
long (*SSL_CTX_callback_ctrl)(SSL_CTX *, int, void (*)(void));
|
||||
int (*SSL_CTX_check_private_key)(const SSL_CTX *);
|
||||
long (*SSL_CTX_ctrl)(SSL_CTX *, int, long, void *);
|
||||
void (*SSL_CTX_free)(SSL_CTX *);
|
||||
SSL_CTX * (*SSL_CTX_new)(SSL_METHOD *);
|
||||
int (*SSL_CTX_set_cipher_list)(SSL_CTX *, const char *);
|
||||
void (*SSL_CTX_set_info_callback)(SSL_CTX *,
|
||||
void (*)(const SSL *, int, int));
|
||||
int (*SSL_CTX_use_PrivateKey_file)(SSL_CTX *, const char *, int);
|
||||
int (*SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *,
|
||||
const unsigned char *, long);
|
||||
|
@ -136,7 +141,6 @@ int (*SSL_write)(SSL *, const void *, int);
|
|||
SSL_METHOD * (*SSLv23_server_method)(void);
|
||||
X509 * (*d2i_X509)(X509 **px, const unsigned char **in, int len);
|
||||
void (*X509_free)(X509 *a);
|
||||
int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str);
|
||||
void (*x_sk_zero)(void *st);
|
||||
void * (*x_SSL_COMP_get_compression_methods)(void);
|
||||
#endif
|
||||
|
@ -166,6 +170,7 @@ void initSSL(struct SSLSupport *ssl) {
|
|||
ssl->sslContext = NULL;
|
||||
ssl->sniCertificatePattern = NULL;
|
||||
ssl->generateMissing = 0;
|
||||
ssl->renegotiationCount = 0;
|
||||
initTrie(&ssl->sniContexts, sslDestroyCachedContext, ssl);
|
||||
}
|
||||
|
||||
|
@ -280,11 +285,17 @@ static void loadSSL(void) {
|
|||
{ { &ERR_clear_error }, "ERR_clear_error" },
|
||||
{ { &ERR_peek_error }, "ERR_peek_error" },
|
||||
{ { &ERR_peek_error }, "ERR_peek_error" },
|
||||
#ifdef HAVE_OPENSSL_EC
|
||||
{ { &EC_KEY_free }, "EC_KEY_free" },
|
||||
{ { &EC_KEY_new_by_curve_name }, "EC_KEY_new_by_curve_name" },
|
||||
#endif
|
||||
{ { &SSL_CTX_callback_ctrl }, "SSL_CTX_callback_ctrl" },
|
||||
{ { &SSL_CTX_check_private_key }, "SSL_CTX_check_private_key" },
|
||||
{ { &SSL_CTX_ctrl }, "SSL_CTX_ctrl" },
|
||||
{ { &SSL_CTX_free }, "SSL_CTX_free" },
|
||||
{ { &SSL_CTX_new }, "SSL_CTX_new" },
|
||||
{ { &SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" },
|
||||
{ { &SSL_CTX_set_info_callback }, "SSL_CTX_set_info_callback" },
|
||||
{ { &SSL_CTX_use_PrivateKey_file }, "SSL_CTX_use_PrivateKey_file" },
|
||||
{ { &SSL_CTX_use_PrivateKey_ASN1 }, "SSL_CTX_use_PrivateKey_ASN1" },
|
||||
{ { &SSL_CTX_use_certificate_file },"SSL_CTX_use_certificate_file"},
|
||||
|
@ -312,12 +323,11 @@ static void loadSSL(void) {
|
|||
{ { &SSLv23_server_method }, "SSLv23_server_method" },
|
||||
{ { &d2i_X509 }, "d2i_X509" },
|
||||
{ { &X509_free }, "X509_free" },
|
||||
{ { &x_SSL_CTX_set_cipher_list }, "SSL_CTX_set_cipher_list" },
|
||||
{ { &x_sk_zero }, "sk_zero" }
|
||||
};
|
||||
for (unsigned i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
|
||||
if (!(*symbols[i].var = loadSymbol(path_libssl, symbols[i].fn))) {
|
||||
debug("Failed to load SSL support. Could not find \"%s\"",
|
||||
debug("SSL: failed to load SSL support. Could not find \"%s\"",
|
||||
symbols[i].fn);
|
||||
for (unsigned j = 0; j < sizeof(symbols)/sizeof(symbols[0]); j++) {
|
||||
*symbols[j].var = NULL;
|
||||
|
@ -329,9 +339,10 @@ static void loadSSL(void) {
|
|||
x_SSL_COMP_get_compression_methods = loadSymbol(path_libssl, "SSL_COMP_get_compression_methods");
|
||||
// ends
|
||||
|
||||
|
||||
SSL_library_init();
|
||||
dcheck(!ERR_peek_error());
|
||||
debug("Loaded SSL suppport");
|
||||
debug("SSL: loaded SSL suppport");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -368,12 +379,12 @@ int serverSupportsSSL(void) {
|
|||
#if defined(HAVE_OPENSSL)
|
||||
static void sslGenerateCertificate(const char *certificate,
|
||||
const char *serverName) {
|
||||
debug("Auto-generating missing certificate \"%s\" for \"%s\"",
|
||||
debug("SSL: auto-generating missing certificate \"%s\" for \"%s\"",
|
||||
certificate, serverName);
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
warn("Failed to generate self-signed certificate \"%s\"", certificate);
|
||||
warn("SSL: failed to generate self-signed certificate \"%s\"", certificate);
|
||||
} else if (pid == 0) {
|
||||
int fd = NOINTR(open("/dev/null", O_RDONLY));
|
||||
check(fd != -1);
|
||||
|
@ -390,14 +401,14 @@ static void sslGenerateCertificate(const char *certificate,
|
|||
if (execlp("openssl", "openssl", "req", "-x509", "-nodes", "-days", "7300",
|
||||
"-newkey", "rsa:2048", "-keyout", certificate, "-out", certificate,
|
||||
"-subj", subject, (char *)NULL) < 0) {
|
||||
warn("Failed to generate self-signed certificate \"%s\"", certificate);
|
||||
warn("SSL: failed to generate self-signed certificate \"%s\"", certificate);
|
||||
free(subject);
|
||||
}
|
||||
} else {
|
||||
int status;
|
||||
check(NOINTR(waitpid(pid, &status, 0)) == pid);
|
||||
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
|
||||
warn("Failed to generate self-signed certificate \"%s\"", certificate);
|
||||
warn("SSL: failed to generate self-signed certificate \"%s\"", certificate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -595,29 +606,73 @@ static int sslSetCertificateFromFile(SSL_CTX *context,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void sslInfoCallback(const SSL *sslHndl, int type, int val) {
|
||||
// Count the number of renegotiations for each SSL session.
|
||||
if (type & SSL_CB_HANDSHAKE_START) {
|
||||
struct HttpConnection *http =
|
||||
(struct HttpConnection *) SSL_get_app_data(sslHndl);
|
||||
http->ssl->renegotiationCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
static SSL_CTX *sslMakeContext(void) {
|
||||
|
||||
SSL_CTX *context;
|
||||
check(context = SSL_CTX_new(SSLv23_server_method()));
|
||||
SSL_CTX_set_options(context, SSL_OP_ALL);
|
||||
SSL_CTX_set_options(context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||
|
||||
long options = SSL_OP_ALL;
|
||||
options |= SSL_OP_NO_SSLv2;
|
||||
options |= SSL_OP_NO_SSLv3;
|
||||
options |= SSL_OP_SINGLE_DH_USE;
|
||||
|
||||
#ifdef SSL_OP_NO_COMPRESSION
|
||||
SSL_CTX_set_options(context, SSL_OP_NO_COMPRESSION);
|
||||
options |= SSL_OP_NO_COMPRESSION;
|
||||
#endif
|
||||
#if defined(HAVE_DLOPEN)
|
||||
|
||||
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
|
||||
options |= SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
|
||||
#endif
|
||||
|
||||
// Set default SSL options.
|
||||
SSL_CTX_set_options(context, options);
|
||||
|
||||
// Workaround for SSL_OP_NO_COMPRESSION with older OpenSSL versions.
|
||||
#ifdef HAVE_DLOPEN
|
||||
if (SSL_COMP_get_compression_methods) {
|
||||
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
|
||||
}
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x00908000L
|
||||
sk_SSL_COMP_zero(SSL_COMP_get_compression_methods());
|
||||
#endif
|
||||
SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
|
||||
#ifdef SSL_OP_SINGLE_ECDH_USE
|
||||
|
||||
// For Perfect Forward Secrecy (PFS) support we need to enable some additional
|
||||
// SSL options, provide eliptic curve key object for handshake and add chipers
|
||||
// suits with ECDHE handshake on top of the ciper list.
|
||||
#ifdef HAVE_OPENSSL_EC
|
||||
SSL_CTX_set_options(context, SSL_OP_SINGLE_ECDH_USE);
|
||||
SSL_CTX_set_options(context, SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
|
||||
EC_KEY *ecKey;
|
||||
check(ecKey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
SSL_CTX_set_tmp_ecdh(context, ecKey);
|
||||
EC_KEY_free(ecKey);
|
||||
|
||||
debug("SSL: support for PFS enabled...");
|
||||
#endif
|
||||
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
|
||||
SSL_CTX_set_options(context, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
#endif
|
||||
check(SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM:!aNULL:!MD5"));
|
||||
|
||||
check(SSL_CTX_set_cipher_list(context,
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-RSA-AES128-GCM-SHA256:"
|
||||
"ECDHE-RSA-AES256-SHA384:"
|
||||
"ECDHE-RSA-AES128-SHA256:"
|
||||
"ECDHE-RSA-AES256-SHA:"
|
||||
"ECDHE-RSA-AES128-SHA:"
|
||||
"ECDHE-RSA-DES-CBC3-SHA:"
|
||||
"HIGH:MEDIUM:!RC4:!aNULL:!MD5"));
|
||||
|
||||
SSL_CTX_set_info_callback(context, sslInfoCallback);
|
||||
|
||||
debug("SSL: server context succesfully initialized...");
|
||||
return context;
|
||||
}
|
||||
#endif
|
||||
|
@ -634,7 +689,7 @@ static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED,
|
|||
}
|
||||
struct HttpConnection *http =
|
||||
(struct HttpConnection *)SSL_get_app_data(sslHndl);
|
||||
debug("Received SNI callback for virtual host \"%s\" from \"%s:%d\"",
|
||||
debug("SSL: received SNI callback for virtual host \"%s\" from \"%s:%d\"",
|
||||
name, httpGetPeerName(http), httpGetPort(http));
|
||||
char *serverName;
|
||||
check(serverName = malloc(strlen(name)+2));
|
||||
|
@ -671,7 +726,7 @@ static int sslSNICallback(SSL *sslHndl, int *al ATTR_UNUSED,
|
|||
// the default certificate, instead.
|
||||
sslSetCertificateFromFile(context, certificate);
|
||||
} else {
|
||||
warn("Could not find matching certificate \"%s\" for \"%s\"",
|
||||
warn("SSL: could not find matching certificate \"%s\" for \"%s\"",
|
||||
certificate, serverName + 1);
|
||||
SSL_CTX_free(context);
|
||||
context = ssl->sslContext;
|
||||
|
@ -748,7 +803,7 @@ void sslSetCertificate(struct SSLSupport *ssl, const char *filename,
|
|||
sslGenerateCertificate(defaultCertificate, he->h_name);
|
||||
} else {
|
||||
if (h_err) {
|
||||
warn("Error getting host information: \"%s\".", hstrerror(h_err));
|
||||
warn("SSL: error getting host information: \"%s\".", hstrerror(h_err));
|
||||
}
|
||||
sslGenerateCertificate(defaultCertificate, hostname);
|
||||
}
|
||||
|
@ -757,7 +812,7 @@ void sslSetCertificate(struct SSLSupport *ssl, const char *filename,
|
|||
}
|
||||
}
|
||||
if (sslSetCertificateFromFile(ssl->sslContext, defaultCertificate) < 0) {
|
||||
fatal("Cannot read valid certificate from \"%s\". "
|
||||
fatal("SSL: cannot read valid certificate from \"%s\". "
|
||||
"Check file permissions and file format.", defaultCertificate);
|
||||
}
|
||||
valid_certificate:
|
||||
|
@ -823,7 +878,7 @@ void sslSetCertificateFd(struct SSLSupport *ssl, int fd) {
|
|||
ssl->sslContext = sslMakeContext();
|
||||
char *filename = sslFdToFilename(fd);
|
||||
if (!sslSetCertificateFromFd(ssl->sslContext, fd)) {
|
||||
fatal("Cannot read valid certificate from %s. Check file format.",
|
||||
fatal("SSL: cannot read valid certificate from %s. Check file format.",
|
||||
filename);
|
||||
}
|
||||
free(filename);
|
||||
|
@ -996,7 +1051,7 @@ void sslFreeHndl(SSL **sslHndl) {
|
|||
// We do not know, how to fix this situation. Something must have
|
||||
// changed in the OpenSSL internals. Either, this is a new bug, or
|
||||
// somebody fixed the code in a way that we did not anticipate.
|
||||
fatal("Unexpected corruption of OpenSSL data structures");
|
||||
fatal("SSL: unexpected corruption of OpenSSL data structures");
|
||||
}
|
||||
}
|
||||
SSL_free(*sslHndl);
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
#undef HAVE_OPENSSL
|
||||
typedef struct BIO BIO;
|
||||
typedef struct BIO_METHOD BIO_METHOD;
|
||||
typedef struct EC_KEY EC_KEY;
|
||||
typedef struct SSL SSL;
|
||||
typedef struct SSL_CTX SSL_CTX;
|
||||
typedef struct SSL_METHOD SSL_METHOD;
|
||||
|
@ -69,6 +70,12 @@ typedef struct X509 X509;
|
|||
#define SSL_ERROR_WANT_WRITE 3
|
||||
#endif
|
||||
|
||||
// EC support was added to OpenSSL in 0.9.8, but it can be disabled in some
|
||||
// distributions.
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x0090800fL && !defined(OPENSSL_NO_EC)
|
||||
# define HAVE_OPENSSL_EC
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_DLOPEN)
|
||||
extern long (*x_BIO_ctrl)(BIO *, int, long, void *);
|
||||
extern BIO_METHOD *(*x_BIO_f_buffer)(void);
|
||||
|
@ -77,15 +84,20 @@ extern BIO *(*x_BIO_new)(BIO_METHOD *);
|
|||
extern BIO *(*x_BIO_new_socket)(int, int);
|
||||
extern BIO *(*x_BIO_pop)(BIO *);
|
||||
extern BIO *(*x_BIO_push)(BIO *, BIO *);
|
||||
#if defined(HAVE_OPENSSL_EC)
|
||||
extern void (*x_EC_KEY_free)(EC_KEY *);
|
||||
extern EC_KEY *(*x_EC_KEY_new_by_curve_name)(int);
|
||||
#endif
|
||||
extern void (*x_ERR_clear_error)(void);
|
||||
extern void (*x_ERR_clear_error)(void);
|
||||
extern unsigned long (*x_ERR_peek_error)(void);
|
||||
extern unsigned long (*x_ERR_peek_error)(void);
|
||||
extern long (*x_SSL_CTX_callback_ctrl)(SSL_CTX *, int, void (*)(void));
|
||||
extern int (*x_SSL_CTX_check_private_key)(const SSL_CTX *);
|
||||
extern long (*x_SSL_CTX_ctrl)(SSL_CTX *, int, long, void *);
|
||||
extern void (*x_SSL_CTX_free)(SSL_CTX *);
|
||||
extern SSL_CTX*(*x_SSL_CTX_new)(SSL_METHOD *);
|
||||
extern int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *, const char *);
|
||||
extern void (*x_SSL_CTX_set_info_callback)(SSL_CTX *,
|
||||
void (*)(const SSL *, int, int));
|
||||
extern int (*x_SSL_CTX_use_PrivateKey_file)(SSL_CTX *, const char *, int);
|
||||
extern int (*x_SSL_CTX_use_PrivateKey_ASN1)(int, SSL_CTX *,
|
||||
const unsigned char *, long);
|
||||
|
@ -111,7 +123,6 @@ extern int (*x_SSL_write)(SSL *, const void *, int);
|
|||
extern SSL_METHOD *(*x_SSLv23_server_method)(void);
|
||||
extern X509 * (*x_d2i_X509)(X509 **px, const unsigned char **in, int len);
|
||||
extern void (*x_X509_free)(X509 *a);
|
||||
extern int (*x_SSL_CTX_set_cipher_list)(SSL_CTX *ctx, const char *str);
|
||||
extern void (*x_sk_zero)(void *st);
|
||||
extern void *(*x_SSL_COMP_get_compression_methods)(void);
|
||||
|
||||
|
@ -122,15 +133,17 @@ extern void *(*x_SSL_COMP_get_compression_methods)(void);
|
|||
#define BIO_new_socket x_BIO_new_socket
|
||||
#define BIO_pop x_BIO_pop
|
||||
#define BIO_push x_BIO_push
|
||||
#define EC_KEY_free x_EC_KEY_free
|
||||
#define EC_KEY_new_by_curve_name x_EC_KEY_new_by_curve_name
|
||||
#define ERR_clear_error x_ERR_clear_error
|
||||
#define ERR_clear_error x_ERR_clear_error
|
||||
#define ERR_peek_error x_ERR_peek_error
|
||||
#define ERR_peek_error x_ERR_peek_error
|
||||
#define SSL_CTX_callback_ctrl x_SSL_CTX_callback_ctrl
|
||||
#define SSL_CTX_check_private_key x_SSL_CTX_check_private_key
|
||||
#define SSL_CTX_ctrl x_SSL_CTX_ctrl
|
||||
#define SSL_CTX_free x_SSL_CTX_free
|
||||
#define SSL_CTX_new x_SSL_CTX_new
|
||||
#define SSL_CTX_set_cipher_list x_SSL_CTX_set_cipher_list
|
||||
#define SSL_CTX_set_info_callback x_SSL_CTX_set_info_callback
|
||||
#define SSL_CTX_use_PrivateKey_file x_SSL_CTX_use_PrivateKey_file
|
||||
#define SSL_CTX_use_PrivateKey_ASN1 x_SSL_CTX_use_PrivateKey_ASN1
|
||||
#define SSL_CTX_use_certificate_file x_SSL_CTX_use_certificate_file
|
||||
|
@ -154,13 +167,13 @@ extern void *(*x_SSL_COMP_get_compression_methods)(void);
|
|||
#define SSLv23_server_method x_SSLv23_server_method
|
||||
#define d2i_X509 x_d2i_X509
|
||||
#define X509_free x_X509_free
|
||||
#define SSL_CTX_set_cipher_list x_SSL_CTX_set_cipher_list
|
||||
#define sk_zero x_sk_zero
|
||||
#define SSL_COMP_get_compression_methods x_SSL_COMP_get_compression_methods
|
||||
|
||||
#undef BIO_set_buffer_read_data
|
||||
#undef SSL_CTX_set_tlsext_servername_arg
|
||||
#undef SSL_CTX_set_tlsext_servername_callback
|
||||
#undef SSL_CTX_set_tmp_ecdh
|
||||
#undef SSL_get_app_data
|
||||
#undef SSL_set_app_data
|
||||
#undef SSL_set_mode
|
||||
|
@ -175,6 +188,9 @@ extern void *(*x_SSL_COMP_get_compression_methods)(void);
|
|||
(x_SSL_CTX_callback_ctrl(ctx, \
|
||||
SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, \
|
||||
(void (*)(void))cb))
|
||||
#define SSL_CTX_set_tmp_ecdh(ctx, ecdh) \
|
||||
(x_SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, \
|
||||
0, (char *)ecdh))
|
||||
#define SSL_get_app_data(s) (x_SSL_get_ex_data(s, 0))
|
||||
#define SSL_set_app_data(s, arg) (x_SSL_set_ex_data(s, 0, (char *)arg))
|
||||
#define SSL_set_mode(ssl, op) (x_SSL_ctrl((ssl), SSL_CTRL_MODE, (op), NULL))
|
||||
|
@ -185,6 +201,7 @@ struct SSLSupport {
|
|||
SSL_CTX *sslContext;
|
||||
char *sniCertificatePattern;
|
||||
int generateMissing;
|
||||
int renegotiationCount;
|
||||
struct Trie sniContexts;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue