Hello all
I want to generate a certificate using keystore than add this to my sevrer and browse my sever using IE. I need the steps for generating the certificate in plain english as all what i read in the internet is hard to be understod. The server socket is:
SSLServerSocketFactory ssf = (SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
SSLServerSocket Server = (SSLServerSocket)ssf.createServerSocket(1234);
String[] cipher = {"SSL_DH_anon_WITH_RC4_128_MD5"};
Server.setEnabledCipherSuites(cipher);
The certificate code is this but not sure where to pu it in my server:
InputStream infil = new FileInputStream("server.cer");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(infil);
infil.close();
KeyStore ks = null;
ks = KeyStore.getInstance("JKS", "SUN");
InputStream is = null;
is = new FileInputStream(new File("./keystore"));
ks.load(is,"rootroot".toCharArray());
See the Javadoc/Security/JSSE Reference.
Related
I am working on an android application which need to download through HTTPS connection. But I got SSLHandshakeException - handshake failed.
What I have done is as below
First,using openssl to get server certificate chain
openssl s_client -connect www.coles.com.au:443
And got
Certificate chain
0 s:/C=AU/ST=Victoria/L=Hawthorn East/O=Coles Supermarkets Australia Pty Ltd/OU=Web Team/CN=coles.com.au
i:/C=US/O=thawte, Inc./CN=thawte SSL CA - G2
1 s:/C=US/O=thawte, Inc./CN=thawte SSL CA - G2
i:/C=US/O=thawte, Inc./OU=Certification Services Division/OU=(c) 2006 thawte, Inc. - For authorized use only/CN=thawte Primary Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIE3zCCA8egAwIBAgIQfc9y5DSMNxERU663wd4m+DANBgkqhkiG9w0BAQsFADBB
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3RlLCBJbmMuMRswGQYDVQQDExJ0
aGF3dGUgU1NMIENBIC0gRzIwHhcNMTUxMDMwMDAwMDAwWhcNMTgxMDI5MjM1OTU5
WjCBkTELMAkGA1UEBhMCQVUxETAPBgNVBAgMCFZpY3RvcmlhMRYwFAYDVQQHDA1I
YXd0aG9ybiBFYXN0MS0wKwYDVQQKDCRDb2xlcyBTdXBlcm1hcmtldHMgQXVzdHJh
bGlhIFB0eSBMdGQxETAPBgNVBAsMCFdlYiBUZWFtMRUwEwYDVQQDDAxjb2xlcy5j
b20uYXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBoLhSH1Q/3YGQ
d0d5FEza3EaW4bWYDfHtg0oReJ8OvONWYpPgKZ0HZPUi6m6CDhWKXRmxZbiRDGQR
ihRYpAcRnw/DbkN6+eDSHU0I5eZD4YpdbhvAzeVOkiSyQXipvAJZFvomHsjCIvIu
g/2EInwAeTkgDSJY+PUbiiy+Ooko/H2XpjV0+C3eb2RY/pNV+Df5FG1bzVtEWNna
ncqYK9tJlyfDNM9TENzZdxmLtJsFYzlniJcxVgjPw4uSI4N3Cnr3n3PuSKSQuavl
D7k4H7wuwPvOn6l1wAj7fbgq16ZfF9vUvLXsn/yc99V1/7oYIVA4KDxgLhU10IVp
k2JPDZN9AgMBAAGjggGAMIIBfDApBgNVHREEIjAgghB3d3cuY29sZXMuY29tLmF1
ggxjb2xlcy5jb20uYXUwCQYDVR0TBAIwADBuBgNVHSAEZzBlMGMGBmeBDAECAjBZ
MCYGCCsGAQUFBwIBFhpodHRwczovL3d3dy50aGF3dGUuY29tL2NwczAvBggrBgEF
BQcCAjAjDCFodHRwczovL3d3dy50aGF3dGUuY29tL3JlcG9zaXRvcnkwDgYDVR0P
AQH/BAQDAgWgMB8GA1UdIwQYMBaAFMJPSFf80U+awF04fQ4F29kutVJgMCsGA1Ud
HwQkMCIwIKAeoByGGmh0dHA6Ly90ai5zeW1jYi5jb20vdGouY3JsMB0GA1UdJQQW
MBQGCCsGAQUFBwMBBggrBgEFBQcDAjBXBggrBgEFBQcBAQRLMEkwHwYIKwYBBQUH
MAGGE2h0dHA6Ly90ai5zeW1jZC5jb20wJgYIKwYBBQUHMAKGGmh0dHA6Ly90ai5z
eW1jYi5jb20vdGouY3J0MA0GCSqGSIb3DQEBCwUAA4IBAQAkm5BJW0u7ZJFGVWip
xo/poAFHNMImBfofz8WJGN/npJwLKV0mV8FX6dRPEAjPWWT+I/JonwX7VVxAgUWj
3bl+XdIU3hj8cRh3yDnEvhKVKs3orr/jQnxSNx4JZCwmPUIuKK58R1dYCRV/hT7l
YYDMXj+RrAjhrgu7IgZJDCV9kcznBqMdbHLOb/P4PX6j8CsCufS6iGjKhBHTL/49
uuL9ACqH6BgGVctm4kELGcyS6e+VJ9rHI3P+1muOk4wKEVjps9rbPOmpUTk8WhXb
RghAwHrtQZEZMIAVMg2ksCkl/NGRl64Q1W/lW2JHun6ApdXPsGzTvzp3+Kmhrf5p
mLNK
-----END CERTIFICATE-----
subject=/C=AU/ST=Victoria/L=Hawthorn East/O=Coles Supermarkets Australia Pty Ltd/OU=Web Team/CN=coles.com.au
issuer=/C=US/O=thawte, Inc./CN=thawte SSL CA - G2
---
No client certificate CA names sent
Peer signing digest: SHA1
Then go to thawte website(https://search.thawte.com/support/ssl-digital-certificates/index?page=content&id=SO26817&actp=RSS&viewlocale=en_US#links) to download CA certificate(tell me if I did wrong or from wrong place to download) which is thawte_SSL_CA_G2.cer
Third, I have below code to connect
String url = "https://www.coles.com.au";
String strContent = "";
HttpURLConnection connection;
AssetManager assetManager = context.getAssets();
InputStream caInput = null;
try{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
caInput = assetManager.open("thawte_SSL_CA_G2.cer");
Certificate ca = cf.generateCertificate(caInput);
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
URL urlObj = new URL(url);
HttpsURLConnection urlConnection =
(HttpsURLConnection)urlObj.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while(null != (strContent= reader.readLine())){
System.out.println(strContent);
}
}
catch (IOException e){
String exception = e.getMessage();
System.out.println(exception);
}
I use wireshark to capture and observe below happened
-> Client Hello
<- Server Hello
<- Certificate
<- Server Key Exchange
-> Client Key Exchange, Change Cipher Spec, Hello Request, Hello Request
<- FIN
Please help me on why I got handshake failed.
You should add all the ICA (intermediate certificates) and CA.
You could do the following
openssl s_client -showcerts -connect www.coles.com.au:443
Add all the certificates you receive to your trust store. (Strictly speaking only ICA and CA are enough in trust store)
I am new to Java and SSLSocket. I want to use a specified .cer file to establish a SSLSocket in client part. I search it in google, but doesn't find good solution to it. And here is my code:
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(new FileInputStream("myCer.cer"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
SSLSocket sock = (SSLSocket)context.getSocketFactory().createSocket("...",21000); //"...": here I ignore the host name. The address and port is right.
sock.setUseClientMode(true);
if(sock.isConnected()) {
System.out.println("Connected...");
}
else
{
System.out.println("Connect Fails...");
}
Login.pbLogin login = Login.pbLogin.newBuilder().setUserID("dbs")
.setPassword("abcd1234")
.setNewPassword("")
.setClientVersion("1.0.0.0")
.setRestarted(true)
.build();
OutputStream outputStream =sock.getOutputStream();
byte[] b1=login.getClass().getSimpleName().getBytes("UTF-8");
byte[] b2=login.toByteArray();
byte[] bytes = ByteBuffer.allocate(4).putInt(b1.length + b2.length).array();
outputStream.write(bytes);
outputStream.write(b1); //login.getClass().getSimpleName().getBytes("UTF-8")
outputStream.write(b2); //login.toByteArray()
outputStream.flush();
byte[] content = new byte[100];
int bytesRead = -1;
InputStream inputStream = sock.getInputStream();
String str;
while(( bytesRead = inputStream.read( content) ) != -1){
System.out.println("OK ,receive.....");
// str = new String(Arrays.copyOfRange(content,0,bytesRead), StandardCharsets.UTF_8);
//System.out.println(str);
}
I use TCPViewer to see, the SSLSocket is in Established state, but when executing outstream.write , the SSLsocket will be Close_wait state and cause exception:
Exception in thread "main" java.net.SocketException: Software caused connection abort: socket write error.
So I couldn't write the info to server, and exit program. I guess the SSLSocket is not established successfully, but Tcpviewer show it is established early, and it's in Connected state(print "connected."). But when try to write the outputstream, it will in Close_wait state. Could you help me to sort it out?
Then I found the reason today. The code has no issue, the reason is that server part can't parse the protocol buffer (pblogin) correctly, which causes exception, so it close the socket. As a result , the state will be in close_wait.Since I find the reason , wish I can solve it by myself.
I am new to SSl server sockets. All I am tying to do is to read data over SSL.
My application listens on port 8000. Please give me few steps on how I can do this. When I have a certificate (on my disc), how can I establish the SSL server socket and read from client ?
Here are my steps
1) reading server.crt from file and making X509Certificate (has public certificate and private key)
2) Getting instance of JKS keystore
3) Get instance of context
4) create server socket over the port (8000)
InputStream in = new DataInputStream(new FileInputStream(new File("server.crt")));
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null, null);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(in);
in.close();
ks.setCertificateEntry("dts", cert);
char[] newpass = "password".toCharArray();
String name = "mykeystore.ks";
FileOutputStream output = new FileOutputStream(name);
ks.store(output, newpass);
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, "password".toCharArray());
try{
System.setProperty("javax.net.ssl.keyStore","mykeystore.ks");
System.setProperty("javax.net.ssl.keyStorePassword","password");
System.setProperty("javax.net.debug","all");
SSLContext context = SSLContext.getInstance("TLSv1.2");
context.init(kmf.getKeyManagers(), null, null);
SSLServerSocketFactory sslServerSocketfactory = context.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket)sslServerSocketfactory.createServerSocket(8000);
SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
InputStream dataIN = sslSocket.getInputStream();
byte[] hello = new byte[20];
dataIN.read(hello);
System.out.println(new String(hello));
dataIN.close();
} catch (IOException e){
e.printStackTrace();
}
I got the answer for my question, I did research on how to setup my own keystore with self signed certificate. This way helped me.
ping me for a detailed solutions.
I'm trying to skin this cat: Use PEM Encoded CA Cert on filesystem directly for HTTPS request? another way.
Java has a class KeyStore.TrustedCertificateEntry, but I can't figure out how to load a certificate into it. My code looks similar to below:
import java.security.KeyStore.TrustedCertificateEntry;
...
X509Certificate ca = (X509Certificate) CertificateFactory(...);
KeyStore ks = TrustedCertificateEntry(ca);
And:
X509Certificate ca = (X509Certificate) CertificateFactory(...);
KeyStore ks = KeyStore.TrustedCertificateEntry(ca);
And:
X509Certificate ca = (X509Certificate) CertificateFactory(...);
KeyStore ks = new KeyStore.TrustedCertificateEntry(ca);
And:
X509Certificate ca = (X509Certificate) CertificateFactory(...);
KeyStore ks = new KeyStore.TrustedCertificateEntry(ca);
The program fails to compile with errors similar to:
SuperCert.java:33: error: cannot find symbol
KeyStore ks = TrustedCertificateEntry(ca);
^
symbol: method TrustedCertificateEntry(X509Certificate)
location: class TestCert
After loading my X509 cert into the KeyStore, I plan on using it in a TrustManagerFactory and ultimately fetching a web page with HttpsURLConnection.
How does one load a X509Certificate into a TrustedCertificateEntry?
I found it based on Vit Hnilica's answer at loading a certificate from keystore. I"m going to leave the question with this answer since most Stack Overflow answers start with "convert with openssl, then use keytool ...".
Hat's off to Vit for posting that answer. Hnilica's answer is the only one I found after wading through pages of similar questions and answers on Stack Overflow.
String CA_FILE = ...;
FileInputStream fis = new FileInputStream(CA_FILE);
X509Certificate ca = (X509Certificate) CertificateFactory.getInstance(
"X.509").generateCertificate(new BufferedInputStream(fis));
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null, null);
ks.setCertificateEntry(Integer.toString(1), ca);
TrustManagerFactory tmf = TrustManagerFactory
.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(ks);
There is also another approach.
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(file));
keyStore.setEntry(alias, new KeyStore.TrustedCertificateEntry(certificate), null);
ProtectionParameter for TrustedCertificateEntry should be null.
How can one programmatically obtain a KeyStore from a PEM file containing both a certificate and a private key? I am attempting to provide a client certificate to a server in an HTTPS connection. I have confirmed that the client certificate works if I use openssl and keytool to obtain a jks file, which I load dynamically. I can even get it to work by dynamically reading in a p12 (PKCS12) file.
I'm looking into using the PEMReader class from BouncyCastle, but I can't get past some errors. I'm running the Java client with the -Djavax.net.debug=all option and Apache web server with the debug LogLevel. I'm not sure what to look for though. The Apache error log indicates:
...
OpenSSL: Write: SSLv3 read client certificate B
OpenSSL: Exit: error in SSLv3 read client certificate B
Re-negotiation handshake failed: Not accepted by client!?
The Java client program indicates:
...
main, WRITE: TLSv1 Handshake, length = 48
main, waiting for close_notify or alert: state 3
main, Exception while waiting for close java.net.SocketException: Software caused connection abort: recv failed
main, handling exception: java.net.SocketException: Software caused connection abort: recv failed
%% Invalidated: [Session-3, TLS_RSA_WITH_AES_128_CBC_SHA]
main, SEND TLSv1 ALERT: fatal, description = unexpected_message
...
The client code :
public void testClientCertPEM() throws Exception {
String requestURL = "https://mydomain/authtest";
String pemPath = "C:/Users/myusername/Desktop/client.pem";
HttpsURLConnection con;
URL url = new URL(requestURL);
con = (HttpsURLConnection) url.openConnection();
con.setSSLSocketFactory(getSocketFactoryFromPEM(pemPath));
con.setRequestMethod("GET");
con.setDoInput(true);
con.setDoOutput(false);
con.connect();
String line;
BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
while((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
con.disconnect();
}
public SSLSocketFactory getSocketFactoryFromPEM(String pemPath) throws Exception {
Security.addProvider(new BouncyCastleProvider());
SSLContext context = SSLContext.getInstance("TLS");
PEMReader reader = new PEMReader(new FileReader(pemPath));
X509Certificate cert = (X509Certificate) reader.readObject();
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
keystore.setCertificateEntry("alias", cert);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, null);
KeyManager[] km = kmf.getKeyManagers();
context.init(km, null, null);
return context.getSocketFactory();
}
I noticed the server is outputing SSLv3 in the log while the client is TLSv1. If I add the system property -Dhttps.protocols=SSLv3 then the client will use SSLv3 as well, but I get the same error message. I've also tried adding -Dsun.security.ssl.allowUnsafeRenegotiation=true with no change in outcome.
I've googled around and the usual answer for this question is to just use openssl and keytool first. In my case I need to read the PEM directly on the fly. I'm actually porting a C++ program that already does this, and frankly, I'm very surprised how difficult it is to do this in Java. The C++ code:
curlpp::Easy request;
...
request.setOpt(new Options::Url(myurl));
request.setOpt(new Options::SslVerifyPeer(false));
request.setOpt(new Options::SslCertType("PEM"));
request.setOpt(new Options::SslCert(cert));
request.perform();
I figured it out. The problem is that the X509Certificate by itself isn't sufficient. I needed to put the private key into the dynamically generated keystore as well. It doesn't seem that BouncyCastle PEMReader can handle a PEM file with both cert and private key all in one go, but it can handle each piece separately. I can read the PEM into memory myself and break it into two separate streams and then feed each one to a separate PEMReader. Since I know that the PEM files I'm dealing with will have the cert first and the private key second I can simplify the code at the cost of robustness. I also know that the END CERTIFICATE delimiter will always be surrounded with five hyphens. The implementation that works for me is:
protected static SSLSocketFactory getSocketFactoryPEM(String pemPath) throws Exception {
Security.addProvider(new BouncyCastleProvider());
SSLContext context = SSLContext.getInstance("TLS");
byte[] certAndKey = fileToBytes(new File(pemPath));
String delimiter = "-----END CERTIFICATE-----";
String[] tokens = new String(certAndKey).split(delimiter);
byte[] certBytes = tokens[0].concat(delimiter).getBytes();
byte[] keyBytes = tokens[1].getBytes();
PEMReader reader;
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(certBytes)));
X509Certificate cert = (X509Certificate)reader.readObject();
reader = new PEMReader(new InputStreamReader(new ByteArrayInputStream(keyBytes)));
PrivateKey key = (PrivateKey)reader.readObject();
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
keystore.setCertificateEntry("cert-alias", cert);
keystore.setKeyEntry("key-alias", key, "changeit".toCharArray(), new Certificate[] {cert});
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, "changeit".toCharArray());
KeyManager[] km = kmf.getKeyManagers();
context.init(km, null, null);
return context.getSocketFactory();
}
Update: It seems this can be done without BouncyCastle:
byte[] certAndKey = fileToBytes(new File(pemPath));
byte[] certBytes = parseDERFromPEM(certAndKey, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
byte[] keyBytes = parseDERFromPEM(certAndKey, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----");
X509Certificate cert = generateCertificateFromDER(certBytes);
RSAPrivateKey key = generatePrivateKeyFromDER(keyBytes);
...
protected static byte[] parseDERFromPEM(byte[] pem, String beginDelimiter, String endDelimiter) {
String data = new String(pem);
String[] tokens = data.split(beginDelimiter);
tokens = tokens[1].split(endDelimiter);
return DatatypeConverter.parseBase64Binary(tokens[0]);
}
protected static RSAPrivateKey generatePrivateKeyFromDER(byte[] keyBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory factory = KeyFactory.getInstance("RSA");
return (RSAPrivateKey)factory.generatePrivate(spec);
}
protected static X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
return (X509Certificate)factory.generateCertificate(new ByteArrayInputStream(certBytes));
}
Although the answer of Ryan works well I want to provide an alternative for other developers as I faced a similar challenge in the past where I also needed to handle encrypted private keys in pem format. I have created a library to simplify loading pem files and creating SSLSocketFactory or SSLContext out of it, see here: GitHub - SSLContext Kickstart I hope you like it :)
The pem files can be loaded with the following snippet:
var keyManager = PemUtils.loadIdentityMaterial("certificate-chain.pem", "private-key.pem");
var trustManager = PemUtils.loadTrustMaterial("some-trusted-certificate.pem");
var sslFactory = SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
var sslContext = sslFactory.getSslContext();
var sslSocketFactory = sslFactory.getSslSocketFactory();
Coming back to your main question, with the above snippet it is not needed to create a keystore object from the pem files. It will take care of that under the covers and it will map it to a KeyManager instance.