Skip to content

Commit 3ea5f07

Browse files
committed
8294985: SSLEngine throws IAE during parsing of X500Principal
Backport-of: 80edd5c298f21c5e5be3a0c2bb63129e76e0334f
1 parent 6a87af8 commit 3ea5f07

File tree

4 files changed

+486
-18
lines changed

4 files changed

+486
-18
lines changed

src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -122,8 +122,11 @@ private static List<byte[]> getEncodedAuthorities(
122122
return authorities;
123123
}
124124

125+
// This method will throw IllegalArgumentException if the
126+
// X500Principal cannot be parsed.
125127
X500Principal[] getAuthorities() {
126128
X500Principal[] principals = new X500Principal[authorities.size()];
129+
127130
int i = 0;
128131
for (byte[] encoded : authorities) {
129132
principals[i++] = new X500Principal(encoded);
@@ -138,8 +141,12 @@ public String toString() {
138141
"\"certificate authorities\": '['\n{0}']'", Locale.ENGLISH);
139142
StringBuilder builder = new StringBuilder(512);
140143
for (byte[] encoded : authorities) {
141-
X500Principal principal = new X500Principal(encoded);
142-
builder.append(principal.toString());
144+
try {
145+
X500Principal principal = new X500Principal(encoded);
146+
builder.append(principal.toString());
147+
} catch (IllegalArgumentException iae) {
148+
builder.append("unparseable distinguished name: " + iae);
149+
}
143150
builder.append("\n");
144151
}
145152
Object[] messageFields = {
@@ -277,7 +284,13 @@ public void consume(ConnectionContext context,
277284
new CertificateAuthoritiesSpec(shc, buffer);
278285

279286
// Update the context.
280-
shc.peerSupportedAuthorities = spec.getAuthorities();
287+
try {
288+
shc.peerSupportedAuthorities = spec.getAuthorities();
289+
} catch (IllegalArgumentException iae) {
290+
shc.conContext.fatal(Alert.DECODE_ERROR, "The distinguished " +
291+
"names of the peer's certificate authorities could " +
292+
"not be parsed", iae);
293+
}
281294
shc.handshakeExtensions.put(
282295
SSLExtension.CH_CERTIFICATE_AUTHORITIES, spec);
283296

@@ -398,7 +411,13 @@ public void consume(ConnectionContext context,
398411
new CertificateAuthoritiesSpec(chc, buffer);
399412

400413
// Update the context.
401-
chc.peerSupportedAuthorities = spec.getAuthorities();
414+
try {
415+
chc.peerSupportedAuthorities = spec.getAuthorities();
416+
} catch (IllegalArgumentException iae) {
417+
chc.conContext.fatal(Alert.DECODE_ERROR, "The distinguished " +
418+
"names of the peer's certificate authorities could " +
419+
"not be parsed", iae);
420+
}
402421
chc.handshakeExtensions.put(
403422
SSLExtension.CR_CERTIFICATE_AUTHORITIES, spec);
404423

src/java.base/share/classes/sun/security/ssl/CertificateRequest.java

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -203,9 +203,12 @@ String[] getKeyTypes() {
203203
return ClientCertificateType.getKeyTypes(types);
204204
}
205205

206+
// This method will throw IllegalArgumentException if the
207+
// X500Principal cannot be parsed.
206208
X500Principal[] getAuthorities() {
207209
X500Principal[] principals = new X500Principal[authorities.size()];
208210
int i = 0;
211+
209212
for (byte[] encoded : authorities) {
210213
principals[i++] = new X500Principal(encoded);
211214
}
@@ -258,8 +261,12 @@ public String toString() {
258261

259262
List<String> authorityNames = new ArrayList<>(authorities.size());
260263
for (byte[] encoded : authorities) {
261-
X500Principal principal = new X500Principal(encoded);
262-
authorityNames.add(principal.toString());
264+
try {
265+
X500Principal principal = new X500Principal(encoded);
266+
authorityNames.add(principal.toString());
267+
} catch (IllegalArgumentException iae) {
268+
authorityNames.add("unparseable distinguished name: " + iae);
269+
}
263270
}
264271
Object[] messageFields = {
265272
typeNames,
@@ -374,12 +381,23 @@ public void consume(ConnectionContext context,
374381

375382
X509ExtendedKeyManager km = chc.sslContext.getX509KeyManager();
376383
String clientAlias = null;
377-
if (chc.conContext.transport instanceof SSLSocketImpl) {
378-
clientAlias = km.chooseClientAlias(crm.getKeyTypes(),
379-
crm.getAuthorities(), (SSLSocket)chc.conContext.transport);
380-
} else if (chc.conContext.transport instanceof SSLEngineImpl) {
381-
clientAlias = km.chooseEngineClientAlias(crm.getKeyTypes(),
382-
crm.getAuthorities(), (SSLEngine)chc.conContext.transport);
384+
385+
try {
386+
if (chc.conContext.transport instanceof SSLSocketImpl) {
387+
clientAlias = km.chooseClientAlias(crm.getKeyTypes(),
388+
crm.getAuthorities(),
389+
(SSLSocket) chc.conContext.transport);
390+
} else if (chc.conContext.transport instanceof SSLEngineImpl) {
391+
clientAlias =
392+
km.chooseEngineClientAlias(crm.getKeyTypes(),
393+
crm.getAuthorities(),
394+
(SSLEngine) chc.conContext.transport);
395+
}
396+
} catch (IllegalArgumentException iae) {
397+
chc.conContext.fatal(Alert.DECODE_ERROR,
398+
"The distinguished names of the peer's "
399+
+ "certificate authorities could not be parsed",
400+
iae);
383401
}
384402

385403

@@ -516,9 +534,12 @@ String[] getKeyTypes() {
516534
return ClientCertificateType.getKeyTypes(types);
517535
}
518536

537+
// This method will throw IllegalArgumentException if the
538+
// X500Principal cannot be parsed.
519539
X500Principal[] getAuthorities() {
520540
X500Principal[] principals = new X500Principal[authorities.size()];
521541
int i = 0;
542+
522543
for (byte[] encoded : authorities) {
523544
principals[i++] = new X500Principal(encoded);
524545
}
@@ -582,8 +603,13 @@ public String toString() {
582603

583604
List<String> authorityNames = new ArrayList<>(authorities.size());
584605
for (byte[] encoded : authorities) {
585-
X500Principal principal = new X500Principal(encoded);
586-
authorityNames.add(principal.toString());
606+
try {
607+
X500Principal principal = new X500Principal(encoded);
608+
authorityNames.add(principal.toString());
609+
} catch (IllegalArgumentException iae) {
610+
authorityNames.add("unparseable distinguished name: " +
611+
iae);
612+
}
587613
}
588614
Object[] messageFields = {
589615
typeNames,
@@ -721,8 +747,13 @@ public void consume(ConnectionContext context,
721747
chc.peerRequestedSignatureSchemes = sss;
722748
chc.peerRequestedCertSignSchemes = sss; // use the same schemes
723749
chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
724-
chc.peerSupportedAuthorities = crm.getAuthorities();
725-
750+
try {
751+
chc.peerSupportedAuthorities = crm.getAuthorities();
752+
} catch (IllegalArgumentException iae) {
753+
chc.conContext.fatal(Alert.DECODE_ERROR, "The "
754+
+ "distinguished names of the peer's certificate "
755+
+ "authorities could not be parsed", iae);
756+
}
726757
// For TLS 1.2, we no longer use the certificate_types field
727758
// from the CertificateRequest message to directly determine
728759
// the SSLPossession. Instead, the choosePossession method
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8294985
27+
* @library /test/lib
28+
* @summary SSLEngine throws IAE during parsing of X500Principal
29+
* @run main/othervm TestBadDNForPeerCA
30+
* @run main/othervm -Djavax.net.debug=all TestBadDNForPeerCA
31+
*/
32+
33+
import javax.net.ssl.KeyManagerFactory;
34+
import javax.net.ssl.SSLContext;
35+
import javax.net.ssl.SSLEngine;
36+
import javax.net.ssl.SSLEngineResult;
37+
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
38+
import javax.net.ssl.SSLHandshakeException;
39+
import javax.net.ssl.TrustManagerFactory;
40+
import java.io.FileInputStream;
41+
import java.nio.ByteBuffer;
42+
import java.security.KeyStore;
43+
import java.util.Base64;
44+
45+
46+
public class TestBadDNForPeerCA {
47+
48+
private static final String proto = "TLSv1.3";
49+
50+
private final SSLContext sslc;
51+
52+
private SSLEngine serverEngine; // server Engine
53+
private ByteBuffer serverIn; // read side of serverEngine
54+
55+
private ByteBuffer cTOs; // "reliable" transport client->server
56+
57+
private static final String keyStoreFile =
58+
System.getProperty("test.src", "./")
59+
+ "/../../../../javax/net/ssl/etc/keystore";
60+
61+
// the following ClientHello contains a certificate with an
62+
// invalid/unparseable distinguished name
63+
private static final byte[] payload = Base64.getDecoder().decode(
64+
"FgMDAcsBAAHHAwPbDfeUCIStPzVIfXuGgCu56dSJOJ6xeus1W44frG5tciDEcBfYt"
65+
+ "/PN/6MFCGojEVcmPw21mVyjYInMo0UozIn4NwBiEwITARMDwCzAK8ypwDDMqMAvA"
66+
+ "J/MqgCjAJ4AosAkwCjAI8AnAGsAagBnAEDALsAywC3AMcAmCgAFKsApJcDAFMAJw"
67+
+ "BMAOQA4ADMAMsAFwA/ABMAOAJ0AnAA9ADwANgAvAP8BAAEcAAUABQEAAAAAAAoAF"
68+
+ "gAUAB0AFwAYABkAHgEAAQEBAgEDAQQACwACAQAAEQAJAAcCAAQAAAAAABcAAAAjA"
69+
+ "AAADQAsACoEAwUDBgMIBwgICAQIBQgGCAkICggLBAEFAQYBBAIDAwMBAwICAwIBA"
70+
+ "gIAKwAFBAMEAwMALQACAQEAMgAsACoEAwUDBgMIBwgICAQIBQgGCAkICggLBAEFA"
71+
+ "QYBBAIDAwMBAwICAwIBAgIALwBrAGkAHQAAAAARACAAZMUAADkwsiaOwcsWAwAAA"
72+
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
73+
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
74+
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
75+
+ "AAAAAAtAAAAAAAAAAEAADAAAAA=");
76+
77+
/*
78+
* The following is to set up the keystores.
79+
*/
80+
private static final String passwd = "passphrase";
81+
82+
/*
83+
* Main entry point for this demo.
84+
*/
85+
public static void main(String[] args) throws Exception {
86+
87+
TestBadDNForPeerCA test = new TestBadDNForPeerCA();
88+
89+
try {
90+
test.runTest();
91+
throw new Exception(
92+
"TEST FAILED: Didn't generate any exception");
93+
} catch (SSLHandshakeException she) {
94+
System.out.println("TEST PASSED: Caught expected exception");
95+
}
96+
}
97+
98+
/*
99+
* Create an initialized SSLContext to use for this demo.
100+
*/
101+
102+
public TestBadDNForPeerCA() throws Exception {
103+
104+
KeyStore ks = KeyStore.getInstance("JKS");
105+
KeyStore ts = KeyStore.getInstance("JKS");
106+
107+
char[] passphrase = passwd.toCharArray();
108+
109+
ks.load(new FileInputStream(keyStoreFile), passphrase);
110+
ts.load(new FileInputStream(keyStoreFile), passphrase);
111+
112+
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
113+
kmf.init(ks, passphrase);
114+
115+
TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
116+
tmf.init(ts);
117+
118+
SSLContext sslCtx = SSLContext.getInstance(proto);
119+
120+
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
121+
122+
sslc = sslCtx;
123+
}
124+
125+
126+
private void runTest() throws Exception {
127+
128+
createSSLEngines();
129+
createBuffers();
130+
131+
cTOs = ByteBuffer.wrap(payload);
132+
133+
System.out.println("injecting client hello");
134+
135+
for (int i = 0; i < 10; i++) { //retry if survived
136+
SSLEngineResult serverResult = serverEngine.unwrap(cTOs, serverIn);
137+
System.out.println("server unwrap: " + serverResult);
138+
runDelegatedTasks(serverResult, serverEngine);
139+
}
140+
}
141+
142+
private void createSSLEngines() throws Exception {
143+
144+
serverEngine = sslc.createSSLEngine();
145+
serverEngine.setUseClientMode(false);
146+
serverEngine.setNeedClientAuth(true);
147+
148+
}
149+
150+
151+
private void createBuffers() {
152+
153+
serverIn = ByteBuffer.allocateDirect(65536);
154+
155+
cTOs = ByteBuffer.allocateDirect(65536);
156+
157+
}
158+
159+
private static void runDelegatedTasks(SSLEngineResult result,
160+
SSLEngine engine) throws Exception {
161+
162+
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
163+
Runnable runnable;
164+
while ((runnable = engine.getDelegatedTask()) != null) {
165+
System.out.println("\trunning delegated task...");
166+
runnable.run();
167+
}
168+
169+
HandshakeStatus hsStatus = engine.getHandshakeStatus();
170+
if (hsStatus == HandshakeStatus.NEED_TASK) {
171+
throw new Exception("handshake shouldn't need additional " +
172+
"tasks");
173+
}
174+
System.out.println("\tnew HandshakeStatus: " + hsStatus);
175+
}
176+
}
177+
178+
179+
}

0 commit comments

Comments
 (0)