1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2024-11-23 01:49:53 +03:00

Merge pull request #1433 from domosekai/chain

Support user-specified server trust chain
This commit is contained in:
Yihong Wu 2021-11-25 17:15:53 +08:00 committed by GitHub
commit 2d1c8765aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 437 additions and 16 deletions

View File

@ -9455,7 +9455,7 @@ UINT StSetServerCert(ADMIN *a, RPC_KEY_PAIR *t)
} }
} }
SetCedarCert(c, t->Cert, t->Key); SetCedarCertAndChain(c, t->Cert, t->Key, t->Chain);
ALog(a, NULL, "LA_SET_SERVER_CERT"); ALog(a, NULL, "LA_SET_SERVER_CERT");
@ -14555,6 +14555,7 @@ void InRpcKeyPair(RPC_KEY_PAIR *t, PACK *p)
} }
t->Cert = PackGetX(p, "Cert"); t->Cert = PackGetX(p, "Cert");
t->Chain = PackGetXList(p, "Chain");
t->Key = PackGetK(p, "Key"); t->Key = PackGetK(p, "Key");
t->Flag1 = PackGetInt(p, "Flag1"); t->Flag1 = PackGetInt(p, "Flag1");
} }
@ -14567,12 +14568,14 @@ void OutRpcKeyPair(PACK *p, RPC_KEY_PAIR *t)
} }
PackAddX(p, "Cert", t->Cert); PackAddX(p, "Cert", t->Cert);
PackAddXList(p, "Chain", t->Chain);
PackAddK(p, "Key", t->Key); PackAddK(p, "Key", t->Key);
PackAddInt(p, "Flag1", t->Flag1); PackAddInt(p, "Flag1", t->Flag1);
} }
void FreeRpcKeyPair(RPC_KEY_PAIR *t) void FreeRpcKeyPair(RPC_KEY_PAIR *t)
{ {
FreeX(t->Cert); FreeX(t->Cert);
FreeXList(t->Chain);
FreeK(t->Key); FreeK(t->Key);
} }

View File

@ -230,6 +230,7 @@ struct RPC_FARM_CONNECTION_STATUS
struct RPC_KEY_PAIR struct RPC_KEY_PAIR
{ {
X *Cert; // Certificate X *Cert; // Certificate
LIST *Chain; // Trust chain
K *Key; // Secret key K *Key; // Secret key
UINT Flag1; // Flag1 UINT Flag1; // Flag1
}; };

View File

@ -8453,6 +8453,11 @@ bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size)
// Read a set of certificate and private key // Read a set of certificate and private key
bool CmLoadXAndK(HWND hWnd, X **x, K **k) bool CmLoadXAndK(HWND hWnd, X **x, K **k)
{
return CmLoadXListAndK(hWnd, x, k, NULL);
}
// Read a set of certificate and private key and trust chain
bool CmLoadXListAndK(HWND hWnd, X **x, K **k, LIST **cc)
{ {
wchar_t *s; wchar_t *s;
bool is_p12; bool is_p12;
@ -8500,7 +8505,7 @@ START_FIRST:
} }
if (IsEncryptedP12(p12) == false) if (IsEncryptedP12(p12) == false)
{ {
if (ParseP12(p12, x, k, NULL) == false) if (ParseP12Ex(p12, x, k, cc, NULL) == false)
{ {
MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp); MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
FreeP12(p12); FreeP12(p12);
@ -8519,7 +8524,7 @@ START_FIRST:
} }
else else
{ {
if (ParseP12(p12, x, k, password) == false) if (ParseP12Ex(p12, x, k, cc, password) == false)
{ {
MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp); MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_P12_W"), tmp);
FreeP12(p12); FreeP12(p12);
@ -8532,6 +8537,10 @@ START_FIRST:
{ {
FreeX(*x); FreeX(*x);
FreeK(*k); FreeK(*k);
if (cc != NULL)
{
FreeXList(*cc);
}
FreeP12(p12); FreeP12(p12);
FreeBuf(b); FreeBuf(b);
if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY) if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
@ -8540,6 +8549,11 @@ START_FIRST:
} }
return false; return false;
} }
if (cc != NULL && LIST_NUM(*cc) == 0)
{
ReleaseList(*cc);
*cc = NULL;
}
FreeP12(p12); FreeP12(p12);
FreeBuf(b); FreeBuf(b);
return true; return true;
@ -8548,19 +8562,40 @@ START_FIRST:
{ {
// Processing of X509 // Processing of X509
BUF *b = ReadDumpW(tmp); BUF *b = ReadDumpW(tmp);
X *x509; X *x509 = NULL;
K *key; K *key;
LIST *chain = NULL;
if (b == NULL) if (b == NULL)
{ {
MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp); MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
return false; return false;
} }
x509 = BufToX(b, IsBase64(b)); // DER-encoded X509 files can't hold multiple certificates
if (cc == NULL || IsBase64(b) == false)
{
x509 = BufToX(b, IsBase64(b));
}
else
{
chain = BufToXList(b, true);
if (LIST_NUM(chain) > 0)
{
x509 = LIST_DATA(chain, 0);
Delete(chain, x509);
if (LIST_NUM(chain) == 0)
{
ReleaseList(chain);
chain = NULL;
}
}
}
FreeBuf(b); FreeBuf(b);
if (x509 == NULL) if (x509 == NULL)
{ {
MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp); MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_X509_W"), tmp);
FreeXList(chain);
return false; return false;
} }
@ -8569,6 +8604,7 @@ START_FIRST:
if (s == NULL) if (s == NULL)
{ {
FreeX(x509); FreeX(x509);
FreeXList(chain);
return false; return false;
} }
UniStrCpy(tmp, sizeof(tmp), s); UniStrCpy(tmp, sizeof(tmp), s);
@ -8579,6 +8615,7 @@ START_FIRST:
{ {
MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp); MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_OPEN_FILE_ERROR_W"), tmp);
FreeX(x509); FreeX(x509);
FreeXList(chain);
return false; return false;
} }
@ -8593,6 +8630,7 @@ START_FIRST:
{ {
FreeBuf(b); FreeBuf(b);
FreeX(x509); FreeX(x509);
FreeXList(chain);
return false; return false;
} }
key = BufToK(b, true, IsBase64(b), pass); key = BufToK(b, true, IsBase64(b), pass);
@ -8602,6 +8640,7 @@ START_FIRST:
{ {
FreeBuf(b); FreeBuf(b);
FreeX(x509); FreeX(x509);
FreeXList(chain);
MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp); MsgBoxEx(hWnd, MB_ICONSTOP, _UU("DLG_BAD_KEY_W"), tmp);
return false; return false;
} }
@ -8611,6 +8650,7 @@ START_FIRST:
FreeBuf(b); FreeBuf(b);
FreeX(x509); FreeX(x509);
FreeK(key); FreeK(key);
FreeXList(chain);
if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY) if (MsgBox(hWnd, MB_ICONEXCLAMATION | MB_RETRYCANCEL, _UU("DLG_BAD_SIGNATURE")) == IDRETRY)
{ {
goto START_FIRST; goto START_FIRST;
@ -8621,6 +8661,10 @@ START_FIRST:
FreeBuf(b); FreeBuf(b);
*x = x509; *x = x509;
*k = key; *k = key;
if (cc != NULL)
{
*cc = chain;
}
return true; return true;
} }
} }

View File

@ -409,6 +409,7 @@ void CmEditAccountDlgInit(HWND hWnd, CM_ACCOUNT *a);
void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a); void CmEditAccountDlgOnOk(HWND hWnd, CM_ACCOUNT *a);
void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a); void CmEditAccountDlgStartEnumHub(HWND hWnd, CM_ACCOUNT *a);
bool CmLoadXAndK(HWND hWnd, X **x, K **k); bool CmLoadXAndK(HWND hWnd, X **x, K **k);
bool CmLoadXListAndK(HWND hWnd, X **x, K **k, LIST **cc);
bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size); bool CmLoadKEx(HWND hWnd, K **k, char *filename, UINT size);
bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size); bool CmLoadKExW(HWND hWnd, K **k, wchar_t *filename, UINT size);
bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x); bool CmLoadXFromFileOrSecureCard(HWND hWnd, X **x);

View File

@ -1157,6 +1157,10 @@ void CleanupCedar(CEDAR *c)
{ {
FreeK(c->ServerK); FreeK(c->ServerK);
} }
if (c->ServerChain)
{
FreeXList(c->ServerChain);
}
if (c->CipherList) if (c->CipherList)
{ {
@ -1386,6 +1390,10 @@ void FreeNetSvcList(CEDAR *cedar)
// Change certificate of Cedar // Change certificate of Cedar
void SetCedarCert(CEDAR *c, X *server_x, K *server_k) void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
{
SetCedarCertAndChain(c, server_x, server_k, NULL);
}
void SetCedarCertAndChain(CEDAR *c, X *server_x, K *server_k, LIST *server_chain)
{ {
// Validate arguments // Validate arguments
if (server_x == NULL || server_k == NULL) if (server_x == NULL || server_k == NULL)
@ -1405,8 +1413,14 @@ void SetCedarCert(CEDAR *c, X *server_x, K *server_k)
FreeK(c->ServerK); FreeK(c->ServerK);
} }
if (c->ServerChain != NULL)
{
FreeXList(c->ServerChain);
}
c->ServerX = CloneX(server_x); c->ServerX = CloneX(server_x);
c->ServerK = CloneK(server_k); c->ServerK = CloneK(server_k);
c->ServerChain = CloneXList(server_chain);
} }
Unlock(c->lock); Unlock(c->lock);
} }

View File

@ -930,6 +930,7 @@ struct CEDAR
COUNTER *ConnectionIncrement; // Connection increment counter COUNTER *ConnectionIncrement; // Connection increment counter
X *ServerX; // Server certificate X *ServerX; // Server certificate
K *ServerK; // Private key of the server certificate K *ServerK; // Private key of the server certificate
LIST *ServerChain; // Server trust chain
char UsernameHubSeparator; // Character which separates the username from the hub name char UsernameHubSeparator; // Character which separates the username from the hub name
char *CipherList; // List of encryption algorithms char *CipherList; // List of encryption algorithms
UINT Version; // Version information UINT Version; // Version information
@ -1000,6 +1001,7 @@ CEDAR *NewCedar(X *server_x, K *server_k);
void CedarForceLink(); void CedarForceLink();
void SetCedarVpnBridge(CEDAR *c); void SetCedarVpnBridge(CEDAR *c);
void SetCedarCert(CEDAR *c, X *server_x, K *server_k); void SetCedarCert(CEDAR *c, X *server_x, K *server_k);
void SetCedarCertAndChain(CEDAR *c, X *server_x, K *server_k, LIST *server_chain);
void ReleaseCedar(CEDAR *c); void ReleaseCedar(CEDAR *c);
void CleanupCedar(CEDAR *c); void CleanupCedar(CEDAR *c);
void StopCedar(CEDAR *c); void StopCedar(CEDAR *c);

View File

@ -8638,18 +8638,51 @@ UINT PsServerKeyGet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
// Read the certificate and the private key // Read the certificate and the private key
bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename) bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename)
{ {
X *x; return CmdLoadCertChainAndKey(c, xx, kk, NULL, cert_filename, key_filename);
}
bool CmdLoadCertChainAndKey(CONSOLE *c, X **xx, K **kk, LIST **cc, wchar_t *cert_filename, wchar_t *key_filename)
{
X *x = NULL;
K *k; K *k;
LIST *chain = NULL;
// Validate arguments // Validate arguments
if (c == NULL || cert_filename == NULL || key_filename == NULL || xx == NULL || kk == NULL) if (c == NULL || cert_filename == NULL || key_filename == NULL || xx == NULL || kk == NULL)
{ {
return false; return false;
} }
x = FileToXW(cert_filename); BUF *b = ReadDumpW(cert_filename);
if (b == NULL)
{
c->Write(c, _UU("CMD_LOADCERT_FAILED"));
return false;
}
// DER-encoded X509 files can't hold multiple certificates
if (cc == NULL || IsBase64(b) == false)
{
x = BufToX(b, IsBase64(b));
}
else
{
chain = BufToXList(b, true);
if (LIST_NUM(chain) > 0)
{
x = LIST_DATA(chain, 0);
Delete(chain, x);
if (LIST_NUM(chain) == 0)
{
ReleaseList(chain);
chain = NULL;
}
}
}
FreeBuf(b);
if (x == NULL) if (x == NULL)
{ {
c->Write(c, _UU("CMD_LOADCERT_FAILED")); c->Write(c, _UU("CMD_LOADCERT_FAILED"));
FreeXList(chain);
return false; return false;
} }
@ -8658,6 +8691,7 @@ bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar
{ {
c->Write(c, _UU("CMD_LOADKEY_FAILED")); c->Write(c, _UU("CMD_LOADKEY_FAILED"));
FreeX(x); FreeX(x);
FreeXList(chain);
return false; return false;
} }
@ -8666,12 +8700,17 @@ bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar
c->Write(c, _UU("CMD_KEYPAIR_FAILED")); c->Write(c, _UU("CMD_KEYPAIR_FAILED"));
FreeX(x); FreeX(x);
FreeK(k); FreeK(k);
FreeXList(chain);
return false; return false;
} }
*xx = x; *xx = x;
*kk = k; *kk = k;
if (cc != NULL)
{
*cc = chain;
}
return true; return true;
} }
@ -8754,7 +8793,7 @@ UINT PsServerCertSet(CONSOLE *c, char *cmd_name, wchar_t *str, void *param)
Zero(&t, sizeof(t)); Zero(&t, sizeof(t));
if (CmdLoadCertAndKey(c, &t.Cert, &t.Key, if (CmdLoadCertChainAndKey(c, &t.Cert, &t.Key, &t.Chain,
GetParamUniStr(o, "LOADCERT"), GetParamUniStr(o, "LOADCERT"),
GetParamUniStr(o, "LOADKEY"))) GetParamUniStr(o, "LOADKEY")))
{ {

View File

@ -236,6 +236,7 @@ bool CmdEvalPortList(CONSOLE *c, wchar_t *str, void *param);
wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param); wchar_t *PsClusterSettingMemberPromptPorts(CONSOLE *c, void *param);
K *CmdLoadKey(CONSOLE *c, wchar_t *filename); K *CmdLoadKey(CONSOLE *c, wchar_t *filename);
bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename); bool CmdLoadCertAndKey(CONSOLE *c, X **xx, K **kk, wchar_t *cert_filename, wchar_t *key_filename);
bool CmdLoadCertChainAndKey(CONSOLE *c, X **xx, K **kk, LIST **cc, wchar_t *cert_filename, wchar_t *key_filename);
bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param); bool CmdEvalTcpOrUdp(CONSOLE *c, wchar_t *str, void *param);
wchar_t *GetConnectionTypeStr(UINT type); wchar_t *GetConnectionTypeStr(UINT type);
bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param); bool CmdEvalHostAndSubnetMask4(CONSOLE *c, wchar_t *str, void *param);

View File

@ -2990,6 +2990,7 @@ void ConnectionAccept(CONNECTION *c)
SOCK *s; SOCK *s;
X *x; X *x;
K *k; K *k;
LIST *chain;
char tmp[128]; char tmp[128];
UINT initial_timeout = CONNECTING_TIMEOUT; UINT initial_timeout = CONNECTING_TIMEOUT;
UCHAR ctoken_hash[SHA1_SIZE]; UCHAR ctoken_hash[SHA1_SIZE];
@ -3040,24 +3041,27 @@ void ConnectionAccept(CONNECTION *c)
x = CloneX(c->Cedar->ServerX); x = CloneX(c->Cedar->ServerX);
k = CloneK(c->Cedar->ServerK); k = CloneK(c->Cedar->ServerK);
chain = CloneXList(c->Cedar->ServerChain);
} }
Unlock(c->Cedar->lock); Unlock(c->Cedar->lock);
// Start the SSL communication // Start the SSL communication
Copy(&s->SslAcceptSettings, &c->Cedar->SslAcceptSettings, sizeof(SSL_ACCEPT_SETTINGS)); Copy(&s->SslAcceptSettings, &c->Cedar->SslAcceptSettings, sizeof(SSL_ACCEPT_SETTINGS));
if (StartSSL(s, x, k) == false) if (StartSSLEx2(s, x, k, chain, 0, NULL) == false)
{ {
// Failed // Failed
AddNoSsl(c->Cedar, &s->RemoteIP); AddNoSsl(c->Cedar, &s->RemoteIP);
Debug("ConnectionAccept(): StartSSL() failed\n"); Debug("ConnectionAccept(): StartSSL() failed\n");
FreeX(x); FreeX(x);
FreeK(k); FreeK(k);
FreeXList(chain);
goto FINAL; goto FINAL;
} }
FreeX(x); FreeX(x);
FreeK(k); FreeK(k);
FreeXList(chain);
SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName); SLog(c->Cedar, "LS_SSL_START", c->Name, s->CipherName);

View File

@ -3605,7 +3605,7 @@ bool PPPProcessEAPTlsResponse(PPP_SESSION *p, PPP_EAP *eap_packet, UINT eapTlsSi
if (p->Eap_TlsCtx.SslPipe == NULL) if (p->Eap_TlsCtx.SslPipe == NULL)
{ {
p->Eap_TlsCtx.Dh = DhNewFromBits(DH_PARAM_BITS_DEFAULT); p->Eap_TlsCtx.Dh = DhNewFromBits(DH_PARAM_BITS_DEFAULT);
p->Eap_TlsCtx.SslPipe = NewSslPipeEx(true, p->Cedar->ServerX, p->Cedar->ServerK, p->Eap_TlsCtx.Dh, true, &(p->Eap_TlsCtx.ClientCert)); p->Eap_TlsCtx.SslPipe = NewSslPipeEx2(true, p->Cedar->ServerX, p->Cedar->ServerK, p->Cedar->ServerChain, p->Eap_TlsCtx.Dh, true, &(p->Eap_TlsCtx.ClientCert));
} }
// If the current frame is fragmented, or it is a possible last of a fragmented series, bufferize it // If the current frame is fragmented, or it is a possible last of a fragmented series, bufferize it

View File

@ -16809,6 +16809,7 @@ void SmSslDlgOnOk(HWND hWnd, SM_SSL *s)
t.Cert = CloneX(s->Cert); t.Cert = CloneX(s->Cert);
t.Key = CloneK(s->Key); t.Key = CloneK(s->Key);
t.Chain = CloneXList(s->Chain);
if (CALL(hWnd, ScSetServerCert(s->p->Rpc, &t)) == false) if (CALL(hWnd, ScSetServerCert(s->p->Rpc, &t)) == false)
{ {
@ -16923,6 +16924,7 @@ void SmSslDlgInit(HWND hWnd, SM_SSL *s)
// Copy the certificate and key // Copy the certificate and key
s->Cert = CloneX(t.Cert); s->Cert = CloneX(t.Cert);
s->Key = CloneK(t.Key); s->Key = CloneK(t.Key);
s->Chain = CloneXList(t.Chain);
if (t.Key != NULL) if (t.Key != NULL)
{ {
@ -17174,6 +17176,7 @@ UINT SmSslDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param
SM_SSL *s = (SM_SSL *)param; SM_SSL *s = (SM_SSL *)param;
X *x; X *x;
K *k; K *k;
LIST *chain;
// Validate arguments // Validate arguments
if (hWnd == NULL) if (hWnd == NULL)
{ {
@ -17222,16 +17225,18 @@ UINT SmSslDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param
case B_IMPORT: case B_IMPORT:
// Import // Import
if (CmLoadXAndK(hWnd, &x, &k)) if (CmLoadXListAndK(hWnd, &x, &k, &chain))
{ {
wchar_t tmp[MAX_SIZE]; wchar_t tmp[MAX_SIZE];
LABEL_APPLY_NEW_CERT: LABEL_APPLY_NEW_CERT:
FreeX(s->Cert); FreeX(s->Cert);
FreeK(s->Key); FreeK(s->Key);
FreeXList(s->Chain);
s->Cert = x; s->Cert = x;
s->Key = k; s->Key = k;
s->SetCertAndKey = true; s->SetCertAndKey = true;
s->Chain = chain;
// Show the Certificate Information // Show the Certificate Information
SmGetCertInfoStr(tmp, sizeof(tmp), s->Cert); SmGetCertInfoStr(tmp, sizeof(tmp), s->Cert);
SetText(hWnd, S_CERT_INFO, tmp); SetText(hWnd, S_CERT_INFO, tmp);
@ -17310,6 +17315,7 @@ void SmSslDlg(HWND hWnd, SM_SERVER *p)
// Cleanup // Cleanup
FreeX(s.Cert); FreeX(s.Cert);
FreeK(s.Key); FreeK(s.Key);
FreeXList(s.Chain);
} }
// Listener creation dialog procedure // Listener creation dialog procedure

View File

@ -112,6 +112,7 @@ typedef struct SM_SSL
SM_SERVER *p; // P SM_SERVER *p; // P
X *Cert; // Certificate X *Cert; // Certificate
K *Key; // Secret key K *Key; // Secret key
LIST *Chain; // Trust chain
bool SetCertAndKey; // Set the key bool SetCertAndKey; // Set the key
} SM_SSL; } SM_SSL;

View File

@ -5608,6 +5608,7 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f)
char tmp[MAX_SIZE]; char tmp[MAX_SIZE];
X *x = NULL; X *x = NULL;
K *k = NULL; K *k = NULL;
LIST *chain = NewList(NULL);
FOLDER *params_folder; FOLDER *params_folder;
UINT i; UINT i;
// Validate arguments // Validate arguments
@ -5847,10 +5848,14 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f)
FreeBuf(b); FreeBuf(b);
} }
// Server trust chain
SiLoadCertList(chain, CfgGetFolder(f, "ServerChain"));
if (x == NULL || k == NULL || CheckXandK(x, k) == false) if (x == NULL || k == NULL || CheckXandK(x, k) == false)
{ {
FreeX(x); FreeX(x);
FreeK(k); FreeK(k);
FreeXList(chain);
SiGenerateDefaultCert(&x, &k); SiGenerateDefaultCert(&x, &k);
SetCedarCert(c, x, k); SetCedarCert(c, x, k);
@ -5860,10 +5865,18 @@ void SiLoadServerCfg(SERVER *s, FOLDER *f)
} }
else else
{ {
SetCedarCert(c, x, k); if (LIST_NUM(chain) == 0)
{
SetCedarCert(c, x, k);
}
else
{
SetCedarCertAndChain(c, x, k, chain);
}
FreeX(x); FreeX(x);
FreeK(k); FreeK(k);
FreeXList(chain);
} }
// Character which separates the username from the hub name // Character which separates the username from the hub name
@ -6246,6 +6259,9 @@ void SiWriteServerCfg(FOLDER *f, SERVER *s)
CfgAddBuf(f, "ServerKey", b); CfgAddBuf(f, "ServerKey", b);
FreeBuf(b); FreeBuf(b);
// Server trust chain
SiWriteCertList(CfgCreateFolder(f, "ServerChain"), c->ServerChain);
{ {
// Character which separates the username from the hub name // Character which separates the username from the hub name
char str[2]; char str[2];

View File

@ -1079,6 +1079,41 @@ X *CloneX(X *x)
return ret; return ret;
} }
// Clone of certificate chain
LIST *CloneXList(LIST *chain)
{
BUF *b;
X *x;
LIST *ret;
// Validate arguments
if (chain == NULL)
{
return NULL;
}
ret = NewList(NULL);
LockList(chain);
{
UINT i;
for (i = 0;i < LIST_NUM(chain);i++)
{
x = LIST_DATA(chain, i);
b = XToBuf(x, false);
if (b == NULL)
{
continue;
}
x = BufToX(b, false);
Add(ret, x);
FreeBuf(b);
}
}
UnlockList(chain);
return ret;
}
// Generate a P12 // Generate a P12
P12 *NewP12(X *x, K *k, char *password) P12 *NewP12(X *x, K *k, char *password)
{ {
@ -1133,9 +1168,15 @@ bool IsEncryptedP12(P12 *p12)
// Extract the X and the K from the P12 // Extract the X and the K from the P12
bool ParseP12(P12 *p12, X **x, K **k, char *password) bool ParseP12(P12 *p12, X **x, K **k, char *password)
{
return ParseP12Ex(p12, x, k, NULL, password);
}
// Extract the X, the K and the chain from the P12
bool ParseP12Ex(P12 *p12, X **x, K **k, LIST **cc, char *password)
{ {
EVP_PKEY *pkey; EVP_PKEY *pkey;
X509 *x509; X509 *x509;
STACK_OF(X509) *sk = NULL;
// Validate arguments // Validate arguments
if (p12 == NULL || x == NULL || k == NULL) if (p12 == NULL || x == NULL || k == NULL)
{ {
@ -1165,9 +1206,9 @@ bool ParseP12(P12 *p12, X **x, K **k, char *password)
// Extraction // Extraction
Lock(openssl_lock); Lock(openssl_lock);
{ {
if (PKCS12_parse(p12->pkcs12, password, &pkey, &x509, NULL) == false) if (PKCS12_parse(p12->pkcs12, password, &pkey, &x509, &sk) == false)
{ {
if (PKCS12_parse(p12->pkcs12, NULL, &pkey, &x509, NULL) == false) if (PKCS12_parse(p12->pkcs12, NULL, &pkey, &x509, &sk) == false)
{ {
Unlock(openssl_lock); Unlock(openssl_lock);
return false; return false;
@ -1182,6 +1223,7 @@ bool ParseP12(P12 *p12, X **x, K **k, char *password)
if (*x == NULL) if (*x == NULL)
{ {
FreePKey(pkey); FreePKey(pkey);
sk_X509_free(sk);
return false; return false;
} }
@ -1189,6 +1231,37 @@ bool ParseP12(P12 *p12, X **x, K **k, char *password)
(*k)->private_key = true; (*k)->private_key = true;
(*k)->pkey = pkey; (*k)->pkey = pkey;
if (sk == NULL || cc == NULL)
{
if (cc != NULL)
{
*cc = NULL;
}
if (sk != NULL)
{
sk_X509_free(sk);
}
return true;
}
LIST *chain = NewList(NULL);
X *x1;
while (sk_X509_num(sk)) {
x509 = sk_X509_shift(sk);
x1 = X509ToX(x509);
if (x1 != NULL)
{
Add(chain, x1);
}
else
{
X509_free(x509);
}
}
sk_X509_free(sk);
*cc = chain;
return true; return true;
} }
@ -3369,6 +3442,29 @@ void FreeX(X *x)
Free(x); Free(x);
} }
// Release of an X chain
void FreeXList(LIST *chain)
{
// Validate arguments
if (chain == NULL)
{
return;
}
LockList(chain);
{
UINT i;
for (i = 0; i < LIST_NUM(chain); i++)
{
X *x = LIST_DATA(chain, i);
FreeX(x);
}
}
UnlockList(chain);
ReleaseList(chain);
}
// Release of the X509 // Release of the X509
void FreeX509(X509 *x509) void FreeX509(X509 *x509)
{ {
@ -3410,6 +3506,31 @@ X *BufToX(BUF *b, bool text)
return x; return x;
} }
// Convert the BUF to X chain
LIST *BufToXList(BUF *b, bool text)
{
LIST *chain;
BIO *bio;
// Validate arguments
if (b == NULL)
{
return NULL;
}
bio = BufToBio(b);
if (bio == NULL)
{
FreeBuf(b);
return NULL;
}
chain = BioToXList(bio, text);
FreeBio(bio);
return chain;
}
// Get a digest of the X // Get a digest of the X
void GetXDigest(X *x, UCHAR *buf, bool sha1) void GetXDigest(X *x, UCHAR *buf, bool sha1)
{ {
@ -3473,6 +3594,49 @@ X *BioToX(BIO *bio, bool text)
return x; return x;
} }
// Convert BIO to X chain
LIST *BioToXList(BIO *bio, bool text)
{
X *x;
STACK_OF(X509_INFO) *sk = NULL;
X509_INFO *xi;
LIST *chain;
// Validate arguments
if (bio == NULL || text == false)
{
return NULL;
}
Lock(openssl_lock);
{
sk = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
if (sk == NULL)
{
return NULL;
}
chain = NewList(NULL);
while (sk_X509_INFO_num(sk))
{
xi = sk_X509_INFO_shift(sk);
x = X509ToX(xi->x509);
if (x != NULL)
{
Add(chain, x);
xi->x509 = NULL;
}
X509_INFO_free(xi);
}
sk_X509_INFO_free(sk);
}
Unlock(openssl_lock);
return chain;
}
// Convert the X509 to X // Convert the X509 to X
X *X509ToX(X509 *x509) X *X509ToX(X509 *x509)
{ {

View File

@ -293,9 +293,12 @@ BUF *BioToBuf(BIO *bio);
BIO *NewBio(); BIO *NewBio();
void FreeBio(BIO *bio); void FreeBio(BIO *bio);
X *BioToX(BIO *bio, bool text); X *BioToX(BIO *bio, bool text);
LIST *BioToXList(BIO *bio, bool text);
X *BufToX(BUF *b, bool text); X *BufToX(BUF *b, bool text);
LIST *BufToXList(BUF *b, bool text);
void FreeX509(X509 *x509); void FreeX509(X509 *x509);
void FreeX(X *x); void FreeX(X *x);
void FreeXList(LIST *chain);
BIO *XToBio(X *x, bool text); BIO *XToBio(X *x, bool text);
BUF *XToBuf(X *x, bool text); BUF *XToBuf(X *x, bool text);
K *BioToK(BIO *bio, bool private_key, bool text, char *password); K *BioToK(BIO *bio, bool private_key, bool text, char *password);
@ -357,9 +360,11 @@ void FreePKCS12(PKCS12 *pkcs12);
void FreeP12(P12 *p12); void FreeP12(P12 *p12);
bool P12ToFileW(P12 *p12, wchar_t *filename); bool P12ToFileW(P12 *p12, wchar_t *filename);
bool ParseP12(P12 *p12, X **x, K **k, char *password); bool ParseP12(P12 *p12, X **x, K **k, char *password);
bool ParseP12Ex(P12 *p12, X **x, K **k, LIST **cc, char *password);
bool IsEncryptedP12(P12 *p12); bool IsEncryptedP12(P12 *p12);
P12 *NewP12(X *x, K *k, char *password); P12 *NewP12(X *x, K *k, char *password);
X *CloneX(X *x); X *CloneX(X *x);
LIST *CloneXList(LIST *chain);
K *CloneK(K *k); K *CloneK(K *k);
void FreeCryptLibrary(); void FreeCryptLibrary();
void GetPrintNameFromX(wchar_t *str, UINT size, X *x); void GetPrintNameFromX(wchar_t *str, UINT size, X *x);

View File

@ -5702,6 +5702,10 @@ SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh)
// Create a new SSL pipe with extended options // 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 *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert)
{
return NewSslPipeEx2(server_mode, x, k, NULL, dh, verify_peer, clientcert);
}
SSL_PIPE *NewSslPipeEx2(bool server_mode, X *x, K *k, LIST *chain, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert)
{ {
SSL_PIPE *s; SSL_PIPE *s;
SSL *ssl; SSL *ssl;
@ -5715,7 +5719,24 @@ SSL_PIPE *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_pee
SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3); // For some reason pppd under linux doesn't like it SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_3); // For some reason pppd under linux doesn't like it
#endif #endif
AddChainSslCertOnDirectory(ssl_ctx); if (chain == NULL)
{
AddChainSslCertOnDirectory(ssl_ctx);
}
else
{
UINT i;
X *x;
LockList(chain);
{
for (i = 0;i < LIST_NUM(chain);i++)
{
x = LIST_DATA(chain, i);
AddChainSslCert(ssl_ctx, x);
}
}
UnlockList(chain);
}
if (dh != NULL) if (dh != NULL)
{ {
@ -11565,6 +11586,10 @@ bool StartSSL(SOCK *sock, X *x, K *priv)
return StartSSLEx(sock, x, priv, 0, NULL); return StartSSLEx(sock, x, priv, 0, NULL);
} }
bool StartSSLEx(SOCK *sock, X *x, K *priv, UINT ssl_timeout, char *sni_hostname) bool StartSSLEx(SOCK *sock, X *x, K *priv, UINT ssl_timeout, char *sni_hostname)
{
return StartSSLEx2(sock, x, priv, NULL, ssl_timeout, sni_hostname);
}
bool StartSSLEx2(SOCK *sock, X *x, K *priv, LIST *chain, UINT ssl_timeout, char *sni_hostname)
{ {
X509 *x509; X509 *x509;
EVP_PKEY *key; EVP_PKEY *key;
@ -11660,7 +11685,24 @@ bool StartSSLEx(SOCK *sock, X *x, K *priv, UINT ssl_timeout, char *sni_hostname)
#endif #endif
Unlock(openssl_lock); Unlock(openssl_lock);
AddChainSslCertOnDirectory(ssl_ctx); if (chain == NULL)
{
AddChainSslCertOnDirectory(ssl_ctx);
}
else
{
UINT i;
X *x;
LockList(chain);
{
for (i = 0;i < LIST_NUM(chain);i++)
{
x = LIST_DATA(chain, i);
AddChainSslCert(ssl_ctx, x);
}
}
UnlockList(chain);
}
Lock(openssl_lock); Lock(openssl_lock);
} }

View File

@ -1078,6 +1078,7 @@ UINT SecureSend(SOCK *sock, void *data, UINT size);
UINT SecureRecv(SOCK *sock, void *data, UINT size); UINT SecureRecv(SOCK *sock, void *data, UINT size);
bool StartSSL(SOCK *sock, X *x, K *priv); bool StartSSL(SOCK *sock, X *x, K *priv);
bool StartSSLEx(SOCK *sock, X *x, K *priv, UINT ssl_timeout, char *sni_hostname); bool StartSSLEx(SOCK *sock, X *x, K *priv, UINT ssl_timeout, char *sni_hostname);
bool StartSSLEx2(SOCK *sock, X *x, K *priv, LIST *chain, UINT ssl_timeout, char *sni_hostname);
bool AddChainSslCert(struct ssl_ctx_st *ctx, X *x); bool AddChainSslCert(struct ssl_ctx_st *ctx, X *x);
void AddChainSslCertOnDirectory(struct ssl_ctx_st *ctx); void AddChainSslCertOnDirectory(struct ssl_ctx_st *ctx);
bool SendAll(SOCK *sock, void *data, UINT size, bool secure); bool SendAll(SOCK *sock, void *data, UINT size, bool secure);
@ -1353,6 +1354,7 @@ struct SslClientCertInfo {
SSL_PIPE *NewSslPipe(bool server_mode, X *x, K *k, DH_CTX *dh); 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); SSL_PIPE *NewSslPipeEx(bool server_mode, X *x, K *k, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert);
SSL_PIPE *NewSslPipeEx2(bool server_mode, X *x, K *k, LIST *chain, DH_CTX *dh, bool verify_peer, struct SslClientCertInfo *clientcert);
void FreeSslPipe(SSL_PIPE *s); void FreeSslPipe(SSL_PIPE *s);
bool SyncSslPipe(SSL_PIPE *s); bool SyncSslPipe(SSL_PIPE *s);

View File

@ -870,6 +870,50 @@ X *PackGetX(PACK *p, char *name)
return x; return x;
} }
// Get the X chain from the PACK
LIST *PackGetXList(PACK *p, char *name)
{
X *x;
BUF *b;
LIST *chain;
UINT i;
// Validate arguments
if (p == NULL || name == NULL)
{
return NULL;
}
ELEMENT *e = GetElement(p, name, VALUE_DATA);
if (e == NULL)
{
return NULL;
}
chain = NewList(NULL);
for (i = 0;i < e->num_value;i++)
{
b = PackGetBufEx(p, name, i);
if (b == NULL)
{
FreeXList(chain);
return NULL;
}
x = BufToX(b, false);
if (x == NULL)
{
x = BufToX(b, true);
}
FreeBuf(b);
Add(chain, x);
}
return chain;
}
// Add the K to the PACK // Add the K to the PACK
ELEMENT *PackAddK(PACK *p, char *name, K *k) ELEMENT *PackAddK(PACK *p, char *name, K *k)
{ {
@ -916,6 +960,36 @@ ELEMENT *PackAddX(PACK *p, char *name, X *x)
return e; return e;
} }
// Add an X chain into the PACK
ELEMENT *PackAddXList(PACK *p, char *name, LIST *chain)
{
BUF *b;
X *x;
ELEMENT *e = NULL;
// Validate arguments
if (p == NULL || name == NULL || chain == NULL)
{
return NULL;
}
UINT i;
for (i = 0;i < LIST_NUM(chain);i++)
{
x = LIST_DATA(chain, i);
b = XToBuf(x, false);
if (b == NULL)
{
return NULL;
}
e = PackAddBufEx(p, name, b, i, LIST_NUM(chain));
FreeBuf(b);
}
return e;
}
// Get a buffer from the PACK // Get a buffer from the PACK
BUF *PackGetBuf(PACK *p, char *name) BUF *PackGetBuf(PACK *p, char *name)
{ {

View File

@ -127,8 +127,10 @@ VALUE *NewInt64Value(UINT64 i);
TOKEN_LIST *GetPackElementNames(PACK *p); TOKEN_LIST *GetPackElementNames(PACK *p);
X *PackGetX(PACK *p, char *name); X *PackGetX(PACK *p, char *name);
LIST *PackGetXList(PACK *p, char *name);
K *PackGetK(PACK *p, char *name); K *PackGetK(PACK *p, char *name);
ELEMENT *PackAddX(PACK *p, char *name, X *x); ELEMENT *PackAddX(PACK *p, char *name, X *x);
ELEMENT *PackAddXList(PACK *p, char *name, LIST *chain);
ELEMENT *PackAddK(PACK *p, char *name, K *k); ELEMENT *PackAddK(PACK *p, char *name, K *k);
ELEMENT *PackAddStr(PACK *p, char *name, char *str); ELEMENT *PackAddStr(PACK *p, char *name, char *str);
ELEMENT *PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total); ELEMENT *PackAddStrEx(PACK *p, char *name, char *str, UINT index, UINT total);