Android上的本地HTTPS服务器与客户端认证

5
我需要创建一个密钥分发服务器,这只是一个本地服务器,通过DRM提供商的API获取AES密钥并将其返回给连接的客户端。客户端可以是基于FFmpeg库的我的媒体播放器或本机的Android媒体播放器。
我已经在Windows上使用Boost ASIO库和OpenSSL进行了实验 - 有一个示例展示如何创建简单的HTTPS服务器和客户端。在我的情况下,我必须仅允许专用应用程序/客户端访问服务器,因此需要客户端认证。对于我这种不是这种行业专家的人来说,有一些事情还不太清楚。
我知道HTTPS服务器必须要求客户端进行身份验证,客户端应该发送其证书,然后服务器读取并验证证书中的某些数据。
问题是:
- 客户端需要哪种类型的证书,我应该如何创建它? - 服务器需要哪种类型的证书,我应该如何创建它? - 我应该将客户端证书存储在哪里,以使其对客户端(FFmpeg、Android MediaPlayer)可访问?它不应该对任何其他应用程序可见。 - 我应该将服务器证书存储在哪里?
我所写的所有内容都在本地级别执行,即由Linux共享库实现。这就是为什么我认为这是一个针对Linux高手而不是普通Android开发人员的问题。
有人能简要解释一下如何做到这一点吗?如果可能的话,欢迎任何提示!
非常感谢!

你用什么语言编写这个程序? - Bob Bryan
我正在使用C/C++进行编写。 - vitakot
1个回答

2
首先,服务器不会要求客户端提供证书,而是相反。客户端可以(但并非总是)从服务器请求证书。从您的问题措辞来看,似乎您可能不需要使用证书。否则,请参阅此link以获取更多信息。服务器通常需要对客户端进行身份验证,但这通常是通过在安全连接建立后向服务器传递用户名/密码消息来完成的。您需要编写代码来处理服务器和客户端上的身份验证。
以下是我用于通过SSL连接到服务器的一些代码:
void SSLSocket::Connect(SSLSocket* psSLS, const string& serverPath, string& port)
{
   // Connects to the server.
   // serverPath - specifies the path to the server.  Can be either an ip address or url.
   // port - port server is listening on.
   //
   try
   {
      boost::shared_ptr<boost::asio::io_service> IOServ(new boost::asio::io_service);
      IOService = IOServ; // Defined the same way in the class
      Locking CodeLock(SocketLock); // Single thread the code.
      // If the user has tried to connect before, then make sure everything is clean before trying to do so again.
      if (pSocket)
      {
         delete pSocket;
         pSocket = 0;
      }                                                                                                  
      // Create the resolver and query objects to resolve the host name in serverPath to an ip address.
      boost::asio::ip::tcp::resolver resolver(*IOService);
      boost::asio::ip::tcp::resolver::query query(serverPath, port);
      boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query);
      // Set up an SSL context.
      boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
      // Specify to not verify the server certificiate right now.
      ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
      // Init the socket object used to initially communicate with the server.
      pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
      //
      // The thread we are on now, is most likely the user interface thread.  Create a thread to handle all incoming and outgoing socket work messages.
      if (!RcvThreadCreated)
      {
         WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
         RcvThreadCreated = true;
         WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
      }
      // Try to connect to the server.  Note - add timeout logic at some point.
      // This is an async method and will return right away.  When it completes, the
      // SSLSocket::HandleConnect method will be called and will contain error info to
      // identify if a successful connection was made or not.
      boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator,
         boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
}

void SSLSocket::HandleConnect(const boost::system::error_code& error)
{
   // This method is called asynchronously when the server has responded to the connect request.
   std::stringstream ss;
   try
   {
      if (!error)
      {
         pSocket->async_handshake(boost::asio::ssl::stream_base::client,
            boost::bind(&SSLSocket::HandleHandshake, this, boost::asio::placeholders::error));
         ss << "SSLSocket::HandleConnect: From worker thread " << Logger::NumberToString(boost::this_thread::get_id()) << ".\n";
         Log.LogString(ss.str(), LogInfo);
      }
      else
      {
         // Log an error.  This worker thread should exit gracefully after this.
         ss << "SSLSocket::HandleConnect: connect failed to " << sClientIp << " : " << uiClientPort << ".  Error: " << error.message() + ".\n";
         Log.LogString(ss.str(), LogError);
         Stop();
      }
   }
   catch (std::exception& e)
   {
      stringstream ss;
      ss << "SSLSocket::InitAsynchIO: threw an error - " << e.what() << ".\n";
      Log.LogString(ss.str(), LogError);
      Stop();
   }
}

void SSLSocket::HandleHandshake(const boost::system::error_code& error)
{
   // This method is called asynchronously when the server has responded to the handshake request.
   std::stringstream ss;
   try
   {
      if (!error)
      {
         // Try to send the first message that the server is expecting.  This msg tells the server we want to connect.
         // The first 4 bytes specifies the msg length after the first 4 bytes.  The next 2 bytes specifies the msg type.
         // The next 4 bytes specifies the source code.  The next 13 bytes specifies the msg "AttackPoker".
         // The next 2 bytes specifies the locale length.  The last 2 bytes specifies the locale - en for English.
         //
         unsigned char Msg[27] = {0x17, 0x00, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x41,
            0x74, 0x74, 0x61, 0x63, 0x6b, 0x50, 0x6f, 0x6b, 0x65, 0x72, 0x02, 0x00, 0x65, 0x6e};
         boost::system::error_code Err;

         sClientIp = pSocket->lowest_layer().remote_endpoint().address().to_string();
         uiClientPort = pSocket->lowest_layer().remote_endpoint().port();
         ReqAlive = true;
         // boost::asio::async_write(*pSocket, boost::asio::buffer(Msg), boost::bind(&SSLSocket::HandleFirstWrite, this,
         //   boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
         int Count = boost::asio::write(*pSocket, boost::asio::buffer(Msg), boost::asio::transfer_exactly(27), Err);
         if (Err)
         {
            ss << "SSLSocket::HandleHandshake: write failed - " << error.message() << ".\n";
            Log.LogString(ss.str(), LogInfo);
         }
         HandleFirstWrite(Err, Count);
         // boost::asio::async_write(pSocket, boost::asio::buffer(Msg, 27), boost::bind(&SSLSocket::HandleWrite, this,
         // boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
         ss.str("");
         ss << "SSLSocket::HandleHandshake: From worker thread " << boost::this_thread::get_id() << ".\n";
      }
      else
      {
         ss << "SSLSocket::HandleHandshake: failed - " << error.message() << ".\n";
         IOService->stop();
      }
      Log.LogString(ss.str(), LogInfo);
   }
   catch (std::exception& e)
   {
      stringstream ss;
      ss << "SSLSocket::HandleHandshake: threw an error - " << e.what() << ".\n";
      Log.LogString(ss.str(), LogError);
      Stop();
   }
}

void SSLSocket::HandleFirstWrite(const boost::system::error_code& error, size_t bytesTransferred)
{
   // This method is called after a msg has been written out to the socket.
   std::stringstream ss;
   try
   {
      if (!error)
      {
         // boost::asio::async_read(pSocket, boost::asio::buffer(reply_, bytesTransferred), boost::bind(&SSLSocket::handle_read,
         //   this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
         // boost::asio::async_read(pSocket, boost::asio::buffer(reply_, 84), boost::bind(&SSLSocket::handle_read,
         //   this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
         // Locking CodeLock(ReadLock); // Single thread the code.
         // Signal the other threads that msgs are now ready to be sent and received.
         // boost::asio::async_read(pSocket, boost::asio::buffer(pRepBuf), boost::asio::transfer_exactly(4), boost::bind(&SSLSocket::HandleRead,
         //  this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
         //
         // Notify the UI that we are now connected. - TBD
         // Get the 1st 4 bytes of the next msg, which is always the length of the that msg.
         pDataBuf = BufMang.GetPtr(MsgLenBytes);

         // int i1=1,i2=2,i3=3,i4=4,i5=5,i6=6,i7=7,i8=8,i9=9;
         //   (boost::bind(&nine_arguments,_9,_2,_1,_6,_3,_8,_4,_5,_7))
         //     (i1,i2,i3,i4,i5,i6,i7,i8,i9);

         // boost::asio::read(*pSocket, boost::asio::buffer(pReqBuf, MsgLenBytes), boost::asio::transfer_exactly(MsgLenBytes), Err);
         // boost::asio::async_read(pSocket, boost::asio::buffer(pReqBuf, MsgLenBytes), boost::bind(&SSLSocket::HandleRead, _1,_2,_3))
         //   (this, pReqBuf, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred);
         //   boost::asio::async_read(*pSocket, boost::asio::buffer(reply_), boost::asio::transfer_exactly(ByteCount), boost::bind(&Client::handle_read,
         //      this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
         // boost::asio::async_write(*pSocket, boost::asio::buffer(pDataBuf, MsgLenBytes), boost::bind(&SSLSocket::HandleWrite, this,
         //    boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

         HandShakeReady = true;
         Locking CodeLock(SocketLock); // Single thread the code.
         boost::asio::async_read(*pSocket, boost::asio::buffer(pDataBuf, MsgLenBytes), boost::bind(&SSLSocket::HandleRead, this,
            boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
      }
      else
      {
         ss << "SSLSocket::HandleFirstWrite: failed - " << error.message() << ".\n";
         Log.LogString(ss.str(), LogError);
         Stop();
      }
   }
   catch (std::exception& e)
   {
      stringstream ss;
      ss << "SSLSocket::HandleFirstWrite: threw an error - " << e.what() << ".\n";
      Log.LogString(ss.str(), LogError);
      Stop();
   }
}

感谢回应 - 已点赞!问题是我无法在客户端进行任何更改;它是一个“黑盒子” - 希望是一个具有Web浏览器行为的标准HTTPS客户端。否则就很容易解决了。因此,我需要遵循您提供链接中的标准方法。 - vitakot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接