self signed 인증서로 서버 ssl을 처리하면 client에서는 해당 파일로 ssl 처리를 해야 통신이 가능하다. 참고로 구매한 CA인증파일로 서버 ssl을 처리하면 아래와 같은 처리를 하지 않고도 ssl 통신이 가능하다. 관련내용은 아래 url 참고바람. https://lloydkwon.tistory.com/entry/javs-ssl
다양한 확장자를 가진 인증서가 있다.
cer, csr, pem, der, jks, p12
TrustManagerFactory 을 처리하는 것은 어렵지 않은데
KeyManagerFactory 는 위의 다양한 private key 파일을 처리해야 하는 어려움 때문에 난이도가 높았다.
mqtt_cli 소스를 참고하여 구현한 PrivateKey 클래스 생성로직이다.
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.*;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.operator.InputDecryptorProvider;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;
import org.jetbrains.annotations.NotNull;
import javax.net.ssl.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Collection;
private static @NotNull PrivateKey getPrivateKeyFromFile(final @NotNull File keyFile, String pw) throws Exception {
Security.addProvider(new BouncyCastleProvider());
// read the keyfile
final PEMParser pemParser = new PEMParser(new FileReader(keyFile));
final Object object;
try {
object = pemParser.readObject();
System.out.println(object.getClass().getName());
} catch (final PEMException pe) {
throw new Exception(MALFORMED_KEY);
}
final JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
final PrivateKey privateKey;
if (object instanceof PEMEncryptedKeyPair) {
final char[] password = pw.toCharArray();
final PEMEncryptedKeyPair encryptedPrivateKey = (PEMEncryptedKeyPair) object;
final PEMDecryptorProvider decryptorProvider = new JcePEMDecryptorProviderBuilder().build(password);
final KeyPair keyPair = converter.getKeyPair(encryptedPrivateKey.decryptKeyPair(decryptorProvider));
privateKey = keyPair.getPrivate();
} else if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
final char[] password = pw.toCharArray();
final PKCS8EncryptedPrivateKeyInfo encryptedPrivateKey = (PKCS8EncryptedPrivateKeyInfo) object;
final InputDecryptorProvider decryptorProvider =
new JceOpenSSLPKCS8DecryptorProviderBuilder().build(password);
final PrivateKeyInfo privateKeyInfo = encryptedPrivateKey.decryptPrivateKeyInfo(decryptorProvider);
privateKey = converter.getPrivateKey(privateKeyInfo);
} else if (object instanceof PEMKeyPair) {
privateKey = converter.getPrivateKey(((PEMKeyPair) object).getPrivateKeyInfo());
} else if (object instanceof PrivateKeyInfo) {
privateKey = converter.getPrivateKey((PrivateKeyInfo) object);
} else {
throw new IllegalArgumentException(UNRECOGNIZED_KEY);
}
return privateKey;
}
아래는 관련한 참고 로직 입니다.
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Collection;
public class CertificateConverterUtils {
public static final @NotNull String @NotNull [] FILE_EXTENSIONS = {".pem", ".cer", ".crt"};
public static final @NotNull String NO_VALID_CERTIFICATE =
"The given file contains no valid or supported certificate,";
public static @NotNull Collection<X509Certificate> generateX509Certificates(final @NotNull File keyFile)
throws Exception {
// Instantiate X509 certificate factory
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
try {
// Parse X509 certificate chain
final Collection<? extends Certificate> certificateChainCollection =
cf.generateCertificates(new FileInputStream(keyFile));
// Cast to X509Certificate collection and return it
//noinspection unchecked
return (Collection<X509Certificate>) certificateChainCollection;
} catch (final CertificateException | FileNotFoundException e) {
throw new CertificateException(NO_VALID_CERTIFICATE);
}
}
public static boolean endsWithValidExtension(final @NotNull String fileName) {
for (final String extension : FILE_EXTENSIONS) {
if (fileName.endsWith(extension)) {
return true;
}
}
return false;
}
}