/* ***************************************************************** *
 * Copyright 1998 International Business Machines Corporation. All   *
 * Rights Reserved.                                                  *
 *                                                                   *
 * Please read this carefully.  Your use of this reference           *
 * implementation of certain of the IETF public-key infrastructure   *
 * specifications ("Software") indicates your acceptance of the      *
 * following.  If you do not agree to the following, do not install  *
 * or use any of the Software.                                       *
 *                                                                   *
 * Permission to use, reproduce, distribute and create derivative    *
 * works from the Software ("Software Derivative Works"), and to     *
 * distribute such Software Derivative Works is hereby granted to    *
 * you by International Business Machines Corporation ("IBM").  This *
 * permission includes a license under the patents of IBM that are   *
 * necessarily infringed by your use of the Software as provided by  *
 * IBM.                                                              *
 *                                                                   *
 * IBM licenses the Software to you on an "AS IS" basis, without     *
 * warranty of any kind.  IBM HEREBY EXPRESSLY DISCLAIMS ALL         *
 * WARRANTIES OR CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING,   *
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF       *
 * MERCHANTABILITY, NON INFRINGEMENT AND FITNESS FOR A PARTICULAR    *
 * PURPOSE.  You are solely responsible for determining the          *
 * appropriateness of using this Software and assume all risks       *
 * associated with the use of this Software, including but not       *
 * limited to the risks of program errors, damage to or loss of      *
 * data, programs or equipment, and unavailability or interruption   *
 * of operations.                                                    *
 *                                                                   *
 * IBM WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, *
 * INCIDENTAL, OR  INDIRECT DAMAGES OR FOR ANY ECONOMIC              *
 * CONSEQUENTIAL DAMAGES (INCLUDING LOST PROFITS OR SAVINGS), EVEN   *
 * IF IBM HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  IBM  *
 * will not be liable for the loss of, or damage to, your records or *
 * data, or any damages claimed by you based on a third party claim. *
 *                                                                   *
 * IBM wishes to obtain your feedback to assist in improving the     *
 * Software.  You grant IBM a world-wide, royalty-free right to use, *
 * copy, distribute, sublicense and prepare derivative works based   *
 * upon any feedback, including materials, error corrections,        *
 * Software Derivatives, enhancements, suggestions and the like that *
 * you provide to IBM relating to the Software (this does not        *
 * include products for which you charge a royalty and distribute to *
 * IBM under other terms and conditions).                            *
 *                                                                   *
 * You agree to distribute the Software and any Software Derivatives *
 * under a license agreement that: 1) is sufficient to notify all    *
 * licensees of the Software and Software Derivatives that IBM       *
 * assumes no liability for any claim that may arise regarding the   *
 * Software or Software Derivatives, and 2) that disclaims all       *
 * warranties, both express and implied, from IBM regarding the      *
 * Software and Software Derivatives.  (If you include this          *
 * Agreement with any distribution of the Software or Software       *
 * Derivatives you will have met this requirement.)  You agree that  *
 * you will not delete any copyright notices in the Software.        *
 *                                                                   *
 * This Agreement is the exclusive statement of your rights in the   *
 * Software as provided by IBM.   Except for the rights granted to   *
 * you in the second paragraph above, You are not granted any other  *
 * patent rights, including but not limited to the right to make     *
 * combinations of the Software with products that infringe IBM      *
 * patents. You agree to comply with all applicable laws and         *
 * regulations, including all export and import laws and regulation. *
 * This Agreement is governed by the laws of the State of New York.  *
 * This Agreement supersedes all other communications,               *
 * understandings or agreements we may have had prior to this        *
 * Agreement.                                                        *
 * ***************************************************************** */

/*
 *
 * jcrtreq.cpp - This file contains JNH_... routines to handle Certificate
 *               Requests (certreq) inquires and sets.  In most cases, a
 *               certreq is created as part of the preregister process.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <jonah.h>
#include <init.h>
#include <ObjectStore.h>
#include <ObjectDefs.h>
#include <JonahOst.h>
#include <apimsg.h>

// Activating the below #define activates maximum debug babbling
// #define MCDDEBUGON  1
// Activating the below #define activates even more debug babbling!
// #define JCWDEBUGON  1

#if defined(MCDDEBUGON) || defined(JCWDEBUGON)
#define MCDPRINT(x) {printf x ; fflush(stdout);}
#else /* MCDEBUGON */
#define MCDPRINT(x)
#endif /* MCDDEBUGON */

// The following set of local routines are used to get and release the
// records from the object cache.

// GetCertReq  - Get a read only version of the certreq
// DoneWithReq - Release the object and synch if required

#define SET     0
#define INQUIRE 1

// TODO - Handle PKCS requests.  I think this only effects inquire/subject
// and subjectkeypresent and friends.  There isnt anything else interesting
// in a PKCS 10 request

static uint32 GetCertReq(uint32 reqId,
			  CertReqMsg ** certReqMsg,
			  uint32 * objClass,
			  uint32 set_or_inquire)
{
  const ObjStoreData * cobjsPtr=NULL;
  ObjStoreData *  objsPtr=NULL;
  uint32 status=0;
  MCDPRINT(("Begin GetCertReq.\n"));

// Get the object
  status=JnhGetObject(reqId, objClass,&cobjsPtr);

  if (cobjsPtr!=NULL) {
    MCDPRINT(("Message %d was %d.\n",reqId,cobjsPtr->msg.value.selected() ));
// Check various things here

#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("Retrieved (certreq) object %d. details:\n", reqId));
      cobjsPtr->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif
  }

  if (  (*objClass & ObjClTypeCert)!=0  // This is a cert request
      &&(status==0)
      &&(cobjsPtr!=NULL)
      &&(  (cobjsPtr->msg.value.selected()==OBJ_MSG_CERTREQ)
	 ||(cobjsPtr->msg.value.selected()==OBJ_MSG_IREQ)
	)
     )
  {
// Record is good
//
// This is where it is hardcoded that only one certrequest
// can be in a certrequest message
//
    if ( cobjsPtr->msg.value.selected()==OBJ_MSG_CERTREQ )
    {
      *certReqMsg=cobjsPtr->msg.value.certreq.value.get_child(0);
    } 
    else if ( cobjsPtr->msg.value.selected()==OBJ_MSG_IREQ )
    {
      *certReqMsg=cobjsPtr->msg.value.ireq.value.get_child(0);
    }
    else // dont understand this message
    {
      status=API_UNSUPPORTED_MESSAGE_TYPE;
      *certReqMsg=NULL;
    }
    if ( *certReqMsg==NULL)
       {
       MCDPRINT(("Message Missing from object.\n"));
       status=API_UNSUPPORTED_MESSAGE_TYPE;
       cobjsPtr=NULL;
       *certReqMsg=NULL;
       *objClass=0;
       }
  }
  else
  {
// Record is not what we were looking for
// Even so, we don't unlock the record
// status=JnhUnlockObject(reqId);
// We don't care if the unlock really worked, we have no recourse
    
    status=API_WRONG_OBJTYPE;
    cobjsPtr=NULL;
    *certReqMsg=NULL;
    *objClass=0;
  }
  if ( (status==0) && (set_or_inquire == SET) )
  {
// Flag the record as modified
    status=JnhGetObjectModify(reqId, objClass,&objsPtr);
    if ( objsPtr != cobjsPtr )
    {
      MCDPRINT(("Get and GetModify Pointers not equal"));
    }
  }
  else
  {
// We dont need to do anything
  }
  return status;
}

static uint32 GetCertRepCert(uint32 reqId,
			  Certificate ** certRepCert,
			  uint32 * objClass,
			  uint32 set_or_inquire)
{
  const ObjStoreData * cobjsPtr=NULL;
  CertRepMessage * certRepMsg;
  CertResponse * certresp;
  uint32 status=0;

  MCDPRINT(("Begin GetCertRepCert.\n"));
  if ( set_or_inquire == INQUIRE)
  {
    status=JnhGetObject(reqId, objClass,&cobjsPtr);
  }
  else
  {
// You can only inquire on certreps
    status=-1;   /*HCODE*/
    MCDPRINT(("Tried to set %d, which was a Reply.\n",reqId));
  }

  if (cobjsPtr!=NULL) {
	MCDPRINT(("Message %d was %d.\n",reqId,cobjsPtr->msg.value.selected() ));
#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("Retrieved (certrep) object %d. details:\n", reqId));
      cobjsPtr->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif
  }
// Check various things here
  if (  (*objClass & ObjClTypeCert)!=0  // This is a cert request
      &&(status==0)
      &&(cobjsPtr!=NULL)
      &&(  (cobjsPtr->msg.value.selected()==OBJ_MSG_CERTREP)
	 ||(cobjsPtr->msg.value.selected()==OBJ_MSG_IREP)
	)
     )
  {
// Record is good
//
// This is where it is hardcoded that only one certrequest
// can be in a certrequest message
//
    if ( cobjsPtr->msg.value.selected()==OBJ_MSG_CERTREP )
    {
      certresp=cobjsPtr->msg.value.certrep.value.response.get_child(0);
    } 
    else if ( cobjsPtr->msg.value.selected()==OBJ_MSG_IREP )
    {
      certresp=cobjsPtr->msg.value.irep.value.response.get_child(0);
    }
    else // dont understand this message
    {
      status=API_UNSUPPORTED_MESSAGE_TYPE;
      *certRepCert=NULL;
    }
    if (certresp==NULL)
        {
	MCDPRINT(("Message Missing from object.\n"));
        *certRepCert=NULL;
        status=API_UNSUPPORTED_MESSAGE_TYPE;
        }
    else if ( certresp->certifiedKeyPair.certOrEncCert.selected()==1) /*HCODE*/
             {
// TODO - decrypt certificate
               MCDPRINT(("Encrypted Certificate encountered"));
             }
             else
             {
               *certRepCert=&(certresp->certifiedKeyPair.certOrEncCert.certificate.value);
             }
  }
  else
  {
// Record is bad
    MCDPRINT(("CertRep Record is bad!.\n"));
// Even so, dont unlock the record
// status=JnhUnlockObject(reqId);
// We don't care if the unlock really worked, we have no recourse
    status=API_WRONG_OBJTYPE;
    cobjsPtr=NULL;
    *certRepCert=NULL;
    *objClass=0;
  }
  return status;
}

static uint32 DoneWithReq (uint32 reqId, uint32 inquire_or_set)
{
  uint32 status;

   MCDPRINT(("Begin DoneWithReq.\n"));
#ifdef WE_REALLY_WANTED_TO_RELEASE_OBJS
// Dont do anything
  if ( inquire_or_set == INQUIRE)
  {
// Just let it go

#ifdef JCWDEBUGON
    MCDPRINT(("Unlocking object %d\n", reqId));
#endif

    status=JnhUnlockObject(reqId);
  }
  else
  {
// Synch the database

#ifdef JCWDEBUGON
    MCDPRINT(("Saving object %d\n", reqId));
#endif

    status=JnhSynchObject(reqId);
  }
#endif /* WE_REALLY_WANTED_TO_RELEASE_OBJS */
  return status;
}

static uint32 GetExtensions(uint32 reqId,
			  x509_Extensions ** pextensions,
			  uint32 * objClass,
			  uint32 set_or_inquire)
{
  CertReqMsg * certreqmsg = NULL;
  Certificate * certrepcert = NULL;
  uint32 status;

  MCDPRINT(("Begin GetExtensions.\n"));
  status=GetCertReq(reqId,&certreqmsg,objClass,set_or_inquire);

#ifdef MCDDEBUGON
  if (!(certreqmsg->check_encode_flags())) {
    buffer_t buf;
    MCDPRINT(("Encode flags error in getExtensions on initial object:\n"));
    certreqmsg->display_state_flags(buf);
    MCDPRINT(("%.*s", buf.data_len, buf.data));
  }
#endif

  if ( status == 0 )
  {
// This is a certreq and we have the certrep
    *pextensions=&(certreqmsg->certReq.certTemplate.extensions.value);
  }
  else
  {
// This could be a certrep, lets try that
// If this is a SET and a certrep, let GetCertRepCert set rc
    status=GetCertRepCert(reqId,
			  &certrepcert,
			  objClass,
			  set_or_inquire);
    if (status==0)
      *pextensions=&(certrepcert->tbsCertificate.extensions.value);
  }

  if ( status != 0 ) return status;


  if ( *pextensions==NULL)
  {
    DoneWithReq(reqId,INQUIRE);
    status=API_NO_EXTENSIONS;
  }
  return status;
}

EXPORTFN(uint32,
	 JNH_create_certreq,
	 (uint32 * reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_status,
	 (uint32 reqId, 
	  uint32 * status))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 localstatus;

localstatus=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
// If this failed, maybe it is a certRepMessage, so try that
if ( localstatus != 0 ) 
	localstatus=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
if ( localstatus != 0 ) return localstatus;

*status=objClass;
DoneWithReq(reqId,INQUIRE);
return localstatus;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_subjectkey_present,
	 (uint32 reqId,
	  IBOOL * keyPresent))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
unsigned char * p;
uint32 bc;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 )
	{

	bc=0;
	status=certreqmsg->certReq.certTemplate.publicKey.value.
		subjectPublicKey.get_value(p,bc);
	MCDPRINT(("subjectPublicKey.get_value=%d.\n",status));
	MCDPRINT(("Key Bitstring Length=%d.\n",bc));
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		MCDPRINT(("Getting Cert from CertRep.\n"));
		status=certrepcert->tbsCertificate.subjectPublicKeyInfo.
			subjectPublicKey.get_value(p,bc);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}

if ( status==0) *keyPresent=TRUE;
else *keyPresent=FALSE;

DoneWithReq(reqId,INQUIRE);
if ((status==0)||(status=ASN_VALUE_NOT_SET)) return 0;
else return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_subjectkey_algorithm,
	 (uint32 reqId,
	  octetString * algorithm))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
buffer_t buf;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 ) 
	{
	status=certreqmsg->certReq.certTemplate.publicKey.value.
			algorithm.algorithm.get_value(buf);
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		status=certrepcert->tbsCertificate.subjectPublicKeyInfo.
			algorithm.algorithm.get_value(buf);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}
if ( status==0 )
	{
	algorithm->data=(unsigned char *)malloc(buf.data_len);
	if ( algorithm->data != NULL)
		{
		memcpy(algorithm->data,buf.data,buf.data_len);
		algorithm->length=buf.data_len;
		}
	else
		{
		// malloc failed
		status=-1;
		algorithm->length=0;
		algorithm->data=NULL;
		}
	}
DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_subjectkey,
	 (uint32 reqId,
	  octetString * key))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_serialnumber,
	 (uint32 reqId,
	  octetString * serialNumber))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
long templong;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 )
	{
	status=certreqmsg->certReq.certTemplate.
		serialNumber.value.get_value(templong);
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		status=certrepcert->tbsCertificate.
			serialNumber.get_value(templong);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}

if ( status==0)
	{
	MCDPRINT(("We think the serial number is %d.\n",templong));
	serialNumber->data=(unsigned char *)malloc(sizeof(templong));
	serialNumber->length=sizeof(templong);
	memcpy(serialNumber->data,(char *)&templong,sizeof(templong));
	}
else
	{
	serialNumber->data=NULL;
	serialNumber->length=0;
	}

DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_subject,
	 (uint32 reqId,
	  utf8String * subject))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
buffer_t buf;
utf8String returnval;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 )
	{
	if (!certreqmsg->certReq.certTemplate.subject.is_present()) {
		MCDPRINT(("Inquire_certreq_subject called when name not present\n"));
		status = API_FIELD_NOT_SET;
	} else
	status=certreqmsg->certReq.certTemplate.
		subject.value.get_value_UTF8(buf);
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		MCDPRINT(("Getting subject from certrep.\n"));
		status=certrepcert->tbsCertificate.
			subject.get_value_UTF8(buf);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}

if ( status==0)
	{
	MCDPRINT(("We think subject is %.*s.\n",buf.data_len,buf.data));
	returnval=(utf8String)malloc(buf.data_len+1);
	memset(returnval,0,buf.data_len+1);
	memcpy(returnval,buf.data,buf.data_len);
	*subject=returnval;
	}
else
	{
	*subject=NULL;
	}

buf.clear();
DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_issuer,
	 (uint32 reqId,
	  utf8String * issuer))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
buffer_t buf;
utf8String returnval;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 )
	{
	if (!certreqmsg->certReq.certTemplate.subject.is_present()) {
		MCDPRINT(("Inquire_certreq_subject called when name not present\n"));
		status = API_FIELD_NOT_SET;
	} else
	status=certreqmsg->certReq.certTemplate.
		issuer.value.get_value_UTF8(buf);
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		status=certrepcert->tbsCertificate.
			issuer.get_value_UTF8(buf);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}

if ( status==0)
	{
	MCDPRINT(("We think issuer is %.*s.\n",buf.data_len,buf.data));
	returnval=(utf8String)malloc(buf.data_len+1);
	memset(returnval,0,buf.data_len+1);
	memcpy(returnval,buf.data,buf.data_len);
	*issuer=returnval;
	}
else
	{
	*issuer=NULL;
	}

buf.clear();
DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_startdate,
	 (uint32 reqId,
	  utcDateTime * startDate))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
int tz_hour=0;
int tz_min=0;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 )
	{

	if (!certreqmsg->certReq.certTemplate.validity.is_present()) {
		MCDPRINT(("Inquire_certreq_startdate called when validity not present\n"));
		status = API_FIELD_NOT_SET;
	} else
	status=certreqmsg->certReq.certTemplate.
			validity.value.notBefore.
// TODO, use selected() to check for utcTime or generalizedTime
		value.utcTime.get_value(
		startDate->year,
		startDate->month,
		startDate->day,
		startDate->hour,
		startDate->min,
		startDate->sec,
		tz_hour,
		tz_min
		);
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		status=certrepcert->tbsCertificate.
// TODO, use selected() to check for utcTime or generalizedTime
			validity.notBefore.utcTime.get_value(
		startDate->year,
		startDate->month,
		startDate->day,
		startDate->hour,
		startDate->min,
		startDate->sec,
		tz_hour,
		tz_min
		);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}

if ( status==0)
	{
	MCDPRINT(("We think the startdate year is %d.\n",startDate->year));
	}
else
	{
	MCDPRINT(("We think something bad happend in startDate.\n"));
	}

DoneWithReq(reqId,INQUIRE);
return status;
}
		
EXPORTFN(uint32,
	 JNH_inquire_certreq_enddate,
	 (uint32 reqId,
	  utcDateTime * endDate))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
int tz_hour=0;
int tz_min=0;

status=GetCertReq(reqId,&certreqmsg,&objClass,INQUIRE);
if ( status == 0 )
	{
	if (!certreqmsg->certReq.certTemplate.validity.is_present()) {
		MCDPRINT(("Inquire_certreq_enddate called when validity not present\n"));
		status = API_FIELD_NOT_SET;
	} else
// TODO, use selected() to check for utcTime or generalizedTime
	status=certreqmsg->certReq.certTemplate.
		validity.value.notAfter.value.utcTime.get_value(
		endDate->year,
		endDate->month,
		endDate->day,
		endDate->hour,
		endDate->min,
		endDate->sec,
		tz_hour,
		tz_min
		);
	}
else
	{
	status=GetCertRepCert(reqId,&certrepcert,&objClass,INQUIRE);
	if (status == 0 )
		{
		status=certrepcert->tbsCertificate.
// TODO, use selected() to check for utcTime or generalizedTime
			validity.notAfter.utcTime.get_value(
			endDate->year,
			endDate->month,
			endDate->day,
			endDate->hour,
			endDate->min,
			endDate->sec,
			tz_hour,
			tz_min
			);
		// Now fall through to set the return values
		}
	else 
		{
		// both certrep and certreq failed, so just bail
		return status;
		}
	}

if ( status==0)
	{
	MCDPRINT(("We think the enddate year is %d.\n",endDate->year));
	}
else
	{
	MCDPRINT(("We think something bad happend in endDate.\n"));
	}

DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_policies,
	 (uint32 reqId,
	  uint32 * numberPolicies,
	  octetString ** policies))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_authorityKeyId,
	 (uint32 reqId,
	  octetString * keyId,
	  utf8String * authorityName,
	  octetString * serialNumber))
{
// TODO - Implement this function
return 0;
}

int HackedKeyID=9;
EXPORTFN(uint32,
	 JNH_inquire_certreq_subjectKeyId,
	 (uint32 reqId,
	  octetString * subjectKeyId))
{
// TODO - Fix up hacks
// Hacked for now
subjectKeyId->data=(unsigned char *) &HackedKeyID;
subjectKeyId->length=sizeof(HackedKeyID);
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_keyUsage,
	 (uint32 reqId,
	  keyUsage_t * usages))
{
uint32 objClass;
uint32 status;
utf8String returnval;
uint32 num_ext;
uint32 i_ext;
asn_oid usage_oid;
unsigned long usage_oid_els[]={2,5,29,15};
uint32 found_i=0;
x509_Extension *this_ext;
x509_Extensions *all_ext;
unsigned char * p_buffer;
XKeyUsage local_key_usage;
long temp_usages;
buffer_t buf;

status=usage_oid.set_value(usage_oid_els,4);
if ( status != 0 ) return status;

status=GetExtensions(reqId,&all_ext,&objClass,INQUIRE);
if ( status != 0 ) return status;

#ifdef MCDDEBUGON
if (!(all_ext->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in inquire_keyusage on initial extensions:\n"));
  all_ext->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

num_ext=all_ext->get_child_count();
MCDPRINT(("Number of extensions=%d.\n",num_ext));
found_i=0;
if ( num_ext>0 )
	{
	for(i_ext=0;(i_ext<num_ext)&&(found_i==0);i_ext++)
		{
		this_ext=all_ext->get_child(i_ext);
#ifdef MCDDEBUGON
		buf.clear();
		status=this_ext->extnID.display_printable(buf);
		if ( status==0)
		  MCDPRINT(("rc=%d,OID=%.*s\n",status,buf.data_len,buf.data));
		buf.clear();
#endif /* MCDDEBUGON */
		if ( usage_oid == this_ext->extnID )
			{
			found_i=1;
			}
		}
	}
else
	{
	// This is bad - we can't even count things?
	}

if ( found_i == 0 )
	{
	status=API_FIELD_NOT_SET;
	*usages=0;
	MCDPRINT(("No KeyUsage extension found\n"));
	}
else
	{
	status=this_ext->extnValue.get_value(buf.data,buf.data_len);
	if ( (buf.data_len>1)&&(status==0) )
		{
		status=local_key_usage.read(buf);
		if (status==0)MCDPRINT(("OK local_key_usage.setvalue.\n"));
		if (status==0) status=local_key_usage.get_value(temp_usages);
		if (status==0)MCDPRINT(("OK local_key_usage.getvalue.\n"));
		if (status==0) *usages=temp_usages;
		}
	else
		{
		status=API_FIELD_NOT_SET;
		MCDPRINT(("extnValue not retrieved.\n"));
		}

	}

DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_privateKeyUsagePeriod,
	 (uint32 reqId,
	  utcDateTime * notBefore,
	  utcDateTime * notAfter))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_policyQualifiers_CPS,
	 (uint32 reqId,
	  const octetString policy,
	  octetString * policyQualifierId,
	  utf8String * CPS_URI))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_policyQualifiers_userNotice,
	 (uint32 reqId,
	  const octetString policy,
	  octetString * policyQualifierId,
	  utf8String * explicitText,
	  utf8String * organization,
	  uint32 * numberNotices,
	  uint32 ** notices))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_policyMappings,
	 (uint32 reqId,
	  uint32 * numberMappings,
	  octetString ** issuerDomainPolicies,
	  octetString ** subjectDomainPolicies))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_basicConstraints,
	 (uint32 reqId,
	  IBOOL * isCaCert,
	  uint32 * maxPathLen))
{
x509_Extensions * all_ext;
uint32 objClass;
uint32 status;
buffer_t buf;
utf8String returnval;
uint32 num_ext;
uint32 i_ext;
asn_oid baseconstraint_oid;
unsigned long baseconstraint_oid_els[]={2,5,29,19};
uint32 found_i=0;
x509_Extension *this_ext;
XBasicConstraints local_basic_constraints;
bool tempbool;
long templong;

status=baseconstraint_oid.set_value(baseconstraint_oid_els,4);
if ( status != 0 ) return status;

status=GetExtensions(reqId,&all_ext,&objClass,INQUIRE);
if ( status != 0 ) return status;

num_ext=all_ext->get_child_count();
MCDPRINT(("Number of extensions=%d.\n",num_ext));
found_i=0;
if ( num_ext>0 )
	{
	for(i_ext=0;(i_ext<num_ext)&&(found_i==0);i_ext++)
		{
		this_ext=all_ext->get_child(i_ext);
		if ( baseconstraint_oid== this_ext->extnID )
			{
			found_i=1;
			}
		}
	}
else
	{
	// This is bad - we can't even count things?
	}

if ( found_i == 0 )
	{
	status=API_FIELD_NOT_SET;
	MCDPRINT(("OID not found, must not be set.\n"));
	}
else
	{
	// Just replace the existing one
	status=0;
	MCDPRINT(("Using existing extension.\n"));
	}
if (status==0)
	status=this_ext->extnValue.get_value(buf.data,buf.data_len);
if (status==0) MCDPRINT(("OK on this_ext->extnValue.get_value.\n"));
if (status==0) 
	status=local_basic_constraints.read(buf);
if (status==0) MCDPRINT(("OK on local_basic_constraints.read.\n"));
tempbool=FALSE;
if ( status==0)
	status=local_basic_constraints.cA.get_value(tempbool);
*isCaCert=tempbool;
if (status==0) MCDPRINT(("OK on local_basic_constraints.cA.get_value.\n"));
templong=0;
if ( status==0)
	status=local_basic_constraints.pathLenConstraints.get_value(templong);
	*maxPathLen=templong;
if (status==0) MCDPRINT(("OK on local_basic_constraints.Len.get_value.\n"));

DoneWithReq(reqId,INQUIRE);
return status;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_nameConstraints_permittedSubtrees,
	 (uint32 reqId,
	  uint32 * numberSubtrees,
	  utf8String ** bases,
	  uint32 ** maxLengths,
	  uint32 ** minLenths))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_nameConstraints_excludedSubtrees,
	 (uint32 reqId,
	  uint32 * numberSubtrees,
	  utf8String ** bases,
	  uint32 ** maxLengths,
	  uint32 ** minLenths))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_policyConstraints,
	 (uint32 reqId,
	  uint32 * numberConstraints,
	  octetString ** policies,
	  IBOOL ** requireExplicitPolicy,
	  IBOOL ** inhibitMapping))
{
return 0;
}
				   
EXPORTFN(uint32,
	 JNH_inquire_certreq_xKeyUsages,
	 (uint32 reqId,
	  uint32 * numberUsages,
	  octetString ** usages))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_inquire_certreq_extensions,
	 (uint32 reqId,
	  uint32 * numberExtensions,
	  octetString ** extensions,
	  IBOOL ** critical,
	  octetString ** value))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_set_certreq_subjectKey,
	 (uint32 reqId,
	  uint32 keyId))
{
// TODO - Fix up hacks
// This is a Hack until we get key generation going....
// Ignore keyId
CertReqMsg * certreqmsg = NULL;
uint32 objClass;
uint32 status;
unsigned char * p;
uint32 bc;
unsigned long alg_oid_els[]={1,2,840,113549,1,1,1};

// Only GetCertReq needed for _set_
status=GetCertReq(reqId,&certreqmsg,&objClass,SET);
if ( status != 0 ) return status;

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_subkey on initial object:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

p=(unsigned char *)"ABCDEFGH";
bc=8;
status=certreqmsg->certReq.certTemplate.publicKey.value.subjectPublicKey.
		 set_value(p,bc);

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_subkey after key.set_value:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

// TODO - Fix up hacks
// Also, Hack in RSA as the algorithm
if (status==0)
	status=certreqmsg->certReq.certTemplate.publicKey.value.
		algorithm.algorithm.set_value(alg_oid_els,6);

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_subkey after alg.set_value:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

DoneWithReq(reqId,SET);
if ((status==0)||(status=ASN_VALUE_NOT_SET)) return 0;
else return status;
}

EXPORTFN(uint32,
	 JNH_set_certreq_subject,
	 (uint32 reqId,
	  const utf8String subject))
{
  CertReqMsg * certreqmsg = NULL;
  Certificate * certrepcert = NULL;
  uint32 objClass;
  uint32 status;
  buffer_t buf;
  utf8String returnval;

// Only GetCertReq needed for _set_
  status=GetCertReq(reqId,&certreqmsg,&objClass,SET);
  if ( status != 0 ) return status;

#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("Retrieved certreq object %d for set_subjectName. details:\n", reqId));
      certreqmsg->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_subject on initial object:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

buf.append(subject,strlen((char *)subject));
status=certreqmsg->certReq.certTemplate.subject.value.set_value_UTF8(buf);

#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("After set_value_UTF8, object %d is:\n", reqId));
      certreqmsg->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_subject after set_value:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

buf.clear();
if ( status==0 )
	{
	DoneWithReq(reqId,SET);
	}
else
	{
	DoneWithReq(reqId,INQUIRE);
	}
return status;
}

EXPORTFN(uint32,
	 JNH_set_certreq_issuer,
	 (uint32 reqId,
	  const utf8String issuer))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
buffer_t buf;
utf8String returnval;

// Only GetCertReq needed for _set_
status=GetCertReq(reqId,&certreqmsg,&objClass,SET);
if ( status != 0 ) return status;
MCDPRINT(("Get CertReq OK for JNH_set_certreq_issuer.\n"));
#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_issuer on initial object:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

buf.append(issuer,strlen((char *)issuer)+1);
status=certreqmsg->certReq.certTemplate.issuer.value.set_value_UTF8(buf);
#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_issuer after set_value:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

buf.clear();
if ( status==0 )
	{
	DoneWithReq(reqId,SET);
	}
else
	{
	DoneWithReq(reqId,INQUIRE);
	}
return status;
}

EXPORTFN(uint32,
	 JNH_set_certreq_startDate,
	 (uint32 reqId,
	  utcDateTime notBefore))
{
  CertReqMsg * certreqmsg = NULL;
  Certificate * certrepcert = NULL;
  uint32 objClass;
  uint32 status;
  int tz_hour=0;
  int tz_min=0;

// Only GetCertReq needed for _set_
  status=GetCertReq(reqId,&certreqmsg,&objClass,SET);
  if ( status != 0 ) return status;
#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("Retrieved certreq object %d for set_startdate. details:\n", reqId));
      certreqmsg->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif

#ifdef MCDDEBUGON
  if (!(certreqmsg->check_encode_flags())) {
    buffer_t buf;
    MCDPRINT(("Encode flags error in set_startdate on initial object:\n"));
    certreqmsg->display_state_flags(buf);
    MCDPRINT(("%.*s", buf.data_len, buf.data));
  }
#endif

  status=certreqmsg->certReq.certTemplate.validity.value.notBefore.value.select(0);
// Select the UTCtime choice

#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("Called select(0) on object %d for set_startdate. details:\n", reqId));
      certreqmsg->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_startdate after select:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

// TODO - Add logic to use generalized time after 2003
status=certreqmsg->certReq.certTemplate.validity.value.notBefore.
	value.utcTime.set_value(
		notBefore.year,
		notBefore.month,
		notBefore.day,
		notBefore.hour,
		notBefore.min,
		notBefore.sec,
		tz_hour,
		tz_min
		);

#ifdef JCWDEBUGON
    {
      buffer_t buf;
      MCDPRINT(("Called set_value on object %d for set_startdate. details:\n", reqId));
      certreqmsg->display_state_flags(buf);
      MCDPRINT(("%.*s", buf.data_len, buf.data));
    }
#endif

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_startdate after set_value:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif


if ( status==0)
	{
	MCDPRINT(("We think we set the startdate year is %d.\n",notBefore.year));
	}
else
	{
	MCDPRINT(("We think something bad happened in set startDate.\n"));
	}

DoneWithReq(reqId,SET);
return status;
}

EXPORTFN(uint32,
	 JNH_set_certreq_endDate,
	 (uint32 reqId,
	  utcDateTime notAfter))
{
CertReqMsg * certreqmsg = NULL;
Certificate * certrepcert = NULL;
uint32 objClass;
uint32 status;
int tz_hour=0;
int tz_min=0;

status=GetCertReq(reqId,&certreqmsg,&objClass,SET);
if ( status != 0 ) return status;

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_enddate on initial object:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

status=certreqmsg->certReq.certTemplate.validity.value.notAfter.value.select(0);
// Select the UTCtime choice


#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_enddate after select:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

status=certreqmsg->certReq.certTemplate.validity.value.notAfter.
// TODO - Add logic to use generalized time after 2003
		value.utcTime.set_value(
		notAfter.year,
		notAfter.month,
		notAfter.day,
		notAfter.hour,
		notAfter.min,
		notAfter.sec,
		tz_hour,
		tz_min
		);

#ifdef MCDDEBUGON
if (!(certreqmsg->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_enddate after set_value:\n"));
  certreqmsg->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

if ( status==0)
	{
	MCDPRINT(("We think we set the enddate year is %d.\n",notAfter.year));
	}
else
	{
	MCDPRINT(("We think something bad happened in set endDate.\n"));
	}

DoneWithReq(reqId,SET);
return status;
}

EXPORTFN(uint32,
	 JNH_add_certreq_policy,
	 (uint32 reqId,
	  const octetString policy))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_policy,
	 (uint32 reqId,
	  const octetString policy))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_policy,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_set_certreq_authorityKeyId,
	 (uint32 reqId,
	  const octetString keyId,
	  const utf8String authorityName,
	  const octetString serialNumber))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_set_certreq_keyUsage,
	 (uint32 reqId,
	  keyUsage_t keyUsage))
{
x509_Extensions * all_ext;
uint32 objClass;
uint32 status;
buffer_t buf;
utf8String returnval;
uint32 num_ext;
uint32 i_ext;
asn_oid usage_oid;
unsigned long usage_oid_els[]={2,5,29,15};
uint32 found_i=0;
x509_Extension *this_ext;
unsigned char * p_buffer;
unsigned int bc;
XKeyUsage local_key_usage;
long temp_usages;
long local_key_usage_t;

status=usage_oid.set_value(usage_oid_els,4);
if ( status != 0 ) return status;

status=GetExtensions(reqId,&all_ext,&objClass,SET);
if ( status != 0 ) return status;

#ifdef MCDDEBUGON
if (!(all_ext->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_keyusage on initial extensions:\n"));
  all_ext->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

num_ext=all_ext->get_child_count();
MCDPRINT(("Number of extensions=%d.\n",num_ext));
found_i=0;
if ( num_ext>0 )
	{
	for(i_ext=0;(i_ext<num_ext)&&(found_i==0);i_ext++)
		{
		this_ext=all_ext->get_child(i_ext);
		if ( usage_oid == this_ext->extnID )
			{
			found_i=1;
			}
		}
	}
else
	{
	// This is bad - we can't even count things?
	}

if ( found_i == 0 )
	{
	this_ext=
		all_ext->add_child();
	if (this_ext== NULL) 
		{
		status=API_MEMORY_ERROR;
		MCDPRINT(("New child FAILED!\n"));
		}
	else 
		{
		status=0;
		MCDPRINT(("Made new child OK\n"));

#ifdef MCDDEBUGON
if (!(all_ext->check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_keyusage after new_child:\n"));
  all_ext->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif
	
	}
	}
else
	{
	// Just replace the existing one
	status=0;
	MCDPRINT(("Using existing extension\n"));
	}

if (status==0)
	status=this_ext->extnID.set_value(usage_oid_els,4);
if (status==0)
	{
	MCDPRINT(("OK on this_ext->extnID.set_value.\n"));
	status=this_ext->extnID.display_printable(buf);
	MCDPRINT(("rc=%d,OID=%.*s\n",status,buf.data_len,buf.data));
	buf.clear();

#ifdef MCDDEBUGON
if (!(all_ext->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_keyusage after extId.set_value:\n"));
  all_ext->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

	}
if (status==0)
	status=this_ext->critical.set_value(TRUE);
if (status==0) MCDPRINT(("OK on this_ext->critical.set_value.\n"));

#ifdef MCDDEBUGON
if (!(all_ext->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_keyusage after critical.set_value:\n"));
  all_ext->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif


if ( status==0)
	status=local_key_usage.set_value((long)keyUsage);
if (status==0) MCDPRINT(("OK on local_key_usage.set_value.\n"));

#ifdef MCDDEBUGON
if (!(local_key_usage.check_encode_flags())) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_keyusage after usage.set_value:\n"));
  local_key_usage.display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif

if ( status==0)
	status=local_key_usage.get_value(local_key_usage_t);
if (status==0) MCDPRINT(("OK on local_key_usage.get_value, usage=%d/%d\n",
			keyUsage,local_key_usage_t));
if (status==0) 
	status=local_key_usage.write(buf);
if (status==0) MCDPRINT(("OK on local_key_usage.write (%d bytes).\n", buf.data_len));
if (status==0)
	status=this_ext->extnValue.set_value(buf.data,buf.data_len);
if (status==0) MCDPRINT(("OK on this_ext->extnValue.set_value.\n"));

#ifdef MCDDEBUGON
if (!(all_ext->check_encode_flags(false))) {
  buffer_t buf;
  MCDPRINT(("Encode flags error in set_keyusage after set_value:\n"));
  all_ext->display_state_flags(buf);
  MCDPRINT(("%.*s", buf.data_len, buf.data));
}
#endif


DoneWithReq(reqId,SET);
return status;
}

EXPORTFN(uint32,
	 JNH_set_certreq_privateKeyUsagePeriod,
	 (uint32 reqId,
	  utcDateTime notBefore,
	  utcDateTime notAfter))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_add_certreq_policyQualifiers_CPS,
	 (uint32 reqId,
	  const octetString policyId,
	  const utf8String CPS_URI))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_policyQualifiers_CPS,
	 (uint32 reqId,
	  const octetString policyId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_policyQualifiers_CPS,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_add_certreq_policyQualifiers_userNotice,
	 (uint32 reqId,
	  const octetString policyId,
	  const utf8String explicitText,
	  const utf8String organization,
	  uint32 numberNotices,
	  uint32 notices[]))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_policyQualifiers_userNotice,
	 (uint32 reqId,
	  const octetString policyId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_policyQualifiers_userNotice,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_add_certreq_policyMapping,
	 (uint32 reqId,
	  const octetString issuerDomainPolicy,
	  const octetString subjectDomainPolicy))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_policyMapping,
	 (uint32 reqId,
	  const octetString issuerDomainPolicy,
	  const octetString subjectDomainPolicy))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_policyMapping,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_set_certreq_basicConstraints,
	 (uint32 reqId,
	  IBOOL isCaCert,
	  uint32 maxPathLen))
{
x509_Extensions * all_ext;
uint32 objClass;
uint32 status;
buffer_t buf;
utf8String returnval;
uint32 num_ext;
uint32 i_ext;
asn_oid baseconstraint_oid;
unsigned long baseconstraint_oid_els[]={2,5,29,19};
uint32 found_i=0;
x509_Extension *this_ext;
unsigned char * p_buffer;
unsigned int bc;
XKeyUsage local_key_usage;
XBasicConstraints local_basic_constraints;
long temp_usages;

status=baseconstraint_oid.set_value(baseconstraint_oid_els,4);
if ( status != 0 ) return status;

status=GetExtensions(reqId,&all_ext,&objClass,SET);
if ( status != 0 ) return status;

num_ext=all_ext->get_child_count();
MCDPRINT(("Number of extensions=%d.\n",num_ext));
found_i=0;
if ( num_ext>0 )
	{
	for(i_ext=0;(i_ext<num_ext)&&(found_i==0);i_ext++)
		{
		this_ext=all_ext->get_child(i_ext);
		if ( baseconstraint_oid== this_ext->extnID )
			{
			found_i=1;
			}
		}
	}
else
	{
	// This is bad - we can't even count things?
	}

if ( found_i == 0 )
	{
	this_ext=
		all_ext->add_child();
	if (this_ext== NULL) 
		{
		  status=API_MEMORY_ERROR;
		MCDPRINT(("New child FAILED!\n"));
		}
	else 
		{
		status=0;
		MCDPRINT(("Made new child OK\n"));
		}
	}
else
	{
	// Just replace the existing one
	status=0;
	MCDPRINT(("Using existing extension.\n"));
	}
if (status==0)
	status=this_ext->extnID.set_value(baseconstraint_oid_els,4);
if (status==0)
	{
	MCDPRINT(("OK on this_ext->extnID.set_value.\n"));
	status=this_ext->extnID.display_printable(buf);
	MCDPRINT(("rc=%d,OID=%.*s\n",status,buf.data_len,buf.data));
	buf.clear();
	}
if (status==0)
	status=this_ext->critical.set_value(TRUE);
if (status==0) MCDPRINT(("OK on this_ext->critical.set_value.\n"));
if ( status==0)
	status=local_basic_constraints.cA.set_value(isCaCert);
if (status==0) MCDPRINT(("OK on local_basic_constraints.cA.set_value.\n"));
if ( status==0)
	status=local_basic_constraints.pathLenConstraints.set_value(maxPathLen);
if (status==0) MCDPRINT(("OK on local_basic_constraints.Len.set_value.\n"));
if (status==0) 
	status=local_basic_constraints.write(buf);
if (status==0) MCDPRINT(("OK on local_basic_constraints.write.\n"));
if (status==0)
	status=this_ext->extnValue.set_value(buf.data,buf.data_len);
if (status==0) MCDPRINT(("OK on this_ext->extnValue.set_value.\n"));

DoneWithReq(reqId,SET);
return status;
}

EXPORTFN(uint32,
	 JNH_set_certreq_nameConstraints_permittedSubtrees,
	 (uint32 reqId,
	  const utf8String base,
	  uint32 maxLength,
	  uint32 minLength))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_nameConstraints_permittedSubtrees,
	 (uint32 reqId,
	  const utf8String base,
	  uint32 maxLength,
	  uint32 minLength))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_nameConstraints_permittedSubtrees,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_set_certreq_nameConstraints_excludedSubtrees,
	 (uint32 reqId,
	  const utf8String base,
	  uint32 maxLength,
	  uint32 minLength))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_nameConstraints_excludedSubtrees,
	 (uint32 reqId,
	  const utf8String base,
	  uint32 maxLength,
	  uint32 minLength))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_nameConstraints_excludedSubtrees,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_add_certreq_policyConstraints,
	 (uint32 reqId,
	  const octetString policyId,
	  IBOOL requireExplicitPolicy,
	  IBOOL inhibitMapping))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_policyConstraints,
	 (uint32 reqId,
	  const octetString policyId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_policyConstraints,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_add_certreq_xKeyUsages,
	 (uint32 reqId,
	  const octetString usage))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_xKeyUsages,
	 (uint32 reqId,
	  const octetString usage))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_xKeyUsages,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_add_certreq_extensions,
	 (uint32 reqId,
	  const octetString extId,
	  IBOOL critical,
	  const octetString value))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_remove_certreq_extensions,
	 (uint32 reqId,
	  const octetString extId))
{
// TODO - Implement this function
return 0;
}

EXPORTFN(uint32,
	 JNH_clear_certreq_extensions,
	 (uint32 reqId))
{
// TODO - Implement this function
return 0;
}

uint32
JNH_set_certreq_privkey_EE(uint32 reqId, const utf8String algorithm,
			   uint32 keylength)
{
  uint32	status;
  uint32	objClass;
  ObjStoreData *objsPtr;

  do {
    // We are not using the general purpose GetCertReq() call because 
    // what we are modifying is not in the cert request.
    if ((status = JnhGetObjectModify(reqId, &objClass, &objsPtr))) {
      break;
    }
    // We can only do this for request objects
    switch(objsPtr->msg.value.selected()) {
    case OBJ_MSG_CERTREQ:
    case OBJ_MSG_IREQ:
      break;
    default:
      status = API_IMPROPER_MESSAGE_TYPE;
      break;
    }
    if (status) {
      break;
    }
    if ((status = objsPtr->keygen.value.select(0))) { // select ee generated
      break;
    }
    if ((status = objsPtr->keygen.value.ee.value.numBits.
	 set_value(keylength))) {
      break;
    }
    if ((status = objsPtr->keygen.value.ee.value.keyAlg.
	 set_value((char *) algorithm))) {
      break;
    }
  } while(0);
  return status;
}

uint32
JNH_set_certreq_privkey_CA(uint32 reqId)
{
  return 0;
}

uint32
JNH_set_certreq_privkey_import(uint32 reqId, const utf8String filename,
			       const utf8String password)
{
  return 0;
}

