[smuxi: 18/26] Engine(-IRC), Frontend-GNOME: support CertFP (closes: #96)
- From: Mirco M. M. Bauer <mmmbauer src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [smuxi: 18/26] Engine(-IRC), Frontend-GNOME: support CertFP (closes: #96)
- Date: Wed, 14 Oct 2015 16:51:00 +0000 (UTC)
commit 83a2ab1c3e64ef4438b8e901891270f65566ea95
Author: Mirco Bauer <meebey meebey net>
Date: Sun Jan 12 08:26:40 2014 +0100
Engine(-IRC), Frontend-GNOME: support CertFP (closes: #96)
[CertFP][] is a NickServ authentication feature supported by modern IRC networks
as an more secure alternative to the famous "/msg NickServ IDENTIFY my_password"
command.
[CertFP]: https://freenode.net/certfp/
As this is an internal setting only (for now) you need to configure it using
the /config command like this:
/config Servers/IRC/$SERVER_ID/ClientCertificateFilename = mycert.pfx
/config save
The client certificate can be generated using makecert like this:
makecert -eku 1.3.6.1.5.5.7.3.2 -r -cy end -n "CN=$USER" -p12 mycert.pfx ""
The certificate must not use a passphrase, else it can't be loaded. Thus secure
the file against access by other users with:
chmod 400 mycert.pfx
Place the certificate in ~/.config/smuxi/certs/ otherwise specify the full path
in ClientCertificateFilename.
On most IRC networks that support CertFP you can verify if the certificate was
used using /whois on your own nickname. A line like this should show up in the
whois reply:
[276 (?) meebey3] has client certificate fingerprint a15aecab43e1d0965a2da43739a9628d790994e0
Special thanks goes to An-Ivoz for finding out how client certificate selection
works!
src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs | 36 ++++++++++++++++++++
src/Engine/Config/Config.cs | 1 +
src/Engine/Config/ServerModel.cs | 13 +++++++
src/Frontend-GNOME/Views/MenuWidget.cs | 1 +
4 files changed, 51 insertions(+), 0 deletions(-)
---
diff --git a/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
b/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
index 0b2584d..d85da5d 100644
--- a/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
+++ b/src/Engine-IRC/Protocols/Irc/IrcProtocolManager.cs
@@ -21,6 +21,7 @@
*/
using System;
+using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Security.Cryptography.X509Certificates;
@@ -2584,6 +2585,41 @@ namespace Smuxi.Engine
if (server != null) {
_IrcClient.UseSsl = server.UseEncryption;
_IrcClient.ValidateServerCertificate = server.ValidateServerCertificate;
+ if (String.IsNullOrEmpty(server.ClientCertificateFilename)) {
+ _IrcClient.SslClientCertificate = null;
+ } else {
+ var certFile = server.ClientCertificateFilename;
+ if (!Path.IsPathRooted(certFile)) {
+ var configPath = Environment.GetFolderPath(
+ Environment.SpecialFolder.ApplicationData
+ );
+ configPath = Path.Combine(configPath, "smuxi");
+ var certPath = Path.Combine(configPath, "certs");
+ certFile = Path.Combine(certPath, certFile);
+ }
+ var certType = X509Certificate2.GetCertContentType(certFile);
+ if (certType != X509ContentType.Unknown) {
+ var cert = new X509Certificate2();
+ cert.Import(certFile, "", X509KeyStorageFlags.PersistKeySet);
+ if (cert.PublicKey == null) {
+#if LOG4NET
+ _Logger.ErrorFormat(
+ "ApplyConfig(): client certificate {0} does " +
+ "not contain a public key!", certFile
+ );
+#endif
+ }
+ if (cert.PrivateKey == null) {
+#if LOG4NET
+ _Logger.ErrorFormat(
+ "ApplyConfig(): client certificate {0} does " +
+ "not contain a private key!", certFile
+ );
+#endif
+ }
+ _IrcClient.SslClientCertificate = cert;
+ }
+ }
}
}
diff --git a/src/Engine/Config/Config.cs b/src/Engine/Config/Config.cs
index 0441882..6509d30 100644
--- a/src/Engine/Config/Config.cs
+++ b/src/Engine/Config/Config.cs
@@ -617,6 +617,7 @@ namespace Smuxi.Engine
LoadEntry(sprefix+"Password", String.Empty);
LoadEntry(sprefix+"UseEncryption", false);
LoadEntry(sprefix+"ValidateServerCertificate", false);
+ LoadEntry(sprefix+"ClientCertificateFilename", String.Empty);
LoadEntry(sprefix+"OnStartupConnect", false);
string[] commands = GetList(sprefix + "OnConnectCommands");
if (commands == null) {
diff --git a/src/Engine/Config/ServerModel.cs b/src/Engine/Config/ServerModel.cs
index 1cde243..1c753c1 100644
--- a/src/Engine/Config/ServerModel.cs
+++ b/src/Engine/Config/ServerModel.cs
@@ -32,6 +32,7 @@ namespace Smuxi.Engine
{
public bool UseEncryption { get; set; }
public bool ValidateServerCertificate { get; set; }
+ public string ClientCertificateFilename { get; set; }
public string Protocol { get; set; }
public string Hostname { get; set; }
public int Port { get; set; }
@@ -100,6 +101,9 @@ namespace Smuxi.Engine
ValidateServerCertificate = (bool)e.Value;
foundValidation = true;
break;
+ case "ClientCertificateFilename":
+ ClientCertificateFilename = (string) e.Value;
+ break;
}
}
if (foundServerID == false) {
@@ -132,6 +136,12 @@ namespace Smuxi.Engine
if (Realname != null) {
info.AddValue("_Realname", Realname);
}
+ // HACK: skip ClientCertificateFilename if it has no value as it
+ // breaks older ServerModel implementations that relied on automatic
+ // serialization which was the case in < 0.8.11
+ if (String.IsNullOrEmpty(ClientCertificateFilename)) {
+ info.AddValue("ClientCertificateFilename", ClientCertificateFilename);
+ }
info.AddValue("_Protocol", Protocol);
info.AddValue("_Hostname", Hostname);
info.AddValue("_Port", Port);
@@ -175,6 +185,7 @@ namespace Smuxi.Engine
UseEncryption = (bool) config[ConfigKeyPrefix + "UseEncryption"];
ValidateServerCertificate =
(bool) config[ConfigKeyPrefix + "ValidateServerCertificate"];
+ ClientCertificateFilename = (string) config[ConfigKeyPrefix + "ClientCertificateFilename"];
if (config[ConfigKeyPrefix + "OnStartupConnect"] != null) {
OnStartupConnect = (bool) config[ConfigKeyPrefix + "OnStartupConnect"];
}
@@ -196,6 +207,8 @@ namespace Smuxi.Engine
config[ConfigKeyPrefix + "UseEncryption"] = UseEncryption;
config[ConfigKeyPrefix + "ValidateServerCertificate"] =
ValidateServerCertificate;
+ config[ConfigKeyPrefix + "ClientCertificateFilename"] =
+ ClientCertificateFilename;
config[ConfigKeyPrefix + "OnStartupConnect"] = OnStartupConnect;
config[ConfigKeyPrefix + "OnConnectCommands"] = OnConnectCommands;
}
diff --git a/src/Frontend-GNOME/Views/MenuWidget.cs b/src/Frontend-GNOME/Views/MenuWidget.cs
index 829ebab..0a2af64 100644
--- a/src/Frontend-GNOME/Views/MenuWidget.cs
+++ b/src/Frontend-GNOME/Views/MenuWidget.cs
@@ -227,6 +227,7 @@ namespace Smuxi.Frontend.Gnome
server.ServerID = null;
server.Nickname = null;
server.Realname = null;
+ server.ClientCertificateFilename = null;
}
Frontend.Session.Connect(server, Frontend.FrontendManager);
} catch (Exception ex) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]