/* WCETrustManagerFactory.java
   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.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.net.ssl.ManagerFactoryParameters;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactorySpi;
import javax.net.ssl.TrustManagerFactorySpi;
import javax.net.ssl.X509TrustManager;

/**
 * TrustManager implementation for Windows CE device.
 */
public class WCETrustManagerFactorySpi
    extends TrustManagerFactorySpi
{
  @Override
  protected void engineInit(KeyStore ks)
  {
    // キーストアは使わない（WCESSLEngineはシステムにインストールされている証明書を使う）
    if (ks != null)
      {
        System.err.println("WARNING:TrustManagerFactory " + getClass().getName() + " uses system certificate store"
                           + " instead of specified KeyStore " + ks.getType());
      }
  }

  @Override
  protected void engineInit(ManagerFactoryParameters spec)
  {
    // Do nothing.
  }

  @Override
  protected TrustManager[] engineGetTrustManagers()

  {
    return new TrustManager[] { getDefaultTrustManager() };
  }

  /**
   * デフォルトのTrustManagerを返す
   */
  static X509TrustManager getDefaultTrustManager()
  {
    return new WCETrustManager();
  }

  private static class WCETrustManager
      implements X509TrustManager
  {
    /**
     * dwErrorStatus定数
     */
    private static final int CERT_TRUST_NO_ERROR = 0x00000000;

    private static final int CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001;

    private static final int CERT_TRUST_IS_NOT_TIME_NESTED = 0x00000002;

    private static final int CERT_TRUST_IS_REVOKED = 0x00000004;

    private static final int CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008;

    private static final int CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010;

    private static final int CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020;

    private static final int CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040;

    private static final int CERT_TRUST_IS_CYCLIC = 0x00000080;

    private static final int CERT_TRUST_INVALID_EXTENSION = 0x00000100;

    private static final int CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200;

    private static final int CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400;

    private static final int CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800;

    private static final int CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000;

    private static final int CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000;

    private static final int CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000;

    private static final int CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000;

    private static final int CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000;

    private static final int CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000;

    private static final int CERT_TRUST_IS_PARTIAL_CHAIN = 0x00010000;

    private static final int CERT_TRUST_CTL_IS_NOT_TIME_VALID = 0x00020000;

    private static final int CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID = 0x00040000;

    private static final int CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE = 0x00080000;

    /**
     * dwInfoStatus定数
     */
    private static final int CERT_TRUST_HAS_EXACT_MATCH_ISSUER = 0x00000001;

    private static final int CERT_TRUST_HAS_KEY_MATCH_ISSUER = 0x00000002;

    private static final int CERT_TRUST_HAS_NAME_MATCH_ISSUER = 0x00000004;

    private static final int CERT_TRUST_IS_SELF_SIGNED = 0x00000008;

    private static final int CERT_TRUST_HAS_PREFERRED_ISSUER = 0x00000100;

    private static final int CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY = 0x00000200;

    private static final int CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS = 0x00000400;

    private static final int CERT_TRUST_IS_COMPLEX_CHAIN = 0x00010000;

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
      checkTrusted(chain, authType);

    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
      checkTrusted(chain, authType);
    }

    /**
     * 証明書が信頼されているかをチェックする
     */
    private void checkTrusted(X509Certificate[] chain, String authType)
        throws CertificateException
    {
      if (chain == null || chain.length <= 0)
        {
          throw new IllegalArgumentException("chain==null || chain.length <= 0");
        }
      if (authType == null || authType.length() <= 0)
        {
          throw new IllegalArgumentException(
                                             "authType==null || authType.length() <= 0");
        }

      X509Certificate cert = chain[0];
      if (! (cert instanceof WCECertificate))
        {
          // WCECertificateしかサポートしていない
          throw new UnsupportedOperationException(
                                                  "Unsupported certificate class: "
                                                      + cert.getClass().getName());
        }
      WCECertificate wcert = (WCECertificate) cert;
      WCECertificate.TrustStatus ts = wcert.getChainTrustStatus();
      if (ts == null)
        {
          throw new CertificateException("TrustStatus is null");
        }
      if (ts.getErrorStatus() != 0)
        {
          throw new CertificateException(
                                         "dwErrorStatus=0x"
                                             + Integer.toHexString(ts.getErrorStatus())
                                             + " dwInfoStatus=0x"
                                             + Integer.toHexString(ts.getInfoStatus()));

        }
    }

    @Override
    public X509Certificate[] getAcceptedIssuers()
    {
      List<X509Certificate> result = new ArrayList<X509Certificate>();

      // "ROOT"ストア上の全証明書を返す
      try{
        KeyStore keyStore = KeyStore.getInstance(WCESecurity.ROOT_KEY_STORE_TYPE);
        Enumeration<String> e = keyStore.aliases();
        while (e.hasMoreElements())
          {
            String alias = e.nextElement();
            result.add((X509Certificate) keyStore.getCertificate(alias));
          }
      }
      catch (KeyStoreException ke)
      {
        ke.printStackTrace();
      }
      
      return result.toArray(new X509Certificate[result.size()]);
    }
  }
}
