web-dev-qa-db-ja.com

SSLクライアント証明書認証

公開鍵と秘密鍵のみでクライアント証明書認証を使用するプログラムを作成することはできますか(私は証明書を生成していません。公開鍵と秘密鍵しかありません)。

簡単に言うと、クライアント証明書認証を使用してサーバーで認証を行います。しかし、プログラムでクライアント証明書を作成することは困難です。

公開鍵と秘密鍵のみを使用してクライアント証明書認証を作成したい(公開鍵と秘密鍵のみがあり、証明書がない)。

クライアント証明書認証のためにクライアント証明書の代わりにサーバー公開鍵を送信することは可能ですか?

10
Taleh Ibrahimli

証明書は、コンテキストが追加された単なる公開鍵です。鍵の名前、署名、使用ガイドラインなど。SSL/ TLS 依存そのコンテキスト。そうしないと、接続しているホストは、キーが本当に自分のものであるかどうかを認識できません。 SSL信頼メカニズムは、明示的に信頼された証明書と、それらが署名する暗黙的に信頼された証明書の概念に基づいて構築されています。

ただし、SSLまたはTLSを使用していない場合でも、暗号化はSSLなしでも発生しますが、信頼は別の方法で発生する必要があります。 SSHはこの良い例です。SSHは引き続き公開鍵と秘密鍵を使用しますが、署名の階層がないため、証明書が提供する追加情報は役に立たないため、鍵はそのまま送信されます。代わりに、クライアントは最初に接続するときにサーバーの公開鍵を信頼するかどうかを尋ね、その後は毎回、公開鍵が前回見たものと一致するかどうかを確認します。 これは、SSHが暗号化にSSLまたはTLSを使用しないために発生する可能性があります。

ただし、SSLプロトコルを使用している場合、プロトコルでは、公開鍵には証明書の追加のコンテキストを提示する必要があると規定されています。つまり、証明書は、SSLが使用するために公開鍵を配置する必要があるコンテナーです。

秘密鍵がある場合は、OpenSSLなどのツールを使用して自己署名証明書を作成するのは簡単です。

11
tylerl

SSL/TLS 証明書によるクライアント認証をサポートします。内部で実際に発生することは次のとおりです。

  • サーバーは、CertificateRequestメッセージを通じて「クライアント証明書」を要求します。
  • クライアントは証明書をCertificateメッセージとして送信し、ハンドシェイク内の先行するすべてのメッセージに対する署名を(その秘密鍵を使用して)計算します。署名はCertificateVerifyメッセージとして送信されます。
  • サーバーどうにかしてクライアントの公開鍵を取得します(通常、クライアント証明書を X.509 証明書としてデコードし、それを検証します) X.509を使用して公開鍵を抽出し、それを使用してクライアントからの署名を検証します。

ただし、プロトコル自体では、証明書は不透明なバイトのチャンクとして交換されます。各「証明書」は、その長さを指定する3バイトのヘッダーとともに送信されます。したがって、サーバーとクライアントの両方のコードを制御する場合、これらのバイトのチャンクをどのように解釈するかを決定するのは完全にあなた次第です。 X.509証明書を送信する必要はありません。必要に応じて、空のメッセージを送信できます。

重要な点は残っています:

  • 認証が意味を持つためには、サーバーはクライアントの公開鍵を保証して知っている必要があります。この署名は、クライアントが秘密鍵を制御することを示していますが、これは、対応する公開鍵が既知のクライアントIDに明確に添付されている場合にのみ有効です。

  • 鍵ペアは、署名に適したタイプである必要があります(Diffie-Hellmanではなく、RSAまたはDSA)。

既存のSSL実装では、少なくともX.509形式を尊重するinsistが可能です。この場合、公開鍵を何らかの自己署名でラップする必要があります。 X.509証明書。これは OpenSSL などの一部のライブラリを使用すると、プログラムで比較的簡単です。

SSLのX.509証明書をOpenPGP公開鍵で置き換えるための 標準 があり、SSLに固有の形式の俊敏性を示します。

9
Thomas Pornin

(これは SOでの同じ質問に対する私の答え に基づいています。多くの場合、1つのSEサイトだけで質問する方が良いです。)

TLSプロトコルは、生の公開鍵ではなく、証明書の交換のみを許可します。 「PGPキー」(X.509を TLSでの認証用のOpenPGP に置き換えたい場合はサポートされていません)も実際には証明書です(これらは公開キーと識別子と属性のセット)。

Thomasが言うように、独自のタイプの証明書を定義して、それらをプレーンな公開鍵にすることもできます(ただし、技術的には「証明書」と呼ぶことができるかどうかはわかりません)。

実用的な観点から、既存のSSL/TLSスタックを使用して必要なものを実現し、検証X.509証明書の処理方法を微調整することを慎重に行う必要があります。実際、ほとんどのSSL/TLSスタックは、APIを介してX.509証明書の検証を公開していますが、他のタイプの証明書(OpenPGPなど)を許可するものや、コードを簡単にカスタマイズできるものはほとんどありません。非X.509証明書のカスタマイズは非常に困難である可能性があり、SSL/TLS実装に慣れていない場合は追加のバグが発生する可能性があり、すべての潜在的なクライアントもカスタマイズをサポートする必要があるため、実際に展開するのも困難です。 。

自己署名クライアントX.509証明書を使用してクライアント認証を実行し、それらの公開鍵に依存することができます(しかし、この公開鍵を、サーバーがすでに知っている既知のものなどに対して検証する必要がありますリスト)。これを最初に実装する場合のセキュリティへの影響を理解する必要があります。これは、自己署名サーバー証明書とまったく同じ問題ではありません。 (サーバー証明書を検証するための従来のアプローチを維持することをお勧めします。)

クライアントに自己署名証明書を送信させ(場合によっては サーバーによってアドバタイズされたCAリストに関する特定のトリック を使用)、TLSスタックで検証するか、アプリケーションで後で検証することができます。

多くのアプリケーションコンテナ(JavaのTomcat/Jettyなど)では、SSL/TLSレイヤーがクライアント証明書を検証することを期待しています。したがって、そこで認証をスキップした場合(後でコンテナー内またはアプリケーションの一部として認証を実行したい場合)、多くのアプリケーションフレームワークが混乱します。アプリケーションで認証を必要とするアクションを実行する前に、認証が実際にどこかで実行されることを確認するように十分に注意する必要があります。

たとえば、Tomcat/Jettyで任意のクライアント証明書を許可するトラストマネージャーを設定しても問題ありませんが、javax.servlet.request.X509Certificateリクエスト属性を使用して検証する方法はありません(ほとんどのフレームワークではそれ以外の場合は期待)。アプリケーション内にいくつかの検証ロジックを実装する必要があります。たとえば、このクライアント証明書の公開鍵を既知の公開鍵のリストと比較する認証済み機能の前にフィルターを設ける(または、公開鍵を識別子)。あるいは、カスタム検証マネージャー(Java)内でこの検証を実行することもできます。これにより、アプリケーション内で必要な作業が少なくなります。

SSLVerifyClient optional_no_caを使用して、Apache Httpd + PHP=セットアップ(たとえば)で同様のことを行うことができます。ここでも、PHPアプリケーションは証明書が検証されたので、そこでも検証を実装する必要があります。

取得した証明書情報がどの段階で確認されたかを理解していない限り、これを行わないでください。

2
Bruno

私たちの愛する友達に加えて、tylerl

あなたはOpenSSL linuxコマンドについて知っているべきであり、PHPまたはPerl。(特にPHP))での優れたスキルプログラミングを持っている必要があります。1- http:// www。 php.net/manual/en/book.openssl.php および2-openssl。orgあなたはopensslコマンドとその機能について深い知識が必要です。

最後に:(あなたの質問)クライアント証明書認証のためにクライアント証明書の代わりにサーバー公開鍵を送信することは可能ですか?いいえ、クライアントとサーバー間の認証と鍵交換を段階的に示すTLSハンドシェイクプロトコルを忘れる可能性があるためです。 http://msdn.Microsoft.com/en-us/library/windows/desktop/aa380513%28v=vs.85%29.aspx

0
Passenger