|
27 | 27 |
|
28 | 28 | import java.io.IOException;
|
29 | 29 | import java.nio.ByteBuffer;
|
30 |
| -import java.nio.charset.StandardCharsets; |
| 30 | +import java.nio.charset.Charset; |
| 31 | +import java.security.AccessController; |
| 32 | +import java.security.PrivilegedAction; |
| 33 | +import java.security.Security; |
31 | 34 | import java.util.Arrays;
|
32 | 35 | import java.util.Collections;
|
33 | 36 | import java.util.LinkedList;
|
@@ -59,6 +62,20 @@ final class AlpnExtension {
|
59 | 62 |
|
60 | 63 | static final SSLStringizer alpnStringizer = new AlpnStringizer();
|
61 | 64 |
|
| 65 | + // Encoding Charset to convert between String and byte[] |
| 66 | + static final Charset alpnCharset; |
| 67 | + |
| 68 | + static { |
| 69 | + String alpnCharsetString = AccessController.doPrivileged( |
| 70 | + (PrivilegedAction<String>) () |
| 71 | + -> Security.getProperty("jdk.tls.alpnCharset")); |
| 72 | + if ((alpnCharsetString == null) |
| 73 | + || (alpnCharsetString.length() == 0)) { |
| 74 | + alpnCharsetString = "ISO_8859_1"; |
| 75 | + } |
| 76 | + alpnCharset = Charset.forName(alpnCharsetString); |
| 77 | + } |
| 78 | + |
62 | 79 | /**
|
63 | 80 | * The "application_layer_protocol_negotiation" extension.
|
64 | 81 | *
|
@@ -97,7 +114,7 @@ private AlpnSpec(ByteBuffer buffer) throws IOException {
|
97 | 114 | "extension: empty application protocol name");
|
98 | 115 | }
|
99 | 116 |
|
100 |
| - String appProtocol = new String(bytes, StandardCharsets.UTF_8); |
| 117 | + String appProtocol = new String(bytes, alpnCharset); |
101 | 118 | protocolNames.add(appProtocol);
|
102 | 119 | }
|
103 | 120 |
|
@@ -164,10 +181,10 @@ public byte[] produce(ConnectionContext context,
|
164 | 181 | return null;
|
165 | 182 | }
|
166 | 183 |
|
167 |
| - // Produce the extension. |
| 184 | + // Produce the extension: first find the overall length |
168 | 185 | int listLength = 0; // ProtocolNameList length
|
169 | 186 | for (String ap : laps) {
|
170 |
| - int length = ap.getBytes(StandardCharsets.UTF_8).length; |
| 187 | + int length = ap.getBytes(alpnCharset).length; |
171 | 188 | if (length == 0) {
|
172 | 189 | // log the configuration problem
|
173 | 190 | if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
@@ -219,8 +236,10 @@ public byte[] produce(ConnectionContext context,
|
219 | 236 | byte[] extData = new byte[listLength + 2];
|
220 | 237 | ByteBuffer m = ByteBuffer.wrap(extData);
|
221 | 238 | Record.putInt16(m, listLength);
|
| 239 | + |
| 240 | + // opaque ProtocolName<1..2^8-1>; |
222 | 241 | for (String ap : laps) {
|
223 |
| - Record.putBytes8(m, ap.getBytes(StandardCharsets.UTF_8)); |
| 242 | + Record.putBytes8(m, ap.getBytes(alpnCharset)); |
224 | 243 | }
|
225 | 244 |
|
226 | 245 | // Update the context.
|
@@ -415,14 +434,14 @@ public byte[] produce(ConnectionContext context,
|
415 | 434 | }
|
416 | 435 |
|
417 | 436 | // opaque ProtocolName<1..2^8-1>, RFC 7301.
|
418 |
| - int listLen = shc.applicationProtocol.length() + 1; |
419 |
| - // 1: length byte |
| 437 | + byte[] bytes = shc.applicationProtocol.getBytes(alpnCharset); |
| 438 | + int listLen = bytes.length + 1; // 1: length byte |
| 439 | + |
420 | 440 | // ProtocolName protocol_name_list<2..2^16-1>, RFC 7301.
|
421 | 441 | byte[] extData = new byte[listLen + 2]; // 2: list length
|
422 | 442 | ByteBuffer m = ByteBuffer.wrap(extData);
|
423 | 443 | Record.putInt16(m, listLen);
|
424 |
| - Record.putBytes8(m, |
425 |
| - shc.applicationProtocol.getBytes(StandardCharsets.UTF_8)); |
| 444 | + Record.putBytes8(m, bytes); |
426 | 445 |
|
427 | 446 | // Update the context.
|
428 | 447 | shc.conContext.applicationProtocol = shc.applicationProtocol;
|
|
0 commit comments