diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c index 6d23e5c4..9cf11dff 100644 --- a/src/Cedar/Protocol.c +++ b/src/Cedar/Protocol.c @@ -1,17 +1,17 @@ -// SoftEther VPN Source Code +// SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module // // SoftEther VPN Server, Client and Bridge are free software under GPLv2. // -// Copyright (c) 2012-2016 Daiyuu Nobori. -// Copyright (c) 2012-2016 SoftEther VPN Project, University of Tsukuba, Japan. -// Copyright (c) 2012-2016 SoftEther Corporation. +// Copyright (c) Daiyuu Nobori. +// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. +// Copyright (c) SoftEther Corporation. // // All Rights Reserved. // // http://www.softether.org/ // -// Author: Daiyuu Nobori +// Author: Daiyuu Nobori, Ph.D. // Comments: Tetsuo Sugiyama, Ph.D. // // This program is free software; you can redistribute it and/or @@ -690,8 +690,11 @@ void UpdateClientThreadMain(UPDATE_CLIENT *c) cert_hash = StrToBin(UPDATE_SERVER_CERT_HASH); - recv = HttpRequestEx2(&data, NULL, UPDATE_CONNECT_TIMEOUT, UPDATE_COMM_TIMEOUT, &ret, false, NULL, NULL, - NULL, ((cert_hash != NULL && cert_hash->Size == SHA1_SIZE) ? cert_hash->Buf : NULL), + StrCpy(data.SniString, sizeof(data.SniString), DDNS_SNI_VER_STRING); + + recv = HttpRequestEx3(&data, NULL, UPDATE_CONNECT_TIMEOUT, UPDATE_COMM_TIMEOUT, &ret, false, NULL, NULL, + NULL, ((cert_hash != NULL && (cert_hash->Size % SHA1_SIZE) == 0) ? cert_hash->Buf : NULL), + (cert_hash != NULL ? (cert_hash->Size / SHA1_SIZE) : 0), (bool *)&c->HaltFlag, 0, NULL, NULL); FreeBuf(cert_hash); @@ -1312,7 +1315,6 @@ bool ServerAccept(CONNECTION *c) FARM_MEMBER *f = NULL; SERVER *server = NULL; POLICY ticketed_policy; - UINT64 timestamp; UCHAR unique[SHA1_SIZE], unique2[SHA1_SIZE]; CEDAR *cedar; RPC_WINVER winver; @@ -1450,31 +1452,6 @@ bool ServerAccept(CONNECTION *c) } } - // Time inspection - timestamp = PackGetInt64(p, "timestamp"); - if (timestamp != 0) - { - UINT64 now = SystemTime64(); - UINT64 abs; - if (now >= timestamp) - { - abs = now - timestamp; - } - else - { - abs = timestamp - now; - } - - if (abs > ALLOW_TIMESTAMP_DIFF) - { - // Time difference is too large - FreePack(p); - c->Err = ERR_BAD_CLOCK; - error_detail = "ERR_BAD_CLOCK"; - goto CLEANUP; - } - } - // Get the client version PackGetStr(p, "client_str", c->ClientStr, sizeof(c->ClientStr)); c->ClientVer = PackGetInt(p, "client_ver"); @@ -1655,6 +1632,10 @@ bool ServerAccept(CONNECTION *c) { radius_login_opt.In_CheckVLanId = hub->Option->AssignVLanIdByRadiusAttribute; radius_login_opt.In_DenyNoVlanId = hub->Option->DenyAllRadiusLoginWithNoVlanAssign; + if (hub->Option->UseHubNameAsRadiusNasId) + { + StrCpy(radius_login_opt.NasId, sizeof(radius_login_opt.NasId), hubname); + } } // Get the various flags @@ -1814,6 +1795,9 @@ bool ServerAccept(CONNECTION *c) case AUTHTYPE_TICKET: authtype_str = _UU("LH_AUTH_TICKET"); break; + case AUTHTYPE_OPENVPN_CERT: + authtype_str = _UU("LH_AUTH_OPENVPN_CERT"); + break; } IPToStr(ip1, sizeof(ip1), &c->FirstSock->RemoteIP); IPToStr(ip2, sizeof(ip2), &c->FirstSock->LocalIP); @@ -2147,6 +2131,50 @@ bool ServerAccept(CONNECTION *c) } break; + case AUTHTYPE_OPENVPN_CERT: + // For OpenVPN; mostly same as CLIENT_AUTHTYPE_CERT, but without + // signature verification, because it was already performed during TLS handshake. + if (c->IsInProc) + { + // Certificate authentication + cert_size = PackGetDataSize(p, "cert"); + if (cert_size >= 1 && cert_size <= 100000) + { + cert_buf = ZeroMalloc(cert_size); + if (PackGetData(p, "cert", cert_buf)) + { + BUF *b = NewBuf(); + X *x; + WriteBuf(b, cert_buf, cert_size); + x = BufToX(b, false); + if (x != NULL && x->is_compatible_bit) + { + Debug("Got to SamAuthUserByCert %s\n", username); // XXX + // Check whether the certificate is valid. + auth_ret = SamAuthUserByCert(hub, username, x); + if (auth_ret) + { + // Copy the certificate + c->ClientX = CloneX(x); + } + } + FreeX(x); + FreeBuf(b); + } + Free(cert_buf); + } + } + else + { + // OpenVPN certificate authentication cannot be used directly by external clients + Unlock(hub->lock); + ReleaseHub(hub); + FreePack(p); + c->Err = ERR_AUTHTYPE_NOT_SUPPORTED; + goto CLEANUP; + } + break; + default: // Unknown authentication method Unlock(hub->lock); @@ -4574,7 +4602,7 @@ bool ClientSecureSign(CONNECTION *c, UCHAR *sign, UCHAR *random, X **x) if (ret) { - Copy(sign, ss->Signature, 128); + Copy(sign, ss->Signature, sizeof(ss->Signature)); *x = ss->ClientCert; } @@ -5206,7 +5234,7 @@ REDIRECTED: sess->EnableBulkOnRUDP = false; sess->EnableHMacOnBulkOfRUDP = false; - if (s != NULL && s->IsRUDPSocket && s->BulkRecvKey != NULL && s->BulkSendKey != NULL) + if (s->IsRUDPSocket && s->BulkRecvKey != NULL && s->BulkSendKey != NULL) { // Bulk transfer on R-UDP if (PackGetBool(p, "enable_bulk_on_rudp")) @@ -5853,7 +5881,7 @@ bool ClientUploadAuth(CONNECTION *c) // Authentication by secure device if (ClientSecureSign(c, sign, c->Random, &x)) { - p = PackLoginWithCert(o->HubName, a->Username, x, sign, 128); + p = PackLoginWithCert(o->HubName, a->Username, x, sign, x->bits / 8); c->ClientX = CloneX(x); FreeX(x); } @@ -5876,9 +5904,6 @@ bool ClientUploadAuth(CONNECTION *c) PackAddData(p, "ticket", c->Ticket, SHA1_SIZE); } - // Current time - PackAddInt64(p, "timestamp", SystemTime64()); - if (p == NULL) { // Error @@ -6674,7 +6699,10 @@ SOCK *SocksConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port, if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL || server_port == 0) { - c->Err = ERR_PROXY_CONNECT_FAILED; + if (c != NULL) + { + c->Err = ERR_PROXY_CONNECT_FAILED; + } return NULL; } @@ -6868,7 +6896,10 @@ SOCK *ProxyConnectEx2(CONNECTION *c, char *proxy_host_name, UINT proxy_port, if (c == NULL || proxy_host_name == NULL || proxy_port == 0 || server_host_name == NULL || server_port == 0) { - c->Err = ERR_PROXY_CONNECT_FAILED; + if( c != NULL) + { + c->Err = ERR_PROXY_CONNECT_FAILED; + } return NULL; } if (username != NULL && password != NULL && @@ -7263,6 +7294,46 @@ PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_pass return p; } +// Generate a packet of OpenVPN certificate login +PACK *PackLoginWithOpenVPNCertificate(char *hubname, char *username, X *x) +{ + PACK *p; + char cn_username[128]; + BUF *cert_buf = NULL; + // Validate arguments + if (hubname == NULL || username == NULL || x == NULL) + { + return NULL; + } + + p = NewPack(); + PackAddStr(p, "method", "login"); + PackAddStr(p, "hubname", hubname); + + if (IsEmptyStr(username)) + { + if (x->subject_name == NULL) + { + return NULL; + } + wcstombs(cn_username, x->subject_name->CommonName, 127); + cn_username[127] = '\0'; + PackAddStr(p, "username", cn_username); + } + else + { + PackAddStr(p, "username", username); + } + + PackAddInt(p, "authtype", AUTHTYPE_OPENVPN_CERT); + + cert_buf = XToBuf(x, false); + PackAddBuf(p, "cert", cert_buf); + FreeBuf(cert_buf); + + return p; +} + // Create a packet of password authentication login PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password) { @@ -7333,7 +7404,3 @@ void GenerateRC4KeyPair(RC4_KEY_PAIR *k) Rand(k->ServerToClientKey, sizeof(k->ServerToClientKey)); } - -// Developed by SoftEther VPN Project at University of Tsukuba in Japan. -// Department of Computer Science has dozens of overly-enthusiastic geeks. -// Join us: http://www.tsukuba.ac.jp/english/admission/ diff --git a/src/Cedar/SM.c b/src/Cedar/SM.c index a45213b4..d94df78b 100644 --- a/src/Cedar/SM.c +++ b/src/Cedar/SM.c @@ -1,17 +1,17 @@ -// SoftEther VPN Source Code +// SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module // // SoftEther VPN Server, Client and Bridge are free software under GPLv2. // -// Copyright (c) 2012-2016 Daiyuu Nobori. -// Copyright (c) 2012-2016 SoftEther VPN Project, University of Tsukuba, Japan. -// Copyright (c) 2012-2016 SoftEther Corporation. +// Copyright (c) Daiyuu Nobori. +// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. +// Copyright (c) SoftEther Corporation. // // All Rights Reserved. // // http://www.softether.org/ // -// Author: Daiyuu Nobori +// Author: Daiyuu Nobori, Ph.D. // Comments: Tetsuo Sugiyama, Ph.D. // // This program is free software; you can redistribute it and/or @@ -872,17 +872,19 @@ UINT SmDDnsDlg(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param) // Get the ddns key from the server configuration file static UINT SmDdnsGetKey(char *key, SM_DDNS *d){ - RPC *rpc = d->s->Rpc; RPC_CONFIG config; UINT err; BUF *buf; FOLDER *root, *ddnsfolder; + RPC *rpc; // Validate arguments if(d == NULL || d->s == NULL || key == NULL){ return ERR_INTERNAL_ERROR; } + rpc = d->s->Rpc; + Zero(&config, sizeof(config)); err = ScGetConfig(d->s->Rpc, &config); if(err != ERR_NO_ERROR){ @@ -17011,6 +17013,7 @@ void SmSslDlgInit(HWND hWnd, SM_SSL *s) // Set the encryption algorithm list cipher_list = GetCipherList(); + SetFont(hWnd, C_CIPHER, GetFont("Tahoma", 8, false, false, false, false)); CbSetHeight(hWnd, C_CIPHER, 18); for (i = 0;i < cipher_list->NumTokens;i++) { @@ -18362,6 +18365,7 @@ void SmServerDlgInit(HWND hWnd, SM_SERVER *p) void SmServerDlgRefresh(HWND hWnd, SM_SERVER *p) { RPC_ENUM_HUB t; + RPC_LISTENER_LIST t2; DDNS_CLIENT_STATUS st; RPC_AZURE_STATUS sta; UINT i; @@ -18449,38 +18453,34 @@ void SmServerDlgRefresh(HWND hWnd, SM_SERVER *p) } // Listener list update - if (p != NULL) + Zero(&t2, sizeof(RPC_LISTENER_LIST)); + if (CALL(hWnd, ScEnumListener(p->Rpc, &t2))) { - RPC_LISTENER_LIST t; - Zero(&t, sizeof(RPC_LISTENER_LIST)); - if (CALL(hWnd, ScEnumListener(p->Rpc, &t))) + LVB *b = LvInsertStart(); + for (i = 0;i < t2.NumPort;i++) { - LVB *b = LvInsertStart(); - for (i = 0;i < t.NumPort;i++) + wchar_t tmp[MAX_SIZE]; + wchar_t *status; + UINT icon; + UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t2.Ports[i]); + + status = _UU("CM_LISTENER_ONLINE"); + icon = ICO_PROTOCOL; + if (t2.Errors[i]) { - wchar_t tmp[MAX_SIZE]; - wchar_t *status; - UINT icon; - UniFormat(tmp, sizeof(tmp), _UU("CM_LISTENER_TCP_PORT"), t.Ports[i]); - - status = _UU("CM_LISTENER_ONLINE"); - icon = ICO_PROTOCOL; - if (t.Errors[i]) - { - status = _UU("CM_LISTENER_ERROR"); - icon = ICO_PROTOCOL_X; - } - else if (t.Enables[i] == false) - { - status = _UU("CM_LISTENER_OFFLINE"); - icon = ICO_PROTOCOL_OFFLINE; - } - - LvInsertAdd(b, icon, (void *)t.Ports[i], 2, tmp, status); + status = _UU("CM_LISTENER_ERROR"); + icon = ICO_PROTOCOL_X; } - LvInsertEnd(b, hWnd, L_LISTENER); - FreeRpcListenerList(&t); + else if (t2.Enables[i] == false) + { + status = _UU("CM_LISTENER_OFFLINE"); + icon = ICO_PROTOCOL_OFFLINE; + } + + LvInsertAdd(b, icon, (void *)t2.Ports[i], 2, tmp, status); } + LvInsertEnd(b, hWnd, L_LISTENER); + FreeRpcListenerList(&t2); } // Get the DDNS client state @@ -20695,7 +20695,3 @@ void SMExec() #endif // WIN32 - -// Developed by SoftEther VPN Project at University of Tsukuba in Japan. -// Department of Computer Science has dozens of overly-enthusiastic geeks. -// Join us: http://www.tsukuba.ac.jp/english/admission/ diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index 0a7a321a..b6fba840 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -1,17 +1,17 @@ -// SoftEther VPN Source Code +// SoftEther VPN Source Code - Developer Edition Master Branch // Mayaqua Kernel // // SoftEther VPN Server, Client and Bridge are free software under GPLv2. // -// Copyright (c) 2012-2016 Daiyuu Nobori. -// Copyright (c) 2012-2016 SoftEther VPN Project, University of Tsukuba, Japan. -// Copyright (c) 2012-2016 SoftEther Corporation. +// Copyright (c) Daiyuu Nobori. +// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. +// Copyright (c) SoftEther Corporation. // // All Rights Reserved. // // http://www.softether.org/ // -// Author: Daiyuu Nobori +// Author: Daiyuu Nobori, Ph.D. // Contributors: // - nattoheaven (https://github.com/nattoheaven) // Comments: Tetsuo Sugiyama, Ph.D. @@ -233,7 +233,12 @@ static COUNTER *getip_thread_counter = NULL; static UINT max_getip_thread = 0; -static char *cipher_list = "RC4-MD5 RC4-SHA AES128-SHA AES256-SHA DES-CBC-SHA DES-CBC3-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA"; +static char *cipher_list = "RC4-MD5 RC4-SHA AES128-SHA AES256-SHA DES-CBC-SHA DES-CBC3-SHA DHE-RSA-AES128-SHA DHE-RSA-AES256-SHA AES128-GCM-SHA256 AES128-SHA256 AES256-GCM-SHA384 AES256-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES128-SHA256 DHE-RSA-AES256-GCM-SHA384 DHE-RSA-AES256-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-SHA384" +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + " DHE-RSA-CHACHA20-POLY1305 ECDHE-RSA-CHACHA20-POLY1305"; +#endif +; + static LIST *ip_clients = NULL; static LIST *local_mac_list = NULL; @@ -245,7 +250,7 @@ static UINT rand_port_numbers[256] = {0}; static bool g_use_privateip_file = false; static bool g_source_ip_validation_force_disable = false; -static DH_CTX *dh_1024 = NULL; +static DH_CTX *dh_param = NULL; typedef struct PRIVATE_IP_SUBNET { @@ -1722,7 +1727,7 @@ void RUDPDo_NatT_Interrupt(RUDP_STACK *r) PackAddInt64(p, "tran_id", r->NatT_TranId); PackAddStr(p, "token", r->NatT_Token); PackAddStr(p, "svc_name", r->SvcName); - PackAddStr(p, "product_str", CEDAR_PRODUCT_STR); + PackAddStr(p, "product_str", "SoftEther OSS"); PackAddInt64(p, "session_key", r->NatT_SessionKey); PackAddInt(p, "nat_traversal_version", UDP_NAT_TRAVERSAL_VERSION); @@ -2654,7 +2659,7 @@ void RUDPBulkSend(RUDP_STACK *r, RUDP_SESSION *se, void *data, UINT data_size) CRYPT *c; UCHAR crypt_key_src[SHA1_SIZE * 2]; UCHAR crypt_key[SHA1_SIZE]; - UINT icmp_type; + UINT icmp_type = 0; UCHAR sign[SHA1_SIZE]; UCHAR iv[SHA1_SIZE + 1]; // Validate arguments @@ -2724,16 +2729,16 @@ void RUDPBulkSend(RUDP_STACK *r, RUDP_SESSION *se, void *data, UINT data_size) // Start a socket for R-UDP Listening SOCK *ListenRUDP(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode) { - return ListenRUDPEx(svc_name, proc_interrupts, proc_rpc_recv, param, port, no_natt_register, over_dns_mode, NULL, 0); + return ListenRUDPEx(svc_name, proc_interrupts, proc_rpc_recv, param, port, no_natt_register, over_dns_mode, NULL, 0, NULL); } SOCK *ListenRUDPEx(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode, - volatile UINT *natt_global_udp_port, UCHAR rand_port_id) + volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip) { SOCK *s; RUDP_STACK *r; // Creating a R-UDP stack - r = NewRUDPServer(svc_name, proc_interrupts, proc_rpc_recv, param, port, no_natt_register, over_dns_mode, natt_global_udp_port, rand_port_id); + r = NewRUDPServer(svc_name, proc_interrupts, proc_rpc_recv, param, port, no_natt_register, over_dns_mode, natt_global_udp_port, rand_port_id, listen_ip); if (r == NULL) { return NULL; @@ -5259,7 +5264,7 @@ SOCK *NewRUDPClientDirect(char *svc_name, IP *ip, UINT port, UINT *error_code, U return NULL; } - r = NewRUDP(false, svc_name, NULL, NULL, NULL, local_port, sock, sock_event, false, over_dns_mode, ip, NULL, 0); + r = NewRUDP(false, svc_name, NULL, NULL, NULL, local_port, sock, sock_event, false, over_dns_mode, ip, NULL, 0, NULL); if (r == NULL) { *error_code = RUDP_ERROR_UNKNOWN; @@ -5318,7 +5323,7 @@ SOCK *NewRUDPClientDirect(char *svc_name, IP *ip, UINT port, UINT *error_code, U } // Creating a R-UDP server -RUDP_STACK *NewRUDPServer(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode, volatile UINT *natt_global_udp_port, UCHAR rand_port_id) +RUDP_STACK *NewRUDPServer(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, bool no_natt_register, bool over_dns_mode, volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip) { RUDP_STACK *r; // Validate arguments @@ -5334,7 +5339,7 @@ RUDP_STACK *NewRUDPServer(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_inter ListenTcpForPopupFirewallDialog(); - r = NewRUDP(true, svc_name, proc_interrupts, proc_rpc_recv, param, port, NULL, NULL, no_natt_register, over_dns_mode, NULL, natt_global_udp_port, rand_port_id); + r = NewRUDP(true, svc_name, proc_interrupts, proc_rpc_recv, param, port, NULL, NULL, no_natt_register, over_dns_mode, NULL, natt_global_udp_port, rand_port_id, listen_ip); if (r == NULL) { @@ -5345,7 +5350,7 @@ RUDP_STACK *NewRUDPServer(char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_inter } // Creating a R-UDP -RUDP_STACK *NewRUDP(bool server_mode, char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, SOCK *sock, SOCK_EVENT *sock_event, bool server_no_natt_register, bool over_dns_mode, IP *client_target_ip, volatile UINT *natt_global_udp_port, UCHAR rand_port_id) +RUDP_STACK *NewRUDP(bool server_mode, char *svc_name, RUDP_STACK_INTERRUPTS_PROC *proc_interrupts, RUDP_STACK_RPC_RECV_PROC *proc_rpc_recv, void *param, UINT port, SOCK *sock, SOCK_EVENT *sock_event, bool server_no_natt_register, bool over_dns_mode, IP *client_target_ip, volatile UINT *natt_global_udp_port, UCHAR rand_port_id, IP *listen_ip) { RUDP_STACK *r; char tmp[MAX_SIZE]; @@ -5371,11 +5376,11 @@ RUDP_STACK *NewRUDP(bool server_mode, char *svc_name, RUDP_STACK_INTERRUPTS_PROC { if (rand_port_id == 0) { - sock = NewUDP(port); + sock = NewUDPEx2(port, false, listen_ip); } else { - sock = NewUDPEx2RandMachineAndExePath(false, NULL, 0, rand_port_id); + sock = NewUDPEx2RandMachineAndExePath(false, listen_ip, 0, rand_port_id); } } @@ -5804,14 +5809,58 @@ SOCK *ListenAnyPortEx2(bool local_only, bool disable_ca) return NULL; } -int cb_test(int a, X509_STORE_CTX *ctx) + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +#define X509_STORE_CTX_get0_cert(o) ((o)->cert) +#endif + +// Verify client SSL certificate during TLS handshake. +// +// (actually, only save the certificate for later authentication in Protocol.c) +int SslCertVerifyCallback(int preverify_ok, X509_STORE_CTX *ctx) { - WHERE; - return 1; + SSL *ssl; + struct SslClientCertInfo *clientcert; + X509 *cert; + + ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); + clientcert = SSL_get_ex_data(ssl, GetSslClientCertIndex()); + + if (clientcert != NULL) + { + clientcert->PreverifyErr = X509_STORE_CTX_get_error(ctx); + clientcert->PreverifyErrMessage[0] = '\0'; + if (!preverify_ok) + { + const char *msg = X509_verify_cert_error_string(clientcert->PreverifyErr); + StrCpy(clientcert->PreverifyErrMessage, PREVERIFY_ERR_MESSAGE_SIZE, msg); + Debug("SslCertVerifyCallback preverify error: '%s'\n", msg); + } + else + { + cert = X509_STORE_CTX_get0_cert(ctx); + if (cert != NULL) + { + X *tmpX = X509ToX(cert); // this only wraps cert, but we need to make a copy + X *copyX = CloneX(tmpX); + tmpX->do_not_free = true; // do not release inner X509 object + FreeX(tmpX); + clientcert->X = copyX; + } + } + } + + return 1; /* allow the verification process to continue */ } // Create a new SSL pipe SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh) +{ + return NewSslPipeEx(server_mode, x, k, dh, false, NULL); +} + +// Create a new SSL pipe with extended options +SSL_PIPE *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert) { SSL_PIPE *s; SSL *ssl; @@ -5821,7 +5870,8 @@ SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh) { if (server_mode) { - SSL_CTX_set_ssl_version(ssl_ctx, TLSv1_server_method()); + SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_method()); + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); AddChainSslCertOnDirectory(ssl_ctx); @@ -5832,10 +5882,13 @@ SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh) } else { - SSL_CTX_set_ssl_version(ssl_ctx, TLSv1_client_method()); + SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_client_method()); } - //SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, cb_test); + if (verify_peer) + { + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, SslCertVerifyCallback); + } if (dh != NULL) { @@ -5848,6 +5901,8 @@ SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh) } ssl = SSL_new(ssl_ctx); + + SSL_set_ex_data(ssl, GetSslClientCertIndex(), clientcert); } Unlock(openssl_lock); @@ -6484,38 +6539,6 @@ L_LOOP: #endif // OS_WIN32 - -// Get whether the aquirement of the Process ID of the TCP connection succeed -bool CanGetTcpProcessId() -{ - UINT i; - bool ret = false; - LIST *o = GetTcpTableList(); - - if (o == NULL) - { - return false; - } - - for (i = 0;i < LIST_NUM(o);i++) - { - TCPTABLE *t = LIST_DATA(o, i); - - if (t->ProcessId != 0) - { - ret = true; - break; - } - } - - FreeTcpTableList(o); - - return ret; -} - - - - #define USE_OLD_GETIP // Set the arp_filter in Linux @@ -7367,7 +7390,7 @@ bool StrToIP6(IP *ip, char *str) if (StartWith(tmp, "[") && EndWith(tmp, "]")) { // If the string is enclosed in square brackets, remove brackets - StrCpy(tmp, sizeof(tmp), &tmp[1]); + StrCpyAllowOverlap(tmp, sizeof(tmp), &tmp[1]); if (StrLen(tmp) >= 1) { @@ -9157,12 +9180,23 @@ void UnixSetSockEvent(SOCK_EVENT *event) } } +// This is a helper function for select() +int safe_fd_set(int fd, fd_set* fds, int* max_fd) { + FD_SET(fd, fds); + if (fd > *max_fd) { + *max_fd = fd; + } + return 0; +} + // Execute 'select' for the socket void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, UINT timeout) { #ifdef UNIX_MACOS - int kq; - struct kevent *kevents; + fd_set rfds; //read descriptors + fd_set wfds; //write descriptors + int max_fd = 0; //maximum descriptor id + struct timeval tv; //timeval for timeout #else // UNIX_MACOS struct pollfd *p; #endif // UNIX_MACOS @@ -9203,8 +9237,8 @@ void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, U num = num_read_total + num_write_total; #ifdef UNIX_MACOS - kq = kqueue(); - kevents = ZeroMallocFast(sizeof(struct kevent) * (num + num_write_total)); + FD_ZERO(&rfds); //zero out descriptor set for read descriptors + FD_ZERO(&wfds); //same for write #else // UNIX_MACOS p = ZeroMallocFast(sizeof(struct pollfd) * num); #endif // UNIX_MACOS @@ -9216,7 +9250,7 @@ void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, U if (reads[i] != INVALID_SOCKET) { #ifdef UNIX_MACOS - EV_SET(&kevents[n++], reads[i], EVFILT_READ, EV_ADD, 0, 0, NULL); + safe_fd_set(reads[i], &rfds, &max_fd); #else // UNIX_MACOS struct pollfd *pfd = &p[n++]; pfd->fd = reads[i]; @@ -9230,8 +9264,7 @@ void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, U if (writes[i] != INVALID_SOCKET) { #ifdef UNIX_MACOS - EV_SET(&kevents[n++], reads[i], EVFILT_READ, EV_ADD, 0, 0, NULL); - EV_SET(&kevents[n++], reads[i], EVFILT_WRITE, EV_ADD, 0, 0, NULL); + safe_fd_set(writes[i], &wfds, &max_fd); #else // UNIX_MACOS struct pollfd *pfd = &p[n++]; pfd->fd = writes[i]; @@ -9243,15 +9276,9 @@ void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, U if (num != 0) { #ifdef UNIX_MACOS - struct timespec kevent_timeout, *p_kevent_timeout; - if (timeout == INFINITE) { - p_kevent_timeout = NULL; - } else { - kevent_timeout.tv_sec = timeout / 1000; - kevent_timeout.tv_nsec = (timeout % 1000) * 1000000l; - p_kevent_timeout = &kevent_timeout; - } - kevent(kq, kevents, n, kevents, n, p_kevent_timeout); + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000l; + select(max_fd + 1, &rfds, &wfds, NULL, timeout == INFINITE ? NULL : &tv); #else // UNIX_MACOS poll(p, num, timeout == INFINITE ? -1 : (int)timeout); #endif // UNIX_MACOS @@ -9261,12 +9288,9 @@ void UnixSelectInner(UINT num_read, UINT *reads, UINT num_write, UINT *writes, U SleepThread(timeout); } -#ifdef UNIX_MACOS - Free(kevents); - close(kq); -#else // UNIX_MACOS +#ifndef UNIX_MACOS Free(p); -#endif // UNIX_MACOS +#endif // not UNIX_MACOS } // Clean-up of the socket event @@ -9422,11 +9446,13 @@ void UnixInitAsyncSocket(SOCK *sock) UnixSetSocketNonBlockingMode(sock->socket, true); } +#if OPENSSL_VERSION_NUMBER < 0x10100000L if (sock->ssl != NULL && sock->ssl->s3 != NULL) { sock->Ssl_Init_Async_SendAlert[0] = sock->ssl->s3->send_alert[0]; sock->Ssl_Init_Async_SendAlert[1] = sock->ssl->s3->send_alert[1]; } +#endif } // Initializing the socket library @@ -11127,27 +11153,6 @@ void FreeWaitThread() WaitThreadList = NULL; } -// Check the cipher list name -bool CheckCipherListName(char *name) -{ - UINT i; - // Validate arguments - if (name == NULL) - { - return false; - } - - for (i = 0;i < cipher_list_token->NumTokens;i++) - { - if (StrCmpi(cipher_list_token->Token[i], name) == 0) - { - return true; - } - } - - return false; -} - // Renewing the IP address of the DHCP server void RenewDhcp() { @@ -12682,6 +12687,14 @@ bool RecvAll(SOCK *sock, void *data, UINT size, bool secure) { return false; } + if (ret == SOCK_LATER) + { + // I suppose that this is safe because the RecvAll() function is used only + // if the sock->AsyncMode == true. And the Recv() function may return + // SOCK_LATER only if the sock->AsyncMode == false. Therefore the call of + // Recv() function in the RecvAll() function never returns SOCK_LATER. + return false; + } recv_size += ret; if (recv_size >= size) { @@ -12764,7 +12777,6 @@ bool SendAll(SOCK *sock, void *data, UINT size, bool secure) // Set the cipher algorithm name to want to use void SetWantToUseCipher(SOCK *sock, char *name) { - char tmp[254]; // Validate arguments if (sock == NULL || name == NULL) { @@ -12776,12 +12788,7 @@ void SetWantToUseCipher(SOCK *sock, char *name) Free(sock->WaitToUseCipher); } - Zero(tmp, sizeof(tmp)); - StrCpy(tmp, sizeof(tmp), name); - StrCat(tmp, sizeof(tmp), " "); - StrCat(tmp, sizeof(tmp), cipher_list); - - sock->WaitToUseCipher = CopyStr(tmp); + sock->WaitToUseCipher = CopyStr(name); } // Add all the chain certificates in the chain_certs directory @@ -12904,7 +12911,7 @@ bool AddChainSslCert(struct ssl_ctx_st *ctx, X *x) // Start a TCP-SSL communication bool StartSSL(SOCK *sock, X *x, K *priv) { - return StartSSLEx(sock, x, priv, false, 0, NULL); + return StartSSLEx(sock, x, priv, true, 0, NULL); } bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls, UINT ssl_timeout, char *sni_hostname) { @@ -12966,13 +12973,38 @@ bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls, UINT ssl_timeout, ch { if (sock->ServerMode) { - if (sock->AcceptOnlyTls == false) + SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_method()); + +#ifdef SSL_OP_NO_SSLv2 + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); +#endif // SSL_OP_NO_SSLv2 + + if (sock->SslAcceptSettings.AcceptOnlyTls) { - SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_method()); +#ifdef SSL_OP_NO_SSLv3 + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3); +#endif // SSL_OP_NO_SSLv3 } - else + + if (sock->SslAcceptSettings.Tls_Disable1_0) { - SSL_CTX_set_ssl_version(ssl_ctx, TLSv1_method()); +#ifdef SSL_OP_NO_TLSv1 + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1); +#endif // SSL_OP_NO_TLSv1 + } + + if (sock->SslAcceptSettings.Tls_Disable1_1) + { +#ifdef SSL_OP_NO_TLSv1_1 + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); +#endif // SSL_OP_NO_TLSv1_1 + } + + if (sock->SslAcceptSettings.Tls_Disable1_2) + { +#ifdef SSL_OP_NO_TLSv1_2 + SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2); +#endif // SSL_OP_NO_TLSv1_2 } Unlock(openssl_lock); @@ -12983,11 +13015,15 @@ bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls, UINT ssl_timeout, ch { if (client_tls == false) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L SSL_CTX_set_ssl_version(ssl_ctx, SSLv3_method()); +#else + SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_method()); +#endif } else { - SSL_CTX_set_ssl_version(ssl_ctx, TLSv1_client_method()); + SSL_CTX_set_ssl_version(ssl_ctx, SSLv23_client_method()); } } sock->ssl = SSL_new(ssl_ctx); @@ -13003,6 +13039,7 @@ bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls, UINT ssl_timeout, ch } } #endif // SSL_CTRL_SET_TLSEXT_HOSTNAME + } Unlock(openssl_lock); @@ -13029,7 +13066,8 @@ bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls, UINT ssl_timeout, ch // Set the cipher algorithm name to want to use Lock(openssl_lock); { - SSL_set_cipher_list(sock->ssl, sock->WaitToUseCipher); + if (SSL_set_cipher_list(sock->ssl, sock->WaitToUseCipher) == 0) + SSL_set_cipher_list(sock->ssl, DEFAULT_CIPHER_LIST); } Unlock(openssl_lock); } @@ -13188,6 +13226,8 @@ bool StartSSLEx(SOCK *sock, X *x, K *priv, bool client_tls, UINT ssl_timeout, ch return true; } + + #ifdef ENABLE_SSL_LOGGING // Enable SSL logging @@ -13306,7 +13346,7 @@ void SetNoNeedToRead(SOCK *sock) UINT SecureRecv(SOCK *sock, void *data, UINT size) { SOCKET s; - int ret, e = 0; + int ret, e = SSL_ERROR_NONE; SSL *ssl; #ifdef UNIX_SOLARIS @@ -13346,10 +13386,14 @@ UINT SecureRecv(SOCK *sock, void *data, UINT size) e = SSL_get_error(ssl, ret); if (e == SSL_ERROR_WANT_READ || e == SSL_ERROR_WANT_WRITE || e == SSL_ERROR_SSL) { - if (e == SSL_ERROR_SSL && + if (e == SSL_ERROR_SSL +#if OPENSSL_VERSION_NUMBER < 0x10100000L + && sock->ssl->s3->send_alert[0] == SSL3_AL_FATAL && sock->ssl->s3->send_alert[0] != sock->Ssl_Init_Async_SendAlert[0] && - sock->ssl->s3->send_alert[1] != sock->Ssl_Init_Async_SendAlert[1]) + sock->ssl->s3->send_alert[1] != sock->Ssl_Init_Async_SendAlert[1] +#endif + ) { Debug("%s %u SSL Fatal Error on ASYNC socket !!!\n", __FILE__, __LINE__); Disconnect(sock); @@ -13432,10 +13476,14 @@ UINT SecureRecv(SOCK *sock, void *data, UINT size) { if (e == SSL_ERROR_WANT_READ || e == SSL_ERROR_WANT_WRITE || e == SSL_ERROR_SSL) { - if (e == SSL_ERROR_SSL && + if (e == SSL_ERROR_SSL +#if OPENSSL_VERSION_NUMBER < 0x10100000L + && sock->ssl->s3->send_alert[0] == SSL3_AL_FATAL && sock->ssl->s3->send_alert[0] != sock->Ssl_Init_Async_SendAlert[0] && - sock->ssl->s3->send_alert[1] != sock->Ssl_Init_Async_SendAlert[1]) + sock->ssl->s3->send_alert[1] != sock->Ssl_Init_Async_SendAlert[1] +#endif + ) { Debug("%s %u SSL Fatal Error on ASYNC socket !!!\n", __FILE__, __LINE__); Disconnect(sock); @@ -13455,7 +13503,7 @@ UINT SecureRecv(SOCK *sock, void *data, UINT size) UINT SecureSend(SOCK *sock, void *data, UINT size) { SOCKET s; - int ret, e; + int ret, e = SSL_ERROR_NONE; SSL *ssl; s = sock->socket; ssl = sock->ssl; @@ -13820,6 +13868,10 @@ void DisableGetHostNameWhenAcceptInit() // Initialize the connection acceptance void AcceptInit(SOCK *s) +{ + AcceptInitEx(s, false); +} +void AcceptInitEx(SOCK *s, bool no_lookup_hostname) { char tmp[MAX_SIZE]; // Validate arguments @@ -13830,7 +13882,7 @@ void AcceptInit(SOCK *s) Zero(tmp, sizeof(tmp)); - if (disable_gethostname_by_accept == false) + if (disable_gethostname_by_accept == false && no_lookup_hostname == false) { if (GetHostName(tmp, sizeof(tmp), &s->RemoteIP) == false || IsEmptyStr(tmp)) @@ -14202,9 +14254,9 @@ SOCK *Listen(UINT port) } SOCK *ListenEx(UINT port, bool local_only) { - return ListenEx2(port, local_only, false); + return ListenEx2(port, local_only, false, NULL); } -SOCK *ListenEx2(UINT port, bool local_only, bool enable_ca) +SOCK *ListenEx2(UINT port, bool local_only, bool enable_ca, IP *listen_ip) { SOCKET s; SOCK *sock; @@ -14233,7 +14285,14 @@ SOCK *ListenEx2(UINT port, bool local_only, bool enable_ca) SetIP(&localhost, 127, 0, 0, 1); addr.sin_port = htons((UINT)port); - *((UINT *)&addr.sin_addr) = htonl(INADDR_ANY); + if (listen_ip == NULL) + { + *((UINT *)&addr.sin_addr) = htonl(INADDR_ANY); + } + else + { + IPToInAddr(&addr.sin_addr, listen_ip); + } addr.sin_family = AF_INET; if (local_only) @@ -17537,7 +17596,7 @@ void IPToInAddr6(struct in6_addr *addr, IP *ip) return; } - Zero(addr, sizeof(struct in_addr)); + Zero(addr, sizeof(struct in6_addr)); if (IsIP6(ip)) { @@ -17742,9 +17801,9 @@ DH *TmpDhCallback(SSL *ssl, int is_export, int keylength) { DH *ret = NULL; - if (dh_1024 != NULL) + if (dh_param != NULL) { - ret = dh_1024->dh; + ret = dh_param->dh; } return ret; @@ -17768,6 +17827,10 @@ struct ssl_ctx_st *NewSSLCtx(bool server_mode) SSL_CTX_set_tmp_dh_callback(ctx, TmpDhCallback); +#ifdef SSL_CTX_set_ecdh_auto + SSL_CTX_set_ecdh_auto(ctx, 1); +#endif // SSL_CTX_set_ecdh_auto + return ctx; } @@ -17860,9 +17923,6 @@ void InitNetwork() disable_cache = false; - - dh_1024 = DhNewGroup2(); - Zero(rand_port_numbers, sizeof(rand_port_numbers)); SetGetIpThreadMaxNum(DEFAULT_GETIP_THREAD_MAX_NUM); @@ -18270,7 +18330,7 @@ void SetCurrentGlobalIP(IP *ip, bool ipv6) return; } - if (IsZeroIp(ip)); + if (IsZeroIp(ip)) { return; } @@ -18295,10 +18355,10 @@ void SetCurrentGlobalIP(IP *ip, bool ipv6) void FreeNetwork() { - if (dh_1024 != NULL) + if (dh_param != NULL) { - DhFree(dh_1024); - dh_1024 = NULL; + DhFree(dh_param); + dh_param = NULL; } // Release of thread-related @@ -18372,27 +18432,6 @@ void FreeNetwork() } -// Add a socket to socket list -void AddSockList(SOCKLIST *sl, SOCK *s) -{ - // Validate arguments - if (sl == NULL || s == NULL) - { - return; - } - - LockList(sl->SockList); - { - if (IsInList(sl->SockList, s) == false) - { - AddRef(s->ref); - - Insert(sl->SockList, s); - } - } - UnlockList(sl->SockList); -} - // Remove the socket from socket list void DelSockList(SOCKLIST *sl, SOCK *s) { @@ -20062,6 +20101,11 @@ void UdpListenerThread(THREAD *thread, void *param) { IP *ip = LIST_DATA(iplist, i); + if (CmpIpAddr(ip, &u->ListenIP) != 0) + { + continue; + } + WriteBuf(ip_list_buf_new, ip, sizeof(IP)); for (j = 0;j < LIST_NUM(u->PortList);j++) @@ -20205,6 +20249,8 @@ LABEL_RESTART: if (u->PollMyIpAndPort) { + // Create a thread to get a NAT-T IP address if necessary + if (u->GetNatTIpThread == NULL) { // Create a thread to get a NAT-T IP address if necessary if (u->GetNatTIpThread == NULL) @@ -20577,7 +20623,7 @@ void UdpListenerSendPacket(UDPLISTENER *u, UDPPACKET *packet) } // Creating a UDP listener -UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param) +UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param, IP *listen_ip) { UDPLISTENER *u; // Validate arguments @@ -20593,6 +20639,11 @@ UDPLISTENER *NewUdpListener(UDPLISTENER_RECV_PROC *recv_proc, void *param) u->PortList = NewList(NULL); u->Event = NewSockEvent(); + if (listen_ip) + { + Copy(&u->ListenIP, listen_ip, sizeof(IP)); + } + u->RecvProc = recv_proc; u->SendPacketList = NewList(NULL); @@ -22663,7 +22714,14 @@ bool GetSniNameFromSslPacket(UCHAR *packet_buf, UINT packet_size, char *sni, UIN USHORT handshake_length; // Validate arguments - if (packet_buf == NULL || packet_size == 0) + if (packet_buf == NULL || packet_size <= 11) + { + return false; + } + + if (!(packet_buf[0] == 0x16 && packet_buf[1] >= 0x03 && + packet_buf[5] == 0x01 && packet_buf[6] == 0x00 && + packet_buf[9] >= 0x03)) { return false; } @@ -22677,7 +22735,7 @@ bool GetSniNameFromSslPacket(UCHAR *packet_buf, UINT packet_size, char *sni, UIN version = Endian16(version); handshake_length = Endian16(handshake_length); - if (version >= 0x0301) + if (content_type == 0x16 && version >= 0x0301) { UCHAR *handshake_data = Malloc(handshake_length); @@ -22794,9 +22852,12 @@ bool GetSniNameFromSslPacket(UCHAR *packet_buf, UINT packet_size, char *sni, UIN if (ReadBuf(dbuf, name_buf, name_len) == name_len) { - ret = true; + if (StrLen(name_buf) >= 1) + { + ret = true; - StrCpy(sni, sni_size, name_buf); + StrCpy(sni, sni_size, name_buf); + } } Free(name_buf); @@ -22850,6 +22911,12 @@ bool GetSniNameFromSslPacket(UCHAR *packet_buf, UINT packet_size, char *sni, UIN return ret; } -// Developed by SoftEther VPN Project at University of Tsukuba in Japan. -// Department of Computer Science has dozens of overly-enthusiastic geeks. -// Join us: http://www.tsukuba.ac.jp/english/admission/ +void SetDhParam(DH_CTX *dh) + { + if (dh_param) + { + DhFree(dh_param); + } + + dh_param = dh; + }