2017-09-19 5 views
0

Ich habe ein Problem mit Pem-Zertifikat. Ich versuche, den Dienst von einem anderen Server mit Zertifikatautorisierung aufzurufen.CertificateParsingException in RestTemplate - Pem-Zertifikat

@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; 
} 

Und der Fehler ist:

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) 

habe ich versucht, diese Lösungen: RestTemplate with pem certificate, aber es hat nicht funktioniert für mich. Methode getCertificate() gibt ein Zertifikat in Byte [] (Ich habe einen Dienst, der Zertifikat zurückgeben. Ich weiß, es ist eine schlechte Idee, aber das ist, wie es funktioniert).

Es ist mein erster Kontakt mit Zertifikaten. Wie kann ich es beheben?

+0

'CertificateFactory' Griffe PEM-Format, so dass Sie Ihre' parseDERfromPEM' nicht brauchen - und setzen ein CERT (eher als ein Schlüssel PLUS cert) in das Geschäft für keymanager ist sowieso nutzlos. Jedoch tritt Ihr Fehler auf dem cert auf, das _ vom Server_ empfangen wird, das geschieht, bevor sogar _attempting_, Client auth zu tun. Holen (und hinzufügen) Sie das Zertifikat, wie es auf dem Server gespeichert ist, oder wie es mit 'keytool -printcert -sslserver host [: port] -rfc' oder' openssl s_client -connect host: port -servername-host' (der Teil von --- BEGINN ZERTIFIKAT ----- ----- ENDE ZERTIFIKAT ------). –

Antwort

0

Versuchen Sie, diesen Code am Anfang Ihrer Methode hinzuzufügen. Wenn dem so ist, bewegen Sie den Code zu Beginn der Anwendung:

java.lang.System.setProperty("javax.net.ssl.trustStore", "NONE");