Eclipseを使用して、TLS 1.3をサポートし、PKCS#12形式のSSLルート証明書およびクライアント証明書を利用するJava 21のHTTPS通信を実装するには、以下の手順で2つのプロジェクトを作成します。
- 証明書の作成
まず、keytoolを使用して、自己署名のCA証明書、サーバー証明書、およびクライアント証明書を作成します。以下の手順で進めます。
1.自己署名のCA証明書を作成
keytool -genkeypair -alias myca -keyalg RSA -keysize 2048 -validity 3650 -dname "CN=MyCA, OU=Dev, O=MyCompany, L=City, ST=State, C=JP" -keystore myca.p12 -storetype PKCS12 -storepass capassword -keypass capassword
2.CA証明書をエクスポート
keytool -exportcert -alias myca -keystore myca.p12 -storepass capassword -rfc -file myca.crt
3.サーバーのキーストアと証明書署名要求(CSR)を作成
keytool -genkeypair -alias server -keyalg RSA -keysize 2048 -validity 3650 -dname "CN=localhost, OU=Dev, O=MyCompany, L=City, ST=State, C=JP" -keystore server.p12 -storetype PKCS12 -storepass serverpassword -keypass serverpassword
keytool -certreq -alias server -keystore server.p12 -storepass serverpassword -file server.csr
4.CA証明書でサーバー証明書を署名
keytool -gencert -alias myca -keystore myca.p12 -storepass capassword -infile server.csr -outfile server.crt -validity 3650 -ext KU=digitalSignature,keyEncipherment -ext SAN=DNS:localhost
5.サーバーのキーストアにCA証明書と署名済みサーバー証明書をインポート
keytool -importcert -alias myca -file myca.crt -keystore server.p12 -storepass serverpassword -noprompt
keytool -importcert -alias server -file server.crt -keystore server.p12 -storepass serverpassword
6.クライアントのキーストアと証明書署名要求(CSR)を作成
keytool -genkeypair -alias client -keyalg RSA -keysize 2048 -validity 3650 -dname "CN=Client, OU=Dev, O=MyCompany, L=City, ST=State, C=JP" -keystore client.p12 -storetype PKCS12 -storepass clientpassword -keypass clientpassword
keytool -certreq -alias client -keystore client.p12 -storepass clientpassword -file client.csr
7.CA証明書でクライアント証明書を署名
keytool -gencert -alias myca -keystore myca.p12 -storepass capassword -infile client.csr -outfile client.crt -validity 3650 -ext KU=digitalSignature,keyEncipherment
8.クライアントのキーストアにCA証明書と署名済みクライアント証明書をインポート
keytool -importcert -alias myca -file myca.crt -keystore client.p12 -storepass clientpassword -noprompt
keytool -importcert -alias client -file client.crt -keystore client.p12 -storepass clientpassword
サーバー側のjava
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
public class TLSClient {
public static void main(String[] args) throws Exception {
// クライアントキーストアのパスワード
char[] clientPassphrase = "clientpassword".toCharArray();
// クライアントキーストアの読み込み
KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
try (var fis = Files.newInputStream(Path.of("client.p12"))) {
clientKeyStore.load(fis, clientPassphrase);
}
// キーマネージャーファクトリの初期化
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(clientKeyStore, clientPassphrase);
// トラストストアの読み込み(サーバー証明書の検証用)
KeyStore trustStore = KeyStore.getInstance("PKCS12");
try (var fis = Files.newInputStream(Path.of("myca.p12"))) {
trustStore.load(fis, "capassword".toCharArray());
}
// トラストマネージャーファクトリの初期化
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(trustStore);
// SSLコンテキストの作成
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// HttpClientの作成
HttpClient client = HttpClient.newBuilder()
.sslContext(sslContext)
.build();
// HTTPリクエストの作成
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://localhost:8443"))
.GET()
.build();
// リクエストの送信とレスポンスの取得
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
// レスポンスの表示
System.out.println("ステータスコード: " + response.statusCode());
System.out.println("レスポンスボディ: " + response.body());
}
}
クライアント側の実装
import javax.net.ssl.;
import java.io.;
import java.security.KeyStore;
public class TLSServer {
public static void main(String[] args) {
try {
// キーストアとトラストストアのパスワード
char[] keystorePass = "serverpassword".toCharArray();
char[] truststorePass = "capassword".toCharArray();
// キーストアの読み込み
KeyStore keystore = KeyStore.getInstance("PKCS12");
try (FileInputStream keystoreFis = new FileInputStream("server.p12")) {
keystore.load(keystoreFis, keystorePass);
}
// キーマネージャーファクトリの初期化
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, keystorePass);
// トラストストアの読み込み
KeyStore truststore = KeyStore.getInstance("PKCS12");
try (FileInputStream truststoreFis = new FileInputStream("myca.p12")) {
truststore.load(truststoreFis, truststorePass);
}
// トラストマネージャーファクトリの初期化
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
tmf.init(truststore);
// SSLコンテキストの作成
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
// SSLサーバーソケットの作成
SSLServerSocketFactory ssf = sslContext.getServerSocketFactory();
try (SSLServerSocket serverSocket = (SSLServerSocket) ssf.createServerSocket(8443)) {
serverSocket.setNeedClientAuth(true); // クライアント認証を要求
System.out.println("TLS 1.3 サーバーが起動しました。ポート: 8443");
while (true) {
try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String line;
while ((line = in.readLine()) != null && !line.isEmpty()) {
System.out.println("受信: " + line);
}
// レスポンスの送信
out.write("HTTP/1.1 200 OK\r\n");
out.write("Content-Type: text/plain\r\n");
out.write("Content-Length: 13\r\n");
out.write("\r\n");
out.write("Hello, World!");
out.flush();
} catch (IOException e) {
System.err.println("クライアントとの通信中にエラーが発生しました: " + e.getMessage());
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}