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.*;
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[] temproary = null;
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                 temproary = 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 = temproary;
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 = null;
198             switch (algorithm) {
199                 case "RSA":
200                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA);
201                     break;
202                 case "DSA":
203                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
204                     break;
205                 case "EC":
206                     signer = JsseJce.getSignature(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[] temproary = null;
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                 temproary = 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 = temproary;
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 = null;
452             switch (algorithm) {
453                 case "RSA":
454                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA);
455                     break;
456                 case "DSA":
457                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA);
458                     break;
459                 case "EC":
460                     signer = JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA);
461                     break;
462                 default:
463                     throw new SignatureException("Unrecognized algorithm: "
464                         + algorithm);
465             }
466 
467             if (signer != null) {
468                 if (key instanceof PublicKey) {
469                     signer.initVerify((PublicKey)(key));
470                 } else {
471                     signer.initSign((PrivateKey)key);
472                 }
473             }
474 
475             return signer;
476         }
477     }
478 
479     /**
480      * The "CertificateVerify" handshake message producer.
481      */
482     private static final
483             class T10CertificateVerifyProducer implements HandshakeProducer {
484         // Prevent instantiation of this class.
T10CertificateVerifyProducer()485         private T10CertificateVerifyProducer() {
486             // blank
487         }
488 
489         @Override
produce(ConnectionContext context, HandshakeMessage message)490         public byte[] produce(ConnectionContext context,
491                 HandshakeMessage message) throws IOException {
492             // The producing happens in client side only.
493             ClientHandshakeContext chc = (ClientHandshakeContext)context;
494             X509Possession x509Possession = null;
495             for (SSLPossession possession : chc.handshakePossessions) {
496                 if (possession instanceof X509Possession) {
497                     x509Possession = (X509Possession)possession;
498                     break;
499                 }
500             }
501 
502             if (x509Possession == null ||
503                     x509Possession.popPrivateKey == null) {
504                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
505                     SSLLogger.fine(
506                         "No X.509 credentials negotiated for CertificateVerify");
507                 }
508 
509                 return null;
510             }
511 
512             T10CertificateVerifyMessage cvm =
513                     new T10CertificateVerifyMessage(chc, x509Possession);
514             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
515                 SSLLogger.fine(
516                         "Produced CertificateVerify handshake message", cvm);
517             }
518 
519             // Output the handshake message.
520             cvm.write(chc.handshakeOutput);
521             chc.handshakeOutput.flush();
522 
523             // The handshake message has been delivered.
524             return null;
525         }
526     }
527 
528     /**
529      * The "CertificateVerify" handshake message consumer.
530      */
531     private static final
532             class T10CertificateVerifyConsumer implements SSLConsumer {
533         // Prevent instantiation of this class.
T10CertificateVerifyConsumer()534         private T10CertificateVerifyConsumer() {
535             // blank
536         }
537 
538         @Override
consume(ConnectionContext context, ByteBuffer message)539         public void consume(ConnectionContext context,
540                 ByteBuffer message) throws IOException {
541             // The consuming happens in server side only.
542             ServerHandshakeContext shc = (ServerHandshakeContext)context;
543 
544             // Clean up this consumer
545             shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
546 
547             // Ensure that the CV message follows the CKE
548             if (shc.handshakeConsumers.containsKey(
549                     SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
550                 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
551                         "Unexpected CertificateVerify handshake message");
552             }
553 
554             T10CertificateVerifyMessage cvm =
555                     new T10CertificateVerifyMessage(shc, message);
556             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
557                 SSLLogger.fine(
558                         "Consuming CertificateVerify handshake message", cvm);
559             }
560 
561             //
562             // update
563             //
564             // Need no additional validation.
565 
566             //
567             // produce
568             //
569             // Need no new handshake message producers here.        }
570         }
571     }
572 
573     /**
574      * The CertificateVerify handshake message (TLS 1.2).
575      */
576     static final class T12CertificateVerifyMessage extends HandshakeMessage {
577         // the signature algorithm
578         private final SignatureScheme signatureScheme;
579 
580         // signature bytes
581         private final byte[] signature;
582 
T12CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)583         T12CertificateVerifyMessage(HandshakeContext context,
584                 X509Possession x509Possession) throws IOException {
585             super(context);
586 
587             // This happens in client side only.
588             ClientHandshakeContext chc = (ClientHandshakeContext)context;
589             Map.Entry<SignatureScheme, Signature> schemeAndSigner =
590                     SignatureScheme.getSignerOfPreferableAlgorithm(
591                     chc.algorithmConstraints,
592                     chc.peerRequestedSignatureSchemes,
593                     x509Possession,
594                     chc.negotiatedProtocol);
595             if (schemeAndSigner == null) {
596                 // Unlikely, the credentials generator should have
597                 // selected the preferable signature algorithm properly.
598                 throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
599                     "No supported CertificateVerify signature algorithm for " +
600                     x509Possession.popPrivateKey.getAlgorithm() +
601                     "  key");
602             }
603 
604             this.signatureScheme = schemeAndSigner.getKey();
605             byte[] temproary = null;
606             try {
607                 Signature signer = schemeAndSigner.getValue();
608                 signer.update(chc.handshakeHash.archived());
609                 temproary = signer.sign();
610             } catch (SignatureException ikse) {
611                 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
612                         "Cannot produce CertificateVerify signature", ikse);
613             }
614 
615             this.signature = temproary;
616         }
617 
T12CertificateVerifyMessage(HandshakeContext handshakeContext, ByteBuffer m)618         T12CertificateVerifyMessage(HandshakeContext handshakeContext,
619                 ByteBuffer m) throws IOException {
620             super(handshakeContext);
621 
622             // This happens in server side only.
623             ServerHandshakeContext shc =
624                     (ServerHandshakeContext)handshakeContext;
625 
626             // struct {
627             //     SignatureAndHashAlgorithm algorithm;
628             //     opaque signature<0..2^16-1>;
629             // } DigitallySigned;
630             if (m.remaining() < 4) {
631                 throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
632                     "Invalid CertificateVerify message: no sufficient data");
633             }
634 
635             // SignatureAndHashAlgorithm algorithm
636             int ssid = Record.getInt16(m);
637             this.signatureScheme = SignatureScheme.valueOf(ssid);
638             if (signatureScheme == null) {
639                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
640                         "Invalid signature algorithm (" + ssid +
641                         ") used in CertificateVerify handshake message");
642             }
643 
644             if (!shc.localSupportedSignAlgs.contains(signatureScheme)) {
645                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
646                         "Unsupported signature algorithm (" +
647                         signatureScheme.name +
648                         ") used in CertificateVerify handshake message");
649             }
650 
651             // read and verify the signature
652             X509Credentials x509Credentials = null;
653             for (SSLCredentials cd : shc.handshakeCredentials) {
654                 if (cd instanceof X509Credentials) {
655                     x509Credentials = (X509Credentials)cd;
656                     break;
657                 }
658             }
659 
660             if (x509Credentials == null ||
661                     x509Credentials.popPublicKey == null) {
662                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
663                     "No X509 credentials negotiated for CertificateVerify");
664             }
665 
666             // opaque signature<0..2^16-1>;
667             this.signature = Record.getBytes16(m);
668             try {
669                 Signature signer =
670                     signatureScheme.getVerifier(x509Credentials.popPublicKey);
671                 signer.update(shc.handshakeHash.archived());
672                 if (!signer.verify(signature)) {
673                     throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
674                         "Invalid CertificateVerify signature");
675                 }
676             } catch (NoSuchAlgorithmException |
677                     InvalidAlgorithmParameterException nsae) {
678                 throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
679                         "Unsupported signature algorithm (" +
680                         signatureScheme.name +
681                         ") used in CertificateVerify handshake message", nsae);
682             } catch (InvalidKeyException | SignatureException ikse) {
683                 throw shc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
684                         "Cannot verify CertificateVerify signature", ikse);
685             }
686         }
687 
688         @Override
handshakeType()689         public SSLHandshake handshakeType() {
690             return SSLHandshake.CERTIFICATE_VERIFY;
691         }
692 
693         @Override
messageLength()694         public int messageLength() {
695             return 4 + signature.length;    //  2: signature algorithm
696                                             // +2: length of signature
697         }
698 
699         @Override
send(HandshakeOutStream hos)700         public void send(HandshakeOutStream hos) throws IOException {
701             hos.putInt16(signatureScheme.id);
702             hos.putBytes16(signature);
703         }
704 
705         @Override
toString()706         public String toString() {
707             MessageFormat messageFormat = new MessageFormat(
708                     "\"CertificateVerify\": '{'\n" +
709                     "  \"signature algorithm\": {0}\n" +
710                     "  \"signature\": '{'\n" +
711                     "{1}\n" +
712                     "  '}'\n" +
713                     "'}'",
714                     Locale.ENGLISH);
715 
716             HexDumpEncoder hexEncoder = new HexDumpEncoder();
717             Object[] messageFields = {
718                 signatureScheme.name,
719                 Utilities.indent(
720                         hexEncoder.encodeBuffer(signature), "    ")
721             };
722 
723             return messageFormat.format(messageFields);
724         }
725     }
726 
727     /**
728      * The "CertificateVerify" handshake message producer.
729      */
730     private static final
731             class T12CertificateVerifyProducer implements HandshakeProducer {
732         // Prevent instantiation of this class.
T12CertificateVerifyProducer()733         private T12CertificateVerifyProducer() {
734             // blank
735         }
736 
737         @Override
produce(ConnectionContext context, HandshakeMessage message)738         public byte[] produce(ConnectionContext context,
739                 HandshakeMessage message) throws IOException {
740             // The producing happens in client side only.
741             ClientHandshakeContext chc = (ClientHandshakeContext)context;
742 
743             X509Possession x509Possession = null;
744             for (SSLPossession possession : chc.handshakePossessions) {
745                 if (possession instanceof X509Possession) {
746                     x509Possession = (X509Possession)possession;
747                     break;
748                 }
749             }
750 
751             if (x509Possession == null ||
752                     x509Possession.popPrivateKey == null) {
753                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
754                     SSLLogger.fine(
755                         "No X.509 credentials negotiated for CertificateVerify");
756                 }
757 
758                 return null;
759             }
760 
761             T12CertificateVerifyMessage cvm =
762                     new T12CertificateVerifyMessage(chc, x509Possession);
763             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
764                 SSLLogger.fine(
765                         "Produced CertificateVerify handshake message", cvm);
766             }
767 
768             // Output the handshake message.
769             cvm.write(chc.handshakeOutput);
770             chc.handshakeOutput.flush();
771 
772             // The handshake message has been delivered.
773             return null;
774         }
775     }
776 
777     /**
778      * The "CertificateVerify" handshake message consumer.
779      */
780     private static final
781             class T12CertificateVerifyConsumer implements SSLConsumer {
782         // Prevent instantiation of this class.
T12CertificateVerifyConsumer()783         private T12CertificateVerifyConsumer() {
784             // blank
785         }
786 
787         @Override
consume(ConnectionContext context, ByteBuffer message)788         public void consume(ConnectionContext context,
789                 ByteBuffer message) throws IOException {
790             // The consuming happens in server side only.
791             ServerHandshakeContext shc = (ServerHandshakeContext)context;
792 
793             // Clean up this consumer
794             shc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
795 
796             // Ensure that the CV message follows the CKE
797             if (shc.handshakeConsumers.containsKey(
798                     SSLHandshake.CLIENT_KEY_EXCHANGE.id)) {
799                 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
800                         "Unexpected CertificateVerify handshake message");
801             }
802 
803             T12CertificateVerifyMessage cvm =
804                     new T12CertificateVerifyMessage(shc, message);
805             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
806                 SSLLogger.fine(
807                         "Consuming CertificateVerify handshake message", cvm);
808             }
809 
810             //
811             // update
812             //
813             // Need no additional validation.
814 
815             //
816             // produce
817             //
818             // Need no new handshake message producers here.
819         }
820     }
821 
822     /**
823      * The CertificateVerify handshake message (TLS 1.3).
824      */
825     static final class T13CertificateVerifyMessage extends HandshakeMessage {
826         private static final byte[] serverSignHead = new byte[] {
827             // repeated 0x20 for 64 times
828             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
829             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
830             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
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 
845             // "TLS 1.3, server CertificateVerify" + 0x00
846             (byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,
847             (byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,
848             (byte)0x20, (byte)0x73, (byte)0x65, (byte)0x72,
849             (byte)0x76, (byte)0x65, (byte)0x72, (byte)0x20,
850             (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,
851             (byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,
852             (byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,
853             (byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,
854             (byte)0x79, (byte)0x00
855         };
856 
857         private static final byte[] clientSignHead = new byte[] {
858             // repeated 0x20 for 64 times
859             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
860             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
861             (byte)0x20, (byte)0x20, (byte)0x20, (byte)0x20,
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 
876             // "TLS 1.3, client CertificateVerify" + 0x00
877             (byte)0x54, (byte)0x4c, (byte)0x53, (byte)0x20,
878             (byte)0x31, (byte)0x2e, (byte)0x33, (byte)0x2c,
879             (byte)0x20, (byte)0x63, (byte)0x6c, (byte)0x69,
880             (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x20,
881             (byte)0x43, (byte)0x65, (byte)0x72, (byte)0x74,
882             (byte)0x69, (byte)0x66, (byte)0x69, (byte)0x63,
883             (byte)0x61, (byte)0x74, (byte)0x65, (byte)0x56,
884             (byte)0x65, (byte)0x72, (byte)0x69, (byte)0x66,
885             (byte)0x79, (byte)0x00
886         };
887 
888 
889         // the signature algorithm
890         private final SignatureScheme signatureScheme;
891 
892         // signature bytes
893         private final byte[] signature;
894 
T13CertificateVerifyMessage(HandshakeContext context, X509Possession x509Possession)895         T13CertificateVerifyMessage(HandshakeContext context,
896                 X509Possession x509Possession) throws IOException {
897             super(context);
898 
899             Map.Entry<SignatureScheme, Signature> schemeAndSigner =
900                      SignatureScheme.getSignerOfPreferableAlgorithm(
901                      context.algorithmConstraints,
902                      context.peerRequestedSignatureSchemes,
903                      x509Possession,
904                      context.negotiatedProtocol);
905             if (schemeAndSigner == null) {
906                 // Unlikely, the credentials generator should have
907                 // selected the preferable signature algorithm properly.
908                 throw context.conContext.fatal(Alert.INTERNAL_ERROR,
909                     "No supported CertificateVerify signature algorithm for " +
910                     x509Possession.popPrivateKey.getAlgorithm() +
911                     "  key");
912             }
913 
914             this.signatureScheme = schemeAndSigner.getKey();
915 
916             byte[] hashValue = context.handshakeHash.digest();
917             byte[] contentCovered;
918             if (context.sslConfig.isClientMode) {
919                 contentCovered = Arrays.copyOf(clientSignHead,
920                         clientSignHead.length + hashValue.length);
921                 System.arraycopy(hashValue, 0, contentCovered,
922                         clientSignHead.length, hashValue.length);
923             } else {
924                 contentCovered = Arrays.copyOf(serverSignHead,
925                         serverSignHead.length + hashValue.length);
926                 System.arraycopy(hashValue, 0, contentCovered,
927                         serverSignHead.length, hashValue.length);
928             }
929 
930             byte[] temproary = null;
931             try {
932                 Signature signer = schemeAndSigner.getValue();
933                 signer.update(contentCovered);
934                 temproary = signer.sign();
935             } catch (SignatureException ikse) {
936                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
937                         "Cannot produce CertificateVerify signature", ikse);
938             }
939 
940             this.signature = temproary;
941         }
942 
T13CertificateVerifyMessage(HandshakeContext context, ByteBuffer m)943         T13CertificateVerifyMessage(HandshakeContext context,
944                 ByteBuffer m) throws IOException {
945              super(context);
946 
947             // struct {
948             //     SignatureAndHashAlgorithm algorithm;
949             //     opaque signature<0..2^16-1>;
950             // } DigitallySigned;
951             if (m.remaining() < 4) {
952                 throw context.conContext.fatal(Alert.ILLEGAL_PARAMETER,
953                     "Invalid CertificateVerify message: no sufficient data");
954             }
955 
956             // SignatureAndHashAlgorithm algorithm
957             int ssid = Record.getInt16(m);
958             this.signatureScheme = SignatureScheme.valueOf(ssid);
959             if (signatureScheme == null) {
960                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
961                         "Invalid signature algorithm (" + ssid +
962                         ") used in CertificateVerify handshake message");
963             }
964 
965             if (!context.localSupportedSignAlgs.contains(signatureScheme)) {
966                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
967                         "Unsupported signature algorithm (" +
968                         signatureScheme.name +
969                         ") used in CertificateVerify handshake message");
970             }
971 
972             // read and verify the signature
973             X509Credentials x509Credentials = null;
974             for (SSLCredentials cd : context.handshakeCredentials) {
975                 if (cd instanceof X509Credentials) {
976                     x509Credentials = (X509Credentials)cd;
977                     break;
978                 }
979             }
980 
981             if (x509Credentials == null ||
982                     x509Credentials.popPublicKey == null) {
983                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
984                     "No X509 credentials negotiated for CertificateVerify");
985             }
986 
987             // opaque signature<0..2^16-1>;
988             this.signature = Record.getBytes16(m);
989 
990             byte[] hashValue = context.handshakeHash.digest();
991             byte[] contentCovered;
992             if (context.sslConfig.isClientMode) {
993                 contentCovered = Arrays.copyOf(serverSignHead,
994                         serverSignHead.length + hashValue.length);
995                 System.arraycopy(hashValue, 0, contentCovered,
996                         serverSignHead.length, hashValue.length);
997             } else {
998                 contentCovered = Arrays.copyOf(clientSignHead,
999                         clientSignHead.length + hashValue.length);
1000                 System.arraycopy(hashValue, 0, contentCovered,
1001                         clientSignHead.length, hashValue.length);
1002             }
1003 
1004             try {
1005                 Signature signer =
1006                     signatureScheme.getVerifier(x509Credentials.popPublicKey);
1007                 signer.update(contentCovered);
1008                 if (!signer.verify(signature)) {
1009                     throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1010                         "Invalid CertificateVerify signature");
1011                 }
1012             } catch (NoSuchAlgorithmException |
1013                     InvalidAlgorithmParameterException nsae) {
1014                 throw context.conContext.fatal(Alert.INTERNAL_ERROR,
1015                         "Unsupported signature algorithm (" +
1016                         signatureScheme.name +
1017                         ") used in CertificateVerify handshake message", nsae);
1018             } catch (InvalidKeyException | SignatureException ikse) {
1019                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
1020                         "Cannot verify CertificateVerify signature", ikse);
1021             }
1022         }
1023 
1024         @Override
handshakeType()1025         public SSLHandshake handshakeType() {
1026             return SSLHandshake.CERTIFICATE_VERIFY;
1027         }
1028 
1029         @Override
messageLength()1030         public int messageLength() {
1031             return 4 + signature.length;    //  2: signature algorithm
1032                                             // +2: length of signature
1033         }
1034 
1035         @Override
send(HandshakeOutStream hos)1036         public void send(HandshakeOutStream hos) throws IOException {
1037             hos.putInt16(signatureScheme.id);
1038             hos.putBytes16(signature);
1039         }
1040 
1041         @Override
toString()1042         public String toString() {
1043             MessageFormat messageFormat = new MessageFormat(
1044                     "\"CertificateVerify\": '{'\n" +
1045                     "  \"signature algorithm\": {0}\n" +
1046                     "  \"signature\": '{'\n" +
1047                     "{1}\n" +
1048                     "  '}'\n" +
1049                     "'}'",
1050                     Locale.ENGLISH);
1051 
1052             HexDumpEncoder hexEncoder = new HexDumpEncoder();
1053             Object[] messageFields = {
1054                 signatureScheme.name,
1055                 Utilities.indent(
1056                         hexEncoder.encodeBuffer(signature), "    ")
1057             };
1058 
1059             return messageFormat.format(messageFields);
1060         }
1061     }
1062 
1063     /**
1064      * The "CertificateVerify" handshake message producer.
1065      */
1066     private static final
1067             class T13CertificateVerifyProducer implements HandshakeProducer {
1068         // Prevent instantiation of this class.
T13CertificateVerifyProducer()1069         private T13CertificateVerifyProducer() {
1070             // blank
1071         }
1072 
1073         @Override
produce(ConnectionContext context, HandshakeMessage message)1074         public byte[] produce(ConnectionContext context,
1075                 HandshakeMessage message) throws IOException {
1076             // The producing happens in handshake context only.
1077             HandshakeContext hc = (HandshakeContext)context;
1078 
1079             X509Possession x509Possession = null;
1080             for (SSLPossession possession : hc.handshakePossessions) {
1081                 if (possession instanceof X509Possession) {
1082                     x509Possession = (X509Possession)possession;
1083                     break;
1084                 }
1085             }
1086 
1087             if (x509Possession == null ||
1088                     x509Possession.popPrivateKey == null) {
1089                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1090                     SSLLogger.fine(
1091                         "No X.509 credentials negotiated for CertificateVerify");
1092                 }
1093 
1094                 return null;
1095             }
1096 
1097             if (hc.sslConfig.isClientMode) {
1098                 return onProduceCertificateVerify(
1099                         (ClientHandshakeContext)context, x509Possession);
1100             } else {
1101                 return onProduceCertificateVerify(
1102                         (ServerHandshakeContext)context, x509Possession);
1103             }
1104         }
1105 
onProduceCertificateVerify(ServerHandshakeContext shc, X509Possession x509Possession)1106         private byte[] onProduceCertificateVerify(ServerHandshakeContext shc,
1107                 X509Possession x509Possession) throws IOException {
1108             T13CertificateVerifyMessage cvm =
1109                     new T13CertificateVerifyMessage(shc, x509Possession);
1110             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1111                 SSLLogger.fine(
1112                     "Produced server CertificateVerify handshake message", cvm);
1113             }
1114 
1115             // Output the handshake message.
1116             cvm.write(shc.handshakeOutput);
1117             shc.handshakeOutput.flush();
1118 
1119             // The handshake message has been delivered.
1120             return null;
1121         }
1122 
onProduceCertificateVerify(ClientHandshakeContext chc, X509Possession x509Possession)1123         private byte[] onProduceCertificateVerify(ClientHandshakeContext chc,
1124                 X509Possession x509Possession) throws IOException {
1125             T13CertificateVerifyMessage cvm =
1126                     new T13CertificateVerifyMessage(chc, x509Possession);
1127             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1128                 SSLLogger.fine(
1129                     "Produced client CertificateVerify handshake message", cvm);
1130             }
1131 
1132             // Output the handshake message.
1133             cvm.write(chc.handshakeOutput);
1134             chc.handshakeOutput.flush();
1135 
1136             // The handshake message has been delivered.
1137             return null;
1138         }
1139     }
1140 
1141     /**
1142      * The "CertificateVerify" handshake message consumer.
1143      */
1144     private static final
1145             class T13CertificateVerifyConsumer implements SSLConsumer {
1146         // Prevent instantiation of this class.
T13CertificateVerifyConsumer()1147         private T13CertificateVerifyConsumer() {
1148             // blank
1149         }
1150 
1151         @Override
consume(ConnectionContext context, ByteBuffer message)1152         public void consume(ConnectionContext context,
1153                 ByteBuffer message) throws IOException {
1154             // The producing happens in handshake context only.
1155             HandshakeContext hc = (HandshakeContext)context;
1156 
1157             // Clean up this consumer
1158             hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_VERIFY.id);
1159 
1160             T13CertificateVerifyMessage cvm =
1161                     new T13CertificateVerifyMessage(hc, message);
1162             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
1163                 SSLLogger.fine(
1164                         "Consuming CertificateVerify handshake message", cvm);
1165             }
1166 
1167             //
1168             // update
1169             //
1170             // Need no additional validation.
1171 
1172             //
1173             // produce
1174             //
1175             // Need no new handshake message producers here.
1176         }
1177     }
1178 }
1179