From ff3910eb869f567ac9c57fea0135619a0affb27a Mon Sep 17 00:00:00 2001 From: mcallist Date: Mon, 6 Jul 2020 20:25:18 +0200 Subject: [PATCH] Openssl engine certificate authentication TODO cert get, call finish engine, call init engine in another step, handle authentication, internatiolazion (help is needed) --- src/Cedar/Cedar.h | 3 +- src/Cedar/Client.c | 53 +++++++++++++++++++++++++++++- src/Cedar/Client.h | 2 +- src/Cedar/Command.c | 73 +++++++++++++++++++++++++++++++++++++++++- src/Cedar/Command.h | 3 +- src/Cedar/Connection.c | 10 +++++- src/Cedar/Connection.h | 4 ++- src/Cedar/Link.c | 4 +-- src/Cedar/Protocol.c | 16 ++++++++- src/Cedar/Session.c | 17 +++++++--- src/Mayaqua/Encrypt.c | 21 +++++++++++- src/Mayaqua/Encrypt.h | 3 +- 12 files changed, 192 insertions(+), 17 deletions(-) diff --git a/src/Cedar/Cedar.h b/src/Cedar/Cedar.h index dbe65dae..6d2f6b23 100644 --- a/src/Cedar/Cedar.h +++ b/src/Cedar/Cedar.h @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Cedar.h // Header of Cedar.c @@ -376,6 +376,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 diff --git a/src/Cedar/Client.c b/src/Cedar/Client.c index 5e5f4b83..3acf9423 100644 --- a/src/Cedar/Client.c +++ b/src/Cedar/Client.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Client.c // Client Manager @@ -4402,6 +4402,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) @@ -4448,6 +4459,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; } } @@ -6402,6 +6424,11 @@ 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->ClientK = OpensslEngineToK("asdf"); */ + r->ClientAuth->SecureSignProc = NULL; + } else { r->ClientAuth->SecureSignProc = NULL; @@ -9266,6 +9293,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; @@ -9810,6 +9851,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 afe7c985..96b5fe07 100644 --- a/src/Cedar/Client.h +++ b/src/Cedar/Client.h @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Client.h // Header of Client.c diff --git a/src/Cedar/Command.c b/src/Cedar/Command.c index 564d2d87..8abf7749 100644 --- a/src/Cedar/Command.c +++ b/src/Cedar/Command.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Command.c // vpncmd Command Line Management Utility @@ -2948,6 +2948,7 @@ void PcMain(PC *pc) {"AccountStatusShow", PcAccountStatusShow}, {"AccountStatusHide", PcAccountStatusHide}, {"AccountSecureCertSet", PcAccountSecureCertSet}, + {"AccountOpensslEngineCertSet", PcAccountOpensslEngineCertSet}, {"AccountRetrySet", PcAccountRetrySet}, {"AccountStartupSet", PcAccountStartupSet}, {"AccountStartupRemove", PcAccountStartupRemove}, @@ -6420,6 +6421,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_AccountSecureCertSet_PROMPT_KEYNAME"), CmdEvalNotEmpty, NULL}, + {"ENGINENAME", CmdPrompt, _UU("Openssl engine name."), 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) { diff --git a/src/Cedar/Command.h b/src/Cedar/Command.h index 34e23b15..8e0b4943 100644 --- a/src/Cedar/Command.h +++ b/src/Cedar/Command.h @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Command.h // Header of Command.c @@ -368,6 +368,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); diff --git a/src/Cedar/Connection.c b/src/Cedar/Connection.c index dbac5f00..8ae23095 100644 --- a/src/Cedar/Connection.c +++ b/src/Cedar/Connection.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Connection.c // Connection Manager @@ -539,6 +539,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; diff --git a/src/Cedar/Connection.h b/src/Cedar/Connection.h index 2f39edf1..c846ddeb 100644 --- a/src/Cedar/Connection.h +++ b/src/Cedar/Connection.h @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Connection.h // Header of Connection.c @@ -99,6 +99,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 52d4b9ef..ec25023c 100644 --- a/src/Cedar/Link.c +++ b/src/Cedar/Link.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Link.c // Inter-HUB Link @@ -622,7 +622,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 24707635..f515d593 100644 --- a/src/Cedar/Protocol.c +++ b/src/Cedar/Protocol.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Protocol.c // SoftEther protocol related routines @@ -5511,6 +5511,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/Session.c b/src/Cedar/Session.c index b48a3067..1c1ae57c 100644 --- a/src/Cedar/Session.c +++ b/src/Cedar/Session.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Cedar Communication Module - +// © 2020 Nokia // Session.c // Session Manager @@ -1918,10 +1918,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 502aa8d5..27403a6c 100644 --- a/src/Mayaqua/Encrypt.c +++ b/src/Mayaqua/Encrypt.c @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Mayaqua Kernel - +// © 2020 Nokia // Encrypt.c // Encryption and digital certification routine @@ -46,6 +46,7 @@ #include // For __cpuid() #else // _MSC_VER + #ifndef SKIP_CPU_FEATURES #include "cpu_features_macros.h" #endif @@ -3111,6 +3112,24 @@ bool IsEncryptedK(BUF *b, bool private_key) return true; } +K *OpensslEngineToK(char *key_file_name, char *engine_name) +{ +#ifdef UNIX_LINUX + K *k; + ENGINE_load_dynamic(); + ENGINE *engine = ENGINE_by_id("tpm2tss"); + 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; +#else + return NULL; +#endif // UNIX_LINUX +} + // 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 dc82c562..27876e92 100644 --- a/src/Mayaqua/Encrypt.h +++ b/src/Mayaqua/Encrypt.h @@ -1,6 +1,6 @@ // SoftEther VPN Source Code - Developer Edition Master Branch // Mayaqua Kernel - +// © 2020 Nokia // Encrypt.h // Header of Encrypt.c @@ -300,6 +300,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);