자바 자체(셀프? 사설?)인증서 등록하기
System.Net.WebException: The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
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
이런 오류들은 인증서가 없거나 사설인증서일 경우에 발생한다.
사내인트라넷 같은 시스템에 공인된 상용인증서를 쓰기에는 부담스럽기 때문에 사설인증서를 종종사용한다.
아무 작업없이 사설인증서를 사용하면 위와같은 에러를 만날수 있으며 이를 해결하기 위해서는
이런 사설인증서를 자바 ca 인증파일에 삽입해줘야한다.
#사설인증서 생성
openssl genrsa -out systemv.domain.com.key 2048
openssl req -new -key systemv.domain.com.key -out systemv.domain.com.csr
openssl req -new -key systemv.domain.com.key -x509 -out systemv.domain.com.crt
openssl req -new -x509 -nodes -sha1 -days 3600 -key systemv.domain.com.key -out server_ca.crt
# ssl url 호출 테스트용 파일 sslCall.java
vi sslCall.java
import java.io.*;
import java.security.*;
import java.net.*;
public class sslCall {
public static void main(String[] args) {
String url = "https://systemv.domain.com:443";
String responseMessage = "";
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer sb = new StringBuffer();
System.setProperty ( "java.protocol.handler.pkgs","com.sun.net.ssl.internal.www.protocol");
com.sun.net.ssl.internal.ssl.Provider provider = new com.sun.net.ssl.internal.ssl.Provider();
Security.addProvider(provider);
try{
URL httpsUrl = new URL(url);
URLConnection conn = httpsUrl.openConnection();
conn.setUseCaches(false);
conn.setConnectTimeout(4000);
conn.setDoOutput(true);
conn.connect();
responseMessage = conn.getHeaderField(0);
System.out.println(responseMessage);
is = conn.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
String line = null;
while((line=br.readLine()) != null){
sb.append(line);
}
System.out.println(sb.toString());
}catch(Exception e){
e.printStackTrace();
}
}
}
javac sslCall.java
java sslCall
익셉션나면 문제가 있는거.
# 원격지 인증서 뽑아오기
vi InstallCert.java
import javax.net.ssl.*;
import java.io.*;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
public class InstallCert {
public static void main(String[] args) throws Exception {
String host;
int port;
char[] passphrase;
if ((args.length == 1) || (args.length == 2)) {
String[] c = args[0].split(":");
host = c[0];
port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
String p = (args.length == 1) ? "changeit" : args[1];
passphrase = p.toCharArray();
} else {
System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
return;
}
File file = new File("jssecacerts");
if (file.isFile() == false) {
char SEP = File.separatorChar;
File dir = new File(System.getProperty("java.home") + SEP
+ "lib" + SEP + "security");
file = new File(dir, "jssecacerts");
if (file.isFile() == false) {
file = new File(dir, "cacerts");
}
}
System.out.println("Loading KeyStore " + file + "...");
InputStream in = new FileInputStream(file);
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(in, passphrase);
in.close();
SSLContext context = SSLContext.getInstance("TLS");
TrustManagerFactory tmf =
TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
context.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory factory = context.getSocketFactory();
System.out.println("Opening connection to " + host + ":" + port + "...");
SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
socket.setSoTimeout(10000);
try {
System.out.println("Starting SSL handshake...");
socket.startHandshake();
socket.close();
System.out.println();
System.out.println("No errors, certificate is already trusted");
} catch (SSLException e) {
System.out.println();
e.printStackTrace(System.out);
}
X509Certificate[] chain = tm.chain;
if (chain == null) {
System.out.println("Could not obtain server certificate chain");
return;
}
BufferedReader reader =
new BufferedReader(new InputStreamReader(System.in));
System.out.println();
System.out.println("Server sent " + chain.length + " certificate(s):");
System.out.println();
MessageDigest sha1 = MessageDigest.getInstance("SHA1");
MessageDigest md5 = MessageDigest.getInstance("MD5");
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = chain[i];
System.out.println
(" " + (i + 1) + " Subject " + cert.getSubjectDN());
System.out.println(" Issuer " + cert.getIssuerDN());
sha1.update(cert.getEncoded());
System.out.println(" sha1 " + toHexString(sha1.digest()));
md5.update(cert.getEncoded());
System.out.println(" md5 " + toHexString(md5.digest()));
System.out.println();
}
System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
String line = reader.readLine().trim();
int k;
try {
k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
} catch (NumberFormatException e) {
System.out.println("KeyStore not changed");
return;
}
X509Certificate cert = chain[k];
String alias = host + "-" + (k + 1);
ks.setCertificateEntry(alias, cert);
OutputStream out = new FileOutputStream("jssecacerts");
ks.store(out, passphrase);
out.close();
System.out.println();
System.out.println(cert);
System.out.println();
System.out.println
("Added certificate to keystore 'jssecacerts' using alias '"
+ alias + "'");
}
private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();
private static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder(bytes.length * 3);
for (int b : bytes) {
b &= 0xff;
sb.append(HEXDIGITS[b >> 4]);
sb.append(HEXDIGITS[b & 15]);
sb.append(' ');
}
return sb.toString();
}
private static class SavingTrustManager implements X509TrustManager {
private final X509TrustManager tm;
private X509Certificate[] chain;
SavingTrustManager(X509TrustManager tm) {
this.tm = tm;
}
public X509Certificate[] getAcceptedIssuers() {
throw new UnsupportedOperationException();
}
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
throw new UnsupportedOperationException();
}
public void checkServerTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
this.chain = chain;
tm.checkServerTrusted(chain, authType);
}
}
}
javac InstallCert.java
java InstallCert
# 원격지서버 인증서가져와서 저장
java -cp ./ InstallCert systemv.domain.com
.....에러 어쩌고
.......에러 저쩌고
Enter certificate to add to trusted keystore or 'q' to quit: [1]
뜨면 엔터쳐서 저장함.
...어쩌고
......저쩌고
Added certificate to keystore 'jssecacerts' using alias 'systemv.domain.com-1'
현재경로에 jssecacerts 라는 keystore가 생긴다.
자바에는 기본 keystore가 두개가 있는데 cacerts 와 jssecacerts이다.(읽어들일때 jssecacerts가 우선순위가 높은듯)
$JAVA_HOME/jre/lib/security/ 에 jssecacerts 파일이 없다면 방금 생성된 jssecacerts 파일을 카피하는 것만으로도
아래 나오는 익스포트, 임포트 작업은 필요없다.
# 인증서 추출 ( 패스워드 "changeit" 은 디폴트값이므로 변경했다면 해당 변경값으로 입력)
keytool -exportcert -keystore jssecacerts -storepass changeit -file output.cert -alias systemv.domain.com-1
# 추출한 인증서를 로컬 JDK에 임포트
keytool -importcert -keystore /app/java/jdk1.7.0_40/jre/lib/security/cacerts -storepass changeit -file output.cert -alias systemv.domain.com-1
# 확인해보자
keytool -list -keystore /app/java/jdk1.7.0_40/jre/lib/security/cacerts | grep systemv
# 끝으로 sslCall 로 테스트 실행
java sslCall
익셉션 없이 HTTP/1.1 200 OK 찍히고 소스 보이면 굿
# 삭제는 요로케
keytool -delete -keystore /app/java/jdk1.7.0_40/jre/lib/security/cacerts -storepass changeit -alias systemv.domain.com-1
'리눅스ETC' 카테고리의 다른 글
sftp 로그 남기기 (0) | 2016.03.30 |
---|---|
my.cnf utf8 (0) | 2016.03.30 |
mysqldump (0) | 2016.03.30 |
mariaDB xtrabackup (0) | 2016.03.30 |
MySQL my.cnf (0) | 2016.03.30 |