mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-29 13:18:12 +00:00
postfix-2.4-20070221
This commit is contained in:
parent
aaed482ca0
commit
761ae533bd
@ -13255,6 +13255,18 @@ Apologies for any names omitted.
|
||||
multi-valued macro. Files: util/sys_defs.h, util/events.c,
|
||||
master/multi_server.c, *qmgr/qmgr_transport.c.
|
||||
|
||||
20070220
|
||||
|
||||
Work-around: Disable SSL/TLS ciphers when the underlying
|
||||
symmetric algorithm is not available in the OpenSSL crypto
|
||||
library at the required bit strength. Problem observed with
|
||||
SunOS 5.10's bundled OpenSSL 0.9.7 and AES 256. Also possible
|
||||
with OpenSSL 0.9.8 and CAMELLIA 256. Root cause fixed in
|
||||
upcoming OpenSSL 0.9.7m, 0.9.8e and 0.9.9 releases. Victor
|
||||
Duchovni, Morgan Stanley. Files: src/smtp/smtp_proto.c,
|
||||
src/smtpd/smtpd.c, src/tls/tls.h, src/tls/tls_client.c,
|
||||
src/tls/tls_misc.c and src/tls/tls_server.c.
|
||||
|
||||
Wish list:
|
||||
|
||||
Update message content length when adding/removing headers.
|
||||
|
@ -11772,7 +11772,7 @@ setting. </p>
|
||||
</DD>
|
||||
|
||||
<DT><b><a name="tls_null_cipherlist">tls_null_cipherlist</a>
|
||||
(default: !aNULL:eNULL+kRSA)</b></DT><DD>
|
||||
(default: eNULL:!aNULL)</b></DT><DD>
|
||||
|
||||
<p> The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
authentication without encryption. This defines the meaning of the "null"
|
||||
|
@ -441,7 +441,7 @@ SMTP(8) SMTP(8)
|
||||
The OpenSSL cipherlist for "EXPORT" or higher grade
|
||||
ciphers.
|
||||
|
||||
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (!aNULL:eNULL+kRSA)</b>
|
||||
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (eNULL:!aNULL)</b>
|
||||
The OpenSSL cipherlist for "NULL" grade ciphers
|
||||
that provide authentication without encryption.
|
||||
|
||||
|
@ -471,7 +471,7 @@ SMTPD(8) SMTPD(8)
|
||||
The OpenSSL cipherlist for "EXPORT" or higher grade
|
||||
ciphers.
|
||||
|
||||
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (!aNULL:eNULL+kRSA)</b>
|
||||
<b><a href="postconf.5.html#tls_null_cipherlist">tls_null_cipherlist</a> (eNULL:!aNULL)</b>
|
||||
The OpenSSL cipherlist for "NULL" grade ciphers
|
||||
that provide authentication without encryption.
|
||||
|
||||
|
@ -7148,7 +7148,7 @@ certificates). You are strongly encouraged to not change this
|
||||
setting.
|
||||
.PP
|
||||
This feature is available in Postfix 2.3 and later.
|
||||
.SH tls_null_cipherlist (default: !aNULL:eNULL+kRSA)
|
||||
.SH tls_null_cipherlist (default: eNULL:!aNULL)
|
||||
The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
authentication without encryption. This defines the meaning of the "null"
|
||||
setting in smtpd_mandatory_tls_ciphers, smtp_tls_mandatory_ciphers and
|
||||
|
@ -362,7 +362,7 @@ The OpenSSL cipherlist for "MEDIUM" or higher grade ciphers.
|
||||
The OpenSSL cipherlist for "LOW" or higher grade ciphers.
|
||||
.IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
|
||||
The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
|
||||
.IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
|
||||
.IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
|
||||
The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
authentication without encryption.
|
||||
.PP
|
||||
|
@ -386,7 +386,7 @@ The OpenSSL cipherlist for "MEDIUM" or higher grade ciphers.
|
||||
The OpenSSL cipherlist for "LOW" or higher grade ciphers.
|
||||
.IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
|
||||
The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
|
||||
.IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
|
||||
.IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
|
||||
The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
authentication without encryption.
|
||||
.SH "OBSOLETE STARTTLS CONTROLS"
|
||||
|
@ -10399,7 +10399,7 @@ strongly encouraged to not change this setting. </p>
|
||||
|
||||
<p> This feature is available in Postfix 2.3 and later. </p>
|
||||
|
||||
%PARAM tls_null_cipherlist !aNULL:eNULL+kRSA
|
||||
%PARAM tls_null_cipherlist eNULL:!aNULL
|
||||
|
||||
<p> The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
authentication without encryption. This defines the meaning of the "null"
|
||||
|
@ -2692,7 +2692,7 @@ extern char *var_tls_low_clist;
|
||||
extern char *var_tls_export_clist;
|
||||
|
||||
#define VAR_TLS_NULL_CLIST "tls_null_cipherlist"
|
||||
#define DEF_TLS_NULL_CLIST "!aNULL:eNULL+kRSA"
|
||||
#define DEF_TLS_NULL_CLIST "eNULL:!aNULL"
|
||||
extern char *var_tls_null_clist;
|
||||
|
||||
/*
|
||||
|
@ -20,7 +20,7 @@
|
||||
* Patches change both the patchlevel and the release date. Snapshots have no
|
||||
* patchlevel; they change the release date only.
|
||||
*/
|
||||
#define MAIL_RELEASE_DATE "20070218"
|
||||
#define MAIL_RELEASE_DATE "20070221"
|
||||
#define MAIL_VERSION_NUMBER "2.4"
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
|
@ -332,7 +332,7 @@
|
||||
/* The OpenSSL cipherlist for "LOW" or higher grade ciphers.
|
||||
/* .IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
|
||||
/* The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
|
||||
/* .IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
|
||||
/* .IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
|
||||
/* The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
/* authentication without encryption.
|
||||
/* .PP
|
||||
|
@ -753,7 +753,7 @@ static int smtp_start_tls(SMTP_STATE *state)
|
||||
vstring_sprintf_append(serverid, "&p=%s",
|
||||
tls_protocol_names(VAR_SMTP_TLS_MAND_PROTO,
|
||||
session->tls_protocols));
|
||||
if (session->tls_level >= TLS_LEV_ENCRYPT && session->tls_cipherlist)
|
||||
if (session->tls_level >= TLS_LEV_ENCRYPT)
|
||||
vstring_sprintf_append(serverid, "&c=%s", session->tls_cipherlist);
|
||||
|
||||
tls_props.ctx = smtp_tls_ctx;
|
||||
|
@ -354,7 +354,7 @@
|
||||
/* The OpenSSL cipherlist for "LOW" or higher grade ciphers.
|
||||
/* .IP "\fBtls_export_cipherlist (ALL:+RC4:@STRENGTH)\fR"
|
||||
/* The OpenSSL cipherlist for "EXPORT" or higher grade ciphers.
|
||||
/* .IP "\fBtls_null_cipherlist (!aNULL:eNULL+kRSA)\fR"
|
||||
/* .IP "\fBtls_null_cipherlist (eNULL:!aNULL)\fR"
|
||||
/* The OpenSSL cipherlist for "NULL" grade ciphers that provide
|
||||
/* authentication without encryption.
|
||||
/* OBSOLETE STARTTLS CONTROLS
|
||||
@ -4311,6 +4311,8 @@ static void pre_jail_init(char *unused_name, char **unused_argv)
|
||||
enforce_tls ? var_smtpd_tls_mand_excl :
|
||||
TLS_END_EXCLUDE,
|
||||
TLS_END_EXCLUDE);
|
||||
if (props.cipherlist == 0)
|
||||
msg_panic("NULL export cipherlist");
|
||||
}
|
||||
if (havecert || oknocert)
|
||||
smtpd_tls_ctx = tls_server_init(&props);
|
||||
|
@ -130,6 +130,7 @@ extern NAME_CODE tls_cipher_level_table[];
|
||||
|
||||
#define TLS_END_EXCLUDE ((char *)0)
|
||||
extern const char *tls_cipher_list(int,...);
|
||||
extern const char *tls_set_cipher_list(SSL_CTX *, const char *);
|
||||
|
||||
/*
|
||||
* tls_client.c
|
||||
|
@ -626,6 +626,15 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
|
||||
if (props->log_level >= 1)
|
||||
msg_info("setting up TLS connection to %s", props->host);
|
||||
|
||||
/*
|
||||
* Before we create an SSL, update the SSL_CTX cipherlist if necessary.
|
||||
*/
|
||||
if (tls_set_cipher_list(props->ctx, props->cipherlist) == 0) {
|
||||
msg_warn("Invalid cipherlist \"%s\": aborting TLS session",
|
||||
props->cipherlist);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a new TLScontext for the new connection and get an SSL
|
||||
* structure. Add the location of TLScontext to the SSL to later retrieve
|
||||
@ -710,24 +719,13 @@ TLScontext_t *tls_client_start(const tls_client_start_props *props)
|
||||
}
|
||||
|
||||
/*
|
||||
* Per session cipher selection for sessions with mandatory encryption
|
||||
* Try to load an existing session from the TLS session cache.
|
||||
*
|
||||
* By the time a TLS client is negotiating ciphers it has already offered to
|
||||
* re-use a session, it is too late to renege on the offer. So we must
|
||||
* not attempt to re-use sessions whose ciphers are too weak. We expect
|
||||
* the caller to salt the session lookup key with the cipher list, so
|
||||
* that sessions found in the cache are always acceptable.
|
||||
*/
|
||||
if (props->cipherlist != 0)
|
||||
if (SSL_set_cipher_list(TLScontext->con, props->cipherlist) == 0) {
|
||||
msg_warn("Could not set cipherlist: %s", props->cipherlist);
|
||||
tls_print_errors();
|
||||
tls_free_context(TLScontext);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to load an existing session from the TLS session cache.
|
||||
*
|
||||
* XXX To avoid memory leaks we must always call SSL_SESSION_free() after
|
||||
* calling SSL_set_session(), regardless of whether or not the session
|
||||
|
@ -18,6 +18,10 @@
|
||||
/*
|
||||
/* long tls_bug_bits()
|
||||
/*
|
||||
/* const char *tls_set_cipher_list(ssl_ctx, cipher_list)
|
||||
/* SSL_CTX *ssl_ctx;
|
||||
/* char *cipher_list;
|
||||
/*
|
||||
/* const char *tls_cipher_list(cipher_level, ...)
|
||||
/* int cipher_level;
|
||||
/*
|
||||
@ -53,6 +57,11 @@
|
||||
/* for the run-time library. Some of the bug work-arounds are
|
||||
/* not appropriate for some library versions.
|
||||
/*
|
||||
/* tls_set_cipher_list() updates the cipher list of the specified SSL
|
||||
/* context. Returns the new cipherlist on success, otherwise logs a
|
||||
/* suitable warning and returns 0. The storage for the return value
|
||||
/* is overwritted with each call.
|
||||
/*
|
||||
/* tls_cipher_list() generates a cipher list from the specified
|
||||
/* grade, minus any ciphers specified via a null-terminated
|
||||
/* list of string-valued exclusions. The result is overwritten
|
||||
@ -152,45 +161,6 @@ NAME_CODE tls_cipher_level_table[] = {
|
||||
0, TLS_CIPHER_NONE,
|
||||
};
|
||||
|
||||
#if 0
|
||||
|
||||
typedef struct {
|
||||
char *algorithm;
|
||||
char *exclusion;
|
||||
} cipher_probe;
|
||||
|
||||
static cipher_probe cipher_probe_list[] = {
|
||||
|
||||
/*
|
||||
* Check for missing AES256, OpenSSL only checks for AES128, and then
|
||||
* enables both, because they only have one "is AES" boolean flag in the
|
||||
* cipher property mask. The implementation cannot distinguish between
|
||||
* AES128 and AES256. When some O/S distributions play games with
|
||||
* libcrypto and exclude just the AES256 ciphers, they break the OpenSSL
|
||||
* cipherlist construction code, with clients and servers potentially
|
||||
* negotiating unimplemented ciphers.
|
||||
*
|
||||
* This problem is peculiar to AES, which is not a single cipher, but a
|
||||
* family of related ciphers. The other OpenSSL symmetric ciphers are
|
||||
* atomic, either implemented or not. We expect that future ciphers will
|
||||
* either also be atomic, or will have one property bit per family member
|
||||
* and will be filtered accurately by OpenSSL.
|
||||
*
|
||||
* If all else fails, this table can be expanded :-(
|
||||
*
|
||||
* XXX: the probe for AES256 is enclosed in #ifdef. OpenSSL 0.9.6 and and
|
||||
* earlier don't have AES 256, this requires 0.9.7 or later. We recommend
|
||||
* against use of 0.9.6, it has open issues solved in 0.9.7l and 0.9.8d,
|
||||
* but we are not yet prepared to drop support for 0.9.6.
|
||||
*/
|
||||
#ifdef SN_aes_256_cbc
|
||||
SN_aes_256_cbc, SSL_TXT_AES "+HIGH",
|
||||
#endif
|
||||
0, 0,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Parsed OpenSSL version number.
|
||||
*/
|
||||
@ -202,17 +172,140 @@ typedef struct {
|
||||
int status;
|
||||
} TLS_VINFO;
|
||||
|
||||
/*
|
||||
* OpenSSL adopted the cipher selection patch, so we don't expect any more
|
||||
* broken ciphers other than AES and CAMELLIA.
|
||||
*/
|
||||
typedef struct {
|
||||
char *ssl_name;
|
||||
int alg_bits;
|
||||
char *evp_name;
|
||||
} cipher_probe_t;
|
||||
|
||||
static cipher_probe_t cipher_probes[] = {
|
||||
"AES", 256, "AES-256-CBC",
|
||||
"CAMELLIA", 256, "CAMELLIA-256-CBC",
|
||||
0, 0, 0,
|
||||
};
|
||||
|
||||
/* tls_exclude_missing - Append exclusions for missing ciphers */
|
||||
|
||||
static void tls_exclude_missing(SSL_CTX *ctx, VSTRING *buf)
|
||||
{
|
||||
const char *myname = "tls_exclude_missing";
|
||||
static ARGV *exclude; /* Cached */
|
||||
SSL *s = 0;
|
||||
|
||||
STACK_OF(SSL_CIPHER) * ciphers;
|
||||
SSL_CIPHER *c;
|
||||
cipher_probe_t *probe;
|
||||
int alg_bits;
|
||||
int num;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Process a list of probes which specify:
|
||||
*
|
||||
* An SSL cipher-suite name for a family of ciphers that use the same
|
||||
* symmetric algorithm at two or more key sizes, typically 128/256 bits.
|
||||
*
|
||||
* The key size (typically 256) that OpenSSL fails check, and assumes is
|
||||
* available when another key size (typically 128) is usable.
|
||||
*
|
||||
* The OpenSSL name of the symmetric algorithm associated with the SSL
|
||||
* cipher-suite. Typically, this is MUMBLE-256-CBC, where "MUMBLE" is the
|
||||
* name of the SSL cipher-suite that use the MUMBLE symmetric algorithm.
|
||||
* On systems that support the required encryption algorithm, the name is
|
||||
* listed in the output of "openssl list-cipher-algorithms".
|
||||
*
|
||||
* When an encryption algorithm is not available at the given key size but
|
||||
* the corresponding OpenSSL cipher-suite contains ciphers that have have
|
||||
* this key size, the problem ciphers are explicitly disabled in Postfix.
|
||||
* The list is cached in the static "exclude" array.
|
||||
*/
|
||||
if (exclude == 0) {
|
||||
exclude = argv_alloc(1);
|
||||
|
||||
/*
|
||||
* Iterate over the probe list
|
||||
*/
|
||||
for (probe = cipher_probes; probe->ssl_name; ++probe) {
|
||||
/* No exclusions if evp_name is a valid algorithm */
|
||||
if (EVP_get_cipherbyname(probe->evp_name))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Sadly there is no SSL_CTX_get_ciphers() interface, so we are
|
||||
* forced to allocate and free an SSL object. Fatal error if we
|
||||
* can't allocate the SSL object.
|
||||
*/
|
||||
ERR_clear_error();
|
||||
if (s == 0 && (s = SSL_new(ctx)) == 0) {
|
||||
tls_print_errors();
|
||||
msg_fatal("%s: error allocating SSL object", myname);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cipher is not supported by libcrypto, nothing to do if also
|
||||
* not supported by libssl. Flush the OpenSSL error stack.
|
||||
*
|
||||
* XXX: There may be additional places in pre-existing code where
|
||||
* SSL errors are generated and ignored, that require a similar
|
||||
* "flush". Better yet, is to always flush before calls that run
|
||||
* tls_print_errors() on failure.
|
||||
*
|
||||
* Contrary to documentation, on SunOS 5.10 SSL_set_cipher_list()
|
||||
* returns success with no ciphers selected, when this happens
|
||||
* SSL_get_ciphers() produces a stack with 0 elements!
|
||||
*/
|
||||
if (SSL_set_cipher_list(s, probe->ssl_name) == 0
|
||||
|| (ciphers = SSL_get_ciphers(s)) == 0
|
||||
|| (num = sk_SSL_CIPHER_num(ciphers)) == 0) {
|
||||
ERR_clear_error(); /* flush any generated errors */
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < num; ++i) {
|
||||
c = sk_SSL_CIPHER_value(ciphers, i);
|
||||
(void) SSL_CIPHER_get_bits(c, &alg_bits);
|
||||
if (alg_bits == probe->alg_bits)
|
||||
argv_add(exclude, SSL_CIPHER_get_name(c), ARGV_END);
|
||||
}
|
||||
}
|
||||
if (s != 0)
|
||||
SSL_free(s);
|
||||
}
|
||||
for (i = 0; i < exclude->argc; ++i)
|
||||
vstring_sprintf_append(buf, ":!%s", exclude->argv[i]);
|
||||
}
|
||||
|
||||
/* tls_set_cipher_list - Set SSL_CTX cipher list */
|
||||
|
||||
const char *tls_set_cipher_list(SSL_CTX *ssl_ctx, const char *spec)
|
||||
{
|
||||
static VSTRING *buf;
|
||||
const char *ex_spec;
|
||||
|
||||
if (buf == 0)
|
||||
buf = vstring_alloc(10);
|
||||
|
||||
vstring_strcpy(buf, spec);
|
||||
tls_exclude_missing(ssl_ctx, buf);
|
||||
ex_spec = vstring_str(buf);
|
||||
|
||||
ERR_clear_error();
|
||||
if (SSL_CTX_set_cipher_list(ssl_ctx, ex_spec) != 0)
|
||||
return (ex_spec);
|
||||
|
||||
tls_print_errors();
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* tls_cipher_list - Cipherlist for given grade, less exclusions */
|
||||
|
||||
const char *tls_cipher_list(int cipher_level,...)
|
||||
{
|
||||
const char *myname = "tls_cipher_list";
|
||||
static VSTRING *buf;
|
||||
#if 0
|
||||
static ARGV *exclude_unavailable;
|
||||
cipher_probe *probe;
|
||||
int i;
|
||||
#endif
|
||||
va_list ap;
|
||||
const char *exclude;
|
||||
char *tok;
|
||||
@ -241,47 +334,34 @@ const char *tls_cipher_list(int cipher_level,...)
|
||||
case TLS_CIPHER_NONE:
|
||||
return 0;
|
||||
default:
|
||||
|
||||
/*
|
||||
* The caller MUST provide a valid cipher grade
|
||||
*/
|
||||
msg_panic("%s: invalid cipher grade: %d", myname, cipher_level);
|
||||
}
|
||||
|
||||
/*
|
||||
* The base lists for each grade can't be empty.
|
||||
*/
|
||||
if (VSTRING_LEN(buf) == 0)
|
||||
msg_panic("%s: empty cipherlist", myname);
|
||||
|
||||
/*
|
||||
* Exclude ciphers that clueless distributions leave out of libcrypto.
|
||||
*/
|
||||
#if 0
|
||||
if (exclude_unavailable == 0) {
|
||||
exclude_unavailable = argv_alloc(1);
|
||||
for (probe = cipher_probe_list; probe->algorithm; ++probe)
|
||||
if (!EVP_get_cipherbyname(probe->algorithm))
|
||||
argv_add(exclude_unavailable, probe->exclusion, (char *) 0);
|
||||
}
|
||||
for (i = 0; i < exclude_unavailable->argc; ++i)
|
||||
vstring_sprintf_append(buf, ":!%s", exclude_unavailable->argv[i]);
|
||||
#endif
|
||||
|
||||
va_start(ap, cipher_level);
|
||||
while ((exclude = va_arg(ap, char *)) != 0) {
|
||||
if (*exclude == '\0')
|
||||
continue;
|
||||
save = cp = mystrdup(exclude);
|
||||
while ((tok = mystrtok(&cp, "\t\n\r ,")) != 0) {
|
||||
while ((tok = mystrtok(&cp, "\t\n\r ,:")) != 0) {
|
||||
|
||||
/*
|
||||
* Can't exclude ciphers that start with modifiers, or
|
||||
* multi-element (":" separated) ciphers.
|
||||
* Can't exclude ciphers that start with modifiers.
|
||||
*/
|
||||
if (strchr("!+-@", *tok)) {
|
||||
msg_warn("%s: can't exclude '!+-@' modifiers, '%s' ignored",
|
||||
myname, tok);
|
||||
continue;
|
||||
}
|
||||
if (strchr(tok, ':')) {
|
||||
msg_warn("%s: can't exclude compound ciphers, '%s' ignored",
|
||||
myname, tok);
|
||||
continue;
|
||||
}
|
||||
vstring_sprintf_append(buf, ":!%s", tok);
|
||||
}
|
||||
myfree(save);
|
||||
|
@ -329,12 +329,12 @@ SSL_CTX *tls_server_init(const tls_server_props *props)
|
||||
/*
|
||||
* Override the default cipher list with our own list.
|
||||
*/
|
||||
if (*props->cipherlist != 0)
|
||||
if (SSL_CTX_set_cipher_list(server_ctx, props->cipherlist) == 0) {
|
||||
tls_print_errors();
|
||||
SSL_CTX_free(server_ctx); /* 200411 */
|
||||
return (0);
|
||||
}
|
||||
if (tls_set_cipher_list(server_ctx, props->cipherlist) == 0) {
|
||||
SSL_CTX_free(server_ctx);
|
||||
msg_warn("Invalid cipherlist \"%s\": disabling TLS support",
|
||||
props->cipherlist);
|
||||
return (0); /* Already logged */
|
||||
}
|
||||
|
||||
/*
|
||||
* Load the CA public key certificates for both the server cert and for
|
||||
|
Loading…
x
Reference in New Issue
Block a user