0

I have a problem with pem certificate. I'm trying to call service from other server with certificate authorization.

@Override
public void changeAnalitycsState(Device device) {

    SSLContext context = null;

    Security.addProvider(new BouncyCastleProvider());

    context = SSLContexts.custom()
            .loadTrustMaterial(null, new TrustSelfSignedStrategy())
            .useProtocol("TLS").build();

    byte[] certificate = getCertificate();

    byte[] certBytes = parseDERFromPEM(certificate,
            "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----");

    X509Certificate cert = generateCertificateFromDER(certBytes);

    KeyStore keystore = KeyStore.getInstance("JKS");
    keystore.load(null);
    keystore.setCertificateEntry("cert-alias", cert);

    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(keystore, "changeit".toCharArray());

    KeyManager[] km = kmf.getKeyManagers();

    context.init(km, null, null);

    @SuppressWarnings("deprecation")
    HttpClient httpClient =  HttpClientBuilder.create().setSslcontext(context)
            .setSSLSocketFactory(new SSLConnectionSocketFactory(context.getSocketFactory(), new AllowAllHostnameVerifier()))
            .build();

    ClientHttpRequestFactory httpClientRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

    String plainCreds = "user:pass";
    byte[] plainCredsBytes = plainCreds.getBytes();
    byte[] base64CredsBytes = Base64.encodeBase64(plainCredsBytes);
    String base64Creds = new String(base64CredsBytes);

    RestTemplate restTemplate = new RestTemplate(httpClientRequestFactory);

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add(HttpHeaders.AUTHORIZATION, "Basic " + base64Creds);
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);

    HttpEntity<Device> entity = new HttpEntity<Device>(
            device, httpHeaders);
    restTemplate
            .exchange("https://xxx:8666/yyy/", HttpMethod.POST, entity, Void.class);

}

private 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]);
}

private X509Certificate generateCertificateFromDER(byte[] certBytes) {
    CertificateFactory factory;
    X509Certificate cert = null;
    factory = CertificateFactory.getInstance("X.509");
    cert = (X509Certificate) factory
    .generateCertificate(new ByteArrayInputStream(certBytes));

    return cert;
}

And the error is:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://xxx":no more data allowed for version 1 certificate; nested exception is javax.net.ssl.SSLProtocolException: no more data allowed for version 1 certificate

Caused by: javax.net.ssl.SSLProtocolException: no more data allowed for version 1 certificate

10:35:08,479 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.ssl.HandshakeMessage$CertificateMsg.<init>(Unknown Source)

10:35:08,480 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.ssl.ClientHandshaker.processMessage(Unknown Source)

10:35:08,480 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.ssl.Handshaker.processLoop(Unknown Source)

10:35:08,481 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.ssl.Handshaker.process_record(Unknown Source)

10:35:08,481 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.ssl.SSLSocketImpl.readRecord(Unknown Source)

10:35:08,482 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.ssl.SSLSocketImpl.performInitialHandshake(Unknown Source)

Caused by: java.security.cert.CertificateParsingException: no more data allowed for version 1 certificate

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.x509.X509CertInfo.parse(Unknown Source)

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.x509.X509CertInfo.<init>(Unknown Source)

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.x509.X509CertImpl.parse(Unknown Source)

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.x509.X509CertImpl.<init>(Unknown Source)

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at sun.security.provider.X509Factory.engineGenerateCertificate(Unknown Source)

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1)   at java.security.cert.CertificateFactory.generateCertificate(Unknown Source)

10:35:08,489 INFO  [stdout] (http-0.0.0.0-0.0.0.0-8443-1) 

I have tried this solutions: RestTemplate with pem certificate, but it didn't work for me. Method getCertificate() returns a certificate in byte[] (I have a service which return certificate. I know, it's bad idea, but this is how it works).

It's my first contact with certificates. How can I fix it?

thehespe
  • 97
  • 1
  • 12
  • `CertificateFactory` handles PEM format so you don't need your `parseDERfromPEM` -- and putting a cert (rather than a key PLUS cert) in the store for keymanager is useless anyway. However your error is occuring on the cert received _from the server_ which happens before even _attempting_ to do client auth. Get (and add) the cert as stored on the server, or as received with `keytool -printcert -sslserver host[:port] -rfc` or `openssl s_client -connect host:port -servername host` (the part from -----BEGIN CERTIFICATE----- to -----END CERTIFICATE------). – dave_thompson_085 Sep 19 '17 at 10:04

1 Answers1

0

Try adding this code to the beginning of your method. If so, move the code to the beginning of the application:

java.lang.System.setProperty("javax.net.ssl.trustStore", "NONE");
Junior
  • 199
  • 1
  • 9