Skip to content

Support for Base64 encoded p12 keystore using the ssl bundle configuration #35890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.boot.ssl.jks;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
Expand All @@ -24,6 +25,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.cert.CertificateException;
import java.util.Base64;

import org.springframework.boot.ssl.SslStoreBundle;
import org.springframework.util.Assert;
Expand Down Expand Up @@ -109,14 +111,29 @@ private void loadHardwareKeyStore(KeyStore store, String location, char[] passwo
private void loadKeyStore(KeyStore store, String location, char[] password) {
Assert.state(StringUtils.hasText(location), () -> "Location must not be empty or null");
try {
URL url = ResourceUtils.getURL(location);
try (InputStream stream = url.openStream()) {
store.load(stream, password);
if (isBase64(location.getBytes())) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of doing the decode twice, where you test first if you can decode it, you could do the else part in the catch block?

store.load(new ByteArrayInputStream(Base64.getDecoder().decode(location)), password);
}
else {
URL url = ResourceUtils.getURL(location);
try (InputStream stream = url.openStream()) {
store.load(stream, password);
}
}
}
catch (Exception ex) {
throw new IllegalStateException("Could not load store from '" + location + "'", ex);
}
}

private boolean isBase64(byte[] bytes) {
try {
Base64.getDecoder().decode(bytes);
}
catch (final IllegalArgumentException ex) {
return false;
}
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@

package org.springframework.boot.ssl.jks;

import java.io.IOException;
import java.nio.file.Files;
import java.security.KeyStore;
import java.util.function.Consumer;

import org.apache.hc.client5.http.utils.Base64;
import org.junit.jupiter.api.Test;

import org.springframework.boot.web.embedded.test.MockPkcs11Security;
import org.springframework.util.ResourceUtils;
import org.springframework.util.function.ThrowingConsumer;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -120,6 +124,15 @@ void whenHasTrustStoreProvider() {
.withMessageContaining("com.example.KeyStoreProvider");
}

@Test
void whenLocationIsBase64EncodedP12() throws IOException {
byte[] locationBytes = Files.readAllBytes(ResourceUtils.getFile("classpath:test.p12").toPath());
JksSslStoreDetails keyStoreDetails = JksSslStoreDetails.forLocation(Base64.encodeBase64String(locationBytes))
.withPassword("secret");
JksSslStoreBundle bundle = new JksSslStoreBundle(keyStoreDetails, null);
assertThat(bundle.getKeyStore()).satisfies(storeContainingCertAndKey("test-alias", "secret"));
}

private Consumer<KeyStore> storeContainingCertAndKey(String keyAlias, String keyPassword) {
return storeContainingCertAndKey(KeyStore.getDefaultType(), keyAlias, keyPassword);
}
Expand Down