/*                               -*- Mode: C -*- 
 * srvhand.c -- 
 * Copyright (c) 1995 Shaun Savage.
 * All rights reserved.
 *
 * Author          : Shaun Savage
 * Created On      : Sun May  7 17:18:29 1995
 * Last Modified By: Shaun Savage
 * Last Modified On: Sun May  7 17:18:36 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"
#include "tcplib.h"

/*#include "srvhand.h"*/

int AuthCLI;

ssllib* srv_init(ssllib* ssl)
   {
   memset((char*)ssl, 0, sizeof(ssllib));
   ssl->server = 1;
   ssl->pubCrypt = (crypto*) malloc(sizeof(crypto));
   CryptCopy(ssl->pubCrypt, &dummyCrypt);
   ssl->cph = (u_long*) malloc(cipherCnt * sizeof(long));
   return 0;
   }

int srv_handshake(ssllib *ssl)
   {
   int  rslt;
   if ((rslt = srv_recvHello(ssl)) < 0)
      return rslt;
   if ((rslt = srv_sendHello(ssl)) < 0)
      return rslt;
   if (!ssl->sid->sidLen)
      {
      if ((rslt = srv_recvMKey(ssl)) < 0)
	 return rslt;
      }
   MakeKeys(ssl);
   if ((rslt = srv_sendVerify(ssl)) < 0)
      return rslt;
   if ((rslt = srv_recvFinish(ssl)) < 0)
      return rslt;
   if (AuthCLI)
      {
      if ((rslt = srv_sendAuth(ssl)) < 0)
	 return rslt;
      if ((rslt = srv_recvAuth(ssl)) < 0)
	 return rslt;
      }
   if ((rslt = srv_sendFinish(ssl)) < 0)
      return rslt;
   return 0;
   }

int srv_recvHello(ssllib *ssl)
   {
   int  len, slen, clen;
   char buf[1024];
   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_CLIENT_HELLO)
      return sslError(ERROR_BAD_PEER,"SSL: Not client hello");
   if (NTOHS(buf+1) != SSL_LIBRARY_VERSION)
      return sslError(ERROR_UNSUPPORTED,"SSL: Wrong Version");
   if (len < 9) 
      return sslError(ERROR_BAD_PEER,"SSL: Protocol error");
   clen = NTOHS(buf+3);
   slen = NTOHS(buf+5);
   ssl->chalLen = NTOHS(buf+7);
   if ((len = selCipher(ssl, (u_long*)(buf+9), clen)) < 0)
      return len;
   ssl->sid =  findSID(ssl, buf+9+clen, slen);
   ssl->chal = Copy(ssl->chal,buf+9+clen+slen,ssl->chalLen);
   return 0;
   }

int srv_sendHello(ssllib *ssl)
   {
   int rslt, len;
   u_char *msg, *ptr;
   sidRec *sid = ssl->sid;
   ssl->cid = (u_char*) malloc(CIDSIZE);
   genRand(ssl->cid,CIDSIZE);
   ssl->cidLen = CIDSIZE;
   len = 11 + ssl->cphLen  + sid->sidLen + ssl->cidLen;
   ptr = msg = (char*) malloc(len);
   *ptr++ = SSL_MT_SERVER_HELLO;
   *ptr++ = ssl->hit;
   *ptr++ = cert->cerType;
   *(short*)ptr   = htons(SSL_LIBRARY_VERSION); ptr+=2;
   *(short*)ptr   = htons(cert->certLen); ptr+=2;
   *(short*)ptr   = htons(ssl->cphLen); ptr+=2;
   *(short*)ptr   = htons(ssl->cidLen); ptr+=2;
   memcpy(ptr,cert->cert,cert->certLen); ptr+=cert->certLen;
   memcpy(ptr,(u_char*)ssl->cph,ssl->cphLen); ptr+=ssl->cphLen;
   memcpy(ptr,ssl->cid,ssl->cidLen); ptr+=ssl->cidLen;
   rslt = wrClrMsg(ssl, msg,len);
   free(msg);
   return rslt;
   }

int srv_recvMKey(ssllib *ssl)
   {
   int rslt, len, clen, klen, alen;
   u_char buf[1024];
   sidRec *sid = ssl->sid;
   crypto *crypt;
   if ((len = rdClrMsg(ssl,buf,1023)) < 0)
      return len;
   if (buf[0] != SSL_MT_CLIENT_MASTER_KEY)
      return sslError(-1,"");
   *(ssl->cph) = NTOHL(buf+1);
   if ((rslt = selCipher(ssl, (u_long*)(buf+1), 4)) <0)
      return rslt;
   crypt = (crypto*) malloc(sizeof(crypto));
   sid->crypt = CryptCopy(crypt, cipherTypes[rslt].crypt );
   clen = NTOHS(buf+5);
   klen = NTOHS(buf+7);
   alen = NTOHS(buf+9);
   sid->clrLen = clen;
   sid->keyLen = clen + klen;
   sid->argLen = alen;
   rslt = (*ssl->pubCrypt->deCrypt)(ssl->pubCrypt,
				    buf+11+clen, 
				    klen+alen);
   sid->key = Copy(sid->key, buf+11, clen + klen);
   sid->arg = Copy(sid->arg, buf+11+clen+klen, alen);
   return 0;
   }

int srv_sendVerify(ssllib *ssl)
   {
   int rslt;
   u_char *msg;
   if ((msg = (u_char*) malloc(1+ssl->chalLen)) == 0)
      return sslError(-1,"");
   msg[0]=SSL_MT_SERVER_VERIFY;
   memcpy(msg+1,ssl->chal,ssl->chalLen);
   rslt = wrMsg(ssl,msg, (ssl->chalLen)+1);
   free(msg);
   return rslt;
   }

int srv_recvFinish(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: client finish error %d", NTOHS(buf+1));
     return sslError(ERROR_BAD_PEER,buf);}
   if (buf[0] != SSL_MT_CLIENT_FINISHED)
      return sslError(ERROR_BAD_PEER,"SSL: Not client finish");
   if ((rslt = chkCID(ssl,  buf+1, rslt - 1))< 0)
      return rslt;
   return 0;
   }

int srv_sendFinish(ssllib *ssl)
   {
   int rslt;
   u_char *msg;
   sidRec *sid = ssl->sid;
   if (!sid->sidLen)
      {
      sid->sid = (u_char*) malloc(32);
      sid->sidLen = 32;
      }
   addSID(sid);
   if ((msg = (u_char*) malloc(1+sid->sidLen)) == 0)
      return sslError(-1,"");
   msg[0]=SSL_MT_SERVER_FINISHED;
   memcpy(msg+1,sid->sid,sid->sidLen);
   rslt = wrMsg(ssl,msg, sid->sidLen+1);
   free(msg);
   return rslt;
   }

int srv_sendAuth(ssllib *ssl)
   {
   int rslt, rlen;
   u_char *msg, *ptr;
   rlen = rand() & 0x1f;
   if (rlen < 16)
      rlen += 16;
   if ((msg = (u_char*) malloc(2+rlen)) == 0)
      return sslError(-1,"");
   ptr = msg+2;
   msg[0]=SSL_MT_REQUEST_CERTIFICATE;
   msg[1]=ssl->authType;
   genRand(ptr,rlen);
   rslt = wrMsg(ssl, msg, rlen+2);
   free(msg);
   return rslt;
   }

int srv_recvAuth(ssllib *ssl)
   {
   int rslt, cType, authLen, certLen;
   char buf[1024];
   if ((rslt = rdMsg(ssl, buf, 1023)) <= 0)
      return rslt;
   if (buf[0] == SSL_MT_ERROR) {
     sprintf(buf,"SSL: Certificate error %d", NTOHS(buf+1));
     return sslError(ERROR_BAD_PEER,buf);}
   if (buf[0] != SSL_MT_CLIENT_CERTIFICATE)
      return sslError(ERROR_BAD_PEER,"SSL: Not client cert");
   cType = buf[1];
   certLen = NTOHS(buf+2);
   authLen = NTOHS(buf+4);
   if ((rslt = chkCert(ssl, cType, buf+6, certLen))< 0)
      return rslt;
   if ((rslt = chkAuth(ssl, ssl->authType, buf+6+certLen, authLen)) < 0)
      return rslt;
   return 1;
   }











