int k = curveIds.length << 1; s.putInt16(k + 2); s.putInt16(k); for (int curveId : curveIds) { s.putInt16(curveId); } } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Extension " + type + ", curve names: {"); boolean first = true; for (int curveId : curveIds) { if (first) { first = false; } else { sb.append(", "); } // first check if it is a known named curve, then try other cases. String oid = getCurveOid(curveId); if (oid != null) { ECParameterSpec spec = JsseJce.getECParameterSpec(oid); // this toString() output will look nice for the current // implementation of the ECParameterSpec class in the Sun // provider, but may not look good for other implementations. if (spec != null) { sb.append(spec.toString().split(" ")[0]); } else { sb.append(oid); } } else if (curveId == ARBITRARY_PRIME) { sb.append("arbitrary_explicit_prime_curves"); } else if (curveId == ARBITRARY_CHAR2) { sb.append("arbitrary_explicit_char2_curves"); } else { sb.append("unknown curve " + curveId); } } sb.append("}"); return sb.toString(); } // Test whether we support the curve with the given index. static boolean isSupported(int index) { if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) { return false; } if (fips == false) { // in non-FIPS mode, we support all valid indices return true; } return DEFAULT.contains(index); } static int getCurveIndex(ECParameterSpec params) { String oid = JsseJce.getNamedCurveOid(params); if (oid == null) { return -1; } Integer n = curveIndices.get(oid); return (n == null) ? -1 : n; } static String getCurveOid(int index) { if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) { return NAMED_CURVE_OID_TABLE[index]; } return null; } private final static int ARBITRARY_PRIME = 0xff01; private final static int ARBITRARY_CHAR2 = 0xff02; // See sun.security.ec.NamedCurve for the OIDs private final static String[] NAMED_CURVE_OID_TABLE = new String[] { null, // (0) unused "1.3.132.0.1", // (1) sect163k1, NIST K-163 "1.3.132.0.2", // (2) sect163r1 "1.3.132.0.15", // (3) sect163r2, NIST B-163 "1.3.132.0.24", // (4) sect193r1 "1.3.132.0.25", // (5) sect193r2 "1.3.132.0.26", // (6) sect233k1, NIST K-233 "1.3.132.0.27", // (7) sect233r1, NIST B-233 "1.3.132.0.3", // (8) sect239k1 "1.3.132.0.16", // (9) sect283k1, NIST K-283 "1.3.132.0.17", // (10) sect283r1, NIST B-283 "1.3.132.0.36", // (11) sect409k1, NIST K-409 "1.3.132.0.37", // (12) sect409r1, NIST B-409 "1.3.132.0.38", // (13) sect571k1, NIST K-571 "1.3.132.0.39", // (14) sect571r1, NIST B-571 "1.3.132.0.9", // (15) secp160k1 "1.3.132.0.8", // (16) secp160r1 "1.3.132.0.30", // (17) secp160r2 "1.3.132.0.31", // (18) secp192k1 "1.2.840.10045.3.1.1", // (19) secp192r1, NIST P-192 "1.3.132.0.32", // (20) secp224k1 "1.3.132.0.33", // (21) secp224r1, NIST P-224 "1.3.132.0.10", // (22) secp256k1 "1.2.840.10045.3.1.7", // (23) secp256r1, NIST P-256 "1.3.132.0.34", // (24) secp384r1, NIST P-384 "1.3.132.0.35", // (25) secp521r1, NIST P-521 }; private final static Map<String,Integer> curveIndices; static { curveIndices = new HashMap<String,Integer>(); for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) { curveIndices.put(NAMED_CURVE_OID_TABLE[i], i); } } } final class SupportedEllipticPointFormatsExtension extends HelloExtension { final static int FMT_UNCOMPRESSED = 0; final static int FMT_ANSIX962_COMPRESSED_PRIME = 1; final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2; static final HelloExtension DEFAULT = new SupportedEllipticPointFormatsExtension( new byte[] {FMT_UNCOMPRESSED}); private final byte[] formats; private SupportedEllipticPointFormatsExtension(byte[] formats) { super(ExtensionType.EXT_EC_POINT_FORMATS); this.formats = formats; } SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len) throws IOException { super(ExtensionType.EXT_EC_POINT_FORMATS); formats = s.getBytes8(); // RFC 4492 says uncompressed points must always be supported. // Check just to make sure. boolean uncompressed = false; for (int format : formats) { if (format == FMT_UNCOMPRESSED) { uncompressed = true; break; } } if (uncompressed == false) { throw new SSLProtocolException ("Peer does not support uncompressed points"); } } int length() { return 5 + formats.length; } void send(HandshakeOutStream s) throws IOException { s.putInt16(type.id); s.putInt16(formats.length + 1); s.putBytes8(formats); } private static String toString(byte format) { int f = format & 0xff; switch (f) { case FMT_UNCOMPRESSED: return "uncompressed"; case FMT_ANSIX962_COMPRESSED_PRIME: return "ansiX962_compressed_prime"; case FMT_ANSIX962_COMPRESSED_CHAR2: return "ansiX962_compressed_char2"; default: return "unknown-" + f; } } public String toString() { List<String> list = new ArrayList<>(); for (byte format : formats) { list.add(toString(format)); } return "Extension " + type + ", formats: " + list; }} /* * For secure renegotiation, RFC5746 defines a new TLS extension, * "renegotiation_info" (with extension type 0xff01), which contains a * cryptographic binding to the enclosing TLS connection (if any) for * which the renegotiation is being performed. The "extension data" * field of this extension contains a "RenegotiationInfo" structure: * * struct { * opaque renegotiated_connection<0..255>; * } RenegotiationInfo; */final class RenegotiationInfoExtension extends HelloExtension { private final byte[] renegotiated_connection; RenegotiationInfoExtension(byte[] clientVerifyData, byte[] serverVerifyData) { super(ExtensionType.EXT_RENEGOTIATION_INFO); if (clientVerifyData.length != 0) { renegotiated_connection = new byte[clientVerifyData.length + serverVerifyData.length]; System.arraycopy(clientVerifyData, 0, renegotiated_connection, 0, clientVerifyData.length); if (serverVerifyData.length != 0) { System.arraycopy(serverVerifyData, 0, renegotiated_connection, clientVerifyData.length, serverVerifyData.length); } } else { // ignore both the client and server verify data. renegotiated_connection = new byte[0]; } } RenegotiationInfoExtension(HandshakeInStream s, int len) throws IOException { super(ExtensionType.EXT_RENEGOTIATION_INFO); // check the extension length if (len < 1) { throw new SSLProtocolException("Invalid " + type + " extension"); } int renegoInfoDataLen = s.getInt8(); if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read throw new SSLProtocolException("Invalid " + type + " extension"); } renegotiated_connection = new byte[renegoInfoDataLen]; if (renegoInfoDataLen != 0) { s.read(renegotiated_connection, 0, renegoInfoDataLen); } } // Length of the encoded extension, including the type and length fields int length() { return 5 + renegotiated_connection.length; } void send(HandshakeOutStream s) throws IOException { s.putInt16(type.id); s.putInt16(renegotiated_connection.length + 1); s.putBytes8(renegotiated_connection); } boolean isEmpty() { return renegotiated_connection.length == 0; } byte[] getRenegotiatedConnection() { return renegotiated_connection; } public String toString() { return "Extension " + type + ", renegotiated_connection: " + (renegotiated_connection.length == 0 ? "<empty>" : Debug.toString(renegotiated_connection)); } } /* * [RFC5246] The client uses the "signature_algorithms" extension to * indicate to the server which signature/hash algorithm pairs may be * used in digital signatures. The "extension_data" field of this * extension contains a "supported_signature_algorithms" value. * * enum { * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), * sha512(6), (255) * } HashAlgorithm; * * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } * SignatureAlgorithm; * * struct { * HashAlgorithm hash; * SignatureAlgorithm signature; * } SignatureAndHashAlgorithm; * * SignatureAndHashAlgorithm * supported_signature_algorithms<2..2^16-2>; */final class SignatureAlgorithmsExtension extends HelloExtension { private Collection<SignatureAndHashAlgorithm> algorithms; private int algorithmsLen; // length of supported_signature_algorithms SignatureAlgorithmsExtension( Collection<SignatureAndHashAlgorithm> signAlgs) { super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs); algorithmsLen = SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); } SignatureAlgorithmsExtension(HandshakeInStream s, int len) throws IOException { super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); algorithmsLen = s.getInt16(); if (algorithmsLen == 0 || algorithmsLen + 2 != len) { throw new SSLProtocolException("Invalid " + type + " extension"); } algorithms = new ArrayList<SignatureAndHashAlgorithm>(); int remains = algorithmsLen; int sequence = 0; while (remains > 1) { // needs at least two bytes int hash = s.getInt8(); // hash algorithm int signature = s.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 server_name extension"); } } Collection<SignatureAndHashAlgorithm> getSignAlgorithms() { return algorithms; } @Override int length() { return 6 + algorithmsLen; } @Override void send(HandshakeOutStream s) throws IOException { s.putInt16(type.id); s.putInt16(algorithmsLen + 2); s.putInt16(algorithmsLen); for (SignatureAndHashAlgorithm algorithm : algorithms) { s.putInt8(algorithm.getHashValue()); // HashAlgorithm s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm } } @Override public String toString() { StringBuffer buffer = new StringBuffer(); boolean opened = false; for (SignatureAndHashAlgorithm signAlg : algorithms) { if (opened) { buffer.append(", " + signAlg.getAlgorithmName()); } else { buffer.append(signAlg.getAlgorithmName()); opened = true; } } return "Extension " + type + ", signature_algorithms: " + buffer; }}Lines 501–866 of 866. Previous lines
int k = curveIds.length << 1; s.putInt16(k + 2); s.putInt16(k); for (int curveId : curveIds) { s.putInt16(curveId); } } public String toString() { StringBuilder sb = new StringBuilder(); sb.append("Extension " + type + ", curve names: {"); boolean first = true; for (int curveId : curveIds) { if (first) { first = false; } else { sb.append(", "); } // first check if it is a known named curve, then try other cases. String oid = getCurveOid(curveId); if (oid != null) { ECParameterSpec spec = JsseJce.getECParameterSpec(oid); // this toString() output will look nice for the current // implementation of the ECParameterSpec class in the Sun // provider, but may not look good for other implementations. if (spec != null) { sb.append(spec.toString().split(" ")[0]); } else { sb.append(oid); } } else if (curveId == ARBITRARY_PRIME) { sb.append("arbitrary_explicit_prime_curves"); } else if (curveId == ARBITRARY_CHAR2) { sb.append("arbitrary_explicit_char2_curves"); } else { sb.append("unknown curve " + curveId); } } sb.append("}"); return sb.toString(); } // Test whether we support the curve with the given index. static boolean isSupported(int index) { if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) { return false; } if (fips == false) { // in non-FIPS mode, we support all valid indices return true; } return DEFAULT.contains(index); } static int getCurveIndex(ECParameterSpec params) { String oid = JsseJce.getNamedCurveOid(params); if (oid == null) { return -1; } Integer n = curveIndices.get(oid); return (n == null) ? -1 : n; } static String getCurveOid(int index) { if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) { return NAMED_CURVE_OID_TABLE[index]; } return null; } private final static int ARBITRARY_PRIME = 0xff01; private final static int ARBITRARY_CHAR2 = 0xff02; // See sun.security.ec.NamedCurve for the OIDs private final static String[] NAMED_CURVE_OID_TABLE = new String[] { null, // (0) unused "1.3.132.0.1", // (1) sect163k1, NIST K-163 "1.3.132.0.2", // (2) sect163r1 "1.3.132.0.15", // (3) sect163r2, NIST B-163 "1.3.132.0.24", // (4) sect193r1 "1.3.132.0.25", // (5) sect193r2 "1.3.132.0.26", // (6) sect233k1, NIST K-233 "1.3.132.0.27", // (7) sect233r1, NIST B-233 "1.3.132.0.3", // (8) sect239k1 "1.3.132.0.16", // (9) sect283k1, NIST K-283 "1.3.132.0.17", // (10) sect283r1, NIST B-283 "1.3.132.0.36", // (11) sect409k1, NIST K-409 "1.3.132.0.37", // (12) sect409r1, NIST B-409 "1.3.132.0.38", // (13) sect571k1, NIST K-571 "1.3.132.0.39", // (14) sect571r1, NIST B-571 "1.3.132.0.9", // (15) secp160k1 "1.3.132.0.8", // (16) secp160r1 "1.3.132.0.30", // (17) secp160r2 "1.3.132.0.31", // (18) secp192k1 "1.2.840.10045.3.1.1", // (19) secp192r1, NIST P-192 "1.3.132.0.32", // (20) secp224k1 "1.3.132.0.33", // (21) secp224r1, NIST P-224 "1.3.132.0.10", // (22) secp256k1 "1.2.840.10045.3.1.7", // (23) secp256r1, NIST P-256 "1.3.132.0.34", // (24) secp384r1, NIST P-384 "1.3.132.0.35", // (25) secp521r1, NIST P-521 }; private final static Map<String,Integer> curveIndices; static { curveIndices = new HashMap<String,Integer>(); for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) { curveIndices.put(NAMED_CURVE_OID_TABLE[i], i); } } } final class SupportedEllipticPointFormatsExtension extends HelloExtension { final static int FMT_UNCOMPRESSED = 0; final static int FMT_ANSIX962_COMPRESSED_PRIME = 1; final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2; static final HelloExtension DEFAULT = new SupportedEllipticPointFormatsExtension( new byte[] {FMT_UNCOMPRESSED}); private final byte[] formats; private SupportedEllipticPointFormatsExtension(byte[] formats) { super(ExtensionType.EXT_EC_POINT_FORMATS); this.formats = formats; } SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len) throws IOException { super(ExtensionType.EXT_EC_POINT_FORMATS); formats = s.getBytes8(); // RFC 4492 says uncompressed points must always be supported. // Check just to make sure. boolean uncompressed = false; for (int format : formats) { if (format == FMT_UNCOMPRESSED) { uncompressed = true; break; } } if (uncompressed == false) { throw new SSLProtocolException ("Peer does not support uncompressed points"); } } int length() { return 5 + formats.length; } void send(HandshakeOutStream s) throws IOException { s.putInt16(type.id); s.putInt16(formats.length + 1); s.putBytes8(formats); } private static String toString(byte format) { int f = format & 0xff; switch (f) { case FMT_UNCOMPRESSED: return "uncompressed"; case FMT_ANSIX962_COMPRESSED_PRIME: return "ansiX962_compressed_prime"; case FMT_ANSIX962_COMPRESSED_CHAR2: return "ansiX962_compressed_char2"; default: return "unknown-" + f; } } public String toString() { List<String> list = new ArrayList<>(); for (byte format : formats) { list.add(toString(format)); } return "Extension " + type + ", formats: " + list; } } /* * For secure renegotiation, RFC5746 defines a new TLS extension, * "renegotiation_info" (with extension type 0xff01), which contains a * cryptographic binding to the enclosing TLS connection (if any) for * which the renegotiation is being performed. The "extension data" * field of this extension contains a "RenegotiationInfo" structure: * * struct { * opaque renegotiated_connection<0..255>; * } RenegotiationInfo; */ final class RenegotiationInfoExtension extends HelloExtension { private final byte[] renegotiated_connection; RenegotiationInfoExtension(byte[] clientVerifyData, byte[] serverVerifyData) { super(ExtensionType.EXT_RENEGOTIATION_INFO); if (clientVerifyData.length != 0) { renegotiated_connection = new byte[clientVerifyData.length + serverVerifyData.length]; System.arraycopy(clientVerifyData, 0, renegotiated_connection, 0, clientVerifyData.length); if (serverVerifyData.length != 0) { System.arraycopy(serverVerifyData, 0, renegotiated_connection, clientVerifyData.length, serverVerifyData.length); } } else { // ignore both the client and server verify data. renegotiated_connection = new byte[0]; } } RenegotiationInfoExtension(HandshakeInStream s, int len) throws IOException { super(ExtensionType.EXT_RENEGOTIATION_INFO); // check the extension length if (len < 1) { throw new SSLProtocolException("Invalid " + type + " extension"); } int renegoInfoDataLen = s.getInt8(); if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read throw new SSLProtocolException("Invalid " + type + " extension"); } renegotiated_connection = new byte[renegoInfoDataLen]; if (renegoInfoDataLen != 0) { s.read(renegotiated_connection, 0, renegoInfoDataLen); } } // Length of the encoded extension, including the type and length fields int length() { return 5 + renegotiated_connection.length; } void send(HandshakeOutStream s) throws IOException { s.putInt16(type.id); s.putInt16(renegotiated_connection.length + 1); s.putBytes8(renegotiated_connection); } boolean isEmpty() { return renegotiated_connection.length == 0; } byte[] getRenegotiatedConnection() { return renegotiated_connection; } public String toString() { return "Extension " + type + ", renegotiated_connection: " + (renegotiated_connection.length == 0 ? "<empty>" : Debug.toString(renegotiated_connection)); } } /* * [RFC5246] The client uses the "signature_algorithms" extension to * indicate to the server which signature/hash algorithm pairs may be * used in digital signatures. The "extension_data" field of this * extension contains a "supported_signature_algorithms" value. * * enum { * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), * sha512(6), (255) * } HashAlgorithm; * * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } * SignatureAlgorithm; * * struct { * HashAlgorithm hash; * SignatureAlgorithm signature; * } SignatureAndHashAlgorithm; * * SignatureAndHashAlgorithm * supported_signature_algorithms<2..2^16-2>; */ final class SignatureAlgorithmsExtension extends HelloExtension { private Collection<SignatureAndHashAlgorithm> algorithms; private int algorithmsLen; // length of supported_signature_algorithms SignatureAlgorithmsExtension( Collection<SignatureAndHashAlgorithm> signAlgs) { super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs); algorithmsLen = SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); } SignatureAlgorithmsExtension(HandshakeInStream s, int len) throws IOException { super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); algorithmsLen = s.getInt16(); if (algorithmsLen == 0 || algorithmsLen + 2 != len) { throw new SSLProtocolException("Invalid " + type + " extension"); } algorithms = new ArrayList<SignatureAndHashAlgorithm>(); int remains = algorithmsLen; int sequence = 0; while (remains > 1) { // needs at least two bytes int hash = s.getInt8(); // hash algorithm int signature = s.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 server_name extension"); } } Collection<SignatureAndHashAlgorithm> getSignAlgorithms() { return algorithms; } @Override int length() { return 6 + algorithmsLen; } @Override void send(HandshakeOutStream s) throws IOException { s.putInt16(type.id); s.putInt16(algorithmsLen + 2); s.putInt16(algorithmsLen); for (SignatureAndHashAlgorithm algorithm : algorithms) { s.putInt8(algorithm.getHashValue()); // HashAlgorithm s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm } } @Override public String toString() { StringBuffer buffer = new StringBuffer(); boolean opened = false; for (SignatureAndHashAlgorithm signAlg : algorithms) { if (opened) { buffer.append(", " + signAlg.getAlgorithmName()); } else { buffer.append(signAlg.getAlgorithmName()); opened = true; } } return "Extension " + type + ", signature_algorithms: " + buffer; } }