/* * Copyright 1999-2010 University of Chicago * * Licensed 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.globus.gsi.gssapi; import java.io.InputStream; import java.io.IOException; import java.io.EOFException; /** * A collection of SSL-protocol related functions. */ public class SSLUtil { /** * Reads some number of bytes from the input stream. * This function reads maximum data available on the * stream. * * @param in the input stream to read the bytes from. * @param buf the buffer into which read the data is read. * @param off the start offset in array b at which the data is written. * @param len the maximum number of bytes to read. * @exception IOException if I/O error occurs. */ public static int read(InputStream in, byte [] buf, int off, int len) throws IOException { int n = 0; while (n < len) { int count = in.read(buf, off + n, len - n); if (count < 0) { return count; } n += count; } return len; } /** * Reads some number of bytes from the input stream. * This function blocks until all data is read or an I/O * error occurs. * * @param in the input stream to read the bytes from. * @param buf the buffer into which read the data is read. * @param off the start offset in array b at which the data is written. * @param len the maximum number of bytes to read. * @exception IOException if I/O error occurs. */ public static void readFully(InputStream in, byte [] buf, int off, int len) throws IOException { int n = 0; while (n < len) { int count = in.read(buf, off + n, len - n); if (count < 0) throw new EOFException(); n += count; } } /** * Reads an entire SSL message from the specified * input stream. * * @param in the input stream to read the SSL message * from. * @return the byte array containing the SSL message * @exception IOException if I/O error occurs. */ public static byte[] readSslMessage(InputStream in) throws IOException { byte [] header = new byte[5]; readFully(in, header, 0, header.length); int length; if (isSSLv3Packet(header)) length = toShort(header[3], header[4]); else if (isSSLv2HelloPacket(header)) length = (((header[0] & 0x7f) << 8) | (header[1] & 0xff)) - 3; else { throw new IOException("Invalid SSL header"); } byte [] inToken = new byte[header.length + length]; System.arraycopy(header, 0, inToken, 0, header.length); readFully(in, inToken, header.length, length); return inToken; } /** * Determines if a given header is a SSL packet * (has a SSL header) * * @return true if the header is a SSL header. False, otherwise. */ public static final boolean isSSLPacket(byte[] header) { return ( isSSLv3Packet(header) || isSSLv2HelloPacket(header) ); } /** * Determines if a given header is a SSLv3 packet * (has a SSL header) or a backward compatible version of TLS * using the same header format. * * @return true if the header is a SSLv3 header. False, otherwise. */ public static final boolean isSSLv3Packet(byte[] header) { return header[0] >= 20 && header[0] <= 26 && (header[1] == 3 || (header[1] == 2 && header[2] == 0)); } /** * Determines if a given header is a SSLv2 client or server hello packet * * @return true if the header is such a SSLv2 client or server hello * packet. False, otherwise. */ public static final boolean isSSLv2HelloPacket(byte[] header) { return ((header[0] & 0x80) != 0 && (header[2] == 1 || header[2] == 4)); } /** * Converts 2 bytes to a <code>short</code>. * * @param a byte 1 * @param b byte 2 * @return the <code>short</code> value of the 2 bytes */ public static short toShort(byte a, byte b) { return (short)((a << 8) | (b & 0xff)); } /** * Converts 2 bytes to a * <code>unsigned short</code>. * * @param a byte 1 * @param b byte 2 * @return the <code>unsigned short</code> value of the 2 bytes */ public static int toUnsignedShort(byte a, byte b) { int n; n = (a & 0xff) << 8; n |= (b & 0xff); return n; } /** * Converts 4 bytes to an <code>int</code> at * the specified offset in the given byte array. * * @param buf the byte array containing the 4 bytes * to be converted to an <code>int</code>. * @param off offset in the byte array * @return the <code>int</code> value of the 4 bytes. */ public static int toInt(byte[] buf, int off) { int lg = (buf[off] & 0xff) << 24; lg |= (buf[off+1] & 0xff) << 16; lg |= (buf[off+2] & 0xff) << 8; lg |= (buf[off+3] & 0xff); return lg; } /** * Converts the specified int value into * 4 bytes. The bytes are put into the * specified byte array at a given offset * location. * * @param v the int value to convert into 4 bytes. * @param buf the byte array to put the resulting * 4 bytes. * @param off offset in the byte array */ public static void writeInt(int v, byte[] buf, int off) { buf[off] = (byte)((v >>> 24) & 0xFF); buf[off+1] = (byte)((v >>> 16) & 0xFF); buf[off+2] = (byte)((v >>> 8) & 0xFF); buf[off+3] = (byte)((v >>> 0) & 0xFF); } /** * Converts 8 bytes to a <code>long</code> at the * specified offset in the given byte array. * * @param buf the byte array containing the 8 bytes * to be converted to a <code>long</code>. * @param off offset in the byte array * @return the <code>long</code> value of the 8 bytes. */ public static long toLong(byte[]buf, int off) { return ((long)(toInt(buf, off)) << 32) + (toInt(buf, off+4) & 0xFFFFFFFFL); } }