diff --git a/src/Cedar/Admin.c b/src/Cedar/Admin.c index f621c5c4..c4f7d7d4 100644 --- a/src/Cedar/Admin.c +++ b/src/Cedar/Admin.c @@ -1587,6 +1587,7 @@ PACK *AdminDispatch(RPC *rpc, char *name, PACK *p) DECLARE_RPC_EX("EnumFarmMember", RPC_ENUM_FARM, StEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm) DECLARE_RPC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, StGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus) DECLARE_RPC_EX("SetServerCert", RPC_KEY_PAIR, StSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair) + DECLARE_RPC_EX("SetServerOpensslEngineCert", RPC_OPENSSL_ENGINE_KEY_PAIR, StSetServerOpensslEngineCert, InRpcOpensslEngineKeyPair, OutRpcOpensslEngineKeyPair, FreeRpcOpensslEngineKeyPair) DECLARE_RPC_EX("GetServerCert", RPC_KEY_PAIR, StGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair) DECLARE_RPC_EX("GetServerCipher", RPC_STR, StGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr) DECLARE_RPC_EX("SetServerCipher", RPC_STR, StSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr) @@ -1766,6 +1767,7 @@ DECLARE_SC_EX("GetFarmInfo", RPC_FARM_INFO, ScGetFarmInfo, InRpcFarmInfo, OutRpc DECLARE_SC_EX("EnumFarmMember", RPC_ENUM_FARM, ScEnumFarmMember, InRpcEnumFarm, OutRpcEnumFarm, FreeRpcEnumFarm) DECLARE_SC("GetFarmConnectionStatus", RPC_FARM_CONNECTION_STATUS, ScGetFarmConnectionStatus, InRpcFarmConnectionStatus, OutRpcFarmConnectionStatus) DECLARE_SC_EX("SetServerCert", RPC_KEY_PAIR, ScSetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair) +DECLARE_SC_EX("SetServerOpensslEngineCert", RPC_OPENSSL_ENGINE_KEY_PAIR, ScSetServerOpensslEngineCert, InRpcOpensslEngineKeyPair, OutRpcOpensslEngineKeyPair, FreeRpcOpensslEngineKeyPair) DECLARE_SC_EX("GetServerCert", RPC_KEY_PAIR, ScGetServerCert, InRpcKeyPair, OutRpcKeyPair, FreeRpcKeyPair) DECLARE_SC_EX("GetServerCipher", RPC_STR, ScGetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr) DECLARE_SC_EX("SetServerCipher", RPC_STR, ScSetServerCipher, InRpcStr, OutRpcStr, FreeRpcStr) @@ -2253,7 +2255,7 @@ UINT StMakeOpenVpnConfigFile(ADMIN *a, RPC_READ_LOG_FILE *t) { Lock(c->lock); { - x = CloneX(c->ServerX); + x = CloneK(c->ServerX); } Unlock(c->lock); @@ -9434,7 +9436,11 @@ UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t) t->Cert = CloneX(c->ServerX); if (admin && is_vgs_cert == false) { - t->Key = CloneK(c->ServerK); + if (StrCmp(c->ServerKeyType, "engine") == 0) { + t->Key = OpensslEngineToK(c->ServerEngineKey, c->ServerEngineName); + } else { + t->Key = CloneK(c->ServerK); + } } } Unlock(c->lock); @@ -9482,6 +9488,37 @@ UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t) return ERR_NO_ERROR; } +// Set the server certification +UINT StSetServerOpensslEngineCert(ADMIN *a, RPC_OPENSSL_ENGINE_KEY_PAIR *t) +{ + SERVER *s = a->Server; + CEDAR *c = s->Cedar; + + SERVER_ADMIN_ONLY; + + if (t->Cert == NULL) + { + return ERR_PROTOCOL_ERROR; + } + + t->Flag1 = 1; + if (t->Cert->root_cert == false) + { + if (DownloadAndSaveIntermediateCertificatesIfNecessary(t->Cert) == false) + { + t->Flag1 = 0; + } + } + K *k = OpensslEngineToK(t->KeyName, t->EngineName); + + SetCedarEngineCert(c, t->Cert, k, t->EngineName, t->KeyName); + + ALog(a, NULL, "LA_SET_SERVER_CERT"); + + IncrementServerConfigRevision(s); + + return ERR_NO_ERROR; +} // Get status of connection to cluster controller UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t) @@ -14058,6 +14095,35 @@ void FreeRpcKeyPair(RPC_KEY_PAIR *t) FreeX(t->Cert); FreeK(t->Key); } +// RPC_KEY_PAIR +void InRpcOpensslEngineKeyPair(RPC_OPENSSL_ENGINE_KEY_PAIR *t, PACK *p) +{ + // Validate arguments + if (t == NULL || p == NULL) + { + return; + } + t->Cert = PackGetX(p, "Cert"); + PackGetStr(p, "Key", t->KeyName, sizeof(t->KeyName)); + PackGetStr(p, "EngineName", t->EngineName, sizeof(t->EngineName)); + t->Flag1 = PackGetInt(p, "Flag1"); +} +void OutRpcOpensslEngineKeyPair(PACK *p, RPC_OPENSSL_ENGINE_KEY_PAIR *t) +{ + // Validate arguments + if (p == NULL || t == NULL) + { + return; + } + PackAddX(p, "Cert", t->Cert); + PackAddStr(p, "Key", t->KeyName); + PackAddStr(p, "EngineName", t->EngineName); + PackAddInt(p, "Flag1", t->Flag1); +} +void FreeRpcOpensslEngineKeyPair(RPC_OPENSSL_ENGINE_KEY_PAIR *t) +{ + FreeX(t->Cert); +} // NODE_INFO void InRpcNodeInfo(NODE_INFO *t, PACK *p) diff --git a/src/Cedar/Admin.h b/src/Cedar/Admin.h index 59a9f2cf..8e8048c3 100644 --- a/src/Cedar/Admin.h +++ b/src/Cedar/Admin.h @@ -307,6 +307,14 @@ struct RPC_KEY_PAIR K *Key; // Secret key UINT Flag1; // Flag1 }; +// Key pair +struct RPC_OPENSSL_ENGINE_KEY_PAIR +{ + X *Cert; // Certificate + char KeyName[MAX_SIZE]; // key + char EngineName[MAX_SIZE]; // engine name + UINT Flag1; // Flag1 +}; // HUB option struct RPC_HUB_OPTION @@ -1063,6 +1071,7 @@ UINT StGetFarmInfo(ADMIN *a, RPC_FARM_INFO *t); UINT StEnumFarmMember(ADMIN *a, RPC_ENUM_FARM *t); UINT StGetFarmConnectionStatus(ADMIN *a, RPC_FARM_CONNECTION_STATUS *t); UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t); +UINT StSetServerOpensslEngineCert(ADMIN *a, RPC_OPENSSL_ENGINE_KEY_PAIR *t); UINT StGetServerCert(ADMIN *a, RPC_KEY_PAIR *t); UINT StGetServerCipher(ADMIN *a, RPC_STR *t); UINT StSetServerCipher(ADMIN *a, RPC_STR *t); @@ -1206,6 +1215,7 @@ UINT ScGetFarmInfo(RPC *r, RPC_FARM_INFO *t); UINT ScEnumFarmMember(RPC *r, RPC_ENUM_FARM *t); UINT ScGetFarmConnectionStatus(RPC *r, RPC_FARM_CONNECTION_STATUS *t); UINT ScSetServerCert(RPC *r, RPC_KEY_PAIR *t); +UINT ScSetServerOpensslEngineCert(RPC *r, RPC_OPENSSL_ENGINE_KEY_PAIR *t); UINT ScGetServerCert(RPC *r, RPC_KEY_PAIR *t); UINT ScGetServerCipher(RPC *r, RPC_STR *t); UINT ScSetServerCipher(RPC *r, RPC_STR *t); @@ -1460,6 +1470,9 @@ void OutRpcMemInfo(PACK *p, MEMINFO *t); void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p); void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t); void FreeRpcKeyPair(RPC_KEY_PAIR *t); +void InRpcOpensslEngineKeyPair(RPC_OPENSSL_ENGINE_KEY_PAIR *t, PACK *p); +void OutRpcOpensslEngineKeyPair(PACK *p, RPC_OPENSSL_ENGINE_KEY_PAIR *t); +void FreeRpcOpensslEngineKeyPair(RPC_OPENSSL_ENGINE_KEY_PAIR *t); void InRpcAddAccess(RPC_ADD_ACCESS *t, PACK *p); void OutRpcAddAccess(PACK *p, RPC_ADD_ACCESS *t); void InRpcDeleteAccess(RPC_DELETE_ACCESS *t, PACK *p); diff --git a/src/Cedar/Cedar.c b/src/Cedar/Cedar.c index 048c7998..3c5fdbcd 100644 --- a/src/Cedar/Cedar.c +++ b/src/Cedar/Cedar.c @@ -1627,6 +1627,37 @@ void SetCedarCert(CEDAR *c, X *server_x, K *server_k) } Unlock(c->lock); } +// Change certificate of Cedar +void SetCedarEngineCert(CEDAR *c, X *server_x, K *server_k, char *engine_name, char *key_name) +{ + // Validate arguments + if (server_x == NULL || server_k == NULL) + { + return; + } + + Lock(c->lock); + { + if (c->ServerX != NULL) + { + FreeX(c->ServerX); + } + + if (c->ServerK != NULL) + { + FreeK(c->ServerK); + } + + c->ServerX = CloneX(server_x); + c->ServerK = OpensslEngineToK(key_name, engine_name); + c->ServerEngineName = CopyStr(engine_name); + c->ServerEngineKey = CopyStr(key_name); + + c->ServerKeyType = CopyStr("engine"); + } + Unlock(c->lock); +} + // Enable debug log void EnableDebugLog(CEDAR *c) diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h index 1add063b..af5d1c4b 100644 --- a/src/Cedar/Cedar.h +++ b/src/Cedar/Cedar.h @@ -444,6 +444,7 @@ #define CLIENT_AUTHTYPE_PLAIN_PASSWORD 2 // Plain password authentication #define CLIENT_AUTHTYPE_CERT 3 // Certificate authentication #define CLIENT_AUTHTYPE_SECURE 4 // Secure device authentication +#define CLIENT_AUTHTYPE_OPENSSLENGINE 5 // Openssl engine authentication @@ -992,6 +993,10 @@ typedef struct CEDAR COUNTER *ConnectionIncrement; // Connection increment counter X *ServerX; // Server certificate K *ServerK; // Private key of the server certificate + char *ServerKeyType; + char *ServerEngineName; + char *ServerEngineKey; + char UsernameHubSeparator; // Character which separates the username from the hub name char *CipherList; // List of encryption algorithms UINT Version; // Version information UINT Build; // Build Number @@ -1189,6 +1194,7 @@ CEDAR *NewCedar(X *server_x, K *server_k); void CedarForceLink(); void SetCedarVpnBridge(CEDAR *c); void SetCedarCert(CEDAR *c, X *server_x, K *server_k); +void SetCedarEngineCert(CEDAR *c, X *server_x, K *server_k, char *engine_name, char *key_name); void ReleaseCedar(CEDAR *c); void CleanupCedar(CEDAR *c); void StopCedar(CEDAR *c); diff --git a/src/Cedar/CedarType.h b/src/Cedar/CedarType.h index 61406b35..f83fe6c1 100644 --- a/src/Cedar/CedarType.h +++ b/src/Cedar/CedarType.h @@ -396,6 +396,7 @@ typedef struct RPC_ENUM_FARM_ITEM RPC_ENUM_FARM_ITEM; typedef struct RPC_ENUM_FARM RPC_ENUM_FARM; typedef struct RPC_FARM_CONNECTION_STATUS RPC_FARM_CONNECTION_STATUS; typedef struct RPC_KEY_PAIR RPC_KEY_PAIR; +typedef struct RPC_OPENSSL_ENGINE_KEY_PAIR RPC_OPENSSL_ENGINE_KEY_PAIR; typedef struct RPC_HUB_OPTION RPC_HUB_OPTION; typedef struct RPC_RADIUS RPC_RADIUS; typedef struct RPC_HUB RPC_HUB; diff --git a/src/Cedar/Client.c b/src/Cedar/Client.c index 3c7c4ca0..d0d22d26 100644 --- a/src/Cedar/Client.c +++ b/src/Cedar/Client.c @@ -100,7 +100,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Client.c // Client Manager @@ -4727,6 +4726,17 @@ void InRpcClientAuth(CLIENT_AUTH *c, PACK *p) PackGetStr(p, "SecurePublicCertName", c->SecurePublicCertName, sizeof(c->SecurePublicCertName)); PackGetStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName, sizeof(c->SecurePrivateKeyName)); break; + + case CLIENT_AUTHTYPE_OPENSSLENGINE: + b = PackGetBuf(p, "ClientX"); + if (b != NULL) + { + c->ClientX = BufToX(b, false); + FreeBuf(b); + } + PackGetStr(p, "OpensslEnginePrivateKeyName", c->OpensslEnginePrivateKeyName, sizeof(c->OpensslEnginePrivateKeyName)); + PackGetStr(p, "OpensslEngineName", c->OpensslEngineName, sizeof(c->OpensslEngineName)); + break; } } void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c) @@ -4773,6 +4783,17 @@ void OutRpcClientAuth(PACK *p, CLIENT_AUTH *c) PackAddStr(p, "SecurePublicCertName", c->SecurePublicCertName); PackAddStr(p, "SecurePrivateKeyName", c->SecurePrivateKeyName); break; + + case CLIENT_AUTHTYPE_OPENSSLENGINE: + b = XToBuf(c->ClientX, false); + if (b != NULL) + { + PackAddBuf(p, "ClientX", b); + FreeBuf(b); + } + PackAddStr(p, "OpensslEnginePrivateKeyName", c->OpensslEnginePrivateKeyName); + PackAddStr(p, "OpensslEngineName", c->OpensslEngineName); + break; } } @@ -6769,6 +6790,10 @@ bool CtConnect(CLIENT *c, RPC_CLIENT_CONNECT *connect) // Register a procedure for secure device authentication r->ClientAuth->SecureSignProc = CiSecureSignProc; } + else if (r->ClientAuth->AuthType == CLIENT_AUTHTYPE_OPENSSLENGINE) + { + r->ClientAuth->SecureSignProc = NULL; + } else { r->ClientAuth->SecureSignProc = NULL; @@ -9575,6 +9600,20 @@ CLIENT_AUTH *CiLoadClientAuth(FOLDER *f) CfgGetStr(f, "SecurePublicCertName", a->SecurePublicCertName, sizeof(a->SecurePublicCertName)); CfgGetStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName, sizeof(a->SecurePrivateKeyName)); break; + + case CLIENT_AUTHTYPE_OPENSSLENGINE: + b = CfgGetBuf(f, "ClientCert"); + if (b != NULL) + { + a->ClientX = BufToX(b, false); + } + FreeBuf(b); + if (CfgGetStr(f, "OpensslEnginePrivateKeyName", a->OpensslEnginePrivateKeyName, sizeof(a->OpensslEnginePrivateKeyName))) + { + a->ClientK = OpensslEngineToK(a->OpensslEnginePrivateKeyName, a->OpensslEngineName); + } + CfgGetStr(f, "OpensslEngineName", a->OpensslEngineName, sizeof(a->OpensslEngineName)); + break; } return a; @@ -10118,6 +10157,16 @@ void CiWriteClientAuth(FOLDER *f, CLIENT_AUTH *a) CfgAddStr(f, "SecurePublicCertName", a->SecurePublicCertName); CfgAddStr(f, "SecurePrivateKeyName", a->SecurePrivateKeyName); break; + + case CLIENT_AUTHTYPE_OPENSSLENGINE: + if (a->ClientX != NULL) { + b = XToBuf(a->ClientX, false); + CfgAddByte(f, "ClientCert", b->Buf, b->Size); + FreeBuf(b); + } + CfgAddStr(f, "OpensslEnginePrivateKeyName", a->OpensslEnginePrivateKeyName); + CfgAddStr(f, "OpensslEngineName", a->OpensslEngineName); + break; } } diff --git a/src/Cedar/Client.h b/src/Cedar/Client.h index 232bc473..68ee0eeb 100644 --- a/src/Cedar/Client.h +++ b/src/Cedar/Client.h @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Client.h // Header of Client.c diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c index c22a9825..f965e549 100644 --- a/src/Cedar/Command.c +++ b/src/Cedar/Command.c @@ -1,24 +1,5 @@ // SoftEther VPN Source Code - Stable Edition Repository // Cedar Communication Module -// -// SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0. -// -// Copyright (c) Daiyuu Nobori. -// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. -// Copyright (c) SoftEther Corporation. -// Copyright (c) all contributors on SoftEther VPN project in GitHub. -// -// All Rights Reserved. -// -// http://www.softether.org/ -// -// This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project. -// Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN -// -// License: The Apache License, Version 2.0 -// https://www.apache.org/licenses/LICENSE-2.0 -// -// DISCLAIMER // ========== // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -98,7 +79,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Command.c // vpncmd Command Line Management Utility @@ -3114,6 +3094,7 @@ void PcMain(PC *pc) {"AccountStatusShow", PcAccountStatusShow}, {"AccountStatusHide", PcAccountStatusHide}, {"AccountSecureCertSet", PcAccountSecureCertSet}, + {"AccountOpensslEngineCertSet", PcAccountOpensslEngineCertSet}, {"AccountRetrySet", PcAccountRetrySet}, {"AccountStartupSet", PcAccountStartupSet}, {"AccountStartupRemove", PcAccountStartupRemove}, @@ -4870,7 +4851,7 @@ UINT PcAccountCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) if (ret == ERR_NO_ERROR) { - if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT) + if (t.ClientAuth->AuthType != CLIENT_AUTHTYPE_CERT && t.ClientAuth->AuthType != CLIENT_AUTHTYPE_OPENSSLENGINE) { c->Write(c, _UU("CMD_CascadeCertSet_Not_Auth_Cert")); ret = ERR_INTERNAL_ERROR; @@ -6143,6 +6124,76 @@ UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *para return ret; } +UINT PcAccountOpensslEngineCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) +{ + LIST *o; + PC *pc = (PC *)param; + UINT ret = ERR_NO_ERROR; + RPC_CLIENT_GET_ACCOUNT t; + // Parameter list that can be specified + PARAM args[] = + { + {"[name]", CmdPrompt, _UU("CMD_AccountCreate_Prompt_Name"), CmdEvalNotEmpty, NULL}, + {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL}, + {"KEYNAME", CmdPrompt, _UU("CMD_AccountOpensslCertSet_PROMPT_KEYNAME"), CmdEvalNotEmpty, NULL}, + {"ENGINENAME", CmdPrompt, _UU("CMD_AccountOpensslCertSet_PROMPT_ENGINENAME"), CmdEvalNotEmpty, NULL}, + }; + + // Get the parameter list + o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0])); + if (o == NULL) + { + return ERR_INVALID_PARAMETER; + } + + // RPC call + Zero(&t, sizeof(t)); + + UniStrCpy(t.AccountName, sizeof(t.AccountName), GetParamUniStr(o, "[name]")); + + ret = CcGetAccount(pc->RemoteClient, &t); + + if (ret == ERR_NO_ERROR) + { + RPC_CLIENT_CREATE_ACCOUNT z; + t.ClientAuth->AuthType = CLIENT_AUTHTYPE_OPENSSLENGINE; + X *x; + x = FileToXW(GetParamUniStr(o, "LOADCERT")); + if (x == NULL) + { + c->Write(c, _UU("CMD_LOADCERT_FAILED")); + } + StrCpy(t.ClientAuth->OpensslEnginePrivateKeyName, sizeof(t.ClientAuth->OpensslEnginePrivateKeyName), + GetParamStr(o, "KEYNAME")); + StrCpy(t.ClientAuth->OpensslEngineName, sizeof(t.ClientAuth->OpensslEngineName), + GetParamStr(o, "ENGINENAME")); + t.ClientAuth->ClientX = CloneX(x); + Zero(&z, sizeof(z)); + z.CheckServerCert = t.CheckServerCert; + z.RetryOnServerCert = t.RetryOnServerCert; + z.ClientAuth = t.ClientAuth; + z.ClientOption = t.ClientOption; + z.ServerCert = t.ServerCert; + z.StartupAccount = t.StartupAccount; + + ret = CcSetAccount(pc->RemoteClient, &z); + } + + if (ret != ERR_NO_ERROR) + { + // Error has occurred + CmdPrintError(c, ret); + } + + CiFreeClientGetAccount(&t); + + // Release of the parameter list + FreeParamValueList(o); + + return ret; +} + + // Set the retry interval and number of retries when disconnect or connection failure of connection settings UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) { @@ -7082,6 +7133,7 @@ void PsMain(PS *ps) {"ServerCertGet", PsServerCertGet}, {"ServerKeyGet", PsServerKeyGet}, {"ServerCertSet", PsServerCertSet}, + {"ServerOpenSslEngineCertSet", PsServerOpensslEngineCertSet}, {"ServerCipherGet", PsServerCipherGet}, {"ServerCipherSet", PsServerCipherSet}, {"KeepEnable", PsKeepEnable}, @@ -8144,6 +8196,21 @@ bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar return true; } +bool CmdLoadOpensslEngineCert(CONSOLE *c, X **xx, wchar_t *cert_filename) +{ + X *x; + + x = FileToXW(cert_filename); + if (x == NULL) + { + c->Write(c, _UU("CMD_LOADCERT_FAILED")); + return false; + } + *xx = x; + return true; +} + + // Read the secret key K *CmdLoadKey(CONSOLE *c, wchar_t *filename) { @@ -8257,6 +8324,69 @@ UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) return ret; } +// Set the SSL certificate and the private key of the VPN Server +UINT PsServerOpensslEngineCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) +{ + LIST *o; + PS *ps = (PS *)param; + UINT ret = 0; + RPC_OPENSSL_ENGINE_KEY_PAIR t; + // Parameter list that can be specified + PARAM args[] = + { + // "name", prompt_proc, prompt_param, eval_proc, eval_param + {"LOADCERT", CmdPrompt, _UU("CMD_LOADCERTPATH"), CmdEvalIsFile, NULL}, + {"KEYNAME", CmdPrompt, _UU("CMD_AccountOpensslCertSet_PROMPT_KEYNAME"), CmdEvalNotEmpty, NULL}, + {"ENGINENAME", CmdPrompt, _UU("CMD_AccountOpensslCertSet_PROMPT_ENGINENAME"), CmdEvalNotEmpty, NULL}, + + }; + + o = ParseCommandList(c, cmd_name, str, args, sizeof(args) / sizeof(args[0])); + if (o == NULL) + { + return ERR_INVALID_PARAMETER; + } + + Zero(&t, sizeof(t)); + + if (CmdLoadOpensslEngineCert(c, &t.Cert, + GetParamUniStr(o, "LOADCERT"))) + { + wchar_t * engine_name = GetParamStr(o, "ENGINENAME"); + StrCpy(t.EngineName, sizeof(t.EngineName), engine_name); + wchar_t * key_name = GetParamStr(o, "KEYNAME"); + StrCpy(t.KeyName, sizeof(t.KeyName), key_name); + // RPC call + ret = ScSetServerOpensslEngineCert(ps->Rpc, &t); + + if (ret != ERR_NO_ERROR) + { + // An error has occured + CmdPrintError(c, ret); + FreeParamValueList(o); + return ret; + } + + if (t.Flag1 == 0) + { + // Show the warning message + c->Write(c, L""); + c->Write(c, _UU("SM_CERT_NEED_ROOT")); + c->Write(c, L""); + } + + FreeRpcOpensslEngineKeyPair(&t); + } + else + { + ret = ERR_INTERNAL_ERROR; + } + + FreeParamValueList(o); + + return ret; +} + // Get the encryption algorithm used for the VPN communication UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param) { diff --git a/src/Cedar/Command.h b/src/Cedar/Command.h index 48d879ef..141e605c 100644 --- a/src/Cedar/Command.h +++ b/src/Cedar/Command.h @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Command.h // Header of Command.c @@ -332,6 +331,7 @@ bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param); wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param); K *CmdLoadKey(CONSOLE *c, wchar_t *filename); bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename); +bool CmdLoadOpensslEngineCert(CONSOLE *c, X **xx, wchar_t *cert_filename); bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param); wchar_t *GetConnectionTypeStr(UINT type); bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param); @@ -466,6 +466,7 @@ UINT PcAccountNicSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PcAccountStatusShow(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PcAccountStatusHide(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PcAccountSecureCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); +UINT PcAccountOpensslEngineCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PcAccountRetrySet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PcAccountStartupSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PcAccountStartupRemove(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); @@ -506,6 +507,7 @@ UINT PsDebug(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PsServerCertGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); +UINT PsServerOpensslEngineCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PsServerCipherGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PsServerCipherSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); UINT PsKeepEnable(CONSOLE *c, char *cmd_name, wchar_t *str, void *param); diff --git a/src/Cedar/Connection.c b/src/Cedar/Connection.c index 6bbf651f..7e3d69af 100644 --- a/src/Cedar/Connection.c +++ b/src/Cedar/Connection.c @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Connection.c // Connection Manager @@ -636,6 +635,14 @@ CLIENT_AUTH *CopyClientAuth(CLIENT_AUTH *a) StrCpy(ret->SecurePublicCertName, sizeof(ret->SecurePublicCertName), a->SecurePublicCertName); StrCpy(ret->SecurePrivateKeyName, sizeof(ret->SecurePrivateKeyName), a->SecurePrivateKeyName); break; + + case CLIENT_AUTHTYPE_OPENSSLENGINE: + // Secure device authentication + ret->ClientX = CloneX(a->ClientX); + StrCpy(ret->OpensslEnginePrivateKeyName, sizeof(ret->OpensslEnginePrivateKeyName), a->OpensslEnginePrivateKeyName); + StrCpy(ret->OpensslEngineName, sizeof(ret->OpensslEngineName), a->OpensslEngineName); + ret->ClientK = OpensslEngineToK(ret->OpensslEnginePrivateKeyName, ret->OpensslEngineName); + break; } return ret; @@ -3139,9 +3146,13 @@ void ConnectionAccept(CONNECTION *c) { SetWantToUseCipher(s, c->Cedar->CipherList); } - x = CloneXFast(c->Cedar->ServerX); + if (StrCmp(c->Cedar->ServerKeyType, "engine") == 0) { + k = OpensslEngineToK(c->Cedar->ServerEngineKey, c->Cedar->ServerEngineName); + } else { k = CloneKFast(c->Cedar->ServerK); + k = CloneK(c->Cedar->ServerK); + } } Unlock(c->Cedar->lock); diff --git a/src/Cedar/Connection.h b/src/Cedar/Connection.h index f1fde638..cdad8300 100644 --- a/src/Cedar/Connection.h +++ b/src/Cedar/Connection.h @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Connection.h // Header of Connection.c @@ -196,6 +195,8 @@ struct CLIENT_AUTH K *ClientK; // Client private key char SecurePublicCertName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device certificate name char SecurePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name + char OpensslEnginePrivateKeyName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name + char OpensslEngineName[MAX_SECURE_DEVICE_FILE_LEN + 1]; // Secure device secret key name CHECK_CERT_PROC *CheckCertProc; // Server certificate confirmation procedure SECURE_SIGN_PROC *SecureSignProc; // Security signing procedure }; diff --git a/src/Cedar/Link.c b/src/Cedar/Link.c index 9690fd4d..ba236f32 100644 --- a/src/Cedar/Link.c +++ b/src/Cedar/Link.c @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Link.c // Inter-HUB Link @@ -719,7 +718,7 @@ LINK *NewLink(CEDAR *cedar, HUB *hub, CLIENT_OPTION *option, CLIENT_AUTH *auth, // Limitation of authentication method if (auth->AuthType != CLIENT_AUTHTYPE_ANONYMOUS && auth->AuthType != CLIENT_AUTHTYPE_PASSWORD && - auth->AuthType != CLIENT_AUTHTYPE_PLAIN_PASSWORD && auth->AuthType != CLIENT_AUTHTYPE_CERT) + auth->AuthType != CLIENT_AUTHTYPE_PLAIN_PASSWORD && auth->AuthType != CLIENT_AUTHTYPE_CERT && auth->AuthType != CLIENT_AUTHTYPE_OPENSSLENGINE) { // Authentication method other than anonymous authentication, password authentication, plain password, certificate authentication cannot be used return NULL; diff --git a/src/Cedar/Protocol.c b/src/Cedar/Protocol.c index fb6867c2..4f53401f 100644 --- a/src/Cedar/Protocol.c +++ b/src/Cedar/Protocol.c @@ -1,24 +1,5 @@ // SoftEther VPN Source Code - Stable Edition Repository // Cedar Communication Module -// -// SoftEther VPN Server, Client and Bridge are free software under the Apache License, Version 2.0. -// -// Copyright (c) Daiyuu Nobori. -// Copyright (c) SoftEther VPN Project, University of Tsukuba, Japan. -// Copyright (c) SoftEther Corporation. -// Copyright (c) all contributors on SoftEther VPN project in GitHub. -// -// All Rights Reserved. -// -// http://www.softether.org/ -// -// This stable branch is officially managed by Daiyuu Nobori, the owner of SoftEther VPN Project. -// Pull requests should be sent to the Developer Edition Master Repository on https://github.com/SoftEtherVPN/SoftEtherVPN -// -// License: The Apache License, Version 2.0 -// https://www.apache.org/licenses/LICENSE-2.0 -// -// DISCLAIMER // ========== // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR @@ -98,7 +79,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Protocol.c // SoftEther protocol related routines @@ -6859,6 +6839,20 @@ bool ClientUploadAuth(CONNECTION *c) } break; + case CLIENT_AUTHTYPE_OPENSSLENGINE: + // Certificate authentication + if (a->ClientX != NULL && a->ClientX->is_compatible_bit && + a->ClientX->bits != 0 && (a->ClientX->bits / 8) <= sizeof(sign)) + { + if (RsaSignEx(sign, c->Random, SHA1_SIZE, a->ClientK, a->ClientX->bits)) + { + p = PackLoginWithCert(o->HubName, a->Username, a->ClientX, sign, a->ClientX->bits / 8); + c->ClientX = CloneX(a->ClientX); + } + } + break; + + case CLIENT_AUTHTYPE_SECURE: // Authentication by secure device if (ClientSecureSign(c, sign, c->Random, &x)) diff --git a/src/Cedar/Server.c b/src/Cedar/Server.c index a7798768..d056f4f7 100644 --- a/src/Cedar/Server.c +++ b/src/Cedar/Server.c @@ -4328,7 +4328,6 @@ void SiWriteUserCfg(FOLDER *f, USER *u) FreeBuf(b); } break; - case AUTHTYPE_ROOTCERT: rootcert = (AUTHROOTCERT *)u->AuthData; if (rootcert->Serial != NULL && rootcert->Serial->size >= 1) @@ -6062,27 +6061,53 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f) } // Server private key - b = CfgGetBuf(f, "ServerKey"); - if (b != NULL) - { - k = BufToK(b, true, false, NULL); - FreeBuf(b); + bool engine_cert; + if (CfgGetStr(f, "ServerKeyType", tmp, sizeof(tmp))) { + if (StrCmp(tmp, "engine") == 0) { + engine_cert = true; + } else { + engine_cert = false; + } + } else { + engine_cert = false; } + if (!engine_cert) { + b = CfgGetBuf(f, "ServerKey"); + if (b != NULL) + { + k = BufToK(b, true, false, NULL); + FreeBuf(b); + if (x == NULL || k == NULL || CheckXandK(x, k) == false) + { + FreeX(x); + FreeK(k); + SiGenerateDefaultCert(&x, &k); - if (x == NULL || k == NULL || CheckXandK(x, k) == false) - { - FreeX(x); - FreeK(k); - SiGenerateDefaultCert(&x, &k); + SetCedarCert(c, x, k); - SetCedarCert(c, x, k); + FreeX(x); + FreeK(k); + } + else + { + SetCedarCert(c, x, k); - FreeX(x); - FreeK(k); - } - else - { - SetCedarCert(c, x, k); + FreeX(x); + FreeK(k); + } + } + } else { + if (CfgGetStr(f, "ServerEngineName", tmp, sizeof(tmp))) { + //TODO error handling + c->ServerEngineName = CopyStr(tmp); + } + if (CfgGetStr(f, "ServerEngineKey", tmp, sizeof(tmp))) { + // TODO error handling + c->ServerEngineKey = CopyStr(tmp); + } + k = OpensslEngineToK(c->ServerEngineKey, c->ServerEngineName); + + SetCedarEngineCert(c, x, k, c->ServerEngineName, c->ServerEngineKey); FreeX(x); FreeK(k); @@ -6459,18 +6484,26 @@ void SiWriteServerCfg(FOLDER *f, SERVER *s) // Let the client not to send a signature CfgAddBool(f, "NoSendSignature", s->NoSendSignature); - if (is_vgs_cert == false) { - // Server certificate - b = XToBuf(c->ServerX, false); - CfgAddBuf(f, "ServerCert", b); - FreeBuf(b); - // Server private key - b = KToBuf(c->ServerK, false, NULL); - CfgAddBuf(f, "ServerKey", b); - FreeBuf(b); + if (StrCmp(c->ServerKeyType, "engine") == 0) { + CfgAddStr(f, "ServerKeyType", "engine"); + CfgAddStr(f, "ServerEngineKey", c->ServerEngineKey); + CfgAddStr(f, "ServerEngineName", c->ServerEngineName); + b = XToBuf(c->ServerX, false); + CfgAddBuf(f, "ServerCert", b); + FreeBuf(b); + } else { + CfgAddStr(f, "ServerKeyType", "x509"); + // Server certificate + b = XToBuf(c->ServerX, false); + CfgAddBuf(f, "ServerCert", b); + FreeBuf(b); + b = KToBuf(c->ServerK, false, NULL); + CfgAddBuf(f, "ServerKey", b); + FreeBuf(b); + } } // Traffic information diff --git a/src/Cedar/Session.c b/src/Cedar/Session.c index a98b1f46..99932cb7 100644 --- a/src/Cedar/Session.c +++ b/src/Cedar/Session.c @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Session.c // Session Manager @@ -2046,10 +2045,17 @@ SESSION *NewClientSessionEx(CEDAR *cedar, CLIENT_OPTION *option, CLIENT_AUTH *au { s->ClientAuth->ClientX = CloneX(s->ClientAuth->ClientX); } - if (s->ClientAuth->ClientK != NULL) - { - s->ClientAuth->ClientK = CloneK(s->ClientAuth->ClientK); - } + if (s->ClientAuth->ClientK != NULL) + { + if (s->ClientAuth->AuthType != CLIENT_AUTHTYPE_OPENSSLENGINE) + { + s->ClientAuth->ClientK = CloneK(s->ClientAuth->ClientK); + } + else + { + s->ClientAuth->ClientK = OpensslEngineToK(s->ClientAuth->OpensslEnginePrivateKeyName, s->ClientAuth->OpensslEngineName); + } + } if (StrCmpi(s->ClientOption->DeviceName, LINK_DEVICE_NAME) == 0) { diff --git a/src/Mayaqua/Encrypt.c b/src/Mayaqua/Encrypt.c index 86fde1c2..9fc8cc59 100644 --- a/src/Mayaqua/Encrypt.c +++ b/src/Mayaqua/Encrypt.c @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Encrypt.c // Encryption and digital certification routine @@ -4395,6 +4394,22 @@ bool IsEncryptedK(BUF *b, bool private_key) return true; } +K *OpensslEngineToK(char *key_file_name, char *engine_name) +{ + K *k; +#if OPENSSL_API_COMPAT < 0x10100000L + ENGINE_load_dynamic(); +#endif // OPENSSL_API_COMPAT < 0x10100000L + ENGINE *engine = ENGINE_by_id(engine_name); + ENGINE_init(engine); + EVP_PKEY *pkey; + pkey = ENGINE_load_private_key(engine, key_file_name, NULL, NULL); + k = ZeroMalloc(sizeof(K)); + k->pkey = pkey; + k->private_key = true; + return k; +} + // Convert the BUF to a K K *BufToK(BUF *b, bool private_key, bool text, char *password) { diff --git a/src/Mayaqua/Encrypt.h b/src/Mayaqua/Encrypt.h index 587b96d2..b7e92932 100644 --- a/src/Mayaqua/Encrypt.h +++ b/src/Mayaqua/Encrypt.h @@ -98,7 +98,6 @@ // The memory-leaks and resource-leaks verification under the stress // test has been passed before release this source code. - // Encrypt.h // Header of Encrypt.c @@ -457,6 +456,7 @@ K *BioToK(BIO *bio, bool private_key, bool text, char *password); int PKeyPasswordCallbackFunction(char *buf, int bufsize, int verify, void *param); void FreePKey(EVP_PKEY *pkey); void FreeK(K *k); +K *OpensslEngineToK(char *key_file_name, char *engine_name); K *BufToK(BUF *b, bool private_key, bool text, char *password); bool IsEncryptedK(BUF *b, bool private_key); bool IsBase64(BUF *b); diff --git a/src/Mayaqua/Network.c b/src/Mayaqua/Network.c index bc8d02b5..40e867c5 100644 --- a/src/Mayaqua/Network.c +++ b/src/Mayaqua/Network.c @@ -14039,7 +14039,6 @@ bool StartSSLWithSettings(SOCK* sock, UINT ssl_timeout, char* sni_hostname, SSL_ LockOpenSSL(); { sock->ssl = SSL_new(ssl_ctx_shared->SslCtx); - SSL_set_fd(sock->ssl, (int)sock->socket); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (settings->Settings2.IsClient) diff --git a/src/bin/hamcore/strtable_cn.stb b/src/bin/hamcore/strtable_cn.stb index 2da89dcd..f3ebfd19 100644 --- a/src/bin/hamcore/strtable_cn.stb +++ b/src/bin/hamcore/strtable_cn.stb @@ -400,6 +400,7 @@ PW_TYPE_1 标准密码验证 PW_TYPE_2 RADIUS 或 NT 域验证 PW_TYPE_3 客户端证书认证 PW_TYPE_4 智能卡身份验证 +PW_TYPE_5 Openssl Engine Authentication PW_MSG_PROXY 代理服务器 %S 用户身份验证失败。请重新输入正确的用户名和密码。 PW_TYPE_PROXY 代理服务器认证 @@ -6755,6 +6756,11 @@ CMD_AccountSecureCertSet_PROMPT_CERTNAME 智能卡证书对象名: CMD_AccountSecureCertSet_PROMPT_KEYNAME 智能卡私匙对象名: +# PcAccountOpensslEngineCertSet +CMD_AccountOpensslCertSet_PROMPT_KEYNAME Specify the openssl engine specific key name: +CMD_AccountOpensslCertSet_PROMPT_ENGINENAME Specify the openssl engine name: + + # AccountRetrySet 命令 CMD_AccountRetrySet 设置连接设置的连接失败或断开时建立重新连接的次数和间隔 CMD_AccountRetrySet_Help 指定注册到 VPN Client 的连接设置,且其连接设置试图连接到 VPN Server 时,还有连接中的与 VPN Server 的通信被断开或连接失败时,指定连接的重试次数和连接重试的间隔。\n而且,如果用户认证类型为 [智能卡认证] 时,不管连接重试次数如何设置,都将不进行连接重试。 diff --git a/src/bin/hamcore/strtable_en.stb b/src/bin/hamcore/strtable_en.stb index b28e458b..c62a4679 100644 --- a/src/bin/hamcore/strtable_en.stb +++ b/src/bin/hamcore/strtable_en.stb @@ -397,6 +397,7 @@ PW_TYPE_1 Standard Password Authentication PW_TYPE_2 RADIUS or NT Domain Authentication PW_TYPE_3 Client Certificate Authentication PW_TYPE_4 Smart Card Authentication +PW_TYPE_5 Openssl Engine Authentication PW_MSG_PROXY User authentication failed on the proxy server %S. Re-enter the correct user name and password. PW_TYPE_PROXY Proxy Server Authentication @@ -6741,6 +6742,11 @@ CMD_AccountSecureCertSet_PROMPT_CERTNAME Name of Certificate Object on Smart Car CMD_AccountSecureCertSet_PROMPT_KEYNAME Name of Private Key Object on Smart Card: +# PcAccountOpensslEngineCertSet +CMD_AccountOpensslCertSet_PROMPT_KEYNAME Specify the openssl engine specific key name: +CMD_AccountOpensslCertSet_PROMPT_ENGINENAME Specify the openssl engine name: + + # AccountRetrySet コマンド CMD_AccountRetrySet Set Interval between Connection Retries for Connection Failures or Disconnections of VPN Connection Setting CMD_AccountRetrySet_Help When a VPN Connection Setting registered on the VPN Client is specified and that VPN Connection Setting attempts to connect to a VPN Server, use this to specify the interval to wait between connection attempts and the limit of how many times to retry connecting when communication with the VPN Server has been disconnected or when the connection process failed. \nIf the user authentication type is Smart Card Authentication, no connection retry will be performed regardless of the Number of Connection Attempts setting. diff --git a/src/bin/hamcore/strtable_ja.stb b/src/bin/hamcore/strtable_ja.stb index d6ab9e8a..6170491d 100644 --- a/src/bin/hamcore/strtable_ja.stb +++ b/src/bin/hamcore/strtable_ja.stb @@ -399,6 +399,7 @@ PW_TYPE_1 標準パスワード認証 PW_TYPE_2 RADIUS または NT ドメイン認証 PW_TYPE_3 クライアント証明書認証 PW_TYPE_4 スマートカード認証 +PW_TYPE_5 Openssl Engine Authentication PW_MSG_PROXY プロキシサーバー %S でのユーザー認証に失敗しました。正しいユーザー名とパスワードを再入力してください。 PW_TYPE_PROXY プロキシサーバー認証 @@ -6749,6 +6750,11 @@ CMD_AccountSecureCertSet_PROMPT_CERTNAME スマートカード内証明書オブ CMD_AccountSecureCertSet_PROMPT_KEYNAME スマートカード内秘密鍵オブジェクトの名前: +# PcAccountOpensslEngineCertSet +CMD_AccountOpensslCertSet_PROMPT_KEYNAME Specify the openssl engine specific key name: +CMD_AccountOpensslCertSet_PROMPT_ENGINENAME Specify the openssl engine name: + + # AccountRetrySet コマンド CMD_AccountRetrySet 接続設定の接続失敗または切断時の再試行回数と間隔の設定 CMD_AccountRetrySet_Help VPN Client に登録されている接続設定を指定し、その接続設定が VPN Server に接続しようとする際、または接続中に VPN Server との通信が切断されたり、接続に失敗したりした場合に、接続を再試行する回数と接続再試行間隔を指定します。\nなお、ユーザー認証の種類が [スマートカード認証] の場合は、接続試行回数の設定にかかわらず、再試行は行いません。