[英]OpenSSL client not sending client certificate
我正在努力解決客戶證書問題,希望這里有人可以幫助我。 我正在使用boost asio開發客戶端/服務器對,但是我會盡量保持不確定。 我在Windows上並使用openssl 1.0.1e
基本上,我想使用客戶端證書進行客戶端身份驗證。 服務器將僅接受具有由我自己的CA簽名的證書的客戶端。 因此,我建立了一個自簽名的CA。 這又頒發了兩個證書。 一台用於客戶端,一台用於服務器。 兩者均由CA簽署。 我已經做過很多次了,我有信心做到了。
我的服務器端也可以正常工作。 它會請求客戶端證書,如果我使用的是s_client並為這些證書提供一切正常的功能。 另外,如果我使用的是瀏覽器並以受信任的方式安裝了根CA,然后導入客戶端證書。
我唯一無法工作的是libssl客戶端。 它總是在握手過程中失敗,據我所知,它不會發送客戶端證書:
$ openssl.exe s_server -servername localhost -bugs -CAfile myca.crt -cert server.crt
-cert2 server.crt -key private/server.key -key2 private/server.key -accept 8887 -www
-state -Verify 5
verify depth is 5, must return a certificate
Setting secondary ctx parameters
Using default temp DH parameters
Using default temp ECDH parameters
ACCEPT
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write certificate request A
SSL_accept:SSLv3 flush data
SSL3 alert read:warning:no certificate
SSL3 alert write:fatal:handshake failure
SSL_accept:error in SSLv3 read client certificate B
SSL_accept:error in SSLv3 read client certificate B
2675716:error:140890C7:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:peer did not return a
certificate:s3_srvr.c:3193:
ACCEPT
我使用此s_server作為調試工具,但對我的真實服務器卻發生了同樣的事情。 s_client使用相同的證書可以正常工作。 另外,如果我在服務器中禁用“ -Verify”,則連接有效。 因此,實際上似乎只是客戶端拒絕發送它的證書。 可能是什么原因呢?
由於我將boost asio用作SSL包裝器,因此代碼如下所示:
m_ssl_context.set_verify_mode( asio::ssl::context::verify_peer );
m_ssl_context.load_verify_file( "myca.crt" );
m_ssl_context.use_certificate_file( "testclient.crt", asio::ssl::context::pem );
m_ssl_context.use_private_key_file( "testclient.key", asio::ssl::context::pem );
我還嘗試繞過asio並通過說直接訪問SSL上下文:
SSL_CTX *ctx = m_ssl_context.impl();
SSL *ssl = m_ssl_socket.impl()->ssl;
int res = 0;
res = SSL_CTX_use_certificate_chain_file(ctx, "myca.crt");
if (res <= 0) {
// handle error
}
res = SSL_CTX_use_certificate_file(ctx, "testclient.crt", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
res = SSL_CTX_use_PrivateKey_file(ctx, "testclient.key", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
我看不出任何行為上的差異。 應該提到的是,我使用的是非常老的boost 1.43 asio,我無法更新,但我想所有相關調用還是或多或少直接進入了OpenSSL,並且服務器在該版本上運行良好,所以我認為可以排除這一點。
如果我開始將客戶端和服務器強制設置為特定版本,則錯誤消息會更改,但它永遠不會起作用,並且仍然可以與s_client測試一起使用。 當前將其設置為TLSv1
例如,如果我將其切換到TLSv1,則客戶端和服務器之間會有更多的chat不休,最終我收到錯誤消息:
...
SSL_accept:SSLv3 read client key exchange A
<<< TLS 1.0 ChangeCipherSpec [length 0001]
01
<<< TLS 1.0 Handshake [length 0010], Finished
14 00 00 0c f4 71 28 4d ab e3 dd f2 46 e8 8b ed
>>> TLS 1.0 Alert [length 0002], fatal unexpected_message
02 0a
SSL3 alert write:fatal:unexpected_message
SSL_accept:failed in SSLv3 read certificate verify B
2675716:error:140880AE:SSL routines:SSL3_GET_CERT_VERIFY:missing verify
message:s3_srvr.c:2951:
2675716:error:140940E5:SSL routines:SSL3_READ_BYTES:ssl handshake failure:s3_pkt.c:989:
ACCEPT
我發現在opensl郵件列表上發布了一個較早的bug條目,並對此進行了引用。 顯然,兩年前已解決的握手CRLF錯誤。 還是有?
我已經調試了將近一個星期,我真的很困。 有人對嘗試什么有建議嗎? 我沒主意...
干杯,斯蒂芬
PS:這是上面的s_server調試出來的結果,它將使用s_client和相同的證書進行:
$ openssl s_client -CAfile ca.crt -cert testclient.crt -key private/testclient.key -verify 2 -connect myhost:8887
ACCEPT
SSL_accept:before/accept initialization
SSL_accept:SSLv3 read client hello A
SSL_accept:SSLv3 write server hello A
SSL_accept:SSLv3 write certificate A
SSL_accept:SSLv3 write key exchange A
SSL_accept:SSLv3 write certificate request A
SSL_accept:SSLv3 flush data
depth=1 C = DE, // further info
verify return:1
depth=0 C = DE, // further info
verify return:1
SSL_accept:SSLv3 read client certificate A
SSL_accept:SSLv3 read client key exchange A
SSL_accept:SSLv3 read certificate verify A
SSL_accept:SSLv3 read finished A
SSL_accept:SSLv3 write session ticket A
SSL_accept:SSLv3 write change cipher spec A
SSL_accept:SSLv3 write finished A
SSL_accept:SSLv3 flush data
ACCEPT
...握手完成並傳輸了數據。
好吧,在遭受了很多苦難之后,OpenSSL的Dave Thompson找到了答案。
原因是我的ssl代碼在創建套接字對象(SSL *)之后在OpenSSL上下文中調用了所有這些函數。 這意味着所有這些功能實際上什么都不做或做錯了事。
我所要做的就是:
1.調用SSL_use_certificate_file
res = SSL_use_certificate_file(ssl, "testclient.crt", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
res = SSL_use_PrivateKey_file(ssl, "testclient.key", SSL_FILETYPE_PEM);
if (res <= 0) {
// handle error
}
(請注意缺少的CTX )
2.調用CTX函數
在創建套接字之前,請根據上下文調用CTX函數。 正如asio似乎鼓勵在此之后立即創建上下文和套接字(就像我在初始化列表中所做的那樣),這些調用幾乎沒有用。
SSL上下文(在lib OpenSSL或asio中均如此)封裝了SSL用法,並且由此創建的每個套接字都將共享其屬性。
謝謝你們的建議。
您不應該同時使用SSL_CTX_use_certificate_chain_file()和SSL_CTX_use_certificate_file(),因為SSL_CTX_use_certificate_chain_file()嘗試加載包括客戶端證書的鏈,而不僅僅是CA鏈。 來自SSL_CTX_use_certificate(3) :
SSL_CTX_use_certificate_chain_file()將證書鏈從文件加載到ctx。 證書必須為PEM格式,並且必須從主題的證書(實際的客戶端或服務器證書)開始,然后是中間的CA證書(如果適用),並以最高級別(根)CA結束。
我認為您只使用SSL_CTX_use_certificate_file()和SSL_CTX_use_PrivateKey_file()應該會很好,因為客戶端無論如何都不太在乎CA鏈。
我認為您需要在服務器端調用SSL_CTX_set_client_CA_list
。 這將設置要與客戶端證書請求一起發送的證書頒發機構列表。
客戶端將無法發送其證書,即使一個請求, 如果該證書不匹配由服務器發送的CA列表。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.