2017-09-19 3 views
0

pem 인증서에 문제가 있습니다. 인증서 권한이있는 다른 서버에서 서비스를 호출하려고합니다.RestPemplate - Pem 인증서의 CertificateParsingException

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

그리고 오류는 다음과 같습니다

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) 

나는이 솔루션을 시도 : RestTemplate with pem certificate,하지만 나를 위해 작동하지 않았다. 메서드 getCertificate()는 byte [] (나는 인증서를 리턴하는 서비스를 가지고있다. 나도 알아, 나쁜 생각인데, 어떻게 작동하는지)로 인증서를 반환한다.

인증서와 처음 만났습니다. 어떻게 해결할 수 있습니까?

+0

'CertificateFactory'는 PEM 형식을 처리하는 -과에서 (오히려 키 PLUS 인증서보다)는 인증서를 넣어 : 그렇다면, 응용 프로그램의 시작 부분에 코드를 이동 어쨌든 keymanager의 저장소는 쓸모가 없습니다. 그러나 클라이언트 인증을 수행하기 전에 심지어 _attempting_ 전에 발생하는 server_에서받은 인증서에서 오류가 발생합니다. 인증서를 서버에 저장하거나'keytool -printcert -sslserver host [: port] -rfc' 또는'openssl s_client -connect host : port -servername host'와 함께받은 인증서를 얻고 (추가하십시오) --- BEGIN CERTIFICATE ----- ~ ----- END CERTIFICATE ------). –

답변

0

메소드 시작 부분에이 코드를 추가하십시오. 당신이 당신의`parseDERfromPEM`을 필요가 없습니다

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