function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
yukijnoriyukijnori 

Tomcat-two way SSLについて

現在、Tomcat6.0とセールスフォースの認証機関署名証明書を用いて

WebAPサーバ(Tomcat)-SFDC間の双方向SSL通信を行おうとしています。


やり方としては、keytool -genkey -alias tomcat -keyalg RSA -keysize 2048 -keystore tomcat.keystoreでオレオレ証明書を作成し、

あとはhttp://wiki.developerforce.com/index.php/Making_Authenticated_Web_Service_Callouts_Using_Two-Way_SSLにあるようにopensslでルート証明書作成し、SFDCの証明書とキーの管理から作成したcert,p10ファイルをWebAPサーバへ渡して、opensslで署名して、署名したファイルをSFDCへアップロードしています。


しかし、ブラウザからはhttpsでアクセスし、オレオレ証明書を例外追加すれば、ページを表示できるのですが、

SFDCのテストクライアントからHTTPコールアウト(httpsで)を行うと、以下のようなエラーがでてしまいます。


エラー:System.CalloutException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target


これは、WebAPサーバの証明書が信用できないので、出ているのではないかと思うのですが、

Salesforceでは、オレオレ証明書を認めていないということなのでしょうか。

ベリサイン等に署名をしてもらわないと、双方向のSSLは実現不可能なのでしょうか。

何かご存知の方がいましたら、教えて頂きたいです。

よろしくお願い致します。


Best Answer chosen by Admin (Salesforce Developers) 
Twoway2Twoway2

ここを参考にしたような気がします。(覚えていません)

 

 http://www.wkshop.net/m2/privateCA.txt

 

私の環境でclientAuth=trueで動作させるために最後のポイントとなったのは、

 

(1)自前の環境で用意した証明局のキーストアを作成する。

(2)自前の環境で用意した証明局で、クライアント認証用の証明書を作成する。

  (私の場合、ブラウザで動作確認したため、ブラウザにインストールする証明書)

あと、当時のメモ書きをみると、

(3)上で紹介したURLに記載されている内容の、

 「サーバー(tomcat)が信頼するCAを登録する」

 を実行するのもポイントだったかなぁー。うーん。忘れました。

 

の3点だったと思います。

そして、(1)で作成したキーストアは、

server.smlの

< ....略...

   truststoreFile= "C:/etc/work18_tomcat/clientauth.keystore"
...略  />

のように指定します。(何度も書いて恐縮ですが、ここがうまくいっていないのだと思います)

 

なお、そちらの方で参考にした

> 私は、以下のサイトを参考に設定を進めました。

> http://www.ksgmt.com/article/java/javassl_clientce​rt.html

は、私は参考にしませんでした。

(私も当時見ましたが、理由は忘れましたが、参考にするのを止めました。)

 

また、

> 検証環境のwebサーバ上で、サーバ証明書、クライアント証明書を作成し、

> keystoreをこちらに持ってきたのですが、Eclipseでもエラーが出たため、

> crtファイルをこちらに持ってきて、インポートし、ブラウザアクセスを行いました。

 

「keystoreをこちらに持ってきた」 →?

「Eclipseでもエラー」→なぜEclipseの話が?

「crtファイルをこちらに持ってきて、インポートし、ブラウザアクセスを行いました。」→?

記述の簡略化のためにこのような表現になっているのかとも思いますが、

若干理解に苦しむ部分があります。

間違った方向に行っていないのを期待していますが。

 

以上、ご参考まで。

All Answers

tajimatajima

はい、公的認証機関の証明が必要です。

こちらも参考にしてください。

http://wiki.developerforce.com/index.php/Outbound_Messaging_SSL_CA_Certificates

yukijnoriyukijnori

返信が遅れてしまい申し訳ありません。

 

回答ありがとうございました。Verisignで試したところ、一方向のSSLについては実現できました。

ただ、双方向が実現できません。クライアント認証が成功せず、System.CalloutException: Received fatal alert: bad_certificateとエラーが出ます。

Salesforceのマニュアルが微妙に間違っていて、実際はclientAuthをtrueにすべきだと思うので、そうしたところ上手くいかなくなっています。

これは何が原因なのでしょうか・・・。サポートでも原因が分からないようです。証明書を1024にするなどはやってみたのですが。。

 

何かご存知の方いらっしゃいましたら、お願いします。方法はhttp://wiki.developerforce.com/index.php/Making_Authenticated_Web_Service_Callouts_Using_Two-Way_SSLをそのまま行っています。

 


Twoway2Twoway2

何点か確認させてください。

 

・以前は成功していた、

 「クライアント証明書を持つブラウザからのアクセスは可能」

 という状況は、今も同じでしょうか。

 

・クライアント証明書は、どこが発行したものを利用していますか?

 (Webサーバのopenssl、でしょうか)

 

・tomcatのログに何か有益な情報は残っていませんか?

 

・Apache無しのtomcatオンリーという構成、で合ってますか?

yukijnoriyukijnori

返信ありがとうございます。

 

・以前に通信が成功していたのは、clientAuthをfalseにしていたためです。(クライアント認証なし、この時点ではone-wayです)

確かにオレオレ証明書ではsalesforce上でエラーになりましたが、Verisignにして、clientAuth=falseで通信は成功しています。

Verisignにしたことで、信頼できない署名書というエラーはなくなりました。

 

・クライアント証明書は、salesforce上で認証期間証明書を発行し、マニュアル通りopensslで署名しています。

そしてそれをsalesforceにアップロードし、Callout時に証明書を指定しています。

ここで何か他に手順が必要なのでしょうか・・・。

 

・ログは見てみたのですが、それらしいものは今のところ見つけられていません。。。

 

・tomcatのみの構成となっています。Apacheは使用していません。

 

何かわかるようでしたら、よろしくお願い致します。

Twoway2Twoway2

こちらはApache + Tomcatで構築しているため、参考になればと思い、

記載させて頂きます。

 

Apacheの場合、サーバをSSL化し、クライアント認証機能を使用する場合、

設定ファイル(例:httpd-ssl.conf)に対して、

・クライアント認証を「する」に設定

・クライアント証明書を発行した認証局の証明書のパスの設定

をします。

後者の方は、例えば(Windowsの例)

SSLCACertificateFile "C:/etc/demoCA/cacert.pem"

のように、クライアント証明書を発行した認証局の証明書を指定します。

質問者様の場合は、opensslで署名したとの事なので、

その「なんちゃって認証局」の証明書を指定します。

(サーバ証明書でもなく、クライアント証明書でもなく、

 認証局の証明書になります。)

 

Tomcatの場合、その設定をどのようにするかは分かりませんが、そこら辺の

設定の問題ではないでしょうか。

また、動作確認においては、Salesforceからの確認よりも、

単純にブラウザを利用してクライアント認証機能が動くかを確認した方が

簡単だと思います。

 

※蛇足ですが、Apacheの場合、

SSLCACertificateFileでなく、複数ファイルを指定できる

SSLCACertficatePathを指定した場合、ややこしくなりますが、

今回は無関係のようなので触れません。

(SSLCACertficatePathに関しては、ネットの情報の多くが情報不足のため、

 ある意味間違った情報がはびこっているようです。本件とは

 無関係のようですが。)

 

以上、ご参考まで。

Twoway2Twoway2

Tomcatオンリーの場合の補足です。

(私の環境をApache + Tomcat から、Tomcatオンリーに変更してみてやってみました。)

 

Apacheの場合と、Tomcatの場合は設定等が色々違っており、

比較するのも難しいみたいなので、私の環境を利用してやってみました。

(Tomcatオンリーのクライアント認証の環境を作り、ブラウザでアクセスして確認してみました。

 なかなかうまく動きませんでしたが、最終的にはなんとか動きました。)

その結果、はまりそうなのは、server.xmlの、下のサンプルで言う最後の2行だと思います。

(私の環境もTomcat6です)

 

    <Connector port="8443"  SSLEnabled="true"
               protocol="HTTP/1.1"
               maxThreads="150" scheme="https" secure="true"
               keyAlias="tomcat"
               clientAuth="true"
               sslProtocol="TLS"
               keystorePass="changeit"
               keystoreFile="C:/Tomcat60/conf/tomcat.keystore"
               truststoreFile= "C:/etc/work18_tomcat/clientauth.keystore"
               truststorePass="changeit" />

 

truststoreFile=が、Apacheの例で言う、

クライアント証明書を発行した証明局の証明書(->Tomcatの場合、keystore?)になるようです。

あくまで私の環境の場合、ですが、下のコマンドで作り直してます。

(./demoCA/cacert.crt なんてのは、私の環境固有のものですが)

keytool -import -file ./demoCA/cacert.crt -trustcacerts -alias tomcat -keystore clientauth.keystore

 

以上、ご参考まで。

yukijnoriyukijnori

わざわざ試して頂いてありがとうございます。

 

私はserver.xmlで、keystoreとtruststoreともに同じキーストアにまとめていました。

 

    <Connector port="443" minSpareThreads="5" maxSpareThreads="75"
               enableLookups="true" disableUploadTimeout="true"
               keystoreFile="/opt/tomcat/apache-tomcat-6.0.26/conf/tomcat.keystore"
               keystorePass="changeit"
               trustStoreFile="/opt/tomcat/apache-tomcat-6.0.26/conf/tomcat.keystore"
               trustStorePass="changeit"
               SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="true" sslProtocol="TLS" />

そのせいかと思い、今分けて試してみましたがやはり上手くいきません。

でもそちらでうまく動作しているということは、こちらの設定がおかしいんですよね。。

ApexのHttpcallout時に、System.CalloutException: Received fatal alert: bad_certificateが出るのは変わりません。

 

keytool -importcert -trustcacerts -alias my_ca -keystore $HOME/tomcat/conf/tomcat.keystore -file cacert.pem

で追加していたんですが、crtファイルの方を追加すべきなのでしょうか。。。

openssl ca -config openssl.cnf -policy policy_anything -out outbox/test.crt -infiles inbox/test.p10

で作成したcrtで試しましたが、やはり上手くいきません。。何が原因なのか難しいところです(汗)

Twoway2Twoway2

3点ほど。

 

・>keytool -importcert -trustcacerts -alias my_ca -keystore $HOME/tomcat/conf/tomcat.keystore -file cacert.pem

  >で追加していたんですが、crtファイルの方を追加すべきなのでしょうか。。。

 

多分、cacert.crt の方だと思います。(そちらの環境を見た訳ではありませので想像ですが....。)

 

・server.xmlに、私がサンプルで提示している例での "keyAlias=・・・" の項目が無いようですので、追加してみては?

 

・server.xmlの、keystorePass や truststorePass は、実際に設定したパスワードを指定してますか。

 (サンプルでは、デフォルトは"changeit"ですが、そちらの環境に合わせて変更していますか)

 

以上、気になった点を上げさせて頂きました。

yukijnoriyukijnori

返信ありがとうございます。

 

ご指摘頂いた3つについては。既に試してみたのですが、やはりダメでした。

プレミアムサポートに問い合わせても、サーバ側は分からないとのことで、

サンプルとしてTomcatOnlyの構成は載せているものの、動作の保証はできていないようです。

(マニュアルに間違いもありますし・・・)

ですので、もう一度ご指摘頂いた点を含めて、別の検証環境作成し、やり直してみまして、

それでもダメなら他のApache+Tomcatといった構成も検討しようと思います。

本当は、Tomcatだけでいけるのが理想なんですが。。。まぁ仕方なしです。

Twoway2Twoway2

tomcat-users.xml の設定は大丈夫ですか?

 

例:

<role rolename="invoice-readonly"/>
<user username="CN=invoice_service, OU=xxxx, O=xxxx, L=xxxx, ST=xxxx, C=JP"
  password="null" roles="invoice-readonly"/>

 

現在でているエラーは、証明書が壊れている場合、もしくは署名の正当性が確認できない

などの場合に出力されるメッセージのようですので、あと一歩のところだと思うのですが...。

(認証局の証明書の指定のところの問題だと思いますが.....。)

 

なお、Tomcatオンリーの構成にするよりは、Apache+Tomcatの構成にした方が何かと

都合がいいと思いますので、あきらめて構成を変えるのも良いと思います。

ただし、エラーが前述の通りの意味なので、エラーが解消されない可能性もあると思います。

メッセージの通りのエラーならば、opensslで作成した証明書が変、という事だと思いますので。

yukijnoriyukijnori

お返事が遅れ、申し訳ありません。

 

tomcat-users.xmlの設定は大丈夫だと思います。invoice~の部分とxxxxの部分は適宜変更して記述しています。

 

現在、検証環境で試しているのですが、検証環境は予算の都合でVerisignが使用できないので、

オレオレ証明書でサーバ証明書、クライアント証明書を作成しています。

SalesforceをVerisignなどの信頼できるところで作成された証明書しか受け付けないため、

(検証環境はオレオレのためSalesforce上のクライアントからhttpsでコールアウトできない。)

とりあえずブラウザでクライアント認証ができないか検証しています。

 

しかし、なかなかうまく動作せず、やっぱり設定がおかしかったのかと思い始めています。。。

もちろん、clientAuthをfalseにして、ブラウザの例外を追加すればSSLでアクセスできますが、

clientAuthをtrueにすると、FirefoxでSSL peer cannot verify your certificate.などと出ます。

 

そちらでは、TomcatOnlyでブラウザからクライアント認証ができているとのことで、

もしよろしければ、簡単でも良いので手順を教えて頂けないでしょうか。

 

私は、以下のサイトを参考に設定を進めました。

http://www.ksgmt.com/article/java/javassl_clientcert.html

検証環境のwebサーバ上で、サーバ証明書、クライアント証明書を作成し、

keystoreをこちらに持ってきたのですが、Eclipseでもエラーが出たため、

crtファイルをこちらに持ってきて、インポートし、ブラウザアクセスを行いました。

 

以上、よろしくお願い致します。

 

 

Twoway2Twoway2

ここを参考にしたような気がします。(覚えていません)

 

 http://www.wkshop.net/m2/privateCA.txt

 

私の環境でclientAuth=trueで動作させるために最後のポイントとなったのは、

 

(1)自前の環境で用意した証明局のキーストアを作成する。

(2)自前の環境で用意した証明局で、クライアント認証用の証明書を作成する。

  (私の場合、ブラウザで動作確認したため、ブラウザにインストールする証明書)

あと、当時のメモ書きをみると、

(3)上で紹介したURLに記載されている内容の、

 「サーバー(tomcat)が信頼するCAを登録する」

 を実行するのもポイントだったかなぁー。うーん。忘れました。

 

の3点だったと思います。

そして、(1)で作成したキーストアは、

server.smlの

< ....略...

   truststoreFile= "C:/etc/work18_tomcat/clientauth.keystore"
...略  />

のように指定します。(何度も書いて恐縮ですが、ここがうまくいっていないのだと思います)

 

なお、そちらの方で参考にした

> 私は、以下のサイトを参考に設定を進めました。

> http://www.ksgmt.com/article/java/javassl_clientce​rt.html

は、私は参考にしませんでした。

(私も当時見ましたが、理由は忘れましたが、参考にするのを止めました。)

 

また、

> 検証環境のwebサーバ上で、サーバ証明書、クライアント証明書を作成し、

> keystoreをこちらに持ってきたのですが、Eclipseでもエラーが出たため、

> crtファイルをこちらに持ってきて、インポートし、ブラウザアクセスを行いました。

 

「keystoreをこちらに持ってきた」 →?

「Eclipseでもエラー」→なぜEclipseの話が?

「crtファイルをこちらに持ってきて、インポートし、ブラウザアクセスを行いました。」→?

記述の簡略化のためにこのような表現になっているのかとも思いますが、

若干理解に苦しむ部分があります。

間違った方向に行っていないのを期待していますが。

 

以上、ご参考まで。

This was selected as the best answer
yukijnoriyukijnori

お世話になっております。

 

クライアント認証に関してですが、自己解決しました。

私が色々試して出た結論ですが、TomcatがtrustStoreFileを見に行っていないと思われます。

Javaアプリケーションでは、信頼するCAをjre以下のcacertsかシステムプロパティで指定されるファイルで管理しており、

TomcatもJavaアプリケーションのためこれに当てはまるという情報を得ましたので、

以下のtrustの部分を削除し、jre/lib/security/cacertsにプライベートCAの証明書を登録したところうまく動作しました。

試した結果、trustはなくても動きますが、cacertsにプライベートCAがインポートされていないと動きませんでした。

(ブラウザでは、証明書選択画面で最初選択できる証明書がない、サーバでCAをインポートすると選択できる証明書が現れる)

何故trustStoreで指定した方が見に行かれないのかは疑問ですが、、、とりあえずは解決できました。

色々とありがとうございました。


    <Connector port="443" minSpareThreads="5" maxSpareThreads="75"
               enableLookups="true" disableUploadTimeout="true"
               keystoreFile="tomcat.keystore"
               keystorePass="password"

               trustStoreFile="trust.keystore":ここを削除
               trustStorePass="password":ここを削除
               SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="true" sslProtocol="TLS" />

yukijnoriyukijnori

投稿した直後に投稿が。。。

 

返信ありがとうございます。

 

やはり、以下がポイントのようですが、先ほどの投稿にも書きましたが、trustで指定したものをうまく見てくれないようです・・・

(3)上で紹介したURLに記載されている内容の、

「サーバー(tomcat)が信頼するCAを登録する」

ご指摘の通り、truststoreFile= "C:/etc/work18_tomcat/clientauth.keystore"が機能していなかったみたいです。

 

「keystoreをこちらに持ってきた」 →最初ブラウザではなく、Eclipseで接続用のクライアントを作成していて、

その際にkeystoreファイルが必要なようでしたので、サーバからローカルに落としてきました。

「crtファイルをこちらに持ってきて、インポートし、ブラウザアクセスを行いました。」→

ここは間違っていました。サーバで.p12ファイルを作成し、Widowsローカルでダブルクリックでインポートしました。

分かりにくくて、申し訳ありませんでした。

 

trustに関しては疑問ですが、こちらで解決できるように頑張ってみます。

とりあえずSalesforce上の本番環境でも試しまして、動作しているので一安心です。

色々教えて頂き、ありがとうございました。

 

 

 

 

Twoway2Twoway2

無事動いたようで、おめでとうございます。

陰ながら動くことに期待しておりました。

(一番最初、偶然にも同じ日、同じような時間に、ほぼ同じ問題に遭遇していました。

 最後の投稿もほぼ同時とは。奇遇ですね。)

 

なお、Tomcatオンリーかつ、clientAuth=tureの構成を完成させるために

私の環境で最後に実行したコマンドは、私の当時の記録では

keytool -import -file ./demoCA/cacert.crt -trustcacerts -alias tomcat -keystore clientauth.keystore

です。(多分実際に打ったコマンドです。登場する引数、変数は、今までの私の投稿と整合性がとれています。)

おそらく、私の前投稿の(3)に関連し、そちらの環境でこれ相当のコマンドをたたけば、truststoreFile= .....の指定の

問題も解決するのでは、と思ったりします。

 

いずれにせよ、無事動いているようでおめでとうございます。

yukijnoriyukijnori

ありがとうございます。

 

同じ問題に遭遇していたとは、、本当に奇遇ですね(笑)

 

ただ、私の場合以下だけでは、無理なようです。cacert.crtはプライベートCAの証明書だと思うのですが、

(私の場合は、cacert.pem)インポートしただけでは、それを見に行ってくれません。

keytool -import -file ./demoCA/cacert.crt -trustcacerts -alias tomcat -keystore clientauth.keystore

 

そこで、Tomcatの起動スクリプトシェルに、

JAVA_OPTS="-Djavax.net.ssl.trustStore=/home/demoCA/trust.keystore -Djavax.net.ssl.trustStorePassword=pass"

と追加したところ、きちんとtrustStoreを見に行ってくれるようになりました。

この変更は必須なのでしょうか。。でもそちらでは行っていないと思うので、疑問が残りますね。

 

色々とお世話になりました。ありがとうございます!