|
Java example source code file (SSLExplorer.java)
The SSLExplorer.java Java example source code/* * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ import java.nio.ByteBuffer; import java.nio.BufferUnderflowException; import java.io.IOException; import javax.net.ssl.*; import java.util.*; import sun.misc.HexDumpEncoder; /** * Instances of this class acts as an explorer of the network data of an * SSL/TLS connection. */ public final class SSLExplorer { // Private constructor prevents construction outside this class. private SSLExplorer() { } /** * The header size of TLS/SSL records. * <P> * The value of this constant is {@value}. */ public final static int RECORD_HEADER_SIZE = 0x05; /** * Returns the required number of bytes in the {@code source} * {@link ByteBuffer} necessary to explore SSL/TLS connection. * <P> * This method tries to parse as few bytes as possible from * {@code source} byte buffer to get the length of an * SSL/TLS record. * <P> * This method accesses the {@code source} parameter in read-only * mode, and does not update the buffer's properties such as capacity, * limit, position, and mark values. * * @param source * a {@link ByteBuffer} containing * inbound or outbound network data for an SSL/TLS connection. * @throws BufferUnderflowException if less than {@code RECORD_HEADER_SIZE} * bytes remaining in {@code source} * @return the required size in byte to explore an SSL/TLS connection */ public final static int getRequiredSize(ByteBuffer source) { ByteBuffer input = source.duplicate(); // Do we have a complete header? if (input.remaining() < RECORD_HEADER_SIZE) { throw new BufferUnderflowException(); } // Is it a handshake message? byte firstByte = input.get(); byte secondByte = input.get(); byte thirdByte = input.get(); if ((firstByte & 0x80) != 0 && thirdByte == 0x01) { // looks like a V2ClientHello // return (((firstByte & 0x7F) << 8) | (secondByte & 0xFF)) + 2; return RECORD_HEADER_SIZE; // Only need the header fields } else { return (((input.get() & 0xFF) << 8) | (input.get() & 0xFF)) + 5; } } /** * Returns the required number of bytes in the {@code source} byte array * necessary to explore SSL/TLS connection. * <P> * This method tries to parse as few bytes as possible from * {@code source} byte array to get the length of an * SSL/TLS record. * * @param source * a byte array containing inbound or outbound network data for * an SSL/TLS connection. * @param offset * the start offset in array {@code source} at which the * network data is read from. * @param length * the maximum number of bytes to read. * * @throws BufferUnderflowException if less than {@code RECORD_HEADER_SIZE} * bytes remaining in {@code source} * @return the required size in byte to explore an SSL/TLS connection */ public final static int getRequiredSize(byte[] source, int offset, int length) throws IOException { ByteBuffer byteBuffer = ByteBuffer.wrap(source, offset, length).asReadOnlyBuffer(); return getRequiredSize(byteBuffer); } /** * Launch and explore the security capabilities from byte buffer. * <P> * This method tries to parse as few records as possible from * {@code source} byte buffer to get the {@link SSLCapabilities} * of an SSL/TLS connection. * <P> * Please NOTE that this method must be called before any handshaking * occurs. The behavior of this method is not defined in this release * if the handshake has begun, or has completed. * <P> * This method accesses the {@code source} parameter in read-only * mode, and does not update the buffer's properties such as capacity, * limit, position, and mark values. * * @param source * a {@link ByteBuffer} containing * inbound or outbound network data for an SSL/TLS connection. * * @throws IOException on network data error * @throws BufferUnderflowException if not enough source bytes available * to make a complete exploration. * * @return the explored {@link SSLCapabilities} of the SSL/TLS * connection */ public final static SSLCapabilities explore(ByteBuffer source) throws IOException { ByteBuffer input = source.duplicate(); // Do we have a complete header? if (input.remaining() < RECORD_HEADER_SIZE) { throw new BufferUnderflowException(); } // Is it a handshake message? byte firstByte = input.get(); byte secondByte = input.get(); byte thirdByte = input.get(); if ((firstByte & 0x80) != 0 && thirdByte == 0x01) { // looks like a V2ClientHello return exploreV2HelloRecord(input, firstByte, secondByte, thirdByte); } else if (firstByte == 22) { // 22: handshake record return exploreTLSRecord(input, firstByte, secondByte, thirdByte); } else { throw new SSLException("Not handshake record"); } } /** * Launch and explore the security capabilities from byte array. * <P> * Please NOTE that this method must be called before any handshaking * occurs. The behavior of this method is not defined in this release * if the handshake has begun, or has completed. Once handshake has * begun, or has completed, the security capabilities can not and * should not be launched with this method. * * @param source * a byte array containing inbound or outbound network data for * an SSL/TLS connection. * @param offset * the start offset in array {@code source} at which the * network data is read from. * @param length * the maximum number of bytes to read. * * @throws IOException on network data error * @throws BufferUnderflowException if not enough source bytes available * to make a complete exploration. * @return the explored {@link SSLCapabilities} of the SSL/TLS * connection * * @see #explore(ByteBuffer) */ public final static SSLCapabilities explore(byte[] source, int offset, int length) throws IOException { ByteBuffer byteBuffer = ByteBuffer.wrap(source, offset, length).asReadOnlyBuffer(); return explore(byteBuffer); } /* * uint8 V2CipherSpec[3]; * struct { * uint16 msg_length; // The highest bit MUST be 1; * // the remaining bits contain the length * // of the following data in bytes. * uint8 msg_type; // MUST be 1 * Version version; * uint16 cipher_spec_length; // It cannot be zero and MUST be a * // multiple of the V2CipherSpec length. * uint16 session_id_length; // This field MUST be empty. * uint16 challenge_length; // SHOULD use a 32-byte challenge * V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length]; * opaque session_id[V2ClientHello.session_id_length]; * opaque challenge[V2ClientHello.challenge_length; * } V2ClientHello; */ private static SSLCapabilities exploreV2HelloRecord( ByteBuffer input, byte firstByte, byte secondByte, byte thirdByte) throws IOException { // We only need the header. We have already had enough source bytes. // int recordLength = (firstByte & 0x7F) << 8) | (secondByte & 0xFF); try { // Is it a V2ClientHello? if (thirdByte != 0x01) { throw new SSLException( "Unsupported or Unrecognized SSL record"); } // What's the hello version? byte helloVersionMajor = input.get(); byte helloVersionMinor = input.get(); // 0x00: major version of SSLv20 // 0x02: minor version of SSLv20 // // SNIServerName is an extension, SSLv20 doesn't support extension. return new SSLCapabilitiesImpl((byte)0x00, (byte)0x02, helloVersionMajor, helloVersionMinor, Collections.<SNIServerName>emptyList()); } catch (BufferUnderflowException bufe) { throw new SSLProtocolException( "Invalid handshake record"); } } /* * struct { * uint8 major; * uint8 minor; * } ProtocolVersion; * * enum { * change_cipher_spec(20), alert(21), handshake(22), * application_data(23), (255) * } ContentType; * * struct { * ContentType type; * ProtocolVersion version; * uint16 length; * opaque fragment[TLSPlaintext.length]; * } TLSPlaintext; */ private static SSLCapabilities exploreTLSRecord( ByteBuffer input, byte firstByte, byte secondByte, byte thirdByte) throws IOException { // Is it a handshake message? if (firstByte != 22) { // 22: handshake record throw new SSLException("Not handshake record"); } // We need the record version to construct SSLCapabilities. byte recordMajorVersion = secondByte; byte recordMinorVersion = thirdByte; // Is there enough data for a full record? int recordLength = getInt16(input); if (recordLength > input.remaining()) { throw new BufferUnderflowException(); } // We have already had enough source bytes. try { return exploreHandshake(input, recordMajorVersion, recordMinorVersion, recordLength); } catch (BufferUnderflowException bufe) { throw new SSLProtocolException( "Invalid handshake record"); } } /* * enum { * hello_request(0), client_hello(1), server_hello(2), * certificate(11), server_key_exchange (12), * certificate_request(13), server_hello_done(14), * certificate_verify(15), client_key_exchange(16), * finished(20) * (255) * } HandshakeType; * * struct { * HandshakeType msg_type; * uint24 length; * select (HandshakeType) { * case hello_request: HelloRequest; * case client_hello: ClientHello; * case server_hello: ServerHello; * case certificate: Certificate; * case server_key_exchange: ServerKeyExchange; * case certificate_request: CertificateRequest; * case server_hello_done: ServerHelloDone; * case certificate_verify: CertificateVerify; * case client_key_exchange: ClientKeyExchange; * case finished: Finished; * } body; * } Handshake; */ private static SSLCapabilities exploreHandshake( ByteBuffer input, byte recordMajorVersion, byte recordMinorVersion, int recordLength) throws IOException { // What is the handshake type? byte handshakeType = input.get(); if (handshakeType != 0x01) { // 0x01: client_hello message throw new IllegalStateException("Not initial handshaking"); } // What is the handshake body length? int handshakeLength = getInt24(input); // Theoretically, a single handshake message might span multiple // records, but in practice this does not occur. if (handshakeLength > (recordLength - 4)) { // 4: handshake header size throw new SSLException("Handshake message spans multiple records"); } input = input.duplicate(); input.limit(handshakeLength + input.position()); return exploreClientHello(input, recordMajorVersion, recordMinorVersion); } /* * struct { * uint32 gmt_unix_time; * opaque random_bytes[28]; * } Random; * * opaque SessionID<0..32>; * * uint8 CipherSuite[2]; * * enum { null(0), (255) } CompressionMethod; * * struct { * ProtocolVersion client_version; * Random random; * SessionID session_id; * CipherSuite cipher_suites<2..2^16-2>; * CompressionMethod compression_methods<1..2^8-1>; * select (extensions_present) { * case false: * struct {}; * case true: * Extension extensions<0..2^16-1>; * }; * } ClientHello; */ private static SSLCapabilities exploreClientHello( ByteBuffer input, byte recordMajorVersion, byte recordMinorVersion) throws IOException { List<SNIServerName> snList = Collections. Other Java examples (source code examples)Here is a short list of links related to this Java SSLExplorer.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.