#include "config.h"
#ifdef HAVE_SSL

#include "ssl.h"
#include "common.h"
#include "ircd.h"
#include "client.h"
#include "s_log.h"
#include "s_bsd.h"

/* The SSL structures */
SSL_CTX* ctx;
SSL_METHOD* meth;
void init_ssl() {
    /* SSL preliminaries. We keep the certificate and key with the context. */

  SSL_load_error_strings();
  SSLeay_add_ssl_algorithms();
  meth = SSLv23_server_method();
  ctx = SSL_CTX_new (meth);
       if (!ctx)
         {
               ERR_print_errors_fp (stderr);
               exit (2);
         }

       if (SSL_CTX_use_certificate_file (ctx, CERTF, SSL_FILETYPE_PEM) <= 0)
         {
            log(L_ERROR, "Failed to load SSL certificate %s, SSL disabled", CERTF);
            no_ssl = -1;
            return;
         }
       if (SSL_CTX_use_PrivateKey_file (ctx, KEYF, SSL_FILETYPE_PEM) <= 0)
         {
            log(L_ERROR, "Failed to load SSL private key %s, SSL disabled", KEYF);
            no_ssl = -1;            
            return;
         }

       if (!SSL_CTX_check_private_key (ctx))
         {
               fprintf (stderr, "Private key does not match the certificate public key\n");
               exit (5);
         }

}

#define CHK_NULL(x) if ((x)==NULL) {\
        log(L_NOTICE, "Lost connection to %s:Error in SSL", \
                     get_client_name(cptr, TRUE)); \
	return 0;\
	}

int ssl_handshake(struct Client *cptr) {

  char *str;
  int err;

      cptr->ssl = (struct SSL*) SSL_new (ctx);
      CHK_NULL (cptr->ssl);
      SSL_set_fd ((SSL *)cptr->ssl, cptr->fd);
      err = SSL_accept ((SSL *)cptr->ssl);
      if ((err)==-1) {
        log(L_NOTICE,"Lost connection to %s:Error in SSL_accept()", 
                     get_client_name(cptr, TRUE));
        return 0;
      }

      /* Get the cipher - opt */
      SetSecure(cptr);
      
      log (L_DEBUG, "SSL connection using %s", SSL_get_cipher ((SSL *)cptr->ssl));

      /* Get client's certificate (note: beware of dynamic
       * allocation) - opt */

      cptr->client_cert = (struct X509*)SSL_get_peer_certificate ((SSL *)cptr->ssl);

      if (cptr->client_cert != NULL)
      {
        log (L_DEBUG,"Client certificate:");

        str = X509_NAME_oneline (X509_get_subject_name ((X509*)cptr->client_cert), 0, 0);
        CHK_NULL (str);
        log (L_DEBUG, "\t subject: %s", str);
        // Bejvavalo
 	//       Free (str);
	free(str);
	
        str = X509_NAME_oneline (X509_get_issuer_name ((X509*)cptr->client_cert), 0, 0);
        CHK_NULL (str);
        log (L_DEBUG, "\t issuer: %s", str);
        // Bejvavalo
        // Free (str);
	free(str);
	
        /* We could do all sorts of certificate
         * verification stuff here before
         *        deallocating the certificate. */

        X509_free ((X509*)cptr->client_cert);
      }
      else
        log (L_DEBUG, "Client does not have certificate.");

      return 1;

}

int ssl_client_handshake(struct Client *cptr) {

  char *str;
  int err;

  cptr->ssl = (struct SSL*)SSL_new (ctx);                         CHK_NULL(cptr->ssl);    
  SSL_set_fd ((SSL*)cptr->ssl, cptr->fd);
  set_blocking(cptr->fd);
  err = SSL_connect ((SSL*)cptr->ssl);                     
  set_non_blocking(cptr->fd);
  if ((err)==-1) {
     log(L_NOTICE,"Could connect to %s:Error in SSL_connect()", 
                  get_client_name(cptr, TRUE));
     return 0;
     }
    
  /* Following two steps are optional and not required for
     data exchange to be successful. */
  
  /* Get the cipher - opt */
  set_blocking(cptr->fd);
  log (L_NOTICE,"SSL connection using %s", SSL_get_cipher ((SSL*)cptr->ssl));
  
  
  SetSecure(cptr);      
  /* Get server's certificate (note: beware of dynamic allocation) - opt */

  cptr->client_cert = (struct X509*)SSL_get_peer_certificate ((SSL *)cptr->ssl);
  set_non_blocking(cptr->fd);

  if (cptr->client_cert != NULL)
    {
      log (L_NOTICE,"Server certificate:");
  
      str = X509_NAME_oneline (X509_get_subject_name ((X509*)cptr->client_cert),0,0);
      CHK_NULL(str);
      log (L_NOTICE, "\t subject: %s", str);
      // Free (str);
      free (str);
  
      str = X509_NAME_oneline (X509_get_issuer_name  ((X509*)cptr->client_cert),0,0);
      CHK_NULL(str);
      log (L_NOTICE, "\t issuer: %s", str);
      // Free (str);
      free (str);
      /* We could do all sorts of certificate verification stuff here before
      deallocating the certificate. */

      X509_free ((X509*)cptr->client_cert);

    }
    else
      log (L_NOTICE, "Server does not have certificate.");
      
  
  return 1;
}
#endif
