I have an android app that needs to connect to a server using REST. I use Retrofit 2 for the requests and it works well.
The problem is when I want to use an SSL connection. With open ssl, i have a client.crt, myPrivateKey.pem and request.csr. I also have a rootCA that I used to encrypt the client and the server certificate.
When I check online, I find a lot of solutions with one CA files.
This is the code I have so far.
// https://developer.android.com/training/articles/security-ssl.html#java
private OkHttpClient initClient(boolean ssl) {
if (ssl) {
SSLSocketFactory sslSocketFactory = null;
X509TrustManager x509TrustManager = null;
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream certificateFileCRT = mContext.getResources().openRawResource(R.raw.client);
Certificate certCRT = cf.generateCertificate(certificateFileCRT);
System.out.println("ca=" + ((X509Certificate) certCRT).getSubjectDN());
certificateFileCRT.close();
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", certCRT);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
x509TrustManager = (X509TrustManager) trustManagers[0];
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[]{x509TrustManager}, null);
sslSocketFactory = sslContext.getSocketFactory();
} catch (CertificateException |IOException | KeyStoreException | NoSuchAlgorithmException | KeyManagementException e) {
e.printStackTrace();
}
return new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.sslSocketFactory(sslSocketFactory, x509TrustManager)
.build();
// return getUnsafeOkHttpClient();
} else {
return new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.build();
}
}
When I send a request to the client I get java.security.cert.CertPathValidatorException trust anchor for certification path not found.
Can you please help me creating my client with my certificate and my key!
I fixed my code base from this website
private OkHttpClient initClient() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyManagementException {
// Trust self signed certificate
InputStream certificateFileCRT = mContext.getResources().openRawResource(R.raw.server);
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(certificateFileCRT);
String alias = cert.getSubjectX500Principal().getName();
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustStore.setCertificateEntry(alias, cert);
// KeyStore containing client certificate
KeyStore keyStore = KeyStore.getInstance("PKCS12");
InputStream fis = mContext.getResources().openRawResource(R.raw.client);
keyStore.load(fis, "PASSWORD".toCharArray());
// Build an SSL context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, "PASSWORD".toCharArray());
KeyManager[] keyManagers = kmf.getKeyManagers();
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(trustStore);
TrustManager[] trustManagers = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(keyManagers, trustManagers, null);
return new OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.sslSocketFactory(sslContext.getSocketFactory())
.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
})
.build();
}
Related
I need a post request to the server where I will authorize with a certificate. I have the certificate in file.p12 secured by a password. I think I have checked all the solutions on this site and unfortunately none of them work.
I wanted to use OkHttp, but all solutions use libraries that have already been removed.
KeyStore ks = KeyStore.getInstance("PKCS12");
FileInputStream fis = new FileInputStream("C://tls.p12");
ks.load(fis, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, "password".toCharArray());
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(kmf.getKeyManagers(), null, null);
URL url = new URL("https://.....");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
}
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { trustManager }, null);
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sc.getSocketFactory(), trustManager)
.build();
I have a problem in my springboot project.
I have to send rest call to other server(https:///....).
And i also have to use cert key(.pem file) in java.
When i use curl command in linux server(ubuntu), i can get success response.
curl -X GET --cert <pem file path>:<password> https://<serverurl>:4443
But my problem is i have to use RestTemplate in my Springboot java project.
So i tried to config a few steps but i failed.
Is there anybody who knows use config cert(pem) in resttemplate?
My RestTemplateConfig is
#Configuration
public class RestTemplateConfig {
private static Logger logger = LoggerFactory.getLogger(RestTemplateConfig.class);
#Autowired
private Environment env;
// .crt path
#Value("${cert.path}")
private String certFile;
// .p12 path
#Value("${bixby.reward.p12.path}")
private String p12File;
// .jks path
#Value("${http.client.ssl.trust-store}")
private Resource trustStore;
//password
#Value("${http.client.ssl.trust-store-password}")
private char[] trustStorePassword;
#Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager cm = getConnectionManager(2000);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.setProxy(getProxyHost())
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.build();
HttpComponentsClientHttpRequestFactory componentsClientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
componentsClientHttpRequestFactory.setHttpClient(httpClient);
componentsClientHttpRequestFactory.setConnectTimeout(Constants.CONNECTION_TIME_OUT);
componentsClientHttpRequestFactory.setReadTimeout(Constants.READ_TIME_OUT);
RestTemplate restTemplate = new RestTemplate(componentsClientHttpRequestFactory);
return restTemplate;
}
private HttpHost getProxyHost() {
HttpHost proxyHost = null;
String httpProxy = env.getProperty("http_proxy");
if(httpProxy != null) {
try {
String host = null;
int port = -1;
httpProxy = httpProxy.replace("https://", "").replace("http://", "");
String [] proxy = httpProxy.split(":");
host = proxy[0];
if(proxy.length == 1) {
port = 80;
} else {
port = Integer.parseInt(proxy[1]);
}
proxyHost = new HttpHost(host, port);
} catch(Exception e) {
logger.error("[IMPLICIT_ERROR] RestTemplate proxy setting error.", e);
}
}
return proxyHost;
}
private SSLConnectionSocketFactory getSSLSocketFactoryForNoVerification() {
SSLConnectionSocketFactory scsf = null;
try {
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
File f= new File("");
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(null, acceptingTrustStrategy)
.build();
scsf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
} catch (Exception e) {
logger.error("[IMPLICIT_ERROR] RestTemplate ssl connection socket factory setting error.", e);
}
return scsf;
}
private SSLSocketFactory getSSLSocketFactory() {
SSLContext sslContext = null;
try {
InputStream certInputStream = new FileInputStream(certFile);
byte[] certAndKey = ByteStreams.toByteArray(certInputStream);
byte[] certBytes = parseDERFromCert(certAndKey, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");
X509Certificate cert = generateCertificateFromDER(certBytes);
// private key
KeyStore pkeyStore = KeyStore.getInstance("PKCS12");
pkeyStore.load(new FileInputStream(p12File), trustStorePassword.toCharArray());
// "server" is alias
Key pvtKey = pkeyStore.getKey("server", trustStorePassword.toCharArray());
java.security.cert.Certificate[] keychain = pkeyStore.getCertificateChain("server");
KeyStore keystore = KeyStore.getInstance("JKS");
keystore.load(null);
keystore.setCertificateEntry("cert-alias", cert);
keystore.setKeyEntry("key-alias", pvtKey, "changeit".toCharArray(), keychain);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, "changeit".toCharArray());
TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;
sslContext = SSLContexts.custom().loadTrustMaterial(keystore, acceptingTrustStrategy).build();
KeyManager[] km = kmf.getKeyManagers();
sslContext.init(km, null, null);
} catch (Exception e) {
logger.error("[IMPLICIT_ERROR] RestTemplate ssl connection socket factory setting error.", e);
}
return sslContext.getSocketFactory();
}
private PoolingHttpClientConnectionManager getConnectionManager(int maxTotal) {
SSLContext sslContext;
Registry<ConnectionSocketFactory> registry = null;
try {
sslContext = SSLContexts
.custom()
.loadTrustMaterial(trustStore.getFile(),
trustStorePassword)
.build();
// Since only our own certs are trusted, hostname verification is probably safe to bypass
HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.getDefaultHostnameVerifier();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);//new NoopHostnameVerifier());
registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", new PlainConnectionSocketFactory())
//.register("https", getSSLSocketFactoryForNoVerification())
//.register("https", new SSLConnectionSocketFactory(getSSLSocketFactory(), new NoopHostnameVerifier()))
.register("https", sslSocketFactory)
.build();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
cm.setMaxTotal(maxTotal);
cm.setDefaultMaxPerRoute(maxTotal);
return cm;
}
private byte[] parseDERFromCert(byte[] cert, String beginDelimiter, String endDelimiter) {
String data = new String(cert);
String[] tokens = data.split(beginDelimiter);
tokens = tokens[1].split(endDelimiter);
return DatatypeConverter.parseBase64Binary(tokens[0]);
}
private X509Certificate generateCertificateFromDER(byte[] certBytes) throws CertificateException {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
return (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(certBytes));
}}
I reciverd a .p12 certificate, that I need to use a web service. If I import the certificate in my browser, I can access the service, but if I try to perform a POST request, I get this error:
Caused by: java.security.cert.CertPathValidatorException: critical policy qualifiers present in certificate
at sun.security.provider.certpath.PKIXMasterCertPathValidator.validate(PKIXMasterCertPathValidator.java:139)
at sun.security.provider.certpath.PKIXCertPathValidator.doValidate(PKIXCertPathValidator.java:328)
at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:178)
at java.security.cert.CertPathValidator.validate(CertPathValidator.java:250)
at sun.security.validator.PKIXValidator.doValidate(PKIXValidator.java:275)
... 24 more
Here is my code:
KeyStore clientStore = KeyStore.getInstance("PKCS12");
clientStore.load(new FileInputStream("client.p12"), "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientStore, "password".toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(new FileInputStream("client.keystore"), "password".toCharArray());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
TrustManager[] tms = tmf.getTrustManagers();
SSLContext sslContext = null;
sslContext = SSLContext.getInstance("TLS");
sslContext.init(kms, tms, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
URL url = new URL("https://cistest.apis-it.hr:8446/g2bservis");
HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
String query = "<SendDocument></SendDocument>";
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type","text");
con.setDoOutput(true);
con.setDoInput(true);
DataOutputStream output = new DataOutputStream(con.getOutputStream());
output.writeBytes(query);
output.close();
DataInputStream input = new DataInputStream( con.getInputStream() );
for( int c = input.read(); c != -1; c = input.read() )
System.out.print( (char)c );
input.close();
System.out.println("Resp Code:"+con .getResponseCode());
System.out.println("Resp Message:"+ con .getResponseMessage());
The excetion happens on con.getOutputStream()
I resolved the problem by exporting the server's certificate from chrome and using that instead of the default root certificate I had for the page. I noticed that certificate might be the problem, when I was able to open the page in chrome but not in firefox.
I'm trying to make DefaultHttpClient() work with expired SSL certificate.
Android API 2.2
It won't compile because of this line:
SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Error: The constructor SSLSocketFactory(SSLContext) is undefined
What am I doing wrong?
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.http.conn.ssl.SSLSocketFactory;
{...}
SSLContext sslContext = SSLContext.getInstance("SSL");
// set up a TrustManager that trusts everything
sslContext.init(null, new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
System.out.println("getAcceptedIssuers =============");
return null;
}
public void checkClientTrusted(X509Certificate[] certs,
String authType) {
System.out.println("checkClientTrusted =============");
}
public void checkServerTrusted(X509Certificate[] certs,
String authType) {
System.out.println("checkServerTrusted =============");
}
} }, new SecureRandom());
SSLSocketFactory sf = new SSLSocketFactory(sslContext);
Scheme httpsScheme = new Scheme("https", sf, 443);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(httpsScheme);
HttpParams params = new BasicHttpParams();
ClientConnectionManager cm = new SingleClientConnManager(params, schemeRegistry);
//DefaultHttpClient httpclient = new DefaultHttpClient();
DefaultHttpClient httpclient = new DefaultHttpClient(cm, params);
Looking through the documentation for SSLSocketFactory, there doesn't appear to be a constructor:
SSLSocketFactory(javax.net.ssl.SSLContext)
The available constructors are:
SSLSocketFactory(String algorithm, KeyStore keystore, String keystorePassword, KeyStore truststore, SecureRandom random, HostNameResolver nameResolver)
SSLSocketFactory(KeyStore keystore, String keystorePassword, KeyStore truststore)
SSLSocketFactory(KeyStore keystore, String keystorePassword)
SSLSocketFactory(KeyStore truststore)
Am I missing something here?
See also javax.net.ssl.SSLContext
You didn't do anything wrong (except perhaps using some standard Java code).
It appears that the Android implementation of the Apache SSLSocketFactory class does not implement all the constructors of the original Apache SSLSocketFactory class
You'll just have to improvise.
I'd like to programmatically access a site that requires Client certificates, which I have in PEM files. In this application I don't want to add them to my keystore, use keytool, or openssl if I can avoid doing so. I need to deal with them directly in code.
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet("https://my.secure.site.com/url");
// TODO: Specify ca.pem and client.pem here?
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
entity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
How would I 'send' the certificate with the request?
Easiest may well be to use the .p12 format (though the others work fine too - just be careful with extra lines outside the base64 blocks) and add something like:
// systems I trust
System.setProperty("javax.net.ssl.trustStore", "foo");
System.setProperty("javax.net.ssl.trustStorePassword", "changeit");
// my credentials
System.setProperty("javax.net.ssl.keyStoreType", "PKCS12");
System.setProperty("javax.net.ssl.keyStore", "cert.p12");
System.setProperty("javax.net.ssl.keyStorePassword", "changeit");
Or alternatively - use things like
KeyStore ks = KeyStore.getInstance( "pkcs12" );
ks.load( new FileInputStream( ....), "mypassword".toCharArray() );
KeyStore jks = KeyStore.getInstance( "JKS" );
ks.load(...
to create above on the fly instead. And rather than rely on the system property - use somethng like:
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(aboveKeyStore, "changeme".toCharArray());
sslContext = SSLContext.getInstance("SSLv3");
sslContext.init(kmf.getKeyManagers(), null, null);
which keeps it separate from keystore.
DW.
You can create a KeyStore from .pem files like so:
private KeyStore getTrustStore(final InputStream pathToPemFile) throws IOException, KeyStoreException,
NoSuchAlgorithmException, CertificateException {
final KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
// load all certs
for (Certificate cert : CertificateFactory.getInstance("X509")
.generateCertificates(pathToPemFile)) {
final X509Certificate crt = (X509Certificate) cert;
try {
final String alias = crt.getSubjectX500Principal().getName();
ks.setCertificateEntry(alias, crt);
LOG.info("Added alias " + alias + " to TrustStore");
} catch (KeyStoreException exp) {
LOG.error(exp.getMessage());
}
}
return ks;
}