462 lines
14 KiB
Plaintext
462 lines
14 KiB
Plaintext
// TestEcho-SSL-Console Client-Native
|
||
// 纯OpenSSL+Winsock实现的SSL客户端(不使用HP-Socket)
|
||
|
||
#include "pch.h"
|
||
|
||
// SSL证书配置(与Client项目相同)
|
||
static const char* g_c_lpszPemCert =
|
||
"-----BEGIN CERTIFICATE-----\n"
|
||
"MIIDszCCApugAwIBAgIBATANBgkqhkiG9w0BAQsFADB7MQswCQYDVQQGEwJDTjEL\n"
|
||
"MAkGA1UECAwCR0QxCzAJBgNVBAcMAkdaMQwwCgYDVQQKDANTU1QxDzANBgNVBAsM\n"
|
||
"Bkplc3NtYTETMBEGA1UEAwwKamVzc21hLm9yZzEeMBwGCSqGSIb3DQEJARYPbGRj\n"
|
||
"c2FhQDIxY24uY29tMCAXDTI0MDYyNjA1MjUwOFoYDzIyNDMwNzA5MDUyNTA4WjBu\n"
|
||
"MQswCQYDVQQGEwJDTjELMAkGA1UECAwCR0QxDDAKBgNVBAoMA1NTVDEPMA0GA1UE\n"
|
||
"CwwGSmVzc21hMRMwEQYDVQQDDApqZXNzbWEub3JnMR4wHAYJKoZIhvcNAQkBFg9s\n"
|
||
"ZGNzYWFAMjFjbi5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCD\n"
|
||
"+MyrJEKCheRoOpMRjR78S8hr9W7XN0/EZWyVKwXRT7EE0aGiQdH/W2a+qpWRMa6E\n"
|
||
"Qi47zdBnt0P8ZoFiItQhuhwUJ064afpVoaHHX25UdbF8r+sRTofadughETBBj2Cf\n"
|
||
"qh0ia6EOB0QvpJpywWmGZPoMtypjbUiTb/YGOJh2qsVr67MN/E48vt7qt0VxF9SE\n"
|
||
"pucvqhraTBljWCeRVCae2c0yBSpq/n+7NhamK7+g3xxCKWRz4pN3wrIoEsXTboTh\n"
|
||
"z940caDgthCc23VJ080DN44jZg6c87huKIuxbebJqw2HCM4DwrW+OSzTLszpFAXZ\n"
|
||
"yarllOzWnBut20zmYnl1AgMBAAGjTTBLMAkGA1UdEwQCMAAwHQYDVR0OBBYEFJ5E\n"
|
||
"RJmJ4pUzEbcU9Yge6nr0oi51MB8GA1UdIwQYMBaAFN49z48DywmoD4cNTQgC6nn2\n"
|
||
"QJoUMA0GCSqGSIb3DQEBCwUAA4IBAQBpoSFfDDDKMAy95tSROpYu5WSWQXe6B7kl\n"
|
||
"PGJAF6mWe/4b7jHQqDUVkEmFmbMWUAtpTC3P01TrV77dhIosAnC/B76fb7Pto8W4\n"
|
||
"cjGpWAT0sSegZuhnLtguTGlnR0vVSh/yRRDEtjN8loWpu3BLWVHYOKnn62QGfY0B\n"
|
||
"sRGrfZsKvwB+1w+HOvGopnWv6UYwrzEKthjPMR65rOsoManOv24ua8baJmq0gqF9\n"
|
||
"752kD8n703uWUBx79/QlNIPMZC1iUIi1mEjyrTgSag6+3sWAIKihaoF/Nf9d01nw\n"
|
||
"iL16EIT5dJ0QJWDCeIxhuTZckw+gL1pBeQU7pqzKHPnvo+8GBnTG\n"
|
||
"-----END CERTIFICATE-----\n";
|
||
|
||
static const char* g_c_lpszPemKey =
|
||
"-----BEGIN ENCRYPTED PRIVATE KEY-----\n"
|
||
"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\n"
|
||
"-----END ENCRYPTED PRIVATE KEY-----\n";
|
||
|
||
static const char* g_c_lpszCAPemCert =
|
||
"-----BEGIN CERTIFICATE-----\n"
|
||
"MIID2TCCAsGgAwIBAgIUM8TTtPU+ejzffYXCcs/zZsU7OuIwDQYJKoZIhvcNAQEL\n"
|
||
"BQAwezELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQswCQYDVQQHDAJHWjEMMAoG\n"
|
||
"A1UECgwDU1NUMQ8wDQYDVQQLDAZKZXNzbWExEzARBgNVBAMMCmplc3NtYS5vcmcx\n"
|
||
"HjAcBgkqhkiG9w0BCQEWD2xkY3NhYUAyMWNuLmNvbTAgFw0yNDA2MjYwNTA0NDNa\n"
|
||
"GA8yMjcwMTEyNDA1MDQ0M1owezELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAkdEMQsw\n"
|
||
"CQYDVQQHDAJHWjEMMAoGA1UECgwDU1NUMQ8wDQYDVQQLDAZKZXNzbWExEzARBgNV\n"
|
||
"BAMMCmplc3NtYS5vcmcxHjAcBgkqhkiG9w0BCQEWD2xkY3NhYUAyMWNuLmNvbTCC\n"
|
||
"ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAML+v79+aLQt0Za0dTIZHI5B\n"
|
||
"NDs0g5G8bhdOTlW/kNWflaziZ3GY6d6nJSkQ5e29kyFKxlOD6Gls6bOJ86U71u4R\n"
|
||
"bCmoFvRTDH4q2cJ/+PbiioLpNveDG6lnRCs9JNRQoJrkpRo6urnVnAdsIf6UFjLI\n"
|
||
"dlByNMPGYJ0V8/oKJG5Vu5gcbZV0jVA5+tswkH/zquexEXoKvp18mcwl+pNc/LwW\n"
|
||
"0WnGj0uoJjxHg4GsS78PASjhxMR/2d/1OpgPauldFaNHjVPtaLqJnuejwA6M6Sz8\n"
|
||
"iFPybAQAMpHL9W8kf08jtbnFvnm4ibUkQL5h+OJoIEQa9AVZOSoFG2/g5Zcn8X8C\n"
|
||
"AwEAAaNTMFEwHQYDVR0OBBYEFN49z48DywmoD4cNTQgC6nn2QJoUMB8GA1UdIwQY\n"
|
||
"MBaAFN49z48DywmoD4cNTQgC6nn2QJoUMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI\n"
|
||
"hvcNAQELBQADggEBALJnYrYBSZLyYX14FQ04zxG3AX0CtQzNOOa7LDrr+H8Ly+nK\n"
|
||
"qS87gg2njMVZH1zM2demtMwydR/F2Ui8ggaduMvc9h5YgQKEwYl8KarJEY03oZoe\n"
|
||
"zbQGBxCXpDOtMs1vujzcl/iZbSzwEDF3g4la5U8q4MlmfGFKz9CJbvoxecqYA206\n"
|
||
"nNbW2XZsW/xMiQv6iAw5iP/LOR9HAyxcvXIsL790nfcgnTYLmyP254Dj4outc6R+\n"
|
||
"PA+f/c1FvkbUBTR5vJt2tsvHcNU218rY2hyOIhDmZeUWprqBO19sUk3scLbVPr3+\n"
|
||
"WEWEl2XaCekKuPtAnMgVQuFsocXGyiuIhkOe5Z4=\n"
|
||
"-----END CERTIFICATE-----\n";
|
||
|
||
static const char* g_c_lpszKeyPassword = "123456";
|
||
static const char* DEFAULT_ADDRESS = "127.0.0.1";
|
||
static const int DEFAULT_PORT = 5555;
|
||
|
||
// 全局变量
|
||
SSL_CTX* g_ssl_ctx = nullptr;
|
||
SSL* g_ssl = nullptr;
|
||
SOCKET g_socket = INVALID_SOCKET;
|
||
|
||
// 打印OpenSSL错误
|
||
void PrintSSLError(const char* msg)
|
||
{
|
||
unsigned long err = ERR_get_error();
|
||
char errBuf[256];
|
||
ERR_error_string_n(err, errBuf, sizeof(errBuf));
|
||
std::cout << "[错误] " << msg << ": " << errBuf << std::endl;
|
||
}
|
||
|
||
// 从内存加载证书
|
||
X509* LoadCertFromMemory(const char* certPem)
|
||
{
|
||
BIO* bio = BIO_new_mem_buf(certPem, -1);
|
||
if (!bio) {
|
||
PrintSSLError("创建BIO失败");
|
||
return nullptr;
|
||
}
|
||
|
||
X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
|
||
BIO_free(bio);
|
||
|
||
if (!cert) {
|
||
PrintSSLError("读取证书失败");
|
||
}
|
||
|
||
return cert;
|
||
}
|
||
|
||
// 从内存加载私钥
|
||
EVP_PKEY* LoadKeyFromMemory(const char* keyPem, const char* password)
|
||
{
|
||
BIO* bio = BIO_new_mem_buf(keyPem, -1);
|
||
if (!bio) {
|
||
PrintSSLError("创建BIO失败");
|
||
return nullptr;
|
||
}
|
||
|
||
EVP_PKEY* pkey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, (void*)password);
|
||
BIO_free(bio);
|
||
|
||
if (!pkey) {
|
||
PrintSSLError("读取私钥失败");
|
||
}
|
||
|
||
return pkey;
|
||
}
|
||
|
||
// 初始化OpenSSL
|
||
bool InitializeSSL()
|
||
{
|
||
// OpenSSL 1.1.0+ 自动初始化,不需要手动调用初始化函数
|
||
|
||
// 创建SSL上下文(使用TLS客户端方法)
|
||
g_ssl_ctx = SSL_CTX_new(TLS_client_method());
|
||
if (!g_ssl_ctx) {
|
||
PrintSSLError("创建SSL上下文失败");
|
||
return false;
|
||
}
|
||
|
||
// 设置验证模式:验证服务器证书
|
||
SSL_CTX_set_verify(g_ssl_ctx, SSL_VERIFY_PEER, nullptr);
|
||
|
||
// 加载CA证书(用于验证服务器)
|
||
BIO* ca_bio = BIO_new_mem_buf(g_c_lpszCAPemCert, -1);
|
||
if (!ca_bio) {
|
||
PrintSSLError("创建CA BIO失败");
|
||
return false;
|
||
}
|
||
|
||
X509* ca_cert = PEM_read_bio_X509(ca_bio, nullptr, nullptr, nullptr);
|
||
BIO_free(ca_bio);
|
||
|
||
if (!ca_cert) {
|
||
PrintSSLError("读取CA证书失败");
|
||
return false;
|
||
}
|
||
|
||
// 将CA证书添加到信任列表
|
||
X509_STORE* store = SSL_CTX_get_cert_store(g_ssl_ctx);
|
||
if (X509_STORE_add_cert(store, ca_cert) != 1) {
|
||
PrintSSLError("添加CA证书失败");
|
||
X509_free(ca_cert);
|
||
return false;
|
||
}
|
||
X509_free(ca_cert);
|
||
|
||
// 加载客户端证书
|
||
X509* client_cert = LoadCertFromMemory(g_c_lpszPemCert);
|
||
if (!client_cert) {
|
||
return false;
|
||
}
|
||
|
||
if (SSL_CTX_use_certificate(g_ssl_ctx, client_cert) != 1) {
|
||
PrintSSLError("使用客户端证书失败");
|
||
X509_free(client_cert);
|
||
return false;
|
||
}
|
||
X509_free(client_cert);
|
||
|
||
// 加载客户端私钥
|
||
EVP_PKEY* client_key = LoadKeyFromMemory(g_c_lpszPemKey, g_c_lpszKeyPassword);
|
||
if (!client_key) {
|
||
return false;
|
||
}
|
||
|
||
if (SSL_CTX_use_PrivateKey(g_ssl_ctx, client_key) != 1) {
|
||
PrintSSLError("使用客户端私钥失败");
|
||
EVP_PKEY_free(client_key);
|
||
return false;
|
||
}
|
||
EVP_PKEY_free(client_key);
|
||
|
||
// 验证私钥和证书是否匹配
|
||
if (SSL_CTX_check_private_key(g_ssl_ctx) != 1) {
|
||
std::cout << "[错误] 客户端私钥和证书不匹配" << std::endl;
|
||
return false;
|
||
}
|
||
|
||
std::cout << "[客户端] SSL环境初始化成功" << std::endl;
|
||
return true;
|
||
}
|
||
|
||
// 初始化Winsock
|
||
bool InitializeWinsock()
|
||
{
|
||
WSADATA wsaData;
|
||
int result = WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||
if (result != 0) {
|
||
std::cout << "[错误] WSAStartup失败,错误码: " << result << std::endl;
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// 连接到服务器
|
||
bool ConnectToServer()
|
||
{
|
||
// 创建socket
|
||
g_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||
if (g_socket == INVALID_SOCKET) {
|
||
std::cout << "[错误] 创建socket失败,错误码: " << WSAGetLastError() << std::endl;
|
||
return false;
|
||
}
|
||
|
||
// 设置服务器地址
|
||
sockaddr_in serverAddr;
|
||
serverAddr.sin_family = AF_INET;
|
||
serverAddr.sin_port = htons(DEFAULT_PORT);
|
||
inet_pton(AF_INET, DEFAULT_ADDRESS, &serverAddr.sin_addr);
|
||
|
||
// 连接到服务器
|
||
std::cout << "[客户端] 正在连接服务器 " << DEFAULT_ADDRESS << ":" << DEFAULT_PORT << " ..." << std::endl;
|
||
if (connect(g_socket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
|
||
std::cout << "[错误] 连接失败,错误码: " << WSAGetLastError() << std::endl;
|
||
closesocket(g_socket);
|
||
g_socket = INVALID_SOCKET;
|
||
return false;
|
||
}
|
||
|
||
std::cout << "[客户端] TCP连接成功" << std::endl;
|
||
|
||
// 创建SSL对象
|
||
g_ssl = SSL_new(g_ssl_ctx);
|
||
if (!g_ssl) {
|
||
PrintSSLError("创建SSL对象失败");
|
||
closesocket(g_socket);
|
||
g_socket = INVALID_SOCKET;
|
||
return false;
|
||
}
|
||
|
||
// 将SSL绑定到socket
|
||
if (SSL_set_fd(g_ssl, (int)g_socket) != 1) {
|
||
PrintSSLError("绑定SSL到socket失败");
|
||
SSL_free(g_ssl);
|
||
g_ssl = nullptr;
|
||
closesocket(g_socket);
|
||
g_socket = INVALID_SOCKET;
|
||
return false;
|
||
}
|
||
|
||
// 执行SSL握手
|
||
std::cout << "[客户端] 正在进行SSL握手..." << std::endl;
|
||
int ret = SSL_connect(g_ssl);
|
||
if (ret != 1) {
|
||
int err = SSL_get_error(g_ssl, ret);
|
||
std::cout << "[错误] SSL握手失败,错误码: " << err << std::endl;
|
||
PrintSSLError("SSL_connect");
|
||
SSL_free(g_ssl);
|
||
g_ssl = nullptr;
|
||
closesocket(g_socket);
|
||
g_socket = INVALID_SOCKET;
|
||
return false;
|
||
}
|
||
|
||
std::cout << "[客户端] SSL握手完成!" << std::endl;
|
||
|
||
// 显示SSL信息
|
||
std::cout << "[客户端] 使用的加密套件: " << SSL_get_cipher(g_ssl) << std::endl;
|
||
|
||
return true;
|
||
}
|
||
|
||
// 发送数据
|
||
bool SendData(const std::string& data)
|
||
{
|
||
if (!g_ssl) {
|
||
std::cout << "[错误] SSL未初始化" << std::endl;
|
||
return false;
|
||
}
|
||
|
||
int sent = SSL_write(g_ssl, data.c_str(), (int)data.length());
|
||
if (sent <= 0) {
|
||
int err = SSL_get_error(g_ssl, sent);
|
||
std::cout << "[错误] 发送失败,错误码: " << err << std::endl;
|
||
PrintSSLError("SSL_write");
|
||
return false;
|
||
}
|
||
|
||
std::cout << "[客户端] 发送数据: \"" << data << "\" (" << sent << " 字节)" << std::endl;
|
||
return true;
|
||
}
|
||
|
||
// 接收数据(非阻塞检查)
|
||
void ReceiveData()
|
||
{
|
||
if (!g_ssl) {
|
||
return;
|
||
}
|
||
|
||
// 设置socket为非阻塞模式
|
||
u_long mode = 1;
|
||
ioctlsocket(g_socket, FIONBIO, &mode);
|
||
|
||
char buffer[1024];
|
||
int received = SSL_read(g_ssl, buffer, sizeof(buffer) - 1);
|
||
|
||
if (received > 0) {
|
||
buffer[received] = '\0';
|
||
std::cout << "[客户端] 收到数据: \"" << buffer << "\" (" << received << " 字节)" << std::endl;
|
||
}
|
||
else if (received < 0) {
|
||
int err = SSL_get_error(g_ssl, received);
|
||
if (err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) {
|
||
// 真正的错误(不是"没有数据")
|
||
if (err != SSL_ERROR_ZERO_RETURN) { // 忽略正常关闭
|
||
std::cout << "[错误] 接收失败,错误码: " << err << std::endl;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 恢复为阻塞模式
|
||
mode = 0;
|
||
ioctlsocket(g_socket, FIONBIO, &mode);
|
||
}
|
||
|
||
// 清理资源
|
||
void Cleanup()
|
||
{
|
||
if (g_ssl) {
|
||
SSL_shutdown(g_ssl);
|
||
SSL_free(g_ssl);
|
||
g_ssl = nullptr;
|
||
}
|
||
|
||
if (g_socket != INVALID_SOCKET) {
|
||
closesocket(g_socket);
|
||
g_socket = INVALID_SOCKET;
|
||
}
|
||
|
||
if (g_ssl_ctx) {
|
||
SSL_CTX_free(g_ssl_ctx);
|
||
g_ssl_ctx = nullptr;
|
||
}
|
||
|
||
WSACleanup();
|
||
}
|
||
|
||
// 打印菜单
|
||
void PrintMenu()
|
||
{
|
||
std::cout << "\n命令菜单:" << std::endl;
|
||
std::cout << " 1 - 发送 \"hello\"" << std::endl;
|
||
std::cout << " q - 退出程序" << std::endl;
|
||
std::cout << "请输入命令: " << std::flush;
|
||
}
|
||
|
||
int main()
|
||
{
|
||
// 设置控制台UTF-8编码
|
||
SetConsoleOutputCP(CP_UTF8);
|
||
std::locale::global(std::locale(""));
|
||
|
||
std::cout << "========================================" << std::endl;
|
||
std::cout << " SSL Client Native (纯OpenSSL+Winsock)" << std::endl;
|
||
std::cout << "========================================" << std::endl;
|
||
std::cout << std::endl;
|
||
|
||
// 初始化Winsock
|
||
if (!InitializeWinsock()) {
|
||
std::cout << "按任意键退出..." << std::endl;
|
||
_getch();
|
||
return 1;
|
||
}
|
||
|
||
// 初始化SSL
|
||
if (!InitializeSSL()) {
|
||
std::cout << "按任意键退出..." << std::endl;
|
||
_getch();
|
||
Cleanup();
|
||
return 1;
|
||
}
|
||
|
||
// 连接到服务器
|
||
if (!ConnectToServer()) {
|
||
std::cout << "按任意键退出..." << std::endl;
|
||
_getch();
|
||
Cleanup();
|
||
return 1;
|
||
}
|
||
|
||
std::cout << "[客户端] 已连接到服务器,可以开始发送消息" << std::endl;
|
||
|
||
// 主循环
|
||
PrintMenu();
|
||
|
||
bool running = true;
|
||
while (running) {
|
||
// 检查是否有数据可接收
|
||
ReceiveData();
|
||
|
||
// 检查键盘输入
|
||
if (_kbhit()) {
|
||
char ch = _getch();
|
||
std::cout << ch << std::endl;
|
||
|
||
if (ch == '1') {
|
||
// 发送 "hello"
|
||
if (SendData("hello")) {
|
||
Sleep(100); // 等待一下让服务器响应
|
||
ReceiveData(); // 接收响应
|
||
}
|
||
PrintMenu();
|
||
}
|
||
else if (ch == 'q' || ch == 'Q') {
|
||
running = false;
|
||
}
|
||
else {
|
||
std::cout << "无效命令,请重新输入。" << std::endl;
|
||
PrintMenu();
|
||
}
|
||
}
|
||
|
||
Sleep(100);
|
||
}
|
||
|
||
// 清理资源
|
||
std::cout << "[客户端] 正在断开连接..." << std::endl;
|
||
Cleanup();
|
||
std::cout << "[客户端] 已断开连接" << std::endl;
|
||
|
||
std::cout << "按任意键退出..." << std::endl;
|
||
_getch();
|
||
|
||
return 0;
|
||
}
|