| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| package org.apache.qpid.proton.engine.impl.ssl; |
| |
| import org.apache.qpid.proton.engine.impl.TransportWrapper; |
| |
| public class SslHandshakeSniffingTransportWrapper implements SslTransportWrapper |
| { |
| private final SslTransportWrapper _secureTransportWrapper; |
| private final TransportWrapper _plainTransportWrapper; |
| |
| private boolean _determinationMade = false; |
| private boolean _isSecure; |
| |
| public SslHandshakeSniffingTransportWrapper( |
| SslTransportWrapper secureTransportWrapper, |
| TransportWrapper plainTransportWrapper) |
| { |
| _secureTransportWrapper = secureTransportWrapper; |
| _plainTransportWrapper = plainTransportWrapper; |
| } |
| |
| @Override |
| public int input(byte[] sourceBuffer, int offset, int size) |
| { |
| if (_determinationMade==false) |
| { |
| byte[] zeroBasedSrcBytes = new byte[size]; |
| System.arraycopy(sourceBuffer, offset, zeroBasedSrcBytes, 0, size); |
| |
| _isSecure = checkForSslHandshake(zeroBasedSrcBytes); |
| _determinationMade = true; |
| } |
| |
| if (_isSecure) |
| { |
| return _secureTransportWrapper.input(sourceBuffer, offset, size); |
| } |
| else |
| { |
| return _plainTransportWrapper.input(sourceBuffer, offset, size); |
| } |
| } |
| |
| @Override |
| public int output(byte[] destinationBuffer, int offset, int size) |
| { |
| if (_determinationMade == false) |
| { |
| _isSecure = false; |
| _determinationMade = true; |
| } |
| |
| if (_isSecure) |
| { |
| return _secureTransportWrapper.output(destinationBuffer, offset, size); |
| } |
| else |
| { |
| return _plainTransportWrapper.output(destinationBuffer, offset, size); |
| } |
| } |
| |
| @Override |
| public String getCipherName() |
| { |
| return _secureTransportWrapper.getCipherName(); |
| } |
| |
| @Override |
| public String getProtocolName() |
| { |
| return _secureTransportWrapper.getProtocolName(); |
| } |
| |
| // TODO perhaps the sniffer should save up the bytes from each |
| // input call until it has sufficient bytes to make the determination |
| // and only then pass them to the secure or plain wrapped transport? |
| private boolean checkForSslHandshake(byte[] buf) |
| { |
| if (buf.length >= 5) |
| { |
| /* |
| * SSLv2 Client Hello format |
| * http://www.mozilla.org/projects/security/pki/nss/ssl/draft02.html |
| * |
| * Bytes 0-1: RECORD-LENGTH Byte 2: MSG-CLIENT-HELLO (1) Byte 3: |
| * CLIENT-VERSION-MSB Byte 4: CLIENT-VERSION-LSB |
| * |
| * Allowed versions: 2.0 - SSLv2 3.0 - SSLv3 3.1 - TLS 1.0 3.2 - TLS |
| * 1.1 3.3 - TLS 1.2 |
| * |
| * The version sent in the Client-Hello is the latest version |
| * supported by the client. NSS may send version 3.x in an SSLv2 |
| * header for maximum compatibility. |
| */ |
| boolean isSSL2Handshake = buf[2] == 1 && // MSG-CLIENT-HELLO |
| ((buf[3] == 3 && buf[4] <= 3) || // SSL 3.0 & TLS 1.0-1.2 |
| // (v3.1-3.3) |
| (buf[3] == 2 && buf[4] == 0)); // SSL 2 |
| |
| /* |
| * SSLv3/TLS Client Hello format RFC 2246 |
| * |
| * Byte 0: ContentType (handshake - 22) Bytes 1-2: ProtocolVersion |
| * {major, minor} |
| * |
| * Allowed versions: 3.0 - SSLv3 3.1 - TLS 1.0 3.2 - TLS 1.1 3.3 - |
| * TLS 1.2 |
| */ |
| boolean isSSL3Handshake = buf[0] == 22 && // handshake |
| (buf[1] == 3 && buf[2] <= 3); // SSL 3.0 & TLS 1.0-1.2 |
| // (v3.1-3.3) |
| |
| return (isSSL2Handshake || isSSL3Handshake); |
| } |
| else |
| { |
| throw new IllegalArgumentException("Too few bytes (" + buf.length + ") to make SSL/plain determination."); |
| } |
| } |
| } |