} /* * Parse an ECDH server key exchange message. */ ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey, byte[] clntNonce, byte[] svrNonce, Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, ProtocolVersion protocolVersion) throws IOException, GeneralSecurityException { this.protocolVersion = protocolVersion; // read params: ServerECDHParams int curveType = input.getInt8(); ECParameterSpec parameters; // These parsing errors should never occur as we negotiated // the supported curves during the exchange of the Hello messages. if (curveType == CURVE_NAMED_CURVE) { curveId = input.getInt16(); if (SupportedEllipticCurvesExtension.isSupported(curveId) == false) { throw new SSLHandshakeException( "Unsupported curveId: " + curveId); } String curveOid = SupportedEllipticCurvesExtension.getCurveOid(curveId); if (curveOid == null) { throw new SSLHandshakeException( "Unknown named curve: " + curveId); } parameters = JsseJce.getECParameterSpec(curveOid); if (parameters == null) { throw new SSLHandshakeException( "Unsupported curve: " + curveOid); } } else { throw new SSLHandshakeException( "Unsupported ECCurveType: " + curveType); } pointBytes = input.getBytes8(); ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve()); KeyFactory factory = JsseJce.getKeyFactory("EC"); publicKey = (ECPublicKey)factory.generatePublic( new ECPublicKeySpec(point, parameters)); if (signingKey == null) { // ECDH_anon return; } // read the signature and hash algorithm if (protocolVersion.v >= ProtocolVersion.TLS12.v) { int hash = input.getInt8(); // hash algorithm int signature = input.getInt8(); // signature algorithm preferableSignatureAlgorithm = SignatureAndHashAlgorithm.valueOf(hash, signature, 0); // Is it a local supported signature algorithm? if (!localSupportedSignAlgs.contains( preferableSignatureAlgorithm)) { throw new SSLHandshakeException( "Unsupported SignatureAndHashAlgorithm in " + "ServerKeyExchange message"); } } // read the signature signatureBytes = input.getBytes16(); // verify the signature Signature sig; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { sig = JsseJce.getSignature( preferableSignatureAlgorithm.getAlgorithmName()); } else { sig = getSignature(signingKey.getAlgorithm()); } sig.initVerify(signingKey); updateSignature(sig, clntNonce, svrNonce); if (sig.verify(signatureBytes) == false ) { throw new SSLKeyException( "Invalid signature on ECDH server key exchange message"); } } /* * Get the ephemeral EC public key encapsulated in this message. */ ECPublicKey getPublicKey() { return publicKey; } private static Signature getSignature(String keyAlgorithm) throws NoSuchAlgorithmException { if (keyAlgorithm.equals("EC")) { return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA); } else if (keyAlgorithm.equals("RSA")) { return RSASignature.getInstance(); } else { throw new NoSuchAlgorithmException("neither an RSA or a EC key"); } } private void updateSignature(Signature sig, byte clntNonce[], byte svrNonce[]) throws SignatureException { sig.update(clntNonce); sig.update(svrNonce); sig.update((byte)CURVE_NAMED_CURVE); sig.update((byte)(curveId >> 8)); sig.update((byte)curveId); sig.update((byte)pointBytes.length); sig.update(pointBytes); } int messageLength() { int sigLen = 0; if (signatureBytes != null) { sigLen = 2 + signatureBytes.length; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { sigLen += SignatureAndHashAlgorithm.sizeInRecord(); } } return 4 + pointBytes.length + sigLen; } void send(HandshakeOutStream s) throws IOException { s.putInt8(CURVE_NAMED_CURVE); s.putInt16(curveId); s.putBytes8(pointBytes); if (signatureBytes != null) { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.putInt8(preferableSignatureAlgorithm.getHashValue()); s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); } s.putBytes16(signatureBytes); } } void print(PrintStream s) throws IOException { s.println("*** ECDH ServerKeyExchange"); if (debug != null && Debug.isOn("verbose")) { if (signatureBytes == null) { s.println("Anonymous"); } else { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.println("Signature Algorithm " + preferableSignatureAlgorithm.getAlgorithmName()); } } s.println("Server key: " + publicKey); } }} static final class DistinguishedName { /* * DER encoded distinguished name. * TLS requires that its not longer than 65535 bytes. */ byte name[]; DistinguishedName(HandshakeInStream input) throws IOException { name = input.getBytes16(); } DistinguishedName(X500Principal dn) { name = dn.getEncoded(); } X500Principal getX500Principal() throws IOException { try { return new X500Principal(name); } catch (IllegalArgumentException e) { throw (SSLProtocolException)new SSLProtocolException( e.getMessage()).initCause(e); } } int length() { return 2 + name.length; } void send(HandshakeOutStream output) throws IOException { output.putBytes16(name); } void print(PrintStream output) throws IOException { X500Principal principal = new X500Principal(name); output.println("<" + principal.toString() + ">"); }} /* * CertificateRequest ... SERVER --> CLIENT * * Authenticated servers may ask clients to authenticate themselves * in turn, using this message. * * Prior to TLS 1.2, the structure of the message is defined as: * struct { * ClientCertificateType certificate_types<1..2^8-1>; * DistinguishedName certificate_authorities<0..2^16-1>; * } CertificateRequest; * * In TLS 1.2, the structure is changed to: * struct { * ClientCertificateType certificate_types<1..2^8-1>; * SignatureAndHashAlgorithm * supported_signature_algorithms<2^16-1>; * DistinguishedName certificate_authorities<0..2^16-1>; * } CertificateRequest; * */static finalclass CertificateRequest extends HandshakeMessage{ // enum ClientCertificateType static final int cct_rsa_sign = 1; static final int cct_dss_sign = 2; static final int cct_rsa_fixed_dh = 3; static final int cct_dss_fixed_dh = 4; // The existance of these two values is a bug in the SSL specification. // They are never used in the protocol. static final int cct_rsa_ephemeral_dh = 5; static final int cct_dss_ephemeral_dh = 6; // From RFC 4492 (ECC) static final int cct_ecdsa_sign = 64; static final int cct_rsa_fixed_ecdh = 65; static final int cct_ecdsa_fixed_ecdh = 66; private final static byte[] TYPES_NO_ECC = { cct_rsa_sign, cct_dss_sign }; private final static byte[] TYPES_ECC = { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign }; byte types []; // 1 to 255 types DistinguishedName authorities []; // 3 to 2^16 - 1 // ... "3" because that's the smallest DER-encoded X500 DN // protocol version being established using this CertificateRequest message ProtocolVersion protocolVersion; // supported_signature_algorithms for TLS 1.2 or later private Collection<SignatureAndHashAlgorithm> algorithms; // length of supported_signature_algorithms private int algorithmsLen; CertificateRequest(X509Certificate ca[], KeyExchange keyExchange, Collection<SignatureAndHashAlgorithm> signAlgs, ProtocolVersion protocolVersion) throws IOException { this.protocolVersion = protocolVersion; // always use X500Principal authorities = new DistinguishedName[ca.length]; for (int i = 0; i < ca.length; i++) { X500Principal x500Principal = ca[i].getSubjectX500Principal(); authorities[i] = new DistinguishedName(x500Principal); } // we support RSA, DSS, and ECDSA client authentication and they // can be used with all ciphersuites. If this changes, the code // needs to be adapted to take keyExchange into account. // We only request ECDSA client auth if we have ECC crypto available. this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC; // Use supported_signature_algorithms for TLS 1.2 or later. if (protocolVersion.v >= ProtocolVersion.TLS12.v) { if (signAlgs == null || signAlgs.isEmpty()) { throw new SSLProtocolException( "No supported signature algorithms"); } algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs); algorithmsLen = SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); } else { algorithms = new ArrayList<SignatureAndHashAlgorithm>(); algorithmsLen = 0; } } CertificateRequest(HandshakeInStream input, ProtocolVersion protocolVersion) throws IOException { this.protocolVersion = protocolVersion; // Read the certificate_types. types = input.getBytes8(); // Read the supported_signature_algorithms for TLS 1.2 or later. if (protocolVersion.v >= ProtocolVersion.TLS12.v) { algorithmsLen = input.getInt16(); if (algorithmsLen < 2) { throw new SSLProtocolException( "Invalid supported_signature_algorithms field"); } algorithms = new ArrayList<SignatureAndHashAlgorithm>(); int remains = algorithmsLen; int sequence = 0; while (remains > 1) { // needs at least two bytes int hash = input.getInt8(); // hash algorithm int signature = input.getInt8(); // signature algorithm SignatureAndHashAlgorithm algorithm = SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence); algorithms.add(algorithm); remains -= 2; // one byte for hash, one byte for signature } if (remains != 0) { throw new SSLProtocolException( "Invalid supported_signature_algorithms field"); } } else { algorithms = new ArrayList<SignatureAndHashAlgorithm>(); algorithmsLen = 0; } // read the certificate_authorities int len = input.getInt16(); ArrayList<DistinguishedName> v = new ArrayList<>(); while (len >= 3) { DistinguishedName dn = new DistinguishedName(input); v.add(dn); len -= dn.length(); } if (len != 0) { throw new SSLProtocolException("Bad CertificateRequest DN length"); } authorities = v.toArray(new DistinguishedName[v.size()]); } X500Principal[] getAuthorities() throws IOException { X500Principal[] ret = new X500Principal[authorities.length]; for (int i = 0; i < authorities.length; i++) { ret[i] = authorities[i].getX500Principal(); } return ret; } Collection<SignatureAndHashAlgorithm> getSignAlgorithms() { return algorithms; } @Override int messageType() { return ht_certificate_request; } @Override int messageLength() { int len = 1 + types.length + 2; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { len += algorithmsLen + 2; } for (int i = 0; i < authorities.length; i++) { len += authorities[i].length(); } return len; } @Override void send(HandshakeOutStream output) throws IOException { // put certificate_types output.putBytes8(types); // put supported_signature_algorithms if (protocolVersion.v >= ProtocolVersion.TLS12.v) { output.putInt16(algorithmsLen); for (SignatureAndHashAlgorithm algorithm : algorithms) { output.putInt8(algorithm.getHashValue()); // hash output.putInt8(algorithm.getSignatureValue()); // signature } } // put certificate_authorities int len = 0; for (int i = 0; i < authorities.length; i++) { len += authorities[i].length(); } output.putInt16(len); for (int i = 0; i < authorities.length; i++) { authorities[i].send(output); } } @Override void print(PrintStream s) throws IOException { s.println("*** CertificateRequest"); if (debug != null && Debug.isOn("verbose")) { s.print("Cert Types: "); for (int i = 0; i < types.length; i++) { switch (types[i]) { case cct_rsa_sign: s.print("RSA"); break; case cct_dss_sign: s.print("DSS"); break; case cct_rsa_fixed_dh: s.print("Fixed DH (RSA sig)"); break; case cct_dss_fixed_dh: s.print("Fixed DH (DSS sig)"); break; case cct_rsa_ephemeral_dh: s.print("Ephemeral DH (RSA sig)"); break; case cct_dss_ephemeral_dh: s.print("Ephemeral DH (DSS sig)"); break; case cct_ecdsa_sign: s.print("ECDSA"); break; case cct_rsa_fixed_ecdh: s.print("Fixed ECDH (RSA sig)"); break; case cct_ecdsa_fixed_ecdh: s.print("Fixed ECDH (ECDSA sig)"); break; default: s.print("Type-" + (types[i] & 0xff)); break; } if (i != types.length - 1) { s.print(", "); } } s.println(); if (protocolVersion.v >= ProtocolVersion.TLS12.v) { StringBuffer buffer = new StringBuffer(); boolean opened = false; for (SignatureAndHashAlgorithm signAlg : algorithms) { if (opened) { buffer.append(", " + signAlg.getAlgorithmName()); } else { buffer.append(signAlg.getAlgorithmName()); opened = true; } } s.println("Supported Signature Algorithms: " + buffer); } s.println("Cert Authorities:"); if (authorities.length == 0) { s.println("<Empty>"); } else { for (int i = 0; i < authorities.length; i++) { authorities[i].print(s); } } } }} /* * ServerHelloDone ... SERVER --> CLIENT * * When server's done sending its messages in response to the client's * "hello" (e.g. its own hello, certificate, key exchange message, perhaps * client certificate request) it sends this message to flag that it's * done that part of the handshake. */static finalclass ServerHelloDone extends HandshakeMessage{ int messageType() { return ht_server_hello_done; } ServerHelloDone() { } ServerHelloDone(HandshakeInStream input) { // nothing to do } int messageLength() { return 0; } void send(HandshakeOutStream s) throws IOException { // nothing to send } Lines 1001–1500 of 2006. Previous lines Load more
} /* * Parse an ECDH server key exchange message. */ ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey, byte[] clntNonce, byte[] svrNonce, Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, ProtocolVersion protocolVersion) throws IOException, GeneralSecurityException { this.protocolVersion = protocolVersion; // read params: ServerECDHParams int curveType = input.getInt8(); ECParameterSpec parameters; // These parsing errors should never occur as we negotiated // the supported curves during the exchange of the Hello messages. if (curveType == CURVE_NAMED_CURVE) { curveId = input.getInt16(); if (SupportedEllipticCurvesExtension.isSupported(curveId) == false) { throw new SSLHandshakeException( "Unsupported curveId: " + curveId); } String curveOid = SupportedEllipticCurvesExtension.getCurveOid(curveId); if (curveOid == null) { throw new SSLHandshakeException( "Unknown named curve: " + curveId); } parameters = JsseJce.getECParameterSpec(curveOid); if (parameters == null) { throw new SSLHandshakeException( "Unsupported curve: " + curveOid); } } else { throw new SSLHandshakeException( "Unsupported ECCurveType: " + curveType); } pointBytes = input.getBytes8(); ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve()); KeyFactory factory = JsseJce.getKeyFactory("EC"); publicKey = (ECPublicKey)factory.generatePublic( new ECPublicKeySpec(point, parameters)); if (signingKey == null) { // ECDH_anon return; } // read the signature and hash algorithm if (protocolVersion.v >= ProtocolVersion.TLS12.v) { int hash = input.getInt8(); // hash algorithm int signature = input.getInt8(); // signature algorithm preferableSignatureAlgorithm = SignatureAndHashAlgorithm.valueOf(hash, signature, 0); // Is it a local supported signature algorithm? if (!localSupportedSignAlgs.contains( preferableSignatureAlgorithm)) { throw new SSLHandshakeException( "Unsupported SignatureAndHashAlgorithm in " + "ServerKeyExchange message"); } } // read the signature signatureBytes = input.getBytes16(); // verify the signature Signature sig; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { sig = JsseJce.getSignature( preferableSignatureAlgorithm.getAlgorithmName()); } else { sig = getSignature(signingKey.getAlgorithm()); } sig.initVerify(signingKey); updateSignature(sig, clntNonce, svrNonce); if (sig.verify(signatureBytes) == false ) { throw new SSLKeyException( "Invalid signature on ECDH server key exchange message"); } } /* * Get the ephemeral EC public key encapsulated in this message. */ ECPublicKey getPublicKey() { return publicKey; } private static Signature getSignature(String keyAlgorithm) throws NoSuchAlgorithmException { if (keyAlgorithm.equals("EC")) { return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA); } else if (keyAlgorithm.equals("RSA")) { return RSASignature.getInstance(); } else { throw new NoSuchAlgorithmException("neither an RSA or a EC key"); } } private void updateSignature(Signature sig, byte clntNonce[], byte svrNonce[]) throws SignatureException { sig.update(clntNonce); sig.update(svrNonce); sig.update((byte)CURVE_NAMED_CURVE); sig.update((byte)(curveId >> 8)); sig.update((byte)curveId); sig.update((byte)pointBytes.length); sig.update(pointBytes); } int messageLength() { int sigLen = 0; if (signatureBytes != null) { sigLen = 2 + signatureBytes.length; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { sigLen += SignatureAndHashAlgorithm.sizeInRecord(); } } return 4 + pointBytes.length + sigLen; } void send(HandshakeOutStream s) throws IOException { s.putInt8(CURVE_NAMED_CURVE); s.putInt16(curveId); s.putBytes8(pointBytes); if (signatureBytes != null) { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.putInt8(preferableSignatureAlgorithm.getHashValue()); s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); } s.putBytes16(signatureBytes); } } void print(PrintStream s) throws IOException { s.println("*** ECDH ServerKeyExchange"); if (debug != null && Debug.isOn("verbose")) { if (signatureBytes == null) { s.println("Anonymous"); } else { if (protocolVersion.v >= ProtocolVersion.TLS12.v) { s.println("Signature Algorithm " + preferableSignatureAlgorithm.getAlgorithmName()); } } s.println("Server key: " + publicKey); } } } static final class DistinguishedName { /* * DER encoded distinguished name. * TLS requires that its not longer than 65535 bytes. */ byte name[]; DistinguishedName(HandshakeInStream input) throws IOException { name = input.getBytes16(); } DistinguishedName(X500Principal dn) { name = dn.getEncoded(); } X500Principal getX500Principal() throws IOException { try { return new X500Principal(name); } catch (IllegalArgumentException e) { throw (SSLProtocolException)new SSLProtocolException( e.getMessage()).initCause(e); } } int length() { return 2 + name.length; } void send(HandshakeOutStream output) throws IOException { output.putBytes16(name); } void print(PrintStream output) throws IOException { X500Principal principal = new X500Principal(name); output.println("<" + principal.toString() + ">"); } } /* * CertificateRequest ... SERVER --> CLIENT * * Authenticated servers may ask clients to authenticate themselves * in turn, using this message. * * Prior to TLS 1.2, the structure of the message is defined as: * struct { * ClientCertificateType certificate_types<1..2^8-1>; * DistinguishedName certificate_authorities<0..2^16-1>; * } CertificateRequest; * * In TLS 1.2, the structure is changed to: * struct { * ClientCertificateType certificate_types<1..2^8-1>; * SignatureAndHashAlgorithm * supported_signature_algorithms<2^16-1>; * DistinguishedName certificate_authorities<0..2^16-1>; * } CertificateRequest; * */ static final class CertificateRequest extends HandshakeMessage { // enum ClientCertificateType static final int cct_rsa_sign = 1; static final int cct_dss_sign = 2; static final int cct_rsa_fixed_dh = 3; static final int cct_dss_fixed_dh = 4; // The existance of these two values is a bug in the SSL specification. // They are never used in the protocol. static final int cct_rsa_ephemeral_dh = 5; static final int cct_dss_ephemeral_dh = 6; // From RFC 4492 (ECC) static final int cct_ecdsa_sign = 64; static final int cct_rsa_fixed_ecdh = 65; static final int cct_ecdsa_fixed_ecdh = 66; private final static byte[] TYPES_NO_ECC = { cct_rsa_sign, cct_dss_sign }; private final static byte[] TYPES_ECC = { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign }; byte types []; // 1 to 255 types DistinguishedName authorities []; // 3 to 2^16 - 1 // ... "3" because that's the smallest DER-encoded X500 DN // protocol version being established using this CertificateRequest message ProtocolVersion protocolVersion; // supported_signature_algorithms for TLS 1.2 or later private Collection<SignatureAndHashAlgorithm> algorithms; // length of supported_signature_algorithms private int algorithmsLen; CertificateRequest(X509Certificate ca[], KeyExchange keyExchange, Collection<SignatureAndHashAlgorithm> signAlgs, ProtocolVersion protocolVersion) throws IOException { this.protocolVersion = protocolVersion; // always use X500Principal authorities = new DistinguishedName[ca.length]; for (int i = 0; i < ca.length; i++) { X500Principal x500Principal = ca[i].getSubjectX500Principal(); authorities[i] = new DistinguishedName(x500Principal); } // we support RSA, DSS, and ECDSA client authentication and they // can be used with all ciphersuites. If this changes, the code // needs to be adapted to take keyExchange into account. // We only request ECDSA client auth if we have ECC crypto available. this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC; // Use supported_signature_algorithms for TLS 1.2 or later. if (protocolVersion.v >= ProtocolVersion.TLS12.v) { if (signAlgs == null || signAlgs.isEmpty()) { throw new SSLProtocolException( "No supported signature algorithms"); } algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs); algorithmsLen = SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); } else { algorithms = new ArrayList<SignatureAndHashAlgorithm>(); algorithmsLen = 0; } } CertificateRequest(HandshakeInStream input, ProtocolVersion protocolVersion) throws IOException { this.protocolVersion = protocolVersion; // Read the certificate_types. types = input.getBytes8(); // Read the supported_signature_algorithms for TLS 1.2 or later. if (protocolVersion.v >= ProtocolVersion.TLS12.v) { algorithmsLen = input.getInt16(); if (algorithmsLen < 2) { throw new SSLProtocolException( "Invalid supported_signature_algorithms field"); } algorithms = new ArrayList<SignatureAndHashAlgorithm>(); int remains = algorithmsLen; int sequence = 0; while (remains > 1) { // needs at least two bytes int hash = input.getInt8(); // hash algorithm int signature = input.getInt8(); // signature algorithm SignatureAndHashAlgorithm algorithm = SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence); algorithms.add(algorithm); remains -= 2; // one byte for hash, one byte for signature } if (remains != 0) { throw new SSLProtocolException( "Invalid supported_signature_algorithms field"); } } else { algorithms = new ArrayList<SignatureAndHashAlgorithm>(); algorithmsLen = 0; } // read the certificate_authorities int len = input.getInt16(); ArrayList<DistinguishedName> v = new ArrayList<>(); while (len >= 3) { DistinguishedName dn = new DistinguishedName(input); v.add(dn); len -= dn.length(); } if (len != 0) { throw new SSLProtocolException("Bad CertificateRequest DN length"); } authorities = v.toArray(new DistinguishedName[v.size()]); } X500Principal[] getAuthorities() throws IOException { X500Principal[] ret = new X500Principal[authorities.length]; for (int i = 0; i < authorities.length; i++) { ret[i] = authorities[i].getX500Principal(); } return ret; } Collection<SignatureAndHashAlgorithm> getSignAlgorithms() { return algorithms; } @Override int messageType() { return ht_certificate_request; } @Override int messageLength() { int len = 1 + types.length + 2; if (protocolVersion.v >= ProtocolVersion.TLS12.v) { len += algorithmsLen + 2; } for (int i = 0; i < authorities.length; i++) { len += authorities[i].length(); } return len; } @Override void send(HandshakeOutStream output) throws IOException { // put certificate_types output.putBytes8(types); // put supported_signature_algorithms if (protocolVersion.v >= ProtocolVersion.TLS12.v) { output.putInt16(algorithmsLen); for (SignatureAndHashAlgorithm algorithm : algorithms) { output.putInt8(algorithm.getHashValue()); // hash output.putInt8(algorithm.getSignatureValue()); // signature } } // put certificate_authorities int len = 0; for (int i = 0; i < authorities.length; i++) { len += authorities[i].length(); } output.putInt16(len); for (int i = 0; i < authorities.length; i++) { authorities[i].send(output); } } @Override void print(PrintStream s) throws IOException { s.println("*** CertificateRequest"); if (debug != null && Debug.isOn("verbose")) { s.print("Cert Types: "); for (int i = 0; i < types.length; i++) { switch (types[i]) { case cct_rsa_sign: s.print("RSA"); break; case cct_dss_sign: s.print("DSS"); break; case cct_rsa_fixed_dh: s.print("Fixed DH (RSA sig)"); break; case cct_dss_fixed_dh: s.print("Fixed DH (DSS sig)"); break; case cct_rsa_ephemeral_dh: s.print("Ephemeral DH (RSA sig)"); break; case cct_dss_ephemeral_dh: s.print("Ephemeral DH (DSS sig)"); break; case cct_ecdsa_sign: s.print("ECDSA"); break; case cct_rsa_fixed_ecdh: s.print("Fixed ECDH (RSA sig)"); break; case cct_ecdsa_fixed_ecdh: s.print("Fixed ECDH (ECDSA sig)"); break; default: s.print("Type-" + (types[i] & 0xff)); break; } if (i != types.length - 1) { s.print(", "); } } s.println(); if (protocolVersion.v >= ProtocolVersion.TLS12.v) { StringBuffer buffer = new StringBuffer(); boolean opened = false; for (SignatureAndHashAlgorithm signAlg : algorithms) { if (opened) { buffer.append(", " + signAlg.getAlgorithmName()); } else { buffer.append(signAlg.getAlgorithmName()); opened = true; } } s.println("Supported Signature Algorithms: " + buffer); } s.println("Cert Authorities:"); if (authorities.length == 0) { s.println("<Empty>"); } else { for (int i = 0; i < authorities.length; i++) { authorities[i].print(s); } } } } } /* * ServerHelloDone ... SERVER --> CLIENT * * When server's done sending its messages in response to the client's * "hello" (e.g. its own hello, certificate, key exchange message, perhaps * client certificate request) it sends this message to flag that it's * done that part of the handshake. */ static final class ServerHelloDone extends HandshakeMessage { int messageType() { return ht_server_hello_done; } ServerHelloDone() { } ServerHelloDone(HandshakeInStream input) { // nothing to do } int messageLength() { return 0; } void send(HandshakeOutStream s) throws IOException { // nothing to send }