簡體   English   中英

OpenSSL客戶端未發送客戶端證書

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM