Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/ssl/CertificateVerify.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, 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.*;
31
import java.text.MessageFormat;
32
import java.util.Arrays;
33
import java.util.Locale;
34
import java.util.Map;
35
import sun.security.ssl.SSLHandshake.HandshakeMessage;
36
import sun.security.ssl.X509Authentication.X509Credentials;
37
import sun.security.ssl.X509Authentication.X509Possession;
38
import sun.security.util.HexDumpEncoder;
39
40
/**
41
* Pack of the CertificateVerify handshake message.
42
*/
43
final class CertificateVerify {
44
static final SSLConsumer s30HandshakeConsumer =
45
new S30CertificateVerifyConsumer();
46
static final HandshakeProducer s30HandshakeProducer =
47
new S30CertificateVerifyProducer();
48
49
static final SSLConsumer t10HandshakeConsumer =
50
new T10CertificateVerifyConsumer();
51
static final HandshakeProducer t10HandshakeProducer =
52
new T10CertificateVerifyProducer();
53
54
static final SSLConsumer t12HandshakeConsumer =
55
new T12CertificateVerifyConsumer();
56
static final HandshakeProducer t12HandshakeProducer =
57
new T12CertificateVerifyProducer();
58
59
static final SSLConsumer t13HandshakeConsumer =
60
new T13CertificateVerifyConsumer();
61
static final HandshakeProducer t13HandshakeProducer =
62
new T13CertificateVerifyProducer();
63
64
/**
65
* The CertificateVerify handshake message (SSL 3.0).
66
*/
67
static final class S30CertificateVerifyMessage extends HandshakeMessage {
68
// signature bytes
69
private final byte[] signature;
70
71
S30CertificateVerifyMessage(HandshakeContext context,
72
X509Possession x509Possession) throws IOException {
73
super(context);
74
75
// This happens in client side only.
76
ClientHandshakeContext chc = (ClientHandshakeContext)context;
77
byte[] temporary;
78
String algorithm = x509Possession.popPrivateKey.getAlgorithm();
79
try {
80
Signature signer =
81
getSignature(algorithm, x509Possession.popPrivateKey);
82
byte[] hashes = chc.handshakeHash.digest(algorithm,
83
chc.handshakeSession.getMasterSecret());
84
signer.update(hashes);
85
temporary = signer.sign();
86
} catch (NoSuchAlgorithmException nsae) {
87
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
88
"Unsupported signature algorithm (" + algorithm +
89
") used in CertificateVerify handshake message", nsae);
90
} catch (GeneralSecurityException gse) {
91
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
92
"Cannot produce CertificateVerify signature", gse);
93
}
94
95
this.signature = temporary;
96
}
97
98
S30CertificateVerifyMessage(HandshakeContext context,
99
ByteBuffer m) throws IOException {
100
super(context);
101
102
// This happens in server side only.
103
ServerHandshakeContext shc = (ServerHandshakeContext)context;
104
105
// digitally-signed struct {
106
// select(SignatureAlgorithm) {
107
// case anonymous: struct { };
108
// case rsa:
109
// opaque md5_hash[16];
110
// opaque sha_hash[20];
111
// case dsa:
112
// opaque sha_hash[20];
113
// };
114
// } Signature;
115
if (m.remaining() < 2) {
116
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
117
"Invalid CertificateVerify message: no sufficient data");
118
}
119
120
// read and verify the signature
121
this.signature = Record.getBytes16(m);
122
X509Credentials x509Credentials = null;
123
for (SSLCredentials cd : shc.handshakeCredentials) {
124
if (cd instanceof X509Credentials) {
125
x509Credentials = (X509Credentials)cd;
126
break;
127
}
128
}
129
130
if (x509Credentials == null ||
131
x509Credentials.popPublicKey == null) {
132
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
133
"No X509 credentials negotiated for CertificateVerify");
134
}
135
136
String algorithm = x509Credentials.popPublicKey.getAlgorithm();
137
try {
138
Signature signer =
139
getSignature(algorithm, x509Credentials.popPublicKey);
140
byte[] hashes = shc.handshakeHash.digest(algorithm,
141
shc.handshakeSession.getMasterSecret());
142
signer.update(hashes);
143
if (!signer.verify(signature)) {
144
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
145
"Invalid CertificateVerify message: invalid signature");
146
}
147
} catch (NoSuchAlgorithmException nsae) {
148
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
149
"Unsupported signature algorithm (" + algorithm +
150
") used in CertificateVerify handshake message", nsae);
151
} catch (GeneralSecurityException gse) {
152
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
153
"Cannot verify CertificateVerify signature", gse);
154
}
155
}
156
157
@Override
158
public SSLHandshake handshakeType() {
159
return SSLHandshake.CERTIFICATE_VERIFY;
160
}
161
162
@Override
163
public int messageLength() {
164
return 2 + signature.length; // 2: length of signature
165
}
166
167
@Override
168
public void send(HandshakeOutStream hos) throws IOException {
169
hos.putBytes16(signature);
170
}
171
172
@Override
173
public String toString() {
174
MessageFormat messageFormat = new MessageFormat(
175
"\"CertificateVerify\": '{'\n" +
176
" \"signature\": '{'\n" +
177
"{0}\n" +
178
" '}'\n" +
179
"'}'",
180
Locale.ENGLISH);
181
182
HexDumpEncoder hexEncoder = new HexDumpEncoder();
183
Object[] messageFields = {
184
Utilities.indent(
185
hexEncoder.encodeBuffer(signature), " ")
186
};
187
188
return messageFormat.format(messageFields);
189
}
190
191
/*
192
* Get the Signature object appropriate for verification using the
193
* given signature algorithm.
194
*/
195
private static Signature getSignature(String algorithm,
196
Key key) throws GeneralSecurityException {
197
Signature signer;
198
switch (algorithm) {
199
case "RSA":
200
signer = Signature.getInstance(JsseJce.SIGNATURE_RAWRSA);
201
break;
202
case "DSA":
203
signer = Signature.getInstance(JsseJce.SIGNATURE_RAWDSA);
204
break;
205
case "EC":
206
signer = Signature.getInstance(JsseJce.SIGNATURE_RAWECDSA);
207
break;
208
default:
209
throw new SignatureException("Unrecognized algorithm: "
210
+ algorithm);
211
}
212
213
if (signer != null) {
214
if (key instanceof PublicKey) {
215
signer.initVerify((PublicKey)(key));
216
} else {
217
signer.initSign((PrivateKey)key);
218
}
219
}
220
221
return signer;
222
}
223
}
224
225
/**
226
* The "CertificateVerify" handshake message producer.
227
*/
228
private static final
229
class S30CertificateVerifyProducer implements HandshakeProducer {
230
// Prevent instantiation of this class.
231
private S30CertificateVerifyProducer() {
232
// blank
233
}
234
235
@Override
236
public byte[] produce(ConnectionContext context,
237
HandshakeMessage message) throws IOException {
238
// The producing happens in client side only.
239
ClientHandshakeContext chc = (ClientHandshakeContext)context;
240
241
X509Possession x509Possession = null;
242
for (SSLPossession possession : chc.handshakePossessions) {
243
if (possession instanceof X509Possession) {
244
x509Possession = (X509Possession)possession;
245
break;
246
}
247
}
248
249
if (x509Possession == null ||
250
x509Possession.popPrivateKey == null) {
251
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
252
SSLLogger.fine(
253
"No X.509 credentials negotiated for CertificateVerify");
254
}
255
256
return null;
257
}
258
259
S30CertificateVerifyMessage cvm =
260
new S30CertificateVerifyMessage(chc, x509Possession);
261
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
262
SSLLogger.fine(
263
"Produced CertificateVerify handshake message", cvm);
264
}
265
266
// Output the handshake message.
267
cvm.write(chc.handshakeOutput);
268
chc.handshakeOutput.flush();
269
270
// The handshake message has been delivered.
271
return null;
272
}
273
}
274
275
/**
276
* The "CertificateVerify" handshake message consumer.
277
*/
278
private static final
279
class S30CertificateVerifyConsumer implements SSLConsumer {
280
// Prevent instantiation of this class.
281
private S30CertificateVerifyConsumer() {
282
// blank
283
}
284
285
@Override
286
public void consume(ConnectionContext context,
287
ByteBuffer message) throws IOException {
288
// The consuming happens in server side only.
289
ServerHandshakeContext shc = (ServerHandshakeContext)context;
290
291
// Clean up this consumer
292
shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
293
294
// Ensure that the CV message follows the CKE
295
if (shc.handshakeConsumers.containsKey(
296
SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
297
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
298
"Unexpected CertificateVerify handshake message");
299
}
300
301
S30CertificateVerifyMessage cvm =
302
new S30CertificateVerifyMessage(shc, message);
303
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
304
SSLLogger.fine(
305
"Consuming CertificateVerify handshake message", cvm);
306
}
307
308
//
309
// update
310
//
311
// Need no additional validation.
312
313
//
314
// produce
315
//
316
// Need no new handshake message producers here.
317
}
318
}
319
320
/**
321
* The CertificateVerify handshake message (TLS 1.0/1.1).
322
*/
323
static final class T10CertificateVerifyMessage extends HandshakeMessage {
324
// signature bytes
325
private final byte[] signature;
326
327
T10CertificateVerifyMessage(HandshakeContext context,
328
X509Possession x509Possession) throws IOException {
329
super(context);
330
331
// This happens in client side only.
332
ClientHandshakeContext chc = (ClientHandshakeContext)context;
333
byte[] temporary;
334
String algorithm = x509Possession.popPrivateKey.getAlgorithm();
335
try {
336
Signature signer =
337
getSignature(algorithm, x509Possession.popPrivateKey);
338
byte[] hashes = chc.handshakeHash.digest(algorithm);
339
signer.update(hashes);
340
temporary = signer.sign();
341
} catch (NoSuchAlgorithmException nsae) {
342
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
343
"Unsupported signature algorithm (" + algorithm +
344
") used in CertificateVerify handshake message", nsae);
345
} catch (GeneralSecurityException gse) {
346
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
347
"Cannot produce CertificateVerify signature", gse);
348
}
349
350
this.signature = temporary;
351
}
352
353
T10CertificateVerifyMessage(HandshakeContext context,
354
ByteBuffer m) throws IOException {
355
super(context);
356
357
// This happens in server side only.
358
ServerHandshakeContext shc = (ServerHandshakeContext)context;
359
360
// digitally-signed struct {
361
// select(SignatureAlgorithm) {
362
// case anonymous: struct { };
363
// case rsa:
364
// opaque md5_hash[16];
365
// opaque sha_hash[20];
366
// case dsa:
367
// opaque sha_hash[20];
368
// };
369
// } Signature;
370
if (m.remaining() < 2) {
371
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
372
"Invalid CertificateVerify message: no sufficient data");
373
}
374
375
// read and verify the signature
376
this.signature = Record.getBytes16(m);
377
X509Credentials x509Credentials = null;
378
for (SSLCredentials cd : shc.handshakeCredentials) {
379
if (cd instanceof X509Credentials) {
380
x509Credentials = (X509Credentials)cd;
381
break;
382
}
383
}
384
385
if (x509Credentials == null ||
386
x509Credentials.popPublicKey == null) {
387
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
388
"No X509 credentials negotiated for CertificateVerify");
389
}
390
391
String algorithm = x509Credentials.popPublicKey.getAlgorithm();
392
try {
393
Signature signer =
394
getSignature(algorithm, x509Credentials.popPublicKey);
395
byte[] hashes = shc.handshakeHash.digest(algorithm);
396
signer.update(hashes);
397
if (!signer.verify(signature)) {
398
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
399
"Invalid CertificateVerify message: invalid signature");
400
}
401
} catch (NoSuchAlgorithmException nsae) {
402
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
403
"Unsupported signature algorithm (" + algorithm +
404
") used in CertificateVerify handshake message", nsae);
405
} catch (GeneralSecurityException gse) {
406
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
407
"Cannot verify CertificateVerify signature", gse);
408
}
409
}
410
411
@Override
412
public SSLHandshake handshakeType() {
413
return SSLHandshake.CERTIFICATE_VERIFY;
414
}
415
416
@Override
417
public int messageLength() {
418
return 2 + signature.length; // 2: length of signature
419
}
420
421
@Override
422
public void send(HandshakeOutStream hos) throws IOException {
423
hos.putBytes16(signature);
424
}
425
426
@Override
427
public String toString() {
428
MessageFormat messageFormat = new MessageFormat(
429
"\"CertificateVerify\": '{'\n" +
430
" \"signature\": '{'\n" +
431
"{0}\n" +
432
" '}'\n" +
433
"'}'",
434
Locale.ENGLISH);
435
436
HexDumpEncoder hexEncoder = new HexDumpEncoder();
437
Object[] messageFields = {
438
Utilities.indent(
439
hexEncoder.encodeBuffer(signature), " ")
440
};
441
442
return messageFormat.format(messageFields);
443
}
444
445
/*
446
* Get the Signature object appropriate for verification using the
447
* given signature algorithm.
448
*/
449
private static Signature getSignature(String algorithm,
450
Key key) throws GeneralSecurityException {
451
Signature signer;
452
switch (algorithm) {
453
case "RSA":
454
signer = Signature.getInstance(JsseJce.SIGNATURE_RAWRSA);
455
break;
456
case "DSA":
457
signer = Signature.getInstance(JsseJce.SIGNATURE_RAWDSA);
458
break;
459
case "EC":
460
signer = Signature.getInstance(JsseJce.SIGNATURE_RAWECDSA);
461
break;
462
case "EdDSA":
463
signer = Signature.getInstance(JsseJce.SIGNATURE_EDDSA);
464
break;
465
default:
466
throw new SignatureException("Unrecognized algorithm: "
467
+ algorithm);
468
}
469
470
if (signer != null) {
471
if (key instanceof PublicKey) {
472
signer.initVerify((PublicKey)(key));
473
} else {
474
signer.initSign((PrivateKey)key);
475
}
476
}
477
478
return signer;
479
}
480
}
481
482
/**
483
* The "CertificateVerify" handshake message producer.
484
*/
485
private static final
486
class T10CertificateVerifyProducer implements HandshakeProducer {
487
// Prevent instantiation of this class.
488
private T10CertificateVerifyProducer() {
489
// blank
490
}
491
492
@Override
493
public byte[] produce(ConnectionContext context,
494
HandshakeMessage message) throws IOException {
495
// The producing happens in client side only.
496
ClientHandshakeContext chc = (ClientHandshakeContext)context;
497
X509Possession x509Possession = null;
498
for (SSLPossession possession : chc.handshakePossessions) {
499
if (possession instanceof X509Possession) {
500
x509Possession = (X509Possession)possession;
501
break;
502
}
503
}
504
505
if (x509Possession == null ||
506
x509Possession.popPrivateKey == null) {
507
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
508
SSLLogger.fine(
509
"No X.509 credentials negotiated for CertificateVerify");
510
}
511
512
return null;
513
}
514
515
T10CertificateVerifyMessage cvm =
516
new T10CertificateVerifyMessage(chc, x509Possession);
517
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
518
SSLLogger.fine(
519
"Produced CertificateVerify handshake message", cvm);
520
}
521
522
// Output the handshake message.
523
cvm.write(chc.handshakeOutput);
524
chc.handshakeOutput.flush();
525
526
// The handshake message has been delivered.
527
return null;
528
}
529
}
530
531
/**
532
* The "CertificateVerify" handshake message consumer.
533
*/
534
private static final
535
class T10CertificateVerifyConsumer implements SSLConsumer {
536
// Prevent instantiation of this class.
537
private T10CertificateVerifyConsumer() {
538
// blank
539
}
540
541
@Override
542
public void consume(ConnectionContext context,
543
ByteBuffer message) throws IOException {
544
// The consuming happens in server side only.
545
ServerHandshakeContext shc = (ServerHandshakeContext)context;
546
547
// Clean up this consumer
548
shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
549
550
// Ensure that the CV message follows the CKE
551
if (shc.handshakeConsumers.containsKey(
552
SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
553
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
554
"Unexpected CertificateVerify handshake message");
555
}
556
557
T10CertificateVerifyMessage cvm =
558
new T10CertificateVerifyMessage(shc, message);
559
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
560
SSLLogger.fine(
561
"Consuming CertificateVerify handshake message", cvm);
562
}
563
564
//
565
// update
566
//
567
// Need no additional validation.
568
569
//
570
// produce
571
//
572
// Need no new handshake message producers here. }
573
}
574
}
575
576
/**
577
* The CertificateVerify handshake message (TLS 1.2).
578
*/
579
static final class T12CertificateVerifyMessage extends HandshakeMessage {
580
// the signature algorithm
581
private final SignatureScheme signatureScheme;
582
583
// signature bytes
584
private final byte[] signature;
585
586
T12CertificateVerifyMessage(HandshakeContext context,
587
X509Possession x509Possession) throws IOException {
588
super(context);
589
590
// This happens in client side only.
591
ClientHandshakeContext chc = (ClientHandshakeContext)context;
592
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
593
SignatureScheme.getSignerOfPreferableAlgorithm(
594
chc.algorithmConstraints,
595
chc.peerRequestedSignatureSchemes,
596
x509Possession,
597
chc.negotiatedProtocol);
598
if (schemeAndSigner == null) {
599
// Unlikely, the credentials generator should have
600
// selected the preferable signature algorithm properly.
601
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
602
"No supported CertificateVerify signature algorithm for " +
603
x509Possession.popPrivateKey.getAlgorithm() +
604
" key");
605
}
606
607
this.signatureScheme = schemeAndSigner.getKey();
608
byte[] temporary;
609
try {
610
Signature signer = schemeAndSigner.getValue();
611
signer.update(chc.handshakeHash.archived());
612
temporary = signer.sign();
613
} catch (SignatureException ikse) {
614
throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
615
"Cannot produce CertificateVerify signature", ikse);
616
}
617
618
this.signature = temporary;
619
}
620
621
T12CertificateVerifyMessage(HandshakeContext handshakeContext,
622
ByteBuffer m) throws IOException {
623
super(handshakeContext);
624
625
// This happens in server side only.
626
ServerHandshakeContext shc =
627
(ServerHandshakeContext)handshakeContext;
628
629
// struct {
630
// SignatureAndHashAlgorithm algorithm;
631
// opaque signature<0..2^16-1>;
632
// } DigitallySigned;
633
if (m.remaining() < 4) {
634
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
635
"Invalid CertificateVerify message: no sufficient data");
636
}
637
638
// SignatureAndHashAlgorithm algorithm
639
int ssid = Record.getInt16(m);
640
this.signatureScheme = SignatureScheme.valueOf(ssid);
641
if (signatureScheme == null) {
642
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
643
"Invalid signature algorithm (" + ssid +
644
") used in CertificateVerify handshake message");
645
}
646
647
if (!shc.localSupportedSignAlgs.contains(signatureScheme)) {
648
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
649
"Unsupported signature algorithm (" +
650
signatureScheme.name +
651
") used in CertificateVerify handshake message");
652
}
653
654
// read and verify the signature
655
X509Credentials x509Credentials = null;
656
for (SSLCredentials cd : shc.handshakeCredentials) {
657
if (cd instanceof X509Credentials) {
658
x509Credentials = (X509Credentials)cd;
659
break;
660
}
661
}
662
663
if (x509Credentials == null ||
664
x509Credentials.popPublicKey == null) {
665
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
666
"No X509 credentials negotiated for CertificateVerify");
667
}
668
669
// opaque signature<0..2^16-1>;
670
this.signature = Record.getBytes16(m);
671
try {
672
Signature signer =
673
signatureScheme.getVerifier(x509Credentials.popPublicKey);
674
signer.update(shc.handshakeHash.archived());
675
if (!signer.verify(signature)) {
676
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
677
"Invalid CertificateVerify signature");
678
}
679
} catch (NoSuchAlgorithmException |
680
InvalidAlgorithmParameterException nsae) {
681
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
682
"Unsupported signature algorithm (" +
683
signatureScheme.name +
684
") used in CertificateVerify handshake message", nsae);
685
} catch (InvalidKeyException | SignatureException ikse) {
686
throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
687
"Cannot verify CertificateVerify signature", ikse);
688
}
689
}
690
691
@Override
692
public SSLHandshake handshakeType() {
693
return SSLHandshake.CERTIFICATE_VERIFY;
694
}
695
696
@Override
697
public int messageLength() {
698
return 4 + signature.length; // 2: signature algorithm
699
// +2: length of signature
700
}
701
702
@Override
703
public void send(HandshakeOutStream hos) throws IOException {
704
hos.putInt16(signatureScheme.id);
705
hos.putBytes16(signature);
706
}
707
708
@Override
709
public String toString() {
710
MessageFormat messageFormat = new MessageFormat(
711
"\"CertificateVerify\": '{'\n" +
712
" \"signature algorithm\": {0}\n" +
713
" \"signature\": '{'\n" +
714
"{1}\n" +
715
" '}'\n" +
716
"'}'",
717
Locale.ENGLISH);
718
719
HexDumpEncoder hexEncoder = new HexDumpEncoder();
720
Object[] messageFields = {
721
signatureScheme.name,
722
Utilities.indent(
723
hexEncoder.encodeBuffer(signature), " ")
724
};
725
726
return messageFormat.format(messageFields);
727
}
728
}
729
730
/**
731
* The "CertificateVerify" handshake message producer.
732
*/
733
private static final
734
class T12CertificateVerifyProducer implements HandshakeProducer {
735
// Prevent instantiation of this class.
736
private T12CertificateVerifyProducer() {
737
// blank
738
}
739
740
@Override
741
public byte[] produce(ConnectionContext context,
742
HandshakeMessage message) throws IOException {
743
// The producing happens in client side only.
744
ClientHandshakeContext chc = (ClientHandshakeContext)context;
745
746
X509Possession x509Possession = null;
747
for (SSLPossession possession : chc.handshakePossessions) {
748
if (possession instanceof X509Possession) {
749
x509Possession = (X509Possession)possession;
750
break;
751
}
752
}
753
754
if (x509Possession == null ||
755
x509Possession.popPrivateKey == null) {
756
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
757
SSLLogger.fine(
758
"No X.509 credentials negotiated for CertificateVerify");
759
}
760
761
return null;
762
}
763
764
T12CertificateVerifyMessage cvm =
765
new T12CertificateVerifyMessage(chc, x509Possession);
766
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
767
SSLLogger.fine(
768
"Produced CertificateVerify handshake message", cvm);
769
}
770
771
// Output the handshake message.
772
cvm.write(chc.handshakeOutput);
773
chc.handshakeOutput.flush();
774
775
// The handshake message has been delivered.
776
return null;
777
}
778
}
779
780
/**
781
* The "CertificateVerify" handshake message consumer.
782
*/
783
private static final
784
class T12CertificateVerifyConsumer implements SSLConsumer {
785
// Prevent instantiation of this class.
786
private T12CertificateVerifyConsumer() {
787
// blank
788
}
789
790
@Override
791
public void consume(ConnectionContext context,
792
ByteBuffer message) throws IOException {
793
// The consuming happens in server side only.
794
ServerHandshakeContext shc = (ServerHandshakeContext)context;
795
796
// Clean up this consumer
797
shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
798
799
// Ensure that the CV message follows the CKE
800
if (shc.handshakeConsumers.containsKey(
801
SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
802
throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
803
"Unexpected CertificateVerify handshake message");
804
}
805
806
T12CertificateVerifyMessage cvm =
807
new T12CertificateVerifyMessage(shc, message);
808
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
809
SSLLogger.fine(
810
"Consuming CertificateVerify handshake message", cvm);
811
}
812
813
//
814
// update
815
//
816
// Need no additional validation.
817
818
//
819
// produce
820
//
821
// Need no new handshake message producers here.
822
}
823
}
824
825
/**
826
* The CertificateVerify handshake message (TLS 1.3).
827
*/
828
static final class T13CertificateVerifyMessage extends HandshakeMessage {
829
private static final byte[] serverSignHead = new byte[] {
830
// repeated 0x20 for 64 times
831
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
832
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
833
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
834
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
835
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
836
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
837
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
838
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
839
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
840
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
841
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
842
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
843
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
844
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
845
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
846
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
847
848
// "TLS 1.3, server CertificateVerify" + 0x00
849
(byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,
850
(byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,
851
(byte)0x20, (byte)0x73, (byte)0x65, (byte)0x72,
852
(byte)0x76, (byte)0x65, (byte)0x72, (byte)0x20,
853
(byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,
854
(byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,
855
(byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,
856
(byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,
857
(byte)0x79, (byte)0x00
858
};
859
860
private static final byte[] clientSignHead = new byte[] {
861
// repeated 0x20 for 64 times
862
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
863
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
864
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
865
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
866
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
867
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
868
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
869
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
870
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
871
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
872
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
873
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
874
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
875
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
876
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
877
(byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
878
879
// "TLS 1.3, client CertificateVerify" + 0x00
880
(byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,
881
(byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,
882
(byte)0x20, (byte)0x63, (byte)0x6c, (byte)0x69,
883
(byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x20,
884
(byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,
885
(byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,
886
(byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,
887
(byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,
888
(byte)0x79, (byte)0x00
889
};
890
891
892
// the signature algorithm
893
private final SignatureScheme signatureScheme;
894
895
// signature bytes
896
private final byte[] signature;
897
898
T13CertificateVerifyMessage(HandshakeContext context,
899
X509Possession x509Possession) throws IOException {
900
super(context);
901
902
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
903
SignatureScheme.getSignerOfPreferableAlgorithm(
904
context.algorithmConstraints,
905
context.peerRequestedSignatureSchemes,
906
x509Possession,
907
context.negotiatedProtocol);
908
if (schemeAndSigner == null) {
909
// Unlikely, the credentials generator should have
910
// selected the preferable signature algorithm properly.
911
throw context.conContext.fatal(Alert.INTERNAL_ERROR,
912
"No supported CertificateVerify signature algorithm for " +
913
x509Possession.popPrivateKey.getAlgorithm() +
914
" key");
915
}
916
917
this.signatureScheme = schemeAndSigner.getKey();
918
919
byte[] hashValue = context.handshakeHash.digest();
920
byte[] contentCovered;
921
if (context.sslConfig.isClientMode) {
922
contentCovered = Arrays.copyOf(clientSignHead,
923
clientSignHead.length + hashValue.length);
924
System.arraycopy(hashValue, 0, contentCovered,
925
clientSignHead.length, hashValue.length);
926
} else {
927
contentCovered = Arrays.copyOf(serverSignHead,
928
serverSignHead.length + hashValue.length);
929
System.arraycopy(hashValue, 0, contentCovered,
930
serverSignHead.length, hashValue.length);
931
}
932
933
byte[] temporary;
934
try {
935
Signature signer = schemeAndSigner.getValue();
936
signer.update(contentCovered);
937
temporary = signer.sign();
938
} catch (SignatureException ikse) {
939
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
940
"Cannot produce CertificateVerify signature", ikse);
941
}
942
943
this.signature = temporary;
944
}
945
946
T13CertificateVerifyMessage(HandshakeContext context,
947
ByteBuffer m) throws IOException {
948
super(context);
949
950
// struct {
951
// SignatureAndHashAlgorithm algorithm;
952
// opaque signature<0..2^16-1>;
953
// } DigitallySigned;
954
if (m.remaining() < 4) {
955
throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
956
"Invalid CertificateVerify message: no sufficient data");
957
}
958
959
// SignatureAndHashAlgorithm algorithm
960
int ssid = Record.getInt16(m);
961
this.signatureScheme = SignatureScheme.valueOf(ssid);
962
if (signatureScheme == null) {
963
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
964
"Invalid signature algorithm (" + ssid +
965
") used in CertificateVerify handshake message");
966
}
967
968
if (!context.localSupportedSignAlgs.contains(signatureScheme)) {
969
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
970
"Unsupported signature algorithm (" +
971
signatureScheme.name +
972
") used in CertificateVerify handshake message");
973
}
974
975
// read and verify the signature
976
X509Credentials x509Credentials = null;
977
for (SSLCredentials cd : context.handshakeCredentials) {
978
if (cd instanceof X509Credentials) {
979
x509Credentials = (X509Credentials)cd;
980
break;
981
}
982
}
983
984
if (x509Credentials == null ||
985
x509Credentials.popPublicKey == null) {
986
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
987
"No X509 credentials negotiated for CertificateVerify");
988
}
989
990
// opaque signature<0..2^16-1>;
991
this.signature = Record.getBytes16(m);
992
993
byte[] hashValue = context.handshakeHash.digest();
994
byte[] contentCovered;
995
if (context.sslConfig.isClientMode) {
996
contentCovered = Arrays.copyOf(serverSignHead,
997
serverSignHead.length + hashValue.length);
998
System.arraycopy(hashValue, 0, contentCovered,
999
serverSignHead.length, hashValue.length);
1000
} else {
1001
contentCovered = Arrays.copyOf(clientSignHead,
1002
clientSignHead.length + hashValue.length);
1003
System.arraycopy(hashValue, 0, contentCovered,
1004
clientSignHead.length, hashValue.length);
1005
}
1006
1007
try {
1008
Signature signer =
1009
signatureScheme.getVerifier(x509Credentials.popPublicKey);
1010
signer.update(contentCovered);
1011
if (!signer.verify(signature)) {
1012
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1013
"Invalid CertificateVerify signature");
1014
}
1015
} catch (NoSuchAlgorithmException |
1016
InvalidAlgorithmParameterException nsae) {
1017
throw context.conContext.fatal(Alert.INTERNAL_ERROR,
1018
"Unsupported signature algorithm (" +
1019
signatureScheme.name +
1020
") used in CertificateVerify handshake message", nsae);
1021
} catch (InvalidKeyException | SignatureException ikse) {
1022
throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1023
"Cannot verify CertificateVerify signature", ikse);
1024
}
1025
}
1026
1027
@Override
1028
public SSLHandshake handshakeType() {
1029
return SSLHandshake.CERTIFICATE_VERIFY;
1030
}
1031
1032
@Override
1033
public int messageLength() {
1034
return 4 + signature.length; // 2: signature algorithm
1035
// +2: length of signature
1036
}
1037
1038
@Override
1039
public void send(HandshakeOutStream hos) throws IOException {
1040
hos.putInt16(signatureScheme.id);
1041
hos.putBytes16(signature);
1042
}
1043
1044
@Override
1045
public String toString() {
1046
MessageFormat messageFormat = new MessageFormat(
1047
"\"CertificateVerify\": '{'\n" +
1048
" \"signature algorithm\": {0}\n" +
1049
" \"signature\": '{'\n" +
1050
"{1}\n" +
1051
" '}'\n" +
1052
"'}'",
1053
Locale.ENGLISH);
1054
1055
HexDumpEncoder hexEncoder = new HexDumpEncoder();
1056
Object[] messageFields = {
1057
signatureScheme.name,
1058
Utilities.indent(
1059
hexEncoder.encodeBuffer(signature), " ")
1060
};
1061
1062
return messageFormat.format(messageFields);
1063
}
1064
}
1065
1066
/**
1067
* The "CertificateVerify" handshake message producer.
1068
*/
1069
private static final
1070
class T13CertificateVerifyProducer implements HandshakeProducer {
1071
// Prevent instantiation of this class.
1072
private T13CertificateVerifyProducer() {
1073
// blank
1074
}
1075
1076
@Override
1077
public byte[] produce(ConnectionContext context,
1078
HandshakeMessage message) throws IOException {
1079
// The producing happens in handshake context only.
1080
HandshakeContext hc = (HandshakeContext)context;
1081
1082
X509Possession x509Possession = null;
1083
for (SSLPossession possession : hc.handshakePossessions) {
1084
if (possession instanceof X509Possession) {
1085
x509Possession = (X509Possession)possession;
1086
break;
1087
}
1088
}
1089
1090
if (x509Possession == null ||
1091
x509Possession.popPrivateKey == null) {
1092
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1093
SSLLogger.fine(
1094
"No X.509 credentials negotiated for CertificateVerify");
1095
}
1096
1097
return null;
1098
}
1099
1100
if (hc.sslConfig.isClientMode) {
1101
return onProduceCertificateVerify(
1102
(ClientHandshakeContext)context, x509Possession);
1103
} else {
1104
return onProduceCertificateVerify(
1105
(ServerHandshakeContext)context, x509Possession);
1106
}
1107
}
1108
1109
private byte[] onProduceCertificateVerify(ServerHandshakeContext shc,
1110
X509Possession x509Possession) throws IOException {
1111
T13CertificateVerifyMessage cvm =
1112
new T13CertificateVerifyMessage(shc, x509Possession);
1113
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1114
SSLLogger.fine(
1115
"Produced server CertificateVerify handshake message", cvm);
1116
}
1117
1118
// Output the handshake message.
1119
cvm.write(shc.handshakeOutput);
1120
shc.handshakeOutput.flush();
1121
1122
// The handshake message has been delivered.
1123
return null;
1124
}
1125
1126
private byte[] onProduceCertificateVerify(ClientHandshakeContext chc,
1127
X509Possession x509Possession) throws IOException {
1128
T13CertificateVerifyMessage cvm =
1129
new T13CertificateVerifyMessage(chc, x509Possession);
1130
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1131
SSLLogger.fine(
1132
"Produced client CertificateVerify handshake message", cvm);
1133
}
1134
1135
// Output the handshake message.
1136
cvm.write(chc.handshakeOutput);
1137
chc.handshakeOutput.flush();
1138
1139
// The handshake message has been delivered.
1140
return null;
1141
}
1142
}
1143
1144
/**
1145
* The "CertificateVerify" handshake message consumer.
1146
*/
1147
private static final
1148
class T13CertificateVerifyConsumer implements SSLConsumer {
1149
// Prevent instantiation of this class.
1150
private T13CertificateVerifyConsumer() {
1151
// blank
1152
}
1153
1154
@Override
1155
public void consume(ConnectionContext context,
1156
ByteBuffer message) throws IOException {
1157
// The producing happens in handshake context only.
1158
HandshakeContext hc = (HandshakeContext)context;
1159
1160
// Clean up this consumer
1161
hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
1162
1163
T13CertificateVerifyMessage cvm =
1164
new T13CertificateVerifyMessage(hc, message);
1165
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1166
SSLLogger.fine(
1167
"Consuming CertificateVerify handshake message", cvm);
1168
}
1169
1170
//
1171
// update
1172
//
1173
// Need no additional validation.
1174
1175
//
1176
// produce
1177
//
1178
// Need no new handshake message producers here.
1179
}
1180
}
1181
}
1182
1183