mirror of
https://github.com/SoftEtherVPN/SoftEtherVPN.git
synced 2025-07-07 08:14:58 +03:00
Implement complete server certificate verification
This commit is contained in:
@ -4295,7 +4295,6 @@ bool ClientCheckServerCert(CONNECTION *c, bool *expired)
|
||||
X *x;
|
||||
CHECK_CERT_THREAD_PROC *p;
|
||||
THREAD *thread;
|
||||
CEDAR *cedar;
|
||||
bool ret;
|
||||
UINT64 start;
|
||||
// Validate arguments
|
||||
@ -4310,31 +4309,10 @@ bool ClientCheckServerCert(CONNECTION *c, bool *expired)
|
||||
}
|
||||
|
||||
auth = c->Session->ClientAuth;
|
||||
cedar = c->Cedar;
|
||||
|
||||
if (auth->CheckCertProc == NULL && c->Session->LinkModeClient == false)
|
||||
if (auth->CheckCertProc == NULL)
|
||||
{
|
||||
// No checking function
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c->Session->LinkModeClient && c->Session->Link->CheckServerCert == false)
|
||||
{
|
||||
// It's in cascade connection mode, but do not check the server certificate
|
||||
return true;
|
||||
}
|
||||
|
||||
if (c->UseTicket)
|
||||
{
|
||||
// Check the certificate of the redirected VPN server
|
||||
if (CompareX(c->FirstSock->RemoteX, c->ServerX) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
x = CloneX(c->FirstSock->RemoteX);
|
||||
@ -4344,63 +4322,6 @@ bool ClientCheckServerCert(CONNECTION *c, bool *expired)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (CheckXDateNow(x))
|
||||
{
|
||||
// Check whether it is signed by the root certificate to trust
|
||||
if (c->Session->LinkModeClient == false)
|
||||
{
|
||||
// Normal VPN Client mode
|
||||
if (CheckSignatureByCa(cedar, x))
|
||||
{
|
||||
// This certificate can be trusted because it is signed
|
||||
FreeX(x);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Cascade connection mode
|
||||
if (CheckSignatureByCaLinkMode(c->Session, x))
|
||||
{
|
||||
// This certificate can be trusted because it is signed
|
||||
FreeX(x);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (c->Session->LinkModeClient)
|
||||
{
|
||||
if (CheckXDateNow(x))
|
||||
{
|
||||
Lock(c->Session->Link->lock);
|
||||
{
|
||||
if (c->Session->Link->ServerCert != NULL)
|
||||
{
|
||||
if (CompareX(c->Session->Link->ServerCert, x))
|
||||
{
|
||||
Unlock(c->Session->Link->lock);
|
||||
// Exactly match the certificate that is registered in the cascade configuration
|
||||
FreeX(x);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Unlock(c->Session->Link->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expired != NULL)
|
||||
{
|
||||
*expired = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Verification failure at this point in the case of cascade connection mode
|
||||
FreeX(x);
|
||||
return false;
|
||||
}
|
||||
|
||||
p = ZeroMalloc(sizeof(CHECK_CERT_THREAD_PROC));
|
||||
p->ServerX = x;
|
||||
p->CheckCertProc = auth->CheckCertProc;
|
||||
@ -4418,7 +4339,8 @@ bool ClientCheckServerCert(CONNECTION *c, bool *expired)
|
||||
{
|
||||
// Send a NOOP periodically for disconnection prevention
|
||||
start = Tick64();
|
||||
ClientUploadNoop(c);
|
||||
// Do not send because we now ask for user permission before sending signature
|
||||
//ClientUploadNoop(c);
|
||||
}
|
||||
if (p->UserSelected)
|
||||
{
|
||||
@ -4477,10 +4399,43 @@ REDIRECTED:
|
||||
s = ClientConnectToServer(c);
|
||||
if (s == NULL)
|
||||
{
|
||||
// Do not retry if untrusted or hostname mismatched
|
||||
if (c->Session->LinkModeClient == false && (c->Err == ERR_CERT_NOT_TRUSTED || c->Err == ERR_HOSTNAME_MISMATCH)
|
||||
&& (c->Session->Account == NULL || ! c->Session->Account->RetryOnServerCert))
|
||||
{
|
||||
c->Session->ForceStopFlag = true;
|
||||
}
|
||||
PrintStatus(sess, L"free");
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintStatus(sess, _UU("STATUS_5"));
|
||||
|
||||
// Prompt user whether to continue on verification errors
|
||||
if ((c->Err == ERR_CERT_NOT_TRUSTED || c->Err == ERR_HOSTNAME_MISMATCH || c->Err == ERR_SERVER_CERT_EXPIRES) && ClientCheckServerCert(c, &expired) == false)
|
||||
{
|
||||
if (expired)
|
||||
{
|
||||
c->Err = ERR_SERVER_CERT_EXPIRES;
|
||||
}
|
||||
|
||||
// Do not retry if untrusted or hostname mismatched
|
||||
if (c->Session->LinkModeClient == false && (c->Err == ERR_CERT_NOT_TRUSTED || c->Err == ERR_HOSTNAME_MISMATCH)
|
||||
&& (c->Session->Account == NULL || ! c->Session->Account->RetryOnServerCert))
|
||||
{
|
||||
c->Session->ForceStopFlag = true;
|
||||
}
|
||||
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
// Check the certificate of the redirected VPN server
|
||||
if (c->UseTicket && CompareX(s->RemoteX, c->ServerX) == false)
|
||||
{
|
||||
c->Err = ERR_CERT_NOT_TRUSTED;
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
Copy(&server_ip, &s->RemoteIP, sizeof(IP));
|
||||
|
||||
if (c->Halt)
|
||||
@ -4532,8 +4487,6 @@ REDIRECTED:
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
PrintStatus(sess, _UU("STATUS_5"));
|
||||
|
||||
// Receive a Hello packet
|
||||
Debug("Downloading Hello...\n");
|
||||
if (ClientDownloadHello(c, s) == false)
|
||||
@ -4569,27 +4522,6 @@ REDIRECTED:
|
||||
// During user authentication
|
||||
c->Session->ClientStatus = CLIENT_STATUS_AUTH;
|
||||
|
||||
// Verify the server certificate by the client
|
||||
if (ClientCheckServerCert(c, &expired) == false)
|
||||
{
|
||||
if (expired == false)
|
||||
{
|
||||
c->Err = ERR_CERT_NOT_TRUSTED;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Err = ERR_SERVER_CERT_EXPIRES;
|
||||
}
|
||||
|
||||
if (c->Session->LinkModeClient == false && c->Err == ERR_CERT_NOT_TRUSTED
|
||||
&& (c->Session->Account == NULL || ! c->Session->Account->RetryOnServerCert))
|
||||
{
|
||||
c->Session->ForceStopFlag = true;
|
||||
}
|
||||
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
PrintStatus(sess, _UU("STATUS_6"));
|
||||
|
||||
// Send the authentication data
|
||||
@ -6218,16 +6150,29 @@ SOCK *ClientConnectToServer(CONNECTION *c)
|
||||
SetTimeout(s, CONNECTING_TIMEOUT);
|
||||
|
||||
// Start the SSL communication
|
||||
if (StartSSLEx(s, x, k, 0, c->ServerName) == false)
|
||||
UINT err = 0;
|
||||
if (StartSSLEx3(s, x, k, NULL, 0, c->ServerName, c->Session->SslOption, &err) == false)
|
||||
{
|
||||
// SSL communication start failure
|
||||
Disconnect(s);
|
||||
ReleaseSock(s);
|
||||
c->FirstSock = NULL;
|
||||
c->Err = ERR_SERVER_IS_NOT_VPN;
|
||||
if (err != 0)
|
||||
{
|
||||
c->Err = err;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Err = ERR_SERVER_IS_NOT_VPN;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
c->Err = err;
|
||||
}
|
||||
|
||||
if (s->RemoteX == NULL)
|
||||
{
|
||||
// SSL communication start failure
|
||||
@ -6297,6 +6242,7 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)
|
||||
|
||||
if (o->ProxyType == PROXY_DIRECT)
|
||||
{
|
||||
UINT ssl_err = 0;
|
||||
UINT nat_t_err = 0;
|
||||
wchar_t tmp[MAX_SIZE];
|
||||
UniFormat(tmp, sizeof(tmp), _UU("STATUS_4"), hostname);
|
||||
@ -6306,9 +6252,10 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)
|
||||
{
|
||||
// If additional_connect == false, enable trying to NAT-T connection
|
||||
// If additional_connect == true, follow the IsRUDPSession setting in this session
|
||||
// In additional connect or redirect we do not need ssl verification as the certificate is always compared with a saved one
|
||||
sock = TcpIpConnectEx2(hostname, c->ServerPort,
|
||||
(bool *)cancel_flag, c->hWndForUI, &nat_t_err, (additional_connect ? (!sess->IsRUDPSession) : false),
|
||||
true, o->HintStr, &resolved_ip);
|
||||
true, ((additional_connect || c->UseTicket) ? NULL : sess->SslOption), &ssl_err, o->HintStr, &resolved_ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6331,7 +6278,14 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)
|
||||
// Connection failure
|
||||
if (nat_t_err != RUDP_ERROR_NAT_T_TWO_OR_MORE)
|
||||
{
|
||||
c->Err = ERR_CONNECT_FAILED;
|
||||
if (ssl_err != 0)
|
||||
{
|
||||
c->Err = ssl_err;
|
||||
}
|
||||
else
|
||||
{
|
||||
c->Err = ERR_CONNECT_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6340,6 +6294,11 @@ SOCK *ClientConnectGetSocket(CONNECTION *c, bool additional_connect)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ssl_err != 0)
|
||||
{
|
||||
c->Err = ssl_err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -6445,20 +6404,20 @@ UINT ProxyCodeToCedar(UINT code)
|
||||
// TCP connection function
|
||||
SOCK *TcpConnectEx3(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, IP *ret_ip)
|
||||
{
|
||||
return TcpConnectEx4(hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, NULL, ret_ip);
|
||||
return TcpConnectEx4(hostname, port, timeout, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, NULL, NULL, NULL, ret_ip);
|
||||
}
|
||||
SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, char *hint_str, IP *ret_ip)
|
||||
SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag, void *hWnd, bool no_nat_t, UINT *nat_t_error_code, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip)
|
||||
{
|
||||
#ifdef OS_WIN32
|
||||
if (hWnd == NULL)
|
||||
{
|
||||
#endif // OS_WIN32
|
||||
return ConnectEx5(hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, true, hint_str, ret_ip);
|
||||
return ConnectEx5(hostname, port, timeout, cancel_flag, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), nat_t_error_code, try_start_ssl, true, ssl_option, ssl_err, hint_str, ret_ip);
|
||||
#ifdef OS_WIN32
|
||||
}
|
||||
else
|
||||
{
|
||||
return WinConnectEx4((HWND)hWnd, hostname, port, timeout, 0, NULL, NULL, nat_t_error_code, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), try_start_ssl, hint_str);
|
||||
return WinConnectEx4((HWND)hWnd, hostname, port, timeout, 0, NULL, NULL, nat_t_error_code, (no_nat_t ? NULL : VPN_RUDP_SVC_NAME), try_start_ssl, ssl_option, ssl_err, hint_str);
|
||||
}
|
||||
#endif // OS_WIN32
|
||||
}
|
||||
@ -6466,9 +6425,9 @@ SOCK *TcpConnectEx4(char *hostname, UINT port, UINT timeout, bool *cancel_flag,
|
||||
// Connect with TCP/IP
|
||||
SOCK *TcpIpConnectEx(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, IP *ret_ip)
|
||||
{
|
||||
return TcpIpConnectEx2(hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, NULL, ret_ip);
|
||||
return TcpIpConnectEx2(hostname, port, cancel_flag, hWnd, nat_t_error_code, no_nat_t, try_start_ssl, NULL, NULL, NULL, ret_ip);
|
||||
}
|
||||
SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, char *hint_str, IP *ret_ip)
|
||||
SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd, UINT *nat_t_error_code, bool no_nat_t, bool try_start_ssl, SSL_VERIFY_OPTION *ssl_option, UINT *ssl_err, char *hint_str, IP *ret_ip)
|
||||
{
|
||||
SOCK *s = NULL;
|
||||
UINT dummy_int = 0;
|
||||
@ -6483,7 +6442,7 @@ SOCK *TcpIpConnectEx2(char *hostname, UINT port, bool *cancel_flag, void *hWnd,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = TcpConnectEx4(hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, hint_str, ret_ip);
|
||||
s = TcpConnectEx4(hostname, port, 0, cancel_flag, hWnd, no_nat_t, nat_t_error_code, try_start_ssl, ssl_option, ssl_err, hint_str, ret_ip);
|
||||
if (s == NULL)
|
||||
{
|
||||
return NULL;
|
||||
|
Reference in New Issue
Block a user