|
19 | 19 | */ |
20 | 20 | package org.sonarsource.scanner.lib.internal.http; |
21 | 21 |
|
| 22 | +import java.io.IOException; |
22 | 23 | import java.io.InputStream; |
23 | 24 | import java.net.CookieManager; |
24 | 25 | import java.net.CookiePolicy; |
|
27 | 28 | import java.nio.file.Path; |
28 | 29 | import java.nio.file.StandardOpenOption; |
29 | 30 | import java.security.KeyStore; |
| 31 | +import java.security.KeyStoreException; |
| 32 | +import java.security.NoSuchAlgorithmException; |
| 33 | +import java.security.cert.CertificateException; |
30 | 34 | import java.util.concurrent.TimeUnit; |
| 35 | +import javax.annotation.Nullable; |
31 | 36 | import nl.altindag.ssl.SSLFactory; |
32 | 37 | import nl.altindag.ssl.exception.GenericKeyStoreException; |
| 38 | +import nl.altindag.ssl.util.KeyStoreUtils; |
33 | 39 | import okhttp3.ConnectionSpec; |
34 | 40 | import okhttp3.Credentials; |
35 | 41 | import okhttp3.JavaNetCookieJar; |
|
38 | 44 | import org.bouncycastle.jce.provider.BouncyCastleProvider; |
39 | 45 | import org.slf4j.Logger; |
40 | 46 | import org.slf4j.LoggerFactory; |
| 47 | +import org.sonarsource.scanner.lib.internal.http.ssl.CertificateStore; |
41 | 48 | import org.sonarsource.scanner.lib.internal.http.ssl.SslConfig; |
42 | 49 |
|
43 | 50 | import static java.nio.charset.StandardCharsets.UTF_8; |
@@ -113,27 +120,59 @@ private static SSLFactory configureSsl(SslConfig sslConfig) { |
113 | 120 | sslFactoryBuilder.withSystemPropertyDerivedIdentityMaterial(); |
114 | 121 | } |
115 | 122 | var keyStoreConfig = sslConfig.getKeyStore(); |
116 | | - if (keyStoreConfig != null) { |
117 | | - sslFactoryBuilder.withIdentityMaterial(keyStoreConfig.getPath(), keyStoreConfig.getKeyStorePassword().toCharArray(), keyStoreConfig.getKeyStoreType()); |
| 123 | + if (keyStoreConfig != null && Files.exists(keyStoreConfig.getPath())) { |
| 124 | + keyStoreConfig.getKeyStorePassword() |
| 125 | + .ifPresentOrElse( |
| 126 | + password -> sslFactoryBuilder.withIdentityMaterial(keyStoreConfig.getPath(), password.toCharArray(), keyStoreConfig.getKeyStoreType()), |
| 127 | + () -> loadIdentityMaterialWithDefaultPassword(sslFactoryBuilder, keyStoreConfig.getPath())); |
118 | 128 | } |
119 | 129 | var trustStoreConfig = sslConfig.getTrustStore(); |
120 | | - if (trustStoreConfig != null) { |
121 | | - KeyStore trustStore = loadKeyStoreWithBouncyCastle( |
122 | | - trustStoreConfig.getPath(), |
123 | | - trustStoreConfig.getKeyStorePassword().toCharArray(), |
124 | | - trustStoreConfig.getKeyStoreType()); |
| 130 | + if (trustStoreConfig != null && Files.exists(trustStoreConfig.getPath())) { |
| 131 | + KeyStore trustStore; |
| 132 | + try { |
| 133 | + trustStore = loadTrustStoreWithBouncyCastle( |
| 134 | + trustStoreConfig.getPath(), |
| 135 | + trustStoreConfig.getKeyStorePassword().orElse(null), |
| 136 | + trustStoreConfig.getKeyStoreType()); |
| 137 | + LOG.debug("Loaded truststore from '{}' containing {} certificates", trustStoreConfig.getPath(), trustStore.size()); |
| 138 | + } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException e) { |
| 139 | + throw new GenericKeyStoreException("Unable to read truststore from '" + trustStoreConfig.getPath() + "'", e); |
| 140 | + } |
125 | 141 | sslFactoryBuilder.withTrustMaterial(trustStore); |
126 | 142 | } |
127 | 143 | return sslFactoryBuilder.build(); |
128 | 144 | } |
129 | 145 |
|
130 | | - public static KeyStore loadKeyStoreWithBouncyCastle(Path keystorePath, char[] keystorePassword, String keystoreType) { |
| 146 | + private static void loadIdentityMaterialWithDefaultPassword(SSLFactory.Builder sslFactoryBuilder, Path path) { |
| 147 | + try { |
| 148 | + var keystore = KeyStoreUtils.loadKeyStore(path, CertificateStore.DEFAULT_PASSWORD.toCharArray(), CertificateStore.DEFAULT_STORE_TYPE); |
| 149 | + sslFactoryBuilder.withIdentityMaterial(keystore, CertificateStore.DEFAULT_PASSWORD.toCharArray()); |
| 150 | + } catch (GenericKeyStoreException e) { |
| 151 | + var keystore = KeyStoreUtils.loadKeyStore(path, CertificateStore.OLD_DEFAULT_PASSWORD.toCharArray(), CertificateStore.DEFAULT_STORE_TYPE); |
| 152 | + LOG.warn("Using deprecated default password for keystore '{}'.", path); |
| 153 | + sslFactoryBuilder.withIdentityMaterial(keystore, CertificateStore.OLD_DEFAULT_PASSWORD.toCharArray()); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + static KeyStore loadTrustStoreWithBouncyCastle(Path keystorePath, @Nullable String keystorePassword, String keystoreType) throws IOException, |
| 158 | + KeyStoreException, CertificateException, NoSuchAlgorithmException { |
| 159 | + KeyStore keystore = KeyStore.getInstance(keystoreType, new BouncyCastleProvider()); |
| 160 | + if (keystorePassword != null) { |
| 161 | + loadKeyStoreWithPassword(keystorePath, keystore, keystorePassword); |
| 162 | + } else { |
| 163 | + try { |
| 164 | + loadKeyStoreWithPassword(keystorePath, keystore, CertificateStore.DEFAULT_PASSWORD); |
| 165 | + } catch (Exception e) { |
| 166 | + loadKeyStoreWithPassword(keystorePath, keystore, CertificateStore.OLD_DEFAULT_PASSWORD); |
| 167 | + LOG.warn("Using deprecated default password for truststore '{}'.", keystorePath); |
| 168 | + } |
| 169 | + } |
| 170 | + return keystore; |
| 171 | + } |
| 172 | + |
| 173 | + private static void loadKeyStoreWithPassword(Path keystorePath, KeyStore keystore, String oldDefaultPassword) throws IOException, NoSuchAlgorithmException, CertificateException { |
131 | 174 | try (InputStream keystoreInputStream = Files.newInputStream(keystorePath, StandardOpenOption.READ)) { |
132 | | - KeyStore keystore = KeyStore.getInstance(keystoreType, new BouncyCastleProvider()); |
133 | | - keystore.load(keystoreInputStream, keystorePassword); |
134 | | - return keystore; |
135 | | - } catch (Exception e) { |
136 | | - throw new GenericKeyStoreException(e); |
| 175 | + keystore.load(keystoreInputStream, oldDefaultPassword.toCharArray()); |
137 | 176 | } |
138 | 177 | } |
139 | 178 |
|
|
0 commit comments