Source for gnu.javax.crypto.sasl.InputBuffer

   1: /* InputBuffer.java --
   2:    Copyright (C) 2003, 2006 Free Software Foundation, Inc.
   3: 
   4: This file is a part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2 of the License, or (at
   9: your option) any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; if not, write to the Free Software
  18: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
  19: USA
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version.  */
  37: 
  38: 
  39: package gnu.javax.crypto.sasl;
  40: 
  41: import gnu.java.security.Registry;
  42: 
  43: import java.io.ByteArrayInputStream;
  44: import java.io.IOException;
  45: import java.math.BigInteger;
  46: 
  47: /**
  48:  * The implementation of an incoming SASL buffer.
  49:  * <p>
  50:  * The data elements this class caters for are described in [1].
  51:  * <p>
  52:  * References:
  53:  * <ol>
  54:  * <li><a
  55:  * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
  56:  * Secure Remote Password Authentication Mechanism</a>;<br/>
  57:  * draft-burdis-cat-srp-sasl-09,<br/> <a
  58:  * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
  59:  * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
  60:  * </ol>
  61:  */
  62: public class InputBuffer
  63: {
  64:   /** The internal buffer stream containing the buffer's contents. */
  65:   protected ByteArrayInputStream in;
  66:   /** The length of the buffer, according to its header. */
  67:   protected int length;
  68: 
  69:   /**
  70:    * Constructs a SASL buffer given the buffer's encoded form, including its
  71:    * header bytes.
  72:    *
  73:    * @param frame the encoded form, including the header bytes, of a SASL
  74:    *          buffer.
  75:    * @throws SaslEncodingException if the buffer is malformed.
  76:    */
  77:   public InputBuffer(byte[] frame) throws SaslEncodingException
  78:   {
  79:     this();
  80: 
  81:     if (frame.length < 4)
  82:       throw new SaslEncodingException("SASL buffer header too short");
  83:     length = (frame[0] & 0xFF) << 24
  84:            | (frame[1] & 0xFF) << 16
  85:            | (frame[2] & 0xFF) << 8
  86:            | (frame[3] & 0xFF);
  87:     if (length > Registry.SASL_BUFFER_MAX_LIMIT || length < 0)
  88:       throw new SaslEncodingException("SASL buffer size limit exceeded");
  89:     in = new ByteArrayInputStream(frame, 4, length);
  90:   }
  91: 
  92:   /** Trivial private constructor for use by the class method. */
  93:   private InputBuffer()
  94:   {
  95:     super();
  96:   }
  97: 
  98:   /**
  99:    * Returns an instance of a SASL buffer given the buffer's encoded contents,
 100:    * excluding the buffer's header bytes.
 101:    * <p>
 102:    * Calls the method with the same name and three arguments as:
 103:    * <code>getInstance(raw, 0, raw.length)</code>.
 104:    *
 105:    * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
 106:    * @return a new instance of {@link InputBuffer}.
 107:    */
 108:   public static InputBuffer getInstance(byte[] raw)
 109:   {
 110:     return getInstance(raw, 0, raw.length);
 111:   }
 112: 
 113:   /**
 114:    * Returns an instance of a SASL buffer given the buffer's encoded contents,
 115:    * excluding the buffer's header bytes.
 116:    *
 117:    * @param raw the encoded form, excluding the header bytes, of a SASL buffer.
 118:    * @param offset offset where to start using raw bytes from.
 119:    * @param len number of bytes to use.
 120:    * @return a new instance of {@link InputBuffer}.
 121:    */
 122:   public static InputBuffer getInstance(byte[] raw, int offset, int len)
 123:   {
 124:     InputBuffer result = new InputBuffer();
 125:     result.in = new ByteArrayInputStream(raw, offset, len);
 126:     return result;
 127:   }
 128: 
 129:   /**
 130:    * Converts two octets into the number that they represent.
 131:    *
 132:    * @param b the two octets.
 133:    * @return the length.
 134:    */
 135:   public static int twoBytesToLength(byte[] b) throws SaslEncodingException
 136:   {
 137:     final int result = (b[0] & 0xFF) << 8 | (b[1] & 0xFF);
 138:     if (result > Registry.SASL_TWO_BYTE_MAX_LIMIT)
 139:       throw new SaslEncodingException("SASL MPI/Text size limit exceeded");
 140:     return result;
 141:   }
 142: 
 143:   public boolean hasMoreElements()
 144:   {
 145:     return (in.available() > 0);
 146:   }
 147: 
 148:   /**
 149:    * Decodes a SASL scalar quantity, <code>count</code>-octet long, from the
 150:    * current buffer.
 151:    *
 152:    * @param count the number of octets of this scalar quantity.
 153:    * @return a native representation of a SASL scalar (unsigned integer)
 154:    *         quantity.
 155:    * @throws SaslEncodingException if an encoding exception occurs during the
 156:    *           operation.
 157:    * @throws IOException if any other I/O exception occurs during the operation.
 158:    */
 159:   public long getScalar(int count) throws IOException
 160:   {
 161:     if (count < 0 || count > 4)
 162:       throw new SaslEncodingException("Invalid SASL scalar octet count: "
 163:                                       + String.valueOf(count));
 164:     if (! hasMoreElements())
 165:       throw new SaslEncodingException("Not enough bytes for a scalar in buffer");
 166:     if (in.available() < count)
 167:       throw new SaslEncodingException("Illegal SASL scalar encoding");
 168:     byte[] element = new byte[count];
 169:     in.read(element);
 170:     long result = 0L;
 171:     for (int i = 0; i < count; i++)
 172:       {
 173:         result <<= 8;
 174:         result |= element[i] & 0xFFL;
 175:       }
 176:     return result;
 177:   }
 178: 
 179:   /**
 180:    * Decodes a SASL OS from the current buffer.
 181:    *
 182:    * @return a native representation of a SASL OS.
 183:    * @throws SaslEncodingException if an encoding exception occurs during the
 184:    *           operation.
 185:    * @throws IOException if any other I/O exception occurs during the operation.
 186:    */
 187:   public byte[] getOS() throws IOException
 188:   {
 189:     if (! hasMoreElements())
 190:       throw new SaslEncodingException(
 191:           "Not enough bytes for an octet-sequence in buffer");
 192:     final int elementLength = in.read();
 193:     if (elementLength > Registry.SASL_ONE_BYTE_MAX_LIMIT)
 194:       throw new SaslEncodingException("SASL octet-sequence size limit exceeded");
 195:     if (in.available() < elementLength)
 196:       throw new SaslEncodingException("Illegal SASL octet-sequence encoding");
 197:     byte[] result = new byte[elementLength];
 198:     in.read(result);
 199:     return result;
 200:   }
 201: 
 202:   /**
 203:    * Decodes a SASL EOS from the current buffer.
 204:    *
 205:    * @return a native representation of a SASL EOS.
 206:    * @throws SaslEncodingException if an encoding exception occurs during the
 207:    *           operation.
 208:    * @throws IOException if any other I/O exception occurs during the operation.
 209:    */
 210:   public byte[] getEOS() throws IOException
 211:   {
 212:     if (in.available() < 2)
 213:       throw new SaslEncodingException(
 214:           "Not enough bytes for an extended octet-sequence in buffer");
 215:     byte[] elementLengthBytes = new byte[2];
 216:     in.read(elementLengthBytes);
 217:     final int elementLength = twoBytesToLength(elementLengthBytes);
 218:     if (in.available() < elementLength)
 219:       throw new SaslEncodingException(
 220:           "Illegal SASL extended octet-sequence encoding");
 221:     byte[] result = new byte[elementLength];
 222:     in.read(result);
 223:     return result;
 224:   }
 225: 
 226:   /**
 227:    * Decodes a SASL MPI from the current buffer.
 228:    *
 229:    * @return a native representation of a SASL MPI.
 230:    * @throws SaslEncodingException if an encoding exception occurs during the
 231:    *           operation.
 232:    * @throws IOException if any other I/O exception occurs during the operation.
 233:    */
 234:   public BigInteger getMPI() throws IOException
 235:   {
 236:     if (in.available() < 2)
 237:       throw new SaslEncodingException("Not enough bytes for an MPI in buffer");
 238:     byte[] elementLengthBytes = new byte[2];
 239:     in.read(elementLengthBytes);
 240:     final int elementLength = twoBytesToLength(elementLengthBytes);
 241:     if (in.available() < elementLength)
 242:       throw new SaslEncodingException(
 243:           "Illegal SASL multi-precision integer encoding");
 244:     byte[] element = new byte[elementLength];
 245:     in.read(element);
 246:     return new BigInteger(1, element);
 247:   }
 248: 
 249:   /**
 250:    * Decodes a SASL Text from the current buffer.
 251:    *
 252:    * @return a native representation of a SASL Text.
 253:    * @throws SaslEncodingException if an encoding exception occurs during the
 254:    *           operation.
 255:    * @throws SaslEncodingException if the UTF-8 character encoding is not
 256:    *           supported on this platform.
 257:    * @throws IOException if any other I/O exception occurs during the operation.
 258:    */
 259:   public String getText() throws IOException
 260:   {
 261:     if (in.available() < 2)
 262:       throw new SaslEncodingException("Not enough bytes for a text in buffer");
 263:     byte[] elementLengthBytes = new byte[2];
 264:     in.read(elementLengthBytes);
 265:     final int elementLength = twoBytesToLength(elementLengthBytes);
 266:     if (in.available() < elementLength)
 267:       throw new SaslEncodingException("Illegal SASL text encoding");
 268:     byte[] element = new byte[elementLength];
 269:     in.read(element);
 270:     return new String(element, "UTF8");
 271:   }
 272: }