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
 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
 
 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:
 
 * 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 opusSampleRate = DEFAULT_OPUS_SAMPLE_RATE;
         int opusChannels = DEFAULT_OPUS_NUM_CHANNELS;
+        std::string cert_file = "";
+        std::string privkey_file = "";
         // 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)) { }
     };
 
+    /* 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 {
     public:
         Transport(io_service &ioService,
                   ProcessControlMessageFunction processControlMessageFunc,
                   ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
-                  bool noUdp = false);
+                  bool noUdp = false,
+                  std::string cert_file = "",
+                  std::string privkey_file = "");
 
         ~Transport();
 
@@ -48,6 +62,13 @@ namespace mumlib {
                      string user,
                      string password);
 
+        void connect(string host,
+                     int port,
+                     string user,
+                     string password,
+                     string cert_file,
+                     string privkey_file);
+
         void disconnect();
 
         ConnectionState getConnectionState() {
@@ -85,6 +106,7 @@ namespace mumlib {
         CryptState cryptState;
 
         ssl::context sslContext;
+        SslContextHelper sslContextHelper;
         ssl::stream<tcp::socket> sslSocket;
         uint8_t *sslIncomingBuffer;
 

+ 7 - 3
mumlib_example.cpp

@@ -39,8 +39,8 @@ int main(int argc, char *argv[]) {
     logger.setPriority(log4cpp::Priority::NOTICE);
     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;
     }
 
@@ -50,6 +50,10 @@ int main(int argc, char *argv[]) {
         try {
             mumlib::MumlibConfiguration conf;
             conf.opusEncoderBitrate = 32000;
+            if ( argc > 3 && argc <= 5 ) {
+                conf.cert_file = argv[3];
+                conf.privkey_file = argv[4];
+            }
             mumlib::Mumlib mum(myCallback, conf);
             myCallback.mum = &mum;
             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));
         }
     }
-}
+}

+ 15 - 1
src/Transport.cpp

@@ -29,7 +29,9 @@ mumlib::Transport::Transport(
         io_service &ioService,
         mumlib::ProcessControlMessageFunction processMessageFunc,
         ProcessEncodedAudioPacketFunction processEncodedAudioPacketFunction,
-        bool noUdp) :
+        bool noUdp,
+        std::string cert_file,
+        std::string privkey_file) :
         logger(log4cpp::Category::getInstance("mumlib.Transport")),
         ioService(ioService),
         processMessageFunction(std::move(processMessageFunc)),
@@ -38,6 +40,7 @@ mumlib::Transport::Transport(
         state(ConnectionState::NOT_CONNECTED),
         udpSocket(ioService),
         sslContext(ssl::context::sslv23),
+        sslContextHelper(sslContext, cert_file, privkey_file),
         sslSocket(ioService, sslContext),
         pingTimer(ioService, PING_INTERVAL),
         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);
 
+
     //todo for now it accepts every certificate, move it to callback
     sslSocket.set_verify_callback([](bool preverified, boost::asio::ssl::verify_context &ctx) {
         return true;
@@ -519,6 +523,16 @@ void mumlib::Transport::throwTransportException(string 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) {
     if (state != ConnectionState::CONNECTED) {
         logger.warn("Connection not established.");

+ 11 - 3
src/mumlib.cpp

@@ -43,12 +43,20 @@ namespace mumlib {
             externalIoService = false;
         }
 
-        _Mumlib_Private(Callback &callback, io_service &ioService, MumlibConfiguration &configuration)
+        _Mumlib_Private(
+                Callback &callback,
+                io_service &ioService,
+                MumlibConfiguration &configuration)
                 : callback(callback),
                   ioService(ioService),
                   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.setOpusEncoderBitrate(configuration.opusEncoderBitrate);