diff options
Diffstat (limited to 'Swiften/TLS')
-rw-r--r-- | Swiften/TLS/CertificateFactory.cpp | 23 | ||||
-rw-r--r-- | Swiften/TLS/CertificateFactory.h | 8 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp | 50 | ||||
-rw-r--r-- | Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h | 10 | ||||
-rw-r--r-- | Swiften/TLS/PrivateKey.cpp | 22 | ||||
-rw-r--r-- | Swiften/TLS/PrivateKey.h | 33 | ||||
-rw-r--r-- | Swiften/TLS/SConscript | 2 | ||||
-rw-r--r-- | Swiften/TLS/UnitTest/CertificateTest.cpp | 111 |
8 files changed, 252 insertions, 7 deletions
diff --git a/Swiften/TLS/CertificateFactory.cpp b/Swiften/TLS/CertificateFactory.cpp index 487f7cd..303bcf7 100644 --- a/Swiften/TLS/CertificateFactory.cpp +++ b/Swiften/TLS/CertificateFactory.cpp @@ -1,14 +1,35 @@ /* - * Copyright (c) 2010 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #include <Swiften/TLS/CertificateFactory.h> +#include <cassert> +#include <memory> +#include <sstream> +#include <string> + +#include <boost/algorithm/string/predicate.hpp> +#include <boost/optional.hpp> + +#include <Swiften/Base/Log.h> +#include <Swiften/StringCodecs/Base64.h> +#include <Swiften/TLS/PrivateKey.h> + namespace Swift { CertificateFactory::~CertificateFactory() { } +std::vector<Certificate::ref> CertificateFactory::createCertificateChain(const ByteArray& /* data */) { + assert(false); + return std::vector<Certificate::ref>(); +} + +PrivateKey::ref CertificateFactory::createPrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password) { + return std::make_shared<PrivateKey>(data, password); +} + } diff --git a/Swiften/TLS/CertificateFactory.h b/Swiften/TLS/CertificateFactory.h index 522a6e6..cb7fb6e 100644 --- a/Swiften/TLS/CertificateFactory.h +++ b/Swiften/TLS/CertificateFactory.h @@ -1,13 +1,17 @@ /* - * Copyright (c) 2010-2015 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ #pragma once +#include <boost/optional.hpp> + #include <Swiften/Base/API.h> +#include <Swiften/Base/SafeByteArray.h> #include <Swiften/TLS/Certificate.h> +#include <Swiften/TLS/PrivateKey.h> namespace Swift { class SWIFTEN_API CertificateFactory { @@ -15,5 +19,7 @@ namespace Swift { virtual ~CertificateFactory(); virtual Certificate* createCertificateFromDER(const ByteArray& der) = 0; + virtual std::vector<Certificate::ref> createCertificateChain(const ByteArray& data); + PrivateKey::ref createPrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password = boost::optional<SafeByteArray>()); }; } diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp new file mode 100644 index 0000000..c94702c --- /dev/null +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h> + +#include <openssl/pem.h> + +namespace Swift { + +OpenSSLCertificateFactory::OpenSSLCertificateFactory() { +} + +OpenSSLCertificateFactory::~OpenSSLCertificateFactory() { +} + +Certificate* OpenSSLCertificateFactory::createCertificateFromDER(const ByteArray& der) { + return new OpenSSLCertificate(der); +} + +std::vector<Certificate::ref> OpenSSLCertificateFactory::createCertificateChain(const ByteArray& data) { + std::vector<Certificate::ref> certificateChain; + + if (data.size() > std::numeric_limits<int>::max()) { + return certificateChain; + } + + auto bio = std::shared_ptr<BIO>(BIO_new(BIO_s_mem()), BIO_free); + BIO_write(bio.get(), vecptr(data), int(data.size())); + + // Attempt parsing data as PEM + X509* openSSLCert = nullptr; + auto x509certFromPEM = PEM_read_bio_X509(bio.get(), &openSSLCert, nullptr, nullptr); + if (x509certFromPEM && openSSLCert) { + std::shared_ptr<X509> x509Cert(openSSLCert, X509_free); + certificateChain.push_back(std::make_shared<OpenSSLCertificate>(x509Cert)); + openSSLCert = nullptr; + while ((x509certFromPEM = PEM_read_bio_X509(bio.get(), &openSSLCert, nullptr, nullptr)) != nullptr) { + std::shared_ptr<X509> x509Cert(openSSLCert, X509_free); + certificateChain.push_back(std::make_shared<OpenSSLCertificate>(x509Cert)); + openSSLCert = nullptr; + } + } + + return certificateChain; +} + +} diff --git a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h index c996cd5..af45a33 100644 --- a/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h +++ b/Swiften/TLS/OpenSSL/OpenSSLCertificateFactory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -12,8 +12,10 @@ namespace Swift { class OpenSSLCertificateFactory : public CertificateFactory { public: - virtual Certificate* createCertificateFromDER(const ByteArray& der) { - return new OpenSSLCertificate(der); - } + OpenSSLCertificateFactory(); + virtual ~OpenSSLCertificateFactory() override final; + + virtual Certificate* createCertificateFromDER(const ByteArray& der) override final; + virtual std::vector<Certificate::ref> createCertificateChain(const ByteArray& data) override final; }; } diff --git a/Swiften/TLS/PrivateKey.cpp b/Swiften/TLS/PrivateKey.cpp new file mode 100644 index 0000000..31cac1d --- /dev/null +++ b/Swiften/TLS/PrivateKey.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#include <Swiften/TLS/PrivateKey.h> + +namespace Swift { + +PrivateKey::PrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password) : data_(data), password_(password) { +} + +const SafeByteArray& PrivateKey::getData() const { + return data_; +} + +const boost::optional<SafeByteArray>& PrivateKey::getPassword() const { + return password_; +} + +} diff --git a/Swiften/TLS/PrivateKey.h b/Swiften/TLS/PrivateKey.h new file mode 100644 index 0000000..332fc48 --- /dev/null +++ b/Swiften/TLS/PrivateKey.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. + */ + +#pragma once + +#include <memory> + +#include <boost/optional.hpp> + +#include <Swiften/Base/SafeByteArray.h> +#include <Swiften/TLS/PrivateKey.h> + +namespace Swift { + +class PrivateKey { +public: + using ref = std::shared_ptr<PrivateKey>; + +public: + PrivateKey(const SafeByteArray& data, boost::optional<SafeByteArray> password = boost::optional<SafeByteArray>()); + + const SafeByteArray& getData() const; + const boost::optional<SafeByteArray>& getPassword() const; + +private: + SafeByteArray data_; + boost::optional<SafeByteArray> password_; +}; + +} diff --git a/Swiften/TLS/SConscript b/Swiften/TLS/SConscript index 68bf50b..ec9edd5 100644 --- a/Swiften/TLS/SConscript +++ b/Swiften/TLS/SConscript @@ -4,6 +4,7 @@ objects = swiften_env.SwiftenObject([ "Certificate.cpp", "CertificateFactory.cpp", "CertificateTrustChecker.cpp", + "PrivateKey.cpp", "ServerIdentityVerifier.cpp", "TLSContext.cpp", "TLSContextFactory.cpp", @@ -16,6 +17,7 @@ if myenv.get("HAVE_OPENSSL", 0) : "OpenSSL/OpenSSLContext.cpp", "OpenSSL/OpenSSLCertificate.cpp", "OpenSSL/OpenSSLContextFactory.cpp", + "OpenSSL/OpenSSLCertificateFactory.cpp", ]) myenv.Append(CPPDEFINES = "HAVE_OPENSSL") elif myenv.get("HAVE_SCHANNEL", 0) : diff --git a/Swiften/TLS/UnitTest/CertificateTest.cpp b/Swiften/TLS/UnitTest/CertificateTest.cpp index 2483dae..aac2cfb 100644 --- a/Swiften/TLS/UnitTest/CertificateTest.cpp +++ b/Swiften/TLS/UnitTest/CertificateTest.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2016 Isode Limited. + * Copyright (c) 2010-2018 Isode Limited. * All rights reserved. * See the COPYING file for more information. */ @@ -10,9 +10,12 @@ #include <cppunit/extensions/TestFactoryRegistry.h> #include <Swiften/Base/ByteArray.h> +#include <Swiften/Base/Platform.h> #include <Swiften/Crypto/CryptoProvider.h> #include <Swiften/Crypto/PlatformCryptoProvider.h> #include <Swiften/TLS/Certificate.h> +#include <Swiften/TLS/CertificateFactory.h> +#include <Swiften/TLS/PlatformTLSFactories.h> #include <Swiften/TLS/SimpleCertificate.h> using namespace Swift; @@ -20,6 +23,10 @@ using namespace Swift; class CertificateTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CertificateTest); CPPUNIT_TEST(testGetSHA1Fingerprint); +#ifdef HAVE_OPENSSL + CPPUNIT_TEST(testParsingPEMCertificate); +#endif + CPPUNIT_TEST(testParsingPEMPrivateKey); CPPUNIT_TEST_SUITE_END(); public: @@ -29,6 +36,108 @@ class CertificateTest : public CppUnit::TestFixture { CPPUNIT_ASSERT_EQUAL(std::string("2f:b5:e1:34:19:fc:89:24:68:65:e7:a3:24:f4:76:ec:62:4e:87:40"), Certificate::getSHA1Fingerprint(testling, std::shared_ptr<CryptoProvider>(PlatformCryptoProvider::create()).get())); } + + void testParsingPEMCertificate() { + PlatformTLSFactories tlsFactories; + + auto PEMCertificate = R"(-----BEGIN CERTIFICATE----- +MIIEsjCCApoCCQCbkjlQfUqPtTANBgkqhkiG9w0BAQsFADAbMRkwFwYDVQQDDBBt +b250YWd1ZS5leGFtcGxlMB4XDTE4MDExODE2NTMxMloXDTQ1MDYwNDE2NTMxMlow +GzEZMBcGA1UEAwwQbW9udGFndWUuZXhhbXBsZTCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBALAx5xuEYOjDJ9QHMvwRuDzxbHl1zR97SJFPAkmD8xH0sC61 +DNRyUvRq6UXb4znhqeqrNuZ9PV47GyK2Dpy/c/MY5NE3m/c+Z1tUnrcqyCkxITIn +jdSI/elc9yhtMXX6lRi68BdPJnj/9+6trW0cWHlKEgnaSTAgCVB+4Dg9mjTIroCa +HLoAKhr2zS7Ihs28aWb0cSvZ+qFgQhr7FGP2kfssTTQYyRPn9uHhtyWH6RqSv5x9 +BBGZWN5GtjkJvupcYWLt8ftuQyFpwEeEz5cgtiyKgsfz9CYvS9/OcwdLQr4z5Zq6 +eKxsog9GdwIi1Us4KR0X6tKu9ze42iEWF+foEWFP9/bjrVK/tt5lTSKnenk0nA8I +amkG0btNAGihDti3lv60bGpd3B2/uh4gzzT2buXdf0EaybCt52MIr8xkwMU0Tkri +RAYchdS8U8sekWG5Lg9m3L2BDa8/TKS/WflJhGcZeInGQslgIx7fCgO1M7Zr50pO +wSURPXpvqUkXNEBy639UQEUsnBhntEQwZWx/6x6Ma/U5a5dL6qbtEJjlwIvS+nl9 +3w26g3DvWydNMCtZIVhgdrl+dZs+Uw5eA3QkHkDTSfYvQk7X5SYL0J5ZxwBvU9r1 +ED054+TAEuX2euiRA37xLhxonj8BaKkPQGlAHCLZaZPmNJWkNxElJhMoCfqBAgMB +AAEwDQYJKoZIhvcNAQELBQADggIBAF+FNyW3nVeQeugBMksIhj7EMJl1AEKi0+78 +ZPsYX3CDbc/8GRZoTg/EWSiwPCBYc9VsxuKtODEYABCZgk7LnSBYoEauJDKWqkgM +UOKPJI2hu7mIK7FJpjvEZe2MnRRA63oI/NVDJm8T2clrv/vPkY+ppsVl0toC0SpH +/3dF5c65vYI19rTJraRU6kIrrgxFBzxzpn07LGh2rrOCQfy2umTSRMwz3ORAFfmi ++Kek1Dt7c+JVJ0ivCwhhc8MKza3JS2MuDfVWGnXtDLb81Ai0t4tQfLKvZEcgW+lh +Drz9gv22buwncWL/IxtuhzyILtDSDKAYFbhfG6IAQut9BjMgpMnKrBCDlOLJl08K +tgj2h7vUKyNSt3ndcSAtXjr6FD7+xPExJuyn/MgLONGGAZoZHFB4QO90wQaXxMPh +7rnjUtzfLR8qkDmX8ZB4f4VOWpDWo4hBpgjTk0gYfzEkrh+zTqE9reh7CZ1WzwXO +KnIBU2dZOE+XsJe49lW106DLqGzKRuQMUAwFMb7C7Nlg9GKTnvi41o+g6YE+MgxR +uPKu891pCBtnDxZiWPT+7Fa/9UXxdIOTVIHW6utSWiWYbeNwXSmIm2ShfmNfWj9m +x1JgJrFB6daWGR9aDBeDVRhgL6Z35lH7xI62pLJ4o2d2Y/9dUWAJfz5O8opeCyrF +zqCzpwGL +-----END CERTIFICATE----- +)"; + + auto certificateChain = tlsFactories.getCertificateFactory()->createCertificateChain(createByteArray(PEMCertificate)); + CPPUNIT_ASSERT_EQUAL(size_t(1), certificateChain.size()); + + auto certificate = certificateChain[0]; + CPPUNIT_ASSERT_EQUAL(std::string("/CN=montague.example"), certificate->getSubjectName()); + } + + void testParsingPEMPrivateKey() { + PlatformTLSFactories tlsFactories; + + auto PEMPrivateKey = R"(-----BEGIN PRIVATE KEY----- +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 +5IMXuORWuoq0gXiCdEyko+saXsyWlqw= +-----END PRIVATE KEY----- +)"; + + auto privateKey = tlsFactories.getCertificateFactory()->createPrivateKey(createSafeByteArray(PEMPrivateKey)); + + CPPUNIT_ASSERT(privateKey != nullptr); + } }; CPPUNIT_TEST_SUITE_REGISTRATION(CertificateTest); |