Browse Source

add initial support for client certs

Scott Hardin 7 years ago
parent
commit
e402d62f33
6 changed files with 61 additions and 9 deletions
  1. 3 1
      README.md
  2. 2 0
      include/mumlib.hpp
  3. 23 1
      include/mumlib/Transport.hpp
  4. 7 3
      mumlib_example.cpp
  5. 15 1
      src/Transport.cpp
  6. 11 3
      src/mumlib.cpp

+ 3 - 1
README.md

@@ -35,6 +35,8 @@ make
 Sample usage is covered in *mumlib_example.cpp* file. Basically, you should extend *mumlib::Callback* class
 Sample usage is covered in *mumlib_example.cpp* file. Basically, you should extend *mumlib::Callback* class
 to implement your own handlers.
 to implement your own handlers.
 
 
+To use a client certificate, you'll need a PEM certificate and private key without a passphrase. These are assed in the MumlibConfig struct to the Mumlib object constructor. Support for passphrase still needs to be added.
+
 ## Credits
 ## Credits
 
 
 2015 Michał Słomkowski. The code is published under the terms of Lesser General Public License Version 3.
 2015 Michał Słomkowski. The code is published under the terms of Lesser General Public License Version 3.
@@ -42,4 +44,4 @@ to implement your own handlers.
 The library contains code from following 3rd party projects:
 The library contains code from following 3rd party projects:
 
 
 * official Mumble Client: https://github.com/mumble-voip/mumble
 * official Mumble Client: https://github.com/mumble-voip/mumble
-* *libmumble*: https://github.com/cornejo/libmumble
+* *libmumble*: https://github.com/cornejo/libmumble

+ 2 - 0
include/mumlib.hpp

@@ -26,6 +26,8 @@ namespace mumlib {
         int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE;
         int opusEncoderBitrate = DEFAULT_OPUS_ENCODER_BITRATE;
         int opusSampleRate = DEFAULT_OPUS_SAMPLE_RATE;
         int opusSampleRate = DEFAULT_OPUS_SAMPLE_RATE;
         int opusChannels = DEFAULT_OPUS_NUM_CHANNELS;
         int opusChannels = DEFAULT_OPUS_NUM_CHANNELS;
+        std::string cert_file = "";
+        std::string privkey_file = "";
         // additional fields will be added in the future
         // additional fields will be added in the future
     };
     };
 
 

+ 23 - 1
include/mumlib/Transport.hpp

@@ -34,12 +34,26 @@ namespace mumlib {
         TransportException(string message) : MumlibException(std::move(message)) { }
         TransportException(string message) : MumlibException(std::move(message)) { }
     };
     };
 
 
+    /* This helper is needed because the sslContext and sslSocket are initialized in
+     * the Transport constructor and there wasn't an easier way of passing these two
+     * arguments.
+     * TODO: add support for password callback.
+     */
+    class SslContextHelper : boost::noncopyable {
+        public:
+            SslContextHelper(boost::asio::ssl::context &ctx,
+                    std::string cert_file, std::string privkey_file);
+            ~SslContextHelper() { };
+    };
+
     class Transport : boost::noncopyable {
     class Transport : boost::noncopyable {
     public:
     public:
         Transport(io_service &ioService,
         Transport(io_service &ioService,
                   ProcessControlMessageFunction processControlMessageFunc,
                   ProcessControlMessageFunction processControlMessageFunc,
                   ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
                   ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
-                  bool noUdp = false);
+                  bool noUdp = false,
+                  std::string cert_file = "",
+                  std::string privkey_file = "");
 
 
         ~Transport();
         ~Transport();
 
 
@@ -48,6 +62,13 @@ namespace mumlib {
                      string user,
                      string user,
                      string password);
                      string password);
 
 
+        void connect(string host,
+                     int port,
+                     string user,
+                     string password,
+                     string cert_file,
+                     string privkey_file);
+
         void disconnect();
         void disconnect();
 
 
         ConnectionState getConnectionState() {
         ConnectionState getConnectionState() {
@@ -85,6 +106,7 @@ namespace mumlib {
         CryptState cryptState;
         CryptState cryptState;
 
 
         ssl::context sslContext;
         ssl::context sslContext;
+        SslContextHelper sslContextHelper;
         ssl::stream<tcp::socket> sslSocket;
         ssl::stream<tcp::socket> sslSocket;
         uint8_t *sslIncomingBuffer;
         uint8_t *sslIncomingBuffer;
 
 

+ 7 - 3
mumlib_example.cpp

@@ -39,8 +39,8 @@ int main(int argc, char *argv[]) {
     logger.setPriority(log4cpp::Priority::NOTICE);
     logger.setPriority(log4cpp::Priority::NOTICE);
     logger.addAppender(appender1);
     logger.addAppender(appender1);
 
 
-    if (argc < 3) {
-        logger.crit("Usage: %s {server} {password}", argv[0]);
+    if (argc < 3 || argc == 4 || argc > 5) {
+        logger.crit("Usage: %s {server} {password} [{certfile} {keyfile}]", argv[0]);
         return 1;
         return 1;
     }
     }
 
 
@@ -50,6 +50,10 @@ int main(int argc, char *argv[]) {
         try {
         try {
             mumlib::MumlibConfiguration conf;
             mumlib::MumlibConfiguration conf;
             conf.opusEncoderBitrate = 32000;
             conf.opusEncoderBitrate = 32000;
+            if ( argc > 3 && argc <= 5 ) {
+                conf.cert_file = argv[3];
+                conf.privkey_file = argv[4];
+            }
             mumlib::Mumlib mum(myCallback, conf);
             mumlib::Mumlib mum(myCallback, conf);
             myCallback.mum = &mum;
             myCallback.mum = &mum;
             mum.connect(argv[1], 64738, "mumlib_example", argv[2]);
             mum.connect(argv[1], 64738, "mumlib_example", argv[2]);
@@ -61,4 +65,4 @@ int main(int argc, char *argv[]) {
             std::this_thread::sleep_for(std::chrono::seconds(5));
             std::this_thread::sleep_for(std::chrono::seconds(5));
         }
         }
     }
     }
-}
+}

+ 15 - 1
src/Transport.cpp

@@ -29,7 +29,9 @@ mumlib::Transport::Transport(
         io_service &ioService,
         io_service &ioService,
         mumlib::ProcessControlMessageFunction processMessageFunc,
         mumlib::ProcessControlMessageFunction processMessageFunc,
         ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
         ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
-        bool noUdp) :
+        bool noUdp,
+        std::string cert_file,
+        std::string privkey_file) :
         logger(log4cpp::Category::getInstance("mumlib.Transport")),
         logger(log4cpp::Category::getInstance("mumlib.Transport")),
         ioService(ioService),
         ioService(ioService),
         processMessageFunction(std::move(processMessageFunc)),
         processMessageFunction(std::move(processMessageFunc)),
@@ -38,6 +40,7 @@ mumlib::Transport::Transport(
         state(ConnectionState::NOT_CONNECTED),
         state(ConnectionState::NOT_CONNECTED),
         udpSocket(ioService),
         udpSocket(ioService),
         sslContext(ssl::context::sslv23),
         sslContext(ssl::context::sslv23),
+        sslContextHelper(sslContext, cert_file, privkey_file),
         sslSocket(ioService, sslContext),
         sslSocket(ioService, sslContext),
         pingTimer(ioService, PING_INTERVAL),
         pingTimer(ioService, PING_INTERVAL),
         asyncBufferPool(static_cast<const unsigned long>(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH))) {
         asyncBufferPool(static_cast<const unsigned long>(max(MAX_UDP_LENGTH, MAX_TCP_LENGTH))) {
@@ -67,6 +70,7 @@ void mumlib::Transport::connect(
 
 
     sslSocket.set_verify_mode(boost::asio::ssl::verify_peer);
     sslSocket.set_verify_mode(boost::asio::ssl::verify_peer);
 
 
+
     //todo for now it accepts every certificate, move it to callback
     //todo for now it accepts every certificate, move it to callback
     sslSocket.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx) {
     sslSocket.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx) {
         return true;
         return true;
@@ -519,6 +523,16 @@ void mumlib::Transport::throwTransportException(string message) {
     throw TransportException(std::move(message));
     throw TransportException(std::move(message));
 }
 }
 
 
+mumlib::SslContextHelper::SslContextHelper(ssl::context &ctx, std::string cert_file, std::string privkey_file) {
+    if ( cert_file.size() > 0 ) {
+        ctx.use_certificate_file(cert_file, ssl::context::file_format::pem);
+    }
+    if ( privkey_file.size() > 0 ) {
+        ctx.use_private_key_file(privkey_file, ssl::context::file_format::pem);
+    }
+}
+
+
 void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) {
 void mumlib::Transport::sendEncodedAudioPacket(uint8_t *buffer, int length) {
     if (state != ConnectionState::CONNECTED) {
     if (state != ConnectionState::CONNECTED) {
         logger.warn("Connection not established.");
         logger.warn("Connection not established.");

+ 11 - 3
src/mumlib.cpp

@@ -43,12 +43,20 @@ namespace mumlib {
             externalIoService = false;
             externalIoService = false;
         }
         }
 
 
-        _Mumlib_Private(Callback &callback, io_service &ioService, MumlibConfiguration &configuration)
+        _Mumlib_Private(
+                Callback &callback,
+                io_service &ioService,
+                MumlibConfiguration &configuration)
                 : callback(callback),
                 : callback(callback),
                   ioService(ioService),
                   ioService(ioService),
                   externalIoService(true),
                   externalIoService(true),
-                  transport(ioService, boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3),
-                            boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3)),
+                  transport(
+                          ioService,
+                          boost::bind(&_Mumlib_Private::processIncomingTcpMessage, this, _1, _2, _3),
+                          boost::bind(&_Mumlib_Private::processAudioPacket, this, _1, _2, _3),
+                          false,
+                          configuration.cert_file,
+                          configuration.privkey_file),
                   audio(configuration.opusSampleRate, configuration.opusEncoderBitrate, configuration.opusChannels) {
                   audio(configuration.opusSampleRate, configuration.opusEncoderBitrate, configuration.opusChannels) {
 
 
             audio.setOpusEncoderBitrate(configuration.opusEncoderBitrate);
             audio.setOpusEncoderBitrate(configuration.opusEncoderBitrate);