* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* -------------------------------------------------------------------------
* File Name : gs_openssl_client.cpp
* Brief :
* Description : initialize the ssl system of client which is based on the OpenSSL library
*
* History : 2017-6
*
* IDENTIFICATION
* src/gausskernel/cbb/utils/ssl/gs_openssl_client.cpp
*
* -------------------------------------------------------------------------
*/
#include "securec_check.h"
#include "gs_threadlocal.h"
#include "postgres.h"
#include "knl/knl_variable.h"
#include "ssl/gs_openssl_client.h"
#include "utils/be_module.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "ssl/gs_openssl_client.h"
#include "openssl/ossl_typ.h"
#include "openssl/x509.h"
#include "openssl/asn1.h"
#ifdef ENABLE_UT
#define static
#endif
#ifndef WIN32
static pthread_mutex_t openssl_conf_mtx = PTHREAD_MUTEX_INITIALIZER;
#else
static pthread_mutex_t openssl_conf_mtx = NULL;
#endif
#define OSSL_RANDOM_LEN 16
#define MIN_DHLENTH 112
#define MAX_DHLENTH 192
static bool openssl_system_inited = false;
static inline void ossl_clear_passwd_mem(gs_openssl_client* cli);
static inline void ossl_clear_passwd_mem(gs_openssl_client* cli);
static int opencli_dh_verify_cb(const SSL* s, const SSL_CTX* ctx, int op, int bits, int nid, void* other, void* ex);
static void ossl_init_ssl_context(gs_openssl_client* cli);
static int ossl_init_client_ssl_passwd(SSL_CTX* pstContext, const char* cert_file_path, GS_UCHAR* cipher_passwd);
static int ossl_load_ssl_files(gs_openssl_client* cli);
static int ossl_check_permission_of_cipher_file(const char* parent_dir);
static int ossl_new_ssl_and_bind_socket(gs_openssl_client* cli, int sock_id);
static int ossl_verify_method_name_matches_certificate(X509* peer);
static int ossl_open_connection(gs_openssl_client* cli);
static const char* ossl_error_message(void);
static char* ssl_cipher_list2string(const char* ciphers[], const int num);
static int SSL_CTX_set_cipher_list_ex(SSL_CTX* ctx, const char* ciphers[], const int num);
static const char* ossl_cipher_list[] = {TLS1_TXT_ECDHE_RSA_WITH_AES_128_GCM_SHA256, NULL};
struct gs_openssl_client {
SSL_CTX* m_ssl_context;
SSL* ssl;
X509* peer;
char* ssl_dir;
char* sslclientkey;
char* sslclientcert;
char* sslrootcert;
GS_UCHAR plain_passwd[CIPHER_LEN + 1];
};
* @Description: set user defined files to gs_openssl_client
* @Input: user defined value, ssl_dir, rootcert, client_key, clientcert
* @Output: gs_openssl_client* cli, the client SSL information struct
* @Return: NULL
* @See also:
*/
void gs_openssl_cli_setfiles(
gs_openssl_client* cli, const char* ssl_dir, const char* rootcert, const char* client_key, const char* clientcert)
{
cli->ssl_dir = pstrdup(ssl_dir);
cli->sslclientcert = pstrdup(clientcert);
cli->sslclientkey = pstrdup(client_key);
cli->sslrootcert = pstrdup(rootcert);
}
* @Description: make the member of gs_openssl_client be NULL
* @Input: gs_openssl_client* cli, the client SSL information struct
* @Return: NULL
* @See also:
*/
gs_openssl_cli gs_openssl_cli_create(void)
{
return (gs_openssl_cli)palloc0(sizeof(gs_openssl_client));
}
* @Description: clean the memory of gs_openssl_client
* @Input: gs_openssl_client* cli, the client SSL information struct
* @Return: NULL
* @See also:
*/
void gs_openssl_cli_destroy(gs_openssl_client* cli)
{
if (cli != NULL) {
if (cli->ssl != NULL) {
(void)SSL_free(cli->ssl);
cli->ssl = NULL;
}
if (cli->m_ssl_context != NULL) {
(void)SSL_CTX_free(cli->m_ssl_context);
cli->m_ssl_context = NULL;
}
if (cli->ssl_dir != NULL) {
pfree_ext(cli->ssl_dir);
}
if (cli->sslclientcert != NULL) {
pfree_ext(cli->sslclientcert);
}
if (cli->sslclientkey != NULL) {
pfree_ext(cli->sslclientkey);
}
if (cli->sslrootcert != NULL) {
pfree_ext(cli->sslrootcert);
}
cli->peer = NULL;
}
}
* @Description: the main function of initialize the ssl system of client using OPENSSL.
* step1:prepare the ssl context.
* step2: load the certificate file and key file.
* step3: set the cipher list and verify mode.
* step4: bind SSL with socket
* step5: connect with server using SSL
* @Input: gs_openssl_client* cli, the information struct of OPENSSL
* @Input: int sock_id, the Socket ID number attached to SSL
* @Return: success 0, failed -1
* @See also:
*/
int gs_openssl_cli_initialize_SSL(gs_openssl_client* cli, int sock_id)
{
int ciphers_count = 0;
ossl_init_ssl_context(cli);
ossl_clear_passwd_mem(cli);
if (ossl_init_client_ssl_passwd(cli->m_ssl_context, cli->ssl_dir, cli->plain_passwd) != 0) {
SSL_CTX_free(cli->m_ssl_context);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("Failed to set the default password for private key File: \"%s\"", cli->sslclientkey)));
return -1;
}
(void)ossl_load_ssl_files(cli);
for (int i = 0; ossl_cipher_list[i] != NULL; i++) {
ciphers_count++;
}
if (SSL_CTX_set_cipher_list_ex(cli->m_ssl_context, ossl_cipher_list, ciphers_count) != 1) {
SSL_CTX_free(cli->m_ssl_context);
ereport(ERROR,
(errmodule(MOD_SSL), errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED), errmsg("%s", ossl_error_message())));
return -1;
}
* verify the servers certificate for the ssl context
*/
SSL_CTX_set_verify(cli->m_ssl_context, SSL_VERIFY_PEER, NULL);
(void)ossl_new_ssl_and_bind_socket(cli, sock_id);
(void)ossl_open_connection(cli);
ossl_clear_passwd_mem(cli);
return 0;
}
* @Description: Report the error message of SSL
* @Return: const char*, error message
* @See also:
*/
static const char* ossl_error_message(void)
{
GS_UINT32 errcode = ERR_get_error();
if (errcode == 0) {
return _("no SSL error reported");
}
const char* errreason = ERR_reason_error_string(errcode);
if (errreason != NULL) {
return errreason;
}
* so the total length is less than 32 bytes. it's safe here.
*/
#define ERR_BUF_MAXLEN 32
static THR_LOCAL char errbuf[ERR_BUF_MAXLEN];
int nRet;
nRet = snprintf_s(errbuf, sizeof(errbuf), sizeof(errbuf) - 1, ("SSL error code %ul"), errcode);
securec_check_ss_c(nRet, "\0", "\0");
return errbuf;
}
* @Description: write at most len bytes to SSL connection from buf.
* caller must check the returned bytes be written. if returned
* bytes is less than len, please call this function again.
* @IN buf: input buffer to write
* @IN cli: gs_openssl_client object
* @IN len: bytes number to write
* @Return: written bytes number
* @See also:
*/
int gs_openssl_cli_write(gs_openssl_client* cli, const char* buf, int len)
{
int nwrite = 0;
int sslerr = 0;
int trytimes = 0;
const int maxtimes = 10;
sslretry:
errno = 0;
ERR_clear_error();
nwrite = SSL_write(cli->ssl, buf, len);
sslerr = SSL_get_error(cli->ssl, nwrite);
switch (sslerr) {
case SSL_ERROR_NONE: {
if (nwrite < 0) {
ereport(WARNING,
(errmodule(MOD_SSL),
errmsg("write failed but not provide error info: write %d, errno %d", nwrite, errno)));
}
break;
}
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_ZERO_RETURN: {
if (++trytimes > maxtimes) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("too many writing times(>%d):%d, write %d, errno %d", maxtimes, sslerr, nwrite, errno)));
} else {
ereport(WARNING,
(errmodule(MOD_SSL), errmsg("try to write again:%d, write %d, errno %d", sslerr, nwrite, errno)));
}
nwrite = -1;
goto sslretry;
}
case SSL_ERROR_SYSCALL:
case SSL_ERROR_SSL: {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("%d: write %d, errno %d, detail:%s", sslerr, nwrite, errno, ossl_error_message())));
nwrite = -1;
break;
}
default: {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized error:%d, write %d, errno %d", sslerr, nwrite, errno)));
nwrite = -1;
break;
}
}
return nwrite;
}
* @Description: read at most maxlen bytes from SSL connection,
* and put data into obuf. caller must repeated call this
* function until there is no data in OPENSSL buffer and
* 0 returned
* @IN cli: gs_openssl_client object
* @IN maxlen: max length of output buffer
* @IN obuf: output buffer
* @Return:
* @See also:
*/
int gs_openssl_cli_read(gs_openssl_client* cli, char* obuf, int maxlen)
{
int sslerr = 0;
int nread = 0;
Assert(cli && cli->ssl);
int sockid = SSL_get_fd(cli->ssl);
if (0 > sockid) {
ereport(LOG, (errmodule(MOD_SSL), errmsg("bad socket when reading")));
return OPENSSL_CLI_BAD_SOCKET;
}
sslretry:
errno = 0;
ERR_clear_error();
nread = SSL_read(cli->ssl, obuf, maxlen);
sslerr = SSL_get_error(cli->ssl, nread);
if (nread < 0) {
if (errno == EINTR) {
goto sslretry;
}
#ifdef EAGAIN
if (errno == EAGAIN) {
return OPENSSL_CLI_EAGAIN;
}
#endif
#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
if (errno == EWOULDBLOCK) {
return OPENSSL_CLI_EAGAIN;
}
#endif
ereport(LOG, (errmodule(MOD_SSL), errmsg("exception status during read: sslerr %d, errno %d", sslerr, errno)));
return OPENSSL_CLI_EXCEPTTION;
}
return nread;
}
* @Description: initialize OPENSSL system evn, including
* 1. X509 checking
* 2. CA key checking;
* 3. load SSL library;
* 4. load error string table;
* @See also:
*/
void gs_openssl_cli_init_system(void)
{
if (openssl_system_inited) {
return;
}
(void)pthread_mutex_lock(&openssl_conf_mtx);
if (!openssl_system_inited) {
if (1 != OPENSSL_init_ssl(0, NULL)) {
(void)pthread_mutex_unlock(&openssl_conf_mtx);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("failed to initialize SSL library, detail:%s", ossl_error_message())));
}
SSL_load_error_strings();
openssl_system_inited = true;
}
(void)pthread_mutex_unlock(&openssl_conf_mtx);
}
* @Description: prepare the ssl library in the beginning of initialization
* @Input: gs_openssl_client* cli, the information struct of OPENSSL
* @Return:
* @See also:
*/
static void ossl_init_ssl_context(gs_openssl_client* cli)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
cli->m_ssl_context = SSL_CTX_new(TLSv1_2_client_method());
#pragma GCC diagnostic pop
if (cli->m_ssl_context == NULL) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("failed to create the SSL context, detail:%s", ossl_error_message())));
}
* Disable OPENSSL's moving-write-buffer sanity check, because it
* causes unnecessary failures in nonblocking send cases.
*/
(void)SSL_CTX_set_mode(cli->m_ssl_context, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
}
* @Description: set the default password for certificate/private key loading
* @Input: SSL_CTX *pstContext, SSL context to set the password
* @Input: char* cert_file_dir, the file path that contains certificate files
* @Input: GS_UCHAR *cipher_passwd, decrypt password
* @Return: success 0, failed -1
* @See also:
*/
static int ossl_init_client_ssl_passwd(SSL_CTX* pstContext, const char* cert_file_dir, GS_UCHAR* cipher_passwd)
{
int retval = 0;
if (NULL == cert_file_dir || '\0' == cert_file_dir[0]) {
SSL_CTX_free(pstContext);
ereport(ERROR,
(errmodule(MOD_SSL), errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED), errmsg("invlid cert file directory")));
return -1;
}
* Decrypt the default cipher and rand files begins with client
*/
retval = ossl_check_permission_of_cipher_file(cert_file_dir);
if (retval != 0) {
return retval;
}
decode_cipher_files(GDS_MODE, NULL, cert_file_dir, cipher_passwd);
SSL_CTX_set_default_passwd_cb_userdata(pstContext, (void*)cipher_passwd);
return 0;
}
* @Description: load certificate files for SSL context of the client
* @Input: gs_openssl_client* cli, the information struct of OPENSSL
* @Return:success 0, failed -1
* @See also:
*/
static int ossl_load_ssl_files(gs_openssl_client* cli)
{
char fnbuf[MAXPGPATH] = {0};
int nRet = snprintf_s(fnbuf, MAXPGPATH, sizeof(fnbuf) - 1, "%s/%s", cli->ssl_dir, cli->sslrootcert);
securec_check_ss_c(nRet, "\0", "\0");
if (SSL_CTX_load_verify_locations(cli->m_ssl_context, fnbuf, NULL) != 1) {
SSL_CTX_free(cli->m_ssl_context);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("failed to load the root CA Certificate %s(%s)", cli->sslrootcert, fnbuf),
errdetail("%s", ossl_error_message())));
return -1;
}
* Load the client certificated file "client.crt" for the SSL context
*/
nRet = snprintf_s(fnbuf, MAXPGPATH, sizeof(fnbuf) - 1, "%s/%s", cli->ssl_dir, cli->sslclientcert);
securec_check_ss_c(nRet, "\0", "\0");
if (SSL_CTX_use_certificate_chain_file(cli->m_ssl_context, fnbuf) != 1) {
SSL_CTX_free(cli->m_ssl_context);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("failed to certificate the %s(%s) file in SSL context", cli->sslclientcert, fnbuf)));
return -1;
}
return 0;
}
static int ossl_check_permission_of_cipher_file(const char* parent_dir)
{
char cipher_file[MAXPGPATH] = {0};
char rand_file[MAXPGPATH] = {0};
struct stat cipherbuf;
struct stat randbuf;
int nRet = 0;
nRet = snprintf_s(cipher_file, MAXPGPATH, MAXPGPATH - 1, "%s/server%s", parent_dir, CIPHER_KEY_FILE);
securec_check_ss_c(nRet, "\0", "\0");
nRet = snprintf_s(rand_file, MAXPGPATH, MAXPGPATH - 1, "%s/server%s", parent_dir, RAN_KEY_FILE);
securec_check_ss_c(nRet, "\0", "\0");
if (lstat(cipher_file, &cipherbuf) != 0) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_file_access(),
errmsg("stat cipher file \"%s\" failed, detail: %s", cipher_file, gs_strerror(errno))));
return -1;
}
if (lstat(rand_file, &randbuf) != 0) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_file_access(),
errmsg("stat rand file \"%s\" failed, detail: %s", rand_file, gs_strerror(errno))));
return -1;
}
* so check whether permissions meets the requirements
*/
if (!S_ISREG(cipherbuf.st_mode) || (cipherbuf.st_mode & (S_IRWXG | S_IRWXO))) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_file_access(),
errmsg("cipher file \"%s\" has group or world access;"
"permissions should be u=rw (0600) or less with Error: %s",
cipher_file,
gs_strerror(errno))));
return -1;
}
if (!S_ISREG(randbuf.st_mode) || (randbuf.st_mode & (S_IRWXG | S_IRWXO))) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_file_access(),
errmsg("rand file \"%s\" has group or world access;"
"permissions should be u=rw (0600) or less with Error: %s",
rand_file,
gs_strerror(errno))));
return -1;
}
return 0;
}
* @Description: bind the SSL with socket ID, read the certificate files
* for SSL and check the verify method.
* @Input: gs_openssl_client* cli, the information struct of OPENSSL
* @Input: int sock_id, socket ID to be binded with.
* @Return: success 0 failed -1
* @See also:
*/
static int ossl_new_ssl_and_bind_socket(gs_openssl_client* cli, int sock_id)
{
#define MAX_CERTIFICATE_DEPTH_SUPPORTED 20
cli->ssl = SSL_new(cli->m_ssl_context);
if (cli->ssl == NULL) {
ereport(ERROR,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("Failed to create the SSL."),
errdetail("%s", ossl_error_message())));
}
if (SSL_set_fd(cli->ssl, sock_id) != 1) {
SSL_free(cli->ssl);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_socket_access(),
errmsg("Failed to set the socket(%d) for SSL", sock_id),
errdetail("%s", ossl_error_message())));
return -1;
}
char fnbuf[MAXPGPATH] = {0};
int nRet = snprintf_s(fnbuf, MAXPGPATH, sizeof(fnbuf) - 1, "%s/%s", cli->ssl_dir, cli->sslclientcert);
securec_check_ss_c(nRet, "\0", "\0");
if (SSL_use_certificate_file(cli->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) {
SSL_free(cli->ssl);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_socket_access(),
errmsg("Failed to certificate file \"%s\" in SSL object", fnbuf),
errdetail("%s", ossl_error_message())));
return -1;
}
nRet = snprintf_s(fnbuf, MAXPGPATH, sizeof(fnbuf) - 1, "%s/%s", cli->ssl_dir, cli->sslclientkey);
securec_check_ss_c(nRet, "\0", "\0");
if (SSL_use_PrivateKey_file(cli->ssl, fnbuf, SSL_FILETYPE_PEM) != 1) {
SSL_free(cli->ssl);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_socket_access(),
errmsg("Failed to certificate file \"%s\" in SSL object", fnbuf),
errdetail("%s", ossl_error_message())));
return -1;
}
if (SSL_check_private_key(cli->ssl) != 1) {
SSL_free(cli->ssl);
ereport(ERROR,
(errmodule(MOD_SSL),
errcode_for_socket_access(),
errmsg("Failed to check the private key File."),
errdetail("%s", ossl_error_message())));
return -1;
}
SSL_set_security_callback(cli->ssl, opencli_dh_verify_cb);
SSL_set_verify(cli->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_verify_depth(cli->m_ssl_context, MAX_CERTIFICATE_DEPTH_SUPPORTED - 2);
return 0;
}
* @Description: verify the common name of the certificate
* @Input: X509 *peer, extended certificate structure contains certificate
* @Return: success 0, failed other value
* @See also:
*/
static int ossl_verify_method_name_matches_certificate(X509* peer)
{
int index;
X509_NAME* pstName = NULL;
X509_NAME_ENTRY* entry = NULL;
ASN1_STRING* common_name_asn = NULL;
char* common_name_str = NULL;
pstName = X509_get_subject_name(peer);
index = X509_NAME_get_index_by_NID(pstName, NID_commonName, 0);
if (index < 0) {
return -1;
}
entry = X509_NAME_get_entry(pstName, index);
if (entry == NULL) {
return -1;
}
common_name_asn = X509_NAME_ENTRY_get_data(entry);
if (common_name_asn == NULL) {
return -1;
}
common_name_str = (char*)ASN1_STRING_get0_data(common_name_asn);
if (common_name_str == NULL) {
return -1;
}
if ((size_t)ASN1_STRING_length(common_name_asn) != strlen(common_name_str)) {
ereport(LOG, (errmodule(MOD_SSL), errmsg("certificate's common name contains embedded null")));
return -1;
}
return 0;
}
* @Description: connect with server using SSL
* @Input: gs_openssl_client* cli, the information struct of OPENSSL
* @Return: success 0, failed other value
* @See also:
*/
static int ossl_open_connection(gs_openssl_client* cli)
{
ERR_clear_error();
int r = SSL_connect(cli->ssl);
if (r <= 0) {
int err = SSL_get_error(cli->ssl, r);
SSL_free(cli->ssl);
cli->ssl = NULL;
* We added the hint part because we don't have SSL compatibility yet on Windows GDS.
* When we connect to an non-ssl GDS with gsfss, we fail through here. Therefore this hint
* is meant to guild the user. Though not all SSL connection failures are result from the usage
* of Windows GDS.
* Moreover, the SSL handshake mech we currently have is really bad in many ways. It will need to
* be further restructured and improved.
*/
ereport(ERROR, (errmodule(MOD_SSL), errmsg("SSL connect failed, code %d", err)));
return err;
}
ereport(DEBUG2,
(errmodule(MOD_SSL),
errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED),
errmsg("connection successful using cipher(%s)", SSL_get_cipher_name(cli->ssl))));
cli->peer = SSL_get_peer_certificate(cli->ssl);
if (NULL == cli->peer) {
SSL_free(cli->ssl);
cli->ssl = NULL;
ereport(ERROR,
(errmodule(MOD_SSL), errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED), errmsg("%s", ossl_error_message())));
return -1;
}
if (ossl_verify_method_name_matches_certificate(cli->peer) != 0) {
SSL_free(cli->ssl);
cli->ssl = NULL;
ereport(ERROR,
(errmodule(MOD_SSL), errcode(ERRCODE_OPERATE_RESULT_NOT_EXPECTED), errmsg("%s", ossl_error_message())));
return -1;
}
return 0;
}
* @Description: clear the sensitive info in password
* @Input: gs_openssl_client* cli, the information struct of OPENSSL
* @Return: NULL
* @See also:
*/
static inline void ossl_clear_passwd_mem(gs_openssl_client* cli)
{
int rc = memset_s(cli->plain_passwd, CIPHER_LEN + 1, 0, CIPHER_LEN + 1);
securec_check(rc, "\0", "\0");
}
* @Description:DH verification callback which verifies the DH paramters of
* Server DH Public key
* @Return:success 1, failed 0
* @See also:
*/
static int opencli_dh_verify_cb(const SSL* s, const SSL_CTX* ctx, int op, int bits, int nid, void* other, void* ex)
{
if (op == SSL_SECOP_TMP_DH && ((bits < MIN_DHLENTH) || (bits > MAX_DHLENTH))) {
return 0;
}
return 1;
}
static char* ssl_cipher_list2string(const char* ciphers[], const int num)
{
int i;
int catlen = 0;
char* cipher_buf = NULL;
errno_t errorno = EOK;
size_t CIPHER_BUF_SIZE = 0;
for (i = 0; i < num; i++) {
CIPHER_BUF_SIZE += (strlen(ciphers[i]) + 1);
}
cipher_buf = (char*)OPENSSL_zalloc(CIPHER_BUF_SIZE);
if (cipher_buf == NULL) {
return NULL;
}
for (i = 0; i < num; i++) {
errorno = memcpy_s(cipher_buf + catlen, strlen(ciphers[i]), ciphers[i], strlen(ciphers[i]));
securec_check(errorno, "\0", "\0");
catlen += strlen(ciphers[i]);
if (i < num - 1) {
errorno = memcpy_s(cipher_buf + catlen, CIPHER_BUF_SIZE - catlen, ":", 1);
securec_check(errorno, "\0", "\0");
catlen += 1;
}
}
cipher_buf[catlen] = 0;
return cipher_buf;
}
* Brief : static int SSL_CTX_set_cipher_list_ex(SSL_CTX *ctx, const char* ciphers[], const int num)
* Description : set ssl ciphers.
*/
static int SSL_CTX_set_cipher_list_ex(SSL_CTX* ctx, const char* ciphers[], const int num)
{
int ret = 0;
char* cipher_buf = NULL;
if (num == 0) {
return 0;
}
if (ctx == NULL) {
return 0;
}
cipher_buf = ssl_cipher_list2string(ciphers, num);
if (cipher_buf == NULL) {
return 0;
}
ret = SSL_CTX_set_cipher_list(ctx, cipher_buf);
if (ret != 1) {
return 0;
}
OPENSSL_free(cipher_buf);
return ret;
}
#ifdef ENABLE_UT
#undef static
#endif