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 
S30CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)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 
S30CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)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
handshakeType()158         public SSLHandshake handshakeType() {
159             return SSLHandshake.CERTIFICATE_VERIFY;
160         }
161 
162         @Override
messageLength()163         public int messageLength() {
164             return 2 + signature.length;    //  2: length of signature
165         }
166 
167         @Override
send(HandshakeOutStream hos)168         public void send(HandshakeOutStream hos) throws IOException {
169             hos.putBytes16(signature);
170         }
171 
172         @Override
toString()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          */
getSignature(String algorithm, Key key)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.
S30CertificateVerifyProducer()231         private S30CertificateVerifyProducer() {
232             // blank
233         }
234 
235         @Override
produce(ConnectionContext context, HandshakeMessage message)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.
S30CertificateVerifyConsumer()281         private S30CertificateVerifyConsumer() {
282             // blank
283         }
284 
285         @Override
consume(ConnectionContext context, ByteBuffer message)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 
T10CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)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 
T10CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)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
handshakeType()412         public SSLHandshake handshakeType() {
413             return SSLHandshake.CERTIFICATE_VERIFY;
414         }
415 
416         @Override
messageLength()417         public int messageLength() {
418             return 2 + signature.length;    //  2: length of signature
419         }
420 
421         @Override
send(HandshakeOutStream hos)422         public void send(HandshakeOutStream hos) throws IOException {
423             hos.putBytes16(signature);
424         }
425 
426         @Override
toString()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          */
getSignature(String algorithm, Key key)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.
T10CertificateVerifyProducer()488         private T10CertificateVerifyProducer() {
489             // blank
490         }
491 
492         @Override
produce(ConnectionContext context, HandshakeMessage message)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.
T10CertificateVerifyConsumer()537         private T10CertificateVerifyConsumer() {
538             // blank
539         }
540 
541         @Override
consume(ConnectionContext context, ByteBuffer message)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 
T12CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)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 
T12CertificateVerifyMessage(HandshakeContext handshakeContext, ByteBuffer m)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
handshakeType()692         public SSLHandshake handshakeType() {
693             return SSLHandshake.CERTIFICATE_VERIFY;
694         }
695 
696         @Override
messageLength()697         public int messageLength() {
698             return 4 + signature.length;    //  2: signature algorithm
699                                             // +2: length of signature
700         }
701 
702         @Override
send(HandshakeOutStream hos)703         public void send(HandshakeOutStream hos) throws IOException {
704             hos.putInt16(signatureScheme.id);
705             hos.putBytes16(signature);
706         }
707 
708         @Override
toString()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.
T12CertificateVerifyProducer()736         private T12CertificateVerifyProducer() {
737             // blank
738         }
739 
740         @Override
produce(ConnectionContext context, HandshakeMessage message)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.
T12CertificateVerifyConsumer()786         private T12CertificateVerifyConsumer() {
787             // blank
788         }
789 
790         @Override
consume(ConnectionContext context, ByteBuffer message)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 
T13CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)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 
T13CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)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
handshakeType()1028         public SSLHandshake handshakeType() {
1029             return SSLHandshake.CERTIFICATE_VERIFY;
1030         }
1031 
1032         @Override
messageLength()1033         public int messageLength() {
1034             return 4 + signature.length;    //  2: signature algorithm
1035                                             // +2: length of signature
1036         }
1037 
1038         @Override
send(HandshakeOutStream hos)1039         public void send(HandshakeOutStream hos) throws IOException {
1040             hos.putInt16(signatureScheme.id);
1041             hos.putBytes16(signature);
1042         }
1043 
1044         @Override
toString()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.
T13CertificateVerifyProducer()1072         private T13CertificateVerifyProducer() {
1073             // blank
1074         }
1075 
1076         @Override
produce(ConnectionContext context, HandshakeMessage message)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 
onProduceCertificateVerify(ServerHandshakeContext shc, X509Possession x509Possession)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 
onProduceCertificateVerify(ClientHandshakeContext chc, X509Possession x509Possession)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.
T13CertificateVerifyConsumer()1150         private T13CertificateVerifyConsumer() {
1151             // blank
1152         }
1153 
1154         @Override
consume(ConnectionContext context, ByteBuffer message)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