Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/KeyShareExtension.java
38830 views
1
/*
2
* Copyright (c) 2015, 2018, 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. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.ssl;
27
28
import java.io.IOException;
29
import java.nio.ByteBuffer;
30
import java.security.CryptoPrimitive;
31
import java.security.GeneralSecurityException;
32
import java.text.MessageFormat;
33
import java.util.Arrays;
34
import java.util.Collections;
35
import java.util.EnumSet;
36
import java.util.LinkedList;
37
import java.util.List;
38
import java.util.Locale;
39
import java.util.Map;
40
import javax.net.ssl.SSLProtocolException;
41
import sun.security.ssl.DHKeyExchange.DHECredentials;
42
import sun.security.ssl.DHKeyExchange.DHEPossession;
43
import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
44
import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
45
import sun.security.ssl.KeyShareExtension.CHKeyShareSpec;
46
import sun.security.ssl.SSLExtension.ExtensionConsumer;
47
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
48
import sun.security.ssl.SSLHandshake.HandshakeMessage;
49
import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
50
import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
51
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
52
import sun.misc.HexDumpEncoder;
53
54
/**
55
* Pack of the "key_share" extensions.
56
*/
57
final class KeyShareExtension {
58
static final HandshakeProducer chNetworkProducer =
59
new CHKeyShareProducer();
60
static final ExtensionConsumer chOnLoadConsumer =
61
new CHKeyShareConsumer();
62
static final SSLStringizer chStringizer =
63
new CHKeyShareStringizer();
64
65
static final HandshakeProducer shNetworkProducer =
66
new SHKeyShareProducer();
67
static final ExtensionConsumer shOnLoadConsumer =
68
new SHKeyShareConsumer();
69
static final HandshakeAbsence shOnLoadAbsence =
70
new SHKeyShareAbsence();
71
static final SSLStringizer shStringizer =
72
new SHKeyShareStringizer();
73
74
static final HandshakeProducer hrrNetworkProducer =
75
new HRRKeyShareProducer();
76
static final ExtensionConsumer hrrOnLoadConsumer =
77
new HRRKeyShareConsumer();
78
static final HandshakeProducer hrrNetworkReproducer =
79
new HRRKeyShareReproducer();
80
static final SSLStringizer hrrStringizer =
81
new HRRKeyShareStringizer();
82
83
/**
84
* The key share entry used in "key_share" extensions.
85
*/
86
private static final class KeyShareEntry {
87
final int namedGroupId;
88
final byte[] keyExchange;
89
90
private KeyShareEntry(int namedGroupId, byte[] keyExchange) {
91
this.namedGroupId = namedGroupId;
92
this.keyExchange = keyExchange;
93
}
94
95
private byte[] getEncoded() {
96
byte[] buffer = new byte[keyExchange.length + 4];
97
// 2: named group id
98
// +2: key exchange length
99
ByteBuffer m = ByteBuffer.wrap(buffer);
100
try {
101
Record.putInt16(m, namedGroupId);
102
Record.putBytes16(m, keyExchange);
103
} catch (IOException ioe) {
104
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
105
SSLLogger.warning(
106
"Unlikely IOException", ioe);
107
}
108
}
109
110
return buffer;
111
}
112
113
private int getEncodedSize() {
114
return keyExchange.length + 4; // 2: named group id
115
// +2: key exchange length
116
}
117
118
@Override
119
public String toString() {
120
MessageFormat messageFormat = new MessageFormat(
121
"\n'{'\n" +
122
" \"named group\": {0}\n" +
123
" \"key_exchange\": '{'\n" +
124
"{1}\n" +
125
" '}'\n" +
126
"'}',", Locale.ENGLISH);
127
128
HexDumpEncoder hexEncoder = new HexDumpEncoder();
129
Object[] messageFields = {
130
NamedGroup.nameOf(namedGroupId),
131
Utilities.indent(hexEncoder.encode(keyExchange), " ")
132
};
133
134
return messageFormat.format(messageFields);
135
}
136
}
137
138
/**
139
* The "key_share" extension in a ClientHello handshake message.
140
*/
141
static final class CHKeyShareSpec implements SSLExtensionSpec {
142
final List<KeyShareEntry> clientShares;
143
144
private CHKeyShareSpec(List<KeyShareEntry> clientShares) {
145
this.clientShares = clientShares;
146
}
147
148
private CHKeyShareSpec(ByteBuffer buffer) throws IOException {
149
// struct {
150
// KeyShareEntry client_shares<0..2^16-1>;
151
// } KeyShareClientHello;
152
if (buffer.remaining() < 2) {
153
throw new SSLProtocolException(
154
"Invalid key_share extension: " +
155
"insufficient data (length=" + buffer.remaining() + ")");
156
}
157
158
int listLen = Record.getInt16(buffer);
159
if (listLen != buffer.remaining()) {
160
throw new SSLProtocolException(
161
"Invalid key_share extension: " +
162
"incorrect list length (length=" + listLen + ")");
163
}
164
165
List<KeyShareEntry> keyShares = new LinkedList<>();
166
while (buffer.hasRemaining()) {
167
int namedGroupId = Record.getInt16(buffer);
168
byte[] keyExchange = Record.getBytes16(buffer);
169
if (keyExchange.length == 0) {
170
throw new SSLProtocolException(
171
"Invalid key_share extension: empty key_exchange");
172
}
173
174
keyShares.add(new KeyShareEntry(namedGroupId, keyExchange));
175
}
176
177
this.clientShares = Collections.unmodifiableList(keyShares);
178
}
179
180
@Override
181
public String toString() {
182
MessageFormat messageFormat = new MessageFormat(
183
"\"client_shares\": '['{0}\n']'", Locale.ENGLISH);
184
185
StringBuilder builder = new StringBuilder(512);
186
for (KeyShareEntry entry : clientShares) {
187
builder.append(entry.toString());
188
}
189
190
Object[] messageFields = {
191
Utilities.indent(builder.toString())
192
};
193
194
return messageFormat.format(messageFields);
195
}
196
}
197
198
private static final class CHKeyShareStringizer implements SSLStringizer {
199
@Override
200
public String toString(ByteBuffer buffer) {
201
try {
202
return (new CHKeyShareSpec(buffer)).toString();
203
} catch (IOException ioe) {
204
// For debug logging only, so please swallow exceptions.
205
return ioe.getMessage();
206
}
207
}
208
}
209
210
/**
211
* Network data producer of the extension in a ClientHello
212
* handshake message.
213
*/
214
private static final
215
class CHKeyShareProducer implements HandshakeProducer {
216
// Prevent instantiation of this class.
217
private CHKeyShareProducer() {
218
// blank
219
}
220
221
@Override
222
public byte[] produce(ConnectionContext context,
223
HandshakeMessage message) throws IOException {
224
// The producing happens in client side only.
225
ClientHandshakeContext chc = (ClientHandshakeContext)context;
226
227
// Is it a supported and enabled extension?
228
if (!chc.sslConfig.isAvailable(SSLExtension.CH_KEY_SHARE)) {
229
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
230
SSLLogger.fine(
231
"Ignore unavailable key_share extension");
232
}
233
return null;
234
}
235
236
List<NamedGroup> namedGroups;
237
if (chc.serverSelectedNamedGroup != null) {
238
// Response to HelloRetryRequest
239
namedGroups = Arrays.asList(chc.serverSelectedNamedGroup);
240
} else {
241
namedGroups = chc.clientRequestedNamedGroups;
242
if (namedGroups == null || namedGroups.isEmpty()) {
243
// No supported groups.
244
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
245
SSLLogger.warning(
246
"Ignore key_share extension, no supported groups");
247
}
248
return null;
249
}
250
}
251
252
List<KeyShareEntry> keyShares = new LinkedList<>();
253
for (NamedGroup ng : namedGroups) {
254
SSLKeyExchange ke = SSLKeyExchange.valueOf(ng);
255
if (ke == null) {
256
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
257
SSLLogger.warning(
258
"No key exchange for named group " + ng.name);
259
}
260
continue;
261
}
262
263
SSLPossession[] poses = ke.createPossessions(chc);
264
for (SSLPossession pos : poses) {
265
// update the context
266
chc.handshakePossessions.add(pos);
267
if (!(pos instanceof ECDHEPossession) &&
268
!(pos instanceof DHEPossession)) {
269
// May need more possesion types in the future.
270
continue;
271
}
272
273
keyShares.add(new KeyShareEntry(ng.id, pos.encode()));
274
}
275
276
// One key share entry only. Too much key share entries makes
277
// the ClientHello handshake message really big.
278
if (!keyShares.isEmpty()) {
279
break;
280
}
281
}
282
283
int listLen = 0;
284
for (KeyShareEntry entry : keyShares) {
285
listLen += entry.getEncodedSize();
286
}
287
byte[] extData = new byte[listLen + 2]; // 2: list length
288
ByteBuffer m = ByteBuffer.wrap(extData);
289
Record.putInt16(m, listLen);
290
for (KeyShareEntry entry : keyShares) {
291
m.put(entry.getEncoded());
292
}
293
294
// update the context
295
chc.handshakeExtensions.put(SSLExtension.CH_KEY_SHARE,
296
new CHKeyShareSpec(keyShares));
297
298
return extData;
299
}
300
}
301
302
/**
303
* Network data consumer of the extension in a ClientHello
304
* handshake message.
305
*/
306
private static final class CHKeyShareConsumer implements ExtensionConsumer {
307
// Prevent instantiation of this class.
308
private CHKeyShareConsumer() {
309
// blank
310
}
311
312
@Override
313
public void consume(ConnectionContext context,
314
HandshakeMessage message, ByteBuffer buffer) throws IOException {
315
// The consuming happens in server side only.
316
ServerHandshakeContext shc = (ServerHandshakeContext)context;
317
318
if (shc.handshakeExtensions.containsKey(SSLExtension.CH_KEY_SHARE)) {
319
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
320
SSLLogger.fine(
321
"The key_share extension has been loaded");
322
}
323
return;
324
}
325
326
// Is it a supported and enabled extension?
327
if (!shc.sslConfig.isAvailable(SSLExtension.CH_KEY_SHARE)) {
328
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
329
SSLLogger.fine(
330
"Ignore unavailable key_share extension");
331
}
332
return; // ignore the extension
333
}
334
335
// Parse the extension
336
CHKeyShareSpec spec;
337
try {
338
spec = new CHKeyShareSpec(buffer);
339
} catch (IOException ioe) {
340
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
341
}
342
343
List<SSLCredentials> credentials = new LinkedList<>();
344
for (KeyShareEntry entry : spec.clientShares) {
345
NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId);
346
if (ng == null || !SupportedGroups.isActivatable(
347
shc.algorithmConstraints, ng)) {
348
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
349
SSLLogger.fine(
350
"Ignore unsupported named group: " +
351
NamedGroup.nameOf(entry.namedGroupId));
352
}
353
continue;
354
}
355
356
if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
357
try {
358
ECDHECredentials ecdhec =
359
ECDHECredentials.valueOf(ng, entry.keyExchange);
360
if (ecdhec != null) {
361
if (!shc.algorithmConstraints.permits(
362
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
363
ecdhec.popPublicKey)) {
364
SSLLogger.warning(
365
"ECDHE key share entry does not " +
366
"comply to algorithm constraints");
367
} else {
368
credentials.add(ecdhec);
369
}
370
}
371
} catch (IOException | GeneralSecurityException ex) {
372
SSLLogger.warning(
373
"Cannot decode named group: " +
374
NamedGroup.nameOf(entry.namedGroupId));
375
}
376
} else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
377
try {
378
DHECredentials dhec =
379
DHECredentials.valueOf(ng, entry.keyExchange);
380
if (dhec != null) {
381
if (!shc.algorithmConstraints.permits(
382
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
383
dhec.popPublicKey)) {
384
SSLLogger.warning(
385
"DHE key share entry does not " +
386
"comply to algorithm constraints");
387
} else {
388
credentials.add(dhec);
389
}
390
}
391
} catch (IOException | GeneralSecurityException ex) {
392
SSLLogger.warning(
393
"Cannot decode named group: " +
394
NamedGroup.nameOf(entry.namedGroupId));
395
}
396
}
397
}
398
399
if (!credentials.isEmpty()) {
400
shc.handshakeCredentials.addAll(credentials);
401
} else {
402
// New handshake credentials are required from the client side.
403
shc.handshakeProducers.put(
404
SSLHandshake.HELLO_RETRY_REQUEST.id,
405
SSLHandshake.HELLO_RETRY_REQUEST);
406
}
407
408
// update the context
409
shc.handshakeExtensions.put(SSLExtension.CH_KEY_SHARE, spec);
410
}
411
}
412
413
/**
414
* The key share entry used in ServerHello "key_share" extensions.
415
*/
416
static final class SHKeyShareSpec implements SSLExtensionSpec {
417
final KeyShareEntry serverShare;
418
419
SHKeyShareSpec(KeyShareEntry serverShare) {
420
this.serverShare = serverShare;
421
}
422
423
private SHKeyShareSpec(ByteBuffer buffer) throws IOException {
424
// struct {
425
// KeyShareEntry server_share;
426
// } KeyShareServerHello;
427
if (buffer.remaining() < 5) { // 5: minimal server_share
428
throw new SSLProtocolException(
429
"Invalid key_share extension: " +
430
"insufficient data (length=" + buffer.remaining() + ")");
431
}
432
433
int namedGroupId = Record.getInt16(buffer);
434
byte[] keyExchange = Record.getBytes16(buffer);
435
436
if (buffer.hasRemaining()) {
437
throw new SSLProtocolException(
438
"Invalid key_share extension: unknown extra data");
439
}
440
441
this.serverShare = new KeyShareEntry(namedGroupId, keyExchange);
442
}
443
444
@Override
445
public String toString() {
446
MessageFormat messageFormat = new MessageFormat(
447
"\"server_share\": '{'\n" +
448
" \"named group\": {0}\n" +
449
" \"key_exchange\": '{'\n" +
450
"{1}\n" +
451
" '}'\n" +
452
"'}',", Locale.ENGLISH);
453
454
HexDumpEncoder hexEncoder = new HexDumpEncoder();
455
Object[] messageFields = {
456
NamedGroup.nameOf(serverShare.namedGroupId),
457
Utilities.indent(
458
hexEncoder.encode(serverShare.keyExchange), " ")
459
};
460
461
return messageFormat.format(messageFields);
462
}
463
}
464
465
private static final class SHKeyShareStringizer implements SSLStringizer {
466
@Override
467
public String toString(ByteBuffer buffer) {
468
try {
469
return (new SHKeyShareSpec(buffer)).toString();
470
} catch (IOException ioe) {
471
// For debug logging only, so please swallow exceptions.
472
return ioe.getMessage();
473
}
474
}
475
}
476
477
/**
478
* Network data producer of the extension in a ServerHello
479
* handshake message.
480
*/
481
private static final class SHKeyShareProducer implements HandshakeProducer {
482
// Prevent instantiation of this class.
483
private SHKeyShareProducer() {
484
// blank
485
}
486
487
@Override
488
public byte[] produce(ConnectionContext context,
489
HandshakeMessage message) throws IOException {
490
// The producing happens in client side only.
491
ServerHandshakeContext shc = (ServerHandshakeContext)context;
492
493
// In response to key_share request only
494
CHKeyShareSpec kss =
495
(CHKeyShareSpec)shc.handshakeExtensions.get(
496
SSLExtension.CH_KEY_SHARE);
497
if (kss == null) {
498
// Unlikely, no key_share extension requested.
499
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
500
SSLLogger.warning(
501
"Ignore, no client key_share extension");
502
}
503
return null;
504
}
505
506
// Is it a supported and enabled extension?
507
if (!shc.sslConfig.isAvailable(SSLExtension.SH_KEY_SHARE)) {
508
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
509
SSLLogger.warning(
510
"Ignore, no available server key_share extension");
511
}
512
return null;
513
}
514
515
// use requested key share entries
516
if ((shc.handshakeCredentials == null) ||
517
shc.handshakeCredentials.isEmpty()) {
518
// Unlikely, HelloRetryRequest should be used ealier.
519
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
520
SSLLogger.warning(
521
"No available client key share entries");
522
}
523
return null;
524
}
525
526
KeyShareEntry keyShare = null;
527
for (SSLCredentials cd : shc.handshakeCredentials) {
528
NamedGroup ng = null;
529
if (cd instanceof ECDHECredentials) {
530
ng = ((ECDHECredentials)cd).namedGroup;
531
} else if (cd instanceof DHECredentials) {
532
ng = ((DHECredentials)cd).namedGroup;
533
}
534
535
if (ng == null) {
536
continue;
537
}
538
539
SSLKeyExchange ke = SSLKeyExchange.valueOf(ng);
540
if (ke == null) {
541
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
542
SSLLogger.warning(
543
"No key exchange for named group " + ng.name);
544
}
545
continue;
546
}
547
548
SSLPossession[] poses = ke.createPossessions(shc);
549
for (SSLPossession pos : poses) {
550
if (!(pos instanceof ECDHEPossession) &&
551
!(pos instanceof DHEPossession)) {
552
// May need more possesion types in the future.
553
continue;
554
}
555
556
// update the context
557
shc.handshakeKeyExchange = ke;
558
shc.handshakePossessions.add(pos);
559
keyShare = new KeyShareEntry(ng.id, pos.encode());
560
break;
561
}
562
563
if (keyShare != null) {
564
for (Map.Entry<Byte, HandshakeProducer> me :
565
ke.getHandshakeProducers(shc)) {
566
shc.handshakeProducers.put(
567
me.getKey(), me.getValue());
568
}
569
570
// We have got one! Don't forgor to break.
571
break;
572
}
573
}
574
575
if (keyShare == null) {
576
// Unlikely, HelloRetryRequest should be used instead ealier.
577
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
578
SSLLogger.warning(
579
"No available server key_share extension");
580
}
581
return null;
582
}
583
584
byte[] extData = keyShare.getEncoded();
585
586
// update the context
587
SHKeyShareSpec spec = new SHKeyShareSpec(keyShare);
588
shc.handshakeExtensions.put(SSLExtension.SH_KEY_SHARE, spec);
589
590
return extData;
591
}
592
}
593
594
/**
595
* Network data consumer of the extension in a ServerHello
596
* handshake message.
597
*/
598
private static final class SHKeyShareConsumer implements ExtensionConsumer {
599
// Prevent instantiation of this class.
600
private SHKeyShareConsumer() {
601
// blank
602
}
603
604
@Override
605
public void consume(ConnectionContext context,
606
HandshakeMessage message, ByteBuffer buffer) throws IOException {
607
// Happens in client side only.
608
ClientHandshakeContext chc = (ClientHandshakeContext)context;
609
if (chc.clientRequestedNamedGroups == null ||
610
chc.clientRequestedNamedGroups.isEmpty()) {
611
// No supported groups.
612
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
613
"Unexpected key_share extension in ServerHello");
614
}
615
616
// Is it a supported and enabled extension?
617
if (!chc.sslConfig.isAvailable(SSLExtension.SH_KEY_SHARE)) {
618
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
619
"Unsupported key_share extension in ServerHello");
620
}
621
622
// Parse the extension
623
SHKeyShareSpec spec;
624
try {
625
spec = new SHKeyShareSpec(buffer);
626
} catch (IOException ioe) {
627
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
628
}
629
630
KeyShareEntry keyShare = spec.serverShare;
631
NamedGroup ng = NamedGroup.valueOf(keyShare.namedGroupId);
632
if (ng == null || !SupportedGroups.isActivatable(
633
chc.algorithmConstraints, ng)) {
634
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
635
"Unsupported named group: " +
636
NamedGroup.nameOf(keyShare.namedGroupId));
637
}
638
639
SSLKeyExchange ke = SSLKeyExchange.valueOf(ng);
640
if (ke == null) {
641
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
642
"No key exchange for named group " + ng.name);
643
}
644
645
SSLCredentials credentials = null;
646
if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
647
try {
648
ECDHECredentials ecdhec =
649
ECDHECredentials.valueOf(ng, keyShare.keyExchange);
650
if (ecdhec != null) {
651
if (!chc.algorithmConstraints.permits(
652
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
653
ecdhec.popPublicKey)) {
654
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
655
"ECDHE key share entry does not " +
656
"comply to algorithm constraints");
657
} else {
658
credentials = ecdhec;
659
}
660
}
661
} catch (IOException | GeneralSecurityException ex) {
662
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
663
"Cannot decode named group: " +
664
NamedGroup.nameOf(keyShare.namedGroupId));
665
}
666
} else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
667
try {
668
DHECredentials dhec =
669
DHECredentials.valueOf(ng, keyShare.keyExchange);
670
if (dhec != null) {
671
if (!chc.algorithmConstraints.permits(
672
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
673
dhec.popPublicKey)) {
674
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
675
"DHE key share entry does not " +
676
"comply to algorithm constraints");
677
} else {
678
credentials = dhec;
679
}
680
}
681
} catch (IOException | GeneralSecurityException ex) {
682
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
683
"Cannot decode named group: " +
684
NamedGroup.nameOf(keyShare.namedGroupId));
685
}
686
} else {
687
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
688
"Unsupported named group: " +
689
NamedGroup.nameOf(keyShare.namedGroupId));
690
}
691
692
if (credentials == null) {
693
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
694
"Unsupported named group: " + ng.name);
695
}
696
697
// update the context
698
chc.handshakeKeyExchange = ke;
699
chc.handshakeCredentials.add(credentials);
700
chc.handshakeExtensions.put(SSLExtension.SH_KEY_SHARE, spec);
701
}
702
}
703
704
/**
705
* The absence processing if the extension is not present in
706
* the ServerHello handshake message.
707
*/
708
private static final class SHKeyShareAbsence implements HandshakeAbsence {
709
@Override
710
public void absent(ConnectionContext context,
711
HandshakeMessage message) throws IOException {
712
// The producing happens in client side only.
713
ClientHandshakeContext chc = (ClientHandshakeContext)context;
714
715
// Cannot use the previous requested key shares any more.
716
if (SSLLogger.isOn && SSLLogger.isOn("handshake")) {
717
SSLLogger.fine(
718
"No key_share extension in ServerHello, " +
719
"cleanup the key shares if necessary");
720
}
721
chc.handshakePossessions.clear();
722
}
723
}
724
725
/**
726
* The key share entry used in HelloRetryRequest "key_share" extensions.
727
*/
728
static final class HRRKeyShareSpec implements SSLExtensionSpec {
729
final int selectedGroup;
730
731
HRRKeyShareSpec(NamedGroup serverGroup) {
732
this.selectedGroup = serverGroup.id;
733
}
734
735
private HRRKeyShareSpec(ByteBuffer buffer) throws IOException {
736
// struct {
737
// NamedGroup selected_group;
738
// } KeyShareHelloRetryRequest;
739
if (buffer.remaining() != 2) {
740
throw new SSLProtocolException(
741
"Invalid key_share extension: " +
742
"improper data (length=" + buffer.remaining() + ")");
743
}
744
745
this.selectedGroup = Record.getInt16(buffer);
746
}
747
748
@Override
749
public String toString() {
750
MessageFormat messageFormat = new MessageFormat(
751
"\"selected group\": '['{0}']'", Locale.ENGLISH);
752
753
Object[] messageFields = {
754
NamedGroup.nameOf(selectedGroup)
755
};
756
return messageFormat.format(messageFields);
757
}
758
}
759
760
private static final class HRRKeyShareStringizer implements SSLStringizer {
761
@Override
762
public String toString(ByteBuffer buffer) {
763
try {
764
return (new HRRKeyShareSpec(buffer)).toString();
765
} catch (IOException ioe) {
766
// For debug logging only, so please swallow exceptions.
767
return ioe.getMessage();
768
}
769
}
770
}
771
772
/**
773
* Network data producer of the extension in a HelloRetryRequest
774
* handshake message.
775
*/
776
private static final
777
class HRRKeyShareProducer implements HandshakeProducer {
778
// Prevent instantiation of this class.
779
private HRRKeyShareProducer() {
780
// blank
781
}
782
783
@Override
784
public byte[] produce(ConnectionContext context,
785
HandshakeMessage message) throws IOException {
786
// The producing happens in server side only.
787
ServerHandshakeContext shc = (ServerHandshakeContext) context;
788
789
// Is it a supported and enabled extension?
790
if (!shc.sslConfig.isAvailable(SSLExtension.HRR_KEY_SHARE)) {
791
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
792
"Unsupported key_share extension in HelloRetryRequest");
793
}
794
795
if (shc.clientRequestedNamedGroups == null ||
796
shc.clientRequestedNamedGroups.isEmpty()) {
797
// No supported groups.
798
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
799
"Unexpected key_share extension in HelloRetryRequest");
800
}
801
802
NamedGroup selectedGroup = null;
803
for (NamedGroup ng : shc.clientRequestedNamedGroups) {
804
if (SupportedGroups.isActivatable(
805
shc.algorithmConstraints, ng)) {
806
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
807
SSLLogger.fine(
808
"HelloRetryRequest selected named group: " +
809
ng.name);
810
}
811
812
selectedGroup = ng;
813
break;
814
}
815
}
816
817
if (selectedGroup == null) {
818
throw shc.conContext.fatal(
819
Alert.UNEXPECTED_MESSAGE, "No common named group");
820
}
821
822
byte[] extdata = new byte[] {
823
(byte)((selectedGroup.id >> 8) & 0xFF),
824
(byte)(selectedGroup.id & 0xFF)
825
};
826
827
// update the context
828
shc.serverSelectedNamedGroup = selectedGroup;
829
shc.handshakeExtensions.put(SSLExtension.HRR_KEY_SHARE,
830
new HRRKeyShareSpec(selectedGroup));
831
832
return extdata;
833
}
834
}
835
836
/**
837
* Network data producer of the extension for stateless
838
* HelloRetryRequest reconstruction.
839
*/
840
private static final
841
class HRRKeyShareReproducer implements HandshakeProducer {
842
// Prevent instantiation of this class.
843
private HRRKeyShareReproducer() {
844
// blank
845
}
846
847
@Override
848
public byte[] produce(ConnectionContext context,
849
HandshakeMessage message) throws IOException {
850
// The producing happens in server side only.
851
ServerHandshakeContext shc = (ServerHandshakeContext) context;
852
853
// Is it a supported and enabled extension?
854
if (!shc.sslConfig.isAvailable(SSLExtension.HRR_KEY_SHARE)) {
855
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
856
"Unsupported key_share extension in HelloRetryRequest");
857
}
858
859
CHKeyShareSpec spec = (CHKeyShareSpec)shc.handshakeExtensions.get(
860
SSLExtension.CH_KEY_SHARE);
861
if (spec != null && spec.clientShares != null &&
862
spec.clientShares.size() == 1) {
863
int namedGroupId = spec.clientShares.get(0).namedGroupId;
864
865
byte[] extdata = new byte[] {
866
(byte)((namedGroupId >> 8) & 0xFF),
867
(byte)(namedGroupId & 0xFF)
868
};
869
870
return extdata;
871
}
872
873
return null;
874
}
875
}
876
877
/**
878
* Network data consumer of the extension in a HelloRetryRequest
879
* handshake message.
880
*/
881
private static final
882
class HRRKeyShareConsumer implements ExtensionConsumer {
883
// Prevent instantiation of this class.
884
private HRRKeyShareConsumer() {
885
// blank
886
}
887
888
@Override
889
public void consume(ConnectionContext context,
890
HandshakeMessage message, ByteBuffer buffer) throws IOException {
891
// The producing happens in client side only.
892
ClientHandshakeContext chc = (ClientHandshakeContext)context;
893
894
// Is it a supported and enabled extension?
895
if (!chc.sslConfig.isAvailable(SSLExtension.HRR_KEY_SHARE)) {
896
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
897
"Unsupported key_share extension in HelloRetryRequest");
898
}
899
900
if (chc.clientRequestedNamedGroups == null ||
901
chc.clientRequestedNamedGroups.isEmpty()) {
902
// No supported groups.
903
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
904
"Unexpected key_share extension in HelloRetryRequest");
905
}
906
907
// Parse the extension
908
HRRKeyShareSpec spec;
909
try {
910
spec = new HRRKeyShareSpec(buffer);
911
} catch (IOException ioe) {
912
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
913
}
914
915
NamedGroup serverGroup = NamedGroup.valueOf(spec.selectedGroup);
916
if (serverGroup == null) {
917
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
918
"Unsupported HelloRetryRequest selected group: " +
919
NamedGroup.nameOf(spec.selectedGroup));
920
}
921
922
if (!chc.clientRequestedNamedGroups.contains(serverGroup)) {
923
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
924
"Unexpected HelloRetryRequest selected group: " +
925
serverGroup.name);
926
}
927
928
// update the context
929
930
// When sending the new ClientHello, the client MUST replace the
931
// original "key_share" extension with one containing only a new
932
// KeyShareEntry for the group indicated in the selected_group
933
// field of the triggering HelloRetryRequest.
934
//
935
chc.serverSelectedNamedGroup = serverGroup;
936
chc.handshakeExtensions.put(SSLExtension.HRR_KEY_SHARE, spec);
937
}
938
}
939
}
940
941