I'm using several RESTful webservice in JAVA based web-application. I'm using the RESTeasy client to access my webservice. Here all communication between the client and service is through XML(JAX-B xml annotated detail classes). Here are the following codes
String serviceURL = "https://service.company.com/Service/getService"
ServiceRequestDetail serviceRequestDetail = getServiceRequestAsDetailClass();
ServiceResponseDetail serviceResponseDetail = new ServiceResponseDetail();
ClientRequest clientRequest = new ClientRequest(serviceURL);
clientRequest.accept(MediaType.APPLICATION_XML);
clientRequest.body(MediaType.APPLICATION_XML, serviceRequestDetail);
ClientResponse<ServiceRequestDetail> response =
clientRequest.post(ServiceRequestDetail.class);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " +
response.getStatus());
}
ServiceResponseDetail serviceResponseDetail =
response.getEntity(ServiceResponseDetail.class);
and when I try to access my service I get the "Peer not Authenticated" error
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
...
Is there any way to add the SSL configuration details in the RESTeasy client? any other suggestions for solving this issue is also welcome
Thanks in advance
I found out the answer but I'm really sorry for the late response.
To answer my question, RESTeasy client does support TLS/SSL. Infact the problem was I missed to install the certificate into the JVM.
keytool -import -alias <Replace certificate Alias name> -keystore $JAVA_HOME\jre\lib\security\cacerts -file <Replace your Certificate file location>
This solved the issue of "Peer Not Authenticated". Hope it helps. Kudos
If you don't want to add certificate to JVM and keep this cert separate. You can load the cert as part of your code like below.
// load the certificate
InputStream fis = this.getClass().getResourceAsStream("file/path/to/your/certificate.crt");
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(fis);
// load the keystore that includes self-signed cert as a "trusted" entry
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
keyStore.setCertificateEntry("cert-alias", cert);
tmf.init(keyStore);
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, tmf.getTrustManagers(), null);`
then attach to rest easy builder like
resteasyClientBuilder.sslContext(sslContext)
Related
I'm trying to secure a REST API using TLS/SSL, to do so I needed to update my client to use the public key and certificate.
The client is written in dart and here's how I implemented the SecurityContext :
SecurityContext clientContext = SecurityContext.defaultContext;
var certificate = (await rootBundle.load("assets/ssl/coastr.crt")).buffer.asInt8List();
print(certificate.toString());
clientContext.setTrustedCertificatesBytes(certificate);
/*var authorities = (await rootBundle.load('assets/ssl/coastr.ca-bundle')).buffer.asUint8List();
print(authorities.toString());
clientContext.setClientAuthoritiesBytes(authorities);*/
var key = (await rootBundle.load("assets/ssl/coastr_public.key")).buffer.asInt8List();
print(key.toString());
clientContext.usePrivateKeyBytes(key);
HttpClient client = HttpClient(context: clientContext);
HttpClientRequest request = await client.getUrl(Uri.parse(url));
HttpClientResponse response = await request.close();
The certificate (.crt file) is added without issue to the clientContext but adding the key to it returns me this error :
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception:
TlsException: Failure in usePrivateKeyBytes (OS Error:
BAD_PKCS12_DATA(pkcs8_x509.c:606)
passed a null parameter(ssl_privkey.cc:375), errno = 0)
The files I'm using are :
coastr.crt with this as a header : -----BEGIN CERTIFICATE-----
coastr_public.key with header : -----BEGIN PUBLIC KEY-----
I have no idea if I'm providing the wrong files to the client or if the error comes from elsewhere.
The files where generated using openssl.
Thank you for your help.
In general, you shouldn't have to add anything to the client to allow it to connect to a correctly configured HTTPS server. Hopefully, the server has a signed server side certificate. If that certificate is signed by a reputable CA, the client should automatically trust it. If it is signed by an in house CA, or self signed, you need to do some work. You need to provide the client with the signing certificate. In the former case that would be the root CA's certificate. In the latter case, supplying the server's certificate may work, though it's probably easier to disable the client check altogether.
The signing certificate is likely to be in CRT form as you've found. And you need to supply that exactly as you are doing. There's no need to supply any public keys as the are distributed in the certificates sent with the server hello.
Unless you want to use a client side certificate, there's no need to supply a private key, so you can skip the step that is failing. And supplying a public key to it is definitely not going to work, anyway.
From client (eg: https://localhost:8080/) we are passing the certificate related values and calling the rest services ( hosted on different port - https://localhost:446/serviceName).
The issue is like, when we try to pass the certificate , SSL handshake is happening correctly (no error on debug) , but the certificate value is not passed to the service hosted on another port. Certificate value is accessed in server code by referring to (X509Certificate)httpReq.getAttribute("javax.servlet.request.X509Certificate");
Note : We use Spring boot application which intenally runs on tomcat server.And desired CA authorised certificates, keystore and truststore are present in resource path in both the projects (client and service hosted). In rest service project config file, the client-auth is set to false.
Sample code snippet used to call rest service:
SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(restserviceTruststore)
.loadKeyMaterial(restserviceKeyStore, password).build();
HttpClient client = HttpClients.custom() .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
.setSslcontext(sslContext).build();
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(client));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_XML);
HttpEntity<String> request = new HttpEntity<>(XML, headers);
response = restTemplate.postForObject(endpointURL, request, String.class);
Question:
1) From client what keystore and trustore should we need to pass to SSLContext? Is it server's keystore /truststore or clients?
2)What are the exact steps to be followed to resolve this issue.
I am trying to implement Digital certificate validity utility using java. I can able to read the certification information(subjectDN, Issure info, validitity..etc) if the certificate in .cert,.cer but can't able to read certificate information from .p7b and .p12 certificate format. I have used the BouncyCastle security provider to read .p7b and .p12 certificate content but not able to get with that security provider might be i was missing on this. I am referring online resources to get some idea on this but not get guideline for this.Could you please someone give suggestion on this.
I suggest if you're looking for validity of the certificate from p12, it can be done as below :
try {
Security.addProvider(new BouncyCastleProvider());
KeyStore keyStore = KeyStore.getInstance("pkcs12");
InputStream input = new FileInputStream("pathToYourP12");
keyStore.load(input, "password");
certFromKeyStore = (X509Certificate)keyStore.getCertificate("keyStoreAllias");
certFromKeyStore.checkValidity();
}
catch(Exception e)
{
// catch exception like if no valid p12 existing at the location, invalid password, or any other exception should get catch properly.
}
How can I enable certificate pinning using OkHttp for my Android / Java application?
The OkHttp documentation gives us a clear way to do this complete with sample code. In case it goes away, here it is pasted in below:
1. Add a broken CertificatePinner and make a request.
Any request will do, even if it doesn't exist. You can do this in your Android application, or just create a dummy Java application and run this as well.
For example, to pin https://publicobject.com, start with a broken
configuration:
String hostname = "publicobject.com";
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.build();
OkHttpClient client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build();
Request request = new Request.Builder()
.url("https://" + hostname)
.build();
client.newCall(request).execute();
As expected, this fails with a certificate pinning exception:
javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
Peer certificate chain:
sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=publicobject.com, OU=PositiveSSL
sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Secure Server CA
sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority
sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=: CN=AddTrust External CA Root
Pinned certificates for publicobject.com:
sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
at okhttp3.CertificatePinner.check(CertificatePinner.java)
at okhttp3.Connection.upgradeToTls(Connection.java)
at okhttp3.Connection.connect(Connection.java)
at okhttp3.Connection.connectAndSetOwner(Connection.java)
2. Configure your OkHttp Client Correctly:
CertificatePinner certificatePinner = new CertificatePinner.Builder()
.add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
.add("publicobject.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")
.add("publicobject.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")
.add("publicobject.com", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=")
.build();
That's all there is to it!
This method will give you all your certificates in the entire chain. This is advantageous since it's safer as only one certificate in the chain has to match for the request to succeed. It's likely at some point in the future, your certificates will be updated, but as long as the entire chain isn't updated, your application shouldn't break.
I use Eclipse to make ssl socket server-client communication.
I am trying to use self signed certificate.
I make keystorage with Eclipse keytool.
Than I try to load this keystorage:
String ksName = "herong.jks";
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream(ksName), ksPass);
But I get following message:
herong.jks (No such file or directory)
Name of keysotre is correct. May be I should do something else? now I only create keystore and certificate in key tool.