From b5ae8c3a9ec236321d705f9a79234777fc28b5fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Thu, 30 Dec 2010 20:19:42 +0100
Subject: Show certificate fingerprint in 'Trust certificate' dialog.


diff --git a/Swift/QtUI/QtLoginWindow.cpp b/Swift/QtUI/QtLoginWindow.cpp
index 37ac755..4a54152 100644
--- a/Swift/QtUI/QtLoginWindow.cpp
+++ b/Swift/QtUI/QtLoginWindow.cpp
@@ -401,7 +401,8 @@ bool QtLoginWindow::askUserToTrustCertificatePermanently(const String& message,
 	dialog.setText("The certificate presented by the server is not valid.");
 	dialog.setInformativeText(P2QSTRING(message) + "\n\nWould you like to permanently trust this certificate? This must only be done if you know it is correct.");
 
-	QString detailedText = "Subject: " + P2QSTRING(certificate->getSubjectName());
+	QString detailedText = "Subject: " + P2QSTRING(certificate->getSubjectName()) + "\n";
+	detailedText += "SHA-1 Fingerprint: " + P2QSTRING(certificate->getSHA1Fingerprint());
 	dialog.setDetailedText(detailedText);
 
 	dialog.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
diff --git a/Swiften/SConscript b/Swiften/SConscript
index a4eb75d..a9b6f41 100644
--- a/Swiften/SConscript
+++ b/Swiften/SConscript
@@ -290,6 +290,7 @@ if env["SCONS_STAGE"] == "build" :
 			File("StringCodecs/UnitTest/HMACSHA1Test.cpp"),
 			File("StringCodecs/UnitTest/PBKDF2Test.cpp"),
 			File("TLS/UnitTest/ServerIdentityVerifierTest.cpp"),
+			File("TLS/UnitTest/CertificateTest.cpp"),
 			File("VCards/UnitTest/VCardManagerTest.cpp"),
 		])
 	
diff --git a/Swiften/StringCodecs/Hexify.cpp b/Swiften/StringCodecs/Hexify.cpp
index 8259912..c762d9b 100644
--- a/Swiften/StringCodecs/Hexify.cpp
+++ b/Swiften/StringCodecs/Hexify.cpp
@@ -15,6 +15,12 @@
 
 namespace Swift {
 
+String Hexify::hexify(unsigned char byte) {
+	std::ostringstream result;
+	result << std::hex << std::setw(2) << std::setfill('0') << boost::numeric_cast<unsigned int>(byte);
+	return String(result.str());
+}
+
 String Hexify::hexify(const ByteArray& data) {
 	std::ostringstream result;
 	result << std::hex;
diff --git a/Swiften/StringCodecs/Hexify.h b/Swiften/StringCodecs/Hexify.h
index cf51bda..5eaabda 100644
--- a/Swiften/StringCodecs/Hexify.h
+++ b/Swiften/StringCodecs/Hexify.h
@@ -12,6 +12,7 @@ namespace Swift {
 
 	class Hexify {
 		public:
+			static String hexify(unsigned char byte);
 			static String hexify(const ByteArray& data);
 	};
 }
diff --git a/Swiften/StringCodecs/UnitTest/HexifyTest.cpp b/Swiften/StringCodecs/UnitTest/HexifyTest.cpp
index 760d661..4ed871a 100644
--- a/Swiften/StringCodecs/UnitTest/HexifyTest.cpp
+++ b/Swiften/StringCodecs/UnitTest/HexifyTest.cpp
@@ -16,12 +16,17 @@ using namespace Swift;
 class HexifyTest : public CppUnit::TestFixture {
 		CPPUNIT_TEST_SUITE(HexifyTest);
 		CPPUNIT_TEST(testHexify);
+		CPPUNIT_TEST(testHexify_Byte);
 		CPPUNIT_TEST_SUITE_END();
 
 	public:
 		void testHexify() {
 			CPPUNIT_ASSERT_EQUAL(String("4206b23ca6b0a643d20d89b04ff58cf78b8096ed"), Hexify::hexify(ByteArray("\x42\x06\xb2\x3c\xa6\xb0\xa6\x43\xd2\x0d\x89\xb0\x4f\xf5\x8c\xf7\x8b\x80\x96\xed")));
 		}
+
+		void testHexify_Byte() {
+			CPPUNIT_ASSERT_EQUAL(String("b2"), Hexify::hexify(0xb2));
+		}
 };
 
 CPPUNIT_TEST_SUITE_REGISTRATION(HexifyTest);
diff --git a/Swiften/TLS/Certificate.cpp b/Swiften/TLS/Certificate.cpp
index 7d61b22..984d668 100644
--- a/Swiften/TLS/Certificate.cpp
+++ b/Swiften/TLS/Certificate.cpp
@@ -4,7 +4,12 @@
  * See Documentation/Licenses/GPLv3.txt for more information.
  */
 
-#include "Swiften/TLS/Certificate.h"
+#include <Swiften/TLS/Certificate.h>
+
+#include <sstream>
+
+#include <Swiften/StringCodecs/SHA1.h>
+#include <Swiften/StringCodecs/Hexify.h>
 
 namespace Swift {
 
@@ -14,4 +19,16 @@ const char* Certificate::ID_ON_DNSSRV_OID = "1.3.6.1.5.5.7.8.7";
 Certificate::~Certificate() {
 }
 
+String Certificate::getSHA1Fingerprint() const {
+	ByteArray hash = SHA1::getHash(toDER());
+	std::ostringstream s;
+	for (size_t i = 0; i < hash.getSize(); ++i) {
+		if (i > 0) {
+			s << ":";
+		}
+		s << Hexify::hexify(hash[i]).getUTF8String();
+	}
+	return String(s.str());
+}
+
 }
diff --git a/Swiften/TLS/Certificate.h b/Swiften/TLS/Certificate.h
index 89c1de6..e01aa74 100644
--- a/Swiften/TLS/Certificate.h
+++ b/Swiften/TLS/Certificate.h
@@ -31,6 +31,8 @@ namespace Swift {
 
 			virtual ByteArray toDER() const = 0;
 
+			virtual String getSHA1Fingerprint() const;
+
 		protected:
 			static const char* ID_ON_XMPPADDR_OID;
 			static const char* ID_ON_DNSSRV_OID;
diff --git a/Swiften/TLS/SimpleCertificate.h b/Swiften/TLS/SimpleCertificate.h
index 2db8291..7af8530 100644
--- a/Swiften/TLS/SimpleCertificate.h
+++ b/Swiften/TLS/SimpleCertificate.h
@@ -55,7 +55,11 @@ namespace Swift {
 			}
 
 			ByteArray toDER() const {
-				return ByteArray();
+				return der;
+			}
+
+			void setDER(const ByteArray& der) {
+				this->der = der;
 			}
 
 		private:
@@ -63,6 +67,7 @@ namespace Swift {
 
 		private:
 			String subjectName;
+			ByteArray der;
 			std::vector<String> commonNames;
 			std::vector<String> dnsNames;
 			std::vector<String> xmppAddresses;
diff --git a/Swiften/TLS/UnitTest/CertificateTest.cpp b/Swiften/TLS/UnitTest/CertificateTest.cpp
new file mode 100644
index 0000000..b5e69c3
--- /dev/null
+++ b/Swiften/TLS/UnitTest/CertificateTest.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+
+#include <Swiften/Base/ByteArray.h>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <boost/smart_ptr/make_shared.hpp>
+
+#include <Swiften/TLS/Certificate.h>
+#include <Swiften/TLS/SimpleCertificate.h>
+
+using namespace Swift;
+
+class CertificateTest : public CppUnit::TestFixture {
+		CPPUNIT_TEST_SUITE(CertificateTest);
+		CPPUNIT_TEST(testGetSHA1Fingerprint);
+		CPPUNIT_TEST_SUITE_END();
+
+	public:
+		void testGetSHA1Fingerprint() {
+			SimpleCertificate::ref testling = boost::make_shared<SimpleCertificate>();
+			testling->setDER(ByteArray("abcdefg"));
+
+			CPPUNIT_ASSERT_EQUAL(String("2f:b5:e1:34:19:fc:89:24:68:65:e7:a3:24:f4:76:ec:62:4e:87:40"), testling->getSHA1Fingerprint());
+		}
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CertificateTest);
-- 
cgit v0.10.2-6-g49f6