258 lines
6.4 KiB
C++
258 lines
6.4 KiB
C++
|
|
#include "pch.h"
|
|||
|
|
#include "SSLClientConnection.h"
|
|||
|
|
|
|||
|
|
namespace SSLClient {
|
|||
|
|
|
|||
|
|
SSLClientConnection::SSLClientConnection()
|
|||
|
|
: m_sslContext(nullptr)
|
|||
|
|
, m_ssl(nullptr)
|
|||
|
|
, m_socket(INVALID_SOCKET)
|
|||
|
|
, m_isConnected(false)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SSLClientConnection::~SSLClientConnection()
|
|||
|
|
{
|
|||
|
|
Cleanup();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool SSLClientConnection::InitializeWinsock()
|
|||
|
|
{
|
|||
|
|
WSADATA wsaData;
|
|||
|
|
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
|||
|
|
if (result != 0) {
|
|||
|
|
std::cerr << "[错误] WSAStartup失败,错误码: " << result << std::endl;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool SSLClientConnection::Initialize(const char* clientCert, const char* clientKey,
|
|||
|
|
const char* caCert, const char* keyPassword)
|
|||
|
|
{
|
|||
|
|
// 初始化Winsock
|
|||
|
|
if (!InitializeWinsock()) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::cout << "[客户端] 正在初始化SSL环境..." << std::endl;
|
|||
|
|
|
|||
|
|
// 创建SSL上下文
|
|||
|
|
m_sslContext = SSL_CTX_new(TLS_client_method());
|
|||
|
|
if (!m_sslContext) {
|
|||
|
|
CertificateManager::PrintSSLError("创建SSL上下文失败");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置验证模式:验证服务器证书
|
|||
|
|
SSL_CTX_set_verify(m_sslContext, SSL_VERIFY_PEER, nullptr);
|
|||
|
|
|
|||
|
|
// 加载CA证书
|
|||
|
|
X509* ca = m_certManager.LoadCertificateFromMemory(caCert);
|
|||
|
|
if (!ca) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
X509_STORE* store = SSL_CTX_get_cert_store(m_sslContext);
|
|||
|
|
if (X509_STORE_add_cert(store, ca) != 1) {
|
|||
|
|
CertificateManager::PrintSSLError("添加CA证书失败");
|
|||
|
|
X509_free(ca);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
X509_free(ca);
|
|||
|
|
|
|||
|
|
// 加载客户端证书
|
|||
|
|
X509* cert = m_certManager.LoadCertificateFromMemory(clientCert);
|
|||
|
|
if (!cert) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (SSL_CTX_use_certificate(m_sslContext, cert) != 1) {
|
|||
|
|
CertificateManager::PrintSSLError("使用客户端证书失败");
|
|||
|
|
X509_free(cert);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
X509_free(cert);
|
|||
|
|
|
|||
|
|
// 加载客户端私钥
|
|||
|
|
EVP_PKEY* pkey = m_certManager.LoadPrivateKeyFromMemory(clientKey, keyPassword);
|
|||
|
|
if (!pkey) {
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (SSL_CTX_use_PrivateKey(m_sslContext, pkey) != 1) {
|
|||
|
|
CertificateManager::PrintSSLError("使用客户端私钥失败");
|
|||
|
|
EVP_PKEY_free(pkey);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
EVP_PKEY_free(pkey);
|
|||
|
|
|
|||
|
|
// 验证私钥和证书是否匹配
|
|||
|
|
if (SSL_CTX_check_private_key(m_sslContext) != 1) {
|
|||
|
|
std::cerr << "[错误] 客户端私钥和证书不匹配" << std::endl;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::cout << "[客户端] SSL环境初始化成功" << std::endl;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool SSLClientConnection::Connect(const char* address, int port)
|
|||
|
|
{
|
|||
|
|
// 创建socket
|
|||
|
|
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
|||
|
|
if (m_socket == INVALID_SOCKET) {
|
|||
|
|
std::cerr << "[错误] 创建socket失败,错误码: " << WSAGetLastError() << std::endl;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置服务器地址
|
|||
|
|
sockaddr_in serverAddr;
|
|||
|
|
serverAddr.sin_family = AF_INET;
|
|||
|
|
serverAddr.sin_port = htons(static_cast<u_short>(port));
|
|||
|
|
inet_pton(AF_INET, address, &serverAddr.sin_addr);
|
|||
|
|
|
|||
|
|
// 连接到服务器
|
|||
|
|
std::cout << "[客户端] 正在连接服务器 " << address << ":" << port << " ..." << std::endl;
|
|||
|
|
if (connect(m_socket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
|
|||
|
|
std::cerr << "[错误] 连接失败,错误码: " << WSAGetLastError() << std::endl;
|
|||
|
|
closesocket(m_socket);
|
|||
|
|
m_socket = INVALID_SOCKET;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::cout << "[客户端] TCP连接成功" << std::endl;
|
|||
|
|
|
|||
|
|
// 创建SSL对象
|
|||
|
|
m_ssl = SSL_new(m_sslContext);
|
|||
|
|
if (!m_ssl) {
|
|||
|
|
CertificateManager::PrintSSLError("创建SSL对象失败");
|
|||
|
|
closesocket(m_socket);
|
|||
|
|
m_socket = INVALID_SOCKET;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 将SSL绑定到socket
|
|||
|
|
if (SSL_set_fd(m_ssl, static_cast<int>(m_socket)) != 1) {
|
|||
|
|
CertificateManager::PrintSSLError("绑定SSL到socket失败");
|
|||
|
|
SSL_free(m_ssl);
|
|||
|
|
m_ssl = nullptr;
|
|||
|
|
closesocket(m_socket);
|
|||
|
|
m_socket = INVALID_SOCKET;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 执行SSL握手
|
|||
|
|
std::cout << "[客户端] 正在进行SSL握手..." << std::endl;
|
|||
|
|
int ret = SSL_connect(m_ssl);
|
|||
|
|
if (ret != 1) {
|
|||
|
|
int err = SSL_get_error(m_ssl, ret);
|
|||
|
|
std::cerr << "[错误] SSL握手失败,错误码: " << err << std::endl;
|
|||
|
|
CertificateManager::PrintSSLError("SSL_connect");
|
|||
|
|
SSL_free(m_ssl);
|
|||
|
|
m_ssl = nullptr;
|
|||
|
|
closesocket(m_socket);
|
|||
|
|
m_socket = INVALID_SOCKET;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
m_isConnected = true;
|
|||
|
|
std::cout << "[客户端] SSL握手完成!" << std::endl;
|
|||
|
|
std::cout << "[客户端] 使用的加密套件: " << GetCipherSuite() << std::endl;
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool SSLClientConnection::Send(const std::string& data)
|
|||
|
|
{
|
|||
|
|
if (!m_isConnected || !m_ssl) {
|
|||
|
|
std::cerr << "[错误] 未连接到服务器" << std::endl;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int sent = SSL_write(m_ssl, data.c_str(), static_cast<int>(data.length()));
|
|||
|
|
if (sent <= 0) {
|
|||
|
|
int err = SSL_get_error(m_ssl, sent);
|
|||
|
|
std::cerr << "[错误] 发送失败,错误码: " << err << std::endl;
|
|||
|
|
CertificateManager::PrintSSLError("SSL_write");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
std::cout << "[客户端] 发送数据: \"" << data << "\" (" << sent << " 字节)" << std::endl;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int SSLClientConnection::Receive(char* buffer, int bufferSize)
|
|||
|
|
{
|
|||
|
|
if (!m_isConnected || !m_ssl || !buffer || bufferSize <= 0) {
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 设置socket为非阻塞模式
|
|||
|
|
u_long mode = 1;
|
|||
|
|
ioctlsocket(m_socket, FIONBIO, &mode);
|
|||
|
|
|
|||
|
|
int received = SSL_read(m_ssl, buffer, bufferSize - 1);
|
|||
|
|
|
|||
|
|
// 恢复为阻塞模式
|
|||
|
|
mode = 0;
|
|||
|
|
ioctlsocket(m_socket, FIONBIO, &mode);
|
|||
|
|
|
|||
|
|
if (received > 0) {
|
|||
|
|
buffer[received] = '\0';
|
|||
|
|
std::cout << "[客户端] 收到数据: \"" << buffer << "\" (" << received << " 字节)" << std::endl;
|
|||
|
|
return received;
|
|||
|
|
}
|
|||
|
|
else if (received < 0) {
|
|||
|
|
int err = SSL_get_error(m_ssl, received);
|
|||
|
|
// SSL_ERROR_WANT_READ 和 SSL_ERROR_WANT_WRITE 表示没有数据,不是错误
|
|||
|
|
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
|
|||
|
|
if (err != SSL_ERROR_ZERO_RETURN) { // 忽略正常关闭
|
|||
|
|
std::cerr << "[错误] 接收失败,错误码: " << err << std::endl;
|
|||
|
|
}
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return 0; // 没有数据
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SSLClientConnection::Disconnect()
|
|||
|
|
{
|
|||
|
|
std::cout << "[客户端] 正在断开连接..." << std::endl;
|
|||
|
|
Cleanup();
|
|||
|
|
m_isConnected = false;
|
|||
|
|
std::cout << "[客户端] 已断开连接" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const char* SSLClientConnection::GetCipherSuite() const
|
|||
|
|
{
|
|||
|
|
if (m_ssl) {
|
|||
|
|
return SSL_get_cipher(m_ssl);
|
|||
|
|
}
|
|||
|
|
return "未知";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SSLClientConnection::Cleanup()
|
|||
|
|
{
|
|||
|
|
if (m_ssl) {
|
|||
|
|
SSL_shutdown(m_ssl);
|
|||
|
|
SSL_free(m_ssl);
|
|||
|
|
m_ssl = nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (m_socket != INVALID_SOCKET) {
|
|||
|
|
closesocket(m_socket);
|
|||
|
|
m_socket = INVALID_SOCKET;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (m_sslContext) {
|
|||
|
|
SSL_CTX_free(m_sslContext);
|
|||
|
|
m_sslContext = nullptr;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
WSACleanup();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
} // namespace SSLClient
|