Как прикрепить сертификат .pfx к запросу на https-соединение с помощью Java?

У меня есть сертификат pfx, который я установил в хранилище сертификатов Windows, и я могу прикрепить его к вызову https rest с помощью C #.

Теперь мне нужно сделать то же самое на Java. Я прочитал, что сертификат .pfx имеет закрытый ключ вместе с одним или несколькими сертификатами.

Я получаю следующую ошибку: Не удалось построить путь PKIX: sun.security.provider.certpath.SunCertPathBuilderException: не удалось найти действительный путь сертификации для запрошенной цели.

Вещи, которые я пробовал на Java

  1. Я напрямую взял сертификат из магазина Windows, используя KeyStore ks = KeyStore.getInstance (Windows-MY, SunMSCAPI), и создал SSLContext, который я использовал в вызове HTTPS.

  2. Я импортировал сертификат из магазина Windows как файл .cer, прочитал его из кода в виде файла и прикрепил к нему https-вызов

  3. Я прочитал файл .pfx из кода и приложил его к звонку.

  4. Я добавил сертификат в файл cacerts Java-Home (C: /Work/certi/jre1.8.0_91/lib/security/cacerts) с помощью KeyTool.

Полный код Java приведен ниже.

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Enumeration;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;

import javax.net.ssl.TrustManagerFactory;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;


public class TestElk {

public static void main(String[] args) throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, UnrecoverableKeyException, NoSuchProviderException {
        
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    Certificate certificate = certificateFactory.generateCertificate(new FileInputStream(new File("C:/Work/certi/jre1.8.0_91/lib/security/elkcert.cer")));//exported certificate

    /* KeyStore ks = KeyStore.getInstance("Windows-MY", "SunMSCAPI");
    ks.load(null,null);
    
    Enumeration enumeration = ks.aliases();     
    while(enumeration.hasMoreElements()) {            
        String alias = (String)enumeration.nextElement();
        System.out.println("alias name: " + alias);        }
    
    Certificate[] certificate = ks.getCertificateChain("alias");
     */
    
    // Create TrustStore        
    KeyStore trustStoreContainingTheCertificate =     KeyStore.getInstance(KeyStore.getDefaultType());
    trustStoreContainingTheCertificate.load(null, null);

    trustStoreContainingTheCertificate.setCertificateEntry("cert", certificate);

    // Create SSLContext
    TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    trustManagerFactory.init(trustStoreContainingTheCertificate);


    final SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null,trustManagerFactory.getTrustManagers(),new SecureRandom());
    SSLContext.setDefault(sslContext);
    
    HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;   
    
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

    URL url = new URL("https://server-link");
    
    HttpsURLConnection con =    (HttpsURLConnection)url.openConnection();           
    con.setRequestMethod("POST");
    con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
    con.setConnectTimeout(10000);
    con.setSSLSocketFactory(sslContext.getSocketFactory()); 
    con.connect();
    
    BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
        sb.append(line+"\n");
    }
    br.close();
    System.out.println(sb.toString());
    //int s= con.getResponseCode();  }

person Jeevika    schedule 17.01.2017    source источник


Ответы (1)


Следующее должно работать, учитывая, что вы импортировали сертификат выдающего CA (см. Комментарий ниже) в файл cacerts, большую помощь можно найти в другом потоке SO Здесь:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;


public class TestElk {

public static void main(String[] args) throws ClientProtocolException, IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException, UnrecoverableKeyException, NoSuchProviderException {

    
    KeyStore clientStore = KeyStore.getInstance("PKCS12");
    clientStore.load(new FileInputStream(new File("C:/path_to_pfx/mypfx.pfx")), "pfxPass".toCharArray());
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(clientStore, "pfxPass".toCharArray());
    KeyManager[] kms = kmf.getKeyManagers();
    
    // Assuming that you imported the CA Cert "Subject: CN=MBIIS CA, OU=MBIIS, O=DAIMLER, C=DE"
    // to your cacerts Store.
    KeyStore trustStore = KeyStore.getInstance("JKS");
    trustStore.load(new FileInputStream("cacerts"), "changeit".toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmf.init(trustStore);
    TrustManager[] tms = tmf.getTrustManagers();

    final SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(kms,tms,new SecureRandom());
    SSLContext.setDefault(sslContext);

    HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;   
    System.setProperty("https.proxyHost", "IP_OF_PROXY_HOST_GOES_HERE");
    System.setProperty("https.proxyPort", "PORT_NUMBER_GOES_HERE");
    HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
    HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

    URL url = new URL("https://server-link");

    HttpsURLConnection con =    (HttpsURLConnection)url.openConnection();           
    con.setRequestMethod("POST");
    con.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko");
    con.setConnectTimeout(10000);
    con.setSSLSocketFactory(sslContext.getSocketFactory()); 
    con.connect();

    BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = br.readLine()) != null) {
        sb.append(line+"\n");
    }
    br.close();
    System.out.println(sb.toString());
    //int s= con.getResponseCode();
}

}
person Exception_al    schedule 17.01.2017
comment
Невозможность найти действительный путь сертификации к запрошенной цели указывает, что корневой / вспомогательный ЦС не является доверенным. В вашем случае вы не доверяете корню (MBIIS CA), который выдал сертификат сервера для CN = *. Dvb.corpinter.net ... - person Exception_al; 17.01.2017
comment
Обновите журнал, указав свой вопрос, я не могу получить доступ к ссылке на вашем диске C: :) - person Exception_al; 17.01.2017
comment
Добавьте только часть ошибки .... Я бы начал чат, но моей репутации для этого недостаточно - person Exception_al; 17.01.2017
comment
Если CN = MBIIS CA, OU = MBIIS, O = DAIMLER, C = CN является SubCA CN = MBIIS CA, OU = MBIIS, O = DAIMLER, C = DE, то ваше клиентское хранилище ключей должно доставить все цепочка ... Когда вы экспортируете pfx из вашего Internet Explorer, вы можете включить цепочку, если я не ошибаюсь, проверьте digicert.com/images/code-signing/export/ - person Exception_al; 18.01.2017
comment
Я использовал настоящий сертификат .pfx, который я получил по почте, для создания диспетчера ключей из клиентского хранилища в нашей программе. Имеет всего 1 сертификат. Затем из браузера я могу экспортировать, используя только первые 3 параметра ... т.е. экспорт .pfx отключен. :(. Как мы узнаем, является ли сертификат подчиненным ЦС другого ЦС, а затем как добавить его и доставить вместе. - person Jeevika; 18.01.2017
comment
Ваша первоначальная проблема решена, и теперь у вас есть новая проблема, было бы неплохо, если бы вы отметили ответ как ответ. .. для дальнейших вопросов я предлагаю вам вместо этого использовать Google для добавления цепочки в pfx: stackoverflow.com/questions/18787491/ - person Exception_al; 18.01.2017