11

私はクライアント証明書の問題に苦しんでおり、ここの誰かが私を助けてくれることを願っています. ブーストasioを使用してクライアント/サーバーのペアを開発していますが、具体的でないようにします。私はWindowsを使用しており、openssl 1.0.1eを使用しています

基本的に、クライアント証明書を使用してクライアント認証を行いたいと考えています。サーバーは、自分の CA によって署名された証明書を持つクライアントのみを受け入れます。そのため、自己署名 CA をセットアップしました。これにより、さらに 2 つの証明書が発行されました。1 つはクライアント用、もう 1 つはサーバー用です。どちらも 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」を無効にすると、接続が機能します。したがって、クライアントが証明書の送信を拒否しただけのようです。その理由は何ですか?

ブースト 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
}

動作に違いは見られません。更新できない非常に古いブースト1.43 asioを使用していることに言及する必要がありますが、関連するすべての呼び出しは多かれ少なかれ直接OpenSSLに送信され、サーバーはそのバージョンで正常に動作するため、除外できると思います。

クライアントとサーバーを特定のバージョンに強制し始めると、エラー メッセージは変わりますが、動作せず、常に s_client テストで動作します。現在は TLSv1 に設定されています

たとえば、TLSv1に切り替えると、クライアントとサーバーの間でより多くのおしゃべりがあり、最終的にエラーが発生します:

...
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

これを参照している openssl メーリング リストに投稿された古いバグ エントリを見つけました。明らかに、2 年前に修正されたハンドシェイクの間違った CRLF です。それともありますか?

私はこれをほぼ1週間デバッグしてきましたが、本当に行き詰まっています。何を試すべきかについて誰か提案がありますか?私はアイデアがありません...

乾杯、ステファン

PS: s_client と同じ証明書を使用した場合の上記の s_server デバッグ アウトは次のとおりです。

$ 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

... ハンドシェイクが完了し、データが転送されます。

4

3 に答える 3

5

よし、多くの苦労の末、答えは OpenSSL の Dave Thompson によって発見された。

その理由は、ソケット オブジェクト (SSL*) が OpenSSL コンテキストから作成された後で、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 の使用をカプセル化し、そこから作成された各ソケットはそのプロパティを共有します。

ご提案いただきありがとうございます。

于 2013-06-11T09:32:42.500 に答える
1

SSL_CTX_set_client_CA_listサーバー側で呼び出す必要があると思います。これにより、クライアント証明書要求とともに送信される認証局のリストが設定されます。

証明書がサーバーから送信された CA リストと一致しない場合、クライアントは、証明書が要求されたとしても送信しません。

于 2013-06-10T15:26:49.987 に答える
1

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 で終わるように並べ替える必要があります。

とにかくクライアントはCAチェーンをあまり気にしないので、SSL_CTX_use_certificate_file()とSSL_CTX_use_PrivateKey_file()のみを使用しても問題ないと思います。

于 2013-06-10T14:58:43.027 に答える