private static List<Integer> exploreRecord( ByteBuffer input) throws SSLException { // client version byte helloMajorVersion = input.get(); byte helloMinorVersion = input.get(); if (helloMajorVersion != 3 && helloMinorVersion != 3) { //we only care about TLS 1.2 return null; } // ignore random for (int i = 0; i < 32; ++i) {// 32: the length of Random byte d = input.get(); } // session id processByteVector8(input); // cipher_suites int int16 = getInt16(input); List<Integer> ciphers = new ArrayList<>(); for (int i = 0; i < int16; i += 2) { ciphers.add(getInt16(input)); } // compression methods processByteVector8(input); if (input.remaining() > 0) { return exploreExtensions(input, ciphers); } return null; }
private static List<Integer> exploreTLSRecord( ByteBuffer input, byte firstByte, byte secondByte, byte thirdByte) throws SSLException { // Is it a handshake message? if (firstByte != 22) { // 22: handshake record throw UndertowMessages.MESSAGES.notHandshakeRecord(); } // 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, secondByte, thirdByte, recordLength); } catch (BufferUnderflowException ignored) { throw UndertowMessages.MESSAGES.invalidHandshakeRecord(); } }
private static List<Integer> exploreHandshake( ByteBuffer input, byte recordMajorVersion, byte recordMinorVersion, int recordLength) throws SSLException { // What is the handshake type? byte handshakeType = input.get(); if (handshakeType != 0x01) { // 0x01: client_hello message throw UndertowMessages.MESSAGES.expectedClientHello(); } // 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 UndertowMessages.MESSAGES.multiRecordSSLHandshake(); } input = input.duplicate(); input.limit(handshakeLength + input.position()); return exploreRecord(input); }
private static void processByteVector8(ByteBuffer input) { int int8 = getInt8(input); processByteVector(input, int8); }
private static void processByteVector16(ByteBuffer input) { int int16 = getInt16(input); processByteVector(input, int16); }
@Override public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { if (done) { return delegate.unwrap(src, dst); } if (ALPNOfferedClientHelloExplorer.isIncompleteHeader(src)) { return UNDERFLOW_RESULT; } try { List<Integer> clientCiphers = ALPNOfferedClientHelloExplorer.parseClientHello(src); if (clientCiphers != null) { limitCiphers(clientCiphers); done = true; } else { done = true; } } catch (BufferUnderflowException e) { return UNDERFLOW_RESULT; } return delegate.unwrap(src, dst); }
/** * Checks if a client handshake is offering ALPN, and if so it returns a list of all ciphers. If ALPN is not being * offered then this will return null. */ static List<Integer> parseClientHello(ByteBuffer source) throws SSLException { ByteBuffer input = source.duplicate(); // Do we have a complete header? if (isIncompleteHeader(input)) { 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, we ignore it. return null; } else if (firstByte == 22) { // 22: handshake record if (secondByte == 3 && thirdByte >= 1 && thirdByte <= 3) { return exploreTLSRecord(input, firstByte, secondByte, thirdByte); } } return null; }
private static List<Integer> exploreExtensions(ByteBuffer input, List<Integer> ciphers) throws SSLException { int length = getInt16(input); // length of extensions while (length > 0) { int extType = getInt16(input); // extenson type int extLen = getInt16(input); // length of extension data if (extType == 16) { // 0x00: ty return ciphers; } else { // ignore other extensions processByteVector(input, extLen); } length -= extLen + 4; } return null; }
@Override public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers, int i, int i1) throws SSLException { if (done) { return delegate.unwrap(byteBuffer, byteBuffers, i, i1); } if (ALPNOfferedClientHelloExplorer.isIncompleteHeader(byteBuffer)) { return UNDERFLOW_RESULT; } try { List<Integer> clientCiphers = ALPNOfferedClientHelloExplorer.parseClientHello(byteBuffer); if (clientCiphers != null) { limitCiphers(clientCiphers); done = true; } else { done = true; } } catch (BufferUnderflowException e) { return UNDERFLOW_RESULT; } return delegate.unwrap(byteBuffer, byteBuffers, i, i1); }
private static void processByteVector8(ByteBuffer input) { int int8 = getInt8(input); processByteVector(input, int8); }
/** * Checks if a client handshake is offering ALPN, and if so it returns a list of all ciphers. If ALPN is not being * offered then this will return null. */ static List<Integer> parseClientHello(ByteBuffer source) throws SSLException { ByteBuffer input = source.duplicate(); // Do we have a complete header? if (isIncompleteHeader(input)) { 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, we ignore it. return null; } else if (firstByte == 22) { // 22: handshake record if (secondByte == 3 && thirdByte >= 1 && thirdByte <= 3) { return exploreTLSRecord(input, firstByte, secondByte, thirdByte); } } return null; }
private static List<Integer> exploreRecord( ByteBuffer input) throws SSLException { // client version byte helloMajorVersion = input.get(); byte helloMinorVersion = input.get(); if (helloMajorVersion != 3 && helloMinorVersion != 3) { //we only care about TLS 1.2 return null; } // ignore random for (int i = 0; i < 32; ++i) {// 32: the length of Random byte d = input.get(); } // session id processByteVector8(input); // cipher_suites int int16 = getInt16(input); List<Integer> ciphers = new ArrayList<>(); for (int i = 0; i < int16; i += 2) { ciphers.add(getInt16(input)); } // compression methods processByteVector8(input); if (input.remaining() > 0) { return exploreExtensions(input, ciphers); } return null; }
private static void processByteVector16(ByteBuffer input) { int int16 = getInt16(input); processByteVector(input, int16); }
@Override public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException { if (done) { return delegate.unwrap(src, dst); } if (ALPNOfferedClientHelloExplorer.isIncompleteHeader(src)) { return UNDERFLOW_RESULT; } try { List<Integer> clientCiphers = ALPNOfferedClientHelloExplorer.parseClientHello(src); if (clientCiphers != null) { limitCiphers(clientCiphers); done = true; } else { done = true; } } catch (BufferUnderflowException e) { return UNDERFLOW_RESULT; } return delegate.unwrap(src, dst); }
private static void processByteVector8(ByteBuffer input) { int int8 = getInt8(input); processByteVector(input, int8); }
private static List<Integer> exploreTLSRecord( ByteBuffer input, byte firstByte, byte secondByte, byte thirdByte) throws SSLException { // Is it a handshake message? if (firstByte != 22) { // 22: handshake record throw UndertowMessages.MESSAGES.notHandshakeRecord(); } // 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, secondByte, thirdByte, recordLength); } catch (BufferUnderflowException ignored) { throw UndertowMessages.MESSAGES.invalidHandshakeRecord(); } }
private static List<Integer> exploreHandshake( ByteBuffer input, byte recordMajorVersion, byte recordMinorVersion, int recordLength) throws SSLException { // What is the handshake type? byte handshakeType = input.get(); if (handshakeType != 0x01) { // 0x01: client_hello message throw UndertowMessages.MESSAGES.expectedClientHello(); } // 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 UndertowMessages.MESSAGES.multiRecordSSLHandshake(); } input = input.duplicate(); input.limit(handshakeLength + input.position()); return exploreRecord(input); }
/** * Checks if a client handshake is offering ALPN, and if so it returns a list of all ciphers. If ALPN is not being * offered then this will return null. */ static List<Integer> parseClientHello(ByteBuffer source) throws SSLException { ByteBuffer input = source.duplicate(); // Do we have a complete header? if (isIncompleteHeader(input)) { 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, we ignore it. return null; } else if (firstByte == 22) { // 22: handshake record if (secondByte == 3 && thirdByte >= 1 && thirdByte <= 3) { return exploreTLSRecord(input, firstByte, secondByte, thirdByte); } } return null; }
private static List<Integer> exploreRecord( ByteBuffer input) throws SSLException { // client version byte helloMajorVersion = input.get(); byte helloMinorVersion = input.get(); if (helloMajorVersion != 3 && helloMinorVersion != 3) { //we only care about TLS 1.2 return null; } // ignore random for (int i = 0; i < 32; ++i) {// 32: the length of Random byte d = input.get(); } // session id processByteVector8(input); // cipher_suites int int16 = getInt16(input); List<Integer> ciphers = new ArrayList<>(); for (int i = 0; i < int16; i += 2) { ciphers.add(getInt16(input)); } // compression methods processByteVector8(input); if (input.remaining() > 0) { return exploreExtensions(input, ciphers); } return null; }
private static void processByteVector16(ByteBuffer input) { int int16 = getInt16(input); processByteVector(input, int16); }