OpenSSL と TLS を使用して、SSH のような信頼モデルを提供しようとしています。つまり、2 つのピアにはそれぞれ RSA キー ペアが保存されており、証明書はありません。また、TLS セッションが確立される前に、公開鍵も交換されています。これを達成するために、OpenSSLの文書化されていない機能を使用しているため、まだ疑問があります。方法は次のとおりです。
初期化中、ピアはメモリ内に一時的な x509 証明書を生成します。これには、ダミーの CN、発行者、および有効期限が切れる何年も前の、私が回避できる最小限のダミー データが含まれています。いずれにせよ、これらは決してチェックされません。SSL コンテキストは、両方の証明書を双方向で交換するように設定されています。
重要なステップは、証明書にホストの公開鍵が含まれており、秘密鍵を使用して署名されていることです。
EVP_PKEY *pkey = EVP_PKEY_new(); EVP_PKEY_assign_RSA(pkey, PRIVKEY); X509_set_pubkey(x509, pkey); X509_sign(x509, pkey, EVP_sha384());
SSL_CTX
この証明書は、アプリケーションの存続期間全体にわたって割り当てられ、使用されます。
一番気になるのはTLSセッション確立時の検証処理です。OpenSSL を使用して実行されるすべての検証を無効にしSSL_CTX_set_cert_verify_callback(always_true_func)
、次のように独自にロールします。
X509 *received_cert = SSL_get_peer_certificate(conn_info->ssl);
EVP_PKEY *received_pubkey = X509_get_pubkey(received_cert);
if (EVP_PKEY_type(received_pubkey->type) != EVP_PKEY_RSA)
error();
ret = X509_verify(received_cert, received_pubkey);
if (ret <= 0)
error("trust_failed");
// Compare received public key with expected one
RSA *expected_rsa_key = read_RSA_key_from_disk();
EVP_PKEY expected_pubkey = { 0 };
EVP_PKEY_assign_RSA(&expected_pubkey, expected_rsa_key);
EVP_PKEY_cmp(received_pubkey, &expected_pubkey);
if (ret == 1)
return true; // identity verified!
else
return false;
質問:これは OpenSSL API の適切な使用法ですか? 特に最後の部分、受信したキーの検証で、セキュリティ ホールが見られますか? 同じ結果を達成するためのより良い方法はありますか?
編集: 答え: TLS ハンドシェイク中に受信した自己署名証明書が保存されている RSA キーと一致することを確認するには、証明書の署名を確認する必要はありません。つまり、X509_verify
. 受信した公開鍵と期待される公開鍵を比較するだけで十分です。
その理由は、(OpenSSL プロジェクトのコア開発者である Stephen Henson 博士の言葉を引用して) 「暗号スイートに応じて、RSA 復号化操作または RSA 署名操作のいずれかがサーバーによって実行されるためです。したがって、ハンドシェイクが正常に完了すると、同じキーが使用されていることを確認できます。証明書に存在するものとして使用されます」。