質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.35%

OpenJDKのcacertsに登録されていないのに、google.co.jpに接続できます

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 3,659

score 24

 前提・実現したいこと

OpenJDK-10.0.2 でhttps接続し、web pageを取得し、加工しようかなと思い
接続テストプログラムを書いています。

 発生している問題・エラーメッセージ

OpenJDKのcacertsをkeytoolで一覧表示すると、alias名とsha256のfingerprintの一覧が得られます。
https://www.google.co.jp/のroot certのfingeprintがcacerts一覧にありません。にもかかわらず、テストプログラムでcertの表示と内容のダンプが取れています。おかしいですね。

 該当のソースコード

import java.io.*;
import java.net.*;
import javax.net.ssl.HttpsURLConnection;
import java.security.cert.Certificate;



public class HttpsTest {
  public static void main(String[] args) {
    String urlString = args[0];
    connectResult(urlString);
  }

    public static void  connectResult(String urlString){
    HttpURLConnection urlconn = null;
    HttpsURLConnection urlconns = null;
    URL url = null;

    try{
        url = new URL(urlString);
    }catch(Exception e){
        System.out.println(e);
        System.exit(1);
    }

    try{
      urlconn = (HttpURLConnection)url.openConnection();
    }catch(Exception e){
        System.out.println(e);
        System.exit(1);
    }

    try{
      urlconn.setRequestMethod("GET");
    }catch(Exception e){
        System.out.println(e);
        System.exit(1);
    }

    try{
        urlconn.connect();
    }catch(Exception e){
        System.out.println(e);
        System.exit(1);
    }

    if(urlString.indexOf("https") > -1){
            urlconns = (HttpsURLConnection)urlconn;
            try{
                Certificate[] certs = urlconns.getServerCertificates();
                for(int i= 0; i < certs.length; i++){
                    System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
                    System.out.println();
                    System.out.println(certs[i].toString());
                }
            }catch(Exception e){
            System.out.println(e);
            System.exit(1);
        }
        }

        System.out.println("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
        System.out.println();
      readPage(urlconn, "UTF-8");

    urlconn.disconnect();

    return;
  }

  public static void readPage(HttpURLConnection urlconn, 
                                                          String charset){
    String line = null; 
        int i = 0;
      boolean continueFlag = false;

    try{
        BufferedReader reader = new BufferedReader(
            new InputStreamReader(urlconn.getInputStream(),charset));

      i = 0;
      continueFlag = true;
      while (continueFlag){
        line = reader.readLine();
        if (line == null){
                    break;
                }
                System.out.println(line);
            }
    }catch(IOException e){}
        return;
  }
}

 試したこと

OracleJDK 10.0.2でも同じです。
実行方法は
>java HttpsTest https://www.google.co.jp/
です。

 補足情報(FW/ツールのバージョンなど)

OpenJDKでもOracleJDKでもcacertsの一覧は以下の方法でできます。
>keytool -list -cacerts > certs.txt

public keyのfingerprint(sha256)はEdgeでサイトを見て、鍵の証明書をみるのが一番楽だと思います。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

少々 try - catchが多かったので、以下で検証はしてみましたが、特にキーストアを何もしてないOpenJDK 10.0.2 ではルートCA証明書が入っていないため、

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at java.base/sun.security.ssl.Alerts.getSSLException(Alerts.java:198)
    at java.base/sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1974)
    at java.base/sun.security.ssl.Handshaker.fatalSE(Handshaker.java:345)
....

となり、OracleJDK 10.0.2 では

2018-08-08 22:24:54,276 INFO o.g.a.j.CertificationReader [main] cert : [
[
  Version: V3
  Subject: CN=*.google.com, O=Google LLC, L=Mountain View, ST=California, C=US
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun EC public key, 256 bits
  public x coord: 78226844107172140816602728215785865852948897417762845700219349569937839729710
  public y coord: 57412027014253819486192935088276186089146207774631521371630436159824343403818
  parameters: secp256r1 [NIST P-256, X9.62 prime256v1] (1.2.840.10045.3.1.7)
  Validity: [From: Wed Jul 25 01:08:25 GMT+09:00 2018,
               To: Wed Oct 03 01:00:00 GMT+09:00 2018]
  Issuer: CN=Google Internet Authority G3, O=Google Trust Services, C=US
  SerialNumber: [    0732f614 c41f4956]

Certificate Extensions: 9
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
.....(中略).....
[8]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 77 C2 B8 50 9A 67 76 76   B1 2D C2 86 D0 83 A0 7E  w..P.gvv.-......
0010: A6 7E BA 4B                                        ...K
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: 1C B7 89 96 E4 53 ED BB   EC DB A8 32 01 9F 2C A3  .....S.....2..,.
0010: CD 6D AD 42 12 77 B3 B8   E6 C9 03 52 60 20 7B 57  .m.B.w.....R` .W
0020: 27 C6 11 B5 3F 67 0D 99   2C 5B 5A CA 22 0A DD 9E  '...?g..,[Z."...
0030: BB 1F 4B 48 3F 8F 02 3D   8B 21 84 45 1D 6D F5 FF  ..KH?..=.!.E.m..
0040: AC 68 89 CD 64 E2 D6 D6   5E 40 C2 8E 2A F7 EF 14  .h..d...^@..*...
0050: D3 36 A4 40 30 F5 32 15   15 92 76 FB 7E 9E 53 EA  .6.@0.2...v...S.
0060: C2 76 FC 39 AD 88 FE 66   92 26 E9 1C C4 38 CD 49  .v.9...f.&...8.I
0070: FA 43 87 F0 5D D6 56 4D   81 D7 7F F1 C2 DD B0 4D  .C..].VM.......M
0080: FE C3 2A 6E 7C 9F 6E 5C   ED 62 42 99 E1 F7 36 EE  ..*n..n\.bB...6.
0090: 14 8C 2C 20 E3 46 97 5A   77 03 C0 A0 C6 4A 88 FD  .., .F.Zw....J..
00A0: 40 22 87 72 5A 18 EA 9C   A5 C7 5A 08 8C E4 05 A4  @".rZ.....Z.....
00B0: 7D B9 84 35 5F 89 36 56   0E 40 3D 12 E8 BB 35 72  ...5_.6V.@=...5r
00C0: ED AF 08 56 4E B0 BB 2E   A9 9B E4 FB 1D 3E 0B 63  ...VN........>.c
00D0: C8 9B 4B 91 44 66 57 C0   14 B4 96 F0 DC 2C 57 3F  ..K.DfW......,W?
00E0: 52 04 AD 95 AA 7D 4D D0   F2 0C 9F 9C 40 E8 D6 55  R.....M.....@..U
00F0: 73 BA 3C DF 90 CB 00 5B   21 11 67 C2 ED 32 1E DE  s.<....[!.g..2..

]

と取得できていますので、Javaランタイム実行時のパスがOracleJDKを指定しているのではないでしょうか。

以下は検証コードです。(ログ出力用にlombok 1.18.0を利用)

package org.github.apz.java10sample;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.Certificate;
import java.util.Arrays;

import javax.net.ssl.HttpsURLConnection;

import lombok.extern.log4j.Log4j2;

/**
 * @author a-pz
 *
 */
@Log4j2
public class CertificationReader {
    public void connect(String inputUrl) throws IOException {
        URL url = new URL(inputUrl);

        URLConnection urlConnection = url.openConnection();
        HttpsURLConnection https = (HttpsURLConnection)urlConnection;
        https.setRequestMethod("GET");
        https.connect();

        Certificate[] certs = https.getServerCertificates();

        Arrays.stream(certs).forEach(cert -> {
            log.info("cert : {}", cert.toString());
        });

        https.disconnect();
    }

    public static void main(String argv[]) throws Exception {
        CertificationReader certReader = new CertificationReader();
        certReader.connect("https://www.google.co.jp");
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/08/10 00:31

    確かに、keytoolは独立したツールではあるのですが、同じパッケージからの提供物なのだから見てもいいのではないか…?と思うところはありますね…。

    キャンセル

  • 2018/08/10 11:31

    keytoolの-cacertsオプションは自パッケージのみを対象にしているが、私のプログラムの実行では、すべてのpathのcacertsを探索しての接続の仕様になっているのかな?と考えると分かるように思えるのですが。
    Windowsのpathの見落としで変な質問をしてしまいました。try/catchを動作ごとにつけているのは、まだHttp(s)URLConnectionまわりでのExceptionの出方が分からないので書いているだけです。Exceptionにしているのは、結構2つ以上のExceptionが発生することもあるので、めんどくさいのでIOExcelptionだけでなく、catchできるように考えたからです。
    まだ、この辺の動作を探っている段階です。

    キャンセル

  • 2018/08/10 11:35

    keytoolでGlobalSign root CA 2 をimportしたら、www.goolg.co.jpは接続できています。OpenJDKのcacertsはまずは80個で結構漏れが多いので用心です。

    キャンセル

0

OpenJDKのcacertsをkeytoolで一覧表示すると、alias名とsha256のfingerprintの一覧が得られます。

いまgoogle.co.jpのドメインをSSL Testにかけてみたところ、ルート証明書のハッシュはSHA-1でした。SHA-256のリストと符合しないのも、そういう理由ではないでしょうか。

なお、ルート証明書の真正性はこのハッシュで確認するわけではないので、SHA-1であっても特に問題はありません(過去の質問)。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/31 17:53

    すみません。書き方が悪かったのでと思います。cacertsの一覧にpublic keyのfingerprintが便宜上表示され、それでcertを区別しています。cacertsのalias名は適当なので、certsの区別にsha256にfingerprintを使って、識別しているだけです。おっしゃる通りgoogleのroot certの署名アルゴリズムはsha-1です。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る