Package org.ejbca.ui.web

Source Code of org.ejbca.ui.web.LimitLengthASN1Reader

/*************************************************************************
*                                                                       *
*  EJBCA: The OpenSource Certificate Authority                          *
*                                                                       *
*  This software is free software; you can redistribute it and/or       *
*  modify it under the terms of the GNU Lesser General Public           *
*  License as published by the Free Software Foundation; either         *
*  version 2.1 of the License, or any later version.                    *
*                                                                       *
*  See terms of license at gnu.org.                                     *
*                                                                       *
*************************************************************************/
package org.ejbca.ui.web;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.log4j.Logger;
import org.bouncycastle.asn1.ASN1InputStream;
import org.ejbca.core.model.InternalResources;
import org.ejbca.core.model.ca.MalformedRequestException;

/** Helper class used all bytes for the first ASN.1 object in the stream.
* Limits the size that is ever read to MAX_REQUEST_SIZE. This class is used for example to read requests from POSTs to servlets,
* when you want to make sure that you never read too many bytes that might have been sent by an attacker.
* Can only be used to read ASN.1 sequences, will throw MalformedException if first tag is not a sequence.
* Example usage:
* <pre>
* final ServletInputStream in = request.getInputStream(); // ServletInputStream does not have to be closed, container handles this
* ret = new LimitLengthServletPostReader(in, n).readFirstASN1Object();
* </pre>
*
* @version $Id: LimitLengthASN1Reader.java 10397 2010-11-08 14:18:57Z anatom $
*/
public class LimitLengthASN1Reader extends ASN1InputStream {

  private static final Logger m_log = Logger.getLogger(LimitLengthASN1Reader.class);
  /** Internal localization of logs and errors */
  private static final InternalResources intres = InternalResources.getInstance();

  /** Max size of a request is 100000 bytes */
  public static final int MAX_REQUEST_SIZE = 100000;
 
  private ByteArrayOutputStream baos;

  final private int contentLength;
  /**
   *
   * @param input
   * @param contentLength the provided contentLength, we do not trust it but will use it if given
   */
  public LimitLengthASN1Reader(InputStream input, int contentLength) {
    super(input, MAX_REQUEST_SIZE);
    this.baos = new ByteArrayOutputStream();
    this.contentLength = contentLength;
  }
  /* (non-Javadoc)
   * @see java.io.FilterInputStream#read()
   * This method is used in #readLeangth()
   */
  public int read() throws IOException {
    final int result = super.read();
    this.baos.write(result);
    return result;
  }
  /**
   * Read the 'value' of the top ASN1 object and append it to the already read 'tag' and 'value'
   * @param length nr of value bytes
   * @return the top ASN1 object
   * @throws IOException
   * @throws MalformedRequestException
   */
  private byte[] readTopASN1(int length) throws IOException, MalformedRequestException {
    final byte value[] = new byte[length];
    final int readLength = read(value);
    if ( readLength != length ) {
      final String msg = intres.getLocalizedMessage("request.notcorrectasn1length", Integer.valueOf(length), Integer.valueOf(readLength));
      m_log.info(msg);
      throw new MalformedRequestException(msg);
    }
    this.baos.write(value);
    this.baos.flush();
    return this.baos.toByteArray();
  }

  /** Reads all bytes for the first ASN.1 object in the stream. Limits the size that is ever read to MAX_REQUEST_SIZE.
   * @return all bytes for the first ASN.1 object in the stream.
   * @throws IOException
   * @throws MalformedRequestException if the request is too large or not correctly GET encoded.
   */
  public byte[] readFirstASN1Object() throws IOException, MalformedRequestException {
    final int tag = read() & 0x1f;
    if (tag != SEQUENCE) {
      final String msg = intres.getLocalizedMessage("request.notasequence", Integer.valueOf(tag));
      m_log.info(msg);
      throw new MalformedRequestException(msg);
    }
    final int length = readLength();
    if (length > MAX_REQUEST_SIZE) {
      final String msg = intres.getLocalizedMessage("request.toolarge", Integer.valueOf(MAX_REQUEST_SIZE), Integer.valueOf(length));
      m_log.info(msg);
      throw new MalformedRequestException(msg);
    }
    // If there was an asn.1 stream of undefined length we will try to read it the classic way, limiting the size of bytes read.
    if (length < 0) {// undefined length
      if (this.contentLength > MAX_REQUEST_SIZE) {
        final String msg = intres.getLocalizedMessage("request.toolarge", Integer.valueOf(MAX_REQUEST_SIZE), Integer.valueOf(this.baos.size()));
        m_log.info(msg);
        throw new MalformedRequestException(msg);
      }
      final int tlByteLength = this.baos.toByteArray().length;
      if (this.contentLength < tlByteLength) { // Content-length invalid. Try to read although.
        if (m_log.isTraceEnabled()) {
          m_log.trace("No content-length, reading as much as we have (<MAX_REQUEST_SIZE)");
        }
        final byte[] t = new byte[10240];
        int r = 0;
        int len = 0;
        while ( ((len = read(t)) != -1) && (r < LimitLengthASN1Reader.MAX_REQUEST_SIZE) ) { // never read more than MAX_OCSP_REQUEST_SIZE bytes
          this.baos.write(t, 0, len);
          r = r + len;
        }
        return this.baos.toByteArray();
      }
      // Read content-length bytes from stream
      if (m_log.isTraceEnabled()) {
        m_log.trace("Got content-length: "+Integer.valueOf(this.contentLength));
      }
      return readTopASN1(this.contentLength-tlByteLength); // 'tlByteLength' bytes already read. 'this.contentLength <= MAX_REQUEST_SIZE' tested above.
    }
    // defined length, just read as many bytes as the length tag says
    if (m_log.isTraceEnabled()) {
      m_log.trace("Got ASN1 length: "+Integer.valueOf(length));
    }
    return readTopASN1(length);
  }
}
TOP

Related Classes of org.ejbca.ui.web.LimitLengthASN1Reader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.