CP-38473: Block RPU if the pool has hosts with certificate key length less than 2048

Signed-off-by: Konstantina Chremmou <konstantina.chremmou@citrix.com>
This commit is contained in:
Konstantina Chremmou 2021-11-25 23:28:48 +00:00
parent 2d5ccdb37e
commit c19fb06bf7
12 changed files with 337 additions and 11 deletions

View File

@ -0,0 +1,117 @@
/* Copyright (c) Citrix Systems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using XenAdmin.Core;
using XenAPI;
using XenAdmin.Diagnostics.Problems;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using XenAdmin.Diagnostics.Hotfixing;
using XenAdmin.Diagnostics.Problems.HostProblem;
namespace XenAdmin.Diagnostics.Checks
{
class CertificateKeyLengthCheck : HostPostLivenessCheck
{
private readonly bool _manualUpgrade;
private readonly Dictionary<string, string> _installMethodConfig;
public CertificateKeyLengthCheck(Host coordinator, bool manualUpgrade = false, Dictionary<string, string> installMethodConfig = null)
: base(coordinator)
{
_manualUpgrade = manualUpgrade;
_installMethodConfig = installMethodConfig;
}
protected override Problem RunHostCheck()
{
//post-stockholm uses stunnel 5.60 which requires certificate key length
//equal to or greater than 2048 bytes; yangtze uses stunnel 5.56
if (!IsShortCertificateKey())
return null;
if (!_manualUpgrade)
{
var hotfix = HotfixFactory.Hotfix(Host);
if (hotfix != null && hotfix.ShouldBeAppliedTo(Host))
return new HostDoesNotHaveHotfixWarning(this, Host);
}
string upgradePlatformVersion = null;
if (_installMethodConfig != null)
Host.TryGetUpgradeVersion(Host, _installMethodConfig, out upgradePlatformVersion, out _);
// we don't know the upgrade version, so add warning
// (this is the case of the manual upgrade or when the rpu plugin doesn't have the function)
if (string.IsNullOrEmpty(upgradePlatformVersion))
return new CertificateKeyLengthWarningUrl(this, Host);
if (Helpers.PostStockholm(upgradePlatformVersion))
return new CertificateKeyLengthProblem(this, Host);
return null;
}
private bool IsShortCertificateKey()
{
var session = Host.Connection?.Session;
if (session == null)
return false;
var certificate = Host.get_server_certificate(session, Host.opaque_ref);
var lines = certificate.Split('\n').ToList();
if (lines.Count > 0)
lines.RemoveAt(0); //remove BEGIN CERTIFICATE header
if (lines.Count > 0)
lines.RemoveAt(lines.Count - 1); //remove END CERTIFICATE footer
certificate = string.Join("\n", lines);
try
{
byte[] bytes = Convert.FromBase64String(certificate);
var x509Cert = new X509Certificate2(bytes);
return x509Cert.PublicKey.Key.KeySize < 2048;
}
catch
{
return false;
}
}
public override string Description => Messages.CERTIFICATE_KEY_LENGTH_CHECK_DESCRIPTION;
}
}

View File

@ -0,0 +1,140 @@
/* Copyright (c) Citrix Systems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
using System;
using System.Windows.Forms;
using XenAdmin.Actions;
using XenAdmin.Commands;
using XenAdmin.Core;
using XenAdmin.Diagnostics.Checks;
using XenAdmin.Dialogs;
using XenAPI;
namespace XenAdmin.Diagnostics.Problems.HostProblem
{
public class CertificateKeyLengthProblem : ProblemWithMoreInfo
{
private readonly Host _host;
public CertificateKeyLengthProblem(Check check, Host host)
: base(check)
{
_host = host;
}
public override string Description => string.Format(Messages.STRING_COLON_SPACE_STRING,
_host.Name(), Messages.CERTIFICATE_KEY_LENGTH_PROBLEM_DESCRIPTION);
public override string Message => string.Format(Messages.CERTIFICATE_KEY_LENGTH_PROBLEM_MORE_INFO,
BrandManager.ProductBrand, BrandManager.ProductVersionPost82);
protected override AsyncAction CreateAction(out bool cancelled)
{
Program.Invoke(Program.MainWindow, delegate
{
if (Helpers.StockholmOrGreater(_host))
{
using (var dlg = new ErrorDialog(Message,
new ThreeButtonDialog.TBDButton(Messages.INSTALL_SERVER_CERTIFICATE_MENU, DialogResult.OK, ThreeButtonDialog.ButtonType.ACCEPT, true),
ThreeButtonDialog.ButtonCancel
))
{
if (dlg.ShowDialog() == DialogResult.OK)
{
var cmd = new InstallCertificateCommand(Program.MainWindow, _host);
if (cmd.CanRun())
cmd.Run();
}
}
}
else
{
//this is only for safety in case version evaluation fails; it shouldn't happen under normal conditions
using (var dlg = new ErrorDialog(Message))
dlg.ShowDialog();
}
});
cancelled = true;
return null;
}
}
public class CertificateKeyLengthWarningUrl : WarningWithMoreInfo
{
private readonly Host _host;
public CertificateKeyLengthWarningUrl(Check check, Host host)
: base(check)
{
_host = host;
}
public override string Description => string.Format(Messages.STRING_COLON_SPACE_STRING,
_host.Name(), Messages.CERTIFICATE_KEY_LENGTH_PROBLEM_DESCRIPTION);
public override string Message => string.Format(Messages.CERTIFICATE_KEY_LENGTH_WARNING_MORE_INFO,
BrandManager.ProductBrand, BrandManager.ProductVersionPost82);
protected override AsyncAction CreateAction(out bool cancelled)
{
Program.Invoke(Program.MainWindow, delegate
{
if (Helpers.StockholmOrGreater(_host))
{
using (var dlg = new WarningDialog(Message,
new ThreeButtonDialog.TBDButton(Messages.INSTALL_SERVER_CERTIFICATE_MENU, DialogResult.OK, ThreeButtonDialog.ButtonType.ACCEPT, true),
ThreeButtonDialog.ButtonCancel
))
{
if (dlg.ShowDialog() == DialogResult.OK)
{
var cmd = new InstallCertificateCommand(Program.MainWindow, _host);
if (cmd.CanRun())
cmd.Run();
}
}
}
else
{
//this is only for safety in case version evaluation fails; it shouldn't happen under normal conditions
using (var dlg = new WarningDialog(Message))
dlg.ShowDialog();
}
});
cancelled = true;
return null;
}
}
}

View File

@ -70,8 +70,6 @@ namespace XenAdmin.Diagnostics.Problems.HostProblem
this.host = host;
}
public override string Title => Check.Description;
public override string Description =>
string.Format(Messages.PROBLEM_POWER_ON_ILO_DESCRIPTION, host,
string.Format(Messages.STRING_SPACE_STRING, BrandManager.ProductBrand, BrandManager.ProductVersion82));

View File

@ -72,8 +72,6 @@ namespace XenAdmin.Diagnostics.Problems.PoolProblem
this.pool = pool;
}
public override string Title => Check.Description;
public override string Description =>
string.Format(Messages.PROBLEM_HEALTH_CHECK_SERVICE_DESCRIPTION, pool, BrandManager.ProductBrand, BrandManager.ProductVersionPost82);

View File

@ -67,8 +67,6 @@ namespace XenAdmin.Diagnostics.Problems.PoolProblem
this.pool = pool;
}
public override string Title => Check.Description;
public override string Description =>
string.Format(Messages.PROBLEM_LEGACY_PROTOCOL_DESCRIPTION, pool,
string.Format(Messages.STRING_SPACE_STRING, BrandManager.ProductBrand, BrandManager.ProductVersion82));

View File

@ -47,8 +47,6 @@ namespace XenAdmin.Diagnostics.Problems.PoolProblem
this.pool = pool;
}
public override string Title => Check.Description;
public override string Description => string.Format(Messages.HOST_UNLICENSED_FOR_AUTOMATED_UPDATES_WARNING, pool);
public override string Message => string.Format(Messages.AUTOMATED_UPDATES_UNLICENSED_WARNING_MORE_INFO, BrandManager.BrandConsole);

View File

@ -68,8 +68,6 @@ namespace XenAdmin.Diagnostics.Problems.PoolProblem
this.pool = pool;
}
public override string Title => Check.Description;
public override string LinkData => InvisibleMessages.DEPRECATION_URL;
public override string LinkText => Messages.LEARN_MORE;

View File

@ -81,7 +81,7 @@ namespace XenAdmin.Diagnostics.Problems
}
public abstract string Message { get; }
public override string Title => Check.Description;
public virtual string LinkData => null;
public virtual string LinkText => LinkData;
}

View File

@ -229,6 +229,15 @@ namespace XenAdmin.Wizards.RollingUpgradeWizard
if (sslChecks.Count > 0)
groups.Add(new CheckGroup(Messages.CHECKING_SECURITY_PROTOCOL_GROUP, sslChecks));
//certificate key length - for each host
var certKeyLengthChecks = (from Host server in hostsToUpgradeOrUpdate
let check = new CertificateKeyLengthCheck(server, ManualUpgrade, InstallMethodConfig)
where check.CanRun()
select check as Check).ToList();
if (certKeyLengthChecks.Count > 0)
groups.Add(new CheckGroup(Messages.CERTIFICATE_KEY_LENGTH_CHECK_GROUP, certKeyLengthChecks));
//power on mode check - for each host
var iloChecks = (from Host server in hostsToUpgradeOrUpdate
let check = new PowerOniLoCheck(server, InstallMethodConfig, ManualUpgrade)

View File

@ -236,6 +236,7 @@
<Compile Include="Diagnostics\Checks\PowerOniLoCheck.cs" />
<Compile Include="Diagnostics\Checks\PoolLegacySslCheck.cs" />
<Compile Include="Diagnostics\Checks\PrepareToUpgradeCheck.cs" />
<Compile Include="Diagnostics\Checks\CertificateKeyLengthCheck.cs" />
<Compile Include="Diagnostics\Checks\PVGuestsCheck.cs" />
<Compile Include="Diagnostics\Checks\RebootPendingOnMasterCheck.cs" />
<Compile Include="Diagnostics\Checks\HostNeedsRebootCheck.cs" />
@ -245,6 +246,7 @@
<Compile Include="Diagnostics\Checks\ClientVersionCheck.cs" />
<Compile Include="Diagnostics\Checks\HostMemoryPostUpgradeCheck.cs" />
<Compile Include="Diagnostics\Problems\HostProblem\BrokenSR.cs" />
<Compile Include="Diagnostics\Problems\HostProblem\CertificateKeyLengthProblem.cs" />
<Compile Include="Diagnostics\Problems\HostProblem\PowerOniLoProblem.cs" />
<Compile Include="Diagnostics\Problems\PoolProblem\HealthCheckServiceProblem.cs" />
<Compile Include="Diagnostics\Problems\PoolProblem\LegacySslProblem.cs" />

View File

@ -7300,6 +7300,55 @@ namespace XenAdmin {
}
}
/// <summary>
/// Looks up a localized string similar to Server certificate compatibility check.
/// </summary>
public static string CERTIFICATE_KEY_LENGTH_CHECK_DESCRIPTION {
get {
return ResourceManager.GetString("CERTIFICATE_KEY_LENGTH_CHECK_DESCRIPTION", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Checking compatibility of server identity certificate.
/// </summary>
public static string CERTIFICATE_KEY_LENGTH_CHECK_GROUP {
get {
return ResourceManager.GetString("CERTIFICATE_KEY_LENGTH_CHECK_GROUP", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The key size of the server&apos;s identity certificate is too small..
/// </summary>
public static string CERTIFICATE_KEY_LENGTH_PROBLEM_DESCRIPTION {
get {
return ResourceManager.GetString("CERTIFICATE_KEY_LENGTH_PROBLEM_DESCRIPTION", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The key size of the server&apos;s identity certificate is smaller than 2048 bytes.
///
///It is recommended that you first install a new certificate with a key size of at least 2048 bytes, otherwise you will not be able to connect to the server after the upgrade..
/// </summary>
public static string CERTIFICATE_KEY_LENGTH_PROBLEM_MORE_INFO {
get {
return ResourceManager.GetString("CERTIFICATE_KEY_LENGTH_PROBLEM_MORE_INFO", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The key size of the server&apos;s identity certificate is smaller than 2048 bytes.
///
///If you are upgrading to {0} {1} and above, it is recommended that you first install a new certificate with a key size of at least 2048 bytes, otherwise you will not be able to connect to the server after the upgrade..
/// </summary>
public static string CERTIFICATE_KEY_LENGTH_WARNING_MORE_INFO {
get {
return ResourceManager.GetString("CERTIFICATE_KEY_LENGTH_WARNING_MORE_INFO", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to A {0} user does not have sufficient permissions to install certificates on the server. Please login using an account with one of the following roles:
///

View File

@ -2635,6 +2635,25 @@ This will cancel compilation of the status report.</value>
<data name="CERTIFICATE_KEY_INVALID" xml:space="preserve">
<value>The selected TLS key file is invalid.</value>
</data>
<data name="CERTIFICATE_KEY_LENGTH_CHECK_DESCRIPTION" xml:space="preserve">
<value>Server certificate compatibility check</value>
</data>
<data name="CERTIFICATE_KEY_LENGTH_CHECK_GROUP" xml:space="preserve">
<value>Checking compatibility of server identity certificate</value>
</data>
<data name="CERTIFICATE_KEY_LENGTH_PROBLEM_DESCRIPTION" xml:space="preserve">
<value>The key size of the server's identity certificate is too small.</value>
</data>
<data name="CERTIFICATE_KEY_LENGTH_PROBLEM_MORE_INFO" xml:space="preserve">
<value>The key size of the server's identity certificate is smaller than 2048 bytes.
It is recommended that you first install a new certificate with a key size of at least 2048 bytes, otherwise you will not be able to connect to the server after the upgrade.</value>
</data>
<data name="CERTIFICATE_KEY_LENGTH_WARNING_MORE_INFO" xml:space="preserve">
<value>The key size of the server's identity certificate is smaller than 2048 bytes.
If you are upgrading to {0} {1} and above, it is recommended that you first install a new certificate with a key size of at least 2048 bytes, otherwise you will not be able to connect to the server after the upgrade.</value>
</data>
<data name="CERTIFICATE_RBAC_RESTRICTION" xml:space="preserve">
<value>A {0} user does not have sufficient permissions to install certificates on the server. Please login using an account with one of the following roles: