|
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 | *
|
@@ -101,7 +118,7 @@ private AlpnSpec(HandshakeContext hc,
|
101 | 118 | "extension: empty application protocol name"));
|
102 | 119 | }
|
103 | 120 |
|
104 |
| - String appProtocol = new String(bytes, StandardCharsets.UTF_8); |
| 121 | + String appProtocol = new String(bytes, alpnCharset); |
105 | 122 | protocolNames.add(appProtocol);
|
106 | 123 | }
|
107 | 124 |
|
@@ -168,10 +185,10 @@ public byte[] produce(ConnectionContext context,
|
168 | 185 | return null;
|
169 | 186 | }
|
170 | 187 |
|
171 |
| - // Produce the extension. |
| 188 | + // Produce the extension: first find the overall length |
172 | 189 | int listLength = 0; // ProtocolNameList length
|
173 | 190 | for (String ap : laps) {
|
174 |
| - int length = ap.getBytes(StandardCharsets.UTF_8).length; |
| 191 | + int length = ap.getBytes(alpnCharset).length; |
175 | 192 | if (length == 0) {
|
176 | 193 | // log the configuration problem
|
177 | 194 | if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
|
@@ -223,8 +240,10 @@ public byte[] produce(ConnectionContext context,
|
223 | 240 | byte[] extData = new byte[listLength + 2];
|
224 | 241 | ByteBuffer m = ByteBuffer.wrap(extData);
|
225 | 242 | Record.putInt16(m, listLength);
|
| 243 | + |
| 244 | + // opaque ProtocolName<1..2^8-1>; |
226 | 245 | for (String ap : laps) {
|
227 |
| - Record.putBytes8(m, ap.getBytes(StandardCharsets.UTF_8)); |
| 246 | + Record.putBytes8(m, ap.getBytes(alpnCharset)); |
228 | 247 | }
|
229 | 248 |
|
230 | 249 | // Update the context.
|
@@ -414,14 +433,14 @@ public byte[] produce(ConnectionContext context,
|
414 | 433 | }
|
415 | 434 |
|
416 | 435 | // opaque ProtocolName<1..2^8-1>, RFC 7301.
|
417 |
| - int listLen = shc.applicationProtocol.length() + 1; |
418 |
| - // 1: length byte |
| 436 | + byte[] bytes = shc.applicationProtocol.getBytes(alpnCharset); |
| 437 | + int listLen = bytes.length + 1; // 1: length byte |
| 438 | + |
419 | 439 | // ProtocolName protocol_name_list<2..2^16-1>, RFC 7301.
|
420 | 440 | byte[] extData = new byte[listLen + 2]; // 2: list length
|
421 | 441 | ByteBuffer m = ByteBuffer.wrap(extData);
|
422 | 442 | Record.putInt16(m, listLen);
|
423 |
| - Record.putBytes8(m, |
424 |
| - shc.applicationProtocol.getBytes(StandardCharsets.UTF_8)); |
| 443 | + Record.putBytes8(m, bytes); |
425 | 444 |
|
426 | 445 | // Update the context.
|
427 | 446 | shc.conContext.applicationProtocol = shc.applicationProtocol;
|
|
0 commit comments