Files
--hp-socket-TCP--ssl--/Client-Native/main.cpp.backup
2026-01-23 08:39:07 +08:00

462 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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"
"MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIK2UJW9QXIj4CAggA\n"
"MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBCDDZQLhAdT91jd6v/5H0+GBIIE\n"
"0PH6tKl+nPi8sU0ryjxDIrHwrT/ZFah+3TAHGE/YFAOZnzRyCFHQTvUZX4p8eSmw\n"
"WOpt5NBUPJ3mT0Ctt7lGBRy4AXSyBrFSamlTruM3P1e3ijluYjMbweZFfCWPq8c/\n"
"jPjbcUkXe6mD96aPSTt/jIunexS8AKovu8c/bFLyTLDk38lATc+GnXQQJ0KiXCRu\n"
"vpjVSKcv2Br6cWqaNTZ71FvH1RmSD6K6givc0w65pKruHYTMApIRR8YC5Y0vx0gD\n"
"6nS12LV/EJEtxTfZFlrzZTRWZISPIzYGuTfS+3bPePlxpbwzhN6vmvgjKhdk+3lN\n"
"3W3ZfqODNhoOKG+mG5Fdj7vR2PU1UND6UUd3+FrzWkXikmalAAwKzRLnyTR1T2rl\n"
"RhM0Qe/HZianeEQTHpCw27gOz1OMw2EKfIEHM6W2BKGOTY5ls5dqgMfP1ZoQUrOr\n"
"59tJo4GpWYFGCuHhTEa5OS/gsgnzymGrkuEwPsdSQaBdzV7lFGTv2/ryKX+vNm9V\n"
"CmKw0nHzOVP19+WL4vPDtbRnLUk8KV9Mg7PdSbGbNcMmTEBk8ju8OvjIUIWZbRTa\n"
"n5C6fhD1DYZcczmlCILYgXyJISu7EDf3z9cKRAf5VbRAedDMB/xHWmrmlxUJ37Kt\n"
"tVgaCD0U6Q3q+3y6OOwugc8UbSo4yA/DbLlG0/U7afwQaNxTLa4HGBQljpoNStIt\n"
"Vgfy2olqHXaf2doSQtsYEl9MHa6neuGfZQMtonDkejnx4KKU+cMhe+KijEUwieYx\n"
"7aoPB71b82XODquDPAL5zOegj0eYgKn5iXyOx5W44S34zfclxtxxgfsDJ3qJ9qoL\n"
"sSenrQ3xAYHJSZRcqEgO31XhoEnkyt1V7G0Bk4/GUMD6uQudr3nsw/ulJpAlNK15\n"
"ZxTSKWrtwOWdwcTj6B14K6wcqMFVNF1Ydbv/qp0b5q5S/orYHzRIPcFmdOAIsjyO\n"
"6na7+D31BH/4pf+TASBNqRNRw5CBqNcGcfiXk11AywxUnmD5ZvC/C0pTpTD/9qC4\n"
"LucWJ0sNAtPq8suFjKqQ+wMvq3rUh050NRm2cm2nUJLxafTnr0v3+kKYbVW8pSWB\n"
"NMelZMVGF1MDYBujg8Mw/xuMhPeLozCZeKmo7eu7aDMXzQMZLfAEJAzU9Du8H4nq\n"
"GgQVUgEkS5rdbjZGkHP0FuM8m8lueKEPDYwHCJv9Be5Z/uxp9OO/Lmdlha0J7gJu\n"
"pihNkAYVxRst96b5okXKooYi/TZxAdThoPYH28VwinGR1I3/8I3M5DbUPIgHhDeB\n"
"ga3u7jt7ZNDUgavukUD0S7WioRb5ooXrXGZ1xmzKLCmMdCDC5S32fQS0wRGfVoMl\n"
"hWbaT+0uak+fOpqVRxSNyE3Ek788ua5iPHaTSXJSoe5lv7OQKDSZ/+wFeLmDPf4M\n"
"BHL2gBLD6RNkz5cWgy14sQcJKNAnyptU4EGPyURZcB8APtB/ITAS2Az/JSxvSBgq\n"
"g/L1FujnP2QEpWpVKkTNxsF867bUPN34KrlPKYjNqcKA2pD4fkFoKSeeNtOEWa++\n"
"d6q9y+mDD97SnIFAAhDFlukzXtyl4MU6uiqRldFiuEt3KzvV19n8M+NyyYIFhfdg\n"
"6TkYEbMJPQ/Y3EGNmyMqbFdJzrdl/B8pr7JQnikTfUZZ\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;
}