Issue #1972: Add new option to verify SSL certificate, in MySQL and MariaDB

This commit is contained in:
Ansgar Becker
2024-06-28 15:38:23 +02:00
parent a15a1713f7
commit 0b3bc66d6e
6 changed files with 93 additions and 10 deletions

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: HeidiSQL\n"
"POT-Creation-Date: 2012-11-05 21:40\n"
"PO-Revision-Date: 2024-06-05 16:41+0200\n"
"PO-Revision-Date: 2024-06-28 15:35+0200\n"
"Last-Translator: Ansgar Becker <anse@heidisql.com>\n"
"Language-Team: English (http://www.transifex.com/projects/p/heidisql/language/en/)\n"
"Language: en\n"
@ -439,6 +439,21 @@ msgstr "SSL certificate:"
msgid "SSL cipher:"
msgstr "SSL cipher:"
msgid "Certificate verification"
msgstr "Certificate verification"
msgid "No verification (insecure)"
msgstr "No verification (insecure)"
msgid "Verify CA"
msgstr "Verify CA"
msgid "Verify CA and host name identity"
msgstr "Verify CA and host name identity"
msgid "You might need to lower the certificate verification in the SSL settings."
msgstr "You might need to lower the certificate verification in the SSL settings."
msgid "Path to key file"
msgstr "Path to key file"

View File

@ -187,7 +187,7 @@ type
asUser, asPassword, asCleartextPluginEnabled, asWindowsAuth, asLoginPrompt, asPort, asLibrary, asAllProviders,
asSSHtunnelActive, asPlinkExecutable, asSshExecutable, asSSHtunnelHost, asSSHtunnelHostPort, asSSHtunnelPort, asSSHtunnelUser,
asSSHtunnelPassword, asSSHtunnelTimeout, asSSHtunnelPrivateKey, asSSLActive, asSSLKey,
asSSLCert, asSSLCA, asSSLCipher, asSSLWarnUnused, asNetType, asCompressed, asLocalTimeZone, asQueryTimeout, asKeepAlive,
asSSLCert, asSSLCA, asSSLCipher, asSSLVerification, asSSLWarnUnused, asNetType, asCompressed, asLocalTimeZone, asQueryTimeout, asKeepAlive,
asStartupScriptFilename, asDatabases, asComment, asDatabaseFilter, asTableFilter, asFilterVT, asExportSQLCreateDatabases,
asExportSQLCreateTables, asExportSQLDataHow, asExportSQLDataInsertSize, asExportSQLFilenames, asExportZIPFilenames, asExportSQLDirectories,
asExportSQLDatabase, asExportSQLServerDatabase, asExportSQLOutput, asExportSQLAddComments, asExportSQLRemoveAutoIncrement, asExportSQLRemoveDefiner,
@ -2539,7 +2539,7 @@ var
rx: TRegExpr;
ExeName, SessName, Host, Lib, Port, User, Pass, Socket, AllDatabases,
SSLPrivateKey, SSLCACertificate, SSLCertificate, SSLCipher: String;
NetType, WindowsAuth, WantSSL, CleartextPluginEnabled: Integer;
NetType, WindowsAuth, WantSSL, CleartextPluginEnabled, SSLVerification: Integer;
AbsentFiles: TStringList;
function GetParamValue(ShortName, LongName: String): String;
@ -2618,6 +2618,7 @@ begin
SSLCACertificate := GetParamValue('sslca', 'sslcacertificate');
SSLCertificate := GetParamValue('sslcert', 'sslcertificate');
SSLCipher := GetParamValue('sslcip', 'sslcipher');
SSLVerification := StrToIntDef(GetParamValue('sslvrf', 'sslverification'), -1);
// Leave out support for startup script, seems reasonable for command line connecting
if (Host <> '') or (User <> '') or (Pass <> '') or (Port <> '') or (Socket <> '') or (AllDatabases <> '') then begin
@ -2654,6 +2655,8 @@ begin
ConnectionParams.SSLCertificate := SSLCertificate;
if SSLCipher <> '' then
ConnectionParams.SSLCipher := SSLCipher;
if SSLVerification >= 0 then
ConnectionParams.SSLVerification := SSLVerification;
if WindowsAuth in [0,1] then
ConnectionParams.WindowsAuth := Boolean(WindowsAuth);
@ -3724,6 +3727,7 @@ begin
InitSetting(asSSLCert, 'SSL_Cert', 0, False, '', True);
InitSetting(asSSLCA, 'SSL_CA', 0, False, '', True);
InitSetting(asSSLCipher, 'SSL_Cipher', 0, False, '', True);
InitSetting(asSSLVerification, 'SSL_Verification', 2, False, '', True);
InitSetting(asSSLWarnUnused, 'SSL_WarnUnused', 0, True);
InitSetting(asNetType, 'NetType', Integer(ntMySQL_TCPIP), False, '', True);
InitSetting(asCompressed, 'Compressed', 0, False, '', True);

View File

@ -763,6 +763,13 @@ object connform: Tconnform
Height = 14
Caption = 'SSL cipher:'
end
object lblSSLVerification: TLabel
Left = 3
Top = 148
Width = 131
Height = 14
Caption = 'Certificate verification:'
end
object chkWantSSL: TCheckBox
Left = 190
Top = 13
@ -776,7 +783,7 @@ object connform: Tconnform
object editSSLcipher: TEdit
Left = 190
Top = 117
Width = 320
Width = 324
Height = 22
Anchors = [akLeft, akTop, akRight]
TabOrder = 4
@ -787,7 +794,7 @@ object connform: Tconnform
object editSSLCertificate: TButtonedEdit
Left = 190
Top = 90
Width = 320
Width = 324
Height = 22
Anchors = [akLeft, akTop, akRight]
Images = MainForm.VirtualImageListMain
@ -803,7 +810,7 @@ object connform: Tconnform
object editSSLCACertificate: TButtonedEdit
Left = 190
Top = 63
Width = 320
Width = 324
Height = 22
Anchors = [akLeft, akTop, akRight]
Images = MainForm.VirtualImageListMain
@ -819,7 +826,7 @@ object connform: Tconnform
object editSSLPrivateKey: TButtonedEdit
Left = 190
Top = 36
Width = 320
Width = 324
Height = 22
Anchors = [akLeft, akTop, akRight]
Images = MainForm.VirtualImageListMain
@ -832,6 +839,20 @@ object connform: Tconnform
OnExit = editTrim
OnRightButtonClick = PickFile
end
object comboSSLVerification: TComboBox
Left = 190
Top = 145
Width = 324
Height = 22
Style = csDropDownList
Anchors = [akLeft, akTop, akRight]
TabOrder = 5
OnChange = Modification
Items.Strings = (
'No verification (insecure)'
'Verify CA'
'Verify CA and host name identity')
end
end
object tabStatistics: TTabSheet
Caption = 'Statistics'

View File

@ -138,6 +138,8 @@ type
timerEditFilterDelay: TTimer;
comboSSHExe: TComboBox;
chkSSHActive: TCheckBox;
comboSSLVerification: TComboBox;
lblSSLVerification: TLabel;
procedure FormCreate(Sender: TObject);
procedure btnOpenClick(Sender: TObject);
procedure FormShow(Sender: TObject);
@ -510,6 +512,7 @@ begin
Sess.SSLCertificate := editSSLCertificate.Text;
Sess.SSLCACertificate := editSSLCACertificate.Text;
Sess.SSLCipher := editSSLCipher.Text;
Sess.SSLVerification := comboSSLVerification.ItemIndex;
Sess.IgnoreDatabasePattern := editIgnoreDatabasePattern.Text;
Sess.LogFileDdl := chkLogFileDdl.Checked;
Sess.LogFileDml := chkLogFileDml.Checked;
@ -733,6 +736,7 @@ begin
Result.SSLCertificate := editSSLCertificate.Text;
Result.SSLCACertificate := editSSLCACertificate.Text;
Result.SSLCipher := editSSLCipher.Text;
Result.SSLVerification := comboSSLVerification.ItemIndex;
Result.StartupScriptFilename := editStartupScript.Text;
Result.Compressed := chkCompressed.Checked;
Result.QueryTimeout := updownQueryTimeout.Position;
@ -1033,6 +1037,7 @@ begin
editSSLCertificate.Text := Sess.SSLCertificate;
editSSLCACertificate.Text := Sess.SSLCACertificate;
editSSLCipher.Text := Sess.SSLCipher;
comboSSLVerification.ItemIndex := Sess.SSLVerification;
editIgnoreDatabasePattern.Text := Sess.IgnoreDatabasePattern;
chkLogFileDdl.Checked := Sess.LogFileDdl;
chkLogFileDml.Checked := Sess.LogFileDml;
@ -1439,6 +1444,7 @@ begin
or (Sess.SSLCertificate <> editSSLCertificate.Text)
or (Sess.SSLCACertificate <> editSSLCACertificate.Text)
or (Sess.SSLCipher <> editSSLCipher.Text)
or (Sess.SSLVerification <> comboSSLVerification.ItemIndex)
or (Sess.IgnoreDatabasePattern <> editIgnoreDatabasePattern.Text)
or (Sess.LogFileDdl <> chkLogFileDdl.Checked)
or (Sess.LogFileDml <> chkLogFileDml.Checked)
@ -1575,6 +1581,8 @@ begin
editSSLCertificate.Enabled := Params.WantSSL;
lblSSLcipher.Enabled := Params.WantSSL;
editSSLcipher.Enabled := Params.WantSSL;
lblSSLVerification.Enabled := Params.WantSSL;
comboSSLVerification.Enabled := Params.WantSSL;
lblQueryTimeout.Enabled := True;
editQueryTimeout.Enabled := lblQueryTimeout.Enabled;
updownQueryTimeout.Enabled := lblQueryTimeout.Enabled;

View File

@ -314,7 +314,7 @@ type
FSessionPath, FSSLPrivateKey, FSSLCertificate, FSSLCACertificate, FSSLCipher, FServerVersion,
FSSHHost, FSSHUser, FSSHPassword, FSSHExe, FSSHPrivateKey,
FIgnoreDatabasePattern: String;
FPort, FSSHPort, FSSHLocalPort, FSSHTimeout, FCounter, FQueryTimeout, FKeepAlive: Integer;
FPort, FSSHPort, FSSHLocalPort, FSSHTimeout, FCounter, FQueryTimeout, FKeepAlive, FSSLVerification: Integer;
FSSHActive, FLoginPrompt, FCompressed, FLocalTimeZone, FFullTableStatus,
FWindowsAuth, FWantSSL, FIsFolder, FCleartextPluginEnabled: Boolean;
FSessionColor: TColor;
@ -403,6 +403,7 @@ type
property SSLCertificate: String read FSSLCertificate write FSSLCertificate;
property SSLCACertificate: String read FSSLCACertificate write FSSLCACertificate;
property SSLCipher: String read FSSLCipher write FSSLCipher;
property SSLVerification: Integer read FSSLVerification write FSSLVerification;
property IgnoreDatabasePattern: String read FIgnoreDatabasePattern write FIgnoreDatabasePattern;
property LogFileDdl: Boolean read FLogFileDdl write FLogFileDdl;
property LogFileDml: Boolean read FLogFileDml write FLogFileDml;
@ -1421,6 +1422,7 @@ begin
FSSLCertificate := AppSettings.GetDefaultString(asSSLCert);
FSSLCACertificate := AppSettings.GetDefaultString(asSSLCA);
FSSLCipher := AppSettings.GetDefaultString(asSSLCipher);
FSSLVerification := AppSettings.GetDefaultInt(asSSLVerification);
FStartupScriptFilename := AppSettings.GetDefaultString(asStartupScriptFilename);
FQueryTimeout := AppSettings.GetDefaultInt(asQueryTimeout);
FKeepAlive := AppSettings.GetDefaultInt(asKeepAlive);
@ -1495,6 +1497,7 @@ begin
FSSLCertificate := AppSettings.ReadString(asSSLCert);
FSSLCACertificate := AppSettings.ReadString(asSSLCA);
FSSLCipher := AppSettings.ReadString(asSSLCipher);
FSSLVerification := AppSettings.ReadInt(asSSLVerification);
FStartupScriptFilename := AppSettings.ReadString(asStartupScriptFilename);
FQueryTimeout := AppSettings.ReadInt(asQueryTimeout);
FKeepAlive := AppSettings.ReadInt(asKeepAlive);
@ -1564,6 +1567,7 @@ begin
AppSettings.WriteString(asSSLCert, FSSLCertificate);
AppSettings.WriteString(asSSLCA, FSSLCACertificate);
AppSettings.WriteString(asSSLCipher, FSSLCipher);
AppSettings.WriteInt(asSSLVerification, FSSLVerification);
AppSettings.WriteString(asIgnoreDatabasePattern, FIgnoreDatabasePattern);
AppSettings.WriteBool(asLogFileDdl, FLogFileDdl);
AppSettings.WriteBool(asLogFileDml, FLogFileDml);
@ -2406,7 +2410,7 @@ end;
procedure TMySQLConnection.SetActive( Value: Boolean );
var
Connected: PMYSQL;
ClientFlags, FinalPort: Integer;
ClientFlags, FinalPort, SSLoption: Integer;
Error, StatusName: String;
FinalHost, FinalSocket, FinalUsername, FinalPassword: String;
ErrorHint: String;
@ -2450,6 +2454,22 @@ begin
if FParameters.SSLCipher <> '' then
SetOptionResult := SetOptionResult +
FLib.mysql_options(FHandle, FLib.MYSQL_OPT_SSL_CIPHER, PAnsiChar(AnsiString(FParameters.SSLCipher)));
if FParameters.SSLVerification in [1,2] then begin
// MySQL and MariaDB have different options for this
if FLib.MYSQL_OPT_SSL_MODE > TMySQLLib.INVALID_OPT then begin
if FParameters.SSLVerification = 1 then
SSLoption := FLib.SSL_MODE_VERIFY_CA
else
SSLoption := FLib.SSL_MODE_VERIFY_IDENTITY;
SetOptionResult := SetOptionResult +
FLib.mysql_options(FHandle, FLib.MYSQL_OPT_SSL_MODE, @SSLoption);
end
else begin
SSLoption := 1;
SetOptionResult := SetOptionResult +
FLib.mysql_options(FHandle, FLib.MYSQL_OPT_SSL_VERIFY_SERVER_CERT, @SSLoption);
end;
end;
if SetOptionResult = 0 then
Log(lcInfo, _('SSL parameters successfully set.'))
else
@ -2540,6 +2560,9 @@ begin
['libmysql']
);
end
else if Error.Contains('certificate verif') then begin
ErrorHint := _('You might need to lower the certificate verification in the SSL settings.');
end
else if (FParameters.DefaultLibrary <> '') and (FParameters.LibraryOrProvider <> FParameters.DefaultLibrary) then begin
ErrorHint := f_('You could try the default library %s in your session settings. (Current: %s)',
[FParameters.DefaultLibrary, FParameters.LibraryOrProvider]

View File

@ -290,6 +290,8 @@ type
mysql_thread_init: function: Byte; stdcall;
mysql_thread_end: procedure; stdcall;
mysql_warning_count: function(Handle: PMYSQL): Cardinal; stdcall;
const
INVALID_OPT = -1;
protected
procedure AssignProcedures; override;
public
@ -303,7 +305,11 @@ type
MYSQL_OPT_SSL_CA,
MYSQL_OPT_SSL_CIPHER,
MYSQL_OPT_CONNECT_ATTR_ADD,
MYSQL_ENABLE_CLEARTEXT_PLUGIN: Integer;
MYSQL_ENABLE_CLEARTEXT_PLUGIN,
MYSQL_OPT_SSL_MODE,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT: Integer;
SSL_MODE_VERIFY_CA,
SSL_MODE_VERIFY_IDENTITY: Integer;
constructor Create(DllFile, DefaultDll: String); override;
end;
var
@ -3113,6 +3119,10 @@ begin
MYSQL_OPT_CONNECT_TIMEOUT := 0;
MYSQL_OPT_LOCAL_INFILE := 8;
MARIADB_OPT_TLS_VERSION := 7005;
MYSQL_OPT_SSL_MODE := INVALID_OPT;
MYSQL_OPT_SSL_VERIFY_SERVER_CERT := INVALID_OPT;
SSL_MODE_VERIFY_CA := 4;
SSL_MODE_VERIFY_IDENTITY := 5;
if String(mysql_get_client_info).StartsWith('8.') then begin
MYSQL_PLUGIN_DIR := 16;
MYSQL_OPT_SSL_KEY := 19;
@ -3122,8 +3132,10 @@ begin
MYSQL_OPT_CONNECT_ATTR_ADD := 27;
MYSQL_ENABLE_CLEARTEXT_PLUGIN := 30;
MYSQL_OPT_TLS_VERSION := 34;
MYSQL_OPT_SSL_MODE := 35;
end
else begin
MYSQL_OPT_SSL_VERIFY_SERVER_CERT := 15;
MYSQL_PLUGIN_DIR := 22;
MYSQL_OPT_SSL_KEY := 25;
MYSQL_OPT_SSL_CERT := 26;