2

C/C++ クライアントが SSL 経由でサーバーを認証するようにしたいと考えています。最初にサーバーから証明書ファイルをダウンロードしました
openssl s_client -showcerts -connect www.openssl.org:443 </dev/null 2>/dev/null | openssl x509 -outform PEM > mycertfile.pem

次に、アプリケーションで次の API 呼び出し (疑似コード) を実行します。


// Register the error strings for libcrypto & libssl
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// New context saying we are a client, and using SSL 2 or 3
ctx = SSL_CTX_new(SSLv23_client_method());
// load the certificate
if(!SSL_CTX_load_verify_locations(ctx, "mycertfile.pem", 0))
  ...
// Create an SSL struct for the connection
ssl = SSL_new(ctx);
// Connect the SSL struct to our pre-existing TCP/IP socket connection
if (!SSL_set_fd(ssl, sd))
  ...
// Initiate SSL handshake
if(SSL_connect(ssl) != 1)
  ...
// form this point onwards the SSL connection is established and works
// perfectly, I would be able to send and receive encrypted data
// **Crucial point now**
// Get certificate (it works)
X509 *cert = SSL_get_peer_certificate(ssl);
if(cert) {
  // the below API returns code 19
  const long cert_res = SSL_get_verify_result(ssl);
  if(cert_res == X509_V_OK) {
    printf("Certificate verified!\n");
  }
  X509_free(cert);
}

上記のコードは、証明書を確認することを気にせず、暗号化された接続に関心があるだけであれば問題なく動作します。
問題は、サーバーの信頼性を検証しようとすると、証明書を取得できますが、5 分前に証明書をダウンロードしただけでもSSL_get_peer_certificate結果の検証が機能しないことです。

私は何を間違っていますか?

これはすべて、 gcc およびopensslを使用した Ubuntu 12.04.03 x86-64 上にあります。

ありがとう、エマ

4

2 に答える 2

3

SSL_CTX_load_verify_locations()OpenSSL がすでに提供しているよりも完全な CA 証明書のセットを持っている場合、または非標準の CA を使用して証明書に署名し、その CA 証明書を持っているサーバーに接続している場合にのみ呼び出す必要があります。サーバー証明書を確認します。SSL_CTX_set_default_verify_paths()それ以外の場合は、代わりに電話する必要があります。

// load the certificate^H^H^H^H^H^H^H^H^H^H^H^H CA trust-store
if(!SSL_CTX_set_default_verify_paths(ctx))
  ...

余談ですが、あなたのプログラムには別のエラーがありました。に間違ったポインタを渡しましたSSL_get_verify_result()。を渡す代わりに、 を渡すSSL_CTX *必要がありSSL *ます。コンパイラは、このエラーについて警告しているはずです。

  const long cert_res = SSL_get_verify_result(ssl);
于 2013-09-18T00:19:50.493 に答える
1

ダウンロードしたばかりの証明書は、認証局 (CA) によって署名されている必要があります。証明書自体ではなく、CA (またはルート CA) の証明書をロードする必要があります。サーバーの証明書を に直接ロードしたためSSL_CTX_load_verify_locations、検証ルーチンSSL_get_verify_resultはエラー コードを返しました。おそらく確認コードは 19 ( X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) だったはずです。

つまり、OpenSSL には、クライアント アプリケーションで使用できる CA (およびルート CA) のセットが組み込まれています。Linux ディストリビューションでは、これらの証明書へのパスは通常、/etc/ssl/certs です。したがって、次のように変更してみてくださいSSL_CTX_load_verify_locations

if (!SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs"))
   ...

もちろん、これは /etc/ssl/certs が存在し、関連する証明書 (そのうちの 1 つがサーバー証明書に署名したもの) を持っていることを前提としています。よく知られているホストを認証している場合、CA は /etc/ssl/certs にある可能性が高いでしょう。

于 2013-09-17T17:31:53.830 に答える