Package ch.ethz.inf.vs.scandium.dtls

Source Code of ch.ethz.inf.vs.scandium.dtls.HandshakeMessage

/*******************************************************************************
* Copyright (c) 2014, Institute for Pervasive Computing, ETH Zurich.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Scandium (Sc) Security for Californium.
******************************************************************************/
package ch.ethz.inf.vs.scandium.dtls;

import java.util.logging.Logger;

import ch.ethz.inf.vs.scandium.dtls.CipherSuite.KeyExchangeAlgorithm;
import ch.ethz.inf.vs.scandium.util.DatagramReader;
import ch.ethz.inf.vs.scandium.util.DatagramWriter;

/**
* Represents a general handshake message and defines the common header. The
* subclasses are responsible for the rest of the message body. See <a
* href="http://tools.ietf.org/html/rfc6347#section-4.2.2">RFC 6347</a> for the
* message format.
*
* @author Stefan Jucker
*
*/
public abstract class HandshakeMessage implements DTLSMessage {

  // Logging ////////////////////////////////////////////////////////

  private static final Logger LOGGER = Logger.getLogger(HandshakeMessage.class.getCanonicalName());

  // CoAP-specific constants ////////////////////////////////////////

  private static final int MESSAGE_TYPE_BITS = 8;

  private static final int MESSAGE_LENGTH_BITS = 24;

  private static final int MESSAGE_SEQ_BITS = 16;

  private static final int FRAGMENT_OFFSET_BITS = 24;

  private static final int FRAGMENT_LENGTH_BITS = 24;

  // Members ////////////////////////////////////////////////////////

  /**
   * Whenever each new message is generated, the message_seq value is
   * incremented by one.
   */
  private int messageSeq = -1;

  /**
   * The number of bytes contained in previous fragments.
   */
  private int fragmentOffset = -1;

  /**
   * The length of this fragment. An unfragmented message is a degenerate case
   * with fragment_offset=0 and fragment_length=length.
   */
  private int fragmentLength = -1;

  // Abstract methods ///////////////////////////////////////////////

  /**
   * Returns the type of the handshake message. See {@link HandshakeType}.
   *
   * @return the {@link HandshakeType}.
   */
  public abstract HandshakeType getMessageType();

  /**
   * Must be implemented by each subclass. The length is given in bytes and
   * only includes the length of the subclass' specific fields (not the
   * handshake message header).
   *
   * @return the length of the message <strong>in bytes</strong>.
   */
  public abstract int getMessageLength();
 
  /**
   * The serialization of the handshake body (without the handshake header).
   * Must be implemented by each subclass.
   *
   * @return the raw byte representation of the handshake body.
   */
  public abstract byte[] fragmentToByteArray();

  // Methods ////////////////////////////////////////////////////////

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("\tHandshake Protocol\n");
    sb.append("\tType: " + getMessageType().toString() + "\n");
    sb.append("\tMessage Sequence: " + messageSeq + " \n");
    sb.append("\tFragment Offset: " + fragmentOffset + "\n");
    sb.append("\tFragment Length: " + fragmentLength + "\n");
    sb.append("\tLength: " + getMessageLength() + "\n");

    return sb.toString();
  }

  // Serialization //////////////////////////////////////////////////

  /**
   * Returns the raw binary representation of the handshake header. The
   * subclasses are responsible for the specific rest of the fragment.
   *
   * @return the byte representation of the handshake message.
   */
  public byte[] toByteArray() {
    // create datagram writer to encode message data
    DatagramWriter writer = new DatagramWriter();

    // write fixed-size handshake message header
    writer.write(getMessageType().getCode(), MESSAGE_TYPE_BITS);
    writer.write(getMessageLength(), MESSAGE_LENGTH_BITS);

    writer.write(messageSeq, MESSAGE_SEQ_BITS);
   
    if (fragmentOffset < 0) {
      // message not fragmented
      fragmentOffset = 0;
    }
    writer.write(fragmentOffset, FRAGMENT_OFFSET_BITS);
   
    if (fragmentLength < 0) {
      // unfragmented message is a degenerate case with fragment_offset=0
      // and fragment_length=length
      fragmentLength = getMessageLength();
    }
    writer.write(fragmentLength, FRAGMENT_LENGTH_BITS);
   
    writer.writeBytes(fragmentToByteArray());

    return writer.toByteArray();
  }

  public static HandshakeMessage fromByteArray(byte[] byteArray, KeyExchangeAlgorithm keyExchange, boolean useRawPublicKey) throws HandshakeException {
    DatagramReader reader = new DatagramReader(byteArray);
    HandshakeType type = HandshakeType.getTypeByCode(reader.read(MESSAGE_TYPE_BITS));

    int length = reader.read(MESSAGE_LENGTH_BITS);

    int messageSeq = reader.read(MESSAGE_SEQ_BITS);

    int fragmentOffset = reader.read(FRAGMENT_OFFSET_BITS);
    int fragmentLength = reader.read(FRAGMENT_LENGTH_BITS);

    byte[] bytesLeft = reader.readBytes(fragmentLength);
   
    if (length != fragmentLength) {
      // fragmented message received
      return new FragmentedHandshakeMessage(type, length, messageSeq, fragmentOffset, bytesLeft);
    }
   
    HandshakeMessage body = null;
    switch (type) {
    case HELLO_REQUEST:
      body = new HelloRequest();
      break;

    case CLIENT_HELLO:
      body = ClientHello.fromByteArray(bytesLeft);
      break;

    case SERVER_HELLO:
      body = ServerHello.fromByteArray(bytesLeft);
      break;

    case HELLO_VERIFY_REQUEST:
      body = HelloVerifyRequest.fromByteArray(bytesLeft);
      break;

    case CERTIFICATE:
      body = CertificateMessage.fromByteArray(bytesLeft, useRawPublicKey);
      break;

    case SERVER_KEY_EXCHANGE:
      switch (keyExchange) {
      case EC_DIFFIE_HELLMAN:
        body = ECDHServerKeyExchange.fromByteArray(bytesLeft);
        break;
      case PSK:
        body = PSKServerKeyExchange.fromByteArray(bytesLeft);
        break;
      case NULL:
        LOGGER.severe("Received unexpected ServerKeyExchange message in NULL key exchange mode.");
        break;
      default:
        LOGGER.severe("Unknown key exchange algorithm: " + keyExchange);
        break;
      }
     
      break;

    case CERTIFICATE_REQUEST:
      body = CertificateRequest.fromByteArray(bytesLeft);
      break;

    case SERVER_HELLO_DONE:
      body = new ServerHelloDone();
      break;

    case CERTIFICATE_VERIFY:
      body = CertificateVerify.fromByteArray(bytesLeft);
      break;

    case CLIENT_KEY_EXCHANGE:
      switch (keyExchange) {
      case EC_DIFFIE_HELLMAN:
        body = ECDHClientKeyExchange.fromByteArray(bytesLeft);
        break;
      case PSK:
        body = PSKClientKeyExchange.fromByteArray(bytesLeft);
        break;
      case NULL:
        body = NULLClientKeyExchange.fromByteArray(bytesLeft);
        break;

      default:
        LOGGER.severe("Unknown key exchange algorithm: " + keyExchange);
        break;
      }
     
      break;

    case FINISHED:
      body = Finished.fromByteArray(bytesLeft);
      break;

    default:
      LOGGER.severe("Unknown handshake type: " + type);
      break;
    }

    body.setFragmentLength(fragmentLength);
    body.setFragmentOffset(fragmentOffset);
    body.setMessageSeq(messageSeq);

    return body;
  }

  // Getters and Setters ////////////////////////////////////////////

  public int getMessageSeq() {
    return messageSeq;
  }

  public void incrementMessageSeq() {
    messageSeq++;
  }

  public int getFragmentOffset() {
    return fragmentOffset;
  }

  public int getFragmentLength() {
    return fragmentLength;
  }

  public void setFragmentLength(int length) {
    this.fragmentLength = length;
  }

  public void setMessageSeq(int messageSeq) {
    this.messageSeq = messageSeq;
  }

  public void setFragmentOffset(int fragmentOffset) {
    this.fragmentOffset = fragmentOffset;
  }

}
TOP

Related Classes of ch.ethz.inf.vs.scandium.dtls.HandshakeMessage

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.