diff --git a/v2rayN/ServiceLib/Manager/CertPemManager.cs b/v2rayN/ServiceLib/Manager/CertPemManager.cs
index b1c8d82a..0a58e2de 100644
--- a/v2rayN/ServiceLib/Manager/CertPemManager.cs
+++ b/v2rayN/ServiceLib/Manager/CertPemManager.cs
@@ -203,7 +203,7 @@ public class CertPemManager
///
/// Get certificate in PEM format from a server with CA pinning validation
///
- public async Task<(string?, string?)> GetCertPemAsync(string target, string serverName, int timeout = 4)
+ public async Task<(string?, string?)> GetCertPemAsync(string target, string serverName, int timeout = 4, bool allowInsecure = false)
{
try
{
@@ -215,12 +215,14 @@ public class CertPemManager
using var client = new TcpClient();
await client.ConnectAsync(domain, port > 0 ? port : 443, cts.Token);
- await using var ssl = new SslStream(client.GetStream(), false, ValidateServerCertificate);
+ var callback = new RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) =>
+ ValidateServerCertificate(sender, certificate, chain, sslPolicyErrors, allowInsecure));
+ await using var ssl = new SslStream(client.GetStream(), false, callback);
var sslOptions = new SslClientAuthenticationOptions
{
TargetHost = serverName,
- RemoteCertificateValidationCallback = ValidateServerCertificate
+ RemoteCertificateValidationCallback = callback
};
await ssl.AuthenticateAsClientAsync(sslOptions, cts.Token);
@@ -249,7 +251,7 @@ public class CertPemManager
///
/// Get certificate chain in PEM format from a server with CA pinning validation
///
- public async Task<(List, string?)> GetCertChainPemAsync(string target, string serverName, int timeout = 4)
+ public async Task<(List, string?)> GetCertChainPemAsync(string target, string serverName, int timeout = 4, bool allowInsecure = false)
{
var pemList = new List();
try
@@ -262,12 +264,14 @@ public class CertPemManager
using var client = new TcpClient();
await client.ConnectAsync(domain, port > 0 ? port : 443, cts.Token);
- await using var ssl = new SslStream(client.GetStream(), false, ValidateServerCertificate);
+ var callback = new RemoteCertificateValidationCallback((sender, certificate, chain, sslPolicyErrors) =>
+ ValidateServerCertificate(sender, certificate, chain, sslPolicyErrors, allowInsecure));
+ await using var ssl = new SslStream(client.GetStream(), false, callback);
var sslOptions = new SslClientAuthenticationOptions
{
TargetHost = serverName,
- RemoteCertificateValidationCallback = ValidateServerCertificate
+ RemoteCertificateValidationCallback = callback
};
await ssl.AuthenticateAsClientAsync(sslOptions, cts.Token);
@@ -300,16 +304,23 @@ public class CertPemManager
/// Validate server certificate with CA pinning
///
private bool ValidateServerCertificate(
- object sender,
+ object _,
X509Certificate? certificate,
X509Chain? chain,
- SslPolicyErrors sslPolicyErrors)
+ SslPolicyErrors sslPolicyErrors,
+ bool allowInsecure)
{
if (certificate == null)
{
return false;
}
+ // In insecure mode, accept any certificate so self-signed certs can be fetched.
+ if (allowInsecure)
+ {
+ return true;
+ }
+
// Check certificate name mismatch
if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch))
{
diff --git a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
index 0743b6c7..74691c67 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
+++ b/v2rayN/ServiceLib/Resx/ResUI.Designer.cs
@@ -2580,6 +2580,24 @@ namespace ServiceLib.Resx {
}
}
+ ///
+ /// 查找类似 Allow insecure cert fetch (self-signed) 的本地化字符串。
+ ///
+ public static string TbAllowInsecureCertFetch {
+ get {
+ return ResourceManager.GetString("TbAllowInsecureCertFetch", resourceCulture);
+ }
+ }
+
+ ///
+ /// 查找类似 Only for fetching self-signed certificates. This may expose you to MITM risks. 的本地化字符串。
+ ///
+ public static string TbAllowInsecureCertFetchTips {
+ get {
+ return ResourceManager.GetString("TbAllowInsecureCertFetchTips", resourceCulture);
+ }
+ }
+
///
/// 查找类似 ALPN 的本地化字符串。
///
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
index 84f9722e..f0878156 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fa-Ir.resx
@@ -1707,4 +1707,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
XHTTP Extra
+
+ Allow insecure cert fetch (self-signed)
+
+
+ Only for fetching self-signed certificates. This may expose you to MITM risks.
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.fr.resx b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
index 84033130..9533c895 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.fr.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.fr.resx
@@ -1710,4 +1710,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
XHTTP Extra
+
+ Allow insecure cert fetch (self-signed)
+
+
+ Only for fetching self-signed certificates. This may expose you to MITM risks.
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.hu.resx b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
index e58ae6f0..cbc77d26 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.hu.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.hu.resx
@@ -1707,4 +1707,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
XHTTP Extra
+
+ Allow insecure cert fetch (self-signed)
+
+
+ Only for fetching self-signed certificates. This may expose you to MITM risks.
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.resx b/v2rayN/ServiceLib/Resx/ResUI.resx
index b4120d3c..5234ed03 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.resx
@@ -1713,4 +1713,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
XHTTP Extra
+
+ Allow insecure cert fetch (self-signed)
+
+
+ Only for fetching self-signed certificates. This may expose you to MITM risks.
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.ru.resx b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
index 4d30949c..13adbf49 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.ru.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.ru.resx
@@ -1707,4 +1707,10 @@
XHTTP Extra
+
+ Allow insecure cert fetch (self-signed)
+
+
+ Only for fetching self-signed certificates. This may expose you to MITM risks.
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
index b47b832e..42a4552b 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hans.resx
@@ -1710,4 +1710,10 @@
XHTTP Extra
+
+ 允许不安全获取证书(自签名)
+
+
+ 仅用于抓取自签证书,存在中间人风险。
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
index 7ba89b33..90d3b549 100644
--- a/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
+++ b/v2rayN/ServiceLib/Resx/ResUI.zh-Hant.resx
@@ -1704,4 +1704,10 @@
XHTTP Extra
+
+ 允許不安全獲取證書(自簽名)
+
+
+ 僅用於抓取自簽證書,存在中間人風險。
+
\ No newline at end of file
diff --git a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs
index 0264bc1f..3dbea94c 100644
--- a/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs
+++ b/v2rayN/ServiceLib/ViewModels/AddServerViewModel.cs
@@ -17,6 +17,9 @@ public class AddServerViewModel : MyReactiveObject
[Reactive]
public string CertSha { get; set; }
+ [Reactive]
+ public bool AllowInsecureCertFetch { get; set; }
+
[Reactive]
public string SalamanderPass { get; set; }
@@ -468,7 +471,7 @@ public class AddServerViewModel : MyReactiveObject
domain += $":{SelectedSource.Port}";
}
- (Cert, var certError) = await CertPemManager.Instance.GetCertPemAsync(domain, serverName);
+ (Cert, var certError) = await CertPemManager.Instance.GetCertPemAsync(domain, serverName, allowInsecure: AllowInsecureCertFetch);
UpdateCertTip(certError);
}
@@ -493,7 +496,7 @@ public class AddServerViewModel : MyReactiveObject
domain += $":{SelectedSource.Port}";
}
- var (certs, certError) = await CertPemManager.Instance.GetCertChainPemAsync(domain, serverName);
+ var (certs, certError) = await CertPemManager.Instance.GetCertChainPemAsync(domain, serverName, allowInsecure: AllowInsecureCertFetch);
Cert = CertPemManager.ConcatenatePemChain(certs);
UpdateCertTip(certError);
}
diff --git a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
index 56a579db..f29afb7f 100644
--- a/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/AddServerWindow.axaml
@@ -1159,6 +1159,25 @@
Margin="{StaticResource Margin4}"
Content="{x:Static resx:ResUI.TbFetchCertChain}" />
+
+
+
+
+
this.Bind(ViewModel, vm => vm.CertSha, v => v.txtCertSha256Pinning.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.togAllowInsecureCertFetch.IsChecked).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.txtAllowInsecureCertFetchTips.IsVisible).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.SelectedValue).DisposeWith(disposables);
diff --git a/v2rayN/v2rayN/Views/AddServerWindow.xaml b/v2rayN/v2rayN/Views/AddServerWindow.xaml
index ec86e904..e2dec9bc 100644
--- a/v2rayN/v2rayN/Views/AddServerWindow.xaml
+++ b/v2rayN/v2rayN/Views/AddServerWindow.xaml
@@ -1483,6 +1483,27 @@
Content="{x:Static resx:ResUI.TbFetchCertChain}"
Style="{StaticResource DefButton}" />
+
+
+
+
+
vm.CertSha, v => v.txtCertSha256Pinning.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.CertTip, v => v.labCertPinning.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.AllowInsecureCertFetch, v => v.togAllowInsecureCertFetch.IsChecked).DisposeWith(disposables);
+ this.WhenAnyValue(x => x.ViewModel.AllowInsecureCertFetch)
+ .Select(b => b ? Visibility.Visible : Visibility.Collapsed)
+ .BindTo(this, v => v.txtAllowInsecureCertFetchTips.Visibility);
this.Bind(ViewModel, vm => vm.Cert, v => v.txtCert.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchConfigList, v => v.txtEchConfigList.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.EchForceQuery, v => v.cmbEchForceQuery.Text).DisposeWith(disposables);