package jacorb.security;

import java.security.*;
import java.io.*;
import java.security.cert.X509Certificate;

import iaik.security.ssl.*;
import iaik.asn1.*;
import iaik.asn1.structures.Name;
import iaik.security.rsa.*;
import iaik.pkcs.*;
import iaik.utils.KeyAndCertificate;
import iaik.pkcs.pkcs8.EncryptedPrivateKeyInfo;

/**
 * @author André Benvenuti ( bnv ), UGFU, Generalstab, Bern
 * @created 04.11.99
 */

/**
 * SSL client.trust decider is a call back class; it decides if the peer's certificated
 * is supported and to be accepted and is able the return his own certificate chain.
 */
 
public class ORBSSLClientTrustDecider implements ClientTrustDecider {

  private final static boolean DEBUG = false;
  private X509Certificate[] rsa_cert;
  private PrivateKey rsa_private_key;

  private void debug ( String s ) {
    if ( DEBUG ) System.out.println(s);
  }

  /**
   * Create a StubTrustDecider from a client certificate chain and
   * the corresponding private key.
   *
   * @param printDebugInfo if true debug information is printed to System.out
   */
  public ORBSSLClientTrustDecider ( String rsaCertFile,
                                    String passPhrase
                                  )
  {
    KeyAndCertificate kac;
    EncryptedPrivateKeyInfo epki;
    try {
   // set the RSA certificate/private key for RSA cipher suites
      kac = new KeyAndCertificate( rsaCertFile );
      epki = ( EncryptedPrivateKeyInfo )kac.getPrivateKey ();
      epki.decrypt( passPhrase );
      rsa_cert = kac.getCertificateChain ();
      rsa_private_key = epki.getPrivateKeyInfo ();
    } catch ( Exception ex ) {
      System.out.println( "Unable to set RSA client certificate.");
    }
  }

  /**
   * This method is called during the SSL handshake procedure to
   * decide if the certificate sent by the server is trusted.
   *
   * If this method returns false the SSL connection is terminated
   * with a fatal bad certificate error.
   *
   * @param certificat the certificate chain sent by the server
   * @return true, if the server certificate is trusted; false otherwise
   */
  public boolean isTrustedPeer( SSLCertificate certificate )
  {
    if ( certificate == null ) return false;
    X509Certificate[] certChain = certificate.getCertificateChain ();
    debug ( "Checking Server certificate chain ..." );
    for ( int i = 0; i < certChain.length; i++ )
     debug ( certChain[ i ].getSubjectDN ().toString ());
    return CertificatesManager.verifyCertificateChain ( certChain );
  }

  /**
   * Returns a client certificate.
   *
   * If a SSL server requieres a client certificate it sends a
   * CertificateRequest message.
   * This message also includes a list of requiered certificate
   * types and a list oft accepted certification authorities
   * ( subject or issuer of self signed top level CAs ).
   *  If now a client SSLSocket receives such a message it calls
   * this method to get a certificate which can be sendet back to
   * the server.
   *
   * @param certificateTypes the certificate types the server requieres
   * @param certificateAuthorities the certification authorities the server accepts
   * @param keyExchangeAlgorithm the currently active key exchange algorithm (from cipher suite)
   * @return the client certificate list
   */
  public SSLCertificate getCertificate( byte[] certificateTypes,
                  Principal[] certificateAuthorities, String keyExchangeAlgorithm)
  {
    debug( "Key exchange algorithm: " + keyExchangeAlgorithm );
    if ( keyExchangeAlgorithm.startsWith ( "RSA" )) {
      debug ( "return RSA certificate..." );
      return new SSLCertificate ( rsa_cert );
    }
    debug ( "have none of requested certificate types..." );
    return null;
  }

  /**
   * Returns the private key belonging to the certificate.
   *
   * @return the private key specified in the constructor
   */
  public PrivateKey getPrivateKey() {
    return rsa_private_key;
  }
}

