/* WCECertificate.java -- implementation of X509Certificate
   Copyright (C) 2009 Mysaifu.com

This file is a part of Mysaifu JVM.

Mysaifu JVM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at
your option) any later version.

Mysaifu JVM is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with Mysaifu JVM; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version.  */


package com.mysaifu.jvm.java.security.provider;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.cert.CertificateException;

public class WCECertificate
    extends gnu.java.security.x509.X509Certificate
{

  /**
   * 証明書の検証結果を示すクラス
   */
  public static class TrustStatus
  {
    private final int errorStatus;

    private final int infoStatus;

    public TrustStatus(int error, int info)
    {
      this.errorStatus = error;
      this.infoStatus = info;
    }

    public int getErrorStatus()
    {
      return this.errorStatus;
    }

    public int getInfoStatus()
    {
      return this.infoStatus;
    }
  }

  /**
   * 証明書チェーン情報
   */
  public static class Chain
  {
    WCEKeyStoreSpi keyStoreSpi;

    final String alias;

    final byte[][] encodedCertificates;

    final int chainErrorStatus;

    final int chainInfoStatus;

    /**
     * 指定された情報に基づき、証明書チェーンを作成する。
     * 
     * @param keyStoreSpi
     *          証明書が格納されているWCEKeyStoreSpi。WCEKeyStoreSpiに格納されていない証明書の場合は
     *          <code>null</code>。
     * @param alias この証明書チェーンの別名。別名が存在しない場合は<code>null</code>。
     * @param encodedCertificates 証明書のDERエンコードデータ
     * @param chainErrorStatus 証明書チェーン検証結果。
     * @param chainInfoStatus 証明書チェーン検証結果の付加情報。
     */
    public Chain(WCEKeyStoreSpi keyStoreSpi, String alias,
                 byte[][] encodedCertificates, int chainErrorStatus,
                 int chainInfoStatus)
    {
      this.keyStoreSpi = keyStoreSpi;
      this.alias = alias;
      this.encodedCertificates = encodedCertificates;
      this.chainErrorStatus = chainErrorStatus;
      this.chainInfoStatus = chainInfoStatus;
    }

    /**
     * 証明書チェーンを WCECertificateの配列として返す。
     * 
     * @return 証明書チェーン。
     */
    public WCECertificate[] getCertificates() throws CertificateException,
        IOException
    {
      WCECertificate[] result = null;
      if (encodedCertificates != null)
        {
          // エンコードされたX509証明書を、WCECertificateに変換する
          result = new WCECertificate[encodedCertificates.length];
          for (int i = 0; i < encodedCertificates.length; ++i)
            {
              byte[] encoded = encodedCertificates[i];
              WCECertificate.TrustStatus ts = null;
              if (i == 0)
                {
                  ts = new WCECertificate.TrustStatus(chainErrorStatus,
                                                      chainInfoStatus);
                }
              result[i] = new WCECertificate(keyStoreSpi, alias, encoded, ts);
            }
        }
      return result;
    }
  }

  /**
   * この証明書を生成したKeyStoreSpi. KeyStoreSpi以外が生成した場合にはnull.
   */
  private final WCEKeyStoreSpi keyStoreSpi;

  private final String alias;

  /**
   * 証明書チェーン全体の検証結果 nullの場合、証明書チェーンの検証結果は不明である。
   */
  private final TrustStatus chainTrustStatus;

  /**
   * インスタンスを作成する
   * 
   * @param keyStoreSpi このインスタンスを生成したKeyStore。存在しない場合は<code>null</code>
   * @param alias KeyStore内でのエイリアス。エイリアスが存在しない場合は<code>null</code>
   * @param encoded DERエンコードされた証明書データ
   * @param chainStatus この証明書を基点とした場合の、証明書チェーン検証結果。不明な場合は<code>null</code>
   */
  WCECertificate(WCEKeyStoreSpi keyStoreSpi, String alias, byte[] encoded,
                 TrustStatus chainStatus) throws CertificateException,
      IOException
  {
    super(new ByteArrayInputStream(encoded));
    this.alias = alias;
    this.keyStoreSpi = keyStoreSpi;
    this.chainTrustStatus = chainStatus;
  }

  WCECertificate(byte[] encoded) throws CertificateException, IOException
  {
    this(null, null, encoded, null);
  }
  /**
   * この証明書を基点とした場合の、証明書チェーン検証結果を返す。現時点で不明な場合は<code>null</code>。
   */
  public TrustStatus getChainTrustStatus()
  {
    return this.chainTrustStatus;
  }

  /**
   * この証明書の元となったCERT_CONTEXT構造体へのポインタを返す。 不明な場合は0を返す。
   */
  int getCertContext() throws CertificateException
  {
    if (this.keyStoreSpi != null)
      {
        return this.keyStoreSpi.getCertContextOf(this);
      }
    return 0;
  }

  /**
   * この証明書のKeyStore内における別名を返す 別名が存在しない場合はnull
   */
  String getAlias()
  {
    return this.alias;
  }
  
  /**
   * この証明書が所属するKeyStoreSpiを返す。
   */
  WCEKeyStoreSpi getKeyStoreSpi()
  {
    return this.keyStoreSpi;
  }
}
