Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Java Новый топик    Ответить
 Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
имеется sping-boot приложение. Появилась задача сделать так, чтобы оно работало по https.

я сделал всё как тут написано(через самоподписанный PKCS12 ключ):
https://www.thomasvitale.com/https-spring-boot-ssl-certificate/

в коде есть запросы к внешним рест сервисам. Пока что они замоканы внутренними же сервисами.
Внешние сервисы тоже будут по https.

ResponseEntity<byte[]> mappingTemplateResponseEntity = restTemplate.exchange(httpsUrl, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), byte[].class);


После перевода на https такой код теперь не работает.

Читаю статью https://myshittycode.com/2015/12/17/java-https-unable-to-find-valid-certification-path-to-requested-target-2/

соответственно если зарегать бин:

@Bean
    public Boolean disableSSLValidation() throws Exception {
        final SSLContext sslContext = SSLContext.getInstance("TLS");

        sslContext.init(null, new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        }}, null);

        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        });

        return true;
    }


то всё работает, но это судя по всему плохо и толку от такого HTTPS мало.

Но второй способ из статьи у меня не работает. У меня винда.

в cmd:
автор
keytool -list -v -storetype pkcs12 -keystore keystore.p12
Enter keystore password:

Keystore type: PKCS12
Keystore provider: SunJSSE

Your keystore contains 1 entry

Alias name: tomcat
Creation date: Jan 9, 2018
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
Issuer: CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
Serial number: 64cd4d27
Valid from: Tue Jan 09 17:56:07 MSK 2018 until: Fri Jan 07 17:56:07 MSK 2028
Certificate fingerprints:
MD5: A6:F5:67:EE:87:65:21:62:50:5B:67:AE:63:F6:AE:C0
SHA1: B8:F5:F7:7D:8C:4C:90:0E:BA:CE:9D:22:3A:D3:A7:6E:BB:12:1B:D8
SHA256: 35:B5:DF:15:FC:3B:DD:D3:05:58:88:92:00:47:8F:62:2C:97:D7:20:77:FA:7D:55:00:64:E9:62:F4:7D:3B:08
Signature algorithm name: SHA256withRSA
Version: 3

Extensions:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 3E D4 2D F8 AF D2 C2 4E 51 4F 3E A4 01 FE E2 34 >.-....NQO>....4
0010: 48 B0 5F 4F H._O
]
]



*******************************************
*******************************************





Также например тут https://stackoverflow.com/a/37824656/2674303 пишут, что запрос надо ещё по другому писать и указывать файл сертификата. С другой стороны если я захожу в личный кабинет своего банка, то я же по https там сижу и я не нажимаю на скачивание сертификата. Может это в фоне как-то происходит? должен ли мне поставщик сервиса предоставлять сертификат отдельным урлом по http ?

Расставьте по полочкам пожалуйста.
10 янв 18, 00:35    [21091872]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
вадя
Member

Откуда: Екатеринбург
Сообщений: 14446
redwhite90,

Теперь всегда требуется наличие в сертификате subjectAltName с хотя бы одним значением, в котором указан ваш домен:
https://groups.google.com/a/chromium.org/d/topic/security-dev/IGT2fLJrAeo/discussion
10 янв 18, 07:35    [21092026]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Usman
Member

Откуда: من ألماتي
Сообщений: 5599
redwhite90,

73.5 Configure SSL:
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret
10 янв 18, 07:46    [21092033]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 8747
redwhite90
Расставьте по полочкам пожалуйста.
Я не смог разобраться в ваших проблемах ("Да как же тебя понять, если ты ничего не говоришь"), но "есть мнение", что вы мешаете в одну кучу "шифрованный канал", "идентификацию по сертификату" и "доверительные отношения".

Вкратце можно сказать следующее.
Для шифрованного обмена требуется надёжный (доверенный и безопасный) канал для передачи пароля.
В данном контексте "безопасный" означает "доступен только для отправителя и получателя", а "доверенный" - "идентифицирует участников".

Существуют схемы открытого распределения ключей, позволяющие согласовать (секретный) пароль по открытому (общедоступному) каналу. Эти схемы являются безопасными, но не являются доверенными.

Доверие может обеспечиваться разными способами, но общепринятым является инфраструктура открытых ключей (ИОК / PKI).
Основой ИОК являются удостоверяющие центры в иерархических или/и сетевых графах.

Каждый удостоверяющий центр, тем или иным образом, ведёт списки отзыва сертификатов, позволяющие проверить статус произвольного сертификата, изданного в данном УЦ.
Практика проверки всей цепочки (конечный сертификат - промежуточные УЦ - корневой УЦ) по спискам отзыва стала стандартом для корректной реализации TLS/SSL.

Когда вы самостоятельно формируете сертификат ключевой пары, хост, использующий такой сертификат не обладает никаким доверием. Это даже если не касаться того факта, что самоизданный сертификат допустим только для корневого УЦ.
10 янв 18, 08:33    [21092096]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
redwhite90,

У jvm есть keystore и есть trustStore. Вот для того чтобы HTTPS клиент работал нужно чтобы был truststore был сконфигурирован и в нём публичный ключ, соответсвенно.
Либо конкретно для Spring Boot:
https://stackoverflow.com/questions/27724544/specifying-trust-store-information-in-spring-boot-application-properties
10 янв 18, 08:33    [21092097]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 8747
Blazkowicz
Вот для того чтобы HTTPS клиент работал нужно чтобы был truststore был сконфигурирован и в нём публичный ключ
... удостоверяющего центра, выпустившего сертификат сервера, к которому обращается клиент.
Так, наверное, будет правильнее.
10 янв 18, 08:40    [21092115]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
Basil A. Sidorov
... удостоверяющего центра, выпустившего сертификат сервера, к которому обращается клиент.
Так, наверное, будет правильнее.

Да, но у топикастера жа самоподписный.
10 янв 18, 08:53    [21092137]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 8747
Blazkowicz
Да, но у топикастера жа самоподписный.
Да, но рано или поздно он осознает, что надо покупать серверный сертификат. Или, как минимум, развернуть собственный УЦ.
10 янв 18, 09:06    [21092165]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
shaden
Member

Откуда: Башкортостан
Сообщений: 159
автор
С другой стороны если я захожу в личный кабинет своего банка, то я же по https там сижу и я не нажимаю на скачивание сертификата.


Данный сертификат выдан доверенным центром сертификации (Thawte, Verisign и т.п.) Корневые сертификаты доверенных центров сертификации уже в хранилищах сертификатов браузеров.

Если же сертификат выпущен удостоверяющим центром, про который не знают браузеры (например, КриптоПро), то цепочку сертификатов надо будет добавлять в хранилище сертификатов браузера, чтобы браузер не ругался на кривой сертификат.
10 янв 18, 09:35    [21092279]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Usman
redwhite90,

73.5 Configure SSL:
server.port=8443
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=secret
server.ssl.key-password=another-secret


а у меня
server.ssl.key-store-type:PKCS12
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=password
server.ssl.key-alias=tomcat


Чем отличается server.ssl.key-store-password от
server.ssl.key-password ?
10 янв 18, 11:15    [21092692]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
redwhite90
Чем отличается server.ssl.key-store-password от
server.ssl.key-password ?

Первый - пароль от JKS файла. Второй - пароль от ключа в нём. Но для SSL/HTTPS их, зачастую, делают одинаковыми.
10 янв 18, 11:24    [21092737]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Blazkowicz,

кажется получилось.



@Value("${http.client.ssl.trust-store}")
    private Resource keyStore;
    @Value("${http.client.ssl.trust-store-password}")
    private String keyStorePassword;

    @Bean
    RestTemplate restTemplate() throws Exception {
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial(
                        keyStore.getURL(),
                        keyStorePassword.toCharArray()
                ).build();
        SSLConnectionSocketFactory socketFactory =
                new SSLConnectionSocketFactory(sslContext);
        HttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(socketFactory).build();
        HttpComponentsClientHttpRequestFactory factory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(factory);
    }


в пропертях:

# The format used for the keystore
server.ssl.key-store-type:PKCS12
# The path to the keystore containing the certificate
server.ssl.key-store=classpath:keystore.p12
# The password used to generate the certificate
server.ssl.key-store-password=password
# The alias mapped to the certificate
server.ssl.key-alias=tomcat

http.client.ssl.trust-store=classpath:keystore.p12
http.client.ssl.trust-store-password=password


запрос

ResponseEntity<byte[]> mappingTemplateResponseEntity = restTemplate.exchange(httpsUrl, HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), byte[].class);


теперь работает.
10 янв 18, 11:41    [21092801]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Blazkowicz
redwhite90
Чем отличается server.ssl.key-store-password от
server.ssl.key-password ?

Первый - пароль от JKS файла. Второй - пароль от ключа в нём. Но для SSL/HTTPS их, зачастую, делают одинаковыми.


У меня не JKS а PKCS12.

Как-то можно посмотреть/поменять эти пароли?
10 янв 18, 11:52    [21092853]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
shaden
автор
С другой стороны если я захожу в личный кабинет своего банка, то я же по https там сижу и я не нажимаю на скачивание сертификата.


Данный сертификат выдан доверенным центром сертификации (Thawte, Verisign и т.п.) Корневые сертификаты доверенных центров сертификации уже в хранилищах сертификатов браузеров.

Если же сертификат выпущен удостоверяющим центром, про который не знают браузеры (например, КриптоПро), то цепочку сертификатов надо будет добавлять в хранилище сертификатов браузера, чтобы браузер не ругался на кривой сертификат.


а если у меня браузера нет, а есть rest template, то когда у меня появится не самоподписный сертификат, а нормальный, то что мне делать?
10 янв 18, 11:56    [21092869]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
redwhite90
а если у меня браузера нет, а есть rest template, то когда у меня появится не самоподписный сертификат, а нормальный, то что мне делать?

Ничего. Корневые сертификаты доверительных центров уже находятся в хранилище JRE, если вы только его не сломали.
10 янв 18, 12:39    [21093016]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Blazkowicz
redwhite90
а если у меня браузера нет, а есть rest template, то когда у меня появится не самоподписный сертификат, а нормальный, то что мне делать?

Ничего. Корневые сертификаты доверительных центров уже находятся в хранилище JRE, если вы только его не сломали.



Понял, благодарю
10 янв 18, 13:11    [21093124]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
а помогите ещё с кемелом:

@Component
public class MyRouteDefinition extends RouteBuilder {

    @Override
    public void configure() throws Exception {

        KeyStoreParameters ksp = new KeyStoreParameters();
        ksp.setType("pkcs12");
        ksp.setResource(PushRoutesDefinition.class.getResource("/keystore.p12").getPath());
        ksp.setPassword("password");

        KeyManagersParameters kmp = new KeyManagersParameters();
        kmp.setKeyStore(ksp);
        kmp.setKeyPassword("password");

        SSLContextParameters scp = new SSLContextParameters();
        scp.setKeyManagers(kmp);

        HttpComponent httpComponent = getContext().getComponent("https4", HttpComponent.class);
        httpComponent.setSslContextParameters(scp);

        //TO HTTPS
        from(...)
        .to("https4://localhost:8080/load")
        .process(exchange -> {
                    Integer responseCode = 
             exchange.getIn().getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
             log.debug("The response code is: {}", responseCode);
         }
    }


та же ошибка:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:382)
	... 40 common frames omitted
10 янв 18, 17:02    [21094248]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Blazkowicz
Member

Откуда:
Сообщений: 24443
Сертификат привязан к имени домена. Поэтому вместо localhost нужно использовать то имя, которое у сертификата в CN указано. Ну или в CN прописать localhost когда генеришь сертификат.
10 янв 18, 17:10    [21094275]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Blazkowicz,

Этот тот же сертификат, что и до этого, а там httpsUrl c localhost

Помогло написать вот так:

KeyStoreParameters ksp = new KeyStoreParameters();
        ksp.setType("pkcs12");
        ksp.setResource(PushRoutesDefinition.class.getResource("/keystore.p12").getPath());
        ksp.setPassword("password");

        KeyManagersParameters kmp = new KeyManagersParameters();
        kmp.setKeyStore(ksp);
        kmp.setKeyPassword("password");

        TrustManagersParameters trustManagersParameters = new TrustManagersParameters();
        trustManagersParameters.setKeyStore(ksp);

        SSLContextParameters scp = new SSLContextParameters();
        scp.setKeyManagers(kmp);
        scp.setTrustManagers(trustManagersParameters);

        HttpComponent httpComponent = getContext().getComponent("https4", HttpComponent.class);
        httpComponent.setSslContextParameters(scp);
10 янв 18, 17:17    [21094302]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Blazkowicz,

Теперь дали УРЛ, который уже имеет нормальный сертификат

и в постмане запрос прохолдит нормально:
Картинка с другого сайта.

а если через RestTemplate:

ResponseEntity<String> result = restTemplate.exchange(buildUrl(), HttpMethod.POST, requestEntity, String.class);


То старая ошибка:

автор
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target



Конфигурация всего этого дела:


@Configuration
public class ConnectorConfig {
    @Value("${server.port}")
    private Integer port;
    @Value("${http.client.ssl.trust-store}")
    private Resource trustStore;
    @Value("${http.client.ssl.trust-store-password}")
    private String trustStorePassword;
    @Value("${http.client.ssl.trust-store}")
    private Resource keyStore;
    @Value("${http.client.ssl.trust-store-password}")
    private String keyStorePassword;
    @Value("${server.ssl.key-store-type}")
    private String keyStoreType;

    public Integer getPort() {
        return port;
    }

    public Resource getTrustStore() {
        return trustStore;
    }

    public String getTrustStorePassword() {
        return trustStorePassword;
    }

    public Resource getKeyStore() {
        return keyStore;
    }

    public String getKeyStorePassword() {
        return keyStorePassword;
    }

    public String getKeyStoreType() {
        return keyStoreType;
    }

    @Bean
    public TomcatEmbeddedServletContainerFactory servletContainer() {
        TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory() {
            @Override
            protected void postProcessContext(Context context) {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
        tomcat.addAdditionalTomcatConnectors(getHttpConnector());
        tomcat.addConnectorCustomizers((TomcatConnectorCustomizer) connector -> {
            // configure maxSwallowSize
            if ((connector.getProtocolHandler() instanceof AbstractHttp11Protocol<?>)) {
                // -1 means unlimited, accept bytes
                ((AbstractHttp11Protocol<?>) connector.getProtocolHandler()).setMaxSwallowSize(-1);
            }
        });
        return tomcat;
    }

    private Connector getHttpConnector() {
        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
        connector.setScheme("http");
        connector.setPort(port + 1);
        connector.setSecure(false);
        connector.setRedirectPort(port);
        return connector;
    }

    @Bean
    RestTemplate restTemplate() throws Exception {
        SSLContext sslContext = new SSLContextBuilder()
                .loadTrustMaterial(
                        trustStore.getURL(),
                        trustStorePassword.toCharArray()
                ).build();
        SSLConnectionSocketFactory socketFactory =
                new SSLConnectionSocketFactory(sslContext);
        HttpClient httpClient = HttpClients.custom()
                .setSSLSocketFactory(socketFactory).build();
        HttpComponentsClientHttpRequestFactory factory =
                new HttpComponentsClientHttpRequestFactory(httpClient);
        return new RestTemplate(factory);
    }
}
12 янв 18, 17:21    [21102459]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 8747
Есть системное хранилище сертификатов, которое может (не) использоваться конкретным приложением (средой).
Если у JRE - собственное хранилище, то вполне логично предположить, что его содержимое может отличаться от системного.
12 янв 18, 17:58    [21102600]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Basil A. Sidorov,

Как быть?
12 янв 18, 18:10    [21102631]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 8747
redwhite90
Как быть?
+ Use "keytool -command_name -help" for usage of command_name
keytool
Key and Certificate Management Tool
Commands:
-certreq Generates a certificate request
-changealias Changes an entry's alias
-delete Deletes an entry
-exportcert Exports certificate
-genkeypair Generates a key pair
-genseckey Generates a secret key
-gencert Generates certificate from a certificate request
-importcert Imports a certificate or a certificate chain
-importpass Imports a password
-importkeystore Imports one or all entries from another keystore
-keypasswd Changes the key password of an entry
-list Lists entries in a keystore
-printcert Prints the content of a certificate
-printcertreq Prints the content of a certificate request
-printcrl Prints the content of a CRL file
-storepasswd Changes the store password of a keystore
Use "keytool -command_name -help" for usage of command_name
12 янв 18, 18:19    [21102669]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
redwhite90
Member

Откуда:
Сообщений: 1870
Basil A. Sidorov,

а как его найти?
12 янв 18, 19:13    [21102826]     Ответить | Цитировать Сообщить модератору
 Re: Как зарегистрировать сертификат?  [new]
Basil A. Sidorov
Member

Откуда:
Сообщений: 8747
В lib/security есть умалчиваемое хранилище доверенных сертификатов - файл cacerts (пустой пароль).
Можно импортировать его содержимое в используемое вами хранилище, не забыв установить "флаг доверия УЦ" при импорте.
Вполне возможно, что сертификат сервера издан одним из "стандартных" УЦ.

Можно действовать точечно, тогда варианты могут быть разные.

Если известен издатель серверного сертификата - находим страницу загрузки этого издателя, скачиваем и импортируем сертификаты корневого и промежуточных удостоверяющих центров.

Можно обратиться к администратору целевого сервера и попросить у него или pem-файл или cer-файлы "россыпью".

Можно взять винду, ослика, подключиться к какой-нибудь "нейтральной" (шифрованной) странице сервера - появится возможность посмотреть свойства серверного сертификата.
Это будет стандартная системная утилита, где на одной из закладок будет отображена "цепочка доверия".
Каждый сертификат в цепочке можно, опять-таки, просмотреть, и на другой одной из закладок - экспортировать в файл.

Можно взять любые другие браузер и операционку, но тогда интерфейс просмотра и экспорта сертификатов может (будет) отличаться. Сам функционал общепринятый и есть в любом браузере сложнее links/lynx.
12 янв 18, 19:37    [21102906]     Ответить | Цитировать Сообщить модератору
Все форумы / Java Ответить