/*                               -*- Mode: C -*- 
 * clihand.c -- 
 * Copyright (c) 1995 Shaun Savage.
 * All rights reserved.
 *
 * Author          : Shaun Savage
 * Created On      : Sun May  7 17:17:13 1995
 * Last Modified By: Shaun Savage
 * Last Modified On: Sun May  7 17:17:20 1995
 * Update Count    : 1
 * Status          : Unknown, Use with caution!
 * PURPOSE
 * 	|>Description of modules purpose<|
 * TABLE OF CONTENTS
 * 
 */

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include "ssl.h"

ssllib * cli_init(ssllib *ssl)
   {
   int i;
   u_long *ptr;
   memset((char*)ssl, 0, sizeof(ssllib));
   ssl->pubCrypt = (crypto*) malloc(sizeof(crypto));
   CryptCopy(ssl->pubCrypt, &dummyCrypt);
   ssl->cphLen = cipherCnt*sizeof(long);
   ssl->cph = (u_long*) malloc(cipherCnt*sizeof(long));
   ptr = ssl->cph;
   for (i=0;i<cipherCnt;i++)
      ptr[i] = cipherTypes[i].type;
   return 0;
   }

int cli_handshake(ssllib *ssl)
   {
   int rslt, done = 0;
   u_char buf[1024];
   if ((rslt = cli_sendHello(ssl)) < 0)
      return rslt;
   if ((rslt = cli_recvHello(ssl)) < 0)
      return rslt;
   MakeKeys(ssl);
   if ((rslt = cli_sendFinish(ssl)) < 0)
      return rslt;
   if ((rslt = cli_recvVerify(ssl)) < 0)
      return rslt;
   while (!done)
      {
      if ((rslt = rdMsg(ssl,buf,1023)) < 0)
	 return rslt;
      switch (buf[0])
	 {
	 case SSL_MT_ERROR:
	    return -1;
	 case SSL_MT_SERVER_FINISHED:
	    if ((rslt = cli_parseFinish(ssl, buf, rslt)) < 0)
	       return rslt;
	    done=1;
	    break;
	 case SSL_MT_REQUEST_CERTIFICATE:
	    if ((rslt = cli_parseAuth(ssl, buf, rslt)) < 0)
	       return rslt;
	    break;
	 default:
	    break;
	 }
      }
   return 0;
   }

int cli_sendHello(ssllib *ssl)
   {
   int rslt, len;
   u_char *msg, *ptr;
   sidRec *sid;
   ssl->chal = (u_char*) malloc(CHALSIZE);
   genRand(ssl->chal,CHALSIZE);
   ssl->chalLen = CHALSIZE;
   sid = ssl->sid = findSID(ssl, NULL , 0);
   len = 9 + ssl->cphLen  + sid->sidLen + ssl->chalLen;
   ptr = msg = (char*) malloc(len);
   *ptr++ = SSL_MT_CLIENT_HELLO;
   *(short*)ptr   = htons(SSL_LIBRARY_VERSION); ptr+=2;
   *(short*)ptr   = htons(ssl->cphLen); ptr+=2;
   *(short*)ptr   = htons(sid->sidLen); ptr+=2;
   *(short*)ptr   = htons(ssl->chalLen); ptr+=2;
   memcpy(ptr,(u_char*)ssl->cph,ssl->cphLen); ptr+=ssl->cphLen;
   memcpy(ptr,sid->sid,sid->sidLen); ptr+=sid->sidLen;
   memcpy(ptr,ssl->chal,ssl->chalLen); ptr+=ssl->chalLen;
   rslt = wrClrMsg(ssl, msg,len);
   free(msg);
   return rslt;
   }

int cli_recvHello(ssllib *ssl)
   {
   int rslt, len, certLen, cphLen;
   char cerType, hit, buf[1024], *cipher, *cert;
   if ((len = rdClrMsg(ssl,buf,1023)) < 0)
      return len;
   if (buf[0] == SSL_MT_ERROR) {
      sprintf(buf,"SSL: Protocol error %d", NTOHS(buf+1));
      return sslError(ERROR_BAD_PEER,buf);}
   if (buf[0] != SSL_MT_SERVER_HELLO)
      return sslError(ERROR_BAD_PEER,"SSL: Not server hello");
   if (NTOHS(buf+3) != SSL_LIBRARY_VERSION)
      return sslError(ERROR_UNSUPPORTED,"SSL: Wrong Version");
   if (len < 11) 
      return sslError(ERROR_BAD_PEER,"SSL: Protocol error");
   hit = buf[1];
   cerType = buf[2];
   certLen = NTOHS(buf+5);
   cphLen = NTOHS(buf+7);
   ssl->cidLen = NTOHS(buf+9);
   cert = buf+11;
   cipher =  buf+11+certLen;
   ssl->cid = Copy(ssl->cid,buf+11+certLen+ssl->cphLen,ssl->cidLen);
   if (!hit)
      {
      if ((rslt = chkCert(ssl, cerType,cert,certLen)) < 0)
	 return rslt;
      if ((rslt = selCipher(ssl, (u_long*)cipher, cphLen)) < 0)
	 return rslt;
      ssl->sid->crypt = (crypto*) malloc(sizeof(crypto));
      CryptCopy(ssl->sid->crypt,cipherTypes[rslt].crypt);
      if ((rslt = genMKey(ssl)) < 0)
	 return rslt;
      if ((rslt = cli_sendMKey(ssl)) < 0)
	 return rslt;
      }
   return 0;
   }

int cli_sendMKey(ssllib *ssl)
{
  u_char *msg, *ptr, *cptr;
  int rslt,clrLen,keyLen,argLen,len;
  sidRec *sid = ssl->sid;
  clrLen = sid->clrLen;
  keyLen = sid->keyLen;
  argLen = sid->argLen;
  len = keyLen+argLen;
  ptr = msg = (u_char*) malloc(len + 11);
  if (ptr== NULL)
    return sslError(-1,"SSL: ");
  *ptr++ = SSL_MT_CLIENT_MASTER_KEY;
  memcpy(ptr,ssl->cph, 4); ptr+=4;
  *(short*)ptr = htons(clrLen); ptr+=2;
  *(short*)ptr = htons(keyLen-clrLen); ptr+=2;
  *(short*)ptr = htons(argLen); ptr+=2;
  memcpy(ptr,sid->key,keyLen); 
  cptr = ptr + clrLen; 
  ptr += keyLen;
  memcpy(ptr,sid->arg,argLen); ptr+=argLen;
  rslt = (*ssl->pubCrypt->enCrypt)(ssl->pubCrypt,
				   cptr,
				   keyLen-clrLen+argLen );
  return wrClrMsg(ssl, msg, len+11);
  return 0;
}

int cli_sendFinish(ssllib *ssl)
{
  u_char *msg;
  int rslt;
  if ((msg = (u_char*) malloc(1024)) == NULL)
    return sslError(-1,"SSL: Finish malloc");
  msg[0] = SSL_MT_CLIENT_FINISHED;
  memcpy(msg+1, ssl->cid, ssl->cidLen);
  rslt = wrMsg(ssl,msg,(ssl->cidLen)+1);
  free(msg);
  return rslt;
}

int cli_recvVerify(ssllib *ssl)
   {
  int rslt;
  char buf[1024];
  if ((rslt = rdMsg(ssl,buf,1023)) < 0)
    return rslt;
  if (buf[0] == SSL_MT_ERROR) {
    sprintf(buf,"SSL: Protocol error %d", NTOHS(buf+1));
    return sslError(ERROR_BAD_PEER,buf);}
  if (buf[0] != SSL_MT_SERVER_VERIFY)
    return sslError(ERROR_BAD_PEER,"SSL: Not server verify");
   if ((rslt = chkChal( ssl, buf+1, rslt - 1))< 0)
      return rslt;
  return 0;
   }

int cli_parseFinish(ssllib *ssl, u_char* buf, int len)
   {
   int rslt;
   sidRec *sid = ssl->sid;
   if ((rslt = chkSID(sid, buf+1, len-1))< 0)
      return rslt;
  return 0;
   }

int cli_parseAuth(ssllib *ssl, u_char* buf, int len)
   {
   int rslt;
   if ((rslt = cli_sendAuth( ssl))< 0)
      return rslt;
  return 0;
   }

int cli_sendAuth(ssllib *ssl)
   {
   int rslt, aType, aLen, cType, cLen, len;
   u_char  *buf, msg[255];
/*   aType = ssl->data[1];
   aLen = getAuthLen(aType);
   cLen = getCertLen(ssl->certType);
   Copy( buf, ssl->data+2, aLen);*/
   msg[0]=SSL_MT_CLIENT_CERTIFICATE;
   cLen = mkCert(msg+2,&cType);
   msg[1]=cType;
   mkAuth(msg+2);
   len = cLen + aLen;
   rslt = wrMsg(ssl,msg, len);
   return 0;
   }

int genMKey(ssllib* ssl)
   {
   sidRec * sid = ssl->sid;
   sid->key = (u_char*) malloc(32);
   sid->keyLen = 32;
   sid->arg = (u_char*) malloc(32);
   sid->argLen = 32;
   sid->clrLen = 0;
   genRand(sid->key, 32);
   genRand(sid->arg, 32);
   return 0;
   }





