diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h index fb006e31..1352bcea 100644 --- a/src/Cedar/Cedar.h +++ b/src/Cedar/Cedar.h @@ -448,6 +448,7 @@ #define AUTHTYPE_ROOTCERT 3 // Root certificate which is issued by trusted Certificate Authority #define AUTHTYPE_RADIUS 4 // Radius authentication #define AUTHTYPE_NT 5 // Windows NT authentication +#define AUTHTYPE_OPENVPN_CERT 98 // TLS client certificate authentication #define AUTHTYPE_TICKET 99 // Ticket authentication // Constant of the client side diff --git a/src/Cedar/IPsec_EtherIP.c b/src/Cedar/IPsec_EtherIP.c index 15dde766..41d11630 100644 --- a/src/Cedar/IPsec_EtherIP.c +++ b/src/Cedar/IPsec_EtherIP.c @@ -170,7 +170,7 @@ void EtherIPIpcConnectThread(THREAD *t, void *p) &s->ClientIP, s->ClientPort, &s->ServerIP, s->ServerPort, tmp, - s->CryptName, true, mss, NULL); + s->CryptName, true, mss, NULL, NULL); if (ipc != NULL) { diff --git a/src/Cedar/IPsec_IPC.c b/src/Cedar/IPsec_IPC.c index 7bd5d7e5..be6b7d41 100644 --- a/src/Cedar/IPsec_IPC.c +++ b/src/Cedar/IPsec_IPC.c @@ -323,7 +323,7 @@ IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code) param->UserName, param->Password, error_code, ¶m->ClientIp, param->ClientPort, ¶m->ServerIp, param->ServerPort, param->ClientHostname, param->CryptName, - param->BridgeMode, param->Mss, NULL); + param->BridgeMode, param->Mss, NULL, param->ClientCertificate); return ipc; } @@ -332,7 +332,7 @@ IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code) IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password, UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *client_hostname, char *crypt_name, - bool bridge_mode, UINT mss, EAP_CLIENT *eap_client) + bool bridge_mode, UINT mss, EAP_CLIENT *eap_client, X *client_certificate) { IPC *ipc; UINT dummy_int = 0; @@ -425,7 +425,14 @@ IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char FreePack(p); // Upload the authentication data - p = PackLoginWithPlainPassword(hubname, username, password); + if (client_certificate != NULL) + { + p = PackLoginWithOpenVPNCertificate(hubname, username, client_certificate); + } + else + { + p = PackLoginWithPlainPassword(hubname, username, password); + } PackAddStr(p, "hello", client_name); PackAddInt(p, "client_ver", cedar->Version); PackAddInt(p, "client_build", cedar->Build); diff --git a/src/Cedar/IPsec_IPC.h b/src/Cedar/IPsec_IPC.h index f65a053e..718e7c1e 100644 --- a/src/Cedar/IPsec_IPC.h +++ b/src/Cedar/IPsec_IPC.h @@ -165,6 +165,7 @@ struct IPC_PARAM UINT Mss; bool IsL3Mode; bool IsOpenVPN; + X *ClientCertificate; }; // IPC_ASYNC object @@ -224,7 +225,7 @@ struct IPC_MSCHAP_V2_AUTHINFO IPC *NewIPC(CEDAR *cedar, char *client_name, char *postfix, char *hubname, char *username, char *password, UINT *error_code, IP *client_ip, UINT client_port, IP *server_ip, UINT server_port, char *client_hostname, char *crypt_name, - bool bridge_mode, UINT mss, EAP_CLIENT *eap_client); + bool bridge_mode, UINT mss, EAP_CLIENT *eap_client, X *client_certificate); IPC *NewIPCByParam(CEDAR *cedar, IPC_PARAM *param, UINT *error_code); IPC *NewIPCBySock(CEDAR *cedar, SOCK *s, void *mac_address); void FreeIPC(IPC *ipc); diff --git a/src/Cedar/IPsec_PPP.c b/src/Cedar/IPsec_PPP.c index d2b7cb18..6c5a4e9e 100644 --- a/src/Cedar/IPsec_PPP.c +++ b/src/Cedar/IPsec_PPP.c @@ -1018,7 +1018,7 @@ PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req) // Attempt to connect with IPC ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password, &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort, - p->ClientHostname, p->CryptName, false, p->AdjustMss, p->EapClient); + p->ClientHostname, p->CryptName, false, p->AdjustMss, p->EapClient, NULL); if (ipc != NULL) { @@ -1151,7 +1151,7 @@ PPP_PACKET *PPPProcessRequestPacket(PPP_SESSION *p, PPP_PACKET *req) ipc = NewIPC(p->Cedar, p->ClientSoftwareName, p->Postfix, hub, id, password, &error_code, &p->ClientIP, p->ClientPort, &p->ServerIP, p->ServerPort, - p->ClientHostname, p->CryptName, false, p->AdjustMss, NULL); + p->ClientHostname, p->CryptName, false, p->AdjustMss, NULL, NULL); if (ipc != NULL) { diff --git a/src/Cedar/Interop_OpenVPN.c b/src/Cedar/Interop_OpenVPN.c index 5d3f379d..3b344c97 100644 --- a/src/Cedar/Interop_OpenVPN.c +++ b/src/Cedar/Interop_OpenVPN.c @@ -442,7 +442,8 @@ void OvsProcessRecvControlPacket(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN // Create an SSL pipe Lock(s->Cedar->lock); { - c->SslPipe = NewSslPipe(true, s->Cedar->ServerX, s->Cedar->ServerK, s->Dh); + bool cert_verify = true; + c->SslPipe = NewSslPipeEx(true, s->Cedar->ServerX, s->Cedar->ServerK, s->Dh, cert_verify, &c->ClientCert); } Unlock(s->Cedar->lock); @@ -712,6 +713,11 @@ void OvsBeginIPCAsyncConnectionIfEmpty(OPENVPN_SERVER *s, OPENVPN_SESSION *se, O p.BridgeMode = true; } + if (c->ClientCert.X != NULL) + { + p.ClientCertificate = c->ClientCert.X; + } + p.IsOpenVPN = true; // Calculate the MSS @@ -780,6 +786,26 @@ void OvsSetupSessionParameters(OPENVPN_SERVER *s, OPENVPN_SESSION *se, OPENVPN_C OvsLog(s, se, c, "LO_OPTION_STR_RECV", data->OptionString); + if (c->ClientCert.X != NULL) + { + if (c->ClientCert.X->subject_name != NULL) + { + OvsLog(s, se, c, "LO_CLIENT_CERT", c->ClientCert.X->subject_name->CommonName); + } + else + { + OvsLog(s, se, c, "LO_CLIENT_CERT", "(unknown CN)"); + } + } + else if (!c->ClientCert.PreverifyErr) + { + OvsLog(s, se, c, "LO_CLIENT_NO_CERT"); + } + else + { + OvsLog(s, se, c, "LO_CLIENT_UNVERIFIED_CERT", c->ClientCert.PreverifyErrMessage); + } + Zero(opt_str, sizeof(opt_str)); StrCpy(opt_str, sizeof(opt_str), data->OptionString); if (s->Cedar != NULL && (IsEmptyStr(opt_str) || StartWith(opt_str, "V0 UNDEF") || InStr(opt_str, ",") == false)) @@ -1359,6 +1385,11 @@ void OvsFreeChannel(OPENVPN_CHANNEL *c) FreeMd(c->MdRecv); FreeMd(c->MdSend); + if (c->ClientCert.X != NULL) + { + FreeX(c->ClientCert.X); + } + Free(c); } diff --git a/src/Cedar/Interop_OpenVPN.h b/src/Cedar/Interop_OpenVPN.h index a7cd6c1a..4157206a 100644 --- a/src/Cedar/Interop_OpenVPN.h +++ b/src/Cedar/Interop_OpenVPN.h @@ -257,6 +257,7 @@ struct OPENVPN_CHANNEL bool IsInitiatorServer; // Whether the channel was started from the server side bool RekeyInitiated; // Whether re-keying has already started UINT64 NextRekey; + struct SslClientCertInfo ClientCert; // Client certificate and verification data }; // OpenVPN session diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c index 501b7eff..5421f897 100644 --- a/src/Cedar/Protocol.c +++ b/src/Cedar/Protocol.c @@ -1795,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); @@ -2128,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); @@ -7247,6 +7294,45 @@ 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; + // Validate arguments + if (hubname == NULL || username == NULL || x == NULL) + { + return NULL; + } + + p = NewPack(); + PackAddStr(p, "method", "login"); + PackAddStr(p, "hubname", hubname); + + char cn_username[128]; + 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); + + BUF *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) { diff --git a/src/Cedar/Protocol.h b/src/Cedar/Protocol.h index 406d3777..9190bc7a 100644 --- a/src/Cedar/Protocol.h +++ b/src/Cedar/Protocol.h @@ -242,6 +242,7 @@ PACK *PackLoginWithAnonymous(char *hubname, char *username); PACK *PackLoginWithPassword(char *hubname, char *username, void *secure_password); PACK *PackLoginWithPlainPassword(char *hubname, char *username, void *plain_password); PACK *PackLoginWithCert(char *hubname, char *username, X *x, void *sign, UINT sign_size); +PACK *PackLoginWithOpenVPNCertificate(char *hubname, char *username, X *x); bool GetMethodFromPack(PACK *p, char *method, UINT size); bool GetHubnameAndUsernameFromPack(PACK *p, char *username, UINT username_size, char *hubname, UINT hubname_size); diff --git a/src/Mayaqua/Encrypt.c b/src/Mayaqua/Encrypt.c index e9094f6c..015cdfeb 100644 --- a/src/Mayaqua/Encrypt.c +++ b/src/Mayaqua/Encrypt.c @@ -151,6 +151,8 @@ LOCK *openssl_lock = NULL; +int ssl_clientcert_index = 0; + LOCK **ssl_lock_obj = NULL; UINT ssl_lock_num; static bool openssl_inited = false; @@ -4064,6 +4066,8 @@ void InitCryptLibrary() ERR_load_crypto_strings(); SSL_load_error_strings(); + ssl_clientcert_index = SSL_get_ex_new_index(0, "struct SslClientCertInfo *", NULL, NULL, NULL); + #ifdef OS_UNIX { char *name1 = "/dev/random"; @@ -5289,5 +5293,9 @@ static unsigned char *Internal_SHA0(const unsigned char *d, size_t n, unsigned c } +int GetSslClientCertIndex() +{ + return ssl_clientcert_index; +} diff --git a/src/Mayaqua/Encrypt.h b/src/Mayaqua/Encrypt.h index 512c7054..428ec9bc 100644 --- a/src/Mayaqua/Encrypt.h +++ b/src/Mayaqua/Encrypt.h @@ -581,6 +581,8 @@ BUF *EasyDecrypt(BUF *src_buf); void DisableIntelAesAccel(); +int GetSslClientCertIndex(); + #ifdef ENCRYPT_C // Inner function diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index 73166847..befe5f7c 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -5809,14 +5809,52 @@ SOCK *ListenAnyPortEx2(bool local_only, bool disable_ca) return NULL; } -int cb_test(int a, X509_STORE_CTX *ctx) +// 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; + + 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 = 0; + clientcert->PreverifyErrMessage[0] = '\0'; + if (!preverify_ok) + { + clientcert->PreverifyErr = X509_STORE_CTX_get_error(ctx); + 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 + { + if (ctx->cert != NULL) + { + X *tmpX = X509ToX(ctx->cert); // this only wraps ctx->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; @@ -5841,7 +5879,10 @@ SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh) 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) { @@ -5854,6 +5895,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); diff --git a/src/Mayaqua/Network.h b/src/Mayaqua/Network.h index 21b67ba7..ccec80b1 100644 --- a/src/Mayaqua/Network.h +++ b/src/Mayaqua/Network.h @@ -1615,7 +1615,16 @@ void Win32WaitForTubes(TUBE **tubes, UINT num, UINT timeout); void UnixWaitForTubes(TUBE **tubes, UINT num, UINT timeout); #endif // OS_WIN32 +#define PREVERIFY_ERR_MESSAGE_SIZE 100 +// Info on client certificate collected during TLS handshake +struct SslClientCertInfo { + int PreverifyErr; + char PreverifyErrMessage[PREVERIFY_ERR_MESSAGE_SIZE]; + X *X; +}; + SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh); +SSL_PIPE *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert); void FreeSslPipe(SSL_PIPE *s); bool SyncSslPipe(SSL_PIPE *s); diff --git a/src/bin/hamcore/strtable_cn.stb b/src/bin/hamcore/strtable_cn.stb index 23aa0e03..df8212b3 100644 --- a/src/bin/hamcore/strtable_cn.stb +++ b/src/bin/hamcore/strtable_cn.stb @@ -1810,6 +1810,9 @@ LO_PREFIX_CHANNEL OpenVPN 会话%u (%r:%u -> %r:%u) 通道 %u: LO_NEW_CHANNEL 已创创建一个新通道。 LO_CHANNEL_ESTABLISHED_NEWKEY 通道已建立。(触发器: Re-key完成。) LO_OPTION_STR_RECV 接收到的选项字符串:"%S" +LO_CLIENT_CERT Client certificate received (subject: CN="%s"), will use certificate authentication. +LO_CLIENT_UNVERIFIED_CERT Client certificate was provided but did not pass verification (error="%S"), will use password authentication. +LO_CLIENT_NO_CERT Client certificate is not provided, will use password authentication. LO_OPTION_STR_SEND 发送选项字符串:"%S" LO_NEW_SESSION 已创建新的会话。协议:%S LO_INITIATE_REKEY re-keying 进程已开始。 @@ -1906,6 +1909,7 @@ LH_AUTH_PASSWORD 密码验证 LH_AUTH_PLAIN_PASSWORD 外部服务器身份验证 LH_AUTH_CERT 证书验证 LH_AUTH_TICKET 票证验证 +LH_AUTH_OPENVPN_CERT OpenVPN certificate authentication LH_AUTH_RADIUS_NOT_SUPPORT 连接 "%S": 用户 "%S" 身份验证方法 RADIUS 或 Active Directory (NT 域),但 VPN Server 是 "%S",因为 RADIUS 或 Active Directory (NT 域)不能使用。连接被拒绝。 LH_AUTH_RADIUS_NOT_SUPPORT_ON_OPEN_SOURCE "%S" 的连接方法: 用户 "%S" 的身份验证方法被指定为 RADIUS 身份验证或 Active Directory 身份验证 (NT 域验证)。然而,这样一个外部用户身份验证功能尚未在 SoftEther VPN 的开源版本上实施。该连接将被拒绝。 LH_AUTH_CERT_NOT_SUPPORT_ON_OPEN_SOURCE "%S" 的连接方法: 用户 "%S" 的身份验证方法被指定为证书认证。然而,证书验证功能尚未在 SoftEther VPN 的开源版本上实施。该连接将被拒绝。 diff --git a/src/bin/hamcore/strtable_en.stb b/src/bin/hamcore/strtable_en.stb index 3b534ed3..d83c5dce 100644 --- a/src/bin/hamcore/strtable_en.stb +++ b/src/bin/hamcore/strtable_en.stb @@ -1792,6 +1792,9 @@ LO_PREFIX_CHANNEL OpenVPN Session %u (%r:%u -> %r:%u) Channel %u: LO_NEW_CHANNEL A new channel is created. LO_CHANNEL_ESTABLISHED_NEWKEY The channel is established. (Trigger: Re-key completion.) LO_OPTION_STR_RECV Option Strings Received: "%S" +LO_CLIENT_CERT Client certificate received (subject: CN="%s"), will use certificate authentication. +LO_CLIENT_UNVERIFIED_CERT Client certificate was provided but did not pass verification (error="%S"), will use password authentication. +LO_CLIENT_NO_CERT Client certificate is not provided, will use password authentication. LO_OPTION_STR_SEND Option Strings to Send: "%S" LO_NEW_SESSION A new session is created. Protocol: %S LO_INITIATE_REKEY The re-keying process is started. @@ -1888,6 +1891,7 @@ LH_AUTH_PASSWORD Password authentication LH_AUTH_PLAIN_PASSWORD External server authentication LH_AUTH_CERT Certificate authentication LH_AUTH_TICKET Ticket authentication +LH_AUTH_OPENVPN_CERT OpenVPN certificate authentication LH_AUTH_RADIUS_NOT_SUPPORT Connection "%S": The authentication method of the user "%S" has been specified as RADIUS Authentication or Active Directory Authentication (NT Domain Authentication). However, the edition of the VPN Server is "%S". This edition does not support RADIUS Authentication nor Active Directory Authentication (NT Domain Authentication). The connection will be denied. LH_AUTH_RADIUS_NOT_SUPPORT_ON_OPEN_SOURCE Connection "%S": The authentication method of the user "%S" has been specified as RADIUS Authentication or Active Directory Authentication (NT Domain Authentication). However, such an external user-authentication function hasn't been implemented on the Open-Source version of SoftEther VPN yet. The connection will be denied. LH_AUTH_CERT_NOT_SUPPORT_ON_OPEN_SOURCE Connection "%S": The authentication method of the user "%S" has been specified as Certificate Authentication. However, the Certificate Authentication function hasn't been implemented on the Open-Source version of SoftEther VPN yet. The connection will be denied. @@ -7164,5 +7168,3 @@ SW_LINK_NAME_LANGUAGE_COMMENT Change the display language setting of %s. SW_LINK_NAME_DEBUG Debugging Information Collecting Tool SW_LINK_NAME_DEBUG_COMMENT Collects debugging information of SoftEther VPN. Use this tool only if your support staff asks you to do so. - - diff --git a/src/bin/hamcore/strtable_ja.stb b/src/bin/hamcore/strtable_ja.stb index ce3b7868..3875aaa0 100644 --- a/src/bin/hamcore/strtable_ja.stb +++ b/src/bin/hamcore/strtable_ja.stb @@ -1796,6 +1796,9 @@ LO_PREFIX_CHANNEL OpenVPN セッション %u (%r:%u -> %r:%u) チャネル %u: LO_NEW_CHANNEL 新しいチャネルを作成しました。 LO_CHANNEL_ESTABLISHED_NEWKEY チャネルが確立状態になりました (原因: リキーの完了)。 LO_OPTION_STR_RECV 受信したオプション文字列: "%S" +LO_CLIENT_CERT Client certificate received (subject: CN="%s"), will use certificate authentication. +LO_CLIENT_UNVERIFIED_CERT Client certificate was provided but did not pass verification (error="%S"), will use password authentication. +LO_CLIENT_NO_CERT Client certificate is not provided, will use password authentication. LO_OPTION_STR_SEND 送信するオプション文字列: "%S" LO_NEW_SESSION 新しいセッションを作成しました。プロトコル: %S LO_INITIATE_REKEY このチャネルのリキーを開始します。 @@ -1892,6 +1895,7 @@ LH_AUTH_PASSWORD パスワード認証 LH_AUTH_PLAIN_PASSWORD 外部サーバー認証 LH_AUTH_CERT 証明書認証 LH_AUTH_TICKET チケット認証 +LH_AUTH_OPENVPN_CERT OpenVPN certificate authentication LH_AUTH_RADIUS_NOT_SUPPORT コネクション "%S": ユーザー "%S" の認証方法として RADIUS 認証または Active Directory 認証 (NT ドメイン認証) が指定されましたが、現在の VPN Server のエディションは "%S" であるため、RADIUS 認証または Active Directory 認証 (NT ドメイン認証) を使用することができません。接続は拒否されます。 LH_AUTH_RADIUS_NOT_SUPPORT_ON_OPEN_SOURCE コネクション "%S": ユーザー "%S" の認証方法として RADIUS 認証または Active Directory 認証 (NT ドメイン認証) が指定されましたが、RADIUS 認証または Active Directory 認証 (NT ドメイン認証) を使用することができません。この機能はオープンソース版 SoftEther VPN にはまだ実装されていません。接続は拒否されます。 LH_AUTH_CERT_NOT_SUPPORT_ON_OPEN_SOURCE コネクション "%S": ユーザー "%S" の認証方法として証明書認証が指定されましたが、証明書認証を使用することができません。この機能はオープンソース版 SoftEther VPN にはまだ実装されていません。接続は拒否されます。 diff --git a/src/bin/hamcore/strtable_tw.stb b/src/bin/hamcore/strtable_tw.stb index 2d7453e5..3ea1364b 100644 --- a/src/bin/hamcore/strtable_tw.stb +++ b/src/bin/hamcore/strtable_tw.stb @@ -1812,6 +1812,9 @@ LO_PREFIX_CHANNEL OpenVPN 會話%u (%r:%u -> %r:%u) 通道 %u: LO_NEW_CHANNEL 已創建一個新通道。 LO_CHANNEL_ESTABLISHED_NEWKEY 通道已建立。(觸發器: Re-key完成。) LO_OPTION_STR_RECV 接收到的選項字串:"%S" +LO_CLIENT_CERT Client certificate received (subject: CN="%s"), will use certificate authentication. +LO_CLIENT_UNVERIFIED_CERT Client certificate was provided but did not pass verification (error="%S"), will use password authentication. +LO_CLIENT_NO_CERT Client certificate is not provided, will use password authentication. LO_OPTION_STR_SEND 發送選項字串:"%S" LO_NEW_SESSION 已創建新的會話。協議:%S LO_INITIATE_REKEY re-keying 進程已開始。 @@ -1908,6 +1911,7 @@ LH_AUTH_PASSWORD 密碼驗證 LH_AUTH_PLAIN_PASSWORD 外部伺服器身份驗證 LH_AUTH_CERT 證書驗證 LH_AUTH_TICKET 票證驗證 +LH_AUTH_OPENVPN_CERT OpenVPN certificate authentication LH_AUTH_RADIUS_NOT_SUPPORT 連接 "%S": 用戶 "%S" 身份驗證方法 RADIUS 或 Active Directory (NT 域),但 VPN Server 是 "%S",因為 RADIUS 或 Active Directory (NT 域)不能使用。連接被拒絕。 LH_AUTH_RADIUS_NOT_SUPPORT_ON_OPEN_SOURCE "%S" 的連接方法: 用戶 "%S" 的身份驗證方法被指定為 RADIUS 身份驗證或 Active Directory 身份驗證 (NT 域驗證)。然而,這樣一個外部用戶身份驗證功能尚未在 SoftEther VPN 的開源版本上實施。該連接將被拒絕。 LH_AUTH_CERT_NOT_SUPPORT_ON_OPEN_SOURCE "%S" 的連接方法: 用戶 "%S" 的身份驗證方法被指定為證書認證。然而,證書驗證功能尚未在 SoftEther VPN 的開源版本上實施。該連接將被拒絕。