2013-06-27 149 views
2

我試圖使用POCO庫編寫向服務器發送HTTPS請求的程序。出於測試目的,我將連接到具有自簽名證書的服務器,並且我想允許客戶端連接。爲了做到這一點,我試圖安裝一個InvalidCertificateHandler這是一個AcceptCertificateHandler的實例 - 我認爲即使它沒有簽名也會接受證書。下面是我使用的代碼:無法獲取POCO HTTPSClientSession發送請求 - 證書驗證失敗

try { 
      Poco::SharedPtr<Poco::Net::InvalidCertificateHandler> pAcceptCertHandler = 
              new Poco::Net::AcceptCertificateHandler(true); 
      Poco::Net::Context::Ptr pContext = 
       new Poco::Net::Context(Poco::Net::Context::CLIENT_USE, "", 
             "","",Poco::Net::Context::VERIFY_RELAXED, 
             9, true, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH"); 
      SSLManager::instance().initializeClient(NULL, pAcceptCertHandler, pContext); 

      Poco::Net::HTTPSClientSession theSess(myHostName,myHostPort); 

      // Create the HTTP request object 
      Poco::Net::HTTPRequest request("POST", 
           "https://myservername.com/MockServlet/activateEnc","1.1"); 

      // Send the request 
      std::cout << "Debug point A" << std::endl; 
      std::ostream& aStream = theSess.sendRequest(request); 
      std::cout << "Debug point B" << std::endl; 
      if (aStream.fail()) { 
       std::cout << "Fail to send HTTP request for activateEnc" << std::endl; 
       return WSERR_CONNECTION_ERR; 
      } 
     } catch (Poco::Exception& exc) { 
      std::cout << "Exception caught while attempting to connect." << std::endl; 
      std::cerr << exc.displayText() << std::endl; 
      return WSERR_CONNECTION_ERR; 
     } 

當我運行這段代碼,我得到以下輸出:

Debug point A 
Exception caught while attempting to connect. 
Certificate validation error: Unacceptable certificate from myservername.com: application verification failure 

我的期望是,由於我使用的AcceptCertificateHandler,證書會即使它無效也會被接受。我可能會做錯什麼?

一對夫婦的注意事項:

  1. 在上下文對象中構造函數調用,我傳遞了privateKeyFile,certificateFile和caLocation參數空字符串。我這樣做的原因是因爲我認爲作爲客戶端我不需要私鑰,客戶端證書或證書頒發機構證書。也許這是問題?
  2. 在對initializeClient的調用中,我將NULL作爲PrivateKeyPasshraseHandler傳遞 - 因爲我沒有爲客戶端使用私鑰。
  3. 在使用Context對象之前,我沒有調用Context :: useCertificate()。該文檔說,你需要調用userCertificate()或usePrivateKey(),但我不確定要傳遞什麼,或者如果這是客戶端需要的,或者僅用於服務器。也許這是問題?

回答

0

經過進一步的實驗,結果證明服務器上的證書不僅是自簽名的,而且還過期了。我嘗試連接到不同的服務器,發現我能夠。因此,即使使用AcceptCertificateHandler,庫似乎也不會接受過期的證書。

更新證書後,它不再過期,可以進行連接。

+0

我收到此錯誤時,連接到smtp.gmail.com ...任何建議?你認爲谷歌有一個到期的證書嗎?我間歇地得到它,但每天幾次,像5或6. –

+0

只是在黑暗中拍攝這裏:也許這是因爲谷歌兩步驗證(請參閱下面的評論下面的答案):http:// stackoverflow .COM /問題/ 11183738/POCO-站 - 後smtpclientsession登錄/ 11998973#11998973 – Alex

2

我發現,如果您通過主機名連接到服務器時發生了相同的錯誤,該主機名與TLS(可能爲SSL)握手期間服務器證書中的主機名不相同。在Poco::Net::HTTPSClientSession theSess(myHostName, myHostPort);中使用正確的主機名解決此問題。

在我的情況正確的名稱是證書的領域CN,我發現它的後續命令(〔實施例維基百科):

openssl s_client -connect en.wikipedia.org:443 -tls1 -state 

在輸出我們可以看到:

<...> 
Server certificate 
-----BEGIN CERTIFICATE----- 
MIIKCTCCCPGgAwIBAgIQARQZX2b6/4/WbhJJblFvTzANBgkqhkiG9w0BAQUFADBm 
<...> 
JW1fZqU0WxncxV8AfXeWfKzI1vkil45CJ4g++7U= 
-----END CERTIFICATE----- 
subject=/C=US/ST=California/L=San Francisco/O=Wikimedia Foundation, Inc./CN=*.wikipedia.org 
<...> 

有它:CN=*.wikipedia.org,所以使用任何%domain%.wikipedia.org作爲主機名應該沒問題。

P.S.順便說一下,Poco中與SSL相關的錯誤可能會有一些異常類,並帶有更詳細的錯誤消息。

0

我被這個問題困住了,原來是證書CN。顯然在POCO你可以禁用驗證使用配置選項openSSL.client.extendedVerification = falsepContext->enableExtendedCertificateVerification(false);

相關問題