867 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			867 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 has_method_none)
 | |
| {
 | |
|   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 {
 | |
|       //if server has auth method none, server does not verify client identity
 | |
|       if (has_method_none) {
 | |
|         SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
 | |
|       }
 | |
|       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;
 | |
| }
 | |
| 
 | |
| SSL_CTX* ussl_get_server_ctx(int ctx_id)
 | |
| {
 | |
|   SSL_CTX *ctx = NULL;
 | |
|   pthread_rwlock_rdlock(&g_ssl_ctx_rwlock);
 | |
|   ctx = gs_ssl_ctx_array[ctx_id][SSL_ROLE_SERVER];
 | |
|   pthread_rwlock_unlock(&g_ssl_ctx_rwlock);
 | |
|   return ctx;
 | |
| } | 
