854 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			854 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/**
 | 
						|
 * Copyright (c) 2021 OceanBase
 | 
						|
 * OceanBase CE is licensed under Mulan PubL v2.
 | 
						|
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 | 
						|
 * You may obtain a copy of Mulan PubL v2 at:
 | 
						|
 *          http://license.coscl.org.cn/MulanPubL-2.0
 | 
						|
 * 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 PubL v2 for more details.
 | 
						|
 */
 | 
						|
 | 
						|
#include <openssl/evp.h>
 | 
						|
#include <openssl/x509.h>
 | 
						|
#include <openssl/pem.h>
 | 
						|
#include <openssl/err.h>
 | 
						|
#include <openssl/engine.h>
 | 
						|
#include <openssl/ssl.h>
 | 
						|
#include <string.h>
 | 
						|
#include <pthread.h>
 | 
						|
#include <dlfcn.h>
 | 
						|
#include <bits/pthreadtypes.h>
 | 
						|
#include "ssl_config.h"
 | 
						|
 | 
						|
#define SSL_CTX_ID_MAX 10
 | 
						|
static pthread_rwlock_t g_ssl_ctx_rwlock;
 | 
						|
static __thread int hook_flag = 1;
 | 
						|
#define FD_MAX (100 * 10000) // set the fd limit to be 100w
 | 
						|
 | 
						|
static const char tls_ciphers_list[] =
 | 
						|
    "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:"
 | 
						|
    "!DHE-DSS-DES-CBC3-SHA:!DHE-RSA-DES-CBC3-SHA:"
 | 
						|
    "!ECDH-RSA-DES-CBC3-SHA:!ECDH-ECDSA-DES-CBC3-SHA:"
 | 
						|
    "!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA:"
 | 
						|
    "ECDHE-ECDSA-AES128-GCM-SHA256:"
 | 
						|
    "ECDHE-ECDSA-AES256-GCM-SHA384:"
 | 
						|
    "ECDHE-RSA-AES128-GCM-SHA256:"
 | 
						|
    "ECDHE-RSA-AES256-GCM-SHA384:"
 | 
						|
    "ECDHE-ECDSA-AES128-SHA256:"
 | 
						|
    "ECDHE-RSA-AES128-SHA256:"
 | 
						|
    "ECDHE-ECDSA-AES256-SHA384:"
 | 
						|
    "ECDHE-RSA-AES256-SHA384:"
 | 
						|
    "DHE-RSA-AES128-GCM-SHA256:"
 | 
						|
    "DHE-DSS-AES128-GCM-SHA256:"
 | 
						|
    "DHE-RSA-AES128-SHA256:"
 | 
						|
    "DHE-DSS-AES128-SHA256:"
 | 
						|
    "DHE-DSS-AES256-GCM-SHA384:"
 | 
						|
    "DHE-RSA-AES256-SHA256:"
 | 
						|
    "DHE-DSS-AES256-SHA256:"
 | 
						|
    "ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:"
 | 
						|
    "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:"
 | 
						|
    "DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
 | 
						|
    "TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
 | 
						|
    "AES128-GCM-SHA256:DH-DSS-AES128-GCM-SHA256:"
 | 
						|
    "ECDH-ECDSA-AES128-GCM-SHA256:AES256-GCM-SHA384:"
 | 
						|
    "DH-DSS-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:"
 | 
						|
    "AES128-SHA256:DH-DSS-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:AES256-SHA256:"
 | 
						|
    "DH-DSS-AES256-SHA256:ECDH-ECDSA-AES256-SHA384:AES128-SHA:"
 | 
						|
    "DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
 | 
						|
    "DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:"
 | 
						|
    "DH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-GCM-SHA256:DH-RSA-AES256-GCM-SHA384:"
 | 
						|
    "ECDH-RSA-AES256-GCM-SHA384:DH-RSA-AES128-SHA256:"
 | 
						|
    "ECDH-RSA-AES128-SHA256:DH-RSA-AES256-SHA256:"
 | 
						|
    "ECDH-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:"
 | 
						|
    "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA:"
 | 
						|
    "ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
 | 
						|
    "TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
 | 
						|
    "AES128-SHA:DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
 | 
						|
    "DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DH-RSA-AES128-SHA:"
 | 
						|
    "ECDH-RSA-AES128-SHA:DH-RSA-AES256-SHA:ECDH-RSA-AES256-SHA:DES-CBC3-SHA";
 | 
						|
 | 
						|
static const char baba_tls_ciphers_list[] =
 | 
						|
    "!aNULL:!eNULL:!EXPORT:!LOW:!MD5:!DES:!RC2:!RC4:!PSK:"
 | 
						|
    "!DHE-DSS-DES-CBC3-SHA:!DHE-RSA-DES-CBC3-SHA:"
 | 
						|
    "!ECDH-RSA-DES-CBC3-SHA:!ECDH-ECDSA-DES-CBC3-SHA:"
 | 
						|
    "!ECDHE-RSA-DES-CBC3-SHA:!ECDHE-ECDSA-DES-CBC3-SHA:"
 | 
						|
    "ECC-SM2-WITH-SM4-SM3:ECDHE-SM2-WITH-SM4-SM3:"
 | 
						|
    "ECDHE-ECDSA-AES128-GCM-SHA256:"
 | 
						|
    "ECDHE-ECDSA-AES256-GCM-SHA384:"
 | 
						|
    "ECDHE-RSA-AES128-GCM-SHA256:"
 | 
						|
    "ECDHE-RSA-AES256-GCM-SHA384:"
 | 
						|
    "ECDHE-ECDSA-AES128-SHA256:"
 | 
						|
    "ECDHE-RSA-AES128-SHA256:"
 | 
						|
    "ECDHE-ECDSA-AES256-SHA384:"
 | 
						|
    "ECDHE-RSA-AES256-SHA384:"
 | 
						|
    "DHE-RSA-AES128-GCM-SHA256:"
 | 
						|
    "DHE-DSS-AES128-GCM-SHA256:"
 | 
						|
    "DHE-RSA-AES128-SHA256:"
 | 
						|
    "DHE-DSS-AES128-SHA256:"
 | 
						|
    "DHE-DSS-AES256-GCM-SHA384:"
 | 
						|
    "DHE-RSA-AES256-SHA256:"
 | 
						|
    "DHE-DSS-AES256-SHA256:"
 | 
						|
    "ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:"
 | 
						|
    "ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:"
 | 
						|
    "DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
 | 
						|
    "TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
 | 
						|
    "AES128-GCM-SHA256:DH-DSS-AES128-GCM-SHA256:"
 | 
						|
    "ECDH-ECDSA-AES128-GCM-SHA256:AES256-GCM-SHA384:"
 | 
						|
    "DH-DSS-AES256-GCM-SHA384:ECDH-ECDSA-AES256-GCM-SHA384:"
 | 
						|
    "AES128-SHA256:DH-DSS-AES128-SHA256:ECDH-ECDSA-AES128-SHA256:AES256-SHA256:"
 | 
						|
    "DH-DSS-AES256-SHA256:ECDH-ECDSA-AES256-SHA384:AES128-SHA:"
 | 
						|
    "DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
 | 
						|
    "DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DHE-RSA-AES256-GCM-SHA384:"
 | 
						|
    "DH-RSA-AES128-GCM-SHA256:ECDH-RSA-AES128-GCM-SHA256:DH-RSA-AES256-GCM-SHA384:"
 | 
						|
    "ECDH-RSA-AES256-GCM-SHA384:DH-RSA-AES128-SHA256:"
 | 
						|
    "ECDH-RSA-AES128-SHA256:DH-RSA-AES256-SHA256:"
 | 
						|
    "ECDH-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:"
 | 
						|
    "ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA:"
 | 
						|
    "ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES128-SHA:DHE-RSA-AES128-SHA:"
 | 
						|
    "TLS_DHE_DSS_WITH_AES_256_CBC_SHA:DHE-RSA-AES256-SHA:"
 | 
						|
    "AES128-SHA:DH-DSS-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES256-SHA:"
 | 
						|
    "DH-DSS-AES256-SHA:ECDH-ECDSA-AES256-SHA:DH-RSA-AES128-SHA:"
 | 
						|
    "ECDH-RSA-AES128-SHA:DH-RSA-AES256-SHA:ECDH-RSA-AES256-SHA:DES-CBC3-SHA";
 | 
						|
 | 
						|
 | 
						|
struct fd_ssl_st
 | 
						|
{
 | 
						|
  SSL *ssl;
 | 
						|
  int hand_shake_done;
 | 
						|
  int type;
 | 
						|
  //USSL_AUTH_SSL_HANDSHAKE: only use ssl to do authentication
 | 
						|
  //USSL_AUTH_SSL_IO :use ssl to do authentication and I/O
 | 
						|
};
 | 
						|
 | 
						|
static SSL_CTX *gs_ssl_ctx_array[SSL_CTX_ID_MAX][SSL_ROLE_MAX];
 | 
						|
static struct fd_ssl_st gs_fd_ssl_array[FD_MAX];
 | 
						|
 | 
						|
static void __attribute__((constructor(103))) setup()
 | 
						|
{
 | 
						|
  memset(gs_ssl_ctx_array, 0, sizeof(gs_ssl_ctx_array));
 | 
						|
  memset(gs_fd_ssl_array, 0, sizeof(gs_fd_ssl_array));
 | 
						|
  pthread_rwlock_init(&g_ssl_ctx_rwlock, NULL);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
static X509 *ob_ssl_get_sm_cert_memory(const char *cert)
 | 
						|
{
 | 
						|
  BIO *bio = NULL;
 | 
						|
  X509 *x509 = NULL;
 | 
						|
  if (NULL == (bio = BIO_new_mem_buf(cert, -1))) {
 | 
						|
    ussl_log_error("BIO_new_mem_buf failed, errno:%d", errno);
 | 
						|
  } else if (NULL == (x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL))) {
 | 
						|
    ussl_log_error("PEM_read_bio_X509 failed, errno:%d", errno);
 | 
						|
  }
 | 
						|
  if (NULL != bio) {
 | 
						|
    BIO_free(bio);
 | 
						|
  }
 | 
						|
  return x509;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
static EVP_PKEY *ob_ssl_get_sm_pkey_memory(const char *key)
 | 
						|
{
 | 
						|
  BIO *bio = NULL;
 | 
						|
  EVP_PKEY *pkey = NULL;
 | 
						|
  if (NULL == (bio = BIO_new_mem_buf(key, strlen(key)))) {
 | 
						|
    ussl_log_error("BIO_new_mem_buf failed, errno:%d", errno);
 | 
						|
  } else if (NULL == (pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL))) {
 | 
						|
    ussl_log_error("PEM_read_bio_PrivateKey failed, errno:%d", errno);
 | 
						|
  }
 | 
						|
  if (NULL != bio) {
 | 
						|
    BIO_free(bio);
 | 
						|
  }
 | 
						|
  return pkey;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static int ob_ssl_config_check(const ssl_config_item_t *ssl_config)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  if (NULL == ssl_config->ca_cert || 0 == strlen(ssl_config->ca_cert)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("invalid ca_cert, ret:%d", ret);
 | 
						|
  } else if (NULL == ssl_config->sign_cert || 0 == strlen(ssl_config->sign_cert)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("invalid sign_cert, ret:%d", ret);
 | 
						|
  } else if (NULL == ssl_config->sign_private_key || 0 == strlen(ssl_config->sign_private_key)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("invalid sign_private_key, ret:%d", ret);
 | 
						|
  } else if (ssl_config->is_sm) {
 | 
						|
    if (NULL == ssl_config->enc_cert || 0 == strlen(ssl_config->enc_cert)) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("SM mode, invalid enc_cert, ret:%d", ret);
 | 
						|
    } else if (NULL == ssl_config->enc_private_key || 0 == strlen(ssl_config->enc_private_key)) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("SM mode, invalid  enc_private_key, ret:%d", ret);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int ob_ssl_set_verify_mode_and_load_CA(SSL_CTX *ctx, const ssl_config_item_t *ssl_config, int verify_flag)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL_CTX_set_verify(ctx, verify_flag, NULL);
 | 
						|
  if (ssl_config->is_from_file) {
 | 
						|
    STACK_OF(X509_NAME) *list = NULL;
 | 
						|
    if (0 == SSL_CTX_load_verify_locations(ctx, ssl_config->ca_cert, NULL)) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("SSL_CTX_load_verify_locations failed ret:%d, err:%s", ret,
 | 
						|
                    ERR_error_string(ERR_get_error(), NULL));
 | 
						|
    } else if (NULL == (list = SSL_load_client_CA_file(ssl_config->ca_cert))) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("SSL_load_client_CA_file failed, ret:%d, err:%s", ret,
 | 
						|
                    ERR_error_string(ERR_get_error(), NULL));
 | 
						|
    } else {
 | 
						|
      ERR_clear_error();
 | 
						|
      SSL_CTX_set_client_CA_list(ctx, list);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    BIO *bio = NULL;
 | 
						|
    X509 *cert_x509 = NULL;
 | 
						|
    X509_STORE *x509_store = NULL;
 | 
						|
    if (NULL == (bio = BIO_new_mem_buf((void *)ssl_config->ca_cert, -1))) {
 | 
						|
      ret = ENOMEM;
 | 
						|
      ussl_log_error("BIO_new_mem_buf failed, ret:%d", ret);
 | 
						|
    } else if (NULL == (cert_x509 = PEM_read_bio_X509(bio, NULL, 0, NULL))) {
 | 
						|
      ret = ENOMEM;
 | 
						|
      ussl_log_error("PEM_read_bio_X509 failed, ret:%d", ret);
 | 
						|
    } else if (NULL == (x509_store = X509_STORE_new())) {
 | 
						|
      ret = ENOMEM;
 | 
						|
      ussl_log_error("X509_STORE_new failed, ret:%d", ret);
 | 
						|
    } else if (0 == X509_STORE_add_cert(x509_store, cert_x509)) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("X509_STORE_add_cert failed, ret:%d, err:%s", ret,
 | 
						|
                    ERR_error_string(ERR_get_error(), NULL));
 | 
						|
    } else {
 | 
						|
      SSL_CTX_set_cert_store(ctx, x509_store);
 | 
						|
    }
 | 
						|
    if (NULL != bio) {
 | 
						|
      BIO_free(bio);
 | 
						|
    }
 | 
						|
    if (NULL != cert_x509) {
 | 
						|
      X509_free(cert_x509);
 | 
						|
    }
 | 
						|
    if (0 != ret) {
 | 
						|
      if (NULL != x509_store) {
 | 
						|
        X509_STORE_free(x509_store);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
static int ob_ssl_load_cert_and_pkey_for_sm_memory(SSL_CTX *ctx,
 | 
						|
                                                   const ssl_config_item_t *ssl_config)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  EVP_PKEY *sign_pkey = NULL;
 | 
						|
  EVP_PKEY *enc_pkey = NULL;
 | 
						|
  X509 *sign_x509 = NULL;
 | 
						|
  X509 *enc_x509 = NULL;
 | 
						|
  if (NULL == (sign_pkey = ob_ssl_get_sm_pkey_memory(ssl_config->sign_private_key))) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("ob_ssl_get_sm_pkey_memory failed, ret:%d", ret);
 | 
						|
  } else if (!SSL_CTX_use_sign_PrivateKey(ctx, sign_pkey)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX_use_sign_PrivateKey failed, ret:%d, err:%s", ret,
 | 
						|
                  ERR_error_string(ERR_get_error(), NULL));
 | 
						|
  } else if (NULL == (sign_x509 = ob_ssl_get_sm_cert_memory(ssl_config->sign_cert))) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("ob_ssl_get_sm_cert_memory failed, ret:%d", ret);
 | 
						|
  } else if (!SSL_CTX_use_sign_certificate(ctx, sign_x509)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX_use_sign_certificate failed, ret:%d, err:%s", ret,
 | 
						|
                  ERR_error_string(ERR_get_error(), NULL));
 | 
						|
  } else if (NULL == (enc_pkey = ob_ssl_get_sm_pkey_memory(ssl_config->enc_private_key))) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("ob_ssl_get_sm_pkey_memory failed, ret:%d", ret);
 | 
						|
  } else if (!SSL_CTX_use_enc_PrivateKey(ctx, enc_pkey)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX_use_enc_PrivateKey failed, ret:%d, err:%s", ret,
 | 
						|
                  ERR_error_string(ERR_get_error(), NULL));
 | 
						|
  } else if (NULL == (enc_x509 = ob_ssl_get_sm_cert_memory(ssl_config->enc_cert))) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("ob_ssl_get_sm_cert_memory failed, ret:%d", ret);
 | 
						|
  } else if (!SSL_CTX_use_enc_certificate(ctx, enc_x509)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX_use_enc_certificate failed,ret:%d, err:%s", ret,
 | 
						|
                  ERR_error_string(ERR_get_error(), NULL));
 | 
						|
  }
 | 
						|
  if (NULL != sign_pkey) {
 | 
						|
    EVP_PKEY_free(sign_pkey);
 | 
						|
  }
 | 
						|
  if (NULL != enc_pkey) {
 | 
						|
    EVP_PKEY_free(enc_pkey);
 | 
						|
  }
 | 
						|
  if (NULL != sign_x509) {
 | 
						|
    X509_free(sign_x509);
 | 
						|
  }
 | 
						|
  if (NULL != enc_x509) {
 | 
						|
    X509_free(enc_x509);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
static int ob_ssl_load_cert_and_pkey_for_intl_memory(SSL_CTX *ctx,
 | 
						|
                                                     const ssl_config_item_t *ssl_config)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  int is_first = 1;
 | 
						|
  BIO *bio = NULL;
 | 
						|
  STACK_OF(X509_INFO) *inf = NULL;
 | 
						|
 | 
						|
  if (NULL == (bio = BIO_new_mem_buf((void *)ssl_config->sign_cert, -1))) {
 | 
						|
    ret = ENOMEM;
 | 
						|
    ussl_log_error("BIO_new_mem_buf failed, ret:%d", ret);
 | 
						|
  } else if (NULL == (inf = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL))) {
 | 
						|
    ret = ENOMEM;
 | 
						|
    ussl_log_error("PEM_X509_INFO_read_bio failed, ret:%d", ret);
 | 
						|
  } else {
 | 
						|
    for (int i = 0; i < sk_X509_INFO_num(inf) && (0 == ret); i++) {
 | 
						|
      X509_INFO *itmp = sk_X509_INFO_value(inf, i);
 | 
						|
      if (itmp->x509) {
 | 
						|
        if (is_first) {
 | 
						|
          is_first = 0;
 | 
						|
          if (SSL_CTX_use_certificate(ctx, itmp->x509) <= 0) {
 | 
						|
            ret = EINVAL;
 | 
						|
            ussl_log_warn("SSL_CTX_use_certificate failed, ret:%d", ret);
 | 
						|
          }
 | 
						|
        } else {
 | 
						|
          if (SSL_CTX_add_extra_chain_cert(ctx, itmp->x509) <= 0) {
 | 
						|
            ret = EINVAL;
 | 
						|
            ussl_log_warn("SSL_CTX_add_extra_chain_cert failed, ret:%d", ret);
 | 
						|
          } else {
 | 
						|
            itmp->x509 = NULL;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    // free bio allocate before
 | 
						|
    if (NULL != bio) {
 | 
						|
      BIO_free(bio);
 | 
						|
    }
 | 
						|
    bio = NULL;
 | 
						|
    if (0 == ret) {
 | 
						|
      RSA *rsa = NULL;
 | 
						|
      if (NULL == (bio = BIO_new_mem_buf((void *)ssl_config->sign_private_key, -1))) {
 | 
						|
        ret = ENOMEM;
 | 
						|
        ussl_log_error("BIO_new_mem_buf for sign_private_key failed, ret:%d", ret);
 | 
						|
      } else if (NULL == (rsa = PEM_read_bio_RSAPrivateKey(bio, NULL, 0, NULL))) {
 | 
						|
        ret = ENOMEM;
 | 
						|
        ussl_log_warn("PEM_read_bio_RSAPrivateKey failed, ret:%d", ret);
 | 
						|
      } else if (SSL_CTX_use_RSAPrivateKey(ctx, rsa) <= 0) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_RSAPrivateKey failed, ret:%d", ret);
 | 
						|
      }
 | 
						|
      if (0 != ret) {
 | 
						|
        if (NULL != rsa) {
 | 
						|
          RSA_free(rsa);
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (NULL != inf) {
 | 
						|
    sk_X509_INFO_pop_free(inf, X509_INFO_free);
 | 
						|
  }
 | 
						|
  if (NULL != bio) {
 | 
						|
    BIO_free(bio);
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
static int ob_ssl_load_cert_and_pkey(SSL_CTX *ctx, const ssl_config_item_t *ssl_config)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  if (ssl_config->is_from_file) {
 | 
						|
    if (ssl_config->is_sm) {
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
      if (!SSL_CTX_use_sign_PrivateKey_file(ctx, ssl_config->sign_private_key, SSL_FILETYPE_PEM)) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_sign_PrivateKey_file failed,ret:%d", ret);
 | 
						|
      } else if (!SSL_CTX_use_sign_certificate_file(ctx, ssl_config->sign_cert, SSL_FILETYPE_PEM)) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_sign_certificate_file failed, ret:%d", ret);
 | 
						|
      } else if (!SSL_CTX_use_enc_PrivateKey_file(ctx, ssl_config->enc_private_key,
 | 
						|
                                                  SSL_FILETYPE_PEM)) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_enc_PrivateKey_file failed, ret:%d", ret);
 | 
						|
      } else if (!SSL_CTX_use_enc_certificate_file(ctx, ssl_config->enc_cert, SSL_FILETYPE_PEM)) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_enc_certificate_file failed, ret:%d", ret);
 | 
						|
      }
 | 
						|
#endif
 | 
						|
    } else {
 | 
						|
      if (SSL_CTX_use_certificate_chain_file(ctx, ssl_config->sign_cert) <= 0) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_certificate_chain_file failed, ret:%d", ret);
 | 
						|
      } else if (SSL_CTX_use_PrivateKey_file(ctx, ssl_config->sign_private_key, SSL_FILETYPE_PEM) <=
 | 
						|
                 0) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_use_PrivateKey_file failed, ret:%d", ret);
 | 
						|
      } else if (SSL_CTX_check_private_key(ctx) <= 0) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_check_private_key failed, ret:%d", ret);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if (ssl_config->is_sm) {
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
      if (0 != (ret = ob_ssl_load_cert_and_pkey_for_sm_memory(ctx, ssl_config))) {
 | 
						|
        ussl_log_warn("ob_ssl_load_cert_and_pkey_for_sm_memory failed, ret:%d", ret);
 | 
						|
      }
 | 
						|
#endif
 | 
						|
    } else {
 | 
						|
      if (0 != (ret = ob_ssl_load_cert_and_pkey_for_intl_memory(ctx, ssl_config))) {
 | 
						|
        ussl_log_warn("ob_ssl_load_cert_and_pkey_for_intl_memory failed, ret:%d", ret);
 | 
						|
      } else if (SSL_CTX_check_private_key(ctx) <= 0) {
 | 
						|
        ret = EINVAL;
 | 
						|
        ussl_log_warn("SSL_CTX_check_private_key failed, ret:%d, err:%s", ret,
 | 
						|
                      ERR_error_string(ERR_get_error(), NULL));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
static const int CLIENT = 0;
 | 
						|
static const int SERVER = 1;
 | 
						|
 | 
						|
static SSL_CTX *ob_ssl_create_ssl_ctx(const ssl_config_item_t *ssl_config, int type)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL_CTX *ctx = NULL;
 | 
						|
  int verify_flag = 0;
 | 
						|
  if (CLIENT == type) {
 | 
						|
    verify_flag = SSL_VERIFY_NONE;
 | 
						|
  } else {
 | 
						|
    verify_flag = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
 | 
						|
  }
 | 
						|
 | 
						|
  if (ssl_config->is_sm) {
 | 
						|
#ifdef OB_USE_BABASSL
 | 
						|
    ctx = SSL_CTX_new(NTLS_method());
 | 
						|
    if (NULL != ctx) {
 | 
						|
      SSL_CTX_enable_ntls(ctx);
 | 
						|
    }
 | 
						|
#endif
 | 
						|
  } else {
 | 
						|
    ctx = SSL_CTX_new(SSLv23_method());
 | 
						|
  }
 | 
						|
 | 
						|
  if (NULL == ctx) {
 | 
						|
    ret = ENOMEM;
 | 
						|
    ussl_log_error("SSL_CTX_new failed, ret:%d", ret);
 | 
						|
  } else if (SSL_CTX_set_cipher_list(
 | 
						|
                 ctx, (ssl_config->is_sm ? baba_tls_ciphers_list : tls_ciphers_list)) <= 0) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX_set_cipher_list failed, ret:%d, err:%s", ret,
 | 
						|
                  ERR_error_string(ERR_get_error(), NULL));
 | 
						|
  } else if (0 != (ret = ob_ssl_set_verify_mode_and_load_CA(ctx, ssl_config, verify_flag))) {
 | 
						|
    ussl_log_warn("ob_ssl_set_verify_mode_and_load_CA failed, ret:%d", ret);
 | 
						|
  } else if (0 != (ret = ob_ssl_load_cert_and_pkey(ctx, ssl_config))) {
 | 
						|
    ussl_log_warn("ob_ssl_load_cert_and_pkey for client failed, ret:%d", ret);
 | 
						|
  } else {
 | 
						|
    /* client side options */
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_NETSCAPE_CHALLENGE_BUG);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG);
 | 
						|
 | 
						|
    /* server side options */
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER);
 | 
						|
  #if OPENSSL_VERSION_NUMBER >= 0x10101000L
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_NO_TLSv1_3);
 | 
						|
  #endif
 | 
						|
    /* this option allow a potential SSL 2.0 rollback (CAN-2005-2969) */
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_MSIE_SSLV2_RSA_PADDING);
 | 
						|
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_SSLEAY_080_CLIENT_DH_BUG);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_TLS_D5_BUG);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_TLS_BLOCK_PADDING_BUG);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
 | 
						|
    SSL_CTX_set_options(ctx, SSL_OP_SINGLE_DH_USE);
 | 
						|
    /*set_read_ahead may cause the first application data that been sent after
 | 
						|
    * SSL handshake being unprocessed, forbid it.
 | 
						|
    */
 | 
						|
    SSL_CTX_set_read_ahead(ctx, 0);
 | 
						|
  }
 | 
						|
  if (0 != ret) {
 | 
						|
    SSL_CTX_free(ctx);
 | 
						|
    ctx = NULL;
 | 
						|
  }
 | 
						|
  return ctx;
 | 
						|
}
 | 
						|
 | 
						|
static int ob_ssl_ctx_reconfigure(int ctx_id, int ctx_role, SSL_CTX *ssl_ctx)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL_CTX *ssl_ctx_temp = NULL;
 | 
						|
  if (NULL == (ssl_ctx_temp = gs_ssl_ctx_array[ctx_id][ctx_role])) {
 | 
						|
    gs_ssl_ctx_array[ctx_id][ctx_role] = ssl_ctx;
 | 
						|
  } else {
 | 
						|
    SSL_CTX_free(ssl_ctx_temp);
 | 
						|
    gs_ssl_ctx_array[ctx_id][ctx_role] = ssl_ctx;
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
void fd_disable_ssl(int fd)
 | 
						|
{
 | 
						|
  if (fd >= 0) {
 | 
						|
    SSL *ssl = gs_fd_ssl_array[fd].ssl;
 | 
						|
    gs_fd_ssl_array[fd].ssl = NULL;
 | 
						|
    gs_fd_ssl_array[fd].hand_shake_done = 0;
 | 
						|
    gs_fd_ssl_array[fd].type = 0;
 | 
						|
    if (NULL == ssl) {
 | 
						|
    } else {
 | 
						|
      int mode = 0;
 | 
						|
      mode = SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN;
 | 
						|
      SSL_set_shutdown(ssl, mode);
 | 
						|
      ERR_clear_error();
 | 
						|
      SSL_shutdown(ssl);
 | 
						|
      SSL_free(ssl);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
int ssl_load_config(int ctx_id, const ssl_config_item_t *ssl_config)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL_CTX *client_ssl_ctx = NULL;
 | 
						|
  SSL_CTX *server_ssl_ctx = NULL;
 | 
						|
  if (ctx_id >= SSL_CTX_ID_MAX || ctx_id < 0) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_error("ctx_id is invalid, ret:%d, ctx_id:%d, max_ctx_id:%d", ret, ctx_id,
 | 
						|
                   SSL_CTX_ID_MAX);
 | 
						|
  } else {
 | 
						|
    if (0 != (ret = ob_ssl_config_check(ssl_config))) {
 | 
						|
      ussl_log_warn("ob_ssl_config_check failed, ret:%d, ctx_id:%d", ret, ctx_id);
 | 
						|
    } else if (NULL == (client_ssl_ctx = ob_ssl_create_ssl_ctx(ssl_config, CLIENT))) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("ob_ssl_create_client_ctx failed, ctx_id:%d, ret:%d", ctx_id, ret);
 | 
						|
    } else if (NULL == (server_ssl_ctx = ob_ssl_create_ssl_ctx(ssl_config, SERVER))) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("ob_ssl_create_server_ctx failed, ctx_id:%d, ret:%d", ctx_id, ret);
 | 
						|
    } else {
 | 
						|
      pthread_rwlock_wrlock(&g_ssl_ctx_rwlock);
 | 
						|
      if (0 != (ret = ob_ssl_ctx_reconfigure(ctx_id, SSL_ROLE_SERVER, server_ssl_ctx))) {
 | 
						|
        ussl_log_warn("ob_ssl_ctx_reconfigure for server failed, ctx_id:%d, ret:%d", ctx_id, ret);
 | 
						|
      } else if (0 != (ret = ob_ssl_ctx_reconfigure(ctx_id, SSL_ROLE_CLIENT, client_ssl_ctx))) {
 | 
						|
        ussl_log_warn("ob_ssl_ctx_reconfigure for client failed, ctx_id:%d, ret:%d", ctx_id, ret);
 | 
						|
      } else {
 | 
						|
        ssl_config_ctx_id = ctx_id;
 | 
						|
        ussl_log_info("load ssl config success! ctx_id:%d", ctx_id);
 | 
						|
      }
 | 
						|
      pthread_rwlock_unlock(&g_ssl_ctx_rwlock);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int fd_enable_ssl_for_server(int fd, int ctx_id, int type)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL_CTX *ctx = NULL;
 | 
						|
  pthread_rwlock_rdlock(&g_ssl_ctx_rwlock);
 | 
						|
  if (ctx_id >= SSL_CTX_ID_MAX || ctx_id < 0 || fd >= FD_MAX) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_error("ctx_id or fd is beyond limit, ret:%d, fd:%d, ctx_id:%d", ret, fd, ctx_id);
 | 
						|
  } else if (NULL == (ctx = gs_ssl_ctx_array[ctx_id][SSL_ROLE_SERVER])) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX is null, maybe not configured, ret:%d, fd:%d, ctx_id:%d", ret, fd,
 | 
						|
                  ctx_id);
 | 
						|
  } else {
 | 
						|
    SSL *ssl = NULL;
 | 
						|
    if (NULL == (ssl = SSL_new(ctx))) {
 | 
						|
      ret = ENOMEM;
 | 
						|
      ussl_log_error("SSL_new failed, ret:%d, fd:%d, ctx_id:%d", ret, fd, ctx_id);
 | 
						|
    } else if (0 == SSL_set_fd(ssl, fd)) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("SSL_set_fd failed, ret:%d, fd:%d, ctx_id:%d", ret, fd, ctx_id);
 | 
						|
    } else {
 | 
						|
      SSL_set_accept_state(ssl);
 | 
						|
      ATOMIC_STORE(&(gs_fd_ssl_array[fd].ssl), ssl);
 | 
						|
      ATOMIC_STORE(&(gs_fd_ssl_array[fd].type), type);
 | 
						|
    }
 | 
						|
    if (0 != ret) {
 | 
						|
      if (NULL != ssl) {
 | 
						|
        SSL_free(ssl);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  pthread_rwlock_unlock(&g_ssl_ctx_rwlock);
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int fd_enable_ssl_for_client(int fd, int ctx_id, int type)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL_CTX *ctx = NULL;
 | 
						|
  pthread_rwlock_rdlock(&g_ssl_ctx_rwlock);
 | 
						|
  if (ctx_id >= SSL_CTX_ID_MAX || ctx_id < 0 || fd >= FD_MAX) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_error("ctx_id or fd is beyond limit, ret:%d, fd:%d, ctx_id:%d", ret, fd, ctx_id);
 | 
						|
  } else if (NULL == (ctx = gs_ssl_ctx_array[ctx_id][SSL_ROLE_CLIENT])) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_warn("SSL_CTX is null, maybe not configured, ret:%d, fd:%d, ctx_id:%d", ret, fd,
 | 
						|
                  ctx_id);
 | 
						|
  } else {
 | 
						|
    SSL *ssl = NULL;
 | 
						|
    if (NULL == (ssl = SSL_new(ctx))) {
 | 
						|
      ret = ENOMEM;
 | 
						|
      ussl_log_error("SSL_new failed, ret:%d, fd:%d, ctx_id:%d", ret, fd, ctx_id);
 | 
						|
    } else if (0 == SSL_set_fd(ssl, fd)) {
 | 
						|
      ret = EINVAL;
 | 
						|
      ussl_log_warn("SSL_set_fd failed, ret:%d, fd:%d, ctx_id:%d", ret, fd, ctx_id);
 | 
						|
    } else {
 | 
						|
      SSL_set_connect_state(ssl);
 | 
						|
      ATOMIC_STORE(&(gs_fd_ssl_array[fd].ssl), ssl);
 | 
						|
      ATOMIC_STORE(&(gs_fd_ssl_array[fd].type), type);
 | 
						|
    }
 | 
						|
    if (0 != ret) {
 | 
						|
      if (NULL != ssl) {
 | 
						|
        SSL_free(ssl);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  pthread_rwlock_unlock(&g_ssl_ctx_rwlock);
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
int ssl_do_handshake(int fd)
 | 
						|
{
 | 
						|
  int ret = 0;
 | 
						|
  SSL *ssl = NULL;
 | 
						|
  if (NULL == (ssl = gs_fd_ssl_array[fd].ssl)) {
 | 
						|
    ret = EINVAL;
 | 
						|
    ussl_log_error("ssl is NULL, fd:%d, ret:%d", fd, ret);
 | 
						|
  } else {
 | 
						|
    ERR_clear_error();
 | 
						|
    int ssl_ret = SSL_do_handshake(ssl);
 | 
						|
    if (ssl_ret > 0) {
 | 
						|
      gs_fd_ssl_array[fd].hand_shake_done = 1;
 | 
						|
      if (USSL_AUTH_SSL_HANDSHAKE == gs_fd_ssl_array[fd].type) {
 | 
						|
        fd_disable_ssl(fd);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      int err = SSL_get_error(ssl, ssl_ret);
 | 
						|
      if (SSL_ERROR_WANT_READ == err) {
 | 
						|
        ret = EAGAIN;
 | 
						|
      } else if (SSL_ERROR_WANT_WRITE == err) {
 | 
						|
        fd_disable_ssl(fd);
 | 
						|
        ret = EIO;
 | 
						|
        ussl_log_error("SSL_do_handshake want write, fd:%d", fd);
 | 
						|
      } else {
 | 
						|
        fd_disable_ssl(fd);
 | 
						|
        ret = EIO;
 | 
						|
        ussl_log_warn("SSL_do_handshake failed, err:%s", ERR_error_string(ERR_get_error(), NULL));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
static ssize_t do_ssl_read(int fildes, void *buf, size_t nbyte)
 | 
						|
{
 | 
						|
  ssize_t rbytes = -1;
 | 
						|
  SSL *ssl = gs_fd_ssl_array[fildes].ssl;
 | 
						|
  rbytes = SSL_read(ssl, buf, nbyte);
 | 
						|
  if (rbytes <= 0) {
 | 
						|
    int ssl_error = 0;
 | 
						|
    ssl_error = SSL_get_error(ssl, rbytes);
 | 
						|
    if (SSL_ERROR_WANT_READ == ssl_error) {
 | 
						|
      rbytes = -1;
 | 
						|
      errno = EAGAIN;
 | 
						|
    } else if (SSL_ERROR_WANT_WRITE == ssl_error) {
 | 
						|
      rbytes = -1;
 | 
						|
      errno = EIO;
 | 
						|
      ussl_log_error("SSL_read want write, maybe peer started SSL renegotiation, fd:%d", fildes);
 | 
						|
    } else if (SSL_ERROR_ZERO_RETURN == ssl_error) {
 | 
						|
      //connection shutdown by peer
 | 
						|
      rbytes = 0;
 | 
						|
      ussl_log_info("SSL_read return SSL_ERROR_ZERO_RETURN, peer shutdown, fd:%d", fildes);
 | 
						|
    } else {
 | 
						|
      rbytes = -1;
 | 
						|
      errno = EIO;
 | 
						|
      ussl_log_error("SSL_read failed, fd:%d, ssl_error:%d, errno:%d, reason:%s", fildes, ssl_error,
 | 
						|
                     errno, ERR_error_string(ERR_get_error(), NULL));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return rbytes;
 | 
						|
}
 | 
						|
*/
 | 
						|
 | 
						|
static ssize_t do_ssl_write(int fildes, const void *buf, size_t nbyte)
 | 
						|
{
 | 
						|
  ssize_t wbytes = -1;
 | 
						|
  SSL *ssl = gs_fd_ssl_array[fildes].ssl;
 | 
						|
  wbytes = SSL_write(ssl, buf, nbyte);
 | 
						|
  if (wbytes <= 0) {
 | 
						|
    wbytes = -1;
 | 
						|
    int ssl_error = SSL_get_error(ssl, wbytes);
 | 
						|
    if (SSL_ERROR_WANT_WRITE == ssl_error) {
 | 
						|
      errno = EAGAIN;
 | 
						|
    } else if (SSL_ERROR_WANT_READ == ssl_error) {
 | 
						|
      errno = EIO;
 | 
						|
      ussl_log_error("SSL_write want read, fd:%d", fildes);
 | 
						|
    } else {
 | 
						|
      errno = EIO;
 | 
						|
      ussl_log_error("SSL_write failed, fd:%d, reason:%s", fildes,
 | 
						|
                     ERR_error_string(ERR_get_error(), NULL));
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return wbytes;
 | 
						|
}
 | 
						|
 | 
						|
ssize_t write_regard_ssl(int fildes, const void *buf, size_t nbyte)
 | 
						|
{
 | 
						|
  ssize_t wbytes = -1;
 | 
						|
  if (fildes < 0 || fildes >= FD_MAX) {
 | 
						|
    errno = EINVAL;
 | 
						|
  } else {
 | 
						|
    if (NULL == gs_fd_ssl_array[fildes].ssl) {
 | 
						|
      wbytes = libc_write(fildes, buf, nbyte);
 | 
						|
    } else {
 | 
						|
      ERR_clear_error();
 | 
						|
      wbytes = do_ssl_write(fildes, buf, nbyte);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return wbytes;
 | 
						|
}
 | 
						|
 | 
						|
static int ssl_handle_recv(SSL *ssl, ssize_t n)
 | 
						|
{
 | 
						|
  int sslerr = 0;
 | 
						|
  int err = 0;
 | 
						|
  int ret = 0;
 | 
						|
  if (n > 0) {
 | 
						|
    ret = 0;
 | 
						|
  } else {
 | 
						|
    sslerr = SSL_get_error(ssl, n);
 | 
						|
    err = (SSL_ERROR_SYSCALL == sslerr) ? errno: 0;
 | 
						|
    if (SSL_ERROR_WANT_READ == sslerr) {
 | 
						|
      ret = EAGAIN;
 | 
						|
      errno = EAGAIN;
 | 
						|
    } else if (SSL_ERROR_ZERO_RETURN == sslerr || ERR_peek_error() == 0) {
 | 
						|
      errno = ECONNRESET;
 | 
						|
      ret = ECONNRESET;
 | 
						|
    } else {
 | 
						|
      errno = EIO;
 | 
						|
      ret = EIO;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return ret;
 | 
						|
}
 | 
						|
 | 
						|
ssize_t read_regard_ssl(int fildes, char *buf, size_t nbytes)
 | 
						|
{
 | 
						|
  ssize_t rbytes = -1;
 | 
						|
  if (fildes < 0 || fildes >= FD_MAX) {
 | 
						|
    errno = EINVAL;
 | 
						|
  } else {
 | 
						|
    if (NULL == gs_fd_ssl_array[fildes].ssl) {
 | 
						|
      rbytes = libc_read(fildes, buf, nbytes);
 | 
						|
    } else {
 | 
						|
      rbytes = 0;
 | 
						|
      ssize_t n = 0;
 | 
						|
      SSL *ssl = gs_fd_ssl_array[fildes].ssl;
 | 
						|
      ERR_clear_error();
 | 
						|
      int tmp_ret = 0;
 | 
						|
      while (0 == tmp_ret) {
 | 
						|
        n = SSL_read(ssl, buf, nbytes);
 | 
						|
        if (n > 0) {
 | 
						|
          rbytes += n;
 | 
						|
        }
 | 
						|
        int ret = ssl_handle_recv(ssl, n);
 | 
						|
        if (0 == ret) {
 | 
						|
          nbytes -= n;
 | 
						|
          if (0 == nbytes) {
 | 
						|
            tmp_ret = ENODATA;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
          buf += n;
 | 
						|
          continue;
 | 
						|
        } else {
 | 
						|
          if (rbytes) {
 | 
						|
            tmp_ret = ENODATA;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
          if (ECONNRESET == ret) {
 | 
						|
            rbytes = 0;
 | 
						|
            tmp_ret = ENODATA;
 | 
						|
            continue;
 | 
						|
          } else {
 | 
						|
            rbytes = -1;
 | 
						|
            tmp_ret = ENODATA;
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return rbytes;
 | 
						|
}
 | 
						|
 | 
						|
ssize_t writev_regard_ssl(int fildes, const struct iovec *iov, int iovcnt)
 | 
						|
{
 | 
						|
  ssize_t wbytes = -1;
 | 
						|
  if (fildes < 0 || fildes >= FD_MAX) {
 | 
						|
    errno = EINVAL;
 | 
						|
  } else {
 | 
						|
    if (NULL == gs_fd_ssl_array[fildes].ssl) {
 | 
						|
      wbytes = libc_writev(fildes, iov, iovcnt);
 | 
						|
    } else {
 | 
						|
      int i = 0;
 | 
						|
      int ret = 0;
 | 
						|
      ssize_t n = 0;
 | 
						|
      SSL *ssl = gs_fd_ssl_array[fildes].ssl;
 | 
						|
      wbytes = 0;
 | 
						|
      for (i = 0; (i < iovcnt) && (0 == ret); i++) {
 | 
						|
        ERR_clear_error();
 | 
						|
        n = SSL_write(ssl, iov[i].iov_base, iov[i].iov_len);
 | 
						|
        if (n > 0) {
 | 
						|
          wbytes += n;
 | 
						|
        } else {
 | 
						|
          int ssl_error = SSL_get_error(ssl, n);
 | 
						|
          if (SSL_ERROR_WANT_WRITE == ssl_error) {
 | 
						|
            errno = EAGAIN;
 | 
						|
          } else if (SSL_ERROR_WANT_READ == ssl_error) {
 | 
						|
            errno = EIO;
 | 
						|
            ussl_log_error("SSL_write want read, fd:%d", fildes);
 | 
						|
          } else {
 | 
						|
            errno = EIO;
 | 
						|
            ussl_log_error("SSL_write failed, fd:%d, reason:%s", fildes,
 | 
						|
                          ERR_error_string(ERR_get_error(), NULL));
 | 
						|
          }
 | 
						|
          // errno: EIO, need destroy connection
 | 
						|
          // errno: EAGAIN:
 | 
						|
          // (1) wbytes larger than 0 (means already send some data successfully), just return wbytes
 | 
						|
          // (2) wbytes equal to zero (means send the first iov), wbytes equals to n (-1 means socket buffer
 | 
						|
          // temporarily unwritable, 0 means need destroy connection)
 | 
						|
          if (EIO == errno) {
 | 
						|
            wbytes = -1;
 | 
						|
          } else if (EAGAIN == errno) {
 | 
						|
            if (wbytes > 0) {
 | 
						|
            } else {
 | 
						|
              wbytes += n;
 | 
						|
            }
 | 
						|
          }
 | 
						|
          ret = ENODATA;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return wbytes;
 | 
						|
}
 |