Request Https potwierdzony certyfikatem p12

0

Cześc,

Potrzebuję wysłać request typu POST do serwisu który wymaga własnego certyfikatu przy autoryzacji.

znalazłem na stacku rozwiązanie z ładowaniem certyfikatu jednak cały czas sypie mi błędem

 KeyStore p12 = KeyStore.getInstance("pkcs12");
 p12.load(new FileInputStream("sciezkoaDocertyfikatu"), "haslo".toCharArray());

System.setProperty("javax.net.ssl.trustStore", "p12");
System.setProperty("javax.net.ssl.trustStorePassword", "haslo");

OkHttpClient client = new OkHttpClient();
Exception in thread "main" java.security.KeyStoreException: problem accessing trust store
Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
Caused by: java.security.UnrecoverableKeyException: Password verification failed

Hasło w 100% jest dobrze wpisane bo takim samym wgrywam certyfikat do windowsa.

0

Jeśli możesz wrzuć więcej kodu, najlepiej całą metodą. Spójrz też że masz opcję dodania formatowania jako kod, będzie łatwiej się czytało :)

0

Wszystko mam aktualnie w jednym pliku bo dopiero testuję czy to zadziała

public class Program {

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

        Payload payloadValues = new Payload();
        Map<String, Object> claims = new HashMap<>();
        claims.put("iss", payloadValues.iss);
        claims.put("sub", payloadValues.sub);
        claims.put("aud", payloadValues.aud);
        claims.put("jti",payloadValues.jti);
        claims.put("exp", ZonedDateTime.now().plusMinutes(5).toEpochSecond());
        claims.put("user_id", payloadValues.user_id);
        claims.put("user_role", payloadValues.user_role);
        Map<String, Object> headers = new HashMap<>();
        headers.put("typ", "JWT");
        String file_wss = "C:\\Users\\Mintaa\\Desktop\\Program\\Certs\\wss.p12";
        InputStream input = new FileInputStream(file_wss);
        char[] haslodoCertyfikatu = "password".toCharArray();
        String aliasCertyfikatu = "uwierzytelnienie danych";
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(input,haslodoCertyfikatu);
        Key privateKey = keyStore.getKey(aliasCertyfikatu, haslodoCertyfikatu);
        String token = Jwts.builder()
                .signWith(privateKey,SignatureAlgorithm.RS256)
                .setHeader(headers)
                .setClaims(claims)
                .compact();
        System.out.println(token);

        String pass = "password";

        KeyStore p12 = KeyStore.getInstance("pkcs12");
        p12.load(new FileInputStream("C:\\Users\\Mintaa\\Desktop\\Program\\Certs\\tls.p12"), "password".toCharArray());

        System.setProperty("javax.net.ssl.trustStore", "p12");
        System.setProperty("javax.net.ssl.trustStorePassword", "password");

        OkHttpClient client = new OkHttpClient();

        MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
        RequestBody body = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("Content-Type","application/x-www-form-urlencoded")
                .addFormDataPart("client_assertion_type","urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
                .addFormDataPart("grant_type", "client_credentials")
                .addFormDataPart("client_assertion", token)
                .addFormDataPart("scope", url)
                .build();

        Request request = new Request.Builder()
                .url("https://xxxxxx")
                .method("POST", body)
                .addHeader("Content-Type", "application/x-www-form-urlencoded")
                .build();
        Response response = client.newCall(request).execute();
        System.out.println(response);
        System.out.println(response.body());



    }
}

1

@Mintaa:

 KeyStore p12 = KeyStore.getInstance("pkcs12");
 ...
 System.setProperty("javax.net.ssl.trustStore", "p12");

Jesteś pewien, że java w property javax.net.ssl.trustStore spodziewa się "p12", a nie ścieżki do pliku "C:\\Users\\Mintaa\\Desktop\\Program\\Certs\\tls.p12" ?

0
yarel napisał(a):

@Mintaa:

 KeyStore p12 = KeyStore.getInstance("pkcs12");
 ...
 System.setProperty("javax.net.ssl.trustStore", "p12");

Jesteś pewien, że java w property javax.net.ssl.trustStore spodziewa się "p12", a nie ścieżki do pliku "C:\\Users\\Mintaa\\Desktop\\Program\\Certs\\tls.p12" ?

Niestety podając tam ścieżkę rownież nie działa

0

A sam plik tls.p12 na pewno jest okej w środku?

0
tekan napisał(a):

A sam plik tls.p12 na pewno jest okej w środku?

tak bo przez pythona przechodziło to połączenie bez problemu

0

Nie jestem pewny na 100%, ale chciałeś chyba ustawić javax.net.ssl.keyStore i javax.net.ssl.keyStorePassword a nie javax.net.ssl.trustStore. Ja mam trustStore ustawione na pełną ścieżkę do pliku cacerts i tak raczej powinno zostać.

https://www.geeksforgeeks.org/difference-between-truststore-and-keystore-in-java/

0
obscurity napisał(a):

Nie jestem pewny na 100%, ale chciałeś chyba ustawić javax.net.ssl.keyStore i javax.net.ssl.keyStorePassword a nie javax.net.ssl.trustStore. Ja mam trustStore ustawione na pełną ścieżkę do pliku cacerts i tak raczej powinno zostać.

https://www.geeksforgeeks.org/difference-between-truststore-and-keystore-in-java/

Tak to też zauważyłem jednak po zmienia jest dalej to samo

Exception in thread "main" javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

2

Co tu się dzieje w tym kodzie :D

Po pierwsze i najważniejsze - zdecyduj się, czy:

  • chcesz, żeby tylko OkHttpClient korzystał z twoich certyfikatów czy chcesz, żeby cała aplikacja (instancja JVM) korzystała z twoich certyfikatów
  • chcesz trzymać to w plikach, czy w runtime
  1. Jeśli odpowiedź na pierwsze pytanie brzmi "tylko OkHttpClient", to zapoznaj się z modułem TLS do OkHttpClient - builder pozwala ci na nadpisywanie SSLSocketFactory: https://square.github.io/okhttp/features/https/
  2. Jeśli z kolei chcesz, żeby cała maszyna wirtualna Javy korzystała z wskazanych przez ciebie trustStore/keyStore to wczytaj to przez zmienne środowiskowe, np.
-Djavax.net.ssl.keyStoreType=PKCS12 
-Djavax.net.ssl.keyStore=%PATH_TO_P12% 
-Djavax.net.ssl.keyStorePassword=%KS_PASSWORD% 

-Djavax.net.ssl.trustStoreType=PKCS12
-Djavax.net.ssl.trustStore=%PATH_TO_P12% 
-Djavax.net.ssl.trustStorePassword=%TS_PASSWORD%

Przy czym pierwsze dwie opcje są zdaje się z defaultu ustawiane na PKCS12 przy Javie wyższej od 1.8

  1. Jeśli z jakiegoś powodu nie chcesz przekazywać tych danych przez parametry to faktycznie można ustawić te zmienne w runtime. Należy jednak pamiętać, że różne frameworki mogą się różnie zachować. Niektóre frameworki po prostu kopiują sobie ustawienia domyślne SSL na starcie.

Bonus:
4. Sugeruję też dorzucić -Djavax.net.debug=ssl:handshake na starcie bo może być tak, że handshake wywala się nie dlatego, że brakuje certyfikatów, ale np. strony nie mogą się dogadać co do szyfrowania.

0

Skąd wiesz, że hasło się zgadza z hasłem keystore? Z tego co pamiętam, tam można ustawić osobne hasło na keystore i samym certyfikacie, możliwe więc, że ustawiłeś hasło na certyfikacie, a na keystore nie...
To narzędzie może trochę pomóc w rozkminkach https://keystore-explorer.org/

0
wartek01 napisał(a):

Co tu się dzieje w tym kodzie :D

Po pierwsze i najważniejsze - zdecyduj się, czy:

  • chcesz, żeby tylko OkHttpClient korzystał z twoich certyfikatów czy chcesz, żeby cała aplikacja (instancja JVM) korzystała z twoich certyfikatów
  • chcesz trzymać to w plikach, czy w runtime
  1. Jeśli odpowiedź na pierwsze pytanie brzmi "tylko OkHttpClient", to zapoznaj się z modułem TLS do OkHttpClient - builder pozwala ci na nadpisywanie SSLSocketFactory: https://square.github.io/okhttp/features/https/
  2. Jeśli z kolei chcesz, żeby cała maszyna wirtualna Javy korzystała z wskazanych przez ciebie trustStore/keyStore to wczytaj to przez zmienne środowiskowe, np.
-Djavax.net.ssl.keyStoreType=PKCS12 
-Djavax.net.ssl.keyStore=%PATH_TO_P12% 
-Djavax.net.ssl.keyStorePassword=%KS_PASSWORD% 

-Djavax.net.ssl.trustStoreType=PKCS12
-Djavax.net.ssl.trustStore=%PATH_TO_P12% 
-Djavax.net.ssl.trustStorePassword=%TS_PASSWORD%

Przy czym pierwsze dwie opcje są zdaje się z defaultu ustawiane na PKCS12 przy Javie wyższej od 1.8

  1. Jeśli z jakiegoś powodu nie chcesz przekazywać tych danych przez parametry to faktycznie można ustawić te zmienne w runtime. Należy jednak pamiętać, że różne frameworki mogą się różnie zachować. Niektóre frameworki po prostu kopiują sobie ustawienia domyślne SSL na starcie.

Bonus:
4. Sugeruję też dorzucić -Djavax.net.debug=ssl:handshake na starcie bo może być tak, że handshake wywala się nie dlatego, że brakuje certyfikatów, ale np. strony nie mogą się dogadać co do szyfrowania.

Zrobiłem tak jak podałeś w punkcie 2.

Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

keystore i trustore ten sam plik

2
Mintaa napisał(a):

keystore i trustore ten sam plik

nie no raczej nie.
keystore powinien zawierać certyfikaty z prywatnymi kluczami do uwierzytelnienia
truststore powinien zawierać główne urzędy certyfikacyjne z publicznymi kluczami do weryfikacji zdalnych certyfikatów
otwórz certyfikat serwera i sprawdź kto go wydał - ten wydawca powinien być w truststore

0

Rozwiązanie

        KeyStore ks = KeyStore.getInstance("PKCS12");
        FileInputStream fis = new FileInputStream("C://tls.p12");
        ks.load(fis, "password".toCharArray());
        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, "password".toCharArray());
        SSLContext sc = SSLContext.getInstance("TLS");
        sc.init(kmf.getKeyManagers(), null, null);
    
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init((KeyStore) null);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers));
        }
        X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
        SSLContext sslContext = SSLContext.getInstance("SSL");
        sslContext.init(null, new TrustManager[] { trustManager }, null);

        OkHttpClient client = new OkHttpClient.Builder()
                .sslSocketFactory(sc.getSocketFactory(), trustManager)
                .build();

1 użytkowników online, w tym zalogowanych: 0, gości: 1