/*                               -*- Mode: C -*- 
 * tcpio.c -- 
 * Copyright (c) 1995 Shaun Savage.
 * All rights reserved.
 *
 * Author          : Shaun Savage
 * Created On      : Sun May  7 17:22:43 1995
 * Last Modified By: Shaun Savage
 * Last Modified On: Sun May  7 17:22:57 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 <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <string.h>
#include "ssl.h"
#include "md5.h"

#ifdef BLOCK_MSG
static int szRead(ssllib* ssl, char* buf, int sz)
   {
   int rslt, done = 0;
   while (!done)
      {
      if ((rslt = TCP2Block(buf, sz, 1, &done, ssl->rfile)) < 0)
	 {
	 return sslError(-1,"");
	 }
      }
   return rslt;
   }
#else
static int szRead(ssllib* ssl, char* buf, int sz)
   {
   int rslt, cnt = 0;
   while (sz)
      {
      if ((rslt = read(ssl->fd, buf, sz)) < 0)
	 return sslError(-2,"");
      if (rslt == 0) break;
      cnt+=rslt;
      sz-=rslt;
      buf+=rslt;
      }
   if (cnt < sz)
      return sslError(-3,"");
   return cnt;
   }
#endif
int rdMsg(ssllib *ssl, u_char *buf, int mlen)
{
  int rslt;
  int sz, msgLen;
  u_char head[4], *padding, *tbuf, pad;
  crypto *crypt = ssl->sid->crypt;
  MD5_CTX md5;
  pad=0;
  if ((rslt = szRead(ssl, head, 4)) <= 0)
    return rslt;
  if (~head[0] & 0x80)
     {
     /* escape */
     return sslError(-99,"Escape");
     }
  head[0] &= ~0x80;
  msgLen = (int) NTOHS(head);
  if (msgLen > mlen)
     return sslError(-4,"");
  pad = head[2];
  sz = msgLen + MD5_LEN + pad;
  if ((tbuf = (u_char*) malloc(sz)) == NULL)
     return sslError(-5,"");
  if ((rslt = szRead(ssl, tbuf, sz)) <= 0)
     {
     free(tbuf);
     return rslt;
     }
  padding = tbuf + (MD5_LEN + msgLen);
  (*crypt->init)(crypt,
		 crypt->mKey,crypt->mkeyLen,
		 crypt->arg,crypt->argLen, DE1);
  (*crypt->update)(crypt, tbuf, tbuf, sz);
  (*crypt->finish)(crypt, padding, 0);
  memcpy(buf,tbuf+(MD5_LEN),msgLen);
  MD5Init(&md5);
  MD5Update(&md5,crypt->rdKey,crypt->keyLen);
  MD5Update(&md5,buf,msgLen);
  MD5Update(&md5,padding, pad);
  MD5Update(&md5,(char*)&ssl->rdSeq, 4);
  MD5Final(&md5);
  free(padding);
  rslt = memcmp(tbuf, md5.digest, MD5_LEN);
  free(tbuf);
  if (rslt != 0)
     return sslError(-7,"");
  return msgLen;
}

int wrMsg(ssllib *ssl, u_char *buf, int len)
{
  int rslt, pad;
  u_char head[4], *tbuf, *padding;
  crypto *crypt = ssl->sid->crypt;
  MD5_CTX md5;
  
  *(short*)head = htons(len);
  head[2] = 0;
  head[3] = 0;
  head[0] |= 0x80;

  pad = len & crypt->padnum;
  pad = (pad)? crypt->padnum - pad + 1 : 0;
  head[2] = pad;
  tbuf = (u_char*) malloc(MD5_LEN+len+pad);
  padding = tbuf+(MD5_LEN+len);
  memset(padding, pad, pad);
  memcpy(tbuf+(MD5_LEN),buf,len);

  MD5Init(&md5);
  MD5Update(&md5,crypt->wrKey,crypt->keyLen);
  MD5Update(&md5,buf,len);
  MD5Update(&md5,padding, pad);
  MD5Update(&md5,(char*)&ssl->wrSeq, 4);
  MD5Final(&md5);
  memcpy(tbuf,md5.digest,MD5_LEN);

  (*crypt->init)(crypt,
		 crypt->mKey,crypt->mkeyLen,
		 crypt->arg,crypt->argLen, EN0);
  (*crypt->update)(crypt, tbuf, tbuf,len+MD5_LEN+pad);
  (*crypt->finish)(crypt, padding, 0);

#ifdef BLOCK_MSG
  if ((rslt = Block2TCP( head, 4, 1, 0, ssl->desc)) <= 0)
     {
#else
  if ((rslt = write(ssl->fd, head, 4)) <= 0)
    {
#endif
    free(tbuf);
    return sslError(-4,"");
    }
#ifdef BLOCK_MSG
  rslt = Block2TCP( tbuf, len+MD5_LEN+pad, 0, 1, ssl->desc);
#else
  rslt = write(ssl->fd, tbuf, len+MD5_LEN+pad);
#endif
  free(tbuf);
  if (rslt < 0)
     rslt = sslError(-4,"");
  return rslt;
}

int rdClrMsg(ssllib* ssl, u_char *buf, int mlen)
   {
   int rslt, sz;
   u_char head[4];
   if ((rslt = szRead(ssl, head, 4)) <= 0)
      return rslt;
   if (~head[0] & 0x80)
      {
      /* escape */
      return sslError(-99,"Escape");
      }
   head[0] &= ~0x80;
   sz = NTOHS(head);
   if (sz > mlen)
      return sslError(-4,"");
   if ((rslt = szRead(ssl, buf, sz)) <= 0)
      return rslt;
   return rslt;
   }

int wrClrMsg(ssllib* ssl, u_char *buf, int len)
   {
   int rslt, fd = ssl->fd;
   u_char head[4];

   *(short*)head = htons(len);
   head[2] = 0;
   head[3] = 0;
   head[0] |= 0x80;
   
#ifdef BLOCK_MSG
   if ((rslt = Block2TCP( head, 4, 1, 0, ssl->desc)) <= 0)
#else
   if ((rslt = write(fd, head, 4)) <= 0)
#endif
      return sslError(-4,"");
#ifdef BLOCK_MSG
   if ((rslt = Block2TCP( buf, len, 0, 1, ssl->desc)) <= 0)
#else   
   if ((rslt = write(fd, buf, len)) <= 0)
#endif
      return sslError(-4,"");
   return rslt;
   }







