//////////////////////////////////////////////////////////////////////////// 
// 
// 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.cms.v1;

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;
import java.security.Security;
import java.security.Signature;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;

import com.dstc.security.asn1.Asn1Exception;
import com.dstc.security.asn1.Sequence;
import com.dstc.security.asn1.SetOf;
import com.dstc.security.asn1.Asn1;
import com.dstc.security.asn1.OctetString;
import com.dstc.security.x509.AlgorithmId;
import com.dstc.security.x509.Attribute;
import com.dstc.security.provider.OID;

/**
 * <p>A class representing the ASN.1 structure SignerInfo.
 *
 * <pre>
 *      SignerInfo ::= SEQUENCE { 
 *        version CMSVersion, 
 *        issuerAndSerialNumber IssuerAndSerialNumber,
 *        digestAlgorithm DigestAlgorithmIdentifier,
 *        signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL,
 *        signatureAlgorithm SignatureAlgorithmIdentifier,
 *        signature SignatureValue,
 *        unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL }
 *   
 *      SignedAttributes ::= SET SIZE (1..MAX) OF Attribute
 *   
 *      UnsignedAttributes ::= SET SIZE (1..MAX) OF Attribute
 *   
 *      Attribute ::= SEQUENCE {
 *        attrType OBJECT IDENTIFIER,
 *        attrValues SET OF AttributeValue }
 *   
 *      AttributeValue ::= ANY
 *   
 *      SignatureValue ::= OCTET STRING
 * </pre>
 *
 * @version 0.98, 98/07/01
 * @author Ming Yung
 */
public final class SignerInfo extends Sequence
{
  private int version = 2;
  private IssuerAndSerialNumber issuer;
  private AlgorithmId digestAlgo;
  private AlgorithmId signatureAlgo;
  private SignedAttributes signedAtts;
  private byte[] signature;

  /**
   * Constructs a SignerInfo
   */
  public SignerInfo(IssuerAndSerialNumber is, AlgorithmId digestAlgo,
                    Set signedAtts, String sigAlgName, byte[] signature)
  {
    try
    {
      addComponent(new com.dstc.security.asn1.Integer(version));
  
      this.issuer = is;
      addComponent(is);
  
      this.digestAlgo = digestAlgo;
      addComponent(digestAlgo);

      this.signedAtts = new SignedAttributes(signedAtts);
      this.signedAtts.setTagNumber(0);
      this.signedAtts.setTagClass(Asn1.TAG_CLASS_CONTEXT);
      addComponent(this.signedAtts);    
  
      if (sigAlgName.equals("SHA-1/DSA"))
        this.signatureAlgo = new AlgorithmId(OID.getAlgOid(sigAlgName), false);
      else
        this.signatureAlgo = new AlgorithmId(OID.getAlgOid(sigAlgName));
      addComponent(this.signatureAlgo);
  
      this.signature = signature;
      addComponent(new OctetString(signature));
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }

  /**
   * Constructs a SignerInfo from a DER encoding
   */
  public SignerInfo(byte encoded[]) throws Asn1Exception
  {
    doDecode(encoded);
    int i = 0;
    
    this.version = 
      ((com.dstc.security.asn1.Integer)components.elementAt(i++)).getInt();

    this.issuer = 
      new IssuerAndSerialNumber(((Asn1)components.elementAt(i++)).encode());

    this.digestAlgo = 
      new AlgorithmId(((Asn1)components.elementAt(i++)).encode());

    //test for presence
    this.signedAtts = 
      new SignedAttributes(((Asn1)components.elementAt(i++)).encode());

    this.signatureAlgo = 
      new AlgorithmId(((Asn1)components.elementAt(i++)).encode());

    this.signature = ((OctetString)components.elementAt(i)).getBytes();
  }

  /**
   * Returns a Set of signed Attributes for this SignerInfo
   */
  public Set getSignedAttributes()
  {
    return this.signedAtts.getAttributes();
  }

  /**
   * Returns the signature for this SignerInfo
   */
  public byte[] getSignature()
  {
    return this.signature;
  }

  /**
   * Returns the digest algorithm for this SignerInfo
   */
  public String getDigestAlgorithm()
  {
    return OID.getAlgName(this.digestAlgo.getOid());
  }

  /**
   * Returns the signature algorithm for this SignerInfo
   */
  public String getSignatureAlgorithm()
  {
    return OID.getAlgName(this.signatureAlgo.getOid());
  }

  /**
   * Returns the IssuerAndSerialNumber for this SignerInfo
   */
  public IssuerAndSerialNumber getIssuerAndSerialNumber()
  {
    return this.issuer;
  }

  /**
   * Returns the byte array of data to be signed
   */
  public byte[] getToBeSigned()
  {
    return this.signedAtts.encode();
  }
}
