/*******************************************************************
 *
 * This file was generated by TIS/ASN1COMP Ver. 4.0, an ASN.1 compiler.
 * TIS/ASN1COMP is Copyright (c) 1998, TIS Labs at Network Associates, Inc.
 *
 * This file was AUTOMATICALLY GENERATED on Wed Nov 18 16:32:31 1998
 *
 ******************************************************************/


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

#include "pkcs7_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 CertificateRevocationLists
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_CertificateRevocationLists)
        lth = PKIMAX_CertificateRevocationLists;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofCertificateListInternal((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;
} /* PKISizeofCertificateRevocationListsInternal */

void PKIDropInPlaceCertificateRevocationLists(
    PKICONTEXT *ctx,
    PKICertificateRevocationLists *f)
{
    long i, lth;

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

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

size_t PKIPackCertificateRevocationListsInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKICertificateRevocationLists *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_CertificateRevocationLists];

    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_CertificateRevocationLists) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofCertificateRevocationLists(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 += PKIPackCertificateListInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_CertificateList, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofCertificateList(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) PKIPackCertificateListInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_CertificateList, 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;
} /* PKIPackCertificateRevocationListsInternal */

size_t PKIUnpkInPlaceCertificateRevocationLists(
    PKICONTEXT *ctx,
    PKICertificateRevocationLists *asnstruct,
    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", "CertificateRevocationLists");

    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_CertificateRevocationLists) && (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] = PKINewCertificateList(ctx);
        bytesused += PKIUnpkInPlaceCertificateList(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_CertificateList, erret);
        if (*erret != 0 || asnstruct->elt[i] == NULL)
            break;
        asnstruct->n = i+1 ; /* note the new element */
    } /* 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;
} /* PKIUnpkInPlaceCertificateRevocationLists */

size_t PKIUnpackCertificateRevocationListsInternal(
    PKICONTEXT *ctx,
    PKICertificateRevocationLists **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKICertificateRevocationLists *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 = PKINewCertificateRevocationLists(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceCertificateRevocationLists(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeCertificateRevocationLists(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackCertificateRevocationListsInternal */


/******************************************************************
 * Routines for ContentInfo
 ******************************************************************/

size_t PKISizeofContentInfoInternal(PKIContentInfo *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofContentTypeInternal(&asnstruct->contentType, PKITRUE, PKIFALSE)
          + PKISizeofANYInternal(asnstruct->content, 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;

} /* PKISizeofContentInfoInternal */

void PKIDropInPlaceContentInfo(
    PKICONTEXT *ctx,
    PKIContentInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceContentType(ctx, &(f->contentType));
    PKIFreeANY(ctx, f->content);
    f->content = NULL;
} /* PKIDropInPlaceContentInfo */

size_t PKIPackContentInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIContentInfo *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 = PKISizeofContentInfo(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 contentType of ContentInfo */
    bytesused += PKIPackContentTypeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->contentType), PKIID_ContentType, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field content of ContentInfo */
    if (asnstruct->content != NULL) { /* optional */
        bytesused += PKIPutTag(buf+bytesused, 0xa0 | 0x00, PKISizeofANY(ctx, asnstruct->content, PKITRUE));
        bytesused += PKIPackANYInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->content, 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;
} /* PKIPackContentInfoInternal */

size_t PKIUnpkInPlaceContentInfo(
    PKICONTEXT *ctx,
    PKIContentInfo *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", "ContentInfo" );

    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 contentType of ContentInfo */
    bytesused += PKIUnpkInPlaceContentType(ctx, &(asnstruct->contentType), buf+bytesused,
                        localsize-bytesused, PKIID_ContentType, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field content of ContentInfo */
    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->content != NULL)
                PKIFreeANY(ctx, asnstruct->content);
            bytesused += PKIUnpackANYInternal(ctx, &(asnstruct->content),
                    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;
            if (asnstruct->content != NULL)
                PKIFreeANY(ctx, asnstruct->content);
            bytesused += PKIUnpackANYInternal(ctx, &(asnstruct->content),
                       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;
} /* PKIUnpkInPlaceContentInfo */

size_t PKIUnpackContentInfoInternal(
    PKICONTEXT *ctx,
    PKIContentInfo **asnstruct,
    const unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIContentInfo *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 = PKINewContentInfo(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceContentInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeContentInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackContentInfoInternal */


/******************************************************************
 * Routines for ExtendedCertificateInfo
 ******************************************************************/

size_t PKISizeofExtendedCertificateInfoInternal(PKIExtendedCertificateInfo *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofCertificateInternal(&asnstruct->certificate, 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;

} /* PKISizeofExtendedCertificateInfoInternal */

void PKIDropInPlaceExtendedCertificateInfo(
    PKICONTEXT *ctx,
    PKIExtendedCertificateInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceCertificate(ctx, &(f->certificate));
    PKIDropInPlaceAttributes(ctx, &(f->attributes));
} /* PKIDropInPlaceExtendedCertificateInfo */

size_t PKIPackExtendedCertificateInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtendedCertificateInfo *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 = PKISizeofExtendedCertificateInfo(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 ExtendedCertificateInfo */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field certificate of ExtendedCertificateInfo */
    bytesused += PKIPackCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->certificate), PKIID_Certificate, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field attributes of ExtendedCertificateInfo */
    bytesused += PKIPackAttributesInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->attributes), PKIID_Attributes, 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;
} /* PKIPackExtendedCertificateInfoInternal */

size_t PKIUnpkInPlaceExtendedCertificateInfo(
    PKICONTEXT *ctx,
    PKIExtendedCertificateInfo *asnstruct,
    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", "ExtendedCertificateInfo" );

    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 ExtendedCertificateInfo */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field certificate of ExtendedCertificateInfo */
    bytesused += PKIUnpkInPlaceCertificate(ctx, &(asnstruct->certificate), buf+bytesused,
                        localsize-bytesused, PKIID_Certificate, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field attributes of ExtendedCertificateInfo */
    bytesused += PKIUnpkInPlaceAttributes(ctx, &(asnstruct->attributes), buf+bytesused,
                        localsize-bytesused, PKIID_Attributes, 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;
} /* PKIUnpkInPlaceExtendedCertificateInfo */

size_t PKIUnpackExtendedCertificateInfoInternal(
    PKICONTEXT *ctx,
    PKIExtendedCertificateInfo **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtendedCertificateInfo *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 = PKINewExtendedCertificateInfo(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceExtendedCertificateInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeExtendedCertificateInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackExtendedCertificateInfoInternal */


/******************************************************************
 * Routines for IssuerAndSerialNumber
 ******************************************************************/

size_t PKISizeofIssuerAndSerialNumberInternal(PKIIssuerAndSerialNumber *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofNameInternal(&asnstruct->issuer, PKITRUE, PKIFALSE)
          + PKISizeofCertificateSerialNumberInternal(&asnstruct->serialNumber, 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;

} /* PKISizeofIssuerAndSerialNumberInternal */

void PKIDropInPlaceIssuerAndSerialNumber(
    PKICONTEXT *ctx,
    PKIIssuerAndSerialNumber *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceName(ctx, &(f->issuer));
    PKIDropInPlaceCertificateSerialNumber(ctx, &(f->serialNumber));
} /* PKIDropInPlaceIssuerAndSerialNumber */

size_t PKIPackIssuerAndSerialNumberInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIIssuerAndSerialNumber *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 = PKISizeofIssuerAndSerialNumber(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 issuer of IssuerAndSerialNumber */
    bytesused += PKIPackNameInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuer), PKIID_Name, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field serialNumber of IssuerAndSerialNumber */
    bytesused += PKIPackCertificateSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->serialNumber), PKIID_CertificateSerialNumber, 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;
} /* PKIPackIssuerAndSerialNumberInternal */

size_t PKIUnpkInPlaceIssuerAndSerialNumber(
    PKICONTEXT *ctx,
    PKIIssuerAndSerialNumber *asnstruct,
    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", "IssuerAndSerialNumber" );

    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 issuer of IssuerAndSerialNumber */
    bytesused += PKIUnpkInPlaceName(ctx, &(asnstruct->issuer), buf+bytesused,
                        localsize-bytesused, PKIID_Name, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field serialNumber of IssuerAndSerialNumber */
    bytesused += PKIUnpkInPlaceCertificateSerialNumber(ctx, &(asnstruct->serialNumber), buf+bytesused,
                        localsize-bytesused, PKIID_CertificateSerialNumber, 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;
} /* PKIUnpkInPlaceIssuerAndSerialNumber */

size_t PKIUnpackIssuerAndSerialNumberInternal(
    PKICONTEXT *ctx,
    PKIIssuerAndSerialNumber **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIIssuerAndSerialNumber *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 = PKINewIssuerAndSerialNumber(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceIssuerAndSerialNumber(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeIssuerAndSerialNumber(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackIssuerAndSerialNumberInternal */


/******************************************************************
 * Routines for DigestAlgorithmIdentifiers
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_DigestAlgorithmIdentifiers)
        lth = PKIMAX_DigestAlgorithmIdentifiers;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofDigestAlgorithmIdentifierInternal((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;
} /* PKISizeofDigestAlgorithmIdentifiersInternal */

void PKIDropInPlaceDigestAlgorithmIdentifiers(
    PKICONTEXT *ctx,
    PKIDigestAlgorithmIdentifiers *f)
{
    long i, lth;

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

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

size_t PKIPackDigestAlgorithmIdentifiersInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDigestAlgorithmIdentifiers *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_DigestAlgorithmIdentifiers];

    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_DigestAlgorithmIdentifiers) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofDigestAlgorithmIdentifiers(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 += PKIPackDigestAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_DigestAlgorithmIdentifier, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofDigestAlgorithmIdentifier(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) PKIPackDigestAlgorithmIdentifierInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_DigestAlgorithmIdentifier, 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;
} /* PKIPackDigestAlgorithmIdentifiersInternal */

size_t PKIUnpkInPlaceDigestAlgorithmIdentifiers(
    PKICONTEXT *ctx,
    PKIDigestAlgorithmIdentifiers *asnstruct,
    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", "DigestAlgorithmIdentifiers");

    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_DigestAlgorithmIdentifiers) && (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] = PKINewDigestAlgorithmIdentifier(ctx);
        bytesused += PKIUnpkInPlaceDigestAlgorithmIdentifier(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_DigestAlgorithmIdentifier, erret);
        if (*erret != 0 || asnstruct->elt[i] == NULL)
            break;
        asnstruct->n = i+1 ; /* note the new element */
    } /* 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;
} /* PKIUnpkInPlaceDigestAlgorithmIdentifiers */

size_t PKIUnpackDigestAlgorithmIdentifiersInternal(
    PKICONTEXT *ctx,
    PKIDigestAlgorithmIdentifiers **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDigestAlgorithmIdentifiers *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 = PKINewDigestAlgorithmIdentifiers(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceDigestAlgorithmIdentifiers(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeDigestAlgorithmIdentifiers(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDigestAlgorithmIdentifiersInternal */


/******************************************************************
 * Routines for DigestInfo
 ******************************************************************/

size_t PKISizeofDigestInfoInternal(PKIDigestInfo *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofDigestAlgorithmIdentifierInternal(&asnstruct->digestAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofDigestInternal(&asnstruct->digest, 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;

} /* PKISizeofDigestInfoInternal */

void PKIDropInPlaceDigestInfo(
    PKICONTEXT *ctx,
    PKIDigestInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceDigestAlgorithmIdentifier(ctx, &(f->digestAlgorithm));
    PKIDropInPlaceDigest(ctx, &(f->digest));
} /* PKIDropInPlaceDigestInfo */

size_t PKIPackDigestInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIDigestInfo *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 = PKISizeofDigestInfo(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 digestAlgorithm of DigestInfo */
    bytesused += PKIPackDigestAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->digestAlgorithm), PKIID_DigestAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field digest of DigestInfo */
    bytesused += PKIPackDigestInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->digest), PKIID_Digest, 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;
} /* PKIPackDigestInfoInternal */

size_t PKIUnpkInPlaceDigestInfo(
    PKICONTEXT *ctx,
    PKIDigestInfo *asnstruct,
    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", "DigestInfo" );

    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 digestAlgorithm of DigestInfo */
    bytesused += PKIUnpkInPlaceDigestAlgorithmIdentifier(ctx, &(asnstruct->digestAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_DigestAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field digest of DigestInfo */
    bytesused += PKIUnpkInPlaceDigest(ctx, &(asnstruct->digest), buf+bytesused,
                        localsize-bytesused, PKIID_Digest, 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;
} /* PKIUnpkInPlaceDigestInfo */

size_t PKIUnpackDigestInfoInternal(
    PKICONTEXT *ctx,
    PKIDigestInfo **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIDigestInfo *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 = PKINewDigestInfo(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceDigestInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeDigestInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackDigestInfoInternal */


/******************************************************************
 * Routines for EncryptedContentInfo
 ******************************************************************/

size_t PKISizeofEncryptedContentInfoInternal(PKIEncryptedContentInfo *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofContentTypeInternal(&asnstruct->contentType, PKITRUE, PKIFALSE)
          + PKISizeofContentEncryptionAlgorithmIdentifierInternal(&asnstruct->contentEncryptionAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofEncryptedContentInternal(asnstruct->encryptedContent, 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;

} /* PKISizeofEncryptedContentInfoInternal */

void PKIDropInPlaceEncryptedContentInfo(
    PKICONTEXT *ctx,
    PKIEncryptedContentInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceContentType(ctx, &(f->contentType));
    PKIDropInPlaceContentEncryptionAlgorithmIdentifier(ctx, &(f->contentEncryptionAlgorithm));
    PKIFreeEncryptedContent(ctx, f->encryptedContent);
    f->encryptedContent = NULL;
} /* PKIDropInPlaceEncryptedContentInfo */

size_t PKIPackEncryptedContentInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIEncryptedContentInfo *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 = PKISizeofEncryptedContentInfo(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 contentType of EncryptedContentInfo */
    bytesused += PKIPackContentTypeInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->contentType), PKIID_ContentType, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field contentEncryptionAlgorithm of EncryptedContentInfo */
    bytesused += PKIPackContentEncryptionAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->contentEncryptionAlgorithm), PKIID_ContentEncryptionAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field encryptedContent of EncryptedContentInfo */
    if (asnstruct->encryptedContent != NULL) { /* optional */
        bytesused += PKIPackEncryptedContentInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->encryptedContent, 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;
} /* PKIPackEncryptedContentInfoInternal */

size_t PKIUnpkInPlaceEncryptedContentInfo(
    PKICONTEXT *ctx,
    PKIEncryptedContentInfo *asnstruct,
    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", "EncryptedContentInfo" );

    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 contentType of EncryptedContentInfo */
    bytesused += PKIUnpkInPlaceContentType(ctx, &(asnstruct->contentType), buf+bytesused,
                        localsize-bytesused, PKIID_ContentType, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field contentEncryptionAlgorithm of EncryptedContentInfo */
    bytesused += PKIUnpkInPlaceContentEncryptionAlgorithmIdentifier(ctx, &(asnstruct->contentEncryptionAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_ContentEncryptionAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field encryptedContent of EncryptedContentInfo */
    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->encryptedContent != NULL)
        PKIFreeEncryptedContent(ctx, asnstruct->encryptedContent);
    bytesused += PKIUnpackEncryptedContentInternal(ctx, &(asnstruct->encryptedContent),
                 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;
} /* PKIUnpkInPlaceEncryptedContentInfo */

size_t PKIUnpackEncryptedContentInfoInternal(
    PKICONTEXT *ctx,
    PKIEncryptedContentInfo **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIEncryptedContentInfo *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 = PKINewEncryptedContentInfo(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceEncryptedContentInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeEncryptedContentInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackEncryptedContentInfoInternal */


/******************************************************************
 * Routines for ExtendedCertificate
 ******************************************************************/

size_t PKISizeofExtendedCertificateInternal(PKIExtendedCertificate *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofExtendedCertificateInfoInternal(&asnstruct->extendedCertificateInfo, PKITRUE, PKIFALSE)
          + PKISizeofSignatureAlgorithmIdentifierInternal(&asnstruct->signatureAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofSignatureInternal(&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;

} /* PKISizeofExtendedCertificateInternal */

void PKIDropInPlaceExtendedCertificate(
    PKICONTEXT *ctx,
    PKIExtendedCertificate *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceExtendedCertificateInfo(ctx, &(f->extendedCertificateInfo));
    PKIDropInPlaceSignatureAlgorithmIdentifier(ctx, &(f->signatureAlgorithm));
    PKIDropInPlaceSignature(ctx, &(f->signature));
} /* PKIDropInPlaceExtendedCertificate */

size_t PKIPackExtendedCertificateInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtendedCertificate *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 = PKISizeofExtendedCertificate(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 extendedCertificateInfo of ExtendedCertificate */
    bytesused += PKIPackExtendedCertificateInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->extendedCertificateInfo), PKIID_ExtendedCertificateInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signatureAlgorithm of ExtendedCertificate */
    bytesused += PKIPackSignatureAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signatureAlgorithm), PKIID_SignatureAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field signature of ExtendedCertificate */
    bytesused += PKIPackSignatureInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signature), PKIID_Signature, 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;
} /* PKIPackExtendedCertificateInternal */

size_t PKIUnpkInPlaceExtendedCertificate(
    PKICONTEXT *ctx,
    PKIExtendedCertificate *asnstruct,
    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", "ExtendedCertificate" );

    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 extendedCertificateInfo of ExtendedCertificate */
    bytesused += PKIUnpkInPlaceExtendedCertificateInfo(ctx, &(asnstruct->extendedCertificateInfo), buf+bytesused,
                        localsize-bytesused, PKIID_ExtendedCertificateInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signatureAlgorithm of ExtendedCertificate */
    bytesused += PKIUnpkInPlaceSignatureAlgorithmIdentifier(ctx, &(asnstruct->signatureAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_SignatureAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signature of ExtendedCertificate */
    bytesused += PKIUnpkInPlaceSignature(ctx, &(asnstruct->signature), buf+bytesused,
                        localsize-bytesused, PKIID_Signature, 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;
} /* PKIUnpkInPlaceExtendedCertificate */

size_t PKIUnpackExtendedCertificateInternal(
    PKICONTEXT *ctx,
    PKIExtendedCertificate **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtendedCertificate *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 = PKINewExtendedCertificate(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceExtendedCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeExtendedCertificate(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackExtendedCertificateInternal */


/******************************************************************
 * Routines for RecipientInfo
 ******************************************************************/

size_t PKISizeofRecipientInfoInternal(PKIRecipientInfo *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofIssuerAndSerialNumberInternal(&asnstruct->issuerAndSerialNumber, PKITRUE, PKIFALSE)
          + PKISizeofKeyEncryptionAlgorithmIdentifierInternal(&asnstruct->keyEncryptionAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofEncryptedKeyInternal(&asnstruct->encryptedKey, 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;

} /* PKISizeofRecipientInfoInternal */

void PKIDropInPlaceRecipientInfo(
    PKICONTEXT *ctx,
    PKIRecipientInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceIssuerAndSerialNumber(ctx, &(f->issuerAndSerialNumber));
    PKIDropInPlaceKeyEncryptionAlgorithmIdentifier(ctx, &(f->keyEncryptionAlgorithm));
    PKIDropInPlaceEncryptedKey(ctx, &(f->encryptedKey));
} /* PKIDropInPlaceRecipientInfo */

size_t PKIPackRecipientInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRecipientInfo *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 = PKISizeofRecipientInfo(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 RecipientInfo */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuerAndSerialNumber of RecipientInfo */
    bytesused += PKIPackIssuerAndSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuerAndSerialNumber), PKIID_IssuerAndSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field keyEncryptionAlgorithm of RecipientInfo */
    bytesused += PKIPackKeyEncryptionAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->keyEncryptionAlgorithm), PKIID_KeyEncryptionAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field encryptedKey of RecipientInfo */
    bytesused += PKIPackEncryptedKeyInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->encryptedKey), PKIID_EncryptedKey, 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;
} /* PKIPackRecipientInfoInternal */

size_t PKIUnpkInPlaceRecipientInfo(
    PKICONTEXT *ctx,
    PKIRecipientInfo *asnstruct,
    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", "RecipientInfo" );

    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 RecipientInfo */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuerAndSerialNumber of RecipientInfo */
    bytesused += PKIUnpkInPlaceIssuerAndSerialNumber(ctx, &(asnstruct->issuerAndSerialNumber), buf+bytesused,
                        localsize-bytesused, PKIID_IssuerAndSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field keyEncryptionAlgorithm of RecipientInfo */
    bytesused += PKIUnpkInPlaceKeyEncryptionAlgorithmIdentifier(ctx, &(asnstruct->keyEncryptionAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_KeyEncryptionAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field encryptedKey of RecipientInfo */
    bytesused += PKIUnpkInPlaceEncryptedKey(ctx, &(asnstruct->encryptedKey), buf+bytesused,
                        localsize-bytesused, PKIID_EncryptedKey, 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;
} /* PKIUnpkInPlaceRecipientInfo */

size_t PKIUnpackRecipientInfoInternal(
    PKICONTEXT *ctx,
    PKIRecipientInfo **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRecipientInfo *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 = PKINewRecipientInfo(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceRecipientInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeRecipientInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRecipientInfoInternal */


/******************************************************************
 * Routines for SignerInfo
 ******************************************************************/

size_t PKISizeofSignerInfoInternal(PKISignerInfo *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofIssuerAndSerialNumberInternal(&asnstruct->issuerAndSerialNumber, PKITRUE, PKIFALSE)
          + PKISizeofDigestAlgorithmIdentifierInternal(&asnstruct->digestAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofAttributesInternal(asnstruct->authenticatedAttributes, PKITRUE, PKIFALSE)
          + PKISizeofDigestEncryptionAlgorithmIdentifierInternal(&asnstruct->digestEncryptionAlgorithm, PKITRUE, PKIFALSE)
          + PKISizeofEncryptedDigestInternal(&asnstruct->encryptedDigest, PKITRUE, PKIFALSE)
          + PKISizeofAttributesInternal(asnstruct->unauthenticatedAttributes, 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;

} /* PKISizeofSignerInfoInternal */

void PKIDropInPlaceSignerInfo(
    PKICONTEXT *ctx,
    PKISignerInfo *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceIssuerAndSerialNumber(ctx, &(f->issuerAndSerialNumber));
    PKIDropInPlaceDigestAlgorithmIdentifier(ctx, &(f->digestAlgorithm));
    PKIFreeAttributes(ctx, f->authenticatedAttributes);
    f->authenticatedAttributes = NULL;
    PKIDropInPlaceDigestEncryptionAlgorithmIdentifier(ctx, &(f->digestEncryptionAlgorithm));
    PKIDropInPlaceEncryptedDigest(ctx, &(f->encryptedDigest));
    PKIFreeAttributes(ctx, f->unauthenticatedAttributes);
    f->unauthenticatedAttributes = NULL;
} /* PKIDropInPlaceSignerInfo */

size_t PKIPackSignerInfoInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKISignerInfo *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 = PKISizeofSignerInfo(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 SignerInfo */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field issuerAndSerialNumber of SignerInfo */
    bytesused += PKIPackIssuerAndSerialNumberInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->issuerAndSerialNumber), PKIID_IssuerAndSerialNumber, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field digestAlgorithm of SignerInfo */
    bytesused += PKIPackDigestAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->digestAlgorithm), PKIID_DigestAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

    /* field digestEncryptionAlgorithm of SignerInfo */
    bytesused += PKIPackDigestEncryptionAlgorithmIdentifierInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->digestEncryptionAlgorithm), PKIID_DigestEncryptionAlgorithmIdentifier, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field encryptedDigest of SignerInfo */
    bytesused += PKIPackEncryptedDigestInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->encryptedDigest), PKIID_EncryptedDigest, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field unauthenticatedAttributes of SignerInfo */
    if (asnstruct->unauthenticatedAttributes != NULL) { /* optional */
        bytesused += PKIPackAttributesInternal(ctx, buf+bytesused, buflen-bytesused,
                           asnstruct->unauthenticatedAttributes, 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;
} /* PKIPackSignerInfoInternal */

size_t PKIUnpkInPlaceSignerInfo(
    PKICONTEXT *ctx,
    PKISignerInfo *asnstruct,
    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", "SignerInfo" );

    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 SignerInfo */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field issuerAndSerialNumber of SignerInfo */
    bytesused += PKIUnpkInPlaceIssuerAndSerialNumber(ctx, &(asnstruct->issuerAndSerialNumber), buf+bytesused,
                        localsize-bytesused, PKIID_IssuerAndSerialNumber, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field digestAlgorithm of SignerInfo */
    bytesused += PKIUnpkInPlaceDigestAlgorithmIdentifier(ctx, &(asnstruct->digestAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_DigestAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field authenticatedAttributes of SignerInfo */
    if (asnstruct->authenticatedAttributes != NULL)
        PKIFreeAttributes(ctx, asnstruct->authenticatedAttributes);
    bytesused += PKIUnpackAttributesInternal(ctx, &(asnstruct->authenticatedAttributes),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field digestEncryptionAlgorithm of SignerInfo */
    bytesused += PKIUnpkInPlaceDigestEncryptionAlgorithmIdentifier(ctx, &(asnstruct->digestEncryptionAlgorithm), buf+bytesused,
                        localsize-bytesused, PKIID_DigestEncryptionAlgorithmIdentifier, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field encryptedDigest of SignerInfo */
    bytesused += PKIUnpkInPlaceEncryptedDigest(ctx, &(asnstruct->encryptedDigest), buf+bytesused,
                        localsize-bytesused, PKIID_EncryptedDigest, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field unauthenticatedAttributes of SignerInfo */
    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->unauthenticatedAttributes != NULL)
        PKIFreeAttributes(ctx, asnstruct->unauthenticatedAttributes);
    bytesused += PKIUnpackAttributesInternal(ctx, &(asnstruct->unauthenticatedAttributes),
                 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;
} /* PKIUnpkInPlaceSignerInfo */

size_t PKIUnpackSignerInfoInternal(
    PKICONTEXT *ctx,
    PKISignerInfo **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKISignerInfo *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 = PKINewSignerInfo(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceSignerInfo(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeSignerInfo(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackSignerInfoInternal */


/******************************************************************
 * Routines for EncryptedData
 ******************************************************************/

size_t PKISizeofEncryptedDataInternal(PKIEncryptedData *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofEncryptedContentInfoInternal(&asnstruct->encryptedContentInfo, 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;

} /* PKISizeofEncryptedDataInternal */

void PKIDropInPlaceEncryptedData(
    PKICONTEXT *ctx,
    PKIEncryptedData *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceEncryptedContentInfo(ctx, &(f->encryptedContentInfo));
} /* PKIDropInPlaceEncryptedData */

size_t PKIPackEncryptedDataInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIEncryptedData *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 = PKISizeofEncryptedData(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 EncryptedData */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field encryptedContentInfo of EncryptedData */
    bytesused += PKIPackEncryptedContentInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->encryptedContentInfo), PKIID_EncryptedContentInfo, 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;
} /* PKIPackEncryptedDataInternal */

size_t PKIUnpkInPlaceEncryptedData(
    PKICONTEXT *ctx,
    PKIEncryptedData *asnstruct,
    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", "EncryptedData" );

    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 EncryptedData */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field encryptedContentInfo of EncryptedData */
    bytesused += PKIUnpkInPlaceEncryptedContentInfo(ctx, &(asnstruct->encryptedContentInfo), buf+bytesused,
                        localsize-bytesused, PKIID_EncryptedContentInfo, 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;
} /* PKIUnpkInPlaceEncryptedData */

size_t PKIUnpackEncryptedDataInternal(
    PKICONTEXT *ctx,
    PKIEncryptedData **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIEncryptedData *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 = PKINewEncryptedData(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceEncryptedData(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeEncryptedData(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackEncryptedDataInternal */


/******************************************************************
 * Routines for ExtendedCertificateOrCertificate
 ******************************************************************/

size_t PKISizeofExtendedCertificateOrCertificateInternal(
    PKIExtendedCertificateOrCertificate *asnstruct,
    int outerSizeFlag,
    int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    switch (asnstruct->CHOICE_field_type) {
      case PKIID_Certificate:
      case 0x20|PKIID_Certificate:
        body_size = PKISizeofCertificateInternal((PKICertificate *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      case 0x80|0x00:
      case 0x80|0x20|0x00:
        body_size = PKISizeofExtendedCertificateInternal((PKIExtendedCertificate *)(asnstruct->data), outerSizeFlag, expTaggedFlag);
        break;

      default:
        break;

    } /* switch */

    return (body_size);
} /* PKISizeofExtendedCertificateOrCertificateInternal */

void PKIDropInPlaceExtendedCertificateOrCertificate(
    PKICONTEXT *ctx,
    PKIExtendedCertificateOrCertificate *f)
{
    if (ctx == NULL) return;
    if (f == NULL) return;

    switch(f->CHOICE_field_type) {

    case PKIID_Certificate:
    case 0x20|PKIID_Certificate:
        PKIFreeCertificate(ctx, (PKICertificate *)( f->data ));
        break;
    case 0x80|0x00:
    case 0x80|0x20|0x00:
        PKIFreeExtendedCertificate(ctx, (PKIExtendedCertificate *)(f->data));
        break;
    default:
        break;
    } /* switch */

} /* PKIDropInPlaceExtendedCertificateOrCertificate */

size_t PKIPackExtendedCertificateOrCertificateInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtendedCertificateOrCertificate *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 = PKISizeofExtendedCertificateOrCertificate(ctx, asnstruct, PKITRUE);
    if (datasize > buflen) {
        PKIERR(PKIErrPackBufferTooShort);
        return 0;
    }

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

    case PKIID_Certificate:
        bytesused += PKIPackCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                     (PKICertificate *)(asnstruct->data),
                     PKIID_Certificate,
                     erret);
        break;

    case 0x80|0x00:
        bytesused += PKIPackExtendedCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                      (PKIExtendedCertificate *)(asnstruct->data),
                      0x80|0x00,
                      erret);
        break;

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

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

  return bytesused;
} /* PKIPackExtendedCertificateOrCertificateInternal */

size_t PKIUnpkInPlaceExtendedCertificateOrCertificate(
     PKICONTEXT *ctx,
     PKIExtendedCertificateOrCertificate *asnstruct,/* output block */
     unsigned char *buf,/* loc of input pointer */
     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) {

    /* certificate */
    case PKIID_Certificate:
    case 0x20|PKIID_Certificate:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewCertificate(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceCertificate(ctx, (PKICertificate *)(asnstruct->data),
                    buf, buflen,
                    PKIID_Certificate, erret));
        /*NOTREACHED*/
        break;

    /* extendedCertificate */
    case 0x80|0x00:
    case 0x80|0x20|0x00:
        asnstruct->CHOICE_field_type = *buf;
        asnstruct->data = (void *)PKINewExtendedCertificate(ctx);
        if (asnstruct->data == NULL) {
            PKIERR(PKIErrOutOfMemory);
            return 0;
        }
        return (PKIUnpkInPlaceExtendedCertificate(ctx, (PKIExtendedCertificate *)(asnstruct->data),
                    buf, buflen,
                    0x80|0x00, erret));
        /*NOTREACHED*/
        break;

    default:
        PKIERR(PKIErrChoiceBadType);
        return 0;

    } /* switch */

} /* PKIUnpkInPlaceExtendedCertificateOrCertificate */

size_t PKIUnpackExtendedCertificateOrCertificateInternal(
    PKICONTEXT *ctx,
    PKIExtendedCertificateOrCertificate **asnstruct,
    unsigned char *buf, /* location of cur ptr into the ASN block */
    size_t buflen, /* my end pointer */
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtendedCertificateOrCertificate *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 = PKINewExtendedCertificateOrCertificate(ctx) ; /* carve a block for it */
    bytesused = PKIUnpkInPlaceExtendedCertificateOrCertificate(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeExtendedCertificateOrCertificate(ctx, local);
        return 0;
    }

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


/******************************************************************
 * Routines for RecipientInfos
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_RecipientInfos)
        lth = PKIMAX_RecipientInfos;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofRecipientInfoInternal((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;
} /* PKISizeofRecipientInfosInternal */

void PKIDropInPlaceRecipientInfos(
    PKICONTEXT *ctx,
    PKIRecipientInfos *f)
{
    long i, lth;

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

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

size_t PKIPackRecipientInfosInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIRecipientInfos *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_RecipientInfos];

    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_RecipientInfos) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofRecipientInfos(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 += PKIPackRecipientInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_RecipientInfo, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofRecipientInfo(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) PKIPackRecipientInfoInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_RecipientInfo, 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;
} /* PKIPackRecipientInfosInternal */

size_t PKIUnpkInPlaceRecipientInfos(
    PKICONTEXT *ctx,
    PKIRecipientInfos *asnstruct,
    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", "RecipientInfos");

    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_RecipientInfos) && (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] = PKINewRecipientInfo(ctx);
        bytesused += PKIUnpkInPlaceRecipientInfo(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_RecipientInfo, erret);
        if (*erret != 0 || asnstruct->elt[i] == NULL)
            break;
        asnstruct->n = i+1 ; /* note the new element */
    } /* 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;
} /* PKIUnpkInPlaceRecipientInfos */

size_t PKIUnpackRecipientInfosInternal(
    PKICONTEXT *ctx,
    PKIRecipientInfos **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIRecipientInfos *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 = PKINewRecipientInfos(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceRecipientInfos(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeRecipientInfos(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackRecipientInfosInternal */


/******************************************************************
 * Routines for SignerInfos
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_SignerInfos)
        lth = PKIMAX_SignerInfos;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofSignerInfoInternal((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;
} /* PKISizeofSignerInfosInternal */

void PKIDropInPlaceSignerInfos(
    PKICONTEXT *ctx,
    PKISignerInfos *f)
{
    long i, lth;

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

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

size_t PKIPackSignerInfosInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKISignerInfos *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_SignerInfos];

    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_SignerInfos) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofSignerInfos(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 += PKIPackSignerInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_SignerInfo, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofSignerInfo(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) PKIPackSignerInfoInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_SignerInfo, 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;
} /* PKIPackSignerInfosInternal */

size_t PKIUnpkInPlaceSignerInfos(
    PKICONTEXT *ctx,
    PKISignerInfos *asnstruct,
    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", "SignerInfos");

    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_SignerInfos) && (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] = PKINewSignerInfo(ctx);
        bytesused += PKIUnpkInPlaceSignerInfo(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_SignerInfo, erret);
        if (*erret != 0 || asnstruct->elt[i] == NULL)
            break;
        asnstruct->n = i+1 ; /* note the new element */
    } /* 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;
} /* PKIUnpkInPlaceSignerInfos */

size_t PKIUnpackSignerInfosInternal(
    PKICONTEXT *ctx,
    PKISignerInfos **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKISignerInfos *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 = PKINewSignerInfos(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceSignerInfos(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeSignerInfos(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackSignerInfosInternal */


/******************************************************************
 * Routines for EnvelopedData
 ******************************************************************/

size_t PKISizeofEnvelopedDataInternal(PKIEnvelopedData *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofRecipientInfosInternal(&asnstruct->recipientInfos, PKITRUE, PKIFALSE)
          + PKISizeofEncryptedContentInfoInternal(&asnstruct->encryptedContentInfo, 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;

} /* PKISizeofEnvelopedDataInternal */

void PKIDropInPlaceEnvelopedData(
    PKICONTEXT *ctx,
    PKIEnvelopedData *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceRecipientInfos(ctx, &(f->recipientInfos));
    PKIDropInPlaceEncryptedContentInfo(ctx, &(f->encryptedContentInfo));
} /* PKIDropInPlaceEnvelopedData */

size_t PKIPackEnvelopedDataInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIEnvelopedData *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 = PKISizeofEnvelopedData(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 EnvelopedData */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field recipientInfos of EnvelopedData */
    bytesused += PKIPackRecipientInfosInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->recipientInfos), PKIID_RecipientInfos, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field encryptedContentInfo of EnvelopedData */
    bytesused += PKIPackEncryptedContentInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->encryptedContentInfo), PKIID_EncryptedContentInfo, 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;
} /* PKIPackEnvelopedDataInternal */

size_t PKIUnpkInPlaceEnvelopedData(
    PKICONTEXT *ctx,
    PKIEnvelopedData *asnstruct,
    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", "EnvelopedData" );

    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 EnvelopedData */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field recipientInfos of EnvelopedData */
    bytesused += PKIUnpkInPlaceRecipientInfos(ctx, &(asnstruct->recipientInfos), buf+bytesused,
                        localsize-bytesused, PKIID_RecipientInfos, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field encryptedContentInfo of EnvelopedData */
    bytesused += PKIUnpkInPlaceEncryptedContentInfo(ctx, &(asnstruct->encryptedContentInfo), buf+bytesused,
                        localsize-bytesused, PKIID_EncryptedContentInfo, 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;
} /* PKIUnpkInPlaceEnvelopedData */

size_t PKIUnpackEnvelopedDataInternal(
    PKICONTEXT *ctx,
    PKIEnvelopedData **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIEnvelopedData *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 = PKINewEnvelopedData(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceEnvelopedData(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeEnvelopedData(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackEnvelopedDataInternal */


/******************************************************************
 * Routines for ExtendedCertificatesAndCertificates
 ******************************************************************/

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

    if (asnstruct == NULL)
        return 0;

    lth = asnstruct->n;
    if (lth > PKIMAX_ExtendedCertificatesAndCertificates)
        lth = PKIMAX_ExtendedCertificatesAndCertificates;	/* clamp it */
    for (i=0;i<lth;i++)
        body_size += PKISizeofExtendedCertificateOrCertificateInternal((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;
} /* PKISizeofExtendedCertificatesAndCertificatesInternal */

void PKIDropInPlaceExtendedCertificatesAndCertificates(
    PKICONTEXT *ctx,
    PKIExtendedCertificatesAndCertificates *f)
{
    long i, lth;

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

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

size_t PKIPackExtendedCertificatesAndCertificatesInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKIExtendedCertificatesAndCertificates *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_ExtendedCertificatesAndCertificates];

    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_ExtendedCertificatesAndCertificates) {
        PKIERR(PKIErrPackSETOFArrayTooLong);
        return 0;
    }

    datasize = PKISizeofExtendedCertificatesAndCertificates(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 += PKIPackExtendedCertificateOrCertificateInternal(ctx, buf+bytesused, buflen-bytesused,
                           (asnstruct->elt)[0], PKIID_ExtendedCertificateOrCertificate, erret);
    }

    else {

        /* calculate lengths and max */
        for (i=0; i<numElem; i++) {
            length = PKISizeofExtendedCertificateOrCertificate(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) PKIPackExtendedCertificateOrCertificateInternal(ctx, temp[i].val,
                          max, (asnstruct->elt)[i],
                          PKIID_ExtendedCertificateOrCertificate, 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;
} /* PKIPackExtendedCertificatesAndCertificatesInternal */

size_t PKIUnpkInPlaceExtendedCertificatesAndCertificates(
    PKICONTEXT *ctx,
    PKIExtendedCertificatesAndCertificates *asnstruct,
    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", "ExtendedCertificatesAndCertificates");

    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_ExtendedCertificatesAndCertificates) && (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] = PKINewExtendedCertificateOrCertificate(ctx);
        bytesused += PKIUnpkInPlaceExtendedCertificateOrCertificate(ctx, asnstruct->elt[i],
                          buf+bytesused, localsize-bytesused,
                          PKIID_ExtendedCertificateOrCertificate, erret);
        if (*erret != 0 || asnstruct->elt[i] == NULL)
            break;
        asnstruct->n = i+1 ; /* note the new element */
    } /* 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;
} /* PKIUnpkInPlaceExtendedCertificatesAndCertificates */

size_t PKIUnpackExtendedCertificatesAndCertificatesInternal(
    PKICONTEXT *ctx,
    PKIExtendedCertificatesAndCertificates **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKIExtendedCertificatesAndCertificates *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 = PKINewExtendedCertificatesAndCertificates(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceExtendedCertificatesAndCertificates(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeExtendedCertificatesAndCertificates(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackExtendedCertificatesAndCertificatesInternal */


/******************************************************************
 * Routines for SignedData
 ******************************************************************/

size_t PKISizeofSignedDataInternal(PKISignedData *asnstruct, int outerSizeFlag, int expTaggedFlag)
{
    size_t body_size = 0;

    if (asnstruct == NULL)
        return 0;

    body_size =
            PKISizeofVersionInternal(&asnstruct->version, PKITRUE, PKIFALSE)
          + PKISizeofDigestAlgorithmIdentifiersInternal(&asnstruct->digestAlgorithms, PKITRUE, PKIFALSE)
          + PKISizeofContentInfoInternal(&asnstruct->contentInfo, PKITRUE, PKIFALSE)
          + PKISizeofExtendedCertificatesAndCertificatesInternal(asnstruct->certificates, PKITRUE, PKIFALSE)
          + PKISizeofCertificateRevocationListsInternal(asnstruct->crls, PKITRUE, PKIFALSE)
          + PKISizeofSignerInfosInternal(&asnstruct->signerInfos, 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;

} /* PKISizeofSignedDataInternal */

void PKIDropInPlaceSignedData(
    PKICONTEXT *ctx,
    PKISignedData *f)
{
    if (ctx == NULL)
        return;

    if (f == NULL) return ;
    PKIDropInPlaceVersion(ctx, &(f->version));
    PKIDropInPlaceDigestAlgorithmIdentifiers(ctx, &(f->digestAlgorithms));
    PKIDropInPlaceContentInfo(ctx, &(f->contentInfo));
    PKIFreeExtendedCertificatesAndCertificates(ctx, f->certificates);
    f->certificates = NULL;
    PKIFreeCertificateRevocationLists(ctx, f->crls);
    f->crls = NULL;
    PKIDropInPlaceSignerInfos(ctx, &(f->signerInfos));
} /* PKIDropInPlaceSignedData */

size_t PKIPackSignedDataInternal(
    PKICONTEXT *ctx,
    unsigned char *buf,
    size_t buflen,
    PKISignedData *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 = PKISizeofSignedData(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 SignedData */
    bytesused += PKIPackVersionInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->version), PKIID_Version, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field digestAlgorithms of SignedData */
    bytesused += PKIPackDigestAlgorithmIdentifiersInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->digestAlgorithms), PKIID_DigestAlgorithmIdentifiers, erret);
    if (bytesused > datasize || *erret != 0)
        break;

    /* field contentInfo of SignedData */
    bytesused += PKIPackContentInfoInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->contentInfo), PKIID_ContentInfo, erret);
    if (bytesused > datasize || *erret != 0)
        break;

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

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

    /* field signerInfos of SignedData */
    bytesused += PKIPackSignerInfosInternal(ctx, buf+bytesused, buflen-bytesused,
                       &(asnstruct->signerInfos), PKIID_SignerInfos, 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;
} /* PKIPackSignedDataInternal */

size_t PKIUnpkInPlaceSignedData(
    PKICONTEXT *ctx,
    PKISignedData *asnstruct,
    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", "SignedData" );

    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 SignedData */
    bytesused += PKIUnpkInPlaceVersion(ctx, &(asnstruct->version), buf+bytesused,
                        localsize-bytesused, PKIID_Version, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field digestAlgorithms of SignedData */
    bytesused += PKIUnpkInPlaceDigestAlgorithmIdentifiers(ctx, &(asnstruct->digestAlgorithms), buf+bytesused,
                        localsize-bytesused, PKIID_DigestAlgorithmIdentifiers, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field contentInfo of SignedData */
    bytesused += PKIUnpkInPlaceContentInfo(ctx, &(asnstruct->contentInfo), buf+bytesused,
                        localsize-bytesused, PKIID_ContentInfo, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field certificates of SignedData */
    if (asnstruct->certificates != NULL)
        PKIFreeExtendedCertificatesAndCertificates(ctx, asnstruct->certificates);
    bytesused += PKIUnpackExtendedCertificatesAndCertificatesInternal(ctx, &(asnstruct->certificates),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x00, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field crls of SignedData */
    if (asnstruct->crls != NULL)
        PKIFreeCertificateRevocationLists(ctx, asnstruct->crls);
    bytesused += PKIUnpackCertificateRevocationListsInternal(ctx, &(asnstruct->crls),
                 buf+bytesused, localsize-bytesused,
                 0x80 | 0x01, erret);
    if (bytesused > localsize || *erret != 0)
        break;

    /* field signerInfos of SignedData */
    bytesused += PKIUnpkInPlaceSignerInfos(ctx, &(asnstruct->signerInfos), buf+bytesused,
                        localsize-bytesused, PKIID_SignerInfos, 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;
} /* PKIUnpkInPlaceSignedData */

size_t PKIUnpackSignedDataInternal(
    PKICONTEXT *ctx,
    PKISignedData **asnstruct,
    unsigned char *buf,
    size_t buflen,
    unsigned char tag,
    int *erret)
{
    size_t bytesused;
    PKISignedData *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 = PKINewSignedData(ctx);	/* carve a block for it */
    bytesused = PKIUnpkInPlaceSignedData(ctx, local, buf, buflen, tag, erret);
    if (*erret != 0) {
        PKIFreeSignedData(ctx, local);
        return 0;
    }
    *asnstruct = local;
    return bytesused;
} /* PKIUnpackSignedDataInternal */

