//////////////////////////////////////////////////////////////////////////// 
// 
// Copyright (C) DSTC Pty Ltd (ACN 052 372 577) 1993, 1994, 1995.
// Unpublished work.  All Rights Reserved.
// 
// The software contained on this media is the property of the
// DSTC Pty Ltd.  Use of this software is strictly in accordance
// with the license agreement in the accompanying LICENSE.DOC 
// file. If your distribution of this software does not contain 
// a LICENSE.DOC file then you have no rights to use this 
// software in any manner and should contact DSTC at the address 
// below to determine an appropriate licensing arrangement.
// 
//      DSTC Pty Ltd
//      Level 7, GP South
//      University of Queensland
//      St Lucia, 4072
//      Australia
//      Tel: +61 7 3365 4310
//      Fax: +61 7 3365 4311
//      Email: jcsi@dstc.qut.edu.au
// 
// This software is being provided "AS IS" without warranty of
// any kind.  In no event shall DSTC Pty Ltd be liable for
// damage of any kind arising out of or in connection with
// the use or performance of this software.
// 
//////////////////////////////////////////////////////////////////////////// 

package com.dstc.security.kerberos.v5;

import java.util.Vector;
import java.util.Enumeration;

import com.dstc.security.kerberos.v5.base.*;

import com.dstc.security.asn1.Asn1;
import com.dstc.security.asn1.Asn1Exception;
import com.dstc.security.asn1.Explicit;
import com.dstc.security.asn1.Sequence;

/**
 * <p>A class representing the Kerberos ASN.1 structure EncKrbCredPart.
 *
 * <pre>
 *   EncKrbCredPart ::= [APPLICATION 29]  SEQUENCE {
 *  ticket-info[0]      SEQUENCE OF KrbCredInfo,
 *                        nonce[1]      INTEGER OPTIONAL,
 *                        timestamp[2]        KerberosTime OPTIONAL,
 *                        usec[3]             INTEGER OPTIONAL,
 *                        s-address[4]        HostAddress OPTIONAL,
 *                        r-address[5]        HostAddress OPTIONAL
 *                      }
 * </pre>
 */
public final class EncKrbCredPart extends Explicit 
{
  public static final int TAG_KRB_ENC_KRB_CRED_PART = 29;
  private Vector credsInfo;      // Vector of KrbCredInfo
  private int nonce = 0;  // valid nonce should not be 0
  private KerberosTime timestamp;
  private int usec = 0;  
  private HostAddress s_address;
  private HostAddress r_address;

  /**
   * Constructs an EncKrbCredPart using the current system time. 
   *
   * @param credsInfo KrbCredInfo of all the credentials to be forwarded
   * @param nonce   Random nonce, 0 means no nonce 
   * @param s_addr  Address of sender, optional, i.e. could be null
   * @param r_addr  Address of receiver, optional, i.e. could be null
   */
  public EncKrbCredPart(Vector credsInfo, int nonce, String s_addr, 
                        String r_addr) 
  {
    super(Asn1.TAG_CLASS_APPLICATION, TAG_KRB_ENC_KRB_CRED_PART);

    Sequence seq = new Sequence();

    this.credsInfo = credsInfo;
    CredInfoSeq credInfoSeq = new CredInfoSeq(credsInfo);
    Explicit exp = new Explicit(Asn1.TAG_CLASS_CONTEXT, 0);
    exp.addComponent(credInfoSeq);
    seq.addComponent(exp);

    this.nonce = nonce;
    if (nonce != 0) 
    {
      exp = new Explicit(Asn1.TAG_CLASS_CONTEXT, 1);
      exp.addComponent(new com.dstc.security.asn1.Integer(nonce));
      seq.addComponent(exp);
    }

    this.timestamp = new KerberosTime();
    exp = new Explicit(Asn1.TAG_CLASS_CONTEXT, 2);
    exp.addComponent(timestamp);
    seq.addComponent(exp);

    this.usec = 0;   // no finer granularity for time in this implementation
    exp = new Explicit(Asn1.TAG_CLASS_CONTEXT, 3);
    exp.addComponent(new com.dstc.security.asn1.Integer(usec));
    seq.addComponent(exp);

    if (s_address != null) 
    {
      this.s_address = new HostAddress(s_addr);
      exp = new Explicit(Asn1.TAG_CLASS_CONTEXT, 4);
      exp.addComponent(this.s_address);
      seq.addComponent(exp);
    }

    if (r_address != null) 
    {
      this.r_address = new HostAddress(r_addr);
      exp = new Explicit(Asn1.TAG_CLASS_CONTEXT, 5);
      exp.addComponent(this.r_address);
      seq.addComponent(exp);
    }

    addComponent(seq);
  }

  /**
   * Constructs an EncKrbCredPart from a DER encoding
   */
  public EncKrbCredPart(byte encoded[]) throws Asn1Exception 
  {
    doDecode(encoded);
   
    if (getTagNumber() != TAG_KRB_ENC_KRB_CRED_PART)
      throw new Asn1Exception("Bad Tag Number");
 
    Sequence seq = (Sequence)this.getComponent();
    Enumeration comps = seq.getComponents().elements();

    Explicit exp = (Explicit)comps.nextElement();
    CredInfoSeq infoSeq = new CredInfoSeq(exp.getComponent().encode());
    credsInfo = infoSeq.credsInfo;

    int prevTag = 0, tag;
    while (comps.hasMoreElements()) {
      exp = (Explicit) comps.nextElement();

      tag = exp.getTagNumber();
      if (tag <= prevTag) throw new Asn1Exception("Sequence out of order");
      prevTag = tag;

      switch (tag) {
      case 1:
        nonce = ((com.dstc.security.asn1.Integer)exp.getComponent()).getInt();
break;
      case 2:
        timestamp = new KerberosTime(exp.getComponent().encode());
        break;
      case 3:
        usec = ((com.dstc.security.asn1.Integer)exp.getComponent()).getInt();
        break;
      case 4:
        s_address = new HostAddress(exp.getComponent().encode());
break;
      case 5:
r_address = new HostAddress(exp.getComponent().encode());
break;
      default:
throw new Asn1Exception("Invalid context tag number in sequence");
      }
    }
  }

  /**
   * Returns the Vector of KrbCredInfo containing tickets information
   * corresponding to the Vector of Tickets in the KrbCred message owning this
   * EncKrbCredPart
   */
  public Vector getCredsInfo() 
  {
    return credsInfo;
  }

  /**
   * Returns the nonce, a nonce value of 0 is considered not good enough
   */
  public int getNonce() 
  {
    return nonce;
  }

  /**
   * Returns the timestamp which is always included in this implementation
   */
  public KerberosTime getTimestamp() 
  {
    return timestamp;
  }

  /**
   * Returns the microsecond part of the timestamp
   */
  public int getUsec() 
  {
    return usec;
  }

  /**
   * Returns the sender's address if present, null is returned otherwise
   */
  public HostAddress getSenderAddress() 
  {
    return s_address;
  }

  /**
   * Returns the receiver's address if present, null is returned otherwise
   */
  public HostAddress getReceiverAddress() 
  {
    return r_address;
  }

  /**
   * An inner class representing the structure SEQUENCE OF KrbCredInfo
   */
  protected class CredInfoSeq extends Sequence 
  {
    protected Vector credsInfo; // Vector of CredentialInfo objects

    /**
     * Construct a CredInfoSeq from a Vector of KrbCredInfo
     */
    protected CredInfoSeq(Vector credsInfo) 
    {
      KrbCredInfo info;

      this.credsInfo = credsInfo;
      for (int i = 0; i < credsInfo.size(); i++) 
      {
info = (KrbCredInfo)credsInfo.elementAt(i);
addComponent(info);
      }
    }

    /**
     * Construct a CredInfoSeq from a DER encoding
     */
    protected CredInfoSeq(byte[] encoded) throws Asn1Exception 
    {
      doDecode(encoded);

      credsInfo = new Vector(components.size());
      for (int i = 0; i < components.size(); i++) 
      {
KrbCredInfo info;

info = new KrbCredInfo(((Asn1)components.elementAt(i)).encode());
credsInfo.addElement(info);
      }
    }
  }
}
