| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.ssl;  | 
 | 
 | 
 | 
import java.io.IOException;  | 
 | 
import java.nio.ByteBuffer;  | 
 | 
import java.text.MessageFormat;  | 
 | 
import java.util.Arrays;  | 
 | 
import java.util.Collections;  | 
 | 
import java.util.LinkedList;  | 
 | 
import java.util.List;  | 
 | 
import java.util.Locale;  | 
 | 
import javax.net.ssl.SSLProtocolException;  | 
 | 
import sun.security.ssl.SSLExtension.ExtensionConsumer;  | 
 | 
import sun.security.ssl.SSLExtension.SSLExtensionSpec;  | 
 | 
import sun.security.ssl.SSLHandshake.HandshakeMessage;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class SignatureAlgorithmsExtension { | 
 | 
    static final HandshakeProducer chNetworkProducer =  | 
 | 
            new CHSignatureSchemesProducer();  | 
 | 
    static final ExtensionConsumer chOnLoadConsumer =  | 
 | 
            new CHSignatureSchemesConsumer();  | 
 | 
    static final HandshakeAbsence chOnLoadAbsence =  | 
 | 
            new CHSignatureSchemesOnLoadAbsence();  | 
 | 
    static final HandshakeConsumer chOnTradeConsumer =  | 
 | 
            new CHSignatureSchemesUpdate();  | 
 | 
    static final HandshakeAbsence chOnTradeAbsence =  | 
 | 
            new CHSignatureSchemesOnTradeAbsence();  | 
 | 
 | 
 | 
    static final HandshakeProducer crNetworkProducer =  | 
 | 
            new CRSignatureSchemesProducer();  | 
 | 
    static final ExtensionConsumer crOnLoadConsumer =  | 
 | 
            new CRSignatureSchemesConsumer();  | 
 | 
    static final HandshakeAbsence crOnLoadAbsence =  | 
 | 
            new CRSignatureSchemesAbsence();  | 
 | 
    static final HandshakeConsumer crOnTradeConsumer =  | 
 | 
            new CRSignatureSchemesUpdate();  | 
 | 
 | 
 | 
    static final SSLStringizer ssStringizer =  | 
 | 
            new SignatureSchemesStringizer();  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static final class SignatureSchemesSpec implements SSLExtensionSpec { | 
 | 
        final int[] signatureSchemes;  | 
 | 
 | 
 | 
        SignatureSchemesSpec(List<SignatureScheme> schemes) { | 
 | 
            if (schemes != null) { | 
 | 
                signatureSchemes = new int[schemes.size()];  | 
 | 
                int i = 0;  | 
 | 
                for (SignatureScheme scheme : schemes) { | 
 | 
                    signatureSchemes[i++] = scheme.id;  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                this.signatureSchemes = new int[0];  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        SignatureSchemesSpec(ByteBuffer buffer) throws IOException { | 
 | 
            if (buffer.remaining() < 2) {       | 
 | 
                throw new SSLProtocolException(  | 
 | 
                    "Invalid signature_algorithms: insufficient data");  | 
 | 
            }  | 
 | 
 | 
 | 
            byte[] algs = Record.getBytes16(buffer);  | 
 | 
            if (buffer.hasRemaining()) { | 
 | 
                throw new SSLProtocolException(  | 
 | 
                    "Invalid signature_algorithms: unknown extra data");  | 
 | 
            }  | 
 | 
 | 
 | 
            if (algs == null || algs.length == 0 || (algs.length & 0x01) != 0) { | 
 | 
                throw new SSLProtocolException(  | 
 | 
                    "Invalid signature_algorithms: incomplete data");  | 
 | 
            }  | 
 | 
 | 
 | 
            int[] schemes = new int[algs.length / 2];  | 
 | 
            for (int i = 0, j = 0; i < algs.length;) { | 
 | 
                byte hash = algs[i++];  | 
 | 
                byte sign = algs[i++];  | 
 | 
                schemes[j++] = ((hash & 0xFF) << 8) | (sign & 0xFF);  | 
 | 
            }  | 
 | 
 | 
 | 
            this.signatureSchemes = schemes;  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public String toString() { | 
 | 
            MessageFormat messageFormat = new MessageFormat(  | 
 | 
                "\"signature schemes\": '['{0}']'", Locale.ENGLISH); | 
 | 
 | 
 | 
            if (signatureSchemes == null || signatureSchemes.length == 0) { | 
 | 
                Object[] messageFields = { | 
 | 
                        "<no supported signature schemes specified>"  | 
 | 
                    };  | 
 | 
                return messageFormat.format(messageFields);  | 
 | 
            } else { | 
 | 
                StringBuilder builder = new StringBuilder(512);  | 
 | 
                boolean isFirst = true;  | 
 | 
                for (int pv : signatureSchemes) { | 
 | 
                    if (isFirst) { | 
 | 
                        isFirst = false;  | 
 | 
                    } else { | 
 | 
                        builder.append(", "); | 
 | 
                    }  | 
 | 
 | 
 | 
                    builder.append(SignatureScheme.nameOf(pv));  | 
 | 
                }  | 
 | 
 | 
 | 
                Object[] messageFields = { | 
 | 
                        builder.toString()  | 
 | 
                    };  | 
 | 
 | 
 | 
                return messageFormat.format(messageFields);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final  | 
 | 
            class SignatureSchemesStringizer implements SSLStringizer { | 
 | 
        @Override  | 
 | 
        public String toString(ByteBuffer buffer) { | 
 | 
            try { | 
 | 
                return (new SignatureSchemesSpec(buffer)).toString();  | 
 | 
            } catch (IOException ioe) { | 
 | 
                  | 
 | 
                return ioe.getMessage();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CHSignatureSchemesProducer implements HandshakeProducer { | 
 | 
          | 
 | 
        private CHSignatureSchemesProducer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public byte[] produce(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            if (!chc.sslConfig.isAvailable(  | 
 | 
                    SSLExtension.CH_SIGNATURE_ALGORITHMS)) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.fine(  | 
 | 
                        "Ignore unavailable signature_algorithms extension");  | 
 | 
                }  | 
 | 
                return null;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            if (chc.localSupportedSignAlgs == null) { | 
 | 
                chc.localSupportedSignAlgs =  | 
 | 
                    SignatureScheme.getSupportedAlgorithms(  | 
 | 
                            chc.sslConfig,  | 
 | 
                            chc.algorithmConstraints, chc.activeProtocols);  | 
 | 
            }  | 
 | 
 | 
 | 
            int vectorLen = SignatureScheme.sizeInRecord() *  | 
 | 
                    chc.localSupportedSignAlgs.size();  | 
 | 
            byte[] extData = new byte[vectorLen + 2];  | 
 | 
            ByteBuffer m = ByteBuffer.wrap(extData);  | 
 | 
            Record.putInt16(m, vectorLen);  | 
 | 
            for (SignatureScheme ss : chc.localSupportedSignAlgs) { | 
 | 
                Record.putInt16(m, ss.id);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            chc.handshakeExtensions.put(  | 
 | 
                    SSLExtension.CH_SIGNATURE_ALGORITHMS,  | 
 | 
                    new SignatureSchemesSpec(chc.localSupportedSignAlgs));  | 
 | 
 | 
 | 
            return extData;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CHSignatureSchemesConsumer implements ExtensionConsumer { | 
 | 
          | 
 | 
        private CHSignatureSchemesConsumer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
            HandshakeMessage message, ByteBuffer buffer) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
              | 
 | 
            if (!shc.sslConfig.isAvailable(  | 
 | 
                    SSLExtension.CH_SIGNATURE_ALGORITHMS)) { | 
 | 
                if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
 | 
                    SSLLogger.fine(  | 
 | 
                        "Ignore unavailable signature_algorithms extension");  | 
 | 
                }  | 
 | 
                return;       | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            SignatureSchemesSpec spec;  | 
 | 
            try { | 
 | 
                spec = new SignatureSchemesSpec(buffer);  | 
 | 
            } catch (IOException ioe) { | 
 | 
                throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            shc.handshakeExtensions.put(  | 
 | 
                    SSLExtension.CH_SIGNATURE_ALGORITHMS, spec);  | 
 | 
 | 
 | 
            // No impact on session resumption.  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class CHSignatureSchemesUpdate  | 
 | 
            implements HandshakeConsumer { | 
 | 
          | 
 | 
        private CHSignatureSchemesUpdate() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
            SignatureSchemesSpec spec =  | 
 | 
                    (SignatureSchemesSpec)shc.handshakeExtensions.get(  | 
 | 
                            SSLExtension.CH_SIGNATURE_ALGORITHMS);  | 
 | 
            if (spec == null) { | 
 | 
                  | 
 | 
                return;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            List<SignatureScheme> sss =  | 
 | 
                    SignatureScheme.getSupportedAlgorithms(  | 
 | 
                            shc.sslConfig,  | 
 | 
                            shc.algorithmConstraints, shc.negotiatedProtocol,  | 
 | 
                            spec.signatureSchemes);  | 
 | 
            shc.peerRequestedSignatureSchemes = sss;  | 
 | 
 | 
 | 
            // If no "signature_algorithms_cert" extension is present, then  | 
 | 
            // the "signature_algorithms" extension also applies to  | 
 | 
              | 
 | 
            SignatureSchemesSpec certSpec =  | 
 | 
                    (SignatureSchemesSpec)shc.handshakeExtensions.get(  | 
 | 
                            SSLExtension.CH_SIGNATURE_ALGORITHMS_CERT);  | 
 | 
            if (certSpec == null) { | 
 | 
                shc.peerRequestedCertSignSchemes = sss;  | 
 | 
                shc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);  | 
 | 
            }  | 
 | 
 | 
 | 
            if (!shc.isResumption &&  | 
 | 
                    shc.negotiatedProtocol.useTLS13PlusSpec()) { | 
 | 
                if (shc.sslConfig.clientAuthType !=  | 
 | 
                        ClientAuthType.CLIENT_AUTH_NONE) { | 
 | 
                    shc.handshakeProducers.putIfAbsent(  | 
 | 
                            SSLHandshake.CERTIFICATE_REQUEST.id,  | 
 | 
                            SSLHandshake.CERTIFICATE_REQUEST);  | 
 | 
                }  | 
 | 
                shc.handshakeProducers.put(  | 
 | 
                        SSLHandshake.CERTIFICATE.id,  | 
 | 
                        SSLHandshake.CERTIFICATE);  | 
 | 
                shc.handshakeProducers.putIfAbsent(  | 
 | 
                        SSLHandshake.CERTIFICATE_VERIFY.id,  | 
 | 
                        SSLHandshake.CERTIFICATE_VERIFY);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CHSignatureSchemesOnLoadAbsence implements HandshakeAbsence { | 
 | 
        @Override  | 
 | 
        public void absent(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
            // This is a mandatory extension for certificate authentication  | 
 | 
            // in TLS 1.3.  | 
 | 
            //  | 
 | 
            // We may support the server authentication other than X.509  | 
 | 
              | 
 | 
            if (shc.negotiatedProtocol.useTLS13PlusSpec()) { | 
 | 
                throw shc.conContext.fatal(Alert.MISSING_EXTENSION,  | 
 | 
                    "No mandatory signature_algorithms extension in the " +  | 
 | 
                    "received CertificateRequest handshake message");  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CHSignatureSchemesOnTradeAbsence implements HandshakeAbsence { | 
 | 
        @Override  | 
 | 
        public void absent(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
            if (shc.negotiatedProtocol.useTLS12PlusSpec()) { | 
 | 
                // Use default hash and signature algorithm:  | 
 | 
                //      {sha1,rsa} | 
 | 
                //      {sha1,dsa} | 
 | 
                //      {sha1,ecdsa} | 
 | 
                // Per RFC 5246, If the client supports only the default hash  | 
 | 
                // and signature algorithms, it MAY omit the  | 
 | 
                // signature_algorithms extension.  If the client does not  | 
 | 
                // support the default algorithms, or supports other hash  | 
 | 
                // and signature algorithms (and it is willing to use them  | 
 | 
                // for verifying messages sent by the server, i.e., server  | 
 | 
                // certificates and server key exchange), it MUST send the  | 
 | 
                // signature_algorithms extension, listing the algorithms it  | 
 | 
                  | 
 | 
                List<SignatureScheme> schemes = Arrays.asList(  | 
 | 
                        SignatureScheme.RSA_PKCS1_SHA1,  | 
 | 
                        SignatureScheme.DSA_SHA1,  | 
 | 
                        SignatureScheme.ECDSA_SHA1  | 
 | 
                );  | 
 | 
 | 
 | 
                shc.peerRequestedSignatureSchemes = schemes;  | 
 | 
                if (shc.peerRequestedCertSignSchemes == null ||  | 
 | 
                        shc.peerRequestedCertSignSchemes.isEmpty()) { | 
 | 
                    shc.peerRequestedCertSignSchemes = schemes;  | 
 | 
                }  | 
 | 
 | 
 | 
                  | 
 | 
                shc.handshakeSession.setUseDefaultPeerSignAlgs();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CRSignatureSchemesProducer implements HandshakeProducer { | 
 | 
          | 
 | 
        private CRSignatureSchemesProducer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public byte[] produce(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ServerHandshakeContext shc = (ServerHandshakeContext)context;  | 
 | 
 | 
 | 
            // Is it a supported and enabled extension?  | 
 | 
            //  | 
 | 
            // Note that this is a mandatory extension for CertificateRequest  | 
 | 
              | 
 | 
            if (!shc.sslConfig.isAvailable(  | 
 | 
                    SSLExtension.CR_SIGNATURE_ALGORITHMS)) { | 
 | 
                throw shc.conContext.fatal(Alert.MISSING_EXTENSION,  | 
 | 
                        "No available signature_algorithms extension " +  | 
 | 
                        "for client certificate authentication");  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            List<ProtocolVersion> protocols = Arrays.asList(shc.negotiatedProtocol);  | 
 | 
            protocols = Collections.unmodifiableList(protocols);  | 
 | 
            List<SignatureScheme> sigAlgs =  | 
 | 
                    SignatureScheme.getSupportedAlgorithms(  | 
 | 
                            shc.sslConfig,  | 
 | 
                            shc.algorithmConstraints,  | 
 | 
                            protocols);  | 
 | 
 | 
 | 
            int vectorLen = SignatureScheme.sizeInRecord() * sigAlgs.size();  | 
 | 
            byte[] extData = new byte[vectorLen + 2];  | 
 | 
            ByteBuffer m = ByteBuffer.wrap(extData);  | 
 | 
            Record.putInt16(m, vectorLen);  | 
 | 
            for (SignatureScheme ss : sigAlgs) { | 
 | 
                Record.putInt16(m, ss.id);  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            shc.handshakeExtensions.put(  | 
 | 
                    SSLExtension.CR_SIGNATURE_ALGORITHMS,  | 
 | 
                    new SignatureSchemesSpec(shc.localSupportedSignAlgs));  | 
 | 
 | 
 | 
            return extData;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CRSignatureSchemesConsumer implements ExtensionConsumer { | 
 | 
          | 
 | 
        private CRSignatureSchemesConsumer() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
            HandshakeMessage message, ByteBuffer buffer) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
            // Is it a supported and enabled extension?  | 
 | 
            //  | 
 | 
            // Note that this is a mandatory extension for CertificateRequest  | 
 | 
              | 
 | 
            if (!chc.sslConfig.isAvailable(  | 
 | 
                    SSLExtension.CR_SIGNATURE_ALGORITHMS)) { | 
 | 
                throw chc.conContext.fatal(Alert.HANDSHAKE_FAILURE,  | 
 | 
                        "No available signature_algorithms extension " +  | 
 | 
                        "for client certificate authentication");  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            SignatureSchemesSpec spec;  | 
 | 
            try { | 
 | 
                spec = new SignatureSchemesSpec(buffer);  | 
 | 
            } catch (IOException ioe) { | 
 | 
                throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);  | 
 | 
            }  | 
 | 
 | 
 | 
            List<SignatureScheme> knownSignatureSchemes = new LinkedList<>();  | 
 | 
            for (int id : spec.signatureSchemes) { | 
 | 
                SignatureScheme ss = SignatureScheme.valueOf(id);  | 
 | 
                if (ss != null) { | 
 | 
                    knownSignatureSchemes.add(ss);  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            // Update the context.  | 
 | 
              | 
 | 
            chc.handshakeExtensions.put(  | 
 | 
                    SSLExtension.CR_SIGNATURE_ALGORITHMS, spec);  | 
 | 
 | 
 | 
            // No impact on session resumption.  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final class CRSignatureSchemesUpdate  | 
 | 
            implements HandshakeConsumer { | 
 | 
          | 
 | 
        private CRSignatureSchemesUpdate() { | 
 | 
            // blank  | 
 | 
        }  | 
 | 
 | 
 | 
        @Override  | 
 | 
        public void consume(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
            SignatureSchemesSpec spec =  | 
 | 
                    (SignatureSchemesSpec)chc.handshakeExtensions.get(  | 
 | 
                            SSLExtension.CR_SIGNATURE_ALGORITHMS);  | 
 | 
            if (spec == null) { | 
 | 
                  | 
 | 
                return;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            List<SignatureScheme> sss =  | 
 | 
                    SignatureScheme.getSupportedAlgorithms(  | 
 | 
                            chc.sslConfig,  | 
 | 
                            chc.algorithmConstraints, chc.negotiatedProtocol,  | 
 | 
                            spec.signatureSchemes);  | 
 | 
            chc.peerRequestedSignatureSchemes = sss;  | 
 | 
 | 
 | 
            // If no "signature_algorithms_cert" extension is present, then  | 
 | 
            // the "signature_algorithms" extension also applies to  | 
 | 
              | 
 | 
            SignatureSchemesSpec certSpec =  | 
 | 
                    (SignatureSchemesSpec)chc.handshakeExtensions.get(  | 
 | 
                            SSLExtension.CR_SIGNATURE_ALGORITHMS_CERT);  | 
 | 
            if (certSpec == null) { | 
 | 
                chc.peerRequestedCertSignSchemes = sss;  | 
 | 
                chc.handshakeSession.setPeerSupportedSignatureAlgorithms(sss);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final  | 
 | 
            class CRSignatureSchemesAbsence implements HandshakeAbsence { | 
 | 
        @Override  | 
 | 
        public void absent(ConnectionContext context,  | 
 | 
                HandshakeMessage message) throws IOException { | 
 | 
              | 
 | 
            ClientHandshakeContext chc = (ClientHandshakeContext)context;  | 
 | 
 | 
 | 
            // This is a mandatory extension for CertificateRequest handshake  | 
 | 
              | 
 | 
            throw chc.conContext.fatal(Alert.MISSING_EXTENSION,  | 
 | 
                    "No mandatory signature_algorithms extension in the " +  | 
 | 
                    "received CertificateRequest handshake message");  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |