/*******************************************************************
 *
 * This file was generated by TIS/ASN1COMP Ver. 4.2, an ASN.1 compiler.
 * TIS/ASN1COMP is Copyright (c) 1998, TIS Labs at Network Associates, Inc.
 *
 * This file was AUTOMATICALLY GENERATED on Mon May 17 09:25:53 1999
 *
 ******************************************************************/


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "cert_asn.h"

/*******************************************************************
 *
 * Code for internal routines
 *
 *  DropInPlaceXXX:  drops the contents of a block, in place
 *
 *  _PackXXX: packs up a structure into an ASN.1 block
 *
 *  UnpkInPlaceXXX:  unpacks an ASN.1 block into a structure in place
 *
 *  _unPackXXX: carves a structure block and unpacks into it
 *
 ******************************************************************/


/******************************************************************
 * Routines for noticeNumbers_SEQ_OF
 ******************************************************************/

size_t PKISizeofnoticeNumbers_SEQ_OFInternal(
    PKInoticeNumbers_SEQ_OF *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_noticeNumbers_SEQ_OF)
        lth = PKIMAX_noticeNumbers_SEQ_OF;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofINTEGERInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofnoticeNumbers_SEQ_OFInternal */

void PKIDropInPlacenoticeNumbers_SEQ_OF(
    PKICONTEXT *ctx,
    PKInoticeNumbers_SEQ_OF *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_noticeNumbers_SEQ_OF)
        lth = PKIMAX_noticeNumbers_SEQ_OF ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeINTEGER(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlacenoticeNumbers_SEQ_OF */

size_t PKIPacknoticeNumbers_SEQ_OFInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKInoticeNumbers_SEQ_OF *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_noticeNumbers_SEQ_OF) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofnoticeNumbers_SEQ_OF(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_INTEGER, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPacknoticeNumbers_SEQ_OFInternal */

size_t PKIUnpkInPlacenoticeNumbers_SEQ_OF(
     PKICONTEXT *ctx,
     PKInoticeNumbers_SEQ_OF *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "noticeNumbers_SEQ_OF");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_noticeNumbers_SEQ_OF) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewINTEGER(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceINTEGER(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_INTEGER, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacenoticeNumbers_SEQ_OF */

size_t PKIUnpacknoticeNumbers_SEQ_OFInternal(
    PKICONTEXT *ctx,
    PKInoticeNumbers_SEQ_OF **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKInoticeNumbers_SEQ_OF *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewnoticeNumbers_SEQ_OF(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacenoticeNumbers_SEQ_OF(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreenoticeNumbers_SEQ_OF(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpacknoticeNumbers_SEQ_OFInternal */


/******************************************************************
 * Routines for AlgorithmIdentifier
 ******************************************************************/

size_t PKISizeofAlgorithmIdentifierInternal(
    PKIAlgorithmIdentifier *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofOBJECT_IDInternal(&asnstruct->algorithm, PKITRUE, PKIFALSE)
          + PKISizeofANYInternal(asnstruct->parameters, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofAlgorithmIdentifierInternal */

void PKIDropInPlaceAlgorithmIdentifier(
    PKICONTEXT *ctx,
    PKIAlgorithmIdentifier *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceOBJECT_ID(ctx, &(f->algorithm));
    PKIFreeANY(ctx, f->parameters);
    f->parameters = NULL;
} /* PKIDropInPlaceAlgorithmIdentifier */

size_t PKIPackAlgorithmIdentifierInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAlgorithmIdentifier *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofAlgorithmIdentifier(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field algorithm of AlgorithmIdentifier */
    bytesused += PKIPackOBJECT_IDInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->algorithm), PKIID_OBJECT_ID, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field parameters of AlgorithmIdentifier */
    if (asnstruct->parameters != NULL) { /* optional */
        bytesused += PKIPackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->parameters, PKIID_ANY, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAlgorithmIdentifierInternal */

size_t PKIUnpkInPlaceAlgorithmIdentifier(
    PKICONTEXT *ctx,
    PKIAlgorithmIdentifier *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "AlgorithmIdentifier" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field algorithm of AlgorithmIdentifier */
    bytesused += PKIUnpkInPlaceOBJECT_ID(ctx, &(asnstruct->algorithm), buf+bytesused,
                        localsize-bytesused, PKIID_OBJECT_ID, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field parameters of AlgorithmIdentifier */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->parameters != NULL)
        PKIFreeANY(ctx, asnstruct->parameters);
    bytesused += PKIUnpackANYInternal(ctx, &(asnstruct->parameters),
                    buf+bytesused, localsize-bytesused, PKIID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAlgorithmIdentifier */

size_t PKIUnpackAlgorithmIdentifierInternal(
    PKICONTEXT *ctx,
    PKIAlgorithmIdentifier **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAlgorithmIdentifier *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAlgorithmIdentifier(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAlgorithmIdentifier(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAlgorithmIdentifier(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAlgorithmIdentifierInternal */


/******************************************************************
 * Routines for AnotherName
 ******************************************************************/

size_t PKISizeofAnotherNameInternal(
    PKIAnotherName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofOBJECT_IDInternal(&asnstruct->type_id, PKITRUE, PKIFALSE)
          + PKISizeofANYInternal(&asnstruct->value, PKITRUE, PKITRUE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofAnotherNameInternal */

void PKIDropInPlaceAnotherName(
    PKICONTEXT *ctx,
    PKIAnotherName *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceOBJECT_ID(ctx, &(f->type_id));
    PKIDropInPlaceANY(ctx, &(f->value));
} /* PKIDropInPlaceAnotherName */

size_t PKIPackAnotherNameInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAnotherName *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofAnotherName(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field type_id of AnotherName */
    bytesused += PKIPackOBJECT_IDInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->type_id), PKIID_OBJECT_ID, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field value of AnotherName */
    bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofANY(ctx, &(asnstruct->value ), PKITRUE));
    bytesused += PKIPackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->value), PKIID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAnotherNameInternal */

size_t PKIUnpkInPlaceAnotherName(
    PKICONTEXT *ctx,
    PKIAnotherName *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "AnotherName" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field type_id of AnotherName */
    bytesused += PKIUnpkInPlaceOBJECT_ID(ctx, &(asnstruct->type_id), buf+bytesused,
                        localsize-bytesused, PKIID_OBJECT_ID, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field value of AnotherName */
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x00,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            bytesused += PKIUnpkInPlaceANY(ctx, &(asnstruct->value), buf+bytesused,
                        localsize-bytesused, PKIID_ANY, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            bytesused += PKIUnpkInPlaceANY(ctx, &(asnstruct->value), buf+bytesused,
                        localsize-bytesused, PKIID_ANY, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAnotherName */

size_t PKIUnpackAnotherNameInternal(
    PKICONTEXT *ctx,
    PKIAnotherName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAnotherName *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAnotherName(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAnotherName(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAnotherName(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAnotherNameInternal */


/******************************************************************
 * Routines for AttributeTypeAndValue
 ******************************************************************/

size_t PKISizeofAttributeTypeAndValueInternal(
    PKIAttributeTypeAndValue *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofAttributeTypeInternal(&asnstruct->type, PKITRUE, PKIFALSE)
          + PKISizeofAttributeValueInternal(&asnstruct->value, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofAttributeTypeAndValueInternal */

void PKIDropInPlaceAttributeTypeAndValue(
    PKICONTEXT *ctx,
    PKIAttributeTypeAndValue *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceAttributeType(ctx, &(f->type));
    PKIDropInPlaceAttributeValue(ctx, &(f->value));
} /* PKIDropInPlaceAttributeTypeAndValue */

size_t PKIPackAttributeTypeAndValueInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAttributeTypeAndValue *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofAttributeTypeAndValue(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field type of AttributeTypeAndValue */
    bytesused += PKIPackAttributeTypeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->type), PKIID_AttributeType, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field value of AttributeTypeAndValue */
    bytesused += PKIPackAttributeValueInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->value), PKIID_AttributeValue, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAttributeTypeAndValueInternal */

size_t PKIUnpkInPlaceAttributeTypeAndValue(
    PKICONTEXT *ctx,
    PKIAttributeTypeAndValue *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "AttributeTypeAndValue" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field type of AttributeTypeAndValue */
    bytesused += PKIUnpkInPlaceAttributeType(ctx, &(asnstruct->type), buf+bytesused,
                        localsize-bytesused, PKIID_AttributeType, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field value of AttributeTypeAndValue */
    bytesused += PKIUnpkInPlaceAttributeValue(ctx, &(asnstruct->value), buf+bytesused,
                        localsize-bytesused, PKIID_AttributeValue, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAttributeTypeAndValue */

size_t PKIUnpackAttributeTypeAndValueInternal(
    PKICONTEXT *ctx,
    PKIAttributeTypeAndValue **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAttributeTypeAndValue *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAttributeTypeAndValue(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAttributeTypeAndValue(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAttributeTypeAndValue(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAttributeTypeAndValueInternal */


/******************************************************************
 * Routines for BasicConstraints
 ******************************************************************/

size_t PKISizeofBasicConstraintsInternal(
    PKIBasicConstraints *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofBOOLEANInternal(asnstruct->cA, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(asnstruct->pathLenConstraint, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofBasicConstraintsInternal */

void PKIDropInPlaceBasicConstraints(
    PKICONTEXT *ctx,
    PKIBasicConstraints *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeBOOLEAN(ctx, f->cA);
    f->cA = NULL;
    PKIFreeINTEGER(ctx, f->pathLenConstraint);
    f->pathLenConstraint = NULL;
} /* PKIDropInPlaceBasicConstraints */

size_t PKIPackBasicConstraintsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIBasicConstraints *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofBasicConstraints(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field cA of BasicConstraints */
    if (asnstruct->cA != NULL) { /* optional */
        bytesused += PKIPackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->cA, PKIID_BOOLEAN, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field pathLenConstraint of BasicConstraints */
    if (asnstruct->pathLenConstraint != NULL) { /* optional */
        bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->pathLenConstraint, PKIID_INTEGER, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackBasicConstraintsInternal */

size_t PKIUnpkInPlaceBasicConstraints(
    PKICONTEXT *ctx,
    PKIBasicConstraints *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "BasicConstraints" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field cA of BasicConstraints */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->cA != NULL)
        PKIFreeBOOLEAN(ctx, asnstruct->cA);
    bytesused += PKIUnpackBOOLEANInternal(ctx, &(asnstruct->cA),
                    buf+bytesused, localsize-bytesused, PKIID_BOOLEAN, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field pathLenConstraint of BasicConstraints */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->pathLenConstraint != NULL)
        PKIFreeINTEGER(ctx, asnstruct->pathLenConstraint);
    bytesused += PKIUnpackINTEGERInternal(ctx, &(asnstruct->pathLenConstraint),
                    buf+bytesused, localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceBasicConstraints */

size_t PKIUnpackBasicConstraintsInternal(
    PKICONTEXT *ctx,
    PKIBasicConstraints **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIBasicConstraints *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewBasicConstraints(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceBasicConstraints(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeBasicConstraints(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackBasicConstraintsInternal */


/******************************************************************
 * Routines for DirectoryString
 ******************************************************************/

size_t PKISizeofDirectoryStringInternal(
    PKIDirectoryString *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PKIID_T61String:
      case 0x20|PKIID_T61String:
        body_size = PKISizeofT61StringInternal((PKIT61String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_PrintableString:
      case 0x20|PKIID_PrintableString:
        body_size = PKISizeofPrintableStringInternal((PKIPrintableString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_UniversalString:
      case 0x20|PKIID_UniversalString:
        body_size = PKISizeofUniversalStringInternal((PKIUniversalString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_UTF8String:
      case 0x20|PKIID_UTF8String:
        body_size = PKISizeofUTF8StringInternal((PKIUTF8String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_BMPString:
      case 0x20|PKIID_BMPString:
        body_size = PKISizeofBMPStringInternal((PKIBMPString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofDirectoryStringInternal */

void PKIDropInPlaceDirectoryString(
    PKICONTEXT *ctx,
    PKIDirectoryString *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PKIID_T61String:
    case 0x20|PKIID_T61String:
        PKIFreeT61String(ctx, (PKIT61String *)( f->data ));
        break;
    case PKIID_PrintableString:
    case 0x20|PKIID_PrintableString:
        PKIFreePrintableString(ctx, (PKIPrintableString *)( f->data ));
        break;
    case PKIID_UniversalString:
    case 0x20|PKIID_UniversalString:
        PKIFreeUniversalString(ctx, (PKIUniversalString *)( f->data ));
        break;
    case PKIID_UTF8String:
    case 0x20|PKIID_UTF8String:
        PKIFreeUTF8String(ctx, (PKIUTF8String *)( f->data ));
        break;
    case PKIID_BMPString:
    case 0x20|PKIID_BMPString:
        PKIFreeBMPString(ctx, (PKIBMPString *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceDirectoryString */

size_t PKIPackDirectoryStringInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDirectoryString *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;

    (void)tag; /* unused */

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDirectoryString(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    switch ( (asnstruct->CHOICE_field_type & 0xDF) ) {

    case PKIID_T61String:
        bytesused += PKIPackT61StringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIT61String *)(asnstruct->data),
                     PKIID_T61String,
                     erret);
        break;

    case PKIID_PrintableString:
        bytesused += PKIPackPrintableStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIPrintableString *)(asnstruct->data),
                     PKIID_PrintableString,
                     erret);
        break;

    case PKIID_UniversalString:
        bytesused += PKIPackUniversalStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIUniversalString *)(asnstruct->data),
                     PKIID_UniversalString,
                     erret);
        break;

    case PKIID_UTF8String:
        bytesused += PKIPackUTF8StringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIUTF8String *)(asnstruct->data),
                     PKIID_UTF8String,
                     erret);
        break;

    case PKIID_BMPString:
        bytesused += PKIPackBMPStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIBMPString *)(asnstruct->data),
                     PKIID_BMPString,
                     erret);
        break;

    default:
        PKIERR( PKIErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

  return bytesused;
} /* PKIPackDirectoryStringInternal */

size_t PKIUnpkInPlaceDirectoryString(
     PKICONTEXT *ctx,
     PKIDirectoryString *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    switch (*buf) {

    /* teletexString */
    case PKIID_T61String:
    case 0x20|PKIID_T61String:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewT61String(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceT61String(ctx, (PKIT61String *)(asnstruct->data),
                    buf, buflen,
                    PKIID_T61String, erret));
        /*NOTREACHED*/
        break;

    /* printableString */
    case PKIID_PrintableString:
    case 0x20|PKIID_PrintableString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewPrintableString(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlacePrintableString(ctx, (PKIPrintableString *)(asnstruct->data),
                    buf, buflen,
                    PKIID_PrintableString, erret));
        /*NOTREACHED*/
        break;

    /* universalString */
    case PKIID_UniversalString:
    case 0x20|PKIID_UniversalString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewUniversalString(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceUniversalString(ctx, (PKIUniversalString *)(asnstruct->data),
                    buf, buflen,
                    PKIID_UniversalString, erret));
        /*NOTREACHED*/
        break;

    /* utf8String */
    case PKIID_UTF8String:
    case 0x20|PKIID_UTF8String:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewUTF8String(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceUTF8String(ctx, (PKIUTF8String *)(asnstruct->data),
                    buf, buflen,
                    PKIID_UTF8String, erret));
        /*NOTREACHED*/
        break;

    /* bmpString */
    case PKIID_BMPString:
    case 0x20|PKIID_BMPString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewBMPString(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceBMPString(ctx, (PKIBMPString *)(asnstruct->data),
                    buf, buflen,
                    PKIID_BMPString, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceDirectoryString */

size_t PKIUnpackDirectoryStringInternal(
    PKICONTEXT *ctx,
    PKIDirectoryString **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDirectoryString *local = NULL ;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    local = PKINewDirectoryString(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceDirectoryString(ctx, local, buf, buflen, tag, erret);
    if (*erret == PKIErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) PKIFreeDirectoryString(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) PKIFreeDirectoryString(ctx, local);
        return 0;
    }

    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDirectoryStringInternal */


/******************************************************************
 * Routines for DisplayText
 ******************************************************************/

size_t PKISizeofDisplayTextInternal(
    PKIDisplayText *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PKIID_VisibleString:
      case 0x20|PKIID_VisibleString:
        body_size = PKISizeofVisibleStringInternal((PKIVisibleString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_BMPString:
      case 0x20|PKIID_BMPString:
        body_size = PKISizeofBMPStringInternal((PKIBMPString *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_UTF8String:
      case 0x20|PKIID_UTF8String:
        body_size = PKISizeofUTF8StringInternal((PKIUTF8String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofDisplayTextInternal */

void PKIDropInPlaceDisplayText(
    PKICONTEXT *ctx,
    PKIDisplayText *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PKIID_VisibleString:
    case 0x20|PKIID_VisibleString:
        PKIFreeVisibleString(ctx, (PKIVisibleString *)( f->data ));
        break;
    case PKIID_BMPString:
    case 0x20|PKIID_BMPString:
        PKIFreeBMPString(ctx, (PKIBMPString *)( f->data ));
        break;
    case PKIID_UTF8String:
    case 0x20|PKIID_UTF8String:
        PKIFreeUTF8String(ctx, (PKIUTF8String *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceDisplayText */

size_t PKIPackDisplayTextInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDisplayText *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;

    (void)tag; /* unused */

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDisplayText(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    switch ( (asnstruct->CHOICE_field_type & 0xDF) ) {

    case PKIID_VisibleString:
        bytesused += PKIPackVisibleStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIVisibleString *)(asnstruct->data),
                     PKIID_VisibleString,
                     erret);
        break;

    case PKIID_BMPString:
        bytesused += PKIPackBMPStringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIBMPString *)(asnstruct->data),
                     PKIID_BMPString,
                     erret);
        break;

    case PKIID_UTF8String:
        bytesused += PKIPackUTF8StringInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIUTF8String *)(asnstruct->data),
                     PKIID_UTF8String,
                     erret);
        break;

    default:
        PKIERR( PKIErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

  return bytesused;
} /* PKIPackDisplayTextInternal */

size_t PKIUnpkInPlaceDisplayText(
     PKICONTEXT *ctx,
     PKIDisplayText *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    switch (*buf) {

    /* visibleString */
    case PKIID_VisibleString:
    case 0x20|PKIID_VisibleString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewVisibleString(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceVisibleString(ctx, (PKIVisibleString *)(asnstruct->data),
                    buf, buflen,
                    PKIID_VisibleString, erret));
        /*NOTREACHED*/
        break;

    /* bmpString */
    case PKIID_BMPString:
    case 0x20|PKIID_BMPString:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewBMPString(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceBMPString(ctx, (PKIBMPString *)(asnstruct->data),
                    buf, buflen,
                    PKIID_BMPString, erret));
        /*NOTREACHED*/
        break;

    /* utf8String */
    case PKIID_UTF8String:
    case 0x20|PKIID_UTF8String:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewUTF8String(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceUTF8String(ctx, (PKIUTF8String *)(asnstruct->data),
                    buf, buflen,
                    PKIID_UTF8String, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceDisplayText */

size_t PKIUnpackDisplayTextInternal(
    PKICONTEXT *ctx,
    PKIDisplayText **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDisplayText *local = NULL ;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    local = PKINewDisplayText(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceDisplayText(ctx, local, buf, buflen, tag, erret);
    if (*erret == PKIErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) PKIFreeDisplayText(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) PKIFreeDisplayText(ctx, local);
        return 0;
    }

    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDisplayTextInternal */


/******************************************************************
 * Routines for Dss_Parms
 ******************************************************************/

size_t PKISizeofDss_ParmsInternal(
    PKIDss_Parms *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofINTEGERInternal(&asnstruct->p, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->q, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->g, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofDss_ParmsInternal */

void PKIDropInPlaceDss_Parms(
    PKICONTEXT *ctx,
    PKIDss_Parms *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceINTEGER(ctx, &(f->p));
    PKIDropInPlaceINTEGER(ctx, &(f->q));
    PKIDropInPlaceINTEGER(ctx, &(f->g));
} /* PKIDropInPlaceDss_Parms */

size_t PKIPackDss_ParmsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDss_Parms *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDss_Parms(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field p of Dss_Parms */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->p), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field q of Dss_Parms */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->q), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field g of Dss_Parms */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->g), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackDss_ParmsInternal */

size_t PKIUnpkInPlaceDss_Parms(
    PKICONTEXT *ctx,
    PKIDss_Parms *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Dss_Parms" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field p of Dss_Parms */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->p), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field q of Dss_Parms */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->q), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field g of Dss_Parms */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->g), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceDss_Parms */

size_t PKIUnpackDss_ParmsInternal(
    PKICONTEXT *ctx,
    PKIDss_Parms **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDss_Parms *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewDss_Parms(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceDss_Parms(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeDss_Parms(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDss_ParmsInternal */


/******************************************************************
 * Routines for Dss_Sig_Value
 ******************************************************************/

size_t PKISizeofDss_Sig_ValueInternal(
    PKIDss_Sig_Value *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofINTEGERInternal(&asnstruct->r, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->s, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofDss_Sig_ValueInternal */

void PKIDropInPlaceDss_Sig_Value(
    PKICONTEXT *ctx,
    PKIDss_Sig_Value *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceINTEGER(ctx, &(f->r));
    PKIDropInPlaceINTEGER(ctx, &(f->s));
} /* PKIDropInPlaceDss_Sig_Value */

size_t PKIPackDss_Sig_ValueInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDss_Sig_Value *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDss_Sig_Value(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field r of Dss_Sig_Value */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->r), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field s of Dss_Sig_Value */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->s), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackDss_Sig_ValueInternal */

size_t PKIUnpkInPlaceDss_Sig_Value(
    PKICONTEXT *ctx,
    PKIDss_Sig_Value *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Dss_Sig_Value" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field r of Dss_Sig_Value */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->r), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field s of Dss_Sig_Value */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->s), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceDss_Sig_Value */

size_t PKIUnpackDss_Sig_ValueInternal(
    PKICONTEXT *ctx,
    PKIDss_Sig_Value **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDss_Sig_Value *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewDss_Sig_Value(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceDss_Sig_Value(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeDss_Sig_Value(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDss_Sig_ValueInternal */


/******************************************************************
 * Routines for ExtKeyUsageSyntax
 ******************************************************************/

size_t PKISizeofExtKeyUsageSyntaxInternal(
    PKIExtKeyUsageSyntax *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_ExtKeyUsageSyntax)
        lth = PKIMAX_ExtKeyUsageSyntax;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofKeyPurposeIdInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofExtKeyUsageSyntaxInternal */

void PKIDropInPlaceExtKeyUsageSyntax(
    PKICONTEXT *ctx,
    PKIExtKeyUsageSyntax *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_ExtKeyUsageSyntax)
        lth = PKIMAX_ExtKeyUsageSyntax ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeKeyPurposeId(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceExtKeyUsageSyntax */

size_t PKIPackExtKeyUsageSyntaxInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtKeyUsageSyntax *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_ExtKeyUsageSyntax) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofExtKeyUsageSyntax(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackKeyPurposeIdInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_KeyPurposeId, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackExtKeyUsageSyntaxInternal */

size_t PKIUnpkInPlaceExtKeyUsageSyntax(
     PKICONTEXT *ctx,
     PKIExtKeyUsageSyntax *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "ExtKeyUsageSyntax");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_ExtKeyUsageSyntax) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewKeyPurposeId(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceKeyPurposeId(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_KeyPurposeId, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceExtKeyUsageSyntax */

size_t PKIUnpackExtKeyUsageSyntaxInternal(
    PKICONTEXT *ctx,
    PKIExtKeyUsageSyntax **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtKeyUsageSyntax *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewExtKeyUsageSyntax(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceExtKeyUsageSyntax(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeExtKeyUsageSyntax(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackExtKeyUsageSyntaxInternal */


/******************************************************************
 * Routines for Extension
 ******************************************************************/

size_t PKISizeofExtensionInternal(
    PKIExtension *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofOBJECT_IDInternal(&asnstruct->extnID, PKITRUE, PKIFALSE)
          + PKISizeofBOOLEANInternal(asnstruct->critical, PKITRUE, PKIFALSE)
          + PKISizeofOCTET_STRINGInternal(&asnstruct->extnValue, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofExtensionInternal */

void PKIDropInPlaceExtension(
    PKICONTEXT *ctx,
    PKIExtension *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceOBJECT_ID(ctx, &(f->extnID));
    PKIFreeBOOLEAN(ctx, f->critical);
    f->critical = NULL;
    PKIDropInPlaceOCTET_STRING(ctx, &(f->extnValue));
} /* PKIDropInPlaceExtension */

size_t PKIPackExtensionInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtension *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofExtension(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field extnID of Extension */
    bytesused += PKIPackOBJECT_IDInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->extnID), PKIID_OBJECT_ID, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field critical of Extension */
    if (asnstruct->critical != NULL) { /* optional */
        bytesused += PKIPackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->critical, PKIID_BOOLEAN, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field extnValue of Extension */
    bytesused += PKIPackOCTET_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->extnValue), PKIID_OCTET_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackExtensionInternal */

size_t PKIUnpkInPlaceExtension(
    PKICONTEXT *ctx,
    PKIExtension *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Extension" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field extnID of Extension */
    bytesused += PKIUnpkInPlaceOBJECT_ID(ctx, &(asnstruct->extnID), buf+bytesused,
                        localsize-bytesused, PKIID_OBJECT_ID, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field critical of Extension */
    if (asnstruct->critical != NULL)
        PKIFreeBOOLEAN(ctx, asnstruct->critical);
    bytesused += PKIUnpackBOOLEANInternal(ctx, &(asnstruct->critical),
                    buf+bytesused, localsize-bytesused, PKIID_BOOLEAN, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field extnValue of Extension */
    bytesused += PKIUnpkInPlaceOCTET_STRING(ctx, &(asnstruct->extnValue), buf+bytesused,
                        localsize-bytesused, PKIID_OCTET_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceExtension */

size_t PKIUnpackExtensionInternal(
    PKICONTEXT *ctx,
    PKIExtension **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtension *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewExtension(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceExtension(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeExtension(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackExtensionInternal */


/******************************************************************
 * Routines for PolicyConstraints
 ******************************************************************/

size_t PKISizeofPolicyConstraintsInternal(
    PKIPolicyConstraints *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofSkipCertsInternal(asnstruct->requireExplicitPolicy, PKITRUE, PKIFALSE)
          + PKISizeofSkipCertsInternal(asnstruct->inhibitPolicyMapping, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofPolicyConstraintsInternal */

void PKIDropInPlacePolicyConstraints(
    PKICONTEXT *ctx,
    PKIPolicyConstraints *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeSkipCerts(ctx, f->requireExplicitPolicy);
    f->requireExplicitPolicy = NULL;
    PKIFreeSkipCerts(ctx, f->inhibitPolicyMapping);
    f->inhibitPolicyMapping = NULL;
} /* PKIDropInPlacePolicyConstraints */

size_t PKIPackPolicyConstraintsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIPolicyConstraints *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofPolicyConstraints(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field requireExplicitPolicy of PolicyConstraints */
    if (asnstruct->requireExplicitPolicy != NULL) { /* optional */
        bytesused += PKIPackSkipCertsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->requireExplicitPolicy, 0x80 | 0x00, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field inhibitPolicyMapping of PolicyConstraints */
    if (asnstruct->inhibitPolicyMapping != NULL) { /* optional */
        bytesused += PKIPackSkipCertsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->inhibitPolicyMapping, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackPolicyConstraintsInternal */

size_t PKIUnpkInPlacePolicyConstraints(
    PKICONTEXT *ctx,
    PKIPolicyConstraints *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PolicyConstraints" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field requireExplicitPolicy of PolicyConstraints */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->requireExplicitPolicy != NULL)
        PKIFreeSkipCerts(ctx, asnstruct->requireExplicitPolicy);
    bytesused += PKIUnpackSkipCertsInternal(ctx, &(asnstruct->requireExplicitPolicy),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field inhibitPolicyMapping of PolicyConstraints */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->inhibitPolicyMapping != NULL)
        PKIFreeSkipCerts(ctx, asnstruct->inhibitPolicyMapping);
    bytesused += PKIUnpackSkipCertsInternal(ctx, &(asnstruct->inhibitPolicyMapping),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacePolicyConstraints */

size_t PKIUnpackPolicyConstraintsInternal(
    PKICONTEXT *ctx,
    PKIPolicyConstraints **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIPolicyConstraints *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewPolicyConstraints(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacePolicyConstraints(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreePolicyConstraints(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackPolicyConstraintsInternal */


/******************************************************************
 * Routines for PolicyMappings_SEQUENCE
 ******************************************************************/

size_t PKISizeofPolicyMappings_SEQUENCEInternal(
    PKIPolicyMappings_SEQUENCE *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofCertPolicyIdInternal(&asnstruct->issuerDomainPolicy, PKITRUE, PKIFALSE)
          + PKISizeofCertPolicyIdInternal(&asnstruct->subjectDomainPolicy, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofPolicyMappings_SEQUENCEInternal */

void PKIDropInPlacePolicyMappings_SEQUENCE(
    PKICONTEXT *ctx,
    PKIPolicyMappings_SEQUENCE *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceCertPolicyId(ctx, &(f->issuerDomainPolicy));
    PKIDropInPlaceCertPolicyId(ctx, &(f->subjectDomainPolicy));
} /* PKIDropInPlacePolicyMappings_SEQUENCE */

size_t PKIPackPolicyMappings_SEQUENCEInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIPolicyMappings_SEQUENCE *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofPolicyMappings_SEQUENCE(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field issuerDomainPolicy of PolicyMappings_SEQUENCE */
    bytesused += PKIPackCertPolicyIdInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuerDomainPolicy), PKIID_CertPolicyId, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectDomainPolicy of PolicyMappings_SEQUENCE */
    bytesused += PKIPackCertPolicyIdInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectDomainPolicy), PKIID_CertPolicyId, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackPolicyMappings_SEQUENCEInternal */

size_t PKIUnpkInPlacePolicyMappings_SEQUENCE(
    PKICONTEXT *ctx,
    PKIPolicyMappings_SEQUENCE *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PolicyMappings_SEQUENCE" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field issuerDomainPolicy of PolicyMappings_SEQUENCE */
    bytesused += PKIUnpkInPlaceCertPolicyId(ctx, &(asnstruct->issuerDomainPolicy), buf+bytesused,
                        localsize-bytesused, PKIID_CertPolicyId, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectDomainPolicy of PolicyMappings_SEQUENCE */
    bytesused += PKIUnpkInPlaceCertPolicyId(ctx, &(asnstruct->subjectDomainPolicy), buf+bytesused,
                        localsize-bytesused, PKIID_CertPolicyId, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacePolicyMappings_SEQUENCE */

size_t PKIUnpackPolicyMappings_SEQUENCEInternal(
    PKICONTEXT *ctx,
    PKIPolicyMappings_SEQUENCE **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIPolicyMappings_SEQUENCE *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewPolicyMappings_SEQUENCE(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacePolicyMappings_SEQUENCE(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreePolicyMappings_SEQUENCE(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackPolicyMappings_SEQUENCEInternal */


/******************************************************************
 * Routines for PolicyQualifierInfo
 ******************************************************************/

size_t PKISizeofPolicyQualifierInfoInternal(
    PKIPolicyQualifierInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofPolicyQualifierIdInternal(&asnstruct->policyQualifierId, PKITRUE, PKIFALSE)
          + PKISizeofANYInternal(&asnstruct->qualifier, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofPolicyQualifierInfoInternal */

void PKIDropInPlacePolicyQualifierInfo(
    PKICONTEXT *ctx,
    PKIPolicyQualifierInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlacePolicyQualifierId(ctx, &(f->policyQualifierId));
    PKIDropInPlaceANY(ctx, &(f->qualifier));
} /* PKIDropInPlacePolicyQualifierInfo */

size_t PKIPackPolicyQualifierInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIPolicyQualifierInfo *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofPolicyQualifierInfo(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field policyQualifierId of PolicyQualifierInfo */
    bytesused += PKIPackPolicyQualifierIdInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->policyQualifierId), PKIID_PolicyQualifierId, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field qualifier of PolicyQualifierInfo */
    bytesused += PKIPackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->qualifier), PKIID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackPolicyQualifierInfoInternal */

size_t PKIUnpkInPlacePolicyQualifierInfo(
    PKICONTEXT *ctx,
    PKIPolicyQualifierInfo *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PolicyQualifierInfo" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field policyQualifierId of PolicyQualifierInfo */
    bytesused += PKIUnpkInPlacePolicyQualifierId(ctx, &(asnstruct->policyQualifierId), buf+bytesused,
                        localsize-bytesused, PKIID_PolicyQualifierId, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field qualifier of PolicyQualifierInfo */
    bytesused += PKIUnpkInPlaceANY(ctx, &(asnstruct->qualifier), buf+bytesused,
                        localsize-bytesused, PKIID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacePolicyQualifierInfo */

size_t PKIUnpackPolicyQualifierInfoInternal(
    PKICONTEXT *ctx,
    PKIPolicyQualifierInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIPolicyQualifierInfo *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewPolicyQualifierInfo(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacePolicyQualifierInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreePolicyQualifierInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackPolicyQualifierInfoInternal */


/******************************************************************
 * Routines for PrivateKeyUsagePeriod
 ******************************************************************/

size_t PKISizeofPrivateKeyUsagePeriodInternal(
    PKIPrivateKeyUsagePeriod *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofGeneralizedTimeInternal(asnstruct->notBefore, PKITRUE, PKIFALSE)
          + PKISizeofGeneralizedTimeInternal(asnstruct->notAfter, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofPrivateKeyUsagePeriodInternal */

void PKIDropInPlacePrivateKeyUsagePeriod(
    PKICONTEXT *ctx,
    PKIPrivateKeyUsagePeriod *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeGeneralizedTime(ctx, f->notBefore);
    f->notBefore = NULL;
    PKIFreeGeneralizedTime(ctx, f->notAfter);
    f->notAfter = NULL;
} /* PKIDropInPlacePrivateKeyUsagePeriod */

size_t PKIPackPrivateKeyUsagePeriodInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIPrivateKeyUsagePeriod *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofPrivateKeyUsagePeriod(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field notBefore of PrivateKeyUsagePeriod */
    if (asnstruct->notBefore != NULL) { /* optional */
        bytesused += PKIPackGeneralizedTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->notBefore, 0x80 | 0x00, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field notAfter of PrivateKeyUsagePeriod */
    if (asnstruct->notAfter != NULL) { /* optional */
        bytesused += PKIPackGeneralizedTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->notAfter, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackPrivateKeyUsagePeriodInternal */

size_t PKIUnpkInPlacePrivateKeyUsagePeriod(
    PKICONTEXT *ctx,
    PKIPrivateKeyUsagePeriod *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PrivateKeyUsagePeriod" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field notBefore of PrivateKeyUsagePeriod */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->notBefore != NULL)
        PKIFreeGeneralizedTime(ctx, asnstruct->notBefore);
    bytesused += PKIUnpackGeneralizedTimeInternal(ctx, &(asnstruct->notBefore),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field notAfter of PrivateKeyUsagePeriod */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->notAfter != NULL)
        PKIFreeGeneralizedTime(ctx, asnstruct->notAfter);
    bytesused += PKIUnpackGeneralizedTimeInternal(ctx, &(asnstruct->notAfter),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacePrivateKeyUsagePeriod */

size_t PKIUnpackPrivateKeyUsagePeriodInternal(
    PKICONTEXT *ctx,
    PKIPrivateKeyUsagePeriod **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIPrivateKeyUsagePeriod *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewPrivateKeyUsagePeriod(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacePrivateKeyUsagePeriod(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreePrivateKeyUsagePeriod(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackPrivateKeyUsagePeriodInternal */


/******************************************************************
 * Routines for RSAKey
 ******************************************************************/

size_t PKISizeofRSAKeyInternal(
    PKIRSAKey *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofINTEGERInternal(&asnstruct->modulus, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->exponent, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofRSAKeyInternal */

void PKIDropInPlaceRSAKey(
    PKICONTEXT *ctx,
    PKIRSAKey *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceINTEGER(ctx, &(f->modulus));
    PKIDropInPlaceINTEGER(ctx, &(f->exponent));
} /* PKIDropInPlaceRSAKey */

size_t PKIPackRSAKeyInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRSAKey *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofRSAKey(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field modulus of RSAKey */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->modulus), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field exponent of RSAKey */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->exponent), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackRSAKeyInternal */

size_t PKIUnpkInPlaceRSAKey(
    PKICONTEXT *ctx,
    PKIRSAKey *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "RSAKey" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field modulus of RSAKey */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->modulus), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field exponent of RSAKey */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->exponent), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceRSAKey */

size_t PKIUnpackRSAKeyInternal(
    PKICONTEXT *ctx,
    PKIRSAKey **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRSAKey *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewRSAKey(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceRSAKey(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeRSAKey(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRSAKeyInternal */


/******************************************************************
 * Routines for Time
 ******************************************************************/

size_t PKISizeofTimeInternal(
    PKITime *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PKIID_UTCTime:
      case 0x20|PKIID_UTCTime:
        body_size = PKISizeofUTCTimeInternal((PKIUTCTime *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case PKIID_GeneralizedTime:
      case 0x20|PKIID_GeneralizedTime:
        body_size = PKISizeofGeneralizedTimeInternal((PKIGeneralizedTime *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofTimeInternal */

void PKIDropInPlaceTime(
    PKICONTEXT *ctx,
    PKITime *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PKIID_UTCTime:
    case 0x20|PKIID_UTCTime:
        PKIFreeUTCTime(ctx, (PKIUTCTime *)( f->data ));
        break;
    case PKIID_GeneralizedTime:
    case 0x20|PKIID_GeneralizedTime:
        PKIFreeGeneralizedTime(ctx, (PKIGeneralizedTime *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceTime */

size_t PKIPackTimeInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKITime *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;

    (void)tag; /* unused */

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofTime(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    switch ( (asnstruct->CHOICE_field_type & 0xDF) ) {

    case PKIID_UTCTime:
        bytesused += PKIPackUTCTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIUTCTime *)(asnstruct->data),
                     PKIID_UTCTime,
                     erret);
        break;

    case PKIID_GeneralizedTime:
        bytesused += PKIPackGeneralizedTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIGeneralizedTime *)(asnstruct->data),
                     PKIID_GeneralizedTime,
                     erret);
        break;

    default:
        PKIERR( PKIErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

  return bytesused;
} /* PKIPackTimeInternal */

size_t PKIUnpkInPlaceTime(
     PKICONTEXT *ctx,
     PKITime *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    switch (*buf) {

    /* utcTime */
    case PKIID_UTCTime:
    case 0x20|PKIID_UTCTime:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewUTCTime(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceUTCTime(ctx, (PKIUTCTime *)(asnstruct->data),
                    buf, buflen,
                    PKIID_UTCTime, erret));
        /*NOTREACHED*/
        break;

    /* generalTime */
    case PKIID_GeneralizedTime:
    case 0x20|PKIID_GeneralizedTime:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewGeneralizedTime(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceGeneralizedTime(ctx, (PKIGeneralizedTime *)(asnstruct->data),
                    buf, buflen,
                    PKIID_GeneralizedTime, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceTime */

size_t PKIUnpackTimeInternal(
    PKICONTEXT *ctx,
    PKITime **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKITime *local = NULL ;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    local = PKINewTime(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceTime(ctx, local, buf, buflen, tag, erret);
    if (*erret == PKIErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) PKIFreeTime(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) PKIFreeTime(ctx, local);
        return 0;
    }

    *asnstruct = local;
    return bytesused;
} /* PKIUnpackTimeInternal */


/******************************************************************
 * Routines for ValidationParms
 ******************************************************************/

size_t PKISizeofValidationParmsInternal(
    PKIValidationParms *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofBIT_STRINGInternal(&asnstruct->seed, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->pgenCounter, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofValidationParmsInternal */

void PKIDropInPlaceValidationParms(
    PKICONTEXT *ctx,
    PKIValidationParms *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceBIT_STRING(ctx, &(f->seed));
    PKIDropInPlaceINTEGER(ctx, &(f->pgenCounter));
} /* PKIDropInPlaceValidationParms */

size_t PKIPackValidationParmsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIValidationParms *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofValidationParms(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field seed of ValidationParms */
    bytesused += PKIPackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->seed), PKIID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field pgenCounter of ValidationParms */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->pgenCounter), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackValidationParmsInternal */

size_t PKIUnpkInPlaceValidationParms(
    PKICONTEXT *ctx,
    PKIValidationParms *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "ValidationParms" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field seed of ValidationParms */
    bytesused += PKIUnpkInPlaceBIT_STRING(ctx, &(asnstruct->seed), buf+bytesused,
                        localsize-bytesused, PKIID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field pgenCounter of ValidationParms */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->pgenCounter), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceValidationParms */

size_t PKIUnpackValidationParmsInternal(
    PKICONTEXT *ctx,
    PKIValidationParms **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIValidationParms *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewValidationParms(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceValidationParms(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeValidationParms(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackValidationParmsInternal */


/******************************************************************
 * Routines for values_SET_OF
 ******************************************************************/

size_t PKISizeofvalues_SET_OFInternal(
    PKIvalues_SET_OF *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;
    long i, lth;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_values_SET_OF)
        lth = PKIMAX_values_SET_OF;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofAttributeValueInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofvalues_SET_OFInternal */

void PKIDropInPlacevalues_SET_OF(
    PKICONTEXT *ctx,
    PKIvalues_SET_OF *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n;
    if (lth > PKIMAX_values_SET_OF)
        lth = PKIMAX_values_SET_OF;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeAttributeValue(ctx, (f->elt)[i] );
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlacevalues_SET_OF */

size_t PKIPackvalues_SET_OFInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIvalues_SET_OF *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i, j;
    size_t length;
    size_t max = 0;
    PKIVariableBlock temp[PKIMAX_values_SET_OF];

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0; /* nothing to pack */

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_values_SET_OF) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofvalues_SET_OF(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SET_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    if (numElem == 1) {
        bytesused += PKIPackAttributeValueInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_AttributeValue, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofAttributeValue(ctx, (asnstruct->elt)[i], PKITRUE);
            if (length > max)
                max = length;
            temp[i].len = length;
        }

        /* temporarily allocate and pack */
        *erret = 0;
        for (i=0; i<numElem; i++) {
            temp[i].val = (unsigned char *)PKIAlloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) PKIPackAttributeValueInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_AttributeValue, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PKIFree(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PKIVariableBlock), PKICompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PKIERR(PKIErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PKIFree(ctx->memMgr, temp[j].val);
                return 0;
            }

        /* pack for real and deallocate temp */
        for (i=0; i<numElem; i++) {
            (void)memcpy(buf+bytesused, temp[i].val, temp[i].len);
            bytesused += temp[i].len;
            if (bytesused > datasize)
                break;
            PKIFree(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackvalues_SET_OFInternal */

size_t PKIUnpkInPlacevalues_SET_OF(
    PKICONTEXT *ctx,
    PKIvalues_SET_OF *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t datasize;
    size_t localsize;
    long i;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "values_SET_OF");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
       return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    PKITRACE_INCR_LEVEL;
    bytesused = 1; /* consume the tag byte */

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_values_SET_OF) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 ) {
            break;
        }

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewAttributeValue(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceAttributeValue(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_AttributeValue, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacevalues_SET_OF */

size_t PKIUnpackvalues_SET_OFInternal(
    PKICONTEXT *ctx,
    PKIvalues_SET_OF **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIvalues_SET_OF *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewvalues_SET_OF(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacevalues_SET_OF(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreevalues_SET_OF(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackvalues_SET_OFInternal */


/******************************************************************
 * Routines for Attribute
 ******************************************************************/

size_t PKISizeofAttributeInternal(
    PKIAttribute *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofAttributeTypeInternal(&asnstruct->type, PKITRUE, PKIFALSE)
          + PKISizeofvalues_SET_OFInternal(&asnstruct->values, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofAttributeInternal */

void PKIDropInPlaceAttribute(
    PKICONTEXT *ctx,
    PKIAttribute *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceAttributeType(ctx, &(f->type));
    PKIDropInPlacevalues_SET_OF(ctx, &(f->values));
} /* PKIDropInPlaceAttribute */

size_t PKIPackAttributeInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAttribute *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofAttribute(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field type of Attribute */
    bytesused += PKIPackAttributeTypeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->type), PKIID_AttributeType, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field values of Attribute */
    bytesused += PKIPackvalues_SET_OFInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->values), PKIID_values_SET_OF, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAttributeInternal */

size_t PKIUnpkInPlaceAttribute(
    PKICONTEXT *ctx,
    PKIAttribute *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Attribute" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field type of Attribute */
    bytesused += PKIUnpkInPlaceAttributeType(ctx, &(asnstruct->type), buf+bytesused,
                        localsize-bytesused, PKIID_AttributeType, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field values of Attribute */
    bytesused += PKIUnpkInPlacevalues_SET_OF(ctx, &(asnstruct->values), buf+bytesused,
                        localsize-bytesused, PKIID_values_SET_OF, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAttribute */

size_t PKIUnpackAttributeInternal(
    PKICONTEXT *ctx,
    PKIAttribute **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAttribute *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAttribute(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAttribute(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAttribute(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAttributeInternal */


/******************************************************************
 * Routines for DomainParameters
 ******************************************************************/

size_t PKISizeofDomainParametersInternal(
    PKIDomainParameters *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofINTEGERInternal(&asnstruct->p, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->g, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(&asnstruct->q, PKITRUE, PKIFALSE)
          + PKISizeofINTEGERInternal(asnstruct->j, PKITRUE, PKIFALSE)
          + PKISizeofValidationParmsInternal(asnstruct->validationParms, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofDomainParametersInternal */

void PKIDropInPlaceDomainParameters(
    PKICONTEXT *ctx,
    PKIDomainParameters *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceINTEGER(ctx, &(f->p));
    PKIDropInPlaceINTEGER(ctx, &(f->g));
    PKIDropInPlaceINTEGER(ctx, &(f->q));
    PKIFreeINTEGER(ctx, f->j);
    f->j = NULL;
    PKIFreeValidationParms(ctx, f->validationParms);
    f->validationParms = NULL;
} /* PKIDropInPlaceDomainParameters */

size_t PKIPackDomainParametersInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDomainParameters *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDomainParameters(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field p of DomainParameters */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->p), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field g of DomainParameters */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->g), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field q of DomainParameters */
    bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->q), PKIID_INTEGER, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field j of DomainParameters */
    if (asnstruct->j != NULL) { /* optional */
        bytesused += PKIPackINTEGERInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->j, PKIID_INTEGER, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field validationParms of DomainParameters */
    if (asnstruct->validationParms != NULL) { /* optional */
        bytesused += PKIPackValidationParmsInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->validationParms, PKIID_ValidationParms, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackDomainParametersInternal */

size_t PKIUnpkInPlaceDomainParameters(
    PKICONTEXT *ctx,
    PKIDomainParameters *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "DomainParameters" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field p of DomainParameters */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->p), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field g of DomainParameters */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->g), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field q of DomainParameters */
    bytesused += PKIUnpkInPlaceINTEGER(ctx, &(asnstruct->q), buf+bytesused,
                        localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field j of DomainParameters */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->j != NULL)
        PKIFreeINTEGER(ctx, asnstruct->j);
    bytesused += PKIUnpackINTEGERInternal(ctx, &(asnstruct->j),
                    buf+bytesused, localsize-bytesused, PKIID_INTEGER, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field validationParms of DomainParameters */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->validationParms != NULL)
        PKIFreeValidationParms(ctx, asnstruct->validationParms);
    bytesused += PKIUnpackValidationParmsInternal(ctx, &(asnstruct->validationParms),
                    buf+bytesused, localsize-bytesused, PKIID_ValidationParms, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceDomainParameters */

size_t PKIUnpackDomainParametersInternal(
    PKICONTEXT *ctx,
    PKIDomainParameters **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDomainParameters *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewDomainParameters(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceDomainParameters(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeDomainParameters(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDomainParametersInternal */


/******************************************************************
 * Routines for EDIPartyName
 ******************************************************************/

size_t PKISizeofEDIPartyNameInternal(
    PKIEDIPartyName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofDirectoryStringInternal(asnstruct->nameAssigner, PKITRUE, PKITRUE)
          + PKISizeofDirectoryStringInternal(&asnstruct->partyName, PKITRUE, PKITRUE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofEDIPartyNameInternal */

void PKIDropInPlaceEDIPartyName(
    PKICONTEXT *ctx,
    PKIEDIPartyName *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeDirectoryString(ctx, f->nameAssigner);
    f->nameAssigner = NULL;
    PKIDropInPlaceDirectoryString(ctx, &(f->partyName));
} /* PKIDropInPlaceEDIPartyName */

size_t PKIPackEDIPartyNameInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIEDIPartyName *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofEDIPartyName(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field nameAssigner of EDIPartyName */
    if (asnstruct->nameAssigner != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofDirectoryString(ctx, asnstruct->nameAssigner, PKITRUE));
        bytesused += PKIPackDirectoryStringInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->nameAssigner, PKIID_DirectoryString, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field partyName of EDIPartyName */
    bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x01, PKISizeofDirectoryString(ctx, &(asnstruct->partyName ), PKITRUE));
    bytesused += PKIPackDirectoryStringInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->partyName), PKIID_DirectoryString, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackEDIPartyNameInternal */

size_t PKIUnpkInPlaceEDIPartyName(
    PKICONTEXT *ctx,
    PKIEDIPartyName *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "EDIPartyName" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field nameAssigner of EDIPartyName */
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x00,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->nameAssigner != NULL)
                PKIFreeDirectoryString(ctx, asnstruct->nameAssigner);
            bytesused += PKIUnpackDirectoryStringInternal(ctx, &(asnstruct->nameAssigner),
                    buf+bytesused, localsize-bytesused, PKIID_DirectoryString, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->nameAssigner != NULL)
                PKIFreeDirectoryString(ctx, asnstruct->nameAssigner);
            bytesused += PKIUnpackDirectoryStringInternal(ctx, &(asnstruct->nameAssigner),
                       buf+bytesused, localsize-bytesused, PKIID_DirectoryString, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field partyName of EDIPartyName */
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x01,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x01, 0x01);
            PKITRACE_INCR_LEVEL;
            bytesused += PKIUnpkInPlaceDirectoryString(ctx, &(asnstruct->partyName), buf+bytesused,
                        localsize-bytesused, PKIID_DirectoryString, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x01, 0x01);
            PKITRACE_INCR_LEVEL;
            bytesused += PKIUnpkInPlaceDirectoryString(ctx, &(asnstruct->partyName), buf+bytesused,
                        localsize-bytesused, PKIID_DirectoryString, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceEDIPartyName */

size_t PKIUnpackEDIPartyNameInternal(
    PKICONTEXT *ctx,
    PKIEDIPartyName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIEDIPartyName *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewEDIPartyName(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceEDIPartyName(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeEDIPartyName(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackEDIPartyNameInternal */


/******************************************************************
 * Routines for Extensions
 ******************************************************************/

size_t PKISizeofExtensionsInternal(
    PKIExtensions *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_Extensions)
        lth = PKIMAX_Extensions;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofExtensionInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofExtensionsInternal */

void PKIDropInPlaceExtensions(
    PKICONTEXT *ctx,
    PKIExtensions *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_Extensions)
        lth = PKIMAX_Extensions ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeExtension(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceExtensions */

size_t PKIPackExtensionsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtensions *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_Extensions) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofExtensions(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackExtensionInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_Extension, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackExtensionsInternal */

size_t PKIUnpkInPlaceExtensions(
     PKICONTEXT *ctx,
     PKIExtensions *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "Extensions");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_Extensions) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewExtension(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceExtension(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_Extension, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceExtensions */

size_t PKIUnpackExtensionsInternal(
    PKICONTEXT *ctx,
    PKIExtensions **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtensions *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewExtensions(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceExtensions(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeExtensions(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackExtensionsInternal */


/******************************************************************
 * Routines for NoticeReference
 ******************************************************************/

size_t PKISizeofNoticeReferenceInternal(
    PKINoticeReference *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofDisplayTextInternal(&asnstruct->organization, PKITRUE, PKIFALSE)
          + PKISizeofnoticeNumbers_SEQ_OFInternal(&asnstruct->noticeNumbers, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofNoticeReferenceInternal */

void PKIDropInPlaceNoticeReference(
    PKICONTEXT *ctx,
    PKINoticeReference *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceDisplayText(ctx, &(f->organization));
    PKIDropInPlacenoticeNumbers_SEQ_OF(ctx, &(f->noticeNumbers));
} /* PKIDropInPlaceNoticeReference */

size_t PKIPackNoticeReferenceInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKINoticeReference *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofNoticeReference(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field organization of NoticeReference */
    bytesused += PKIPackDisplayTextInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->organization), PKIID_DisplayText, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field noticeNumbers of NoticeReference */
    bytesused += PKIPacknoticeNumbers_SEQ_OFInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->noticeNumbers), PKIID_noticeNumbers_SEQ_OF, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackNoticeReferenceInternal */

size_t PKIUnpkInPlaceNoticeReference(
    PKICONTEXT *ctx,
    PKINoticeReference *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "NoticeReference" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field organization of NoticeReference */
    bytesused += PKIUnpkInPlaceDisplayText(ctx, &(asnstruct->organization), buf+bytesused,
                        localsize-bytesused, PKIID_DisplayText, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field noticeNumbers of NoticeReference */
    bytesused += PKIUnpkInPlacenoticeNumbers_SEQ_OF(ctx, &(asnstruct->noticeNumbers), buf+bytesused,
                        localsize-bytesused, PKIID_noticeNumbers_SEQ_OF, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceNoticeReference */

size_t PKIUnpackNoticeReferenceInternal(
    PKICONTEXT *ctx,
    PKINoticeReference **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKINoticeReference *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewNoticeReference(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceNoticeReference(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeNoticeReference(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackNoticeReferenceInternal */


/******************************************************************
 * Routines for PolicyMappings
 ******************************************************************/

size_t PKISizeofPolicyMappingsInternal(
    PKIPolicyMappings *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_PolicyMappings)
        lth = PKIMAX_PolicyMappings;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofPolicyMappings_SEQUENCEInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofPolicyMappingsInternal */

void PKIDropInPlacePolicyMappings(
    PKICONTEXT *ctx,
    PKIPolicyMappings *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_PolicyMappings)
        lth = PKIMAX_PolicyMappings ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreePolicyMappings_SEQUENCE(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlacePolicyMappings */

size_t PKIPackPolicyMappingsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIPolicyMappings *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_PolicyMappings) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofPolicyMappings(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackPolicyMappings_SEQUENCEInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_PolicyMappings_SEQUENCE, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackPolicyMappingsInternal */

size_t PKIUnpkInPlacePolicyMappings(
     PKICONTEXT *ctx,
     PKIPolicyMappings *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "PolicyMappings");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_PolicyMappings) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewPolicyMappings_SEQUENCE(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlacePolicyMappings_SEQUENCE(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_PolicyMappings_SEQUENCE, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacePolicyMappings */

size_t PKIUnpackPolicyMappingsInternal(
    PKICONTEXT *ctx,
    PKIPolicyMappings **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIPolicyMappings *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewPolicyMappings(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacePolicyMappings(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreePolicyMappings(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackPolicyMappingsInternal */


/******************************************************************
 * Routines for RelativeDistinguishedName
 ******************************************************************/

size_t PKISizeofRelativeDistinguishedNameInternal(
    PKIRelativeDistinguishedName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;
    long i, lth;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_RelativeDistinguishedName)
        lth = PKIMAX_RelativeDistinguishedName;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofAttributeTypeAndValueInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofRelativeDistinguishedNameInternal */

void PKIDropInPlaceRelativeDistinguishedName(
    PKICONTEXT *ctx,
    PKIRelativeDistinguishedName *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n;
    if (lth > PKIMAX_RelativeDistinguishedName)
        lth = PKIMAX_RelativeDistinguishedName;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeAttributeTypeAndValue(ctx, (f->elt)[i] );
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceRelativeDistinguishedName */

size_t PKIPackRelativeDistinguishedNameInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRelativeDistinguishedName *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i, j;
    size_t length;
    size_t max = 0;
    PKIVariableBlock temp[PKIMAX_RelativeDistinguishedName];

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0; /* nothing to pack */

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_RelativeDistinguishedName) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofRelativeDistinguishedName(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SET_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    if (numElem == 1) {
        bytesused += PKIPackAttributeTypeAndValueInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_AttributeTypeAndValue, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofAttributeTypeAndValue(ctx, (asnstruct->elt)[i], PKITRUE);
            if (length > max)
                max = length;
            temp[i].len = length;
        }

        /* temporarily allocate and pack */
        *erret = 0;
        for (i=0; i<numElem; i++) {
            temp[i].val = (unsigned char *)PKIAlloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) PKIPackAttributeTypeAndValueInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_AttributeTypeAndValue, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PKIFree(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PKIVariableBlock), PKICompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PKIERR(PKIErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PKIFree(ctx->memMgr, temp[j].val);
                return 0;
            }

        /* pack for real and deallocate temp */
        for (i=0; i<numElem; i++) {
            (void)memcpy(buf+bytesused, temp[i].val, temp[i].len);
            bytesused += temp[i].len;
            if (bytesused > datasize)
                break;
            PKIFree(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackRelativeDistinguishedNameInternal */

size_t PKIUnpkInPlaceRelativeDistinguishedName(
    PKICONTEXT *ctx,
    PKIRelativeDistinguishedName *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t datasize;
    size_t localsize;
    long i;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "RelativeDistinguishedName");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
       return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    PKITRACE_INCR_LEVEL;
    bytesused = 1; /* consume the tag byte */

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_RelativeDistinguishedName) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 ) {
            break;
        }

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewAttributeTypeAndValue(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceAttributeTypeAndValue(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_AttributeTypeAndValue, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceRelativeDistinguishedName */

size_t PKIUnpackRelativeDistinguishedNameInternal(
    PKICONTEXT *ctx,
    PKIRelativeDistinguishedName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRelativeDistinguishedName *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewRelativeDistinguishedName(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceRelativeDistinguishedName(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeRelativeDistinguishedName(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRelativeDistinguishedNameInternal */


/******************************************************************
 * Routines for SubjectPublicKeyInfo
 ******************************************************************/

size_t PKISizeofSubjectPublicKeyInfoInternal(
    PKISubjectPublicKeyInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofAlgorithmIdentifierInternal(&asnstruct->algorithm, PKITRUE, PKIFALSE)
          + PKISizeofBIT_STRINGInternal(&asnstruct->subjectPublicKey, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofSubjectPublicKeyInfoInternal */

void PKIDropInPlaceSubjectPublicKeyInfo(
    PKICONTEXT *ctx,
    PKISubjectPublicKeyInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->algorithm));
    PKIDropInPlaceBIT_STRING(ctx, &(f->subjectPublicKey));
} /* PKIDropInPlaceSubjectPublicKeyInfo */

size_t PKIPackSubjectPublicKeyInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKISubjectPublicKeyInfo *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofSubjectPublicKeyInfo(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field algorithm of SubjectPublicKeyInfo */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->algorithm), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectPublicKey of SubjectPublicKeyInfo */
    bytesused += PKIPackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKey), PKIID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackSubjectPublicKeyInfoInternal */

size_t PKIUnpkInPlaceSubjectPublicKeyInfo(
    PKICONTEXT *ctx,
    PKISubjectPublicKeyInfo *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "SubjectPublicKeyInfo" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field algorithm of SubjectPublicKeyInfo */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->algorithm), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectPublicKey of SubjectPublicKeyInfo */
    bytesused += PKIUnpkInPlaceBIT_STRING(ctx, &(asnstruct->subjectPublicKey), buf+bytesused,
                        localsize-bytesused, PKIID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceSubjectPublicKeyInfo */

size_t PKIUnpackSubjectPublicKeyInfoInternal(
    PKICONTEXT *ctx,
    PKISubjectPublicKeyInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKISubjectPublicKeyInfo *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewSubjectPublicKeyInfo(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceSubjectPublicKeyInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeSubjectPublicKeyInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackSubjectPublicKeyInfoInternal */


/******************************************************************
 * Routines for Validity
 ******************************************************************/

size_t PKISizeofValidityInternal(
    PKIValidity *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofTimeInternal(&asnstruct->notBefore, PKITRUE, PKIFALSE)
          + PKISizeofTimeInternal(&asnstruct->notAfter, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofValidityInternal */

void PKIDropInPlaceValidity(
    PKICONTEXT *ctx,
    PKIValidity *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceTime(ctx, &(f->notBefore));
    PKIDropInPlaceTime(ctx, &(f->notAfter));
} /* PKIDropInPlaceValidity */

size_t PKIPackValidityInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIValidity *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofValidity(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field notBefore of Validity */
    bytesused += PKIPackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->notBefore), PKIID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field notAfter of Validity */
    bytesused += PKIPackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->notAfter), PKIID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackValidityInternal */

size_t PKIUnpkInPlaceValidity(
    PKICONTEXT *ctx,
    PKIValidity *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Validity" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field notBefore of Validity */
    bytesused += PKIUnpkInPlaceTime(ctx, &(asnstruct->notBefore), buf+bytesused,
                        localsize-bytesused, PKIID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field notAfter of Validity */
    bytesused += PKIUnpkInPlaceTime(ctx, &(asnstruct->notAfter), buf+bytesused,
                        localsize-bytesused, PKIID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceValidity */

size_t PKIUnpackValidityInternal(
    PKICONTEXT *ctx,
    PKIValidity **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIValidity *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewValidity(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceValidity(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeValidity(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackValidityInternal */


/******************************************************************
 * Routines for XCertificate
 ******************************************************************/

size_t PKISizeofXCertificateInternal(
    PKIXCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofANYInternal(&asnstruct->tbsCertificate, PKITRUE, PKIFALSE)
          + PKISizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofBIT_STRINGInternal(&asnstruct->signature, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofXCertificateInternal */

void PKIDropInPlaceXCertificate(
    PKICONTEXT *ctx,
    PKIXCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceANY(ctx, &(f->tbsCertificate));
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    PKIDropInPlaceBIT_STRING(ctx, &(f->signature));
} /* PKIDropInPlaceXCertificate */

size_t PKIPackXCertificateInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIXCertificate *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofXCertificate(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field tbsCertificate of XCertificate */
    bytesused += PKIPackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertificate), PKIID_ANY, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signatureAlgorithm of XCertificate */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signatureAlgorithm), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of XCertificate */
    bytesused += PKIPackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackXCertificateInternal */

size_t PKIUnpkInPlaceXCertificate(
    PKICONTEXT *ctx,
    PKIXCertificate *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "XCertificate" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field tbsCertificate of XCertificate */
    bytesused += PKIUnpkInPlaceANY(ctx, &(asnstruct->tbsCertificate), buf+bytesused,
                        localsize-bytesused, PKIID_ANY, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signatureAlgorithm of XCertificate */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signatureAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of XCertificate */
    bytesused += PKIUnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceXCertificate */

size_t PKIUnpackXCertificateInternal(
    PKICONTEXT *ctx,
    PKIXCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIXCertificate *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewXCertificate(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceXCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeXCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackXCertificateInternal */


/******************************************************************
 * Routines for policyQualifiers_SEQ_OF
 ******************************************************************/

size_t PKISizeofpolicyQualifiers_SEQ_OFInternal(
    PKIpolicyQualifiers_SEQ_OF *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_policyQualifiers_SEQ_OF)
        lth = PKIMAX_policyQualifiers_SEQ_OF;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofPolicyQualifierInfoInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofpolicyQualifiers_SEQ_OFInternal */

void PKIDropInPlacepolicyQualifiers_SEQ_OF(
    PKICONTEXT *ctx,
    PKIpolicyQualifiers_SEQ_OF *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_policyQualifiers_SEQ_OF)
        lth = PKIMAX_policyQualifiers_SEQ_OF ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreePolicyQualifierInfo(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlacepolicyQualifiers_SEQ_OF */

size_t PKIPackpolicyQualifiers_SEQ_OFInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIpolicyQualifiers_SEQ_OF *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_policyQualifiers_SEQ_OF) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofpolicyQualifiers_SEQ_OF(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackPolicyQualifierInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_PolicyQualifierInfo, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackpolicyQualifiers_SEQ_OFInternal */

size_t PKIUnpkInPlacepolicyQualifiers_SEQ_OF(
     PKICONTEXT *ctx,
     PKIpolicyQualifiers_SEQ_OF *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "policyQualifiers_SEQ_OF");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_policyQualifiers_SEQ_OF) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewPolicyQualifierInfo(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlacePolicyQualifierInfo(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_PolicyQualifierInfo, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacepolicyQualifiers_SEQ_OF */

size_t PKIUnpackpolicyQualifiers_SEQ_OFInternal(
    PKICONTEXT *ctx,
    PKIpolicyQualifiers_SEQ_OF **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIpolicyQualifiers_SEQ_OF *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewpolicyQualifiers_SEQ_OF(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacepolicyQualifiers_SEQ_OF(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreepolicyQualifiers_SEQ_OF(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackpolicyQualifiers_SEQ_OFInternal */


/******************************************************************
 * Routines for Attributes
 ******************************************************************/

size_t PKISizeofAttributesInternal(
    PKIAttributes *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;
    long i, lth;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_Attributes)
        lth = PKIMAX_Attributes;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofAttributeInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofAttributesInternal */

void PKIDropInPlaceAttributes(
    PKICONTEXT *ctx,
    PKIAttributes *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n;
    if (lth > PKIMAX_Attributes)
        lth = PKIMAX_Attributes;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeAttribute(ctx, (f->elt)[i] );
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceAttributes */

size_t PKIPackAttributesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAttributes *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i, j;
    size_t length;
    size_t max = 0;
    PKIVariableBlock temp[PKIMAX_Attributes];

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0; /* nothing to pack */

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_Attributes) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofAttributes(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SET_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    if (numElem == 1) {
        bytesused += PKIPackAttributeInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_Attribute, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofAttribute(ctx, (asnstruct->elt)[i], PKITRUE);
            if (length > max)
                max = length;
            temp[i].len = length;
        }

        /* temporarily allocate and pack */
        *erret = 0;
        for (i=0; i<numElem; i++) {
            temp[i].val = (unsigned char *)PKIAlloc(ctx->memMgr, max);
            memset(temp[i].val, 0, max);
            (void) PKIPackAttributeInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_Attribute, erret );
            if (*erret != 0) {
                for (j=0; j<i; j++)
                    PKIFree(ctx->memMgr, temp[j].val);
                return 0;
            }
        }

        /* sort and look for duplicates */
        qsort(temp, numElem, sizeof(PKIVariableBlock), PKICompareElems);
        for (i=0; i<(numElem-1); i++)
            if (memcmp(temp[i].val, temp[i+1].val, max) == 0) {
                PKIERR(PKIErrPackSETOFUnsortable);
                for (j=0; j<i; j++)
                    PKIFree(ctx->memMgr, temp[j].val);
                return 0;
            }

        /* pack for real and deallocate temp */
        for (i=0; i<numElem; i++) {
            (void)memcpy(buf+bytesused, temp[i].val, temp[i].len);
            bytesused += temp[i].len;
            if (bytesused > datasize)
                break;
            PKIFree(ctx->memMgr, temp[i].val);
        }
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAttributesInternal */

size_t PKIUnpkInPlaceAttributes(
    PKICONTEXT *ctx,
    PKIAttributes *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t datasize;
    size_t localsize;
    long i;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x31, "SET OF", "Attributes");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
       return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    PKITRACE_INCR_LEVEL;
    bytesused = 1; /* consume the tag byte */

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_Attributes) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 ) {
            break;
        }

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewAttribute(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceAttribute(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_Attribute, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAttributes */

size_t PKIUnpackAttributesInternal(
    PKICONTEXT *ctx,
    PKIAttributes **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAttributes *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAttributes(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAttributes(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAttributes(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAttributesInternal */


/******************************************************************
 * Routines for PolicyInformation
 ******************************************************************/

size_t PKISizeofPolicyInformationInternal(
    PKIPolicyInformation *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofCertPolicyIdInternal(&asnstruct->policyIdentifier, PKITRUE, PKIFALSE)
          + PKISizeofpolicyQualifiers_SEQ_OFInternal(asnstruct->policyQualifiers, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofPolicyInformationInternal */

void PKIDropInPlacePolicyInformation(
    PKICONTEXT *ctx,
    PKIPolicyInformation *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceCertPolicyId(ctx, &(f->policyIdentifier));
    PKIFreepolicyQualifiers_SEQ_OF(ctx, f->policyQualifiers);
    f->policyQualifiers = NULL;
} /* PKIDropInPlacePolicyInformation */

size_t PKIPackPolicyInformationInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIPolicyInformation *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofPolicyInformation(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field policyIdentifier of PolicyInformation */
    bytesused += PKIPackCertPolicyIdInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->policyIdentifier), PKIID_CertPolicyId, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field policyQualifiers of PolicyInformation */
    if (asnstruct->policyQualifiers != NULL) { /* optional */
        bytesused += PKIPackpolicyQualifiers_SEQ_OFInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->policyQualifiers, PKIID_policyQualifiers_SEQ_OF, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackPolicyInformationInternal */

size_t PKIUnpkInPlacePolicyInformation(
    PKICONTEXT *ctx,
    PKIPolicyInformation *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "PolicyInformation" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field policyIdentifier of PolicyInformation */
    bytesused += PKIUnpkInPlaceCertPolicyId(ctx, &(asnstruct->policyIdentifier), buf+bytesused,
                        localsize-bytesused, PKIID_CertPolicyId, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field policyQualifiers of PolicyInformation */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->policyQualifiers != NULL)
        PKIFreepolicyQualifiers_SEQ_OF(ctx, asnstruct->policyQualifiers);
    bytesused += PKIUnpackpolicyQualifiers_SEQ_OFInternal(ctx, &(asnstruct->policyQualifiers),
                    buf+bytesused, localsize-bytesused, PKIID_policyQualifiers_SEQ_OF, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlacePolicyInformation */

size_t PKIUnpackPolicyInformationInternal(
    PKICONTEXT *ctx,
    PKIPolicyInformation **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIPolicyInformation *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewPolicyInformation(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlacePolicyInformation(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreePolicyInformation(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackPolicyInformationInternal */


/******************************************************************
 * Routines for RDNSequence
 ******************************************************************/

size_t PKISizeofRDNSequenceInternal(
    PKIRDNSequence *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_RDNSequence)
        lth = PKIMAX_RDNSequence;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofRelativeDistinguishedNameInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofRDNSequenceInternal */

void PKIDropInPlaceRDNSequence(
    PKICONTEXT *ctx,
    PKIRDNSequence *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_RDNSequence)
        lth = PKIMAX_RDNSequence ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeRelativeDistinguishedName(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceRDNSequence */

size_t PKIPackRDNSequenceInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRDNSequence *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_RDNSequence) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofRDNSequence(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackRelativeDistinguishedNameInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_RelativeDistinguishedName, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackRDNSequenceInternal */

size_t PKIUnpkInPlaceRDNSequence(
     PKICONTEXT *ctx,
     PKIRDNSequence *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "RDNSequence");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_RDNSequence) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewRelativeDistinguishedName(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceRelativeDistinguishedName(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_RelativeDistinguishedName, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceRDNSequence */

size_t PKIUnpackRDNSequenceInternal(
    PKICONTEXT *ctx,
    PKIRDNSequence **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRDNSequence *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewRDNSequence(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceRDNSequence(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeRDNSequence(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRDNSequenceInternal */


/******************************************************************
 * Routines for RevokedCertificate
 ******************************************************************/

size_t PKISizeofRevokedCertificateInternal(
    PKIRevokedCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofCertificateSerialNumberInternal(&asnstruct->userCertificate, PKITRUE, PKIFALSE)
          + PKISizeofTimeInternal(&asnstruct->revocationDate, PKITRUE, PKIFALSE)
          + PKISizeofExtensionsInternal(asnstruct->crlEntryExtensions, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofRevokedCertificateInternal */

void PKIDropInPlaceRevokedCertificate(
    PKICONTEXT *ctx,
    PKIRevokedCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceCertificateSerialNumber(ctx, &(f->userCertificate));
    PKIDropInPlaceTime(ctx, &(f->revocationDate));
    PKIFreeExtensions(ctx, f->crlEntryExtensions);
    f->crlEntryExtensions = NULL;
} /* PKIDropInPlaceRevokedCertificate */

size_t PKIPackRevokedCertificateInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRevokedCertificate *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofRevokedCertificate(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field userCertificate of RevokedCertificate */
    bytesused += PKIPackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->userCertificate), PKIID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field revocationDate of RevokedCertificate */
    bytesused += PKIPackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->revocationDate), PKIID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field crlEntryExtensions of RevokedCertificate */
    if (asnstruct->crlEntryExtensions != NULL) { /* optional */
        bytesused += PKIPackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->crlEntryExtensions, PKIID_Extensions, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackRevokedCertificateInternal */

size_t PKIUnpkInPlaceRevokedCertificate(
    PKICONTEXT *ctx,
    PKIRevokedCertificate *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "RevokedCertificate" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field userCertificate of RevokedCertificate */
    bytesused += PKIUnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->userCertificate), buf+bytesused,
                        localsize-bytesused, PKIID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field revocationDate of RevokedCertificate */
    bytesused += PKIUnpkInPlaceTime(ctx, &(asnstruct->revocationDate), buf+bytesused,
                        localsize-bytesused, PKIID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field crlEntryExtensions of RevokedCertificate */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->crlEntryExtensions != NULL)
        PKIFreeExtensions(ctx, asnstruct->crlEntryExtensions);
    bytesused += PKIUnpackExtensionsInternal(ctx, &(asnstruct->crlEntryExtensions),
                    buf+bytesused, localsize-bytesused, PKIID_Extensions, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceRevokedCertificate */

size_t PKIUnpackRevokedCertificateInternal(
    PKICONTEXT *ctx,
    PKIRevokedCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRevokedCertificate *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewRevokedCertificate(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceRevokedCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeRevokedCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRevokedCertificateInternal */


/******************************************************************
 * Routines for SubjectDirectoryAttributes
 ******************************************************************/

size_t PKISizeofSubjectDirectoryAttributesInternal(
    PKISubjectDirectoryAttributes *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_SubjectDirectoryAttributes)
        lth = PKIMAX_SubjectDirectoryAttributes;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofAttributeInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofSubjectDirectoryAttributesInternal */

void PKIDropInPlaceSubjectDirectoryAttributes(
    PKICONTEXT *ctx,
    PKISubjectDirectoryAttributes *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_SubjectDirectoryAttributes)
        lth = PKIMAX_SubjectDirectoryAttributes ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeAttribute(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceSubjectDirectoryAttributes */

size_t PKIPackSubjectDirectoryAttributesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKISubjectDirectoryAttributes *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_SubjectDirectoryAttributes) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofSubjectDirectoryAttributes(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackAttributeInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_Attribute, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackSubjectDirectoryAttributesInternal */

size_t PKIUnpkInPlaceSubjectDirectoryAttributes(
     PKICONTEXT *ctx,
     PKISubjectDirectoryAttributes *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "SubjectDirectoryAttributes");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_SubjectDirectoryAttributes) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewAttribute(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceAttribute(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_Attribute, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceSubjectDirectoryAttributes */

size_t PKIUnpackSubjectDirectoryAttributesInternal(
    PKICONTEXT *ctx,
    PKISubjectDirectoryAttributes **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKISubjectDirectoryAttributes *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewSubjectDirectoryAttributes(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceSubjectDirectoryAttributes(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeSubjectDirectoryAttributes(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackSubjectDirectoryAttributesInternal */


/******************************************************************
 * Routines for UserNotice
 ******************************************************************/

size_t PKISizeofUserNoticeInternal(
    PKIUserNotice *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofNoticeReferenceInternal(asnstruct->noticeRef, PKITRUE, PKIFALSE)
          + PKISizeofDisplayTextInternal(asnstruct->explicitText, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofUserNoticeInternal */

void PKIDropInPlaceUserNotice(
    PKICONTEXT *ctx,
    PKIUserNotice *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeNoticeReference(ctx, f->noticeRef);
    f->noticeRef = NULL;
    PKIFreeDisplayText(ctx, f->explicitText);
    f->explicitText = NULL;
} /* PKIDropInPlaceUserNotice */

size_t PKIPackUserNoticeInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIUserNotice *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofUserNotice(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field noticeRef of UserNotice */
    if (asnstruct->noticeRef != NULL) { /* optional */
        bytesused += PKIPackNoticeReferenceInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->noticeRef, PKIID_NoticeReference, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field explicitText of UserNotice */
    if (asnstruct->explicitText != NULL) { /* optional */
        bytesused += PKIPackDisplayTextInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->explicitText, PKIID_DisplayText, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackUserNoticeInternal */

size_t PKIUnpkInPlaceUserNotice(
    PKICONTEXT *ctx,
    PKIUserNotice *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "UserNotice" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field noticeRef of UserNotice */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->noticeRef != NULL)
        PKIFreeNoticeReference(ctx, asnstruct->noticeRef);
    bytesused += PKIUnpackNoticeReferenceInternal(ctx, &(asnstruct->noticeRef),
                    buf+bytesused, localsize-bytesused, PKIID_NoticeReference, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field explicitText of UserNotice */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->explicitText != NULL)
        PKIFreeDisplayText(ctx, asnstruct->explicitText);
    bytesused += PKIUnpackDisplayTextInternal(ctx, &(asnstruct->explicitText),
                    buf+bytesused, localsize-bytesused, PKIID_DisplayText, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceUserNotice */

size_t PKIUnpackUserNoticeInternal(
    PKICONTEXT *ctx,
    PKIUserNotice **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIUserNotice *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewUserNotice(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceUserNotice(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeUserNotice(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackUserNoticeInternal */


/******************************************************************
 * Routines for CertificatePolicies
 ******************************************************************/

size_t PKISizeofCertificatePoliciesInternal(
    PKICertificatePolicies *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_CertificatePolicies)
        lth = PKIMAX_CertificatePolicies;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofPolicyInformationInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofCertificatePoliciesInternal */

void PKIDropInPlaceCertificatePolicies(
    PKICONTEXT *ctx,
    PKICertificatePolicies *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_CertificatePolicies)
        lth = PKIMAX_CertificatePolicies ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreePolicyInformation(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceCertificatePolicies */

size_t PKIPackCertificatePoliciesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICertificatePolicies *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_CertificatePolicies) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofCertificatePolicies(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackPolicyInformationInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_PolicyInformation, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackCertificatePoliciesInternal */

size_t PKIUnpkInPlaceCertificatePolicies(
     PKICONTEXT *ctx,
     PKICertificatePolicies *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "CertificatePolicies");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_CertificatePolicies) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewPolicyInformation(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlacePolicyInformation(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_PolicyInformation, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceCertificatePolicies */

size_t PKIUnpackCertificatePoliciesInternal(
    PKICONTEXT *ctx,
    PKICertificatePolicies **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICertificatePolicies *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewCertificatePolicies(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceCertificatePolicies(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeCertificatePolicies(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCertificatePoliciesInternal */


/******************************************************************
 * Routines for Name
 ******************************************************************/

size_t PKISizeofNameInternal(
    PKIName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PKIID_RDNSequence:
      case 0x20|PKIID_RDNSequence:
        body_size = PKISizeofRDNSequenceInternal((PKIRDNSequence *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofNameInternal */

void PKIDropInPlaceName(
    PKICONTEXT *ctx,
    PKIName *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PKIID_RDNSequence:
    case 0x20|PKIID_RDNSequence:
        PKIFreeRDNSequence(ctx, (PKIRDNSequence *)( f->data ));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceName */

size_t PKIPackNameInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIName *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;

    (void)tag; /* unused */

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofName(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    switch ( (asnstruct->CHOICE_field_type & 0xDF) ) {

    case PKIID_RDNSequence:
        bytesused += PKIPackRDNSequenceInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKIRDNSequence *)(asnstruct->data),
                     PKIID_RDNSequence,
                     erret);
        break;

    default:
        PKIERR( PKIErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

  return bytesused;
} /* PKIPackNameInternal */

size_t PKIUnpkInPlaceName(
     PKICONTEXT *ctx,
     PKIName *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    switch (*buf) {

    /* rdnSequence */
    case PKIID_RDNSequence:
    case 0x20|PKIID_RDNSequence:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewRDNSequence(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceRDNSequence(ctx, (PKIRDNSequence *)(asnstruct->data),
                    buf, buflen,
                    PKIID_RDNSequence, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceName */

size_t PKIUnpackNameInternal(
    PKICONTEXT *ctx,
    PKIName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIName *local = NULL ;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    local = PKINewName(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceName(ctx, local, buf, buflen, tag, erret);
    if (*erret == PKIErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) PKIFreeName(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) PKIFreeName(ctx, local);
        return 0;
    }

    *asnstruct = local;
    return bytesused;
} /* PKIUnpackNameInternal */


/******************************************************************
 * Routines for RevokedCertificates
 ******************************************************************/

size_t PKISizeofRevokedCertificatesInternal(
    PKIRevokedCertificates *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_RevokedCertificates)
        lth = PKIMAX_RevokedCertificates;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofRevokedCertificateInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofRevokedCertificatesInternal */

void PKIDropInPlaceRevokedCertificates(
    PKICONTEXT *ctx,
    PKIRevokedCertificates *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_RevokedCertificates)
        lth = PKIMAX_RevokedCertificates ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeRevokedCertificate(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceRevokedCertificates */

size_t PKIPackRevokedCertificatesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRevokedCertificates *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_RevokedCertificates) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofRevokedCertificates(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackRevokedCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_RevokedCertificate, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackRevokedCertificatesInternal */

size_t PKIUnpkInPlaceRevokedCertificates(
     PKICONTEXT *ctx,
     PKIRevokedCertificates *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "RevokedCertificates");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_RevokedCertificates) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewRevokedCertificate(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceRevokedCertificate(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_RevokedCertificate, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceRevokedCertificates */

size_t PKIUnpackRevokedCertificatesInternal(
    PKICONTEXT *ctx,
    PKIRevokedCertificates **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRevokedCertificates *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewRevokedCertificates(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceRevokedCertificates(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeRevokedCertificates(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRevokedCertificatesInternal */


/******************************************************************
 * Routines for CertificationRequestInfo
 ******************************************************************/

size_t PKISizeofCertificationRequestInfoInternal(
    PKICertificationRequestInfo *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofNameInternal(&asnstruct->subject, PKITRUE, PKIFALSE)
          + PKISizeofSubjectPublicKeyInfoInternal(&asnstruct->subjectPublicKeyInfo, PKITRUE, PKIFALSE)
          + PKISizeofAttributesInternal(&asnstruct->attributes, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofCertificationRequestInfoInternal */

void PKIDropInPlaceCertificationRequestInfo(
    PKICONTEXT *ctx,
    PKICertificationRequestInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceName(ctx, &(f->subject));
    PKIDropInPlaceSubjectPublicKeyInfo(ctx, &(f->subjectPublicKeyInfo));
    PKIDropInPlaceAttributes(ctx, &(f->attributes));
} /* PKIDropInPlaceCertificationRequestInfo */

size_t PKIPackCertificationRequestInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICertificationRequestInfo *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofCertificationRequestInfo(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field version of CertificationRequestInfo */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subject of CertificationRequestInfo */
    bytesused += PKIPackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subject), PKIID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of CertificationRequestInfo */
    bytesused += PKIPackSubjectPublicKeyInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKeyInfo), PKIID_SubjectPublicKeyInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field attributes of CertificationRequestInfo */
    bytesused += PKIPackAttributesInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->attributes), 0x80 | 0x00, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackCertificationRequestInfoInternal */

size_t PKIUnpkInPlaceCertificationRequestInfo(
    PKICONTEXT *ctx,
    PKICertificationRequestInfo *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "CertificationRequestInfo" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field version of CertificationRequestInfo */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subject of CertificationRequestInfo */
    bytesused += PKIUnpkInPlaceName(ctx, &(asnstruct->subject), buf+bytesused,
                        localsize-bytesused, PKIID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of CertificationRequestInfo */
    bytesused += PKIUnpkInPlaceSubjectPublicKeyInfo(ctx, &(asnstruct->subjectPublicKeyInfo), buf+bytesused,
                        localsize-bytesused, PKIID_SubjectPublicKeyInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field attributes of CertificationRequestInfo */
    bytesused += PKIUnpkInPlaceAttributes(ctx, &(asnstruct->attributes), buf+bytesused,
                       localsize-bytesused, 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceCertificationRequestInfo */

size_t PKIUnpackCertificationRequestInfoInternal(
    PKICONTEXT *ctx,
    PKICertificationRequestInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICertificationRequestInfo *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewCertificationRequestInfo(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceCertificationRequestInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeCertificationRequestInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCertificationRequestInfoInternal */


/******************************************************************
 * Routines for GeneralName
 ******************************************************************/

size_t PKISizeofGeneralNameInternal(
    PKIGeneralName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case 0x80|0x00:
      case 0x80|0x20|0x00:
        body_size = PKISizeofAnotherNameInternal((PKIAnotherName *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x01:
      case 0x80|0x20|0x01:
        body_size = PKISizeofIA5StringInternal((PKIIA5String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x02:
      case 0x80|0x20|0x02:
        body_size = PKISizeofIA5StringInternal((PKIIA5String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x20|0x04:
        body_size = PKISizeofNameInternal((PKIName *)(asnstruct->data), PKITRUE, PKITRUE);
        break;

      case 0x80|0x05:
      case 0x80|0x20|0x05:
        body_size = PKISizeofEDIPartyNameInternal((PKIEDIPartyName *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x06:
      case 0x80|0x20|0x06:
        body_size = PKISizeofIA5StringInternal((PKIIA5String *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x07:
      case 0x80|0x20|0x07:
        body_size = PKISizeofOCTET_STRINGInternal((PKIOCTET_STRING *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x08:
        body_size = PKISizeofOBJECT_IDInternal((PKIOBJECT_ID *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofGeneralNameInternal */

void PKIDropInPlaceGeneralName(
    PKICONTEXT *ctx,
    PKIGeneralName *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case 0x80|0x00:
    case 0x80|0x20|0x00:
        PKIFreeAnotherName(ctx, (PKIAnotherName *)(f->data));
        break;
    case 0x80|0x01:
    case 0x80|0x20|0x01:
        PKIFreeIA5String(ctx, (PKIIA5String *)(f->data));
        break;
    case 0x80|0x02:
    case 0x80|0x20|0x02:
        PKIFreeIA5String(ctx, (PKIIA5String *)(f->data));
        break;
    case 0x80|0x20|0x04:
        PKIFreeName(ctx, (PKIName *)(f->data) );
        break;
    case 0x80|0x05:
    case 0x80|0x20|0x05:
        PKIFreeEDIPartyName(ctx, (PKIEDIPartyName *)(f->data));
        break;
    case 0x80|0x06:
    case 0x80|0x20|0x06:
        PKIFreeIA5String(ctx, (PKIIA5String *)(f->data));
        break;
    case 0x80|0x07:
    case 0x80|0x20|0x07:
        PKIFreeOCTET_STRING(ctx, (PKIOCTET_STRING *)(f->data));
        break;
    case 0x80|0x08:
        PKIFreeOBJECT_ID(ctx, (PKIOBJECT_ID *)(f->data));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceGeneralName */

size_t PKIPackGeneralNameInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIGeneralName *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;

    (void)tag; /* unused */

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofGeneralName(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    switch ( (asnstruct->CHOICE_field_type & 0xDF) ) {

    case 0x80|0x00:
        bytesused += PKIPackAnotherNameInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIAnotherName *)(asnstruct->data),
                      0x80|0x00,
                      erret);
        break;

    case 0x80|0x01:
        bytesused += PKIPackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIIA5String *)(asnstruct->data),
                      0x80|0x01,
                      erret);
        break;

    case 0x80|0x02:
        bytesused += PKIPackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIIA5String *)(asnstruct->data),
                      0x80|0x02,
                      erret);
        break;

    case 0x80|0x04:
        bytesused += PKIPutTag(buf+bytesused,
                    0x80|0x20|0x04,
                    PKISizeofName(ctx, (PKIName *)(asnstruct->data),PKITRUE) );
        bytesused += PKIPackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       (PKIName *)(asnstruct->data),
                       PKIID_Name, erret);
        break;

    case 0x80|0x05:
        bytesused += PKIPackEDIPartyNameInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIEDIPartyName *)(asnstruct->data),
                      0x80|0x05,
                      erret);
        break;

    case 0x80|0x06:
        bytesused += PKIPackIA5StringInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIIA5String *)(asnstruct->data),
                      0x80|0x06,
                      erret);
        break;

    case 0x80|0x07:
        bytesused += PKIPackOCTET_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIOCTET_STRING *)(asnstruct->data),
                      0x80|0x07,
                      erret);
        break;

    case 0x80|0x08:
        bytesused += PKIPackOBJECT_IDInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIOBJECT_ID *)(asnstruct->data),
                      0x80|0x08,
                      erret);
        break;

    default:
        PKIERR( PKIErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

  return bytesused;
} /* PKIPackGeneralNameInternal */

size_t PKIUnpkInPlaceGeneralName(
     PKICONTEXT *ctx,
     PKIGeneralName *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    switch (*buf) {

    /* otherName */
    case 0x80|0x00:
    case 0x80|0x20|0x00:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewAnotherName(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceAnotherName(ctx, (PKIAnotherName *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x00, erret));
        /*NOTREACHED*/
        break;

    /* rfc822Name */
    case 0x80|0x01:
    case 0x80|0x20|0x01:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewIA5String(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceIA5String(ctx, (PKIIA5String *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x01, erret));
        /*NOTREACHED*/
        break;

    /* dNSName */
    case 0x80|0x02:
    case 0x80|0x20|0x02:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewIA5String(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceIA5String(ctx, (PKIIA5String *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x02, erret));
        /*NOTREACHED*/
        break;

    /* directoryName */
    case 0x80|0x20|0x04:
    {
        size_t bytesused = 0;
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        asnstruct->CHOICE_field_type = *buf;
        used = PKITakeTag(buf, 0x80|0x20|0x04, &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0x80|0x20|0x04, 0x04);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->data != NULL)
                PKIFreeName(ctx, asnstruct->data);
            bytesused += PKIUnpackNameInternal(
                            ctx, (PKIName **)&(asnstruct->data),
                            buf+bytesused, buflen-bytesused,
                            PKIID_Name, erret);
            PKITRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                return 0;
            }
            bytesused += 2;
            return bytesused;
        }
        else if (used > 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0x80|0x20|0x04, 0x04);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->data != NULL )
                PKIFreeName(ctx, (PKIName *)(asnstruct->data));
            bytesused += PKIUnpackNameInternal(
                            ctx, (PKIName **)&(asnstruct->data),
                            buf+bytesused, taggeddatasize,
                            PKIID_Name, erret);
            PKITRACE_DECR_LEVEL;
            if (asnstruct->data == NULL) {
                return 0;
            }
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                return 0;
            }
            return bytesused;
        }
        else {
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }
        break;

    /* ediPartyName */
    case 0x80|0x05:
    case 0x80|0x20|0x05:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewEDIPartyName(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceEDIPartyName(ctx, (PKIEDIPartyName *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x05, erret));
        /*NOTREACHED*/
        break;

    /* uniformResourceIdentifier */
    case 0x80|0x06:
    case 0x80|0x20|0x06:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewIA5String(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceIA5String(ctx, (PKIIA5String *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x06, erret));
        /*NOTREACHED*/
        break;

    /* iPAddress */
    case 0x80|0x07:
    case 0x80|0x20|0x07:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewOCTET_STRING(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceOCTET_STRING(ctx, (PKIOCTET_STRING *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x07, erret));
        /*NOTREACHED*/
        break;

    /* registeredID */
    case 0x80|0x08:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewOBJECT_ID(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceOBJECT_ID(ctx, (PKIOBJECT_ID *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x08, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceGeneralName */

size_t PKIUnpackGeneralNameInternal(
    PKICONTEXT *ctx,
    PKIGeneralName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIGeneralName *local = NULL ;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    local = PKINewGeneralName(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceGeneralName(ctx, local, buf, buflen, tag, erret);
    if (*erret == PKIErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) PKIFreeGeneralName(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) PKIFreeGeneralName(ctx, local);
        return 0;
    }

    *asnstruct = local;
    return bytesused;
} /* PKIUnpackGeneralNameInternal */


/******************************************************************
 * Routines for TBSCertList
 ******************************************************************/

size_t PKISizeofTBSCertListInternal(
    PKITBSCertList *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofAlgorithmIdentifierInternal(&asnstruct->signature, PKITRUE, PKIFALSE)
          + PKISizeofNameInternal(&asnstruct->issuer, PKITRUE, PKIFALSE)
          + PKISizeofTimeInternal(&asnstruct->thisUpdate, PKITRUE, PKIFALSE)
          + PKISizeofTimeInternal(asnstruct->nextUpdate, PKITRUE, PKIFALSE)
          + PKISizeofRevokedCertificatesInternal(asnstruct->revokedCertificates, PKITRUE, PKIFALSE)
          + PKISizeofExtensionsInternal(asnstruct->crlExtensions, PKITRUE, PKITRUE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofTBSCertListInternal */

void PKIDropInPlaceTBSCertList(
    PKICONTEXT *ctx,
    PKITBSCertList *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeVersion(ctx, f->version);
    f->version = NULL;
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->signature));
    PKIDropInPlaceName(ctx, &(f->issuer));
    PKIDropInPlaceTime(ctx, &(f->thisUpdate));
    PKIFreeTime(ctx, f->nextUpdate);
    f->nextUpdate = NULL;
    PKIFreeRevokedCertificates(ctx, f->revokedCertificates);
    f->revokedCertificates = NULL;
    PKIFreeExtensions(ctx, f->crlExtensions);
    f->crlExtensions = NULL;
} /* PKIDropInPlaceTBSCertList */

size_t PKIPackTBSCertListInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKITBSCertList *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofTBSCertList(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field version of TBSCertList */
    if (asnstruct->version != NULL) { /* optional */
        bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->version, PKIID_Version, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field signature of TBSCertList */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuer of TBSCertList */
    bytesused += PKIPackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PKIID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field thisUpdate of TBSCertList */
    bytesused += PKIPackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->thisUpdate), PKIID_Time, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field nextUpdate of TBSCertList */
    if (asnstruct->nextUpdate != NULL) { /* optional */
        bytesused += PKIPackTimeInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->nextUpdate, PKIID_Time, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field revokedCertificates of TBSCertList */
    if (asnstruct->revokedCertificates != NULL) { /* optional */
        bytesused += PKIPackRevokedCertificatesInternal(ctx, buf+bytesused, buflen-bytesused,
                          asnstruct->revokedCertificates, PKIID_RevokedCertificates, erret );
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field crlExtensions of TBSCertList */
    if (asnstruct->crlExtensions != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofExtensions(ctx, asnstruct->crlExtensions, PKITRUE));
        bytesused += PKIPackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->crlExtensions, PKIID_Extensions, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackTBSCertListInternal */

size_t PKIUnpkInPlaceTBSCertList(
    PKICONTEXT *ctx,
    PKITBSCertList *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "TBSCertList" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field version of TBSCertList */
    if (asnstruct->version != NULL)
        PKIFreeVersion(ctx, asnstruct->version);
    bytesused += PKIUnpackVersionInternal(ctx, &(asnstruct->version),
                    buf+bytesused, localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of TBSCertList */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuer of TBSCertList */
    bytesused += PKIUnpkInPlaceName(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PKIID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field thisUpdate of TBSCertList */
    bytesused += PKIUnpkInPlaceTime(ctx, &(asnstruct->thisUpdate), buf+bytesused,
                        localsize-bytesused, PKIID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field nextUpdate of TBSCertList */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->nextUpdate != NULL)
        PKIFreeTime(ctx, asnstruct->nextUpdate);
    bytesused += PKIUnpackTimeInternal(ctx, &(asnstruct->nextUpdate),
                    buf+bytesused, localsize-bytesused, PKIID_Time, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field revokedCertificates of TBSCertList */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->revokedCertificates != NULL)
        PKIFreeRevokedCertificates(ctx, asnstruct->revokedCertificates);
    bytesused += PKIUnpackRevokedCertificatesInternal(ctx, &(asnstruct->revokedCertificates),
                    buf+bytesused, localsize-bytesused, PKIID_RevokedCertificates, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field crlExtensions of TBSCertList */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x00,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->crlExtensions != NULL)
                PKIFreeExtensions(ctx, asnstruct->crlExtensions);
            bytesused += PKIUnpackExtensionsInternal(ctx, &(asnstruct->crlExtensions),
                    buf+bytesused, localsize-bytesused, PKIID_Extensions, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->crlExtensions != NULL)
                PKIFreeExtensions(ctx, asnstruct->crlExtensions);
            bytesused += PKIUnpackExtensionsInternal(ctx, &(asnstruct->crlExtensions),
                       buf+bytesused, localsize-bytesused, PKIID_Extensions, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceTBSCertList */

size_t PKIUnpackTBSCertListInternal(
    PKICONTEXT *ctx,
    PKITBSCertList **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKITBSCertList *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewTBSCertList(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceTBSCertList(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeTBSCertList(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackTBSCertListInternal */


/******************************************************************
 * Routines for TBSCertificate
 ******************************************************************/

size_t PKISizeofTBSCertificateInternal(
    PKITBSCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(asnstruct->version, PKITRUE, PKITRUE)
          + PKISizeofCertificateSerialNumberInternal(&asnstruct->serialNumber, PKITRUE, PKIFALSE)
          + PKISizeofAlgorithmIdentifierInternal(&asnstruct->signature, PKITRUE, PKIFALSE)
          + PKISizeofNameInternal(&asnstruct->issuer, PKITRUE, PKIFALSE)
          + PKISizeofValidityInternal(&asnstruct->validity, PKITRUE, PKIFALSE)
          + PKISizeofNameInternal(&asnstruct->subject, PKITRUE, PKIFALSE)
          + PKISizeofSubjectPublicKeyInfoInternal(&asnstruct->subjectPublicKeyInfo, PKITRUE, PKIFALSE)
          + PKISizeofUniqueIdentifierInternal(asnstruct->issuerUniqueID, PKITRUE, PKIFALSE)
          + PKISizeofUniqueIdentifierInternal(asnstruct->subjectUniqueID, PKITRUE, PKIFALSE)
          + PKISizeofExtensionsInternal(asnstruct->extensions, PKITRUE, PKITRUE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofTBSCertificateInternal */

void PKIDropInPlaceTBSCertificate(
    PKICONTEXT *ctx,
    PKITBSCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeVersion(ctx, f->version);
    f->version = NULL;
    PKIDropInPlaceCertificateSerialNumber(ctx, &(f->serialNumber));
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->signature));
    PKIDropInPlaceName(ctx, &(f->issuer));
    PKIDropInPlaceValidity(ctx, &(f->validity));
    PKIDropInPlaceName(ctx, &(f->subject));
    PKIDropInPlaceSubjectPublicKeyInfo(ctx, &(f->subjectPublicKeyInfo));
    PKIFreeUniqueIdentifier(ctx, f->issuerUniqueID);
    f->issuerUniqueID = NULL;
    PKIFreeUniqueIdentifier(ctx, f->subjectUniqueID);
    f->subjectUniqueID = NULL;
    PKIFreeExtensions(ctx, f->extensions);
    f->extensions = NULL;
} /* PKIDropInPlaceTBSCertificate */

size_t PKIPackTBSCertificateInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKITBSCertificate *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofTBSCertificate(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field version of TBSCertificate */
    if (asnstruct->version != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofVersion(ctx, asnstruct->version, PKITRUE));
        bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->version, PKIID_Version, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field serialNumber of TBSCertificate */
    bytesused += PKIPackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->serialNumber), PKIID_CertificateSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of TBSCertificate */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuer of TBSCertificate */
    bytesused += PKIPackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PKIID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field validity of TBSCertificate */
    bytesused += PKIPackValidityInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->validity), PKIID_Validity, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subject of TBSCertificate */
    bytesused += PKIPackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subject), PKIID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of TBSCertificate */
    bytesused += PKIPackSubjectPublicKeyInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->subjectPublicKeyInfo), PKIID_SubjectPublicKeyInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuerUniqueID of TBSCertificate */
    if (asnstruct->issuerUniqueID != NULL) { /* optional */
        bytesused += PKIPackUniqueIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->issuerUniqueID, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field subjectUniqueID of TBSCertificate */
    if (asnstruct->subjectUniqueID != NULL) { /* optional */
        bytesused += PKIPackUniqueIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->subjectUniqueID, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field extensions of TBSCertificate */
    if (asnstruct->extensions != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x03, PKISizeofExtensions(ctx, asnstruct->extensions, PKITRUE));
        bytesused += PKIPackExtensionsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->extensions, PKIID_Extensions, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackTBSCertificateInternal */

size_t PKIUnpkInPlaceTBSCertificate(
    PKICONTEXT *ctx,
    PKITBSCertificate *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "TBSCertificate" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field version of TBSCertificate */
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x00,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->version != NULL)
                PKIFreeVersion(ctx, asnstruct->version);
            bytesused += PKIUnpackVersionInternal(ctx, &(asnstruct->version),
                    buf+bytesused, localsize-bytesused, PKIID_Version, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->version != NULL)
                PKIFreeVersion(ctx, asnstruct->version);
            bytesused += PKIUnpackVersionInternal(ctx, &(asnstruct->version),
                       buf+bytesused, localsize-bytesused, PKIID_Version, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field serialNumber of TBSCertificate */
    bytesused += PKIUnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->serialNumber), buf+bytesused,
                        localsize-bytesused, PKIID_CertificateSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of TBSCertificate */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuer of TBSCertificate */
    bytesused += PKIUnpkInPlaceName(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PKIID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field validity of TBSCertificate */
    bytesused += PKIUnpkInPlaceValidity(ctx, &(asnstruct->validity), buf+bytesused,
                        localsize-bytesused, PKIID_Validity, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subject of TBSCertificate */
    bytesused += PKIUnpkInPlaceName(ctx, &(asnstruct->subject), buf+bytesused,
                        localsize-bytesused, PKIID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectPublicKeyInfo of TBSCertificate */
    bytesused += PKIUnpkInPlaceSubjectPublicKeyInfo(ctx, &(asnstruct->subjectPublicKeyInfo), buf+bytesused,
                        localsize-bytesused, PKIID_SubjectPublicKeyInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuerUniqueID of TBSCertificate */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->issuerUniqueID != NULL)
        PKIFreeUniqueIdentifier(ctx, asnstruct->issuerUniqueID);
    bytesused += PKIUnpackUniqueIdentifierInternal(ctx, &(asnstruct->issuerUniqueID),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field subjectUniqueID of TBSCertificate */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->subjectUniqueID != NULL)
        PKIFreeUniqueIdentifier(ctx, asnstruct->subjectUniqueID);
    bytesused += PKIUnpackUniqueIdentifierInternal(ctx, &(asnstruct->subjectUniqueID),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field extensions of TBSCertificate */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x03,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x03, 0x03);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->extensions != NULL)
                PKIFreeExtensions(ctx, asnstruct->extensions);
            bytesused += PKIUnpackExtensionsInternal(ctx, &(asnstruct->extensions),
                    buf+bytesused, localsize-bytesused, PKIID_Extensions, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x03, 0x03);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->extensions != NULL)
                PKIFreeExtensions(ctx, asnstruct->extensions);
            bytesused += PKIUnpackExtensionsInternal(ctx, &(asnstruct->extensions),
                       buf+bytesused, localsize-bytesused, PKIID_Extensions, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceTBSCertificate */

size_t PKIUnpackTBSCertificateInternal(
    PKICONTEXT *ctx,
    PKITBSCertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKITBSCertificate *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewTBSCertificate(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceTBSCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeTBSCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackTBSCertificateInternal */


/******************************************************************
 * Routines for AccessDescription
 ******************************************************************/

size_t PKISizeofAccessDescriptionInternal(
    PKIAccessDescription *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofOBJECT_IDInternal(&asnstruct->accessMethod, PKITRUE, PKIFALSE)
          + PKISizeofGeneralNameInternal(&asnstruct->accessLocation, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofAccessDescriptionInternal */

void PKIDropInPlaceAccessDescription(
    PKICONTEXT *ctx,
    PKIAccessDescription *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceOBJECT_ID(ctx, &(f->accessMethod));
    PKIDropInPlaceGeneralName(ctx, &(f->accessLocation));
} /* PKIDropInPlaceAccessDescription */

size_t PKIPackAccessDescriptionInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAccessDescription *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofAccessDescription(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field accessMethod of AccessDescription */
    bytesused += PKIPackOBJECT_IDInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->accessMethod), PKIID_OBJECT_ID, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field accessLocation of AccessDescription */
    bytesused += PKIPackGeneralNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->accessLocation), PKIID_GeneralName, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAccessDescriptionInternal */

size_t PKIUnpkInPlaceAccessDescription(
    PKICONTEXT *ctx,
    PKIAccessDescription *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "AccessDescription" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field accessMethod of AccessDescription */
    bytesused += PKIUnpkInPlaceOBJECT_ID(ctx, &(asnstruct->accessMethod), buf+bytesused,
                        localsize-bytesused, PKIID_OBJECT_ID, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field accessLocation of AccessDescription */
    bytesused += PKIUnpkInPlaceGeneralName(ctx, &(asnstruct->accessLocation), buf+bytesused,
                        localsize-bytesused, PKIID_GeneralName, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAccessDescription */

size_t PKIUnpackAccessDescriptionInternal(
    PKICONTEXT *ctx,
    PKIAccessDescription **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAccessDescription *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAccessDescription(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAccessDescription(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAccessDescription(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAccessDescriptionInternal */


/******************************************************************
 * Routines for Certificate
 ******************************************************************/

size_t PKISizeofCertificateInternal(
    PKICertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofTBSCertificateInternal(&asnstruct->tbsCertificate, PKITRUE, PKIFALSE)
          + PKISizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofBIT_STRINGInternal(&asnstruct->signature, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofCertificateInternal */

void PKIDropInPlaceCertificate(
    PKICONTEXT *ctx,
    PKICertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceTBSCertificate(ctx, &(f->tbsCertificate));
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    PKIDropInPlaceBIT_STRING(ctx, &(f->signature));
} /* PKIDropInPlaceCertificate */

size_t PKIPackCertificateInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICertificate *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofCertificate(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field tbsCertificate of Certificate */
    bytesused += PKIPackTBSCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertificate), PKIID_TBSCertificate, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signatureAlgorithm of Certificate */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signatureAlgorithm), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of Certificate */
    bytesused += PKIPackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackCertificateInternal */

size_t PKIUnpkInPlaceCertificate(
    PKICONTEXT *ctx,
    PKICertificate *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "Certificate" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field tbsCertificate of Certificate */
    bytesused += PKIUnpkInPlaceTBSCertificate(ctx, &(asnstruct->tbsCertificate), buf+bytesused,
                        localsize-bytesused, PKIID_TBSCertificate, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signatureAlgorithm of Certificate */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signatureAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of Certificate */
    bytesused += PKIUnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceCertificate */

size_t PKIUnpackCertificateInternal(
    PKICONTEXT *ctx,
    PKICertificate **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICertificate *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewCertificate(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCertificateInternal */


/******************************************************************
 * Routines for CertificateList
 ******************************************************************/

size_t PKISizeofCertificateListInternal(
    PKICertificateList *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofTBSCertListInternal(&asnstruct->tbsCertList, PKITRUE, PKIFALSE)
          + PKISizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofBIT_STRINGInternal(&asnstruct->signature, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofCertificateListInternal */

void PKIDropInPlaceCertificateList(
    PKICONTEXT *ctx,
    PKICertificateList *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceTBSCertList(ctx, &(f->tbsCertList));
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    PKIDropInPlaceBIT_STRING(ctx, &(f->signature));
} /* PKIDropInPlaceCertificateList */

size_t PKIPackCertificateListInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICertificateList *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofCertificateList(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field tbsCertList of CertificateList */
    bytesused += PKIPackTBSCertListInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->tbsCertList), PKIID_TBSCertList, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signatureAlgorithm of CertificateList */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signatureAlgorithm), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of CertificateList */
    bytesused += PKIPackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackCertificateListInternal */

size_t PKIUnpkInPlaceCertificateList(
    PKICONTEXT *ctx,
    PKICertificateList *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "CertificateList" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field tbsCertList of CertificateList */
    bytesused += PKIUnpkInPlaceTBSCertList(ctx, &(asnstruct->tbsCertList), buf+bytesused,
                        localsize-bytesused, PKIID_TBSCertList, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signatureAlgorithm of CertificateList */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signatureAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of CertificateList */
    bytesused += PKIUnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceCertificateList */

size_t PKIUnpackCertificateListInternal(
    PKICONTEXT *ctx,
    PKICertificateList **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICertificateList *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewCertificateList(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceCertificateList(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeCertificateList(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCertificateListInternal */


/******************************************************************
 * Routines for CertificationRequest
 ******************************************************************/

size_t PKISizeofCertificationRequestInternal(
    PKICertificationRequest *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofCertificationRequestInfoInternal(&asnstruct->certificationRequestInfo, PKITRUE, PKIFALSE)
          + PKISizeofAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofBIT_STRINGInternal(&asnstruct->signature, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofCertificationRequestInternal */

void PKIDropInPlaceCertificationRequest(
    PKICONTEXT *ctx,
    PKICertificationRequest *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceCertificationRequestInfo(ctx, &(f->certificationRequestInfo));
    PKIDropInPlaceAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    PKIDropInPlaceBIT_STRING(ctx, &(f->signature));
} /* PKIDropInPlaceCertificationRequest */

size_t PKIPackCertificationRequestInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICertificationRequest *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofCertificationRequest(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field certificationRequestInfo of CertificationRequest */
    bytesused += PKIPackCertificationRequestInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->certificationRequestInfo), PKIID_CertificationRequestInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signatureAlgorithm of CertificationRequest */
    bytesused += PKIPackAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signatureAlgorithm), PKIID_AlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of CertificationRequest */
    bytesused += PKIPackBIT_STRINGInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_BIT_STRING, erret);
    if (bytesused > datasize || *erret != 0)
        break;

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackCertificationRequestInternal */

size_t PKIUnpkInPlaceCertificationRequest(
    PKICONTEXT *ctx,
    PKICertificationRequest *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "CertificationRequest" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field certificationRequestInfo of CertificationRequest */
    bytesused += PKIUnpkInPlaceCertificationRequestInfo(ctx, &(asnstruct->certificationRequestInfo), buf+bytesused,
                        localsize-bytesused, PKIID_CertificationRequestInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signatureAlgorithm of CertificationRequest */
    bytesused += PKIUnpkInPlaceAlgorithmIdentifier(ctx, &(asnstruct->signatureAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_AlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of CertificationRequest */
    bytesused += PKIUnpkInPlaceBIT_STRING(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_BIT_STRING, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceCertificationRequest */

size_t PKIUnpackCertificationRequestInternal(
    PKICONTEXT *ctx,
    PKICertificationRequest **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICertificationRequest *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewCertificationRequest(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceCertificationRequest(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeCertificationRequest(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCertificationRequestInternal */


/******************************************************************
 * Routines for GeneralNames
 ******************************************************************/

size_t PKISizeofGeneralNamesInternal(
    PKIGeneralNames *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_GeneralNames)
        lth = PKIMAX_GeneralNames;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofGeneralNameInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofGeneralNamesInternal */

void PKIDropInPlaceGeneralNames(
    PKICONTEXT *ctx,
    PKIGeneralNames *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_GeneralNames)
        lth = PKIMAX_GeneralNames ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeGeneralName(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceGeneralNames */

size_t PKIPackGeneralNamesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIGeneralNames *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_GeneralNames) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofGeneralNames(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackGeneralNameInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_GeneralName, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackGeneralNamesInternal */

size_t PKIUnpkInPlaceGeneralNames(
     PKICONTEXT *ctx,
     PKIGeneralNames *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "GeneralNames");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_GeneralNames) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewGeneralName(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceGeneralName(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_GeneralName, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceGeneralNames */

size_t PKIUnpackGeneralNamesInternal(
    PKICONTEXT *ctx,
    PKIGeneralNames **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIGeneralNames *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewGeneralNames(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceGeneralNames(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeGeneralNames(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackGeneralNamesInternal */


/******************************************************************
 * Routines for GeneralSubtree
 ******************************************************************/

size_t PKISizeofGeneralSubtreeInternal(
    PKIGeneralSubtree *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofGeneralNameInternal(&asnstruct->base, PKITRUE, PKIFALSE)
          + PKISizeofBaseDistanceInternal(asnstruct->minimum, PKITRUE, PKIFALSE)
          + PKISizeofBaseDistanceInternal(asnstruct->maximum, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofGeneralSubtreeInternal */

void PKIDropInPlaceGeneralSubtree(
    PKICONTEXT *ctx,
    PKIGeneralSubtree *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceGeneralName(ctx, &(f->base));
    PKIFreeBaseDistance(ctx, f->minimum);
    f->minimum = NULL;
    PKIFreeBaseDistance(ctx, f->maximum);
    f->maximum = NULL;
} /* PKIDropInPlaceGeneralSubtree */

size_t PKIPackGeneralSubtreeInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIGeneralSubtree *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofGeneralSubtree(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field base of GeneralSubtree */
    bytesused += PKIPackGeneralNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->base), PKIID_GeneralName, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field minimum of GeneralSubtree */
    if (asnstruct->minimum != NULL) { /* optional */
        bytesused += PKIPackBaseDistanceInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->minimum, 0x80 | 0x00, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field maximum of GeneralSubtree */
    if (asnstruct->maximum != NULL) { /* optional */
        bytesused += PKIPackBaseDistanceInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->maximum, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackGeneralSubtreeInternal */

size_t PKIUnpkInPlaceGeneralSubtree(
    PKICONTEXT *ctx,
    PKIGeneralSubtree *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "GeneralSubtree" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field base of GeneralSubtree */
    bytesused += PKIUnpkInPlaceGeneralName(ctx, &(asnstruct->base), buf+bytesused,
                        localsize-bytesused, PKIID_GeneralName, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field minimum of GeneralSubtree */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->minimum != NULL)
        PKIFreeBaseDistance(ctx, asnstruct->minimum);
    bytesused += PKIUnpackBaseDistanceInternal(ctx, &(asnstruct->minimum),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field maximum of GeneralSubtree */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->maximum != NULL)
        PKIFreeBaseDistance(ctx, asnstruct->maximum);
    bytesused += PKIUnpackBaseDistanceInternal(ctx, &(asnstruct->maximum),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceGeneralSubtree */

size_t PKIUnpackGeneralSubtreeInternal(
    PKICONTEXT *ctx,
    PKIGeneralSubtree **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIGeneralSubtree *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewGeneralSubtree(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceGeneralSubtree(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeGeneralSubtree(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackGeneralSubtreeInternal */


/******************************************************************
 * Routines for AuthorityInfoAccessSyntax
 ******************************************************************/

size_t PKISizeofAuthorityInfoAccessSyntaxInternal(
    PKIAuthorityInfoAccessSyntax *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_AuthorityInfoAccessSyntax)
        lth = PKIMAX_AuthorityInfoAccessSyntax;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofAccessDescriptionInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofAuthorityInfoAccessSyntaxInternal */

void PKIDropInPlaceAuthorityInfoAccessSyntax(
    PKICONTEXT *ctx,
    PKIAuthorityInfoAccessSyntax *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_AuthorityInfoAccessSyntax)
        lth = PKIMAX_AuthorityInfoAccessSyntax ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeAccessDescription(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceAuthorityInfoAccessSyntax */

size_t PKIPackAuthorityInfoAccessSyntaxInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAuthorityInfoAccessSyntax *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_AuthorityInfoAccessSyntax) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofAuthorityInfoAccessSyntax(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackAccessDescriptionInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_AccessDescription, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackAuthorityInfoAccessSyntaxInternal */

size_t PKIUnpkInPlaceAuthorityInfoAccessSyntax(
     PKICONTEXT *ctx,
     PKIAuthorityInfoAccessSyntax *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "AuthorityInfoAccessSyntax");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_AuthorityInfoAccessSyntax) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewAccessDescription(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceAccessDescription(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_AccessDescription, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAuthorityInfoAccessSyntax */

size_t PKIUnpackAuthorityInfoAccessSyntaxInternal(
    PKICONTEXT *ctx,
    PKIAuthorityInfoAccessSyntax **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAuthorityInfoAccessSyntax *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAuthorityInfoAccessSyntax(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAuthorityInfoAccessSyntax(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAuthorityInfoAccessSyntax(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAuthorityInfoAccessSyntaxInternal */


/******************************************************************
 * Routines for AuthorityKeyIdentifier
 ******************************************************************/

size_t PKISizeofAuthorityKeyIdentifierInternal(
    PKIAuthorityKeyIdentifier *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofKeyIdentifierInternal(asnstruct->keyIdentifier, PKITRUE, PKIFALSE)
          + PKISizeofGeneralNamesInternal(asnstruct->authorityCertIssuer, PKITRUE, PKIFALSE)
          + PKISizeofCertificateSerialNumberInternal(asnstruct->authorityCertSerialNumber, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofAuthorityKeyIdentifierInternal */

void PKIDropInPlaceAuthorityKeyIdentifier(
    PKICONTEXT *ctx,
    PKIAuthorityKeyIdentifier *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeKeyIdentifier(ctx, f->keyIdentifier);
    f->keyIdentifier = NULL;
    PKIFreeGeneralNames(ctx, f->authorityCertIssuer);
    f->authorityCertIssuer = NULL;
    PKIFreeCertificateSerialNumber(ctx, f->authorityCertSerialNumber);
    f->authorityCertSerialNumber = NULL;
} /* PKIDropInPlaceAuthorityKeyIdentifier */

size_t PKIPackAuthorityKeyIdentifierInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIAuthorityKeyIdentifier *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofAuthorityKeyIdentifier(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field keyIdentifier of AuthorityKeyIdentifier */
    if (asnstruct->keyIdentifier != NULL) { /* optional */
        bytesused += PKIPackKeyIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->keyIdentifier, 0x80 | 0x00, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field authorityCertIssuer of AuthorityKeyIdentifier */
    if (asnstruct->authorityCertIssuer != NULL) { /* optional */
        bytesused += PKIPackGeneralNamesInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->authorityCertIssuer, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field authorityCertSerialNumber of AuthorityKeyIdentifier */
    if (asnstruct->authorityCertSerialNumber != NULL) { /* optional */
        bytesused += PKIPackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->authorityCertSerialNumber, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackAuthorityKeyIdentifierInternal */

size_t PKIUnpkInPlaceAuthorityKeyIdentifier(
    PKICONTEXT *ctx,
    PKIAuthorityKeyIdentifier *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "AuthorityKeyIdentifier" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field keyIdentifier of AuthorityKeyIdentifier */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->keyIdentifier != NULL)
        PKIFreeKeyIdentifier(ctx, asnstruct->keyIdentifier);
    bytesused += PKIUnpackKeyIdentifierInternal(ctx, &(asnstruct->keyIdentifier),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field authorityCertIssuer of AuthorityKeyIdentifier */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->authorityCertIssuer != NULL)
        PKIFreeGeneralNames(ctx, asnstruct->authorityCertIssuer);
    bytesused += PKIUnpackGeneralNamesInternal(ctx, &(asnstruct->authorityCertIssuer),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field authorityCertSerialNumber of AuthorityKeyIdentifier */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->authorityCertSerialNumber != NULL)
        PKIFreeCertificateSerialNumber(ctx, asnstruct->authorityCertSerialNumber);
    bytesused += PKIUnpackCertificateSerialNumberInternal(ctx, &(asnstruct->authorityCertSerialNumber),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceAuthorityKeyIdentifier */

size_t PKIUnpackAuthorityKeyIdentifierInternal(
    PKICONTEXT *ctx,
    PKIAuthorityKeyIdentifier **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIAuthorityKeyIdentifier *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewAuthorityKeyIdentifier(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceAuthorityKeyIdentifier(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeAuthorityKeyIdentifier(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackAuthorityKeyIdentifierInternal */


/******************************************************************
 * Routines for DistributionPointName
 ******************************************************************/

size_t PKISizeofDistributionPointNameInternal(
    PKIDistributionPointName *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case 0x80|0x00:
      case 0x80|0x20|0x00:
        body_size = PKISizeofGeneralNamesInternal((PKIGeneralNames *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x01:
      case 0x80|0x20|0x01:
        body_size = PKISizeofRelativeDistinguishedNameInternal((PKIRelativeDistinguishedName *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofDistributionPointNameInternal */

void PKIDropInPlaceDistributionPointName(
    PKICONTEXT *ctx,
    PKIDistributionPointName *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case 0x80|0x00:
    case 0x80|0x20|0x00:
        PKIFreeGeneralNames(ctx, (PKIGeneralNames *)(f->data));
        break;
    case 0x80|0x01:
    case 0x80|0x20|0x01:
        PKIFreeRelativeDistinguishedName(ctx, (PKIRelativeDistinguishedName *)(f->data));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceDistributionPointName */

size_t PKIPackDistributionPointNameInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDistributionPointName *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;

    (void)tag; /* unused */

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDistributionPointName(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    switch ( (asnstruct->CHOICE_field_type & 0xDF) ) {

    case 0x80|0x00:
        bytesused += PKIPackGeneralNamesInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIGeneralNames *)(asnstruct->data),
                      0x80|0x00,
                      erret);
        break;

    case 0x80|0x01:
        bytesused += PKIPackRelativeDistinguishedNameInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIRelativeDistinguishedName *)(asnstruct->data),
                      0x80|0x01,
                      erret);
        break;

    default:
        PKIERR( PKIErrChoiceBadType );
        break;
    } /* switch */

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

  return bytesused;
} /* PKIPackDistributionPointNameInternal */

size_t PKIUnpkInPlaceDistributionPointName(
     PKICONTEXT *ctx,
     PKIDistributionPointName *asnstruct,/* output block */
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    (void)tag; /* unused */


    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    switch (*buf) {

    /* fullName */
    case 0x80|0x00:
    case 0x80|0x20|0x00:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewGeneralNames(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceGeneralNames(ctx, (PKIGeneralNames *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x00, erret));
        /*NOTREACHED*/
        break;

    /* nameRelativeToCRLIssuer */
    case 0x80|0x01:
    case 0x80|0x20|0x01:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewRelativeDistinguishedName(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceRelativeDistinguishedName(ctx, (PKIRelativeDistinguishedName *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x01, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceDistributionPointName */

size_t PKIUnpackDistributionPointNameInternal(
    PKICONTEXT *ctx,
    PKIDistributionPointName **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDistributionPointName *local = NULL ;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    local = PKINewDistributionPointName(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceDistributionPointName(ctx, local, buf, buflen, tag, erret);
    if (*erret == PKIErrChoiceBadType) {
        *erret = 0;
        if (local != NULL) PKIFreeDistributionPointName(ctx, local);
        return 0;
    }
    if (*erret != 0) {
        if (local != NULL) PKIFreeDistributionPointName(ctx, local);
        return 0;
    }

    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDistributionPointNameInternal */


/******************************************************************
 * Routines for GeneralSubtrees
 ******************************************************************/

size_t PKISizeofGeneralSubtreesInternal(
    PKIGeneralSubtrees *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_GeneralSubtrees)
        lth = PKIMAX_GeneralSubtrees;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofGeneralSubtreeInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofGeneralSubtreesInternal */

void PKIDropInPlaceGeneralSubtrees(
    PKICONTEXT *ctx,
    PKIGeneralSubtrees *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_GeneralSubtrees)
        lth = PKIMAX_GeneralSubtrees ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeGeneralSubtree(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceGeneralSubtrees */

size_t PKIPackGeneralSubtreesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIGeneralSubtrees *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_GeneralSubtrees) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofGeneralSubtrees(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackGeneralSubtreeInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_GeneralSubtree, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackGeneralSubtreesInternal */

size_t PKIUnpkInPlaceGeneralSubtrees(
     PKICONTEXT *ctx,
     PKIGeneralSubtrees *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "GeneralSubtrees");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_GeneralSubtrees) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewGeneralSubtree(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceGeneralSubtree(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_GeneralSubtree, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceGeneralSubtrees */

size_t PKIUnpackGeneralSubtreesInternal(
    PKICONTEXT *ctx,
    PKIGeneralSubtrees **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIGeneralSubtrees *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewGeneralSubtrees(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceGeneralSubtrees(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeGeneralSubtrees(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackGeneralSubtreesInternal */


/******************************************************************
 * Routines for DistributionPoint
 ******************************************************************/

size_t PKISizeofDistributionPointInternal(
    PKIDistributionPoint *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofDistributionPointNameInternal(asnstruct->distributionPoint, PKITRUE, PKITRUE)
          + PKISizeofReasonFlagsInternal(asnstruct->reasons, PKITRUE, PKIFALSE)
          + PKISizeofGeneralNamesInternal(asnstruct->cRLIssuer, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofDistributionPointInternal */

void PKIDropInPlaceDistributionPoint(
    PKICONTEXT *ctx,
    PKIDistributionPoint *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeDistributionPointName(ctx, f->distributionPoint);
    f->distributionPoint = NULL;
    PKIFreeReasonFlags(ctx, f->reasons);
    f->reasons = NULL;
    PKIFreeGeneralNames(ctx, f->cRLIssuer);
    f->cRLIssuer = NULL;
} /* PKIDropInPlaceDistributionPoint */

size_t PKIPackDistributionPointInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDistributionPoint *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofDistributionPoint(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field distributionPoint of DistributionPoint */
    if (asnstruct->distributionPoint != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofDistributionPointName(ctx, asnstruct->distributionPoint, PKITRUE));
        bytesused += PKIPackDistributionPointNameInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->distributionPoint, PKIID_DistributionPointName, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field reasons of DistributionPoint */
    if (asnstruct->reasons != NULL) { /* optional */
        bytesused += PKIPackReasonFlagsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->reasons, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field cRLIssuer of DistributionPoint */
    if (asnstruct->cRLIssuer != NULL) { /* optional */
        bytesused += PKIPackGeneralNamesInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->cRLIssuer, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackDistributionPointInternal */

size_t PKIUnpkInPlaceDistributionPoint(
    PKICONTEXT *ctx,
    PKIDistributionPoint *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "DistributionPoint" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field distributionPoint of DistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x00,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                PKIFreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += PKIUnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                    buf+bytesused, localsize-bytesused, PKIID_DistributionPointName, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                PKIFreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += PKIUnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                       buf+bytesused, localsize-bytesused, PKIID_DistributionPointName, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field reasons of DistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->reasons != NULL)
        PKIFreeReasonFlags(ctx, asnstruct->reasons);
    bytesused += PKIUnpackReasonFlagsInternal(ctx, &(asnstruct->reasons),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field cRLIssuer of DistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->cRLIssuer != NULL)
        PKIFreeGeneralNames(ctx, asnstruct->cRLIssuer);
    bytesused += PKIUnpackGeneralNamesInternal(ctx, &(asnstruct->cRLIssuer),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceDistributionPoint */

size_t PKIUnpackDistributionPointInternal(
    PKICONTEXT *ctx,
    PKIDistributionPoint **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDistributionPoint *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewDistributionPoint(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceDistributionPoint(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeDistributionPoint(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDistributionPointInternal */


/******************************************************************
 * Routines for IssuingDistributionPoint
 ******************************************************************/

size_t PKISizeofIssuingDistributionPointInternal(
    PKIIssuingDistributionPoint *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofDistributionPointNameInternal(asnstruct->distributionPoint, PKITRUE, PKITRUE)
          + PKISizeofBOOLEANInternal(asnstruct->onlyContainsUserCerts, PKITRUE, PKIFALSE)
          + PKISizeofBOOLEANInternal(asnstruct->onlyContainsCACerts, PKITRUE, PKIFALSE)
          + PKISizeofReasonFlagsInternal(asnstruct->onlySomeReasons, PKITRUE, PKIFALSE)
          + PKISizeofBOOLEANInternal(asnstruct->indirectCRL, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofIssuingDistributionPointInternal */

void PKIDropInPlaceIssuingDistributionPoint(
    PKICONTEXT *ctx,
    PKIIssuingDistributionPoint *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeDistributionPointName(ctx, f->distributionPoint);
    f->distributionPoint = NULL;
    PKIFreeBOOLEAN(ctx, f->onlyContainsUserCerts);
    f->onlyContainsUserCerts = NULL;
    PKIFreeBOOLEAN(ctx, f->onlyContainsCACerts);
    f->onlyContainsCACerts = NULL;
    PKIFreeReasonFlags(ctx, f->onlySomeReasons);
    f->onlySomeReasons = NULL;
    PKIFreeBOOLEAN(ctx, f->indirectCRL);
    f->indirectCRL = NULL;
} /* PKIDropInPlaceIssuingDistributionPoint */

size_t PKIPackIssuingDistributionPointInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIIssuingDistributionPoint *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofIssuingDistributionPoint(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field distributionPoint of IssuingDistributionPoint */
    if (asnstruct->distributionPoint != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofDistributionPointName(ctx, asnstruct->distributionPoint, PKITRUE));
        bytesused += PKIPackDistributionPointNameInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->distributionPoint, PKIID_DistributionPointName, erret) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field onlyContainsUserCerts of IssuingDistributionPoint */
    if (asnstruct->onlyContainsUserCerts != NULL) { /* optional */
        bytesused += PKIPackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->onlyContainsUserCerts, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field onlyContainsCACerts of IssuingDistributionPoint */
    if (asnstruct->onlyContainsCACerts != NULL) { /* optional */
        bytesused += PKIPackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->onlyContainsCACerts, 0x80 | 0x02, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field onlySomeReasons of IssuingDistributionPoint */
    if (asnstruct->onlySomeReasons != NULL) { /* optional */
        bytesused += PKIPackReasonFlagsInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->onlySomeReasons, 0x80 | 0x03, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field indirectCRL of IssuingDistributionPoint */
    if (asnstruct->indirectCRL != NULL) { /* optional */
        bytesused += PKIPackBOOLEANInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->indirectCRL, 0x80 | 0x04, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackIssuingDistributionPointInternal */

size_t PKIUnpkInPlaceIssuingDistributionPoint(
    PKICONTEXT *ctx,
    PKIIssuingDistributionPoint *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "IssuingDistributionPoint" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field distributionPoint of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    { /* local declaration block*/
        size_t taggeddatasize;
        size_t taggedlocalsize;
        size_t used;

        used = PKITakeTag(buf+bytesused, 0xa0 | 0x00,
                          &taggeddatasize);
        bytesused += used;

        if ((int)taggeddatasize == -1 && used != 0) {
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                PKIFreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += PKIUnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                    buf+bytesused, localsize-bytesused, PKIID_DistributionPointName, erret);
            PKITRACE_DECR_LEVEL;
            if ( *(buf+bytesused) != 0x00 &&
                 *(buf+bytesused+1) != 0x00 ) {
                PKIERR(PKIErrUnpackInvalidEncoding);
                break;
            }
            bytesused += 2;
        }

        else if (taggeddatasize > 0 && used != 0) {
            taggedlocalsize = bytesused + taggeddatasize;
            PKITRACE_PRINT_TAG(0xa0|0x00, 0x00);
            PKITRACE_INCR_LEVEL;
            if (asnstruct->distributionPoint != NULL)
                PKIFreeDistributionPointName(ctx, asnstruct->distributionPoint);
            bytesused += PKIUnpackDistributionPointNameInternal(ctx, &(asnstruct->distributionPoint),
                       buf+bytesused, localsize-bytesused, PKIID_DistributionPointName, erret);
            PKITRACE_DECR_LEVEL;
            if (bytesused != taggedlocalsize) {
                PKIERR(PKIErrUnpackTaggedLth);
                break;
            }
        }
    } /* for the local declaration block */
    if (bytesused > localsize || *erret != 0)
        break;

    /* field onlyContainsUserCerts of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->onlyContainsUserCerts != NULL)
        PKIFreeBOOLEAN(ctx, asnstruct->onlyContainsUserCerts);
    bytesused += PKIUnpackBOOLEANInternal(ctx, &(asnstruct->onlyContainsUserCerts),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field onlyContainsCACerts of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->onlyContainsCACerts != NULL)
        PKIFreeBOOLEAN(ctx, asnstruct->onlyContainsCACerts);
    bytesused += PKIUnpackBOOLEANInternal(ctx, &(asnstruct->onlyContainsCACerts),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x02, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field onlySomeReasons of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->onlySomeReasons != NULL)
        PKIFreeReasonFlags(ctx, asnstruct->onlySomeReasons);
    bytesused += PKIUnpackReasonFlagsInternal(ctx, &(asnstruct->onlySomeReasons),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x03, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field indirectCRL of IssuingDistributionPoint */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->indirectCRL != NULL)
        PKIFreeBOOLEAN(ctx, asnstruct->indirectCRL);
    bytesused += PKIUnpackBOOLEANInternal(ctx, &(asnstruct->indirectCRL),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x04, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceIssuingDistributionPoint */

size_t PKIUnpackIssuingDistributionPointInternal(
    PKICONTEXT *ctx,
    PKIIssuingDistributionPoint **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIIssuingDistributionPoint *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewIssuingDistributionPoint(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceIssuingDistributionPoint(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeIssuingDistributionPoint(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackIssuingDistributionPointInternal */


/******************************************************************
 * Routines for NameConstraints
 ******************************************************************/

size_t PKISizeofNameConstraintsInternal(
    PKINameConstraints *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofGeneralSubtreesInternal(asnstruct->permittedSubtrees, PKITRUE, PKIFALSE)
          + PKISizeofGeneralSubtreesInternal(asnstruct->excludedSubtrees, PKITRUE, PKIFALSE) ;

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;

} /* PKISizeofNameConstraintsInternal */

void PKIDropInPlaceNameConstraints(
    PKICONTEXT *ctx,
    PKINameConstraints *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIFreeGeneralSubtrees(ctx, f->permittedSubtrees);
    f->permittedSubtrees = NULL;
    PKIFreeGeneralSubtrees(ctx, f->excludedSubtrees);
    f->excludedSubtrees = NULL;
} /* PKIDropInPlaceNameConstraints */

size_t PKIPackNameConstraintsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKINameConstraints *asnstruct,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* lth of the block body */
    datasize = PKISizeofNameConstraints(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQUENCE */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

  do {

    /* field permittedSubtrees of NameConstraints */
    if (asnstruct->permittedSubtrees != NULL) { /* optional */
        bytesused += PKIPackGeneralSubtreesInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->permittedSubtrees, 0x80 | 0x00, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

    /* field excludedSubtrees of NameConstraints */
    if (asnstruct->excludedSubtrees != NULL) { /* optional */
        bytesused += PKIPackGeneralSubtreesInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->excludedSubtrees, 0x80 | 0x01, erret ) ;
        if (bytesused > datasize || *erret != 0)
            break;
    }

  } while(0);

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun)

    return bytesused;
} /* PKIPackNameConstraintsInternal */

size_t PKIUnpkInPlaceNameConstraints(
    PKICONTEXT *ctx,
    PKINameConstraints *asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE", "NameConstraints" );

    if (erret == NULL) return 0; /* can't report errors */
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }

    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* no error -- no block */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* no error code, just no block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }

    /* accept the tag byte */
    bytesused++;

    /* get the block length */
    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            return 0;
        }
    }

    PKITRACE_INCR_LEVEL;
  do {

    /* field permittedSubtrees of NameConstraints */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->permittedSubtrees != NULL)
        PKIFreeGeneralSubtrees(ctx, asnstruct->permittedSubtrees);
    bytesused += PKIUnpackGeneralSubtreesInternal(ctx, &(asnstruct->permittedSubtrees),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field excludedSubtrees of NameConstraints */
    if (!indef && bytesused >= localsize) {
        PKITRACE_DECR_LEVEL;
        return bytesused;
    }
    if (indef && *(buf+bytesused) == 0x00 &&
                 *(buf+bytesused+1) == 0x00) {
        PKITRACE_DECR_LEVEL;
        bytesused += 2;
        return bytesused;
    }
    if (asnstruct->excludedSubtrees != NULL)
        PKIFreeGeneralSubtrees(ctx, asnstruct->excludedSubtrees);
    bytesused += PKIUnpackGeneralSubtreesInternal(ctx, &(asnstruct->excludedSubtrees),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
            break;
        }
        bytesused += 2;
    }
  } while(0);

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceNameConstraints */

size_t PKIUnpackNameConstraintsInternal(
    PKICONTEXT *ctx,
    PKINameConstraints **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKINameConstraints *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewNameConstraints(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceNameConstraints(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeNameConstraints(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackNameConstraintsInternal */


/******************************************************************
 * Routines for CRLDistPointsSyntax
 ******************************************************************/

size_t PKISizeofCRLDistPointsSyntaxInternal(
    PKICRLDistPointsSyntax *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    long i, lth;
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n ;
    if (lth > PKIMAX_CRLDistPointsSyntax)
        lth = PKIMAX_CRLDistPointsSyntax;	/* clamp it */
    for (i=0; i<lth; i++)
        body_size += PKISizeofDistributionPointInternal((asnstruct->elt)[i], PKITRUE, PKIFALSE);

    if (outerSizeFlag == PKITRUE)
        body_size = PKITagged(body_size, 1);

    if (expTaggedFlag == PKITRUE)
        body_size = PKITagged(body_size, 1); /* this is seq like */

    return body_size;
} /* PKISizeofCRLDistPointsSyntaxInternal */

void PKIDropInPlaceCRLDistPointsSyntax(
    PKICONTEXT *ctx,
    PKICRLDistPointsSyntax *f)
{
    long i, lth;

    if (ctx == NULL) return;
    if (f == NULL) return;

    lth = f->n ;
    if (lth > PKIMAX_CRLDistPointsSyntax)
        lth = PKIMAX_CRLDistPointsSyntax ;	/* clamp it */
    for (i=0;i<lth;i++) {
        PKIFreeDistributionPoint(ctx, (f->elt)[i]);
        (f->elt)[i] = NULL;
    }
} /* PKIDropInPlaceCRLDistPointsSyntax */

size_t PKIPackCRLDistPointsSyntaxInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICRLDistPointsSyntax *asnstruct,
    unsigned char tag,
    int *erret )
{
    size_t bytesused;
    size_t tagsize;
    size_t datasize;
    long numElem;
    int i;

    if (erret == NULL) return 0; /* can't report errors */

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) return 0;

    /* make sure there aren't too many elements */
    numElem = asnstruct->n;
    if (numElem > PKIMAX_CRLDistPointsSyntax) {
        PKIERR(PKIErrPackSEQOFArrayTooLong);
        return 0;
    }

    /* lth of the block body */
    datasize = PKISizeofCRLDistPointsSyntax(ctx, asnstruct, PKIFALSE);
    tagsize = 1 + PKILengthSize(datasize);
    if (datasize+tagsize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

    /* this is a SEQ_OF */
    bytesused = PKIPutTag(buf, (unsigned char)(tag|0x20), datasize);
    if (bytesused != tagsize) {
        PKIERR(PKIErrPackOverrun);
        return bytesused;
    }
    datasize += tagsize;

    for (i=0; i<numElem; i++) {
        bytesused += PKIPackDistributionPointInternal(ctx, buf+bytesused, buflen-bytesused,
                        (asnstruct->elt)[i],
                        PKIID_DistributionPoint, erret);
        if (bytesused > datasize || *erret != 0)
            break;
    }

    if (bytesused < datasize && *erret == 0)
        PKIERR(PKIErrPackUnderrun)
    else if (bytesused > datasize && *erret == 0)
        PKIERR(PKIErrPackOverrun);

    return bytesused;
} /* PKIPackCRLDistPointsSyntaxInternal */

size_t PKIUnpkInPlaceCRLDistPointsSyntax(
     PKICONTEXT *ctx,
     PKICRLDistPointsSyntax *asnstruct,
     const unsigned char *buf,
     size_t buflen,
     unsigned char tag,
     int *erret)
{
    size_t bytesused = 0;
    size_t datasize;
    size_t localsize;
    int i ;
    int indef = 0;

    PKITRACE_PRINT_FN((tag|0x20), 0x30, "SEQUENCE OF", "CRLDistPointsSyntax");

    if (erret == NULL) return 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }

    if (buf == NULL) {
        PKIERR(PKIErrUnpackNoBlockPtr);
        return 0;
    }

    if (buflen <= 0) return 0; /* out of bytes, no action */

    if ( (*buf & 0xDF) != (tag & 0xDF) )
        return 0; /* not my kind of block */
    if ( (*buf & 0x20) != 0x20) {
        PKIERR(PKIErrUnpackInvalidEncoding);
        return 0;
    }
    bytesused ++; /* consume the tag byte */

    PKITRACE_INCR_LEVEL;

    bytesused += PKIGetLength(buf+bytesused, &datasize);
    if ((int)datasize == -1) {
        localsize = buflen;
        indef = 1;
    }
    else {
        localsize = bytesused + datasize;
        if (localsize > buflen) {
            PKIERR(PKIErrUnpackOverrun);
            asnstruct->n = -1 ; /* note where (-1 treated as 0) */
            PKITRACE_DECR_LEVEL;
            return 0;
        }
    }

    for (i=0; (i < PKIMAX_CRLDistPointsSyntax) && (bytesused < localsize); i++) {

        /* if this is indef length and we have EOC, done */
        if (indef && *(buf+bytesused) == 0x00 &&
                     *(buf+bytesused+1) == 0x00 )
            break;

        if (asnstruct->elt[i] == NULL)
            asnstruct->elt[i] = PKINewDistributionPoint(ctx);
        if (asnstruct->elt[i] == NULL) {
            PKIERR(PKIErrOutOfMemory);
            break;
        }
        asnstruct->n = i+1 ; /* note the new element */
        bytesused += PKIUnpkInPlaceDistributionPoint(ctx, asnstruct->elt[i], buf+bytesused,
                            localsize-bytesused, PKIID_DistributionPoint, erret);
        if (*erret != 0)
            break;
    } /* for */

    if (indef) {
        if ( *(buf+bytesused) != 0x00 &&
             *(buf+bytesused+1) != 0x00 ) {
            PKIERR(PKIErrUnpackInvalidEncoding);
        }
        else
            bytesused += 2;
    }

    PKITRACE_DECR_LEVEL;
    if (bytesused > localsize && *erret == 0)
        PKIERR(PKIErrUnpackOverrun);
    if (!indef && bytesused < localsize && *erret == 0)
        PKIERR(PKIErrUnpackUnderrun);

    return bytesused;
} /* PKIUnpkInPlaceCRLDistPointsSyntax */

size_t PKIUnpackCRLDistPointsSyntaxInternal(
    PKICONTEXT *ctx,
    PKICRLDistPointsSyntax **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICRLDistPointsSyntax *local = NULL;

    if (erret == NULL) return 0;
    *erret = 0;

    if (ctx == NULL) {
        PKIERR(PKIErrBadContext);
        return 0;
    }
    if (asnstruct == NULL) {
        PKIERR(PKIErrUnpackNoStructure);
        return 0;
    }
    *asnstruct = NULL;

    if (buflen <= 0) return 0; /* no bytes left */

    if ( (*buf & 0xDF) != (tag & 0xDF) ) 
        return 0; /* not correct tag */

    local = PKINewCRLDistPointsSyntax(ctx); /* carve a block for it */
    bytesused = PKIUnpkInPlaceCRLDistPointsSyntax(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        if (local != NULL) PKIFreeCRLDistPointsSyntax(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCRLDistPointsSyntaxInternal */

