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.text.MessageFormat;
31 import java.util.Arrays;
32 import java.util.LinkedList;
33 import java.util.List;
34 import java.util.Locale;
35 import javax.net.ssl.SSLProtocolException;
36 import sun.security.ssl.SSLExtension.ExtensionConsumer;
37 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
38 import sun.security.ssl.SSLHandshake.HandshakeMessage;
39 
40 /**
41  * Pack of the "signature_algorithms" extensions [RFC 5246].
42  */
43 final class SignatureAlgorithmsExtension {
44     static final HandshakeProducer chNetworkProducer =
45             new CHSignatureSchemesProducer();
46     static final ExtensionConsumer chOnLoadConsumer =
47             new CHSignatureSchemesConsumer();
48     static final HandshakeAbsence chOnLoadAbsence =
49             new CHSignatureSchemesOnLoadAbsence();
50     static final HandshakeConsumer chOnTradeConsumer =
51             new CHSignatureSchemesUpdate();
52     static final HandshakeAbsence chOnTradeAbsence =
53             new CHSignatureSchemesOnTradeAbsence();
54 
55     static final HandshakeProducer crNetworkProducer =
56             new CRSignatureSchemesProducer();
57     static final ExtensionConsumer crOnLoadConsumer =
58             new CRSignatureSchemesConsumer();
59     static final HandshakeAbsence crOnLoadAbsence =
60             new CRSignatureSchemesAbsence();
61     static final HandshakeConsumer crOnTradeConsumer =
62             new CRSignatureSchemesUpdate();
63 
64     static final SSLStringizer ssStringizer =
65             new SignatureSchemesStringizer();
66 
67     /**
68      * The "signature_algorithms" extension.
69      */
70     static final class SignatureSchemesSpec implements SSLExtensionSpec {
71         final int[] signatureSchemes;
72 
SignatureSchemesSpec(List<SignatureScheme> schemes)73         SignatureSchemesSpec(List<SignatureScheme> schemes) {
74             if (schemes != null) {
75                 signatureSchemes = new int[schemes.size()];
76                 int i = 0;
77                 for (SignatureScheme scheme : schemes) {
78                     signatureSchemes[i++] = scheme.id;
79                 }
80             } else {
81                 this.signatureSchemes = new int[0];
82             }
83         }
84 
SignatureSchemesSpec(ByteBuffer buffer)85         SignatureSchemesSpec(ByteBuffer buffer) throws IOException {
86             if (buffer.remaining() < 2) {      // 2: the length of the list
87                 throw new SSLProtocolException(
88                     "Invalid signature_algorithms: insufficient data");
89             }
90 
91             byte[] algs = Record.getBytes16(buffer);
92             if (buffer.hasRemaining()) {
93                 throw new SSLProtocolException(
94                     "Invalid signature_algorithms: unknown extra data");
95             }
96 
97             if (algs == null || algs.length == 0 || (algs.length & 0x01) != 0) {
98                 throw new SSLProtocolException(
99                     "Invalid signature_algorithms: incomplete data");
100             }
101 
102             int[] schemes = new int[algs.length / 2];
103             for (int i = 0, j = 0; i < algs.length;) {
104                 byte hash = algs[i++];
105                 byte sign = algs[i++];
106                 schemes[j++] = ((hash & 0xFF) << 8) | (sign & 0xFF);
107             }
108 
109             this.signatureSchemes = schemes;
110         }
111 
112         @Override
toString()113         public String toString() {
114             MessageFormat messageFormat = new MessageFormat(
115                 "\"signature schemes\": '['{0}']'", Locale.ENGLISH);
116 
117             if (signatureSchemes == null || signatureSchemes.length == 0) {
118                 Object[] messageFields = {
119                         "<no supported signature schemes specified>"
120                     };
121                 return messageFormat.format(messageFields);
122             } else {
123                 StringBuilder builder = new StringBuilder(512);
124                 boolean isFirst = true;
125                 for (int pv : signatureSchemes) {
126                     if (isFirst) {
127                         isFirst = false;
128                     } else {
129                         builder.append(", ");
130                     }
131 
132                     builder.append(SignatureScheme.nameOf(pv));
133                 }
134 
135                 Object[] messageFields = {
136                         builder.toString()
137                     };
138 
139                 return messageFormat.format(messageFields);
140             }
141         }
142     }
143 
144     private static final
145             class SignatureSchemesStringizer implements SSLStringizer {
146         @Override
toString(ByteBuffer buffer)147         public String toString(ByteBuffer buffer) {
148             try {
149                 return (new SignatureSchemesSpec(buffer)).toString();
150             } catch (IOException ioe) {
151                 // For debug logging only, so please swallow exceptions.
152                 return ioe.getMessage();
153             }
154         }
155     }
156 
157     /**
158      * Network data producer of a "signature_algorithms" extension in
159      * the ClientHello handshake message.
160      */
161     private static final
162             class CHSignatureSchemesProducer implements HandshakeProducer {
163         // Prevent instantiation of this class.
CHSignatureSchemesProducer()164         private CHSignatureSchemesProducer() {
165             // blank
166         }
167 
168         @Override
produce(ConnectionContext context, HandshakeMessage message)169         public byte[] produce(ConnectionContext context,
170                 HandshakeMessage message) throws IOException {
171             // The producing happens in client side only.
172             ClientHandshakeContext chc = (ClientHandshakeContext)context;
173 
174             // Is it a supported and enabled extension?
175             if (!chc.sslConfig.isAvailable(
176                     SSLExtension.CH_SIGNATURE_ALGORITHMS)) {
177                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
178                     SSLLogger.fine(
179                         "Ignore unavailable signature_algorithms extension");
180                 }
181                 return null;
182             }
183 
184             // Produce the extension.
185             if (chc.localSupportedSignAlgs == null) {
186                 chc.localSupportedSignAlgs =
187                     SignatureScheme.getSupportedAlgorithms(
188                             chc.sslConfig,
189                             chc.algorithmConstraints, chc.activeProtocols);
190             }
191 
192             int vectorLen = SignatureScheme.sizeInRecord() *
193                     chc.localSupportedSignAlgs.size();
194             byte[] extData = new byte[vectorLen + 2];
195             ByteBuffer m = ByteBuffer.wrap(extData);
196             Record.putInt16(m, vectorLen);
197             for (SignatureScheme ss : chc.localSupportedSignAlgs) {
198                 Record.putInt16(m, ss.id);
199             }
200 
201             // Update the context.
202             chc.handshakeExtensions.put(
203                     SSLExtension.CH_SIGNATURE_ALGORITHMS,
204                     new SignatureSchemesSpec(chc.localSupportedSignAlgs));
205 
206             return extData;
207         }
208     }
209 
210     /**
211      * Network data consumer of a "signature_algorithms" extension in
212      * the ClientHello handshake message.
213      */
214     private static final
215             class CHSignatureSchemesConsumer implements ExtensionConsumer {
216         // Prevent instantiation of this class.
CHSignatureSchemesConsumer()217         private CHSignatureSchemesConsumer() {
218             // blank
219         }
220 
221         @Override
consume(ConnectionContext context, HandshakeMessage message, ByteBuffer buffer)222         public void consume(ConnectionContext context,
223             HandshakeMessage message, ByteBuffer buffer) throws IOException {
224             // The consuming happens in server side only.
225             ServerHandshakeContext shc = (ServerHandshakeContext)context;
226 
227             // Is it a supported and enabled extension?
228             if (!shc.sslConfig.isAvailable(
229                     SSLExtension.CH_SIGNATURE_ALGORITHMS)) {
230                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
231                     SSLLogger.fine(
232                         "Ignore unavailable signature_algorithms extension");
233                 }
234                 return;     // ignore the extension
235             }
236 
237             // Parse the extension.
238             SignatureSchemesSpec spec;
239             try {
240                 spec = new SignatureSchemesSpec(buffer);
241             } catch (IOException ioe) {
242                 throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
243             }
244 
245             // Update the context.
246             shc.handshakeExtensions.put(
247                     SSLExtension.CH_SIGNATURE_ALGORITHMS, spec);
248 
249             // No impact on session resumption.
250         }
251     }
252 
253     /**
254      * After session creation consuming of a "signature_algorithms"
255      * extension in the ClientHello handshake message.
256      */
257     private static final class CHSignatureSchemesUpdate
258             implements HandshakeConsumer {
259         // Prevent instantiation of this class.
CHSignatureSchemesUpdate()260         private CHSignatureSchemesUpdate() {
261             // blank
262         }
263 
264         @Override
consume(ConnectionContext context, HandshakeMessage message)265         public void consume(ConnectionContext context,
266                 HandshakeMessage message) throws IOException {
267             // The consuming happens in server side only.
268             ServerHandshakeContext shc = (ServerHandshakeContext)context;
269 
270             SignatureSchemesSpec spec =
271                     (SignatureSchemesSpec)shc.handshakeExtensions.get(
272                             SSLExtension.CH_SIGNATURE_ALGORITHMS);
273             if (spec == null) {
274                 // Ignore, no "signature_algorithms" extension requested.
275                 return;
276             }
277 
278             // update the context
279             List<SignatureScheme> sss =
280                     SignatureScheme.getSupportedAlgorithms(
281                             shc.sslConfig,
282                             shc.algorithmConstraints, shc.negotiatedProtocol,
283                             spec.signatureSchemes);
284             shc.peerRequestedSignatureSchemes = sss;
285 
286             // If no "signature_algorithms_cert" extension is present, then
287             // the "signature_algorithms" extension also applies to
288             // signatures appearing in certificates.
289             SignatureSchemesSpec certSpec =
290                     (SignatureSchemesSpec)shc.handshakeExtensions.get(
291                             SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT);
292             if (certSpec == null) {
293                 shc.peerRequestedCertSignSchemes = sss;
294                 shc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
295             }
296 
297             if (!shc.isResumption &&
298                     shc.negotiatedProtocol.useTLS13PlusSpec()) {
299                 if (shc.sslConfig.clientAuthType !=
300                         ClientAuthType.CLIENT_AUTH_NONE) {
301                     shc.handshakeProducers.putIfAbsent(
302                             SSLHandshake.CERTIFICATE_REQUEST.id,
303                             SSLHandshake.CERTIFICATE_REQUEST);
304                 }
305                 shc.handshakeProducers.put(
306                         SSLHandshake.CERTIFICATE.id,
307                         SSLHandshake.CERTIFICATE);
308                 shc.handshakeProducers.putIfAbsent(
309                         SSLHandshake.CERTIFICATE_VERIFY.id,
310                         SSLHandshake.CERTIFICATE_VERIFY);
311             }
312         }
313     }
314 
315     /**
316      * The absence processing if a "signature_algorithms" extension is
317      * not present in the ClientHello handshake message.
318      */
319     private static final
320             class CHSignatureSchemesOnLoadAbsence implements HandshakeAbsence {
321         @Override
absent(ConnectionContext context, HandshakeMessage message)322         public void absent(ConnectionContext context,
323                 HandshakeMessage message) throws IOException {
324             // The consuming happens in server side only.
325             ServerHandshakeContext shc = (ServerHandshakeContext)context;
326 
327             // This is a mandatory extension for certificate authentication
328             // in TLS 1.3.
329             //
330             // We may support the server authentication other than X.509
331             // certificate later.
332             if (shc.negotiatedProtocol.useTLS13PlusSpec()) {
333                 throw shc.conContext.fatal(Alert.MISSING_EXTENSION,
334                     "No mandatory signature_algorithms extension in the " +
335                     "received CertificateRequest handshake message");
336             }
337         }
338     }
339 
340     /**
341      * The absence processing if a "signature_algorithms" extension is
342      * not present in the ClientHello handshake message.
343      */
344     private static final
345             class CHSignatureSchemesOnTradeAbsence implements HandshakeAbsence {
346         @Override
absent(ConnectionContext context, HandshakeMessage message)347         public void absent(ConnectionContext context,
348                 HandshakeMessage message) throws IOException {
349             // The consuming happens in server side only.
350             ServerHandshakeContext shc = (ServerHandshakeContext)context;
351 
352             if (shc.negotiatedProtocol.useTLS12PlusSpec()) {
353                 // Use default hash and signature algorithm:
354                 //      {sha1,rsa}
355                 //      {sha1,dsa}
356                 //      {sha1,ecdsa}
357                 // Per RFC 5246, If the client supports only the default hash
358                 // and signature algorithms, it MAY omit the
359                 // signature_algorithms extension.  If the client does not
360                 // support the default algorithms, or supports other hash
361                 // and signature algorithms (and it is willing to use them
362                 // for verifying messages sent by the server, i.e., server
363                 // certificates and server key exchange), it MUST send the
364                 // signature_algorithms extension, listing the algorithms it
365                 // is willing to accept.
366                 List<SignatureScheme> schemes = Arrays.asList(
367                         SignatureScheme.RSA_PKCS1_SHA1,
368                         SignatureScheme.DSA_SHA1,
369                         SignatureScheme.ECDSA_SHA1
370                 );
371 
372                 shc.peerRequestedSignatureSchemes = schemes;
373                 if (shc.peerRequestedCertSignSchemes == null ||
374                         shc.peerRequestedCertSignSchemes.isEmpty()) {
375                     shc.peerRequestedCertSignSchemes = schemes;
376                 }
377 
378                 // Use the default peer signature algorithms.
379                 shc.handshakeSession.setUseDefaultPeerSignAlgs();
380             }
381         }
382     }
383 
384     /**
385      * Network data producer of a "signature_algorithms" extension in
386      * the CertificateRequest handshake message.
387      */
388     private static final
389             class CRSignatureSchemesProducer implements HandshakeProducer {
390         // Prevent instantiation of this class.
CRSignatureSchemesProducer()391         private CRSignatureSchemesProducer() {
392             // blank
393         }
394 
395         @Override
produce(ConnectionContext context, HandshakeMessage message)396         public byte[] produce(ConnectionContext context,
397                 HandshakeMessage message) throws IOException {
398             // The producing happens in server side only.
399             ServerHandshakeContext shc = (ServerHandshakeContext)context;
400 
401             // Is it a supported and enabled extension?
402             //
403             // Note that this is a mandatory extension for CertificateRequest
404             // handshake message in TLS 1.3.
405             if (!shc.sslConfig.isAvailable(
406                     SSLExtension.CR_SIGNATURE_ALGORITHMS)) {
407                 throw shc.conContext.fatal(Alert.MISSING_EXTENSION,
408                         "No available signature_algorithms extension " +
409                         "for client certificate authentication");
410             }
411 
412             // Produce the extension.
413             List<SignatureScheme> sigAlgs =
414                     SignatureScheme.getSupportedAlgorithms(
415                             shc.sslConfig,
416                             shc.algorithmConstraints,
417                             List.of(shc.negotiatedProtocol));
418 
419             int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size();
420             byte[] extData = new byte[vectorLen + 2];
421             ByteBuffer m = ByteBuffer.wrap(extData);
422             Record.putInt16(m, vectorLen);
423             for (SignatureScheme ss : sigAlgs) {
424                 Record.putInt16(m, ss.id);
425             }
426 
427             // Update the context.
428             shc.handshakeExtensions.put(
429                     SSLExtension.CR_SIGNATURE_ALGORITHMS,
430                     new SignatureSchemesSpec(shc.localSupportedSignAlgs));
431 
432             return extData;
433         }
434     }
435 
436     /**
437      * Network data consumer of a "signature_algorithms" extension in
438      * the CertificateRequest handshake message.
439      */
440     private static final
441             class CRSignatureSchemesConsumer implements ExtensionConsumer {
442         // Prevent instantiation of this class.
CRSignatureSchemesConsumer()443         private CRSignatureSchemesConsumer() {
444             // blank
445         }
446         @Override
consume(ConnectionContext context, HandshakeMessage message, ByteBuffer buffer)447         public void consume(ConnectionContext context,
448             HandshakeMessage message, ByteBuffer buffer) throws IOException {
449             // The consuming happens in client side only.
450             ClientHandshakeContext chc = (ClientHandshakeContext)context;
451 
452             // Is it a supported and enabled extension?
453             //
454             // Note that this is a mandatory extension for CertificateRequest
455             // handshake message in TLS 1.3.
456             if (!chc.sslConfig.isAvailable(
457                     SSLExtension.CR_SIGNATURE_ALGORITHMS)) {
458                 throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
459                         "No available signature_algorithms extension " +
460                         "for client certificate authentication");
461             }
462 
463             // Parse the extension.
464             SignatureSchemesSpec spec;
465             try {
466                 spec = new SignatureSchemesSpec(buffer);
467             } catch (IOException ioe) {
468                 throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
469             }
470 
471             List<SignatureScheme> knownSignatureSchemes = new LinkedList<>();
472             for (int id : spec.signatureSchemes) {
473                 SignatureScheme ss = SignatureScheme.valueOf(id);
474                 if (ss != null) {
475                     knownSignatureSchemes.add(ss);
476                 }
477             }
478 
479             // Update the context.
480             // chc.peerRequestedSignatureSchemes = knownSignatureSchemes;
481             chc.handshakeExtensions.put(
482                     SSLExtension.CR_SIGNATURE_ALGORITHMS, spec);
483 
484             // No impact on session resumption.
485         }
486     }
487 
488     /**
489      * After session creation consuming of a "signature_algorithms"
490      * extension in the CertificateRequest handshake message.
491      */
492     private static final class CRSignatureSchemesUpdate
493             implements HandshakeConsumer {
494         // Prevent instantiation of this class.
CRSignatureSchemesUpdate()495         private CRSignatureSchemesUpdate() {
496             // blank
497         }
498 
499         @Override
consume(ConnectionContext context, HandshakeMessage message)500         public void consume(ConnectionContext context,
501                 HandshakeMessage message) throws IOException {
502             // The consuming happens in client side only.
503             ClientHandshakeContext chc = (ClientHandshakeContext)context;
504 
505             SignatureSchemesSpec spec =
506                     (SignatureSchemesSpec)chc.handshakeExtensions.get(
507                             SSLExtension.CR_SIGNATURE_ALGORITHMS);
508             if (spec == null) {
509                 // Ignore, no "signature_algorithms" extension requested.
510                 return;
511             }
512 
513             // update the context
514             List<SignatureScheme> sss =
515                     SignatureScheme.getSupportedAlgorithms(
516                             chc.sslConfig,
517                             chc.algorithmConstraints, chc.negotiatedProtocol,
518                             spec.signatureSchemes);
519             chc.peerRequestedSignatureSchemes = sss;
520 
521             // If no "signature_algorithms_cert" extension is present, then
522             // the "signature_algorithms" extension also applies to
523             // signatures appearing in certificates.
524             SignatureSchemesSpec certSpec =
525                     (SignatureSchemesSpec)chc.handshakeExtensions.get(
526                             SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT);
527             if (certSpec == null) {
528                 chc.peerRequestedCertSignSchemes = sss;
529                 chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);
530             }
531         }
532     }
533 
534     /**
535      * The absence processing if a "signature_algorithms" extension is
536      * not present in the CertificateRequest handshake message.
537      */
538     private static final
539             class CRSignatureSchemesAbsence implements HandshakeAbsence {
540         @Override
absent(ConnectionContext context, HandshakeMessage message)541         public void absent(ConnectionContext context,
542                 HandshakeMessage message) throws IOException {
543             // The consuming happens in client side only.
544             ClientHandshakeContext chc = (ClientHandshakeContext)context;
545 
546             // This is a mandatory extension for CertificateRequest handshake
547             // message in TLS 1.3.
548             throw chc.conContext.fatal(Alert.MISSING_EXTENSION,
549                     "No mandatory signature_algorithms extension in the " +
550                     "received CertificateRequest handshake message");
551         }
552     }
553 }
554