You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
9.1 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2016 The ZLToolKit project authors. All Rights Reserved.
*
* This file is part of ZLToolKit(https://github.com/ZLMediaKit/ZLToolKit).
*
* Use of this source code is governed by MIT license that can be found in the
* LICENSE file in the root of the source tree. All contributing project authors
* may be found in the AUTHORS file in the root of the source tree.
*/
#ifndef CRYPTO_SSLBOX_H_
#define CRYPTO_SSLBOX_H_
#include <mutex>
#include <string>
#include <functional>
#include "logger.h"
#include "List.h"
#include "util.h"
#include "Network/Buffer.h"
#include "ResourcePool.h"
typedef struct x509_st X509;
typedef struct evp_pkey_st EVP_PKEY;
typedef struct ssl_ctx_st SSL_CTX;
typedef struct ssl_st SSL;
typedef struct bio_st BIO;
namespace toolkit {
class SSL_Initor {
public:
friend class SSL_Box;
static SSL_Initor &Instance();
/**
* 从文件或字符串中加载公钥和私钥
* 该证书文件必须同时包含公钥和私钥(cer格式的证书只包括公钥请使用后面的方法加载)
* 客户端默认可以不加载证书(除非服务器要求客户端提供证书)
* @param pem_or_p12 pem或p12文件路径或者文件内容字符串
* @param server_mode 是否为服务器模式
* @param password 私钥加密密码
* @param is_file 参数pem_or_p12是否为文件路径
* @param is_default 是否为默认证书
* Load public and private keys from a file or string
* The certificate file must contain both public and private keys (cer format certificates only include public keys, use the following method to load)
* The client can load the certificate by default (unless the server requires the client to provide a certificate)
* @param pem_or_p12 pem or p12 file path or file content string
* @param server_mode Whether it is in server mode
* @param password Private key encryption password
* @param is_file Whether the parameter pem_or_p12 is a file path
* @param is_default Whether it is the default certificate
* [AUTO-TRANSLATED:18cec755]
*/
bool loadCertificate(const std::string &pem_or_p12, bool server_mode = true, const std::string &password = "",
bool is_file = true, bool is_default = true);
/**
* 是否忽略无效的证书
* 默认忽略,强烈建议不要忽略!
* @param ignore 标记
* Whether to ignore invalid certificates
* Ignore by default, strongly not recommended!
* @param ignore Flag
* [AUTO-TRANSLATED:fd45125a]
*/
void ignoreInvalidCertificate(bool ignore = true);
/**
* 信任某证书,一般用于客户端信任自签名的证书或自签名CA签署的证书使用
* 比如说我的客户端要信任我自己签发的证书,那么我们可以只信任这个证书
* @param pem_p12_cer pem文件或p12文件或cer文件路径或内容
* @param server_mode 是否为服务器模式
* @param password pem或p12证书的密码
* @param is_file 是否为文件路径
* @return 是否加载成功
* Trust a certain certificate, generally used for clients to trust self-signed certificates or certificates signed by self-signed CAs
* For example, if my client wants to trust a certificate I issued myself, we can only trust this certificate
* @param pem_p12_cer pem file or p12 file or cer file path or content
* @param server_mode Whether it is in server mode
* @param password pem or p12 certificate password
* @param is_file Whether it is a file path
* @return Whether the loading is successful
* [AUTO-TRANSLATED:9ace5400]
*/
bool trustCertificate(const std::string &pem_p12_cer, bool server_mode = false, const std::string &password = "",
bool is_file = true);
/**
* 信任某证书
* @param cer 证书公钥
* @param server_mode 是否为服务模式
* @return 是否加载成功
* Trust a certain certificate
* @param cer Certificate public key
* @param server_mode Whether it is in server mode
* @return Whether the loading is successful
* [AUTO-TRANSLATED:557120dd]
*/
bool trustCertificate(X509 *cer, bool server_mode = false);
/**
* 根据虚拟主机获取SSL_CTX对象
* @param vhost 虚拟主机名
* @param server_mode 是否为服务器模式
* @return SSL_CTX对象
* Get the SSL_CTX object based on the virtual host
* @param vhost Virtual host name
* @param server_mode Whether it is in server mode
* @return SSL_CTX object
* [AUTO-TRANSLATED:4d771109]
*/
std::shared_ptr<SSL_CTX> getSSLCtx(const std::string &vhost, bool server_mode);
private:
SSL_Initor();
~SSL_Initor();
/**
* 创建SSL对象
* Create an SSL object
* [AUTO-TRANSLATED:047a0b4c]
*/
std::shared_ptr<SSL> makeSSL(bool server_mode);
/**
* 设置ssl context
* @param vhost 虚拟主机名
* @param ctx ssl context
* @param server_mode ssl context
* @param is_default 是否为默认证书
* Set the ssl context
* @param vhost Virtual host name
* @param ctx ssl context
* @param server_mode ssl context
* @param is_default Whether it is the default certificate
* [AUTO-TRANSLATED:265f3049]
*/
bool setContext(const std::string &vhost, const std::shared_ptr<SSL_CTX> &ctx, bool server_mode, bool is_default = true);
/**
* 设置SSL_CTX的默认配置
* @param ctx 对象指针
* Set the default configuration for SSL_CTX
* @param ctx Object pointer
* [AUTO-TRANSLATED:1b3438d0]
*/
static void setupCtx(SSL_CTX *ctx);
std::shared_ptr<SSL_CTX> getSSLCtx_l(const std::string &vhost, bool server_mode);
std::shared_ptr<SSL_CTX> getSSLCtxWildcards(const std::string &vhost, bool server_mode);
/**
* 获取默认的虚拟主机
* Get the default virtual host
* [AUTO-TRANSLATED:e2430399]
*/
std::string defaultVhost(bool server_mode);
/**
* 完成vhost name 匹配的回调函数
* Callback function for completing vhost name matching
* [AUTO-TRANSLATED:f9973cfa]
*/
static int findCertificate(SSL *ssl, int *ad, void *arg);
private:
struct less_nocase {
bool operator()(const std::string &x, const std::string &y) const {
return strcasecmp(x.data(), y.data()) < 0;
}
};
private:
std::recursive_mutex _mtx;
std::string _default_vhost[2];
std::shared_ptr<SSL_CTX> _ctx_empty[2];
std::map<std::string, std::shared_ptr<SSL_CTX>, less_nocase> _ctxs[2];
std::map<std::string, std::shared_ptr<SSL_CTX>, less_nocase> _ctxs_wildcards[2];
};
////////////////////////////////////////////////////////////////////////////////////
class SSL_Box {
public:
SSL_Box(bool server_mode = true, bool enable = true, int buff_size = 32 * 1024);
~SSL_Box();
/**
* 收到密文后,调用此函数解密
* @param buffer 收到的密文数据
* Decrypts the received ciphertext after calling this function
* @param buffer Received ciphertext data
* [AUTO-TRANSLATED:7e8b1fc6]
*/
void onRecv(const Buffer::Ptr &buffer);
/**
* 需要加密明文调用此函数
* @param buffer 需要加密的明文数据
* Calls this function to encrypt the plaintext that needs to be encrypted
* @param buffer Plaintext data that needs to be encrypted
* [AUTO-TRANSLATED:9d386695]
*/
void onSend(Buffer::Ptr buffer);
/**
* 设置解密后获取明文的回调
* @param cb 回调对象
* Sets the callback to get the plaintext after decryption
* @param cb Callback object
* [AUTO-TRANSLATED:897359bc]
*/
void setOnDecData(const std::function<void(const Buffer::Ptr &)> &cb);
/**
* 设置加密后获取密文的回调
* @param cb 回调对象
* Sets the callback to get the ciphertext after encryption
* @param cb Callback object
* [AUTO-TRANSLATED:bb31b34b]
*/
void setOnEncData(const std::function<void(const Buffer::Ptr &)> &cb);
/**
* 终结ssl
* Terminates SSL
* [AUTO-TRANSLATED:2ab06469]
*/
void shutdown();
/**
* 清空数据
* Clears data
* [AUTO-TRANSLATED:62d4f400]
*/
void flush();
/**
* 设置虚拟主机名
* @param host 虚拟主机名
* @return 是否成功
* Sets the virtual host name
* @param host Virtual host name
* @return Whether the operation was successful
* [AUTO-TRANSLATED:eebc1e2f]
*/
bool setHost(const char *host);
private:
void flushWriteBio();
void flushReadBio();
private:
bool _server_mode;
bool _send_handshake;
bool _is_flush = false;
int _buff_size;
BIO *_read_bio;
BIO *_write_bio;
std::shared_ptr<SSL> _ssl;
List <Buffer::Ptr> _buffer_send;
ResourcePool <BufferRaw> _buffer_pool;
std::function<void(const Buffer::Ptr &)> _on_dec;
std::function<void(const Buffer::Ptr &)> _on_enc;
};
} /* namespace toolkit */
#endif /* CRYPTO_SSLBOX_H_ */