/*
 * Copyright 1999-2006 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.net.impl;

import java.io.InputStream;
import java.io.IOException;
import java.io.EOFException;

import org.globus.gsi.gssapi.net.GssSocket;
import org.globus.gsi.gssapi.net.GssInputStream;
import org.globus.gsi.gssapi.SSLUtil;

import org.ietf.jgss.GSSContext;

public class GSIGssInputStream extends GssInputStream {
  
    // 32Mb 
    private static final int MAX_LEN = 32 * 1024 * 1024;

    protected byte [] header;
    protected int mode;

    public GSIGssInputStream(InputStream in, GSSContext context) {
        super(in, context);
        this.header = new byte[5];
        this.mode = -1;
    }
  
    protected void readMsg()
        throws IOException {
        byte [] token = readToken();
        if (token == null) {
            this.buff = null;
        } else {
            this.buff = unwrap(token);
        }
        this.index = 0;
    }

    public int getWrapMode() {
        return this.mode;
    }

    public byte[] readHandshakeToken()
        throws IOException {
        byte [] token = readToken();
        if (token == null) {
            throw new EOFException();
        }
        return token;
    }

    protected byte[] readToken()
        throws IOException {
        byte[] buf = null;
        if (SSLUtil.read(this.in, this.header, 0, this.header.length-1) < 0) {
            return null;
        }
        if (SSLUtil.isSSLv3Packet(this.header)) {
            this.mode = GssSocket.SSL_MODE;
            // read the second byte of packet length field
            if (SSLUtil.read(this.in, this.header, 4, 1) < 0) {
                return null;
            }
            int len = SSLUtil.toShort(this.header[3], this.header[4]);
            buf = new byte[this.header.length + len];
            System.arraycopy(this.header, 0, buf, 0, this.header.length);
            if (SSLUtil.read(this.in, buf, this.header.length, len) < 0) {
                return null;
            }
        } else if (SSLUtil.isSSLv2HelloPacket(this.header)) {
            this.mode = GssSocket.SSL_MODE;
            // SSLv2 - assume 2-byte header 
            // read extra 2 bytes so subtract it from total len
            int len = (((header[0] & 0x7f) << 8) | (header[1] & 0xff)) - 2;
            buf = new byte[this.header.length-1 + len];
            System.arraycopy(this.header, 0, buf, 0, this.header.length-1);
            if (SSLUtil.read(this.in, buf, this.header.length-1, len) < 0) {
                return null;
            }
        } else {
            this.mode = GssSocket.GSI_MODE;
            int len = SSLUtil.toInt(this.header, 0);
            if (len > MAX_LEN) {
                throw new IOException("Token length " + len + " > " + MAX_LEN);
            } else if (len < 0) {
                throw new IOException("Token length " + len + " < 0");
            }
            buf = new byte[len];
            if (SSLUtil.read(this.in, buf, 0, buf.length) < 0) {
                return null;
            }
        }
        return buf;
    }
    
}

@@ -1078,16 +1078,41 @@
 nt mode;
+%0A    boolean enc = false;
 %0A%0A    pu
@@ -2566,32 +2566,986 @@
 ;%0A            %7D%0A
+%0A            switch ((int) header%5B0%5D) %7B%0A                case 22:%0A                    if (!enc && (int) buf%5Bthis.header.length%5D == 11) %7B%0A                        // this is the certificate request during a handshake%0A                        int flen = SSLUtil.toInt(buf, this.header.length) & 0x00FFFFFF;%0A                        int alreadyRead = len;%0A                        int bytesToRead = flen - alreadyRead + 4;%0A                        byte%5B%5D certs = new byte%5Bbuf.length + bytesToRead%5D;%0A                        System.arraycopy(buf, 0, certs, 0, buf.length);%0A                        if (SSLUtil.read(this.in, certs, buf.length, bytesToRead) %3C 0) %7B%0A                            return null;%0A                        %7D%0A                        buf = certs;%0A                    %7D%0A                    break;%0A                case 20:%0A                    enc = true;%0A                    break;%0A                default:%0A                    //nop%0A            %7D%0A%0A
         %7D else i

read fully jumbo SSL messages