备份-基础ssl通信

This commit is contained in:
睿 安
2026-01-23 08:39:07 +08:00
parent ef6b8511b1
commit dbb053a691
625 changed files with 305003 additions and 0 deletions

View File

@@ -0,0 +1,461 @@
// 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;
}