Feat: One-way TLS transport for the device port
Add optional one-way TLS on the device port (6543), enabled per client via a pinned trust anchor, so new clients encrypt their transport while legacy plaintext clients keep working unchanged. Server (server/go): sniff each accepted connection and wrap TLS peers (ClientHello 0x16 0x03 + handshake type 0x01) in crypto/tls with MinVersion TLS 1.2; everything else stays on the plaintext path. TLS is enabled only when both YAMA_TLS_CERT and YAMA_TLS_KEY are set, and a cert/key load failure fails startup loudly rather than silently serving plaintext. Client (client/, Windows): Schannel one-way TLS. When the trust anchor is present — registry value Software\<exehash>\settings\tls_cert (REG_SZ holding the PEM), with fallback to settings.ini [settings] tls_cert or yama-ca.pem beside the exe — every outbound connection (main + sub-connections) completes a TLS 1.2 handshake before the app protocol and is strictly pinned to that anchor via a chain engine with hExclusiveRoot; any handshake/cert failure is fail-closed (no plaintext downgrade). Send uses EncryptMessage; Recv uses DecryptMessage and reads plaintext from the stream-mode DATA segment (bufs[1]) rather than the record header. Co-Authored-By: deepseek-v4-pro
This commit is contained in:
1 parent
8d4c118ae6
commit
ca0d7626d2
16 files changed
+1418
-5
No files matched your search
+34
-1
@@ -227,7 +227,11 @@ IOCPClient::IOCPClient(const State&bExit, bool exit_while_disconnect, int mask,
|
||||
m_DataProcess = NULL;
|
||||
m_ReconnectFunc = NULL;
|
||||
m_masker = mask ? new HttpMask(DEFAULT_HOST) : new PkgMask();
|
||||
#ifdef _DEBUG
|
||||
auto enc = GetHeaderEncoder(HeaderEncType(time(nullptr) % (HeaderEncV6 + 1)));
|
||||
#else
|
||||
auto enc = GetHeaderEncoder(HeaderEncType(time(nullptr) % HeaderEncNum));
|
||||
#endif
|
||||
m_EncoderType = encoder;
|
||||
m_Encoder = encoder ? new HellEncoder(enc, new XOREncoder16()) : new ProtocolEncoder();
|
||||
#ifdef _WIN32
|
||||
@@ -463,6 +467,25 @@ BOOL IOCPClient::ConnectServer(const char* szServerIP, unsigned short uPort)
|
||||
SetKeepAliveOptions(m_sClientSocket);
|
||||
#endif
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// 单向 TLS:证书存在(TlsEnabled())时,在应用协议首包前完成握手;握手失败即断开,
|
||||
// 不回退明文(fail-closed,防降级)。证书存在但加载失败(TlsLoadError())同样拒绝
|
||||
// 连接。握手须在 m_bConnected 置位前,确保工作线程不会在握手尚未完成时就开始 recv。
|
||||
if (TlsLoadError()) {
|
||||
Mprintf("[TLS] 证书加载失败,拒绝连接(fail-closed)\n");
|
||||
closesocket(m_sClientSocket);
|
||||
m_sClientSocket = INVALID_SOCKET;
|
||||
return FALSE;
|
||||
}
|
||||
if (TlsEnabled()) {
|
||||
if (!m_tls.Handshake(m_sClientSocket)) {
|
||||
Mprintf("[TLS] 握手失败,断开连接(fail-closed)\n");
|
||||
closesocket(m_sClientSocket);
|
||||
m_sClientSocket = INVALID_SOCKET;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
m_bConnected = TRUE;
|
||||
Mprintf("连接服务端成功: %s:%d.\n", m_sCurIP.c_str(), (int)port);
|
||||
|
||||
@@ -526,6 +549,16 @@ DWORD WINAPI IOCPClient::WorkThreadProc(LPVOID lParam)
|
||||
Sleep(50);
|
||||
continue;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// TLS 会话里可能有已解密、尚未交付的明文(select 只看底层 socket,看不到
|
||||
// Schannel 内部缓冲),优先消费,避免被 select 卡住。
|
||||
if (This->HasPendingData()) {
|
||||
if (!This->ProcessRecvData(&m_CompressedBuffer, szBuffer, MAX_RECV_BUFFER - 1, 0)) {
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
FD_ZERO(&fd);
|
||||
FD_SET(This->m_sClientSocket, &fd);
|
||||
// Linux select() 会修改 timeval,必须每次重置
|
||||
@@ -632,7 +665,7 @@ VOID IOCPClient::OnServerReceiving(CBuffer* m_CompressedBuffer, char* szBuffer,
|
||||
for (int i = 0; i < 16 && i < (int)bufLen; ++i) {
|
||||
char tmp[12]; sprintf(tmp, "%02X ", (unsigned char)src[i]); buf += tmp;
|
||||
}
|
||||
Mprintf("[ERROR] Unknown header! bufLen=%lu, first 16 bytes: %s\n", bufLen, buf.c_str());
|
||||
Mprintf("[ERROR] Unknown header! this=%p bufLen=%lu, first 16 bytes: %s\n", this, bufLen, buf.c_str());
|
||||
m_CompressedBuffer->ClearBuffer();
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user