/*
 * <insert one-line description of what the program does>
 * Copyright (c) <2008-2009>, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include "GUI/error.h"
#include "ConnMgmt/BootCert.h"


#define PUBKEYLEN 				284 
#define CA_certificate_DATA_LEN			1505
#define CA_PACKET_HEAD_LEN		5

#define AUTO_PACKET_LEN				( 1505 + 284 + 284 + 20 )
#define PROVISION_NUMBER_LEN			20
#define DEFAULT_ROOT_CA_FILE 			"/home/student/cacert.cer" 

#define CA_PACKET_ERRCODE_OFFSET		0
#define	CA_PACKET_Actived_FLAG_OFFSET		1
#define	CA_PACKET_PACKET_TYPE_OFFSET		2
#define	CA_PACKET_LEN_OFFSET			3

#define AUTO_PROVISION_PACKET_certificate_OFFSET   	5
#define AUTO_PROVISION_PACKET_ServerPKCert_OFFSET   	(5 + 1505 )
#define AUTO_PROVISION_PACKET_IntelPKCert_OFFSET      	(5 + 1505 + 284 )
#define CA_PACKET_SPECIEL_NUMBER_OFFSET			(5 + 1505 + 284 + 284  )

#define PACKET_TYPE_NO_PACKET				0
#define PACKET_TYPE_AUTO_PACKET				1
#define PACKET_TYPE_CA_PACKET				2


int ParseHttpPacket(unsigned char* bzData, int bzdata_length, BootCert * pBootCert, unsigned char *ServerPKCert, unsigned char *IntelPKCert);

/* Description: open ca file . If the file does not exsit, create the file. 
 * Module: ConnMgmt module
 * Parameter: 
 *               p_cafilename  ca file name
 * Return Value: if success return the pointer of the opened file, otherwise return NULL
 */

FILE * open_cafile ( char * p_cafilename )
{
	if ( NULL == p_cafilename )
		return NULL;

	char * p_start_pos = p_cafilename;
	char * p_splash = NULL;
	char   dir_name[256]={0};
	DIR *  p_dir = NULL;

	/* check the folder, if it does not exsit then create it*/
	while( p_splash = strchr(p_start_pos,'/') )
	{
		int len = p_splash - p_cafilename ;
		strncpy( dir_name, p_cafilename, len );
#ifdef DEBUG
		printf ("%s \n", dir_name );
#endif
		mkdir ( dir_name ,  0777 ) ;

		p_start_pos = p_splash + 1;
	}

	
	return fopen( p_cafilename, "wb" );
}

/* Description:Write CA certificate into ca file. If the file does not exsit, create the file. 
 * Module: ConnMgmt module
 * Parameter: 
 *               p_cafilename  ca file name
 *		    p_data		CA certificate 
 *               len 		CA certificate  length
 * Return Value: if success return the pointer of the opened file, otherwise return NULL
 */

int write_ca_certificate_data( char * p_cafilename  , char * p_data, int len )
{
 	/* Write CA certificate into ca file */	
	size_t  wrtie_data_bytes = 0;
	FILE * fp = open_cafile( p_cafilename );
	
	if ( NULL == fp )
	{
		return ConnMgmt_OPEN_FILE_Error;
	}
 
  	wrtie_data_bytes = fwrite( p_data, sizeof(unsigned char), len, fp );
	fclose( fp );
	
	if ( wrtie_data_bytes != len )
		return ConnMgmt_WRITEFILE_Error;
	
	/* write the CA file name into TCAgent.ini */
	OtherInfo_CARoot(p_cafilename,"SET");
	return 0;
}

/* Description: Parse AutoProvision Packet or CA Packet
 * Module: ConnMgmt module
 * Parameter: 
 *               bzData           - the auto-provision packet
 *		    bzdata_length - the length of total  bz Data inlude head 
 *               ServerPKCert  - store  the Server Public Key
 *               IntelPKCert     - store  Intel Public key 
 * Return Value: 0 represent SUCCEED, other number represent error code .
 */
int ParseHttpPacket(unsigned char* bzData,  int bzdata_length,BootCert * pBootCert, unsigned char *ServerPKCert, unsigned char *IntelPKCert)
{
	char   cafilename[256] = { 0 };
	char   provision_number[30]={0};

	int     approved=0;
	unsigned short * p_len = NULL;
	unsigned short   packet_len;
	
	/*parameter validity check*/
	if ( NULL == bzData ||NULL==pBootCert
		|| NULL == ServerPKCert 
		||NULL == IntelPKCert 
		|| bzdata_length < CA_PACKET_HEAD_LEN )
		return ConnMgmt_ExceptionStatus_ParameterError;

	if ( bzData[CA_PACKET_ERRCODE_OFFSET] != 0  ) // not successful
	{
		return ConnMgmt_RefuseServiceExceptionReason_HWIDInvalid - 1 + bzData[CA_PACKET_ERRCODE_OFFSET];
	}

	/* save the  Approved flag */
	approved = bzData[CA_PACKET_Actived_FLAG_OFFSET];
	OtherInfo_Actived( &approved,  "SET" );
	
  	/* Get ca filename */
	if ( OtherInfo_CARoot(cafilename, "GET" ) != 0 
		|| strlen( cafilename ) == 0 )
	{
		strcpy( cafilename , DEFAULT_ROOT_CA_FILE );
	}

	/* get data length */
	p_len = ( unsigned short * )( bzData + CA_PACKET_LEN_OFFSET );
	packet_len = ntohs( *p_len );
	
	// parse ca packet
	if (  PACKET_TYPE_CA_PACKET == bzData[CA_PACKET_PACKET_TYPE_OFFSET] )
	{
		pBootCert->CertKind = CAPackage;
		if ( packet_len < CA_certificate_DATA_LEN 
			|| bzdata_length - CA_PACKET_HEAD_LEN < CA_certificate_DATA_LEN )
			return ConnMgmt_ExceptionStatus_ReturnDataInvalidation;
		
		return write_ca_certificate_data( cafilename , 
			bzData + AUTO_PROVISION_PACKET_certificate_OFFSET, 
			CA_certificate_DATA_LEN );
	}
	else if ( PACKET_TYPE_AUTO_PACKET == bzData[CA_PACKET_PACKET_TYPE_OFFSET]) // parse auto packet
	{
		pBootCert->CertKind = AutoProvisionPackage;
		if ( packet_len < AUTO_PACKET_LEN 
			|| bzdata_length - CA_PACKET_HEAD_LEN <  AUTO_PACKET_LEN )
			return ConnMgmt_ExceptionStatus_ReturnDataInvalidation;
		
		/* put Server Public Key into ServerPKCert */
		memcpy( ServerPKCert, (bzData + AUTO_PROVISION_PACKET_ServerPKCert_OFFSET) , PUBKEYLEN );
	
		/*put Intel Public key into IntelPKCert */
		memcpy( IntelPKCert, (bzData + AUTO_PROVISION_PACKET_IntelPKCert_OFFSET) , PUBKEYLEN );

		/*WRITE Provision Number into the TDAgent.ini file.*/
		memcpy(provision_number, bzData + CA_PACKET_SPECIEL_NUMBER_OFFSET, PROVISION_NUMBER_LEN);
		OtherInfo_ProvisionNumber( provision_number, "SET" );
		
		return write_ca_certificate_data( cafilename , 
			bzData + AUTO_PROVISION_PACKET_certificate_OFFSET, 
			CA_certificate_DATA_LEN );
	}
	else if ( PACKET_TYPE_NO_PACKET == bzData[CA_PACKET_PACKET_TYPE_OFFSET])
	{
		pBootCert->CertKind =NoCert;
		return 0;
	}

	return ConnMgmt_ExceptionStatus_ReturnDataInvalidation;
	
}

