Skip to content

Commit 01af787

Browse files
committed
Polish RsaKeyConverters
- Remove potential for returning null - Remove potential for parsing more than one header Issue gh-9736
1 parent 5f7d871 commit 01af787

File tree

1 file changed

+71
-35
lines changed

1 file changed

+71
-35
lines changed

core/src/main/java/org/springframework/security/converter/RsaKeyConverters.java

Lines changed: 71 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.util.stream.Collectors;
3636

3737
import org.springframework.core.convert.converter.Converter;
38+
import org.springframework.lang.NonNull;
3839
import org.springframework.util.Assert;
3940

4041
/**
@@ -110,41 +111,18 @@ public static Converter<InputStream, RSAPrivateKey> pkcs8() {
110111
* return a {@link RSAPublicKey}.
111112
*/
112113
public static Converter<InputStream, RSAPublicKey> x509() {
113-
KeyFactory keyFactory = rsaFactory();
114-
CertificateFactory certificateFactory = x509CertificateFactory();
114+
X509PemDecoder pemDecoder = new X509PemDecoder(rsaFactory());
115+
X509CertificateDecoder certDecoder = new X509CertificateDecoder(x509CertificateFactory());
115116
return (source) -> {
116117
List<String> lines = readAllLines(source);
117-
Assert.isTrue(
118-
!lines.isEmpty()
119-
&& (lines.get(0).startsWith(X509_PEM_HEADER) || lines.get(0).startsWith(X509_CERT_HEADER)),
118+
Assert.notEmpty(lines, "Input stream is empty");
119+
String encodingHint = lines.get(0);
120+
Converter<List<String>, RSAPublicKey> decoder = encodingHint.startsWith(X509_PEM_HEADER) ? pemDecoder
121+
: encodingHint.startsWith(X509_CERT_HEADER) ? certDecoder : null;
122+
Assert.notNull(decoder,
120123
"Key is not in PEM-encoded X.509 format or a valid X.509 certificate, please check that the header begins with "
121124
+ X509_PEM_HEADER + " or " + X509_CERT_HEADER);
122-
StringBuilder base64Encoded = new StringBuilder();
123-
for (String line : lines) {
124-
if (RsaKeyConverters.isNotX509PemWrapper(line) && isNotX509CertificateWrapper(line)) {
125-
base64Encoded.append(line);
126-
}
127-
}
128-
byte[] x509 = Base64.getDecoder().decode(base64Encoded.toString());
129-
if (lines.get(0).startsWith(X509_PEM_HEADER)) {
130-
try {
131-
return (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(x509));
132-
}
133-
catch (Exception ex) {
134-
throw new IllegalArgumentException(ex);
135-
}
136-
}
137-
if (lines.get(0).startsWith(X509_CERT_HEADER)) {
138-
try (InputStream x509CertStream = new ByteArrayInputStream(x509)) {
139-
X509Certificate certificate = (X509Certificate) certificateFactory
140-
.generateCertificate(x509CertStream);
141-
return (RSAPublicKey) certificate.getPublicKey();
142-
}
143-
catch (CertificateException | IOException ex) {
144-
throw new IllegalArgumentException(ex);
145-
}
146-
}
147-
return null;
125+
return decoder.convert(lines);
148126
};
149127
}
150128

@@ -175,12 +153,70 @@ private static boolean isNotPkcs8Wrapper(String line) {
175153
return !PKCS8_PEM_HEADER.equals(line) && !PKCS8_PEM_FOOTER.equals(line);
176154
}
177155

178-
private static boolean isNotX509PemWrapper(String line) {
179-
return !X509_PEM_HEADER.equals(line) && !X509_PEM_FOOTER.equals(line);
156+
private static class X509PemDecoder implements Converter<List<String>, RSAPublicKey> {
157+
158+
private final KeyFactory keyFactory;
159+
160+
X509PemDecoder(KeyFactory keyFactory) {
161+
this.keyFactory = keyFactory;
162+
}
163+
164+
@Override
165+
@NonNull
166+
public RSAPublicKey convert(List<String> lines) {
167+
StringBuilder base64Encoded = new StringBuilder();
168+
for (String line : lines) {
169+
if (isNotX509PemWrapper(line)) {
170+
base64Encoded.append(line);
171+
}
172+
}
173+
byte[] x509 = Base64.getDecoder().decode(base64Encoded.toString());
174+
try {
175+
return (RSAPublicKey) this.keyFactory.generatePublic(new X509EncodedKeySpec(x509));
176+
}
177+
catch (Exception ex) {
178+
throw new IllegalArgumentException(ex);
179+
}
180+
}
181+
182+
private boolean isNotX509PemWrapper(String line) {
183+
return !X509_PEM_HEADER.equals(line) && !X509_PEM_FOOTER.equals(line);
184+
}
185+
180186
}
181187

182-
private static boolean isNotX509CertificateWrapper(String line) {
183-
return !X509_CERT_HEADER.equals(line) && !X509_CERT_FOOTER.equals(line);
188+
private static class X509CertificateDecoder implements Converter<List<String>, RSAPublicKey> {
189+
190+
private final CertificateFactory certificateFactory;
191+
192+
X509CertificateDecoder(CertificateFactory certificateFactory) {
193+
this.certificateFactory = certificateFactory;
194+
}
195+
196+
@Override
197+
@NonNull
198+
public RSAPublicKey convert(List<String> lines) {
199+
StringBuilder base64Encoded = new StringBuilder();
200+
for (String line : lines) {
201+
if (isNotX509CertificateWrapper(line)) {
202+
base64Encoded.append(line);
203+
}
204+
}
205+
byte[] x509 = Base64.getDecoder().decode(base64Encoded.toString());
206+
try (InputStream x509CertStream = new ByteArrayInputStream(x509)) {
207+
X509Certificate certificate = (X509Certificate) this.certificateFactory
208+
.generateCertificate(x509CertStream);
209+
return (RSAPublicKey) certificate.getPublicKey();
210+
}
211+
catch (CertificateException | IOException ex) {
212+
throw new IllegalArgumentException(ex);
213+
}
214+
}
215+
216+
private boolean isNotX509CertificateWrapper(String line) {
217+
return !X509_CERT_HEADER.equals(line) && !X509_CERT_FOOTER.equals(line);
218+
}
219+
184220
}
185221

186222
}

0 commit comments

Comments
 (0)